diff --git a/.github/ISSUE_TEMPLATE/checklist-for-release.md b/.github/ISSUE_TEMPLATE/checklist-for-release.md index 649281a4a..6fa2002f9 100644 --- a/.github/ISSUE_TEMPLATE/checklist-for-release.md +++ b/.github/ISSUE_TEMPLATE/checklist-for-release.md @@ -31,13 +31,9 @@ Run `tools/release_tests.sh` on: - [ ] Kali - [ ] Debian Stable - [ ] Debian Testing -- [ ] Ubuntu 24.04 (LTS) -- [ ] Ubuntu 24.10 -- [ ] Ubuntu 25.04 +- [ ] Ubuntu 22 - [ ] ParrotOS -- [ ] Fedora 41 (till 2025-11-19) -- [ ] Fedora 42 (till 2026-05-13) -- [ ] Fedora 43 (till 2026-12-02) +- [ ] Fedora 37 - [ ] OpenSuse Leap - [ ] OpenSuse Tumbleweed - [ ] OSX (MacPorts) diff --git a/CHANGELOG.md b/CHANGELOG.md index d4ca1a385..c9ccf4b1a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,78 +2,11 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... -## [unreleased][unreleased] -- Added `lf t55xx view` - now viewing of T55XX dump files is possible (@iceman1001) -- Fixed `lf indala cone` - now writing the right bits when using `--fc` and `--cn` -- Changed readline hack logic for async dbg msg to be ready for readline 8.3 (@doegox) -- Improved To avoid conflicts with ModemManager on Linux, is recommended to masking the service (@grugnoymeme) -- Changed `data crypto` - now also handles AES-256 (@iceman1001) -- Changed `hf mfdes info` - add recognition of Swissbit iShield Key Mifare (@ah01) -- Changed `hf mf info` - add detection for unknown backdoor keys and for some backdoor variants (@doegox) -- Changed `mqtt` commnands - now honors preference settings (@iceman1001) -- Changed `prefs` - now handles MQTT settings too (@iceman1001) -- Fixed `mqtt` segfault and gdb warning under windows (proper thread stopping and socket handling). (@virtyvoid) -- Added `mqtt` - the pm3 client can now send and receive MQTT messages or json files. (@iceman1001) -- Changed `hf iclass wrbl` - replay behavior to use privilege escalation if the macs field is not passed empty(@antiklesys) -- Changed `hf iclass restore` - it now supports privilege escalation to restore card content using replay (@antiklesys) -- Fixed `hf 15 dump` - now reads sysinfo response correct (@iceman1001) -- Changed `make clean` - it now removes all __pycache__ folders (@iceman1001) -- Fixed `hf 15 readmulti` - fix block calculations (@iceman1001) -- Changed `mem load` - now handles UL-C and UL-AES dictionary files (@iceman1001) -- Changed `hf mfu sim` - now support UL-C simulation (@iceman1001) -- Added `!` - run system commands from inside the client. Potentially dangerous if running client as SUDO, SU, ROOT (@iceman1001) -- Implemented `hf felica scsvcode` - now dumps all service and area codes. (@zinongli) -- Added `hf felica liteauth` - now support FeliCa Lite-S authentication(@q0jt) -- Added `he felica dump` - partial support for dumping all blocks from unauth readable services (@zinongli) -- Changed `hf 14b calypso` - now don't break the file id loop when one file can't be selected or read. Add new file ids to iterate through (@zinongli) - - -## [Daddy Iceman.4.20469][2025-06-16] -- Fixed edge case in fm11rf08s key recovery tools (@doegox) -- Removed `--par` from `lf em 4x70` commands. -- Changed `hf 14a info` - refactored code to be able to detect card technology across the client easier (@iceman1001) -- Changed `hf mf info` - now informs better if a different card technology is detected (@iceman1001) -- Changed `hf mf autopwn` - now exits if desfire is detected and limit attacks if mifare plus is detected (@iceman1001) -- Changed `hf mfp chk` - improved key handling and output (@iceman1001) -- Fix `hf mf dump` - added a check for keyfile to contain enough keys for card (@iceman1001) -- Fix `hf mf eview` - now viewing 2k, 4k cards doesn't get wrong background color (@iceman1001) -- Changed `hf mf info` - skip checking if it detects a MIFARE Ultralight family card (@iceman1001) -- Changed `hf mf rdsc` - it now addeds the used key to the output in the sector trailer (@iceman1001) -- Added the `PM3ULTIMATE` platform in the build / docs. *untested* (@iceman1001) -- Added fpga compilation for PM3ULTIMATE device (@n-hutton) -- Updated the ATR list (@iceman1001) -- Fixed fpga binary images to use fixed seed 2 (@n-hutton) -- Added `hf iclass sam --info` - option that returns sam specific details (@antiklesys) -- Changed `hf iclass sim -t 7` - implemented simulation that glitches key block responses (@antiklesys) -- Changed `hf iclass sim -t 6` - implemented simulation that glitches sio block (@antiklesys) -- Changed `hf iclass legbrute` - implemented multithreading support (@antiklesys) -- Changed `hf iclass legrec` - added a --sl option for further speed increase by tweaking the communication delays (@antiklesys) -- Changed `hf iclass legrec` - added a --fast option for further speed increase and automated AA2 block selection (@antiklesys) -- Changed `hf iclass legrec` - additional code optimizations gaining a ~147% speed increase (@antiklesys) -- Changed `hf iclass tear` - readability improvements for erase phase (@antiklesys) -- Changed `hf iclass legrec` - code optimizations gaining a ~8% speed increase (@antiklesys) -- Modified `hf iclass tear` - now has a device side implementation also. (@antiklesys) (@iceman1001) -- Changed `hf iclass info` - now uses CSN values based checks (@antiklesys) -- Changed `hf iclass dump` - now uses default AA1 key when called without a key or key index (@iceman1001) -- Renamed `hf iclass trbl` to `hf iclass tear` (@iceman1001) -- Changed `hw tearoff` - the device side message is now debug log controlled (@iceman1001) -- Changed `pm3.sh` - Serial ports enumeration on Proxspace3.xx / MINGW environments, now using powershell.exe since wmic is deprecated (@iceman1001) -- Fixed `hf iclass trbl` - to correctly use the credit key when passed and show partial tearoff results (@antiklesys) -- Fixed `hf iclass legbrute` was not correctly parsing the index value -- Fixed `hf mf ekeyprn` - failed to download emulator memory due to wrong size calculation (@iceman1001) -- Fixed `hf mf fchk --mem` to actually use flash dict (@doegox) -- Fixed `make install` on OSX thanks DaveItsLong (@doegox) -- Added new standalone mode `HF_ST25_TEAROFF` to store/restore ST25TB tags with tearoff for counters (@seclabz) -- Added `hf_mfu_ultra.lua` script enables restoring dump to ULTRA/UL-5 tags and clearing previously written ULTRA tags (@mak-42) -- Fixed `hf mfu sim` to make persistent the counter increases in the emulator memory (@sup3rgiu) -- Fixed `hf mf mad` to correctly display MAD version 2 card publisher sector (@BIOS9) -- Fixed `lf hitag dump` and related commands stability when tag is configured in public mode/TTF mode (@rfidgeek1337) - -## [Blue Ice.4.20142][2025-03-25] +## [Blue Ice][2025-03-25] - Added `des_talk.py` script for easier MIFARE DESFire handling (@trigat) - Fixed `hf 14b info` - wrong endianess when looking for lock bits etc (@gentilkiwi) - Changed `hf mf autopwn` - tries to detect static encrypted nonces and also user cancel during chk keys (@iceman1001) -- Changed `hf mf autopwn` - added option to use SPI flash dictionary (@jmichelp) +- Added option to `hf mf autopwn` to use SPI flash dictionary (@jmichelp) - Changed `trace list -t seos` - now annotate ISO7816 (@iceman1001) - Updated aid and mad json files (@iceman1001) - Changed `hf 14a apdu` - now can be interrupted and dynamically adds time (@iceman1001) @@ -105,9 +38,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed `hf mf cload` - now accepts MFC Ev1 sized dumps (@iceman1001) - Changed `hf mfu info` - now properly identify ULEv1 AES 50pF (@iceman1001) - Changed `hf mf info` - now differentiates between full USCUID and cut down ZUID chips (@nvx) -- Changed `lf hitag chk` - added key counter, client side abort and minor delay (@iceman1001) +- Changed `lf hitag chk` - added key counter, client side abort and minor delay (@iceman1001) - Added `hf seos sam` - Added support for HID SAM SEOS communications (@jkramarz) -- Changed the extended area accessible by spiffs into last page of FLASH (@piotrva) +- Changed (extended) area accessible by spiffs into last page of FLASH (@piotrva) - Changed flash-stored key dictionaries (Mifare, iClass, T55XX) and T55XX configurations to SPIFFS files (@piotrva) - Changed `lf em 410x sim` to use default gap value of 0 and extended help (@piotrva) - Changed `hf 14a info` - now identifies MIAFRE Duox (@iceman1001) @@ -121,14 +54,13 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Changed extended area for Mifare keys in SPI flash to hold 4095 keys (@piotrva) - Fixed DESFire D40 secure channel crypto (@nvx) - Fixed `hf mfp info` fix signature check on 4b UID cards (@doegox) -- Changed `hf_mf_ultimatecard` - it now automatically set maximum read/write block when using predefined types (@piotrva) -- Changed SPI flash detection to calculate the size instead of table lookup (@ANTodorov) -- Changed `spi_flash_decode.py` script with more ICs (@ANTodorov) +- Automatically set maximum read/write block when using predefined types in `hf_mf_ultimatecard` script (@piotrva) +- Changed SPI flash detection to calculate the size instead of table lookup, updated spi_flash_decode.py script with more ICs (@ANTodorov) - Fixed `hf/lf tune` segfault when called from script (@doegox) -- Changed `hf_mf_ultimatecard` - added option to set and get maximum read/write block number (@piotrva) +- Added option to set and get maximum read/write block number using `hf_mf_ultimatecard` script (@piotrva) - Added JEDEC information for SPI flash W25Q64JV (@ANTodorov) -- Changed `hf iclass configcard` - added special iclass legacy config cards (@antiklesys) -- Changed `hf iclass legrec` - added simulation function (@antiklesys) +- Added special iclass legacy config cards in `hf iclass configcard` (@antiklesys) +- Added simulation function to `hf iclass legrec` (@antiklesys) - Added keys from Momentum firmware projects. (@onovy) - Added Dutch Statistics Agency default key (@eagle00789) - Fixed Wiegand decode with hex input dropping the first bit (@emilyastranova) diff --git a/Makefile b/Makefile index c985246d5..ce4f7aa7f 100644 --- a/Makefile +++ b/Makefile @@ -32,9 +32,6 @@ endif all clean install uninstall check: %: client/% bootrom/% armsrc/% recovery/% mfc_card_only/% mfc_card_reader/% mfd_aes_brute/% fpga_compress/% cryptorf/% # hitag2crack toolsuite is not yet integrated in "all", it must be called explicitly: "make hitag2crack" #all clean install uninstall check: %: hitag2crack/% -clean: %: hitag2crack/% - find . -type d -name __pycache__ -exec rm -rfv \{\} + - INSTALLTOOLS=mfc/pm3_eml2lower.sh mfc/pm3_eml2upper.sh mfc/pm3_mfdread.py mfc/pm3_mfd2eml.py mfc/pm3_eml2mfd.py pm3_amii_bin2eml.pl pm3_reblay-emulating.py pm3_reblay-reading.py INSTALLSIMFW=sim011.bin sim011.sha512.txt sim013.bin sim013.sha512.txt sim014.bin sim014.sha512.txt @@ -207,7 +204,7 @@ help: @echo "+ fpga_compress - Make tools/fpga_compress" @echo @echo "+ style - Apply some automated source code formatting rules" - @echo "+ commands - Regenerate commands documentation files and autocompletion data" + @echo "+ commands - Regenerate commands documentation files and autocompletion data @echo "+ check - Run offline tests. Set CHECKARGS to pass arguments to the test script" @echo "+ .../check - Run offline tests against specific target. See above." @echo "+ miscchecks - Detect various encoding issues in source code" @@ -267,11 +264,8 @@ ifeq ($(PLATFORM_CHANGED),true) $(Q)$(MAKE) --no-print-directory -C bootrom clean $(Q)$(MAKE) --no-print-directory -C armsrc clean $(Q)$(MAKE) --no-print-directory -C recovery clean - $(Q)$(MAKE) --no-print-directory -C tools/fpga_compress clean -# clean the client only if PLATFORM got changed from or to PM3ICOPYX -ifeq (PM3ICOPYX,$(filter PM3ICOPYX, $(PLATFORM) $(CACHED_PLATFORM))) $(Q)$(MAKE) --no-print-directory -C client clean -endif + $(Q)$(MAKE) --no-print-directory -C tools/fpga_compress clean $(Q)$(ECHO) CACHED_PLATFORM=$(PLATFORM) > .Makefile.options.cache $(Q)$(ECHO) CACHED_PLATFORM_EXTRAS=$(PLATFORM_EXTRAS) >> .Makefile.options.cache $(Q)$(ECHO) CACHED_PLATFORM_DEFS=$(PLATFORM_DEFS) >> .Makefile.options.cache @@ -372,12 +366,10 @@ release: @echo "# - Release Tag: $(VERSION)" @echo "# - Release Name: $(RELEASE_NAME)" # - Removing -Werror... - @find . \( -path "./Makefile.defs" -or -path "./client/Makefile" -or -path "./common_arm/Makefile.common" -or -path "./tools/hitag2crack/*/Makefile" -or -path "./client/deps/*/Makefile" \) -exec sed -i 's/ -Werror//' {} \; - @find . \( -path "./client/deps/*.cmake" -or -path "./client/CMakeLists.txt" -or -path "./client/experimental_lib/CMakeLists.txt" \) -exec sed -i 's/ -Werror//' {} \; + @find . \( -path "./Makefile.defs" -or -path "./client/Makefile" -or -path "./common_arm/Makefile.common" -or -path "./tools/hitag2crack/*/Makefile" \) -exec sed -i 's/ -Werror//' {} \; + @find . \( -path "./client/deps/*.cmake" -or -path "./client/CMakeLists.txt" \) -exec sed -i 's/ -Werror//' {} \; # - Changing banner... - @sed -i "s/^#define BANNERMSG2 .*/#define BANNERMSG2 \" -----------------------------------\"/" client/src/proxmark3.c @sed -i "s/^#define BANNERMSG3 .*/#define BANNERMSG3 \"Release $(VERSION) - $(RELEASE_NAME)\"/" client/src/proxmark3.c - @echo -n "# ";grep "^#define BANNERMSG2" client/src/proxmark3.c @echo -n "# ";grep "^#define BANNERMSG3" client/src/proxmark3.c # - Committing temporarily... @git commit -a -m "Release $(VERSION) - $(RELEASE_NAME)" diff --git a/Makefile.defs b/Makefile.defs index 2496057fa..0d6066489 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -112,8 +112,8 @@ ifeq ($(DEBUG),1) DEFCFLAGS = -g -O0 -fstrict-aliasing -pipe DEFLDFLAGS = else - DEFCXXFLAGS = -Wall -Werror -O3 -pipe - DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe + DEFCXXFLAGS = -Wall -O3 -pipe + DEFCFLAGS = -Wall -O3 -fstrict-aliasing -pipe DEFLDFLAGS = endif diff --git a/Makefile.platform.sample b/Makefile.platform.sample index 0ba8d8603..2e1221cb7 100644 --- a/Makefile.platform.sample +++ b/Makefile.platform.sample @@ -5,7 +5,7 @@ # Comment the line below and uncomment further down according to which device you have PLATFORM=PM3RDV4 -# For PM3 RDV1, RDV2, Easy or rysccorps etc +# For PM3 Easy: # uncomment the line below #PLATFORM=PM3GENERIC @@ -14,26 +14,19 @@ PLATFORM=PM3RDV4 #PLATFORM=PM3ICOPYX #PLATFORM_EXTRAS=FLASH -# For PM3 Ultimate: -# uncomment the line below -#PLATFORM=PM3ULTIMATE # If you want more than one PLATFORM_EXTRAS option, separate them by spaces: #PLATFORM_EXTRAS=BTADDON #PLATFORM_EXTRAS=FLASH #PLATFORM_EXTRAS=SMARTCARD #PLATFORM_EXTRAS=BTADDON FLASH -STANDALONE=HF_UNISNIFF +#STANDALONE=LF_SAMYRUN # Uncomment the line below to set the correct LED order on board Proxmark3 Easy # Only available with PLATFORM=PM3GENERIC #LED_ORDER=PM3EASY -# Uncomment a line below to change default USART baud rate -# defaults to 115200 used by HC-05 in Blueshark -#USART_BAUD_RATE=19200 - # Uncomment the lines below in order to make a 256KB image # and comment out the lines above diff --git a/README.md b/README.md index 9418c837a..64ae86137 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,7 @@ The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the |[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)|[Notes on Magic UID cards](/doc/magic_cards_notes.md)| |[Notes on Color usage](/doc/colors_notes.md)|[Makefile vs CMake](/doc/md/Development/Makefile-vs-CMake.md)|[Notes on Cloner guns](/doc/cloner_notes.md)| |[Notes on cliparser usage](/doc/cliparser.md)|[Notes on clocks](/doc/clocks.md)|[Notes on MIFARE DESFire](/doc/desfire.md)| -|[Notes on CIPURSE](/doc/cipurse.md)|[Notes on NDEF type4a](/doc/ndef_type4a.md)|[Unofficial MIFARE DESFire bible](/doc/unofficial_desfire_bible.md)| -[Notes on downgrade attacks](/doc/hid_downgrade.md)||| +|[Notes on CIPURSE](/doc/cipurse.md)|[Notes on NDEF type4a](/doc/ndef_type4a.md)|[Notes on downgrade attacks](/doc/hid_downgrade.md)| # How to build? @@ -97,14 +96,12 @@ We define generic Proxmark3 platforms as following devices. - **Note**: currently incompatible with iCopy-X GUI as Proxmark client commands using different syntax - **Note**: see also [icopyx-community repos](https://github.com/iCopy-X-Community/) for upstream sources, reversed hw etc. - **Note**: Uses DRM to lock down tags, ignores the open source licences. Use on your own risk. -- ⚠ Proxmark3 Ultimate - - **Note**: unknown device hw - - **Note**: FPGA images is building for it. Use on your own risk. **Unknown support status** - ⚠ VX - **Note**: unknown device hw - +- ⚠ Proxmark3 Ultimate + - **Note**: unknown device hw When it comes to these new unknown models we are depending on the community to report in if this repo works and what they did to make it work. @@ -183,11 +180,10 @@ We usually merge your contributions fast since we do like the idea of getting a The [public roadmap](https://github.com/RfidResearchGroup/proxmark3/wiki/Public-Roadmap) is an excellent start to read if you are interesting in contributing. -## Supported operating systems +## Supported operative systems This repo compiles nicely on - WSL1 on Windows 10 - - WSL2 on Windows 10/11 - Proxspace environment [release v3.xx](https://github.com/Gator96100/ProxSpace/releases) - Windows/MinGW environment - Ubuntu, ParrotOS, Gentoo, Pentoo, Kali, NetHunter, Arch Linux, Fedora, Debian, Raspbian diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index b492b4205..26af3af0d 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -121,7 +121,7 @@ void BigBuf_Clear_ext(bool verbose) { memset(BigBuf, 0, s_bigbuf_size); clear_trace(); if (verbose) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size); + Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size); } } diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 366b7c802..2e905a45c 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -23,8 +23,8 @@ #define MAX_FRAME_SIZE 256 // maximum allowed ISO14443 frame #define MAX_PARITY_SIZE ((MAX_FRAME_SIZE + 7) / 8) -#define MAX_MIFARE_FRAME_SIZE 19 // biggest Mifare frame is UL AES answer to AUTH (1 + 16 Bytes) + 2 Bytes CRC -#define MAX_MIFARE_PARITY_SIZE 3 // need 19 parity bits for the 19 Byte above. 3 Bytes are enough to store these +#define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC +#define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these #define CARD_MEMORY_SIZE 4096 // For now we're storing FM11RF08S nonces in the upper 1k of CARD_MEMORY_SIZE // but we might have to allocate extra space if one day we've to support sth like a FM11RF32S diff --git a/armsrc/Makefile b/armsrc/Makefile index 9929b3ae3..0f83596be 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -186,7 +186,7 @@ showinfo: # version_pm3.c should be checked on every time fullimage.stage1.elf should be remade version_pm3.c: default_version_pm3.c $(OBJDIR)/fpga_version_info.o $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ) .FORCE $(info [-] CHECK $@) - $(Q)$(SH) ../tools/mkversion.sh $@ || $(CP) $< $@ + $(Q)$(CP) $< $@ fpga_version_info.c: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR) $(info [-] GEN $@) diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index b521da878..91d87dd14 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -119,9 +119,6 @@ define KNOWN_STANDALONE_DEFINITIONS | HF_REBLAY | 14A Relay over BT | | (RDV4 only) | - Salvador Mendoza | +----------------------------------------------------------+ -| HF_ST25_TEAROFF | Store/restore ST25TB tags with | -| | tear-off for counters - SecLabz | -+----------------------------------------------------------+ | HF_TCPRST | IKEA Rothult read/sim/dump/emul | | | - Nick Draffen | +----------------------------------------------------------+ @@ -142,11 +139,11 @@ endef STANDALONE_MODES := LF_SKELETON STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE -STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_ST25_TEAROFF HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG +STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG STANDALONE_MODES += DANKARMULTI STANDALONE_MODES_REQ_BT := HF_CARDHOPPER HF_REBLAY STANDALONE_MODES_REQ_SMARTCARD := -STANDALONE_MODES_REQ_FLASH := LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_LEGICSIM HF_MFCSIM HF_ST25_TEAROFF +STANDALONE_MODES_REQ_FLASH := LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_LEGICSIM HF_MFCSIM ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),) STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE) ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),) diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index d4c858e8b..5873c0aff 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -157,10 +157,6 @@ endif ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS))) SRC_STANDALONE = hf_young.c endif -# WITH_STANDALONE_HF_ST25_TEAROFF -ifneq (,$(findstring WITH_STANDALONE_HF_ST25_TEAROFF,$(APP_CFLAGS))) - SRC_STANDALONE = hf_st25_tearoff.c -endif ifneq (,$(findstring WITH_STANDALONE_DANKARMULTI,$(APP_CFLAGS))) SRC_STANDALONE = dankarmulti.c diff --git a/armsrc/Standalone/hf_aveful.c b/armsrc/Standalone/hf_aveful.c index d634f819c..626aa9d17 100644 --- a/armsrc/Standalone/hf_aveful.c +++ b/armsrc/Standalone/hf_aveful.c @@ -157,7 +157,7 @@ void RunMod(void) { if (button_pressed != BUTTON_NO_CLICK || data_available()) break; else if (state == STATE_SEARCH) { - if (iso14443a_select_card(NULL, &card, NULL, true, 0, true) == 0) { + if (!iso14443a_select_card(NULL, &card, NULL, true, 0, true)) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelay(500); @@ -246,7 +246,7 @@ void RunMod(void) { FLAG_SET_UID_IN_DATA(flags, 7); Dbprintf("Starting simulation, press " _GREEN_("pm3 button") " to stop and go back to search state."); - SimulateIso14443aTag(7, flags, card.uid, 0, NULL, 0, false, false); + SimulateIso14443aTag(7, flags, card.uid, 0, NULL, 0); // Go back to search state if user presses pm3-button state = STATE_SEARCH; diff --git a/armsrc/Standalone/hf_cardhopper.c b/armsrc/Standalone/hf_cardhopper.c index d199dcdab..ed6e660bf 100644 --- a/armsrc/Standalone/hf_cardhopper.c +++ b/armsrc/Standalone/hf_cardhopper.c @@ -59,7 +59,7 @@ static const uint8_t magicCARD[4] = "CARD"; static const uint8_t magicEND [4] = "\xff" "END"; static const uint8_t magicRSRT[7] = "RESTART"; static const uint8_t magicERR [4] = "\xff" "ERR"; -static const uint8_t magicACK [1] = "\xfe"; +static uint8_t magicACK [1] = "\xfe"; // is constant, but must be passed to API that doesn't like that // Forward declarations static void become_reader(void); @@ -72,7 +72,7 @@ static bool try_use_canned_response(const uint8_t *, int, tag_response_info_t *) static void reply_with_packet(packet_t *); static void read_packet(packet_t *); -static void write_packet(const packet_t *); +static void write_packet(packet_t *); static bool GetIso14443aCommandFromReaderInterruptible(uint8_t *, uint16_t, uint8_t *, int *); @@ -146,7 +146,7 @@ static void become_reader(void) { packet_t packet = { 0 }; packet_t *rx = &packet; packet_t *tx = &packet; - uint8_t toCard[MAX_FRAME_SIZE] = { 0 }; + uint8_t toCard[256] = { 0 }; uint8_t parity[MAX_PARITY_SIZE] = { 0 }; while (1) { @@ -178,15 +178,11 @@ static void become_reader(void) { AddCrc14A(toCard, rx->len); ReaderTransmit(toCard, rx->len + 2, NULL); - // read to toCard instead of tx->dat directly to allow the extra byte for the CRC - uint16_t fromCardLen = ReaderReceive(toCard, sizeof(toCard), parity); - if (fromCardLen <= 2) { + tx->len = ReaderReceive(tx->dat, sizeof(tx->dat), parity); + if (tx->len == 0) { tx->len = sizeof(magicERR); memcpy(tx->dat, magicERR, sizeof(magicERR)); - } else { - tx->len = fromCardLen - 2; // cut off the CRC - memcpy(tx->dat, toCard, tx->len); - } + } else tx->len -= 2; // cut off the CRC write_packet(tx); } @@ -233,15 +229,14 @@ static void become_card(void) { tag_response_info_t *canned; uint32_t cuid; + uint32_t counters[3] = { 0 }; + uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd }; uint8_t pages; - if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &canned, &cuid, &pages, NULL) == false) { - DbpString(_RED_("Error initializing the emulation process!")); - return; - } + SimulateIso14443aInit(tagType, flags, data, NULL, 0, &canned, &cuid, counters, tearings, &pages); DbpString(_CYAN_("[@]") " Setup done - entering emulation loop"); int fromReaderLen; - uint8_t fromReaderDat[MAX_FRAME_SIZE] = { 0 }; + uint8_t fromReaderDat[256] = { 0 }; uint8_t parity[MAX_PARITY_SIZE] = { 0 }; packet_t packet = { 0 }; packet_t *tx = &packet; @@ -282,14 +277,8 @@ static void become_card(void) { memcpy(tx->dat, fromReaderDat, tx->len); write_packet(tx); - if (no_reply) { - // since the RATS reply has already been sent waiting here will can result in missing the next reader command - // if we do get a reply later on while waiting for the next reader message it will be safely ignored - continue; - } - read_packet(rx); - if (rx->len > 0) { + if (!no_reply && rx->len > 0) { reply_with_packet(rx); } } @@ -355,13 +344,7 @@ static void cook_ats(packet_t *ats, uint8_t fwi, uint8_t sfgi) { uint8_t orig_t0 = ats->dat[1]; // Update FSCI in T0 from the received ATS - uint8_t fsci = orig_t0 & 0x0F; - if (fsci > 8) { - // our packet length maxes out at 255 bytes, an FSCI of 8 requires 256 bytes - // but since we drop the 2 byte CRC16 we're safe capping this at 8 - fsci = 8; - } - t0 |= fsci; + t0 |= orig_t0 & 0x0F; uint8_t len = ats->len - 2; uint8_t *orig_ats_ptr = &ats->dat[2]; @@ -466,12 +449,20 @@ static bool try_use_canned_response(const uint8_t *dat, int len, tag_response_in } -static uint8_t g_responseBuffer [MAX_FRAME_SIZE] = { 0 }; +static uint8_t g_responseBuffer [512 ] = { 0 }; +static uint8_t g_modulationBuffer[1024] = { 0 }; static void reply_with_packet(packet_t *packet) { - memcpy(g_responseBuffer, packet->dat, packet->len); - AddCrc14A(g_responseBuffer, packet->len); - EmSendCmd(g_responseBuffer, packet->len + 2); + tag_response_info_t response = { 0 }; + response.response = g_responseBuffer; + response.modulation = g_modulationBuffer; + + memcpy(response.response, packet->dat, packet->len); + AddCrc14A(response.response, packet->len); + response.response_n = packet->len + 2; + + prepare_tag_modulation(&response, sizeof(g_modulationBuffer)); + EmSendPrecompiledCmd(&response); } @@ -505,27 +496,19 @@ static void read_packet(packet_t *packet) { // clear any remaining buffered data while (cardhopper_data_available()) { - cardhopper_read(packet->dat, sizeof(packet->dat)); + cardhopper_read(packet->dat, 255); } packet->len = 0; return; } } - - if (packet->len > (MAX_FRAME_SIZE - 2)) { - // this will overrun MAX_FRAME_SIZE once we re-add the CRC - // in theory this should never happen but better to be defensive - packet->len = 0; - cardhopper_write(magicERR, sizeof(magicERR)); - } else { - cardhopper_write(magicACK, sizeof(magicACK)); - } + cardhopper_write(magicACK, sizeof(magicACK)); } -static void write_packet(const packet_t *packet) { - cardhopper_write((const uint8_t *) packet, packet->len + 1); +static void write_packet(packet_t *packet) { + cardhopper_write((uint8_t *) packet, packet->len + 1); } diff --git a/armsrc/Standalone/hf_colin.c b/armsrc/Standalone/hf_colin.c index 0aa49c092..423e093f6 100644 --- a/armsrc/Standalone/hf_colin.c +++ b/armsrc/Standalone/hf_colin.c @@ -498,7 +498,7 @@ failtag: SpinOff(50); LED_A_ON(); - while (iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true) == 0) { + while (!iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true)) { WDT_HIT(); if (BUTTON_HELD(10) == BUTTON_HOLD) { WDT_HIT(); @@ -785,7 +785,7 @@ static int e_MifareECardLoad(uint32_t numofsectors, uint8_t keytype) { bool isOK = true; - if (iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true) == 0) { + if (!iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true)) { isOK = false; } @@ -844,7 +844,8 @@ static int cjat91_saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTr for (uint8_t i = 0; i < keyCount; i++) { /* no need for anticollision. just verify tag is still here */ - if (iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true) == 0) { + // if (!iso14443a_fast_select_card(colin_cjuid, 0)) { + if (!iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true)) { cjSetCursLeft(); DbprintfEx(FLAG_NEWLINE, "%sFATAL%s : E_MF_LOSTTAG", _XRED_, _XWHITE_); break; @@ -962,7 +963,7 @@ static int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, const // get UID from chip if (workFlags & 0x01) { - if (iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true) == 0) { + if (!iso14443a_select_card(colin_cjuid, &colin_p_card, &colin_cjcuid, true, 0, true)) { DbprintfEx(FLAG_NEWLINE, "Can't select card"); break; }; diff --git a/armsrc/Standalone/hf_craftbyte.c b/armsrc/Standalone/hf_craftbyte.c index 736e89aca..6eb2ae2a2 100644 --- a/armsrc/Standalone/hf_craftbyte.c +++ b/armsrc/Standalone/hf_craftbyte.c @@ -89,22 +89,22 @@ void RunMod(void) { Dbprintf("Starting simulation, press " _GREEN_("pm3 button") " to stop and go back to search state."); if (card.sak == 0x08 && card.atqa[0] == 0x04 && card.atqa[1] == 0) { DbpString("Mifare Classic 1k"); - SimulateIso14443aTag(1, flags, card.uid, 0, NULL, 0, false, false); + SimulateIso14443aTag(1, flags, card.uid, 0, NULL, 0); } else if (card.sak == 0x08 && card.atqa[0] == 0x44 && card.atqa[1] == 0) { DbpString("Mifare Classic 4k "); - SimulateIso14443aTag(8, flags, card.uid, 0, NULL, 0, false, false); + SimulateIso14443aTag(8, flags, card.uid, 0, NULL, 0); } else if (card.sak == 0x00 && card.atqa[0] == 0x44 && card.atqa[1] == 0) { DbpString("Mifare Ultralight"); - SimulateIso14443aTag(2, flags, card.uid, 0, NULL, 0, false, false); + SimulateIso14443aTag(2, flags, card.uid, 0, NULL, 0); } else if (card.sak == 0x20 && card.atqa[0] == 0x04 && card.atqa[1] == 0x03) { DbpString("Mifare DESFire"); - SimulateIso14443aTag(3, flags, card.uid, 0, NULL, 0, false, false); + SimulateIso14443aTag(3, flags, card.uid, 0, NULL, 0); } else if (card.sak == 0x20 && card.atqa[0] == 0x44 && card.atqa[1] == 0x03) { DbpString("Mifare DESFire Ev1/Plus/JCOP"); - SimulateIso14443aTag(3, flags, card.uid, 0, NULL, 0, false, false); + SimulateIso14443aTag(3, flags, card.uid, 0, NULL, 0); } else { Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation"); - SimulateIso14443aTag(1, flags, card.uid, 0, NULL, 0, false, false); + SimulateIso14443aTag(1, flags, card.uid, 0, NULL, 0); } // Go back to search state if user presses pm3-button diff --git a/armsrc/Standalone/hf_mattyrun.c b/armsrc/Standalone/hf_mattyrun.c index c68d12075..615d79718 100644 --- a/armsrc/Standalone/hf_mattyrun.c +++ b/armsrc/Standalone/hf_mattyrun.c @@ -33,7 +33,6 @@ #include "mifaresim.h" // mifare1ksim #include "mifareutil.h" #include "proxmark3_arm.h" -#include "spiffs.h" #include "standalone.h" // standalone definitions #include "string.h" #include "ticks.h" @@ -535,14 +534,7 @@ void RunMod(void) { SpinErr(LED_D, 50, 8); partialEmulation = true; } else { -#ifdef WITH_FLASH - DbpString("[" _GREEN_("+") "] " _GREEN_("Emulator memory filled completely. Start storing card in spiff memory.")); - uint8_t *emCARD = BigBuf_get_EM_addr(); - char dumpFileName[30] = {0}; - sprintf(dumpFileName, DUMP_FILE, mattyrun_card.uid[0], mattyrun_card.uid[1], mattyrun_card.uid[2], mattyrun_card.uid[3]); - rdv40_spiffs_write(dumpFileName, emCARD, 1024, RDV40_SPIFFS_SAFETY_SAFE); - Dbprintf("[" _GREEN_("+") "] " _GREEN_("Stored card on %s"), dumpFileName); -#endif + DbpString("[" _GREEN_("+") "] " _GREEN_("Emulator memory filled completely.")); } state = STATE_EMULATE; diff --git a/armsrc/Standalone/hf_mattyrun.h b/armsrc/Standalone/hf_mattyrun.h index 892232e88..605ea447b 100644 --- a/armsrc/Standalone/hf_mattyrun.h +++ b/armsrc/Standalone/hf_mattyrun.h @@ -21,9 +21,6 @@ #include -// Filename to store the card info in spiff memory -#define DUMP_FILE "hf_mattyrun_dump_%02x%02x%02x%02x.bin" - // Set of standard keys to be used static uint64_t const MATTYRUN_MFC_DEFAULT_KEYS[] = { 0xFFFFFFFFFFFF, // Default key diff --git a/armsrc/Standalone/hf_msdsal.c b/armsrc/Standalone/hf_msdsal.c index 6eb5b46b2..711e653a4 100644 --- a/armsrc/Standalone/hf_msdsal.c +++ b/armsrc/Standalone/hf_msdsal.c @@ -379,7 +379,7 @@ void RunMod(void) { BigBuf_free_keep_EM(); // tag type: 11 = ISO/IEC 14443-4 - javacard (JCOP) - if (SimulateIso14443aInit(11, flags, data, NULL, 0, &responses, &cuid, NULL, NULL) == false) { + if (SimulateIso14443aInit(11, flags, data, NULL, 0, &responses, &cuid, NULL, NULL, NULL) == false) { BigBuf_free_keep_EM(); reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0); DbpString(_RED_("Error initializing the emulation process!")); diff --git a/armsrc/Standalone/hf_reblay.c b/armsrc/Standalone/hf_reblay.c index 30db64f41..1b84eb3f7 100644 --- a/armsrc/Standalone/hf_reblay.c +++ b/armsrc/Standalone/hf_reblay.c @@ -268,7 +268,7 @@ void RunMod() { BigBuf_free_keep_EM(); // 4 = ISO/IEC 14443-4 - javacard (JCOP) - if (SimulateIso14443aInit(4, flags, data, NULL, 0, &responses, &cuid, NULL, NULL) == false) { + if (SimulateIso14443aInit(4, flags, data, NULL, 0, &responses, &cuid, NULL, NULL, NULL) == false) { BigBuf_free_keep_EM(); reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0); DbpString(_RED_("Error initializing the emulation process!")); diff --git a/armsrc/Standalone/hf_st25_tearoff.c b/armsrc/Standalone/hf_st25_tearoff.c deleted file mode 100644 index 65fc2ba52..000000000 --- a/armsrc/Standalone/hf_st25_tearoff.c +++ /dev/null @@ -1,1170 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) SecLabz, 2025 -// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// See LICENSE.txt for the text of the license. -//----------------------------------------------------------------------------- -// Standalone mode for reading/storing and restoring ST25TB tags with tear-off for counters. -// Handles a collection of tags. Click swaps between Store and Restore modes. -// Requires WITH_FLASH enabled at compile time. -// Only tested on a Proxmark3 Easy with flash -// -// The initial mode is learning/storing with LED D. -// In this mode, the Proxmark3 is looking for an ST25TB tag, reads all its data, -// and stores the tag's contents to flash memory for later restoration. -// -// Clicking the button once will toggle to restore mode (LED C). -// In this mode, the Proxmark3 searches for an ST25TB tag and, if found, compares -// its UID with previously stored tags. If there's a match, it will restore the -// tag data from flash memory, including counter blocks using tear-off technique. -// -// The standalone supports a collection of up to 8 different ST25TB tags. -// -// Special handling is implemented for counter blocks 5 & 6. For these blocks, -// the tear-off technique is used to manipulate counters that normally can only -// be decremented, allowing restoration of previously stored counter values even -// if they're higher than the current value. -// -// Holding the button down for 1 second will exit the standalone mode. -// -// LEDs: -// LED D = Learn/Store mode (reading and storing tag data) -// LED C = Restore mode (writing stored data back to tags) -// LED A (blinking) = Operation successful -// LED B (blinking) = Operation failed -// -// Flash memory is required for this standalone mode to function properly. -// -//----------------------------------------------------------------------------- - - -//============================================================================= -// INCLUDES -//============================================================================= - -// System includes -#include // memcpy, memset - -// Proxmark3 includes -#include "standalone.h" -#include "proxmark3_arm.h" -#include "appmain.h" -#include "fpgaloader.h" -#include "iso14443b.h" // ISO14443B operations -#include "util.h" -#include "spiffs.h" // Flash memory filesystem access -#include "dbprint.h" -#include "ticks.h" -#include "BigBuf.h" -#include "protocols.h" -#include "crc16.h" // compute_crc - -//============================================================================= -// FLASH MEMORY REQUIREMENT CHECK -//============================================================================= - -#ifndef WITH_FLASH -#error "This standalone mode requires WITH_FLASH to be defined. Please recompile with flash memory support." -#endif - -//============================================================================= -// CONSTANTS & DEFINITIONS -//============================================================================= - -// File and data structure constants -#define HF_ST25TB_MULTI_SR_FILE "hf_st25tb_tags.bin" // Store/Restore filename -#define ST25TB_BLOCK_COUNT 16 // ST25TB512 or similar with 16 blocks -#define ST25TB_BLOCK_SIZE 4 // 4 bytes per block -#define ST25TB_COUNTER_BLOCK_5 5 // Counter block indices -#define ST25TB_COUNTER_BLOCK_6 6 -#define ST25TB_DATA_SIZE (ST25TB_BLOCK_COUNT * ST25TB_BLOCK_SIZE) -#define MAX_SAVED_TAGS 8 // Allow storing up to 8 tags - -// Tear-off constants -#define TEAR_OFF_START_OFFSET_US 150 -#define TEAR_OFF_ADJUSTMENT_US 25 -#define PRE_READ_DELAY_US 0 -#define TEAR_OFF_WRITE_RETRY_COUNT 30 -#define TEAR_OFF_CONSOLIDATE_READ_COUNT 6 -#define TEAR_OFF_CONSOLIDATE_WAIT_READ_COUNT 2 -#define TEAR_OFF_CONSOLIDATE_WAIT_MS 2000 - -// Display/console colors -#define RESET "\033[0m" -#define BOLD "\033[01m" -#define RED "\033[31m" -#define BLUE "\033[34m" -#define GREEN "\033[32m" - -// Bit manipulation macros -#define IS_ONE_BIT(value, index) ((value) & ((uint32_t)1 << (index))) -#define IS_ZERO_BIT(value, index) (!IS_ONE_BIT(value, index)) - -#define RF_SWTICH_OFF() FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF) - -//============================================================================= -// TYPE DEFINITIONS -//============================================================================= - -// Operation modes -typedef enum { - MODE_LEARN = 0, // Store/learn tag data - MODE_RESTORE = 1 // Restore tag data -} standalone_mode_t; - -// Operation states -typedef enum { - STATE_BUSY = 0, // Actively processing - STATE_DONE = 1, // Operation completed successfully - STATE_ERROR = 2 // Operation failed -} standalone_state_t; - -// Structure to hold tag data in RAM -typedef struct { - uint64_t uid; - uint32_t blocks[ST25TB_BLOCK_COUNT]; - uint32_t otp; - bool data_valid; // Flag to indicate if this slot holds valid data -} st25tb_data_t; - -//============================================================================= -// GLOBAL VARIABLES -//============================================================================= - -// Tag collection and state tracking -static st25tb_data_t g_stored_tags[MAX_SAVED_TAGS]; -static uint8_t g_valid_tag_count = 0; // Number of valid entries -static standalone_mode_t g_current_mode = MODE_LEARN; // Current operation mode -static standalone_state_t current_state = STATE_BUSY; // Current operation state -static unsigned long g_prng_seed = 1; // Used for PRNG - -//============================================================================= -// FUNCTION DECLARATIONS -//============================================================================= - -// Core utility functions -static int dummy_rand(void); -uint64_t bytes_to_num_le(const uint8_t *src, size_t len); - -// UI/LED interaction functions -static void update_leds_mode(standalone_mode_t mode); -static void indicate_success(void); -static void indicate_failure(void); - -// Flash storage operations -static bool load_tags_from_flash(st25tb_data_t collection[MAX_SAVED_TAGS]); -static bool save_tags_to_flash(const st25tb_data_t collection[MAX_SAVED_TAGS]); -static int find_tag_by_uid(const uint64_t uid); -static int find_free_tag_slot(void); - -// ISO14443B communication functions -static void iso14443b_setup_light(void); - -// Tag read/write operations -static bool st25tb_tag_get_basic_info(iso14b_card_select_t *card_info); -static bool st25tb_tag_read(st25tb_data_t *tag_data_slot); -static bool st25tb_tag_restore(const st25tb_data_t *stored_data_slot); -static void st25tb_tag_print(st25tb_data_t *tag); - -// Tear-off operations -static int st25tb_cmd_write_block(uint8_t block_address, uint8_t *block); -static bool st25tb_write_block_with_retry(uint8_t block_address, uint32_t target_value); -static int st25tb_tear_off_read_block(uint8_t block_address, uint32_t *block_value); -static void st25tb_tear_off_write_block(uint8_t block_address, uint32_t data, uint16_t tearoff_delay_us); -static int8_t st25tb_tear_off_retry_write_verify(uint8_t block_address, uint32_t target_value, uint32_t max_try_count, int sleep_time_ms, uint32_t *read_back_value); -static int8_t st25tb_tear_off_is_consolidated(const uint8_t block_address, uint32_t value, int repeat_read, int sleep_time_ms, uint32_t *read_value); -static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uint32_t current_value, uint32_t target_value, uint32_t *read_back_value); -static uint32_t st25tb_tear_off_next_value(uint32_t current_value, bool randomness); -static void st25tb_tear_off_adjust_timing(int *tear_off_us, uint32_t tear_off_adjustment_us); -static void st25tb_tear_off_log(int tear_off_us, char *color, uint32_t value); -static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t target_value, uint32_t tear_off_adjustment_us, uint32_t safety_value); - -// Main application functions -static void run_learn_function(void); -static void run_restore_function(void); -void ModInfo(void); -void RunMod(void); - -//============================================================================= -// CORE UTILITY FUNCTIONS -//============================================================================= - -/** - * @brief Simple PRNG implementation - * @return Random integer - */ -static int dummy_rand(void) { - g_prng_seed = g_prng_seed * 1103515245 + 12345; - return (unsigned int)(g_prng_seed / 65536) % 32768; -} - -/** - * @brief Convert bytes to number (little-endian) - * @param src Source byte array - * @param len Length of array - * @return Converted 64-bit value - */ -uint64_t bytes_to_num_le(const uint8_t *src, size_t len) { - uint64_t num = 0; - size_t i; - - if (len > sizeof(uint64_t)) { - len = sizeof(uint64_t); - } - - // Iterate from LSB to MSB - for (i = 0; i < len; ++i) { - num |= ((uint64_t)src[i] << (i * 8)); - } - - return num; -} - -//============================================================================= -// UI/LED INTERACTION FUNCTIONS -//============================================================================= - -/** - * @brief Update LEDs to indicate current mode and state - * @param mode Current operation mode - */ -static void update_leds_mode(standalone_mode_t mode) { - LEDsoff(); - if (mode == MODE_LEARN) { - LED_D_ON(); - } else { // MODE_RESTORE - LED_C_ON(); - } -} - -/** - * @brief Indicate successful operation with LED sequence - */ -static void indicate_success(void) { - // Blink Green LED (A) 3 times quickly for success - for (int i = 0; i < 3; ++i) { - LED_A_ON(); - SpinDelay(150); - LED_A_OFF(); - SpinDelay(150); - } -} - -/** - * @brief Indicate failed operation with LED sequence - */ -static void indicate_failure(void) { - // Blink Red LED (B) 3 times quickly for failure - for (int i = 0; i < 3; ++i) { - LED_B_ON(); - SpinDelay(150); - LED_B_OFF(); - SpinDelay(150); - } -} - -//============================================================================= -// FLASH STORAGE OPERATIONS -//============================================================================= - -/** - * @brief Load tag collection from flash - * @param collection Array to store loaded data - * @return true if successful, false otherwise - */ -static bool load_tags_from_flash(st25tb_data_t collection[MAX_SAVED_TAGS]) { - // Check if file exists - if (!exists_in_spiffs(HF_ST25TB_MULTI_SR_FILE)) { - return false; // File doesn't exist, nothing to load - } - - // Verify file size - uint32_t size = size_in_spiffs(HF_ST25TB_MULTI_SR_FILE); - if (size != sizeof(g_stored_tags)) { - Dbprintf(_RED_("Flash file size mismatch (expected %zu, got %u). Wiping old file."), - sizeof(g_stored_tags), size); - // Remove corrupted file - rdv40_spiffs_remove(HF_ST25TB_MULTI_SR_FILE, RDV40_SPIFFS_SAFETY_SAFE); - return false; - } - - // Read file contents - int res = rdv40_spiffs_read(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection, - size, RDV40_SPIFFS_SAFETY_SAFE); - - if (res != SPIFFS_OK) { - Dbprintf(_RED_("Failed to read tag collection from flash (err %d)"), res); - // Mark all as invalid if read failed - for (int i = 0; i < MAX_SAVED_TAGS; i++) - collection[i].data_valid = false; - return false; - } - - return true; -} - -/** - * @brief Save tag collection to flash - * @param collection Array of tag data to save - * @return true if successful, false otherwise - */ -static bool save_tags_to_flash(const st25tb_data_t collection[MAX_SAVED_TAGS]) { - int res = rdv40_spiffs_write(HF_ST25TB_MULTI_SR_FILE, (uint8_t *)collection, - sizeof(g_stored_tags), RDV40_SPIFFS_SAFETY_SAFE); - return (res == SPIFFS_OK); -} - -/** - * @brief Find a tag in the collection by UID - * @param uid UID to search for - * @return Index of tag in collection, or -1 if not found - */ -static int find_tag_by_uid(const uint64_t uid) { - for (int i = 0; i < MAX_SAVED_TAGS; i++) { - if (g_stored_tags[i].data_valid && g_stored_tags[i].uid == uid) { - return i; - } - } - return -1; // Not found -} - -/** - * @brief Find next empty slot in the collection - * @return Index of empty slot, or -1 if collection is full - */ -static int find_free_tag_slot(void) { - for (int i = 0; i < MAX_SAVED_TAGS; i++) { - if (!g_stored_tags[i].data_valid) { - return i; - } - } - return -1; // Collection is full -} - -//============================================================================= -// ISO14443B COMMUNICATION FUNCTIONS -//============================================================================= - -/** - * @brief Stripped version of "iso14443b_setup" that avoids unnecessary LED - * operations and uses shorter delays - */ -static void iso14443b_setup_light(void) { - RF_SWTICH_OFF(); - - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); - - // Set up the synchronous serial port - FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); - - // Signal field is on with the appropriate LED -#ifdef RDV4 - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD_RDV4); -#else - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); -#endif - - SpinDelayUs(250); - - // Start the timer - StartCountSspClk(); -} - -//============================================================================= -// TAG READ/WRITE OPERATIONS -//============================================================================= - -/** - * @brief Select a ST25TB tag and get basic info - * @param card_info Pointer to store card info - * @return true if successful, false otherwise - */ -static bool st25tb_tag_get_basic_info(iso14b_card_select_t *card_info) { - iso14443b_setup_light(); - int res = iso14443b_select_srx_card(card_info); - RF_SWTICH_OFF(); - return (res == PM3_SUCCESS); -} - -/** - * @brief Read all data from a ST25TB tag - * @param tag_data_slot Pointer to store tag data - * @return true if successful, false otherwise - */ -static bool st25tb_tag_read(st25tb_data_t *tag_data_slot) { - iso14443b_setup_light(); - iso14b_card_select_t card_info; - uint8_t block[ST25TB_BLOCK_SIZE]; - int res; - bool success = true; - - // Select card - res = iso14443b_select_srx_card(&card_info); - if (res != PM3_SUCCESS) { - RF_SWTICH_OFF(); - return false; - } - - Dbprintf("Found ST tag. Reading %d blocks...", ST25TB_BLOCK_COUNT); - tag_data_slot->uid = bytes_to_num_le(card_info.uid, sizeof(tag_data_slot->uid)); - - // Read all data blocks - for (uint8_t block_address = 0; block_address < ST25TB_BLOCK_COUNT; block_address++) { - WDT_HIT(); - res = read_14b_srx_block(block_address, block); - if (res != PM3_SUCCESS) { - Dbprintf(_RED_("Failed to read block %d"), block_address); - success = false; - break; - } - - // Store the read block data - tag_data_slot->blocks[block_address] = bytes_to_num_le(block, ST25TB_BLOCK_SIZE); - - if (g_dbglevel >= DBG_DEBUG) { - Dbprintf("Read Block %02d: %08X", block_address, tag_data_slot->blocks[block_address]); - } - SpinDelay(5); // Small delay between block reads - } - - // Read OTP block - res = read_14b_srx_block(255, block); - if (res != PM3_SUCCESS) { - Dbprintf(_RED_("Failed to read otp block")); - success = false; - } else { - tag_data_slot->otp = bytes_to_num_le(block, ST25TB_BLOCK_SIZE); - } - - RF_SWTICH_OFF(); - - tag_data_slot->data_valid = success; - return success; -} - -/** - * @brief Restore data to a ST25TB tag - * @param stored_data_slot Pointer to stored tag data - * @return true if successful, false otherwise - */ -static bool st25tb_tag_restore(const st25tb_data_t *stored_data_slot) { - if (!stored_data_slot->data_valid) { - DbpString(_RED_("Restore error: Slot data is invalid.")); - return false; - } - - iso14443b_setup_light(); - iso14b_card_select_t card_info; - int res; - bool success = true; - - res = iso14443b_select_srx_card(&card_info); - if (res != PM3_SUCCESS) { - DbpString("Restore failed: No tag found or selection failed."); - RF_SWTICH_OFF(); - return false; - } - - uint64_t tag_uid = bytes_to_num_le(card_info.uid, sizeof(uint64_t)); - - // Verify UID match before restoring - if (tag_uid != stored_data_slot->uid) { - Dbprintf("Restore failed: UID mismatch (Tag: %llX, Slot: %llX)", tag_uid, stored_data_slot->uid); - RF_SWTICH_OFF(); - return false; - } - - Dbprintf("Found ST tag, UID: %llX. Starting restore...", tag_uid); - - // Process all blocks - for (uint8_t block_address = 0; block_address < ST25TB_BLOCK_COUNT; block_address++) { - WDT_HIT(); - uint32_t stored_value = stored_data_slot->blocks[block_address]; - - if (g_dbglevel >= DBG_DEBUG) { - Dbprintf("Restoring Block %02d: %08X", block_address, stored_value); - } - - // Special handling for counter blocks 5 and 6 - if (block_address == ST25TB_COUNTER_BLOCK_5 || block_address == ST25TB_COUNTER_BLOCK_6) { - uint32_t current_value = 0; - - res = st25tb_tear_off_read_block(block_address, ¤t_value); - if (res != PM3_SUCCESS) { - Dbprintf(_RED_("Failed to read current counter value for block %d"), block_address); - success = false; - break; - } - - if (g_dbglevel >= DBG_DEBUG) { - Dbprintf("Counter Block %d: Stored=0x%08X, Current=0x%08X", - block_address, stored_value, current_value); - } - - // Only use tear-off logic if stored value is greater - if (stored_value > current_value) { - // The st25tb_tear_off_write_counter function handles the tear-off logic - if (st25tb_tear_off_write_counter(block_address, stored_value, TEAR_OFF_ADJUSTMENT_US, 0x1000) != 0) { - Dbprintf(_RED_("Tear-off write failed for counter block %d"), block_address); - success = false; - break; - } - Dbprintf("Used tear-off write for counter block %d", block_address); - } else if (stored_value < current_value) { - // Standard write for when stored value is less than current - if (!st25tb_write_block_with_retry(block_address, stored_value)) { - Dbprintf(_RED_("Failed to write block %d"), block_address); - success = false; - break; - } - } else { - Dbprintf("Counter block %d already has the target value (0x%08X). Skipping write.", - block_address, stored_value); - } - } else { - // Standard write for non-counter blocks - if (!st25tb_write_block_with_retry(block_address, stored_value)) { - Dbprintf(_RED_("Failed to write block %d with value 0x%08X"), block_address, stored_value); - success = false; - break; - } - } - SpinDelay(10); // Delay between writes - } - - RF_SWTICH_OFF(); - return success; -} - -/** - * @brief Print tag data in formatted table - * @param tag Pointer to tag data - */ -static void st25tb_tag_print(st25tb_data_t *tag) { - uint8_t i; - - Dbprintf("UID: %016llX", tag->uid); - - Dbprintf("+---------------+----------+--------------------+"); - Dbprintf("| BLOCK ADDRESS | VALUE | DESCRIPTION |"); - Dbprintf("+---------------+----------+--------------------+"); - - for (i = 0; i < 16; i++) { - if (i == 2) { - Dbprintf("| %03d | %08X | Lockable EEPROM |", i, tag->blocks[i]); - } else if (i == 5) { - Dbprintf("| %03d | %08X | Count down |", i, tag->blocks[i]); - } else if (i == 6) { - Dbprintf("| %03d | %08X | counter |", i, tag->blocks[i]); - } else if (i == 11) { - Dbprintf("| %03d | %08X | Lockable EEPROM |", i, tag->blocks[i]); - } else { - Dbprintf("| %03d | %08X | |", i, tag->blocks[i]); - } - if (i == 4 || i == 6 || i == 15) { - Dbprintf("+---------------+----------+--------------------+"); - } - } - - Dbprintf("| %03d | %08X | System OTP bits |", 255, tag->otp); - Dbprintf("+---------------+----------+--------------------+"); -} - -//============================================================================= -// TEAR-OFF OPERATIONS -//============================================================================= - -/** - * @brief Read a block - * @param block_address Block address to read - * @param block_value Pointer to store read value - * @return Result code (0 for success) - */ -static int st25tb_tear_off_read_block(uint8_t block_address, uint32_t *block_value) { - int res; - iso14b_card_select_t card; - iso14443b_setup_light(); - - res = iso14443b_select_srx_card(&card); - if (res != PM3_SUCCESS) { - goto out; - } - - uint8_t block[ST25TB_BLOCK_SIZE]; - res = read_14b_srx_block(block_address, block); - if (res == PM3_SUCCESS) { - *block_value = bytes_to_num_le(block, ST25TB_BLOCK_SIZE); - } - -out: - RF_SWTICH_OFF(); - return res; -} - -/** - * @brief Low-level block write function - * @param block_address Block number to write - * @param block Block data - * @return Result code (0 for success) - */ -static int st25tb_cmd_write_block(uint8_t block_address, uint8_t *block) { - uint8_t cmd[] = {ISO14443B_WRITE_BLK, block_address, block[0], block[1], block[2], block[3], 0x00, 0x00}; - AddCrc14B(cmd, 6); - - uint32_t start_time = 0; - uint32_t eof_time = 0; - CodeAndTransmit14443bAsReader(cmd, sizeof(cmd), &start_time, &eof_time, true); - - return PM3_SUCCESS; -} - -/** - * @brief Write a block with retry mechanism - * @param block_address Block number to write - * @param target_value Value to write - * @return true if successful, false otherwise - */ -static bool st25tb_write_block_with_retry(uint8_t block_address, uint32_t target_value) { - uint32_t read_back_value = 0; - int max_retries = 5; - - if (st25tb_tear_off_retry_write_verify(block_address, target_value, max_retries, 0, &read_back_value) != 0) { - return false; - } - - return (read_back_value == target_value); -} - -/** - * @brief Write a block with tear-off capability - * @param block_address Block number to write - * @param data Data to write - * @param tearoff_delay_us Tear-off delay in microseconds - */ -static void st25tb_tear_off_write_block(uint8_t block_address, uint32_t data, uint16_t tearoff_delay_us) { - iso14443b_setup_light(); - - uint8_t block[ST25TB_BLOCK_SIZE]; - block[0] = (data & 0xFF); - block[1] = (data >> 8) & 0xFF; - block[2] = (data >> 16) & 0xFF; - block[3] = (data >> 24) & 0xFF; - - iso14b_card_select_t card; - int res = iso14443b_select_srx_card(&card); - if (res != PM3_SUCCESS) { - goto out; - } - - res = st25tb_cmd_write_block(block_address, block); - - // Tear off the communication at precise timing - SpinDelayUsPrecision(tearoff_delay_us); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - -out: - RF_SWTICH_OFF(); -} - -/** - * @brief Write a block with retry and verification - * @param block_address Block address to write - * @param target_value Value to write - * @param max_try_count Maximum number of retries - * @param sleep_time_ms Sleep time between retries in milliseconds - * @param read_back_value Pointer to store read-back value - * @return 0 for success, -1 for failure - */ -static int8_t st25tb_tear_off_retry_write_verify(uint8_t block_address, uint32_t target_value, - uint32_t max_try_count, int sleep_time_ms, - uint32_t *read_back_value) { - int i = 0; - *read_back_value = ~target_value; // Initialize to ensure the loop runs at least once - - while (*read_back_value != target_value && i < max_try_count) { - st25tb_tear_off_write_block(block_address, target_value, 6000); // Long delay for reliability - if (sleep_time_ms > 0) SpinDelayUsPrecision(sleep_time_ms * 1000); - st25tb_tear_off_read_block(block_address, read_back_value); - if (sleep_time_ms > 0) SpinDelayUsPrecision(sleep_time_ms * 1000); - i++; - } - - return (*read_back_value == target_value) ? 0 : -1; -} - -/** - * @brief Check if a block's value is consolidated (stable) - * @param block_address Block address to check - * @param value Expected value - * @param repeat_read Number of reads to perform - * @param sleep_time_ms Sleep time between reads in milliseconds - * @param read_value Pointer to store read value - * @return 0 if consolidated, -1 otherwise - */ -static int8_t st25tb_tear_off_is_consolidated(const uint8_t block_address, uint32_t value, - int repeat_read, int sleep_time_ms, - uint32_t *read_value) { - int result; - for (int i = 0; i < repeat_read; i++) { - if (sleep_time_ms > 0) SpinDelayUsPrecision(sleep_time_ms * 1000); - result = st25tb_tear_off_read_block(block_address, read_value); - if (result != 0 || value != *read_value) { - return -1; // Read error or value changed - } - } - return 0; // Value remained stable -} - -/** - * @brief Consolidate a block to a stable state - * @param block_address Block address to consolidate - * @param current_value Current value - * @param target_value Target value - * @param read_back_value Pointer to store read-back value - * @return 0 for success, -1 for failure - */ -static int8_t st25tb_tear_off_consolidate_block(const uint8_t block_address, uint32_t current_value, - uint32_t target_value, uint32_t *read_back_value) { - int8_t result; - uint32_t consolidation_value; - - // Determine the value to write for consolidation based on target and current state - if (target_value <= 0xFFFFFFFD && current_value >= (target_value + 2)) { - consolidation_value = target_value + 2; - } else { - consolidation_value = current_value; - } - - // Try writing value - 1 - result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 1, - TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value); - if (result != 0) { - Dbprintf("Consolidation failed at step 1 (write 0x%08X)", consolidation_value - 1); - return -1; - } - - // If value is not FE or target is not FD, try writing value - 2 - if (*read_back_value != 0xFFFFFFFE || (*read_back_value == 0xFFFFFFFE && target_value == 0xFFFFFFFD)) { - result = st25tb_tear_off_retry_write_verify(block_address, consolidation_value - 2, - TEAR_OFF_WRITE_RETRY_COUNT, 0, read_back_value); - if (result != 0) { - Dbprintf("Consolidation failed at step 2 (write 0x%08X)", consolidation_value - 2); - return -1; - } - } - - // Final checks for stability of unstable high values (due to internal dual counters) - if (result == 0 && target_value > 0xFFFFFFFD && *read_back_value > 0xFFFFFFFD) { - result = st25tb_tear_off_is_consolidated(block_address, *read_back_value, - TEAR_OFF_CONSOLIDATE_READ_COUNT, 0, read_back_value); - if (result == 0) { - result = st25tb_tear_off_is_consolidated(block_address, *read_back_value, - TEAR_OFF_CONSOLIDATE_WAIT_READ_COUNT, - TEAR_OFF_CONSOLIDATE_WAIT_MS, read_back_value); - if (result != 0) { - Dbprintf("Consolidation failed stability check (long wait)"); - return -1; - } - } else { - Dbprintf("Consolidation failed stability check (short wait)"); - return -1; - } - } - - return 0; -} - -/** - * @brief Calculate next value for counter decrement - * @param current_value Current counter value - * @param randomness Whether to use randomization - * @return Next value to attempt - */ -static uint32_t st25tb_tear_off_next_value(uint32_t current_value, bool randomness) { - uint32_t value = 0; - int8_t index = 31; - - // Simple decrement for smaller values - if (current_value < 0x0000FFFF) { - return (current_value > 0) ? current_value - 1 : 0; - } - - // Loop through each bit starting from the most significant bit (MSB) - while (index >= 0) { - // Find the most significant '1' bit - if (value == 0 && IS_ONE_BIT(current_value, index)) { - // Create a mask with '1's up to this position - value = 0xFFFFFFFF >> (31 - index); - index--; // Move to the next bit - } - - // Once the first '1' is found, look for the first '0' after it - if (value != 0 && IS_ZERO_BIT(current_value, index)) { - index++; // Go back to the position of the '0' - // Clear the bit at this '0' position in our mask - value &= ~((uint32_t)1 << index); - - // Optional randomization: flip a random bit below the found '0' - if (randomness && value < 0xF0000000 && index > 1) { - value ^= ((uint32_t)1 << (dummy_rand() % index)); - } - return value; - } - - index--; - } - - return (current_value > 0) ? current_value - 1 : 0; -} - -/** - * @brief Adjust timing for tear-off operations - * @param tear_off_us Pointer to current tear-off timing - * @param tear_off_adjustment_us Adjustment amount - */ -static void st25tb_tear_off_adjust_timing(int *tear_off_us, uint32_t tear_off_adjustment_us) { - if (*tear_off_us > TEAR_OFF_START_OFFSET_US) { - *tear_off_us -= tear_off_adjustment_us; - } -} - -/** - * @brief Log tear-off operation details - * @param tear_off_us Current tear-off timing - * @param color Color code for output - * @param value Value being processed - */ -static void st25tb_tear_off_log(int tear_off_us, char *color, uint32_t value) { - char binaryRepresentation[33]; - for (int i = 31; i >= 0; i--) { - binaryRepresentation[31 - i] = IS_ONE_BIT(value, i) ? '1' : '0'; - } - binaryRepresentation[32] = '\0'; - Dbprintf("%s%08X%s : %s%s%s : %d us", color, value, RESET, color, binaryRepresentation, RESET, tear_off_us); -} - -/** - * @brief Main tear-off counter write function - * @param block_address Block address to write - * @param target_value Target value - * @param tear_off_adjustment_us Adjustment for tear-off timing - * @param safety_value Safety threshold to prevent going below - * @return 0 for success, non-zero for failure - */ -static int8_t st25tb_tear_off_write_counter(uint8_t block_address, uint32_t target_value, - uint32_t tear_off_adjustment_us, uint32_t safety_value) { - int result; - bool trigger = true; - - uint32_t read_value = 0; - uint32_t current_value = 0; - uint32_t last_consolidated_value = 0; - uint32_t tear_off_value = 0; - - int tear_off_us = TEAR_OFF_START_OFFSET_US; - if (tear_off_adjustment_us == 0) { - tear_off_adjustment_us = TEAR_OFF_ADJUSTMENT_US; - } - - // Initial read to get the current counter value - result = st25tb_tear_off_read_block(block_address, ¤t_value); - if (result != PM3_SUCCESS) { - Dbprintf("Initial read failed for block %d", block_address); - return -1; // Indicate failure - } - - // Calculate the first value to attempt writing via tear-off - tear_off_value = st25tb_tear_off_next_value(current_value, false); - - Dbprintf(" Target block: %d", block_address); - Dbprintf("Current value: 0x%08X", current_value); - Dbprintf(" Target value: 0x%08X", target_value); - Dbprintf(" Safety value: 0x%08X", safety_value); - Dbprintf("Adjustment us: %u", tear_off_adjustment_us); - - // Check if tear-off is even possible or needed - if (tear_off_value == 0 && current_value != 0) { - Dbprintf("Tear-off technique not possible from current value."); - return -1; - } - if (current_value == target_value) { - Dbprintf("Current value already matches target value."); - return 0; - } - - // Main tear-off loop - for (;;) { - // Safety check: ensure we don't go below the safety threshold - if (tear_off_value < safety_value) { - Dbprintf("Stopped. Safety threshold reached (next value 0x%08X < safety 0x%08X)", - tear_off_value, safety_value); - return -1; - } - - // Perform the tear-off write attempt - st25tb_tear_off_write_block(block_address, tear_off_value, tear_off_us); - - // Read back the value after the attempt - result = st25tb_tear_off_read_block(block_address, &read_value); - if (result != 0) { - continue; // Retry the loop if read fails (ex: tag is removed from the read for a short period) - } - - // Analyze the result and decide next action - if (read_value > current_value) { - // Partial write succeeded (successful tear-off) - if (read_value >= 0xFFFFFFFE || - (read_value - 2) > target_value || - read_value != last_consolidated_value || - ((read_value & 0xF0000000) > (current_value & 0xF0000000))) { // Major bit flip - - result = st25tb_tear_off_consolidate_block(block_address, read_value, - target_value, ¤t_value); - if (result == 0 && current_value == target_value) { - st25tb_tear_off_log(tear_off_us, GREEN, read_value); - Dbprintf("Target value 0x%08X reached successfully!", target_value); - return 0; - } - if (read_value != last_consolidated_value) { - st25tb_tear_off_adjust_timing(&tear_off_us, tear_off_adjustment_us); - } - last_consolidated_value = read_value; - tear_off_value = st25tb_tear_off_next_value(current_value, false); - trigger = true; - st25tb_tear_off_log(tear_off_us, GREEN, read_value); - } - } else if (read_value == tear_off_value) { - // Write succeeded completely (no tear-off effect) - if (trigger) { - tear_off_value = st25tb_tear_off_next_value(tear_off_value, true); - trigger = false; - } else { - tear_off_value = st25tb_tear_off_next_value(read_value, false); - trigger = true; - } - current_value = read_value; - st25tb_tear_off_adjust_timing(&tear_off_us, tear_off_adjustment_us); - st25tb_tear_off_log(tear_off_us, BLUE, read_value); - } else if (read_value < tear_off_value) { - // Partial write succeeded (successful tear-off) but lower value - tear_off_value = st25tb_tear_off_next_value(read_value, false); - st25tb_tear_off_adjust_timing(&tear_off_us, tear_off_adjustment_us); - current_value = read_value; - trigger = true; - st25tb_tear_off_log(tear_off_us, RED, read_value); - } - - // Increment tear-off timing for the next attempt - tear_off_us++; - - // Check for user interruption - WDT_HIT(); - if (BUTTON_PRESS()) { - DbpString("Tear-off stopped by user."); - return -1; - } - } - - return -1; -} - -//============================================================================= -// MAIN APPLICATION FUNCTIONS -//============================================================================= - -/** - * @brief Learn/store function implementation - */ -static void run_learn_function(void) { - st25tb_data_t temp_tag_data; // Temporary buffer to read into - memset(&temp_tag_data, 0, sizeof(temp_tag_data)); - - if (st25tb_tag_read(&temp_tag_data)) { - st25tb_tag_print(&temp_tag_data); - int slot_index = find_tag_by_uid(temp_tag_data.uid); - - if (slot_index != -1) { - Dbprintf("Tag with UID %llX already in Slot %d. Overwriting...", - temp_tag_data.uid, slot_index); - } else { - slot_index = find_free_tag_slot(); - if (slot_index == -1) { - DbpString("Collection full! Overwriting Slot 0."); - slot_index = 0; // Overwrite oldest/first slot if full - } else { - // Only increment if we are adding to a new slot, not overwriting - if (!g_stored_tags[slot_index].data_valid) { - g_valid_tag_count++; - } - } - } - - // Store tag data in collection - memcpy(&g_stored_tags[slot_index], &temp_tag_data, sizeof(st25tb_data_t)); - g_stored_tags[slot_index].data_valid = true; - Dbprintf("Stored tag in Slot %d. (UID: %llX)", slot_index, temp_tag_data.uid); - - // Save collection to flash - if (save_tags_to_flash(g_stored_tags)) { - DbpString("Collection saved to flash."); - } else { - DbpString(_RED_("Failed to save collection to flash!")); - } - - current_state = STATE_DONE; // Indicate success - } -} - -/** - * @brief Restore function implementation - */ -static void run_restore_function(void) { - iso14b_card_select_t current_tag_info; // To get UID of tag in field - - if (st25tb_tag_get_basic_info(¤t_tag_info)) { - // Tag found in field - uint64_t tag_uid = bytes_to_num_le(current_tag_info.uid, sizeof(uint64_t)); - int slot = find_tag_by_uid(tag_uid); - - if (slot != -1) { - Dbprintf("Found matching tag in Slot %d (UID: %llX). Restoring...", slot, tag_uid); - - current_state = STATE_BUSY; // Indicate busy during restore attempt - update_leds_mode(g_current_mode); - - bool success = st25tb_tag_restore(&g_stored_tags[slot]); - - if (success) { - DbpString(_GREEN_("Restore successful.")); - current_state = STATE_DONE; - } else { - DbpString(_RED_("Restore failed.")); - current_state = STATE_ERROR; - } - } else { - // Tag found but not in collection, remain busy to scan again - current_state = STATE_BUSY; - } - } else { - // No tag found, remain busy to scan again - current_state = STATE_BUSY; - } -} - -/** - * @brief Display module information - */ -void ModInfo(void) { - DbpString(" HF ST25TB Store/Restore"); - Dbprintf(" Data stored/restored from: %s", HF_ST25TB_MULTI_SR_FILE); - Dbprintf(" Supports up to %d tag slots.", MAX_SAVED_TAGS); -} - -/** - * @brief Main module function - */ -void RunMod(void) { - StandAloneMode(); - Dbprintf(_YELLOW_("HF ST25TB Store/Restore mode started")); - iso14443b_setup(); - LED_D_OFF(); - FpgaDownloadAndGo(FPGA_BITSTREAM_HF); // Use HF bitstream for ISO14443B - - // Initialize collection - for (int i = 0; i < MAX_SAVED_TAGS; i++) { - g_stored_tags[i].data_valid = false; - } - g_valid_tag_count = 0; - - // Mount filesystem and load previous tags if available - rdv40_spiffs_lazy_mount(); - if (load_tags_from_flash(g_stored_tags)) { - DbpString("Loaded previous tag collection from flash."); - // Count valid entries loaded - for (int i = 0; i < MAX_SAVED_TAGS; i++) { - if (g_stored_tags[i].data_valid) - g_valid_tag_count++; - } - g_current_mode = MODE_RESTORE; // Default to restore if data exists - } else { - DbpString("No previous tag data found in flash or error loading."); - g_current_mode = MODE_LEARN; // Default to store if no data - } - - bool mode_display_update = true; // Force initial display - current_state = STATE_BUSY; // Reset state at the beginning - - // Main application loop - for (;;) { - WDT_HIT(); - - // Exit condition: USB command received - if (data_available()) { - DbpString("USB data detected, exiting standalone mode."); - break; - } - - // --- Button Handling --- - int button_status = BUTTON_HELD(1000); // Check for 1 second hold - - if (button_status == BUTTON_HOLD) { - DbpString("Button held, exiting standalone mode."); - break; - } else if (button_status == BUTTON_SINGLE_CLICK) { - // Toggle between modes - g_current_mode = (g_current_mode == MODE_LEARN) ? MODE_RESTORE : MODE_LEARN; - current_state = STATE_BUSY; // Reset state when changing mode - mode_display_update = true; - SpinDelay(100); // Debounce/allow user to see mode change - } - - // --- Update Display (only if mode changed) --- - if (mode_display_update) { - if (g_current_mode == MODE_LEARN) { - Dbprintf("Mode: " _YELLOW_("Learn") ". (Cnt: %d/%d)", - g_valid_tag_count, MAX_SAVED_TAGS); - } else { - Dbprintf("Mode: " _BLUE_("Restore") ". (Cnt: %d/%d)", - g_valid_tag_count, MAX_SAVED_TAGS); - } - mode_display_update = false; - } - update_leds_mode(g_current_mode); - - // Process according to current state - if (current_state == STATE_BUSY) { - // Run appropriate function based on mode - if (g_current_mode == MODE_LEARN) { - run_learn_function(); - } else { // MODE_RESTORE - run_restore_function(); - } - } else if (current_state == STATE_DONE) { - indicate_success(); - } else { - indicate_failure(); - } - - // Loop delay - SpinDelay(100); - } - - // Clean up before exiting - LED_D_ON(); // Indicate potentially saving state on exit - rdv40_spiffs_lazy_unmount(); - LED_D_OFF(); - - switch_off(); // Turn off RF field - LEDsoff(); - DbpString("Exiting " _YELLOW_("HF ST25TB Store/Restore") " mode."); -} diff --git a/armsrc/Standalone/hf_tcprst.c b/armsrc/Standalone/hf_tcprst.c index d8ced29d4..e6f75bc75 100644 --- a/armsrc/Standalone/hf_tcprst.c +++ b/armsrc/Standalone/hf_tcprst.c @@ -118,6 +118,8 @@ void RunMod(void) { uint8_t tagType = 10; // 10 = ST25TA IKEA Rothult tag_response_info_t *responses; uint32_t cuid = 0; + uint32_t counters[3] = { 0x00, 0x00, 0x00 }; + uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd }; uint8_t pages = 0; // command buffers @@ -191,7 +193,7 @@ void RunMod(void) { memcpy(data, stuid, sizeof(stuid)); - if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &responses, &cuid, &pages, NULL) == false) { + if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &responses, &cuid, counters, tearings, &pages) == false) { BigBuf_free_keep_EM(); reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0); DbpString(_YELLOW_("!!") "Error initializing the simulation process!"); @@ -369,7 +371,7 @@ void RunMod(void) { memcpy(data, stuid, sizeof(stuid)); - if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &responses, &cuid, &pages, NULL) == false) { + if (SimulateIso14443aInit(tagType, flags, data, NULL, 0, &responses, &cuid, counters, tearings, &pages) == false) { BigBuf_free_keep_EM(); reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0); DbpString(_YELLOW_("!!") "Error initializing the simulation process!"); diff --git a/armsrc/Standalone/hf_young.c b/armsrc/Standalone/hf_young.c index 83ad1999a..62d215dba 100644 --- a/armsrc/Standalone/hf_young.c +++ b/armsrc/Standalone/hf_young.c @@ -96,7 +96,7 @@ void RunMod(void) { } } - if (iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true) == 0) { + if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); SpinDelay(500); @@ -253,25 +253,25 @@ void RunMod(void) { if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0) { DbpString("Mifare Classic 1k"); - SimulateIso14443aTag(1, flags, data, 0, NULL, 0, false, false); + SimulateIso14443aTag(1, flags, data, 0, NULL, 0); } else if (uids[selected].sak == 0x18 && uids[selected].atqa[0] == 0x02 && uids[selected].atqa[1] == 0) { DbpString("Mifare Classic 4k (4b uid)"); - SimulateIso14443aTag(8, flags, data, 0, NULL, 0, false, false); + SimulateIso14443aTag(8, flags, data, 0, NULL, 0); } else if (uids[selected].sak == 0x08 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) { DbpString("Mifare Classic 4k (7b uid)"); - SimulateIso14443aTag(8, flags, data, 0, NULL, 0, false, false); + SimulateIso14443aTag(8, flags, data, 0, NULL, 0); } else if (uids[selected].sak == 0x00 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0) { DbpString("Mifare Ultralight"); - SimulateIso14443aTag(2, flags, data, 0, NULL, 0, false, false); + SimulateIso14443aTag(2, flags, data, 0, NULL, 0); } else if (uids[selected].sak == 0x20 && uids[selected].atqa[0] == 0x04 && uids[selected].atqa[1] == 0x03) { DbpString("Mifare DESFire"); - SimulateIso14443aTag(3, flags, data, 0, NULL, 0, false, false); + SimulateIso14443aTag(3, flags, data, 0, NULL, 0); } else if (uids[selected].sak == 0x20 && uids[selected].atqa[0] == 0x44 && uids[selected].atqa[1] == 0x03) { DbpString("Mifare DESFire Ev1/Plus/JCOP"); - SimulateIso14443aTag(3, flags, data, 0, NULL, 0, false, false); + SimulateIso14443aTag(3, flags, data, 0, NULL, 0); } else { Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation"); - SimulateIso14443aTag(1, flags, data, 0, NULL, 0, false, false); + SimulateIso14443aTag(1, flags, data, 0, NULL, 0); } } else if (button_pressed == BUTTON_SINGLE_CLICK) { diff --git a/armsrc/appmain.c b/armsrc/appmain.c index db16394ab..49005a43d 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -99,13 +99,12 @@ int tearoff_hook(void) { if (g_tearoff_enabled) { if (g_tearoff_delay_us == 0) { Dbprintf(_RED_("No tear-off delay configured!")); - g_tearoff_enabled = false; return PM3_SUCCESS; // SUCCESS = the hook didn't do anything } SpinDelayUsPrecision(g_tearoff_delay_us); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); g_tearoff_enabled = false; - if (g_dbglevel >= DBG_ERROR) Dbprintf(_YELLOW_("Tear-off triggered!")); + Dbprintf(_YELLOW_("Tear-off triggered!")); return PM3_ETEAROFF; } else { return PM3_SUCCESS; // SUCCESS = the hook didn't do anything @@ -255,7 +254,7 @@ static uint32_t MeasureAntennaTuningLfData(void) { void print_stack_usage(void) { for (uint32_t *p = _stack_start; ; ++p) { if (*p != 0xdeadbeef) { - Dbprintf(" Max stack usage..... %d / %d bytes", (uint32_t)_stack_end - (uint32_t)p, (uint32_t)_stack_end - (uint32_t)_stack_start); + Dbprintf(" Max stack usage......... %d / %d bytes", (uint32_t)_stack_end - (uint32_t)p, (uint32_t)_stack_end - (uint32_t)_stack_start); break; } } @@ -366,7 +365,7 @@ static void print_debug_level(void) { sprintf(dbglvlstr, "extended"); break; } - Dbprintf(" Debug log level..... %d ( " _YELLOW_("%s")" )", g_dbglevel, dbglvlstr); + Dbprintf(" Debug log level......... %d ( " _YELLOW_("%s")" )", g_dbglevel, dbglvlstr); } // measure the Connection Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. @@ -422,11 +421,11 @@ static void SendStatus(uint32_t wait) { print_debug_level(); tosend_t *ts = get_tosend(); - Dbprintf(" ToSendMax........... %d", ts->max); - Dbprintf(" ToSend BUFFERSIZE... %d", TOSEND_BUFFER_SIZE); + Dbprintf(" ToSendMax............... %d", ts->max); + Dbprintf(" ToSend BUFFERSIZE....... %d", TOSEND_BUFFER_SIZE); while ((AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINRDY) == 0); // Wait for MAINF value to become available... uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINF; // Get # main clocks within 16 slow clocks - Dbprintf(" Slow clock.......... %d Hz", (16 * MAINCK) / mainf); + Dbprintf(" Slow clock.............. %d Hz", (16 * MAINCK) / mainf); uint32_t delta_time = 0; uint32_t start_time = GetTickCount(); #define SLCK_CHECK_MS 50 @@ -450,11 +449,10 @@ static void SendStatus(uint32_t wait) { } else { num = 0; } - if (num > 0) { - Dbprintf(" Mifare... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, MF_KEYS_FILE); + Dbprintf(" Mifare.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, MF_KEYS_FILE); } else { - Dbprintf(" Mifare... "_RED_("%u")" keys - "_RED_("%s"), num, MF_KEYS_FILE); + Dbprintf(" Mifare.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, MF_KEYS_FILE); } if (exists_in_spiffs(T55XX_KEYS_FILE)) { @@ -462,11 +460,10 @@ static void SendStatus(uint32_t wait) { } else { num = 0; } - if (num > 0) { - Dbprintf(" T55xx.... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, T55XX_KEYS_FILE); + Dbprintf(" T55xx................... "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, T55XX_KEYS_FILE); } else { - Dbprintf(" T55xx.... "_RED_("%u")" keys - "_RED_("%s"), num, T55XX_KEYS_FILE); + Dbprintf(" T55xx................... "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, T55XX_KEYS_FILE); } if (exists_in_spiffs(ICLASS_KEYS_FILE)) { @@ -474,38 +471,11 @@ static void SendStatus(uint32_t wait) { } else { num = 0; } - if (num > 0) { - Dbprintf(" iClass... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, ICLASS_KEYS_FILE); + Dbprintf(" iClass.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, ICLASS_KEYS_FILE); } else { - Dbprintf(" iClass... "_RED_("%u")" keys - "_RED_("%s"), num, ICLASS_KEYS_FILE); + Dbprintf(" iClass.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, ICLASS_KEYS_FILE); } - - if (exists_in_spiffs(MFULC_KEYS_FILE)) { - num = size_in_spiffs(MFULC_KEYS_FILE) / MFULC_KEY_LENGTH; - } else { - num = 0; - } - - if (num > 0) { - Dbprintf(" UL-C..... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, MFULC_KEYS_FILE); - } else { - Dbprintf(" UL-C..... "_RED_("%u")" keys - "_RED_("%s"), num, MFULC_KEYS_FILE); - } - - if (exists_in_spiffs(MFULAES_KEYS_FILE)) { - num = size_in_spiffs(MFULAES_KEYS_FILE) / MFULAES_KEY_LENGTH; - } else { - num = 0; - } - - if (num > 0) { - Dbprintf(" UL-AES... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, MFULAES_KEYS_FILE); - } else { - Dbprintf(" UL-AES... "_RED_("%u")" keys - "_RED_("%s"), num, MFULAES_KEYS_FILE); - } - - #endif DbpString(""); reply_ng(CMD_STATUS, PM3_SUCCESS, NULL, 0); @@ -1694,13 +1664,13 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ISO14443A_GET_CONFIG: { - hf14a_config_t *c = getHf14aConfig(); - reply_ng(CMD_HF_ISO14443A_GET_CONFIG, PM3_SUCCESS, (uint8_t *)c, sizeof(hf14a_config_t)); + hf14a_config *hf14aconfig = getHf14aConfig(); + reply_ng(CMD_HF_ISO14443A_GET_CONFIG, PM3_SUCCESS, (uint8_t *)hf14aconfig, sizeof(hf14a_config)); break; } case CMD_HF_ISO14443A_SET_CONFIG: { - hf14a_config_t c; - memcpy(&c, packet->data.asBytes, sizeof(hf14a_config_t)); + hf14a_config c; + memcpy(&c, packet->data.asBytes, sizeof(hf14a_config)); setHf14aConfig(&c); break; } @@ -1749,13 +1719,10 @@ static void PacketReceived(PacketCommandNG *packet) { uint8_t uid[10]; uint8_t exitAfter; uint8_t rats[20]; - bool ulc_p1; - bool ulc_p2; } PACKED; struct p *payload = (struct p *) packet->data.asBytes; SimulateIso14443aTag(payload->tagtype, payload->flags, payload->uid, - payload->exitAfter, payload->rats, sizeof(payload->rats), - payload->ulc_p1, payload->ulc_p2); // ## Simulate iso14443a tag - pass tag type & UID + payload->exitAfter, payload->rats, sizeof(payload->rats)); // ## Simulate iso14443a tag - pass tag type & UID break; } case CMD_HF_ISO14443A_SIM_AID: { @@ -1839,7 +1806,7 @@ static void PacketReceived(PacketCommandNG *packet) { struct p { bool turn_off_field; uint8_t keyno; - uint8_t key[16]; + uint8_t key[18]; } PACKED; struct p *payload = (struct p *) packet->data.asBytes; MifareUL_AES_Auth(payload->turn_off_field, payload->keyno, payload->key); @@ -2002,7 +1969,7 @@ static void PacketReceived(PacketCommandNG *packet) { struct p *payload = (struct p *) packet->data.asBytes; // - size_t size = payload->blockcnt * payload->blockwidth; + size_t size = payload->blockno * payload->blockwidth; if (size > PM3_CMD_DATA_SIZE) { reply_ng(CMD_HF_MIFARE_EML_MEMGET, PM3_EMALLOC, NULL, 0); return; @@ -2259,10 +2226,6 @@ static void PacketReceived(PacketCommandNG *packet) { iclass_credit_epurse((iclass_credit_epurse_t *)packet->data.asBytes); break; } - case CMD_HF_ICLASS_TEARBL: { - iClass_TearBlock((iclass_tearblock_req_t *)packet->data.asBytes); - break; - } #endif #ifdef WITH_HFSNIFF @@ -2391,7 +2354,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint16_t available; uint16_t pre_available = 0; - uint8_t *dest = BigBuf_calloc(USART_FIFOLEN); + uint8_t *dest = BigBuf_malloc(USART_FIFOLEN); uint32_t wait = payload->waittime; StartTicks(); @@ -2435,7 +2398,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint16_t available; uint16_t pre_available = 0; - uint8_t *dest = BigBuf_calloc(USART_FIFOLEN); + uint8_t *dest = BigBuf_malloc(USART_FIFOLEN); uint32_t wait = payload->waittime; StartTicks(); @@ -2731,7 +2694,7 @@ static void PacketReceived(PacketCommandNG *packet) { uint32_t size = packet->oldarg[1]; - uint8_t *buff = BigBuf_calloc(size); + uint8_t *buff = BigBuf_malloc(size); if (buff == NULL) { if (g_dbglevel >= DBG_DEBUG) Dbprintf("Failed to allocate memory"); // Trigger a finish downloading signal with an PM3_EMALLOC @@ -2936,7 +2899,7 @@ static void PacketReceived(PacketCommandNG *packet) { case CMD_FLASHMEM_DOWNLOAD: { LED_B_ON(); - uint8_t *mem = BigBuf_calloc(PM3_CMD_DATA_SIZE); + uint8_t *mem = BigBuf_malloc(PM3_CMD_DATA_SIZE); uint32_t startidx = packet->oldarg[0]; uint32_t numofbytes = packet->oldarg[1]; // arg0 = startindex @@ -2968,7 +2931,7 @@ static void PacketReceived(PacketCommandNG *packet) { case CMD_FLASHMEM_INFO: { LED_B_ON(); - rdv40_validation_t *info = (rdv40_validation_t *)BigBuf_calloc(sizeof(rdv40_validation_t)); + rdv40_validation_t *info = (rdv40_validation_t *)BigBuf_malloc(sizeof(rdv40_validation_t)); bool isok = Flash_ReadData(FLASH_MEM_SIGNATURE_OFFSET_P(spi_flash_pages64k), info->signature, FLASH_MEM_SIGNATURE_LEN); diff --git a/armsrc/dbprint.c b/armsrc/dbprint.c index 687bdfb90..42d96fc3e 100644 --- a/armsrc/dbprint.c +++ b/armsrc/dbprint.c @@ -102,7 +102,9 @@ void Dbhexdump(int len, const uint8_t *d, bool bAsci) { } #endif } -void print_result(const char *name, const uint8_t *d, size_t n) { +void print_result(const char *name, const uint8_t *d, size_t + + n) { const uint8_t *p = d; uint16_t tmp = n & 0xFFF0; diff --git a/armsrc/em4x50.c b/armsrc/em4x50.c index 8de00ccae..095ae4240 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -748,7 +748,7 @@ void em4x50_chk(const char *filename, bool ledcontrol) { uint16_t pwd_count = 0; uint32_t size = size_in_spiffs(filename); pwd_count = size / 4; - uint8_t *pwds = BigBuf_calloc(size); + uint8_t *pwds = BigBuf_malloc(size); rdv40_spiffs_read_as_filetype(filename, pwds, size, RDV40_SPIFFS_SAFETY_SAFE); diff --git a/armsrc/em4x70.c b/armsrc/em4x70.c index ca56a8c2a..4c2e01ded 100644 --- a/armsrc/em4x70.c +++ b/armsrc/em4x70.c @@ -45,7 +45,7 @@ #define DPRINTF_EXTENDED(x) do { if ((FORCE_ENABLE_LOGGING) || (g_dbglevel >= DBG_EXTENDED)) { Dbprintf x ; } } while (0); #define DPRINTF_PROLIX(x) do { if ((FORCE_ENABLE_LOGGING) || (g_dbglevel > DBG_EXTENDED)) { Dbprintf x ; } } while (0); // EM4170 requires a parity bit on commands, other variants do not. -static bool g_deprecated_command_parity = false; +static bool g_command_parity = true; static em4x70_tag_t g_tag = { 0 }; @@ -905,7 +905,8 @@ static bool create_legacy_em4x70_bitstream_for_cmd_id(em4x70_command_bitstream_t bool result = true; memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); out_cmd_bitstream->command = EM4X70_COMMAND_ID; - uint8_t cmd = 0x3u; // CMD + Parity bit == 0b001'1 + //uint8_t cmd = with_command_parity ? 0x3u : 0x1u; + uint8_t cmd = 0x3u; result = result && add_nibble_to_bitstream(&out_cmd_bitstream->to_send, cmd, false); out_cmd_bitstream->to_receive.bitcount = 32; if (out_cmd_bitstream->to_send.bitcount != expected_bits_to_send) { @@ -919,7 +920,8 @@ static bool create_legacy_em4x70_bitstream_for_cmd_um1(em4x70_command_bitstream_ bool result = true; memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); out_cmd_bitstream->command = EM4X70_COMMAND_UM1; - uint8_t cmd = 0x5u; // CMD + Parity bit == 0b010'1 + //uint8_t cmd = with_command_parity ? 0x5u : 0x2u; + uint8_t cmd = 0x5u; result = result && add_nibble_to_bitstream(&out_cmd_bitstream->to_send, cmd, false); out_cmd_bitstream->to_receive.bitcount = 32; if (out_cmd_bitstream->to_send.bitcount != expected_bits_to_send) { @@ -933,7 +935,8 @@ static bool create_legacy_em4x70_bitstream_for_cmd_um2(em4x70_command_bitstream_ bool result = true; memset(out_cmd_bitstream, 0, sizeof(em4x70_command_bitstream_t)); out_cmd_bitstream->command = EM4X70_COMMAND_UM2; - uint8_t cmd = 0xFu; // CMD + Parity bit == 0b111'1 + //uint8_t cmd = with_command_parity ? 0xFu : 0x7u; + uint8_t cmd = 0xFu; result = result && add_nibble_to_bitstream(&out_cmd_bitstream->to_send, cmd, false); out_cmd_bitstream->to_receive.bitcount = 64; if (out_cmd_bitstream->to_send.bitcount != expected_bits_to_send) { @@ -951,7 +954,8 @@ static bool create_legacy_em4x70_bitstream_for_cmd_auth(em4x70_command_bitstream em4x70_bitstream_t *s = &out_cmd_bitstream->to_send; - uint8_t cmd = 0x6u; // CMD + Parity bit == 0b011'0 + // uint8_t cmd = with_command_parity ? 0x6u : 0x3u; + uint8_t cmd = 0x6u; // HACK - always sent with cmd parity result = result && add_nibble_to_bitstream(s, cmd, false); // Reader: [RM][0][Command][N55..N0][0000000][f(RN)27..f(RN)0] @@ -1000,7 +1004,8 @@ static bool create_legacy_em4x70_bitstream_for_cmd_pin(em4x70_command_bitstream_ out_cmd_bitstream->command = EM4X70_COMMAND_PIN; - uint8_t cmd = 0x9u; // CMD + Parity bit == 0b100'1 + //uint8_t cmd = with_command_parity ? 0x9u : 0x4u; + uint8_t cmd = 0x9u; // HACK - always sent with cmd parity, with extra zero bit in RM? result = result && add_nibble_to_bitstream(s, cmd, false); // Send tag's ID ... indexes 4 .. 35 @@ -1032,7 +1037,8 @@ static bool create_legacy_em4x70_bitstream_for_cmd_write(em4x70_command_bitstrea em4x70_bitstream_t *s = &out_cmd_bitstream->to_send; - uint8_t cmd = 0xAu; // CMD + Parity bit == 0b101'0 + //uint8_t cmd = with_command_parity ? 0xAu : 0x5u; + uint8_t cmd = 0xAu; // HACK - always sent with cmd parity, with extra zero bit in RM? result = result && add_nibble_to_bitstream(s, cmd, false); if ((address & 0x0Fu) != address) { @@ -1091,7 +1097,7 @@ static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *respon em4x70_command_bitstream_t auth_cmd; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; - generator->auth(&auth_cmd, g_deprecated_command_parity, rnd, frnd); + generator->auth(&auth_cmd, g_command_parity, rnd, frnd); bool result = send_bitstream_and_read(&auth_cmd); if (result) { @@ -1179,7 +1185,7 @@ static int bruteforce(const uint8_t address, const uint8_t *rnd, const uint8_t * static int send_pin(const uint32_t pin) { em4x70_command_bitstream_t send_pin_cmd; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; - generator->pin(&send_pin_cmd, g_deprecated_command_parity, &g_tag.data[4], pin); + generator->pin(&send_pin_cmd, g_command_parity, &g_tag.data[4], pin); bool result = send_bitstream_wait_ack_wait_read(&send_pin_cmd); return result ? PM3_SUCCESS : PM3_ESOFT; @@ -1190,7 +1196,7 @@ static int write(const uint16_t word, const uint8_t address) { em4x70_command_bitstream_t write_cmd; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; - generator->write(&write_cmd, g_deprecated_command_parity, word, address); + generator->write(&write_cmd, g_command_parity, word, address); bool result = send_bitstream_wait_ack_wait_ack(&write_cmd); if (!result) { @@ -1277,7 +1283,7 @@ static uint8_t encoded_bit_array_to_byte(const uint8_t *bits, int count_of_bits) static bool em4x70_read_id(void) { em4x70_command_bitstream_t read_id_cmd; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; - generator->id(&read_id_cmd, g_deprecated_command_parity); + generator->id(&read_id_cmd, g_command_parity); bool result = send_bitstream_and_read(&read_id_cmd); if (result) { @@ -1294,7 +1300,7 @@ static bool em4x70_read_id(void) { static bool em4x70_read_um1(void) { em4x70_command_bitstream_t read_um1_cmd; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; - generator->um1(&read_um1_cmd, g_deprecated_command_parity); + generator->um1(&read_um1_cmd, g_command_parity); bool result = send_bitstream_and_read(&read_um1_cmd); if (result) { @@ -1313,7 +1319,7 @@ static bool em4x70_read_um1(void) { static bool em4x70_read_um2(void) { em4x70_command_bitstream_t read_um2_cmd; const em4x70_command_generators_t *generator = &legacy_em4x70_command_generators; - generator->um2(&read_um2_cmd, g_deprecated_command_parity); + generator->um2(&read_um2_cmd, g_command_parity); bool result = send_bitstream_and_read(&read_um2_cmd); if (result) { @@ -1429,7 +1435,7 @@ void em4x70_info(const em4x70_data_t *etd, bool ledcontrol) { bool success_with_UM2 = false; // Support tags with and without command parity bits - g_deprecated_command_parity = false; + g_command_parity = etd->parity; init_tag(); em4x70_setup_read(); @@ -1457,10 +1463,10 @@ void em4x70_info(const em4x70_data_t *etd, bool ledcontrol) { void em4x70_write(const em4x70_data_t *etd, bool ledcontrol) { int status = PM3_ESOFT; - g_deprecated_command_parity = false; + g_command_parity = etd->parity; // Disable to prevent sending corrupted data to the tag. - if (g_deprecated_command_parity) { + if (g_command_parity) { DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 write` is non-functional and may corrupt data on the tag.")); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // return; @@ -1493,7 +1499,7 @@ void em4x70_unlock(const em4x70_data_t *etd, bool ledcontrol) { int status = PM3_ESOFT; - g_deprecated_command_parity = false; + g_command_parity = etd->parity; init_tag(); em4x70_setup_read(); @@ -1528,10 +1534,10 @@ void em4x70_auth(const em4x70_data_t *etd, bool ledcontrol) { uint8_t response[3] = {0}; - g_deprecated_command_parity = false; + g_command_parity = etd->parity; // Disable to prevent sending corrupted data to the tag. - if (g_deprecated_command_parity) { + if (g_command_parity) { DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 auth` is non-functional.")); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // return; @@ -1556,10 +1562,10 @@ void em4x70_brute(const em4x70_data_t *etd, bool ledcontrol) { int status = PM3_ESOFT; uint8_t response[2] = {0}; - g_deprecated_command_parity = false; + g_command_parity = etd->parity; // Disable to prevent sending corrupted data to the tag. - if (g_deprecated_command_parity) { + if (g_command_parity) { DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 brute` is non-functional and may corrupt data on the tag.")); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // return; @@ -1584,10 +1590,10 @@ void em4x70_write_pin(const em4x70_data_t *etd, bool ledcontrol) { int status = PM3_ESOFT; - g_deprecated_command_parity = false; + g_command_parity = etd->parity; // Disable to prevent sending corrupted data to the tag. - if (g_deprecated_command_parity) { + if (g_command_parity) { DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 setpin` is non-functional and may corrupt data on the tag.")); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // return; @@ -1633,10 +1639,10 @@ void em4x70_write_key(const em4x70_data_t *etd, bool ledcontrol) { int status = PM3_ESOFT; - g_deprecated_command_parity = false; + g_command_parity = etd->parity; // Disable to prevent sending corrupted data to the tag. - if (g_deprecated_command_parity) { + if (g_command_parity) { DPRINTF_ALWAYS(("Use of `--par` option with `lf em 4x70 setkey` is non-functional and may corrupt data on the tag.")); // reply_ng(CMD_LF_EM4X70_WRITE, PM3_ENOTIMPL, NULL, 0); // return; diff --git a/armsrc/i2c.c b/armsrc/i2c.c index b1af6e30a..501ce388e 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -857,7 +857,7 @@ void SmartCardRaw(const smart_card_raw_t *p) { LED_D_ON(); uint16_t len = 0; - uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME); + uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME); // check if alloacted... smartcard_command_t flags = p->flags; @@ -937,7 +937,7 @@ void SmartCardUpgrade(uint64_t arg0) { bool isOK = true; uint16_t length = arg0, pos = 0; const uint8_t *fwdata = BigBuf_get_addr(); - uint8_t *verfiydata = BigBuf_calloc(I2C_BLOCK_SIZE); + uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE); while (length) { diff --git a/armsrc/i2c.h b/armsrc/i2c.h index b45832acd..3b45c6d7d 100644 --- a/armsrc/i2c.h +++ b/armsrc/i2c.h @@ -36,7 +36,7 @@ // 8051 speaks with smart card. // 1000*50*3.07 = 153.5ms // 1 byte transfer == 1ms with max frame being 256 bytes -#define SIM_WAIT_DELAY 150000 // about 270ms delay // 109773 -- about 337.7ms delay +#define SIM_WAIT_DELAY 88000 // about 270ms delay // 109773 -- about 337.7ms delay void I2C_recovery(void); diff --git a/armsrc/i2c_direct.c b/armsrc/i2c_direct.c index 49aaa4c2c..909c1ec30 100644 --- a/armsrc/i2c_direct.c +++ b/armsrc/i2c_direct.c @@ -40,7 +40,7 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint LED_D_ON(); uint16_t len = 0; - uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME); + uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME); resp[0] = prepend; // check if alloacted... smartcard_command_t flags = p->flags; diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 3eb9df188..6b79b7012 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -38,7 +38,6 @@ #include "iso15693.h" #include "iclass_cmd.h" // iclass_card_select_t struct #include "i2c.h" // i2c defines (SIM module access) -#include "printf.h" uint8_t get_pagemap(const picopass_hdr_t *hdr) { return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3; @@ -196,7 +195,7 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_ if (send_reply) reply_old(CMD_ACK, CMD_HF_ICLASS_SIMULATE, i, 0, mac_responses, i * EPURSE_MAC_SIZE); - } else if (sim_type == ICLASS_SIM_MODE_FULL || sim_type == ICLASS_SIM_MODE_FULL_GLITCH || sim_type == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { + } else if (sim_type == ICLASS_SIM_MODE_FULL) { //This is 'full sim' mode, where we use the emulator storage for data. //ie: BigBuf_get_EM_addr should be previously filled with data from the "eload" command @@ -205,13 +204,19 @@ void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_ if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { do_iclass_simulation_nonsec(); } else { - do_iclass_simulation(sim_type, NULL); + do_iclass_simulation(ICLASS_SIM_MODE_FULL, NULL); } if (send_reply) { reply_mix(CMD_ACK, CMD_HF_ICLASS_SIMULATE, 0, 0, NULL, 0); } + } else if (sim_type == ICLASS_SIM_MODE_CONFIG_CARD) { + + // config card + do_iclass_simulation(ICLASS_SIM_MODE_FULL, NULL); + // swap bin + } else if (sim_type == ICLASS_SIM_MODE_READER_ATTACK_KEYROLL) { // This is the KEYROLL version of sim 2. @@ -328,7 +333,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { // AIA uint8_t aia_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; - if (simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { memcpy(conf_block, emulator + (8 * 1), 8); // blk 1 memcpy(card_challenge_data, emulator + (8 * 2), 8); // e-purse, blk 2 @@ -367,7 +372,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { cipher_state_KD[0] = opt_doTagMAC_1(card_challenge_data, diversified_kd); cipher_state_KC[0] = opt_doTagMAC_1(card_challenge_data, diversified_kc); - if (simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { for (int i = 1; i < max_page; i++) { @@ -380,8 +385,6 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { } } - bool glitch_key_read = false; - // Anti-collision process: // Reader 0a // Tag 0f @@ -396,40 +399,40 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { int trace_data_size; // Respond SOF -- takes 1 bytes - uint8_t resp_sof[2] = {0}; + uint8_t *resp_sof = BigBuf_malloc(1); int resp_sof_len; // Anticollision CSN (rotated CSN) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_anticoll = BigBuf_calloc(22); + uint8_t *resp_anticoll = BigBuf_malloc(22); int resp_anticoll_len; // CSN (block 0) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_csn = BigBuf_calloc(22); + uint8_t *resp_csn = BigBuf_malloc(22); int resp_csn_len; // configuration (blk 1) PICOPASS 2ks - uint8_t *resp_conf = BigBuf_calloc(22); + uint8_t *resp_conf = BigBuf_malloc(22); int resp_conf_len; // e-Purse (blk 2) // 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit) - uint8_t *resp_cc = BigBuf_calloc(18); + uint8_t *resp_cc = BigBuf_malloc(18); int resp_cc_len; // Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only - uint8_t *resp_ff = BigBuf_calloc(22); + uint8_t *resp_ff = BigBuf_malloc(22); int resp_ff_len; uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00}; AddCrc(ff_data, 8); // Application Issuer Area (blk 5) - uint8_t *resp_aia = BigBuf_calloc(22); + uint8_t *resp_aia = BigBuf_malloc(22); int resp_aia_len; // receive command - uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE); + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); // Prepare card messages tosend_t *ts = get_tosend(); @@ -471,11 +474,11 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { //This is used for responding to READ-block commands or other data which is dynamically generated //First the 'trace'-data, not encoded for FPGA - uint8_t *data_generic_trace = BigBuf_calloc(34); // 32 bytes data + 2byte CRC is max tag answer + uint8_t *data_generic_trace = BigBuf_malloc(34); // 32 bytes data + 2byte CRC is max tag answer //Then storage for the modulated data //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) - uint8_t *data_response = BigBuf_calloc((34 * 2) + 3); + uint8_t *data_response = BigBuf_malloc((34 * 2) + 3); enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; @@ -602,27 +605,13 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { goto send; } } // switch - } else if (simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { + } else if (simulationMode == ICLASS_SIM_MODE_FULL) { if (block == 3 || block == 4) { // Kd, Kc, always respond with 0xff bytes modulated_response = resp_ff; modulated_response_size = resp_ff_len; trace_data = ff_data; trace_data_size = sizeof(ff_data); } else { // use data from emulator memory - if (simulationMode == ICLASS_SIM_MODE_FULL_GLITCH) { - //Jam the read based on the last SIO block - if (memcmp(emulator + (current_page * page_size) + (5 * 8), ff_data, PICOPASS_BLOCK_SIZE) == 0) { //SR card - if (block == 16) { //SR cards use a standard legth SIO - goto send; - } - } else { //For SE cards we have to account for different SIO lengths depending if a standard or custom key is used - uint8_t *sio = emulator + (current_page * page_size) + (6 * 8); - if (block == (5 + ((sio[1] + 12) / 8))) { - goto send; - } - } - } - memcpy(data_generic_trace, emulator + (current_page * page_size) + (block * 8), 8); AddCrc(data_generic_trace, 8); trace_data = data_generic_trace; @@ -665,12 +654,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { goto send; } - if (simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { - - if (glitch_key_read) { - goto send; - } - + if (simulationMode == ICLASS_SIM_MODE_FULL) { // NR, from reader, is in receivedCmd +1 opt_doTagMAC_2(*cipher_state, receivedCmd + 1, data_generic_trace, diversified_key); @@ -737,7 +721,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { chip_state = HALTED; goto send; - } else if ((simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) && cmd == ICLASS_CMD_READ4 && len == 4) { // 0x06 + } else if (simulationMode == ICLASS_SIM_MODE_FULL && cmd == ICLASS_CMD_READ4 && len == 4) { // 0x06 if (chip_state != SELECTED) { goto send; @@ -778,24 +762,20 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { resp_cc_len = ts->max; cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); - if (simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { memcpy(emulator + (current_page * page_size) + (8 * 2), card_challenge_data, 8); } } else if (block == 3) { // update Kd for (int i = 0; i < 8; i++) { - if (personalization_mode || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { + if (personalization_mode) { diversified_kd[i] = receivedCmd[2 + i]; } else { diversified_kd[i] ^= receivedCmd[2 + i]; } } cipher_state_KD[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kd); - if (simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { memcpy(emulator + (current_page * page_size) + (8 * 3), diversified_kd, 8); - if (simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { - glitch_key_read = true; - goto send; - } } } else if (block == 4) { // update Kc for (int i = 0; i < 8; i++) { @@ -806,30 +786,14 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { } } cipher_state_KC[current_page] = opt_doTagMAC_1(card_challenge_data, diversified_kc); - if (simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { + if (simulationMode == ICLASS_SIM_MODE_FULL) { memcpy(emulator + (current_page * page_size) + (8 * 4), diversified_kc, 8); } - } else if (simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) { + } else if (simulationMode == ICLASS_SIM_MODE_FULL) { // update emulator memory memcpy(emulator + (current_page * page_size) + (8 * block), receivedCmd + 2, 8); } - if (simulationMode == ICLASS_SIM_MODE_FULL_GLITCH) { - //Jam the read based on the last SIO block - uint8_t *sr_or_sio = emulator + (current_page * page_size) + (6 * 8); - if (memcmp(emulator + (current_page * page_size) + (5 * 8), ff_data, PICOPASS_BLOCK_SIZE) == 0) { //SR card - if (block == 16) { //SR cards use a standard legth SIO - //update block 6 byte 1 from 03 to A3 - sr_or_sio[0] |= 0xA0; - goto send; - } - } else { //For SE cards we have to account for different SIO lengths depending if a standard or custom key is used - if (block == (5 + ((sr_or_sio[1] + 12) / 8))) { - goto send; - } - } - } - memcpy(data_generic_trace, receivedCmd + 2, 8); AddCrc(data_generic_trace, 8); trace_data = data_generic_trace; @@ -849,7 +813,7 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) { goto send; } - if ((simulationMode == ICLASS_SIM_MODE_FULL || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH || simulationMode == ICLASS_SIM_MODE_FULL_GLITCH_KEY) && max_page > 0) { + if (simulationMode == ICLASS_SIM_MODE_FULL && max_page > 0) { // if on 2k, always ignore 3msb, & 0x1F) uint8_t page = receivedCmd[1] & 0x1F; @@ -978,29 +942,29 @@ int do_iclass_simulation_nonsec(void) { int trace_data_size = 0; // Respond SOF -- takes 1 bytes - uint8_t resp_sof[2] = { 0 }; + uint8_t *resp_sof = BigBuf_malloc(2); int resp_sof_len; // Anticollision CSN (rotated CSN) // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_anticoll = BigBuf_calloc(28); + uint8_t *resp_anticoll = BigBuf_malloc(28); int resp_anticoll_len; // CSN // 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte) - uint8_t *resp_csn = BigBuf_calloc(28); + uint8_t *resp_csn = BigBuf_malloc(28); int resp_csn_len; // configuration (blk 1) PICOPASS 2ks - uint8_t *resp_conf = BigBuf_calloc(28); + uint8_t *resp_conf = BigBuf_malloc(28); int resp_conf_len; // Application Issuer Area (blk 5) - uint8_t *resp_aia = BigBuf_calloc(28); + uint8_t *resp_aia = BigBuf_malloc(28); int resp_aia_len; // receive command - uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE); + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); // Prepare card messages tosend_t *ts = get_tosend(); @@ -1033,11 +997,11 @@ int do_iclass_simulation_nonsec(void) { //This is used for responding to READ-block commands or other data which is dynamically generated //First the 'trace'-data, not encoded for FPGA - uint8_t *data_generic_trace = BigBuf_calloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer + uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer //Then storage for the modulated data //Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes) - uint8_t *data_response = BigBuf_calloc((32 + 2) * 2 + 2); + uint8_t *data_response = BigBuf_malloc((32 + 2) * 2 + 2); enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE; @@ -1280,6 +1244,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t * while (tries-- > 0) { iclass_send_as_reader(cmd, cmdsize, start_time, eof_time, shallow_mod); + if (resp == NULL) { return true; } @@ -1617,9 +1582,8 @@ bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, ui uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; AddCrc(c + 1, 1); bool isOK = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time, shallow_mod); - if (isOK) { + if (isOK) memcpy(data, resp, 8); - } return isOK; } @@ -1816,13 +1780,13 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac, } } else if (blockno == 3 || blockno == 4) { // check response. Key updates always return 0xffffffffffffffff - uint8_t all_ff[PICOPASS_BLOCK_SIZE] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - if (memcmp(all_ff, resp, PICOPASS_BLOCK_SIZE)) { + uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + if (memcmp(all_ff, resp, 8)) { return false; } } else { // check response. All other updates return unchanged data - if (memcmp(data, resp, PICOPASS_BLOCK_SIZE)) { + if (memcmp(data, resp, 8)) { return false; } } @@ -1830,66 +1794,8 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac, return true; } -static bool iclass_writeblock_sp(uint8_t blockno, uint8_t *data, uint8_t *mac, bool shallow_mod, uint32_t *start_time, uint32_t *eof_time, bool short_delay) { - - // write command: cmd, 1 blockno, 8 data, 4 mac - uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, blockno }; - uint8_t write_len = 14; - memcpy(write + 2, data, 8); - memcpy(write + 10, mac, 4); - - uint8_t resp[10] = {0}; - bool isOK = false; - if (short_delay) { - isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_UPDATE_FAST, eof_time, shallow_mod); - } else { - isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, start_time, ICLASS_READER_TIMEOUT_UPDATE, eof_time, shallow_mod); - } - if (isOK == false) { - return false; - } - - // check response. All other updates return unchanged data - if (memcmp(data, resp, PICOPASS_BLOCK_SIZE)) { - return false; - } - - return true; -} - -uint8_t credit_key[8] = {0xFD, 0xCB, 0x5A, 0x52, 0xEA, 0x8F, 0x30, 0x90}; - -static bool do_privilege_escalation(uint8_t *read_check_cc, size_t cc_len, uint32_t *eof_time) { - - int priv_esc_tries = 5; - - while (priv_esc_tries--) { - - uint16_t resp_len = 0; - uint8_t resp[10] = {0}; - //The privilege escalation is done with a readcheck and not just a normal read! - uint32_t start_time = *eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - - iclass_send_as_reader(read_check_cc, cc_len, &start_time, eof_time, false); - // expect a 8-byte response here - int res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, eof_time, false, true, &resp_len); - if (res == PM3_SUCCESS && resp_len == 8) { - return true; - } - } - - if (g_dbglevel == DBG_INFO) { - DbpString(""); - DbpString(_RED_("Unable to complete privilege escalation! Stopping.")); - } - return false; -} - // turn off afterwards void iClass_WriteBlock(uint8_t *msg) { - bool priv_esc = false; - uint8_t read_check_cc[] = { 0x10 | ICLASS_CMD_READCHECK, 0x18 }; - uint8_t div_cc[8] = {0}; LED_A_ON(); @@ -1909,9 +1815,6 @@ void iClass_WriteBlock(uint8_t *msg) { goto out; } - iclass_calc_div_key(hdr.csn, credit_key, div_cc, false); - read_check_cc[1] = hdr.conf.app_limit + 1; //first block of AA2 - uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; uint8_t mac[4] = {0}; @@ -1926,7 +1829,7 @@ void iClass_WriteBlock(uint8_t *msg) { } // new block data - memcpy(write + 2, payload->data, PICOPASS_BLOCK_SIZE); + memcpy(write + 2, payload->data, 8); uint8_t pagemap = get_pagemap(&hdr); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { @@ -1938,25 +1841,18 @@ void iClass_WriteBlock(uint8_t *msg) { write_len -= 2; } else { - if (payload->req.use_replay && (memcmp(payload->mac, "\x00\x00\x00\x00", 4) != 0)) { + if (payload->req.use_replay) { memcpy(write + 10, payload->mac, sizeof(payload->mac)); } else { // Secure tags uses MAC uint8_t wb[9]; wb[0] = payload->req.blockno; - memcpy(wb + 1, payload->data, PICOPASS_BLOCK_SIZE); + memcpy(wb + 1, payload->data, 8); - if (payload->req.use_credit_key) { + if (payload->req.use_credit_key) doMAC_N(wb, sizeof(wb), hdr.key_c, mac); - } else if (payload->req.use_replay) { - priv_esc = do_privilege_escalation(read_check_cc, sizeof(read_check_cc), &eof_time); - if (priv_esc == false) { - goto out; - } - doMAC_N(wb, sizeof(wb), div_cc, mac); - } else { + else doMAC_N(wb, sizeof(wb), hdr.key_d, mac); - } memcpy(write + 10, mac, sizeof(mac)); } @@ -2178,425 +2074,7 @@ out: reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t)); } -static void iclass_cmp_print(uint8_t *b1, uint8_t *b2, const char *header1, const char *header2) { - - char line1[240] = {0}; - char line2[240] = {0}; - - strcat(line1, header1); - strcat(line2, header2); - - for (uint8_t i = 0; i < PICOPASS_BLOCK_SIZE; i++) { - - int l1 = strlen(line1); - int l2 = strlen(line2); - - uint8_t hi1 = NIBBLE_HIGH(b1[i]); - uint8_t low1 = NIBBLE_LOW(b1[i]); - - uint8_t hi2 = NIBBLE_HIGH(b2[i]); - uint8_t low2 = NIBBLE_LOW(b2[i]); - - if (hi1 != hi2) { - sprintf(line1 + l1, _RED_("%1X"), hi1); - sprintf(line2 + l2, _GREEN_("%1X"), hi2); - } else { - sprintf(line1 + l1, "%1X", hi1); - sprintf(line2 + l2, "%1X", hi2); - } - - l1 = strlen(line1); - l2 = strlen(line2); - - if (low1 != low2) { - sprintf(line1 + l1, _RED_("%1X"), low1); - sprintf(line2 + l2, _GREEN_("%1X"), low2); - } else { - sprintf(line1 + l1, "%1X", low1); - sprintf(line2 + l2, "%1X", low2); - } - } - DbpString(line1); - DbpString(line2); -} - -void iClass_TearBlock(iclass_tearblock_req_t *msg) { - - if (msg == NULL) { - reply_ng(CMD_HF_ICLASS_TEARBL, PM3_ESOFT, NULL, 0); - return; - } - - // local variable copies - int tear_start = msg->tear_start; - int tear_end = msg->tear_end; - int tear_inc = msg->increment; - int tear_loop = msg->tear_loop; - - int loop_count = 0; - - uint32_t start_time = 0; - uint32_t eof_time = 0; - - int isok = PM3_SUCCESS; - - uint8_t data[8] = {0}; - memcpy(data, msg->data, sizeof(data)); - - uint8_t mac[4] = {0}; - memcpy(mac, msg->mac, sizeof(mac)); - - picopass_hdr_t hdr = {0}; - iclass_auth_req_t req = { - .blockno = msg->req.blockno, - .do_auth = msg->req.do_auth, - .send_reply = msg->req.send_reply, - .shallow_mod = msg->req.shallow_mod, - .use_credit_key = msg->req.use_credit_key, - .use_elite = msg->req.use_elite, - .use_raw = msg->req.use_raw, - .use_replay = msg->req.use_replay - }; - memcpy(req.key, msg->req.key, PICOPASS_BLOCK_SIZE); - - LED_A_ON(); - Iso15693InitReader(); - - // save old debug log level - int oldbg = g_dbglevel; - - // no debug logging please - g_dbglevel = DBG_NONE; - - // select - bool res = select_iclass_tag(&hdr, req.use_credit_key, &eof_time, req.shallow_mod); - if (res == false) { - DbpString(_RED_("Failed to select iClass tag")); - isok = PM3_ECARDEXCHANGE; - goto out; - } - - // authenticate - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = authenticate_iclass_tag(&req, &hdr, &start_time, &eof_time, mac); - if (res == false) { - DbpString(_RED_("Failed to authenticate with iClass tag")); - isok = PM3_ECARDEXCHANGE; - goto out; - } - - uint8_t data_read_orig[PICOPASS_BLOCK_SIZE] = {0}; - - // read block - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = iclass_read_block(req.blockno, data_read_orig, &start_time, &eof_time, req.shallow_mod); - if (res == false) { - Dbprintf("Failed to read block %u", req.blockno); - isok = PM3_ECARDEXCHANGE; - goto out; - } - - bool erase_phase = false; - bool read_ok = false; - - // static uint8_t empty[PICOPASS_BLOCK_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - static uint8_t zeros[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - uint8_t ff_data[PICOPASS_BLOCK_SIZE] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - uint8_t data_read[PICOPASS_BLOCK_SIZE] = {0}; - - // create READ command - uint8_t cmd_read[] = {ICLASS_CMD_READ_OR_IDENTIFY, req.blockno, 0x00, 0x00}; - AddCrc(cmd_read + 1, 1); - - // create WRITE COMMAND and new block data - uint8_t cmd_write[14] = { 0x80 | ICLASS_CMD_UPDATE, req.blockno }; - uint8_t cmd_write_len = 14; - memcpy(cmd_write + 2, data, PICOPASS_BLOCK_SIZE); - - uint8_t pagemap = get_pagemap(&hdr); - if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - // Unsecured tags uses CRC16, but don't include the UPDATE operation code - // byte0 = update op - // byte1 = block no - // byte2..9 = new block data - AddCrc(cmd_write + 1, 9); - cmd_write_len -= 2; - } else { - - if (req.use_replay) { - memcpy(cmd_write + 10, mac, sizeof(mac)); - } else { - // Secure tags uses MAC - uint8_t wb[9]; - wb[0] = req.blockno; - memcpy(wb + 1, data, PICOPASS_BLOCK_SIZE); - - if (req.use_credit_key) - doMAC_N(wb, sizeof(wb), hdr.key_c, mac); - else - doMAC_N(wb, sizeof(wb), hdr.key_d, mac); - - memcpy(cmd_write + 10, mac, sizeof(mac)); - } - } - - // Main loop - while ((tear_start <= tear_end) && (read_ok == false)) { - - if (BUTTON_PRESS() || data_available()) { - isok = PM3_EOPABORTED; - goto out; - } - - // set tear off trigger - g_tearoff_enabled = true; - g_tearoff_delay_us = (tear_start & 0xFFFF); - - if (tear_loop > 1) { - DbprintfEx(FLAG_INPLACE, "[" _BLUE_("#") "] Tear off delay " _YELLOW_("%u") " / " _YELLOW_("%u") " us - " _YELLOW_("%3u") " iter", tear_start, tear_end, loop_count + 1); - } else { - DbprintfEx(FLAG_INPLACE, "[" _BLUE_("#") "] Tear off delay " _YELLOW_("%u") " / " _YELLOW_("%u") " us", tear_start, tear_end); - } - - // write block - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(cmd_write, cmd_write_len, &start_time, &eof_time, req.shallow_mod); - - tearoff_hook(); - - switch_off(); - - // start reading block - - // reinit - Iso15693InitReader(); - - // select tag - res = select_iclass_tag(&hdr, req.use_credit_key, &eof_time, req.shallow_mod); - if (res == false) { - continue; - } - - // skip authentication for config and e-purse blocks (1,2) - if (req.blockno > 2) { - - // authenticate - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = authenticate_iclass_tag(&req, &hdr, &start_time, &eof_time, NULL); - if (res == false) { - DbpString("Failed to authenticate after tear"); - continue; - } - } - - // read again and keep field on - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = iclass_read_block(req.blockno, data_read, &start_time, &eof_time, req.shallow_mod); - if (res == false) { - DbpString("Failed to read block after tear"); - continue; - } - - // - bool tear_success = true; - - if (memcmp(data_read, data, PICOPASS_BLOCK_SIZE) != 0) { - tear_success = false; - } - - if ((tear_success == false) && - (memcmp(data_read, zeros, PICOPASS_BLOCK_SIZE) != 0) && - (memcmp(data_read, data_read_orig, PICOPASS_BLOCK_SIZE) != 0)) { - - // tearoff succeeded (partially) - - if (memcmp(data_read, ff_data, PICOPASS_BLOCK_SIZE) == 0 && - memcmp(data_read_orig, ff_data, PICOPASS_BLOCK_SIZE) != 0) { - - if (erase_phase == false) { - DbpString(""); - DbpString(_CYAN_("Erase phase hit... ALL ONES")); - - iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); - } - erase_phase = true; - - } else { - - if (erase_phase) { - DbpString(""); - DbpString(_MAGENTA_("Tearing! Write phase (post erase)")); - iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); - } else { - DbpString(""); - DbpString(_CYAN_("Tearing! unknown phase")); - iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); - } - } - - // shall we exit? well it depends on some things. - bool goto_out = false; - - if (req.blockno == 2) { - if (memcmp(data_read, ff_data, PICOPASS_BLOCK_SIZE) == 0 && memcmp(data_read_orig, ff_data, PICOPASS_BLOCK_SIZE) != 0) { - DbpString(""); - Dbprintf("E-purse has been teared ( %s )", _GREEN_("ok")); - isok = PM3_SUCCESS; - goto_out = true; - } - } - - if (req.blockno == 1) { - - // if more OTP bits set.. - if (data_read[1] > data_read_orig[1] || - data_read[2] > data_read_orig[2]) { - - - // step 4 if bits changed attempt to write the new bits to the tag - if (data_read[7] == 0xBC) { - data_read[7] = 0xAC; - } - - // prepare WRITE command - cmd_write_len = 14; - memcpy(cmd_write + 2, data_read, PICOPASS_BLOCK_SIZE); - - if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - // Unsecured tags uses CRC16, but don't include the UPDATE operation code - // byte0 = update op - // byte1 = block no - // byte2..9 = new block data - AddCrc(cmd_write + 1, 9); - cmd_write_len -= 2; - } else { - - if (req.use_replay) { - memcpy(cmd_write + 10, mac, sizeof(mac)); - } else { - // Secure tags uses MAC - uint8_t wb[9]; - wb[0] = req.blockno; - memcpy(wb + 1, data_read, PICOPASS_BLOCK_SIZE); - - if (req.use_credit_key) - doMAC_N(wb, sizeof(wb), hdr.key_c, mac); - else - doMAC_N(wb, sizeof(wb), hdr.key_d, mac); - - memcpy(cmd_write + 10, mac, sizeof(mac)); - } - } - - // write block - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(cmd_write, cmd_write_len, &start_time, &eof_time, req.shallow_mod); - - uint16_t resp_len = 0; - uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; - res = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_UPDATE, &eof_time, false, true, &resp_len); - if (res == PM3_SUCCESS && resp_len == 10) { - Dbprintf("Wrote to block"); - } - - switch_off(); - - DbpString(""); - DbpString("More OTP bits got set!!!"); - - Iso15693InitReader(); - - // select tag, during which we read block1 - res = select_iclass_tag(&hdr, req.use_credit_key, &eof_time, req.shallow_mod); - if (res) { - - if (memcmp(&hdr.conf, cmd_write + 2, PICOPASS_BLOCK_SIZE) == 0) { - Dbprintf("Stabilize the bits ( "_GREEN_("ok") " )"); - } else { - Dbprintf("Stabilize the bits ( "_RED_("failed") " )"); - } - } - - isok = PM3_SUCCESS; - goto_out = true; - } - - if (data_read[0] != data_read_orig[0]) { - DbpString(""); - Dbprintf("Application limit changed, from "_YELLOW_("%u")" to "_YELLOW_("%u"), data_read_orig[0], data_read[0]); - isok = PM3_SUCCESS; - goto_out = true; - } - - if (data_read[7] != data_read_orig[7]) { - DbpString(""); - Dbprintf("Fuse changed, from "_YELLOW_("%02x")" to "_YELLOW_("%02x"), data_read_orig[7], data_read[7]); - - const char *flag_names[8] = { - "RA", - "Fprod0", - "Fprod1", - "Crypt0 (*1)", - "Crypt1 (*0)", - "Coding0", - "Coding1", - "Fpers (*1)" - }; - Dbprintf(_YELLOW_("%-10s %-10s %-10s"), "Fuse", "Original", "Changed"); - Dbprintf("---------------------------------------"); - for (int i = 7; i >= 0; --i) { - int bit1 = (data_read_orig[7] >> i) & 1; - int bit2 = (data_read[7] >> i) & 1; - Dbprintf("%-11s %-10d %-10d", flag_names[i], bit1, bit2); - } - - isok = PM3_SUCCESS; - goto_out = true; - } - } - - if (goto_out) { - goto out; - } - } - - // tearoff succeeded with expected values, which is unlikely - if (tear_success) { - read_ok = true; - tear_success = true; - DbpString(""); - DbpString("tear success (expected values)!"); - } - - loop_count++; - - // increase tear off delay - if (loop_count == tear_loop) { - tear_start += tear_inc; - loop_count = 0; - } - } - -out: - - switch_off(); - - // reset tear off trigger - g_tearoff_enabled = false; - - // restore debug message levels - g_dbglevel = oldbg; - - if (msg->req.send_reply) { - reply_ng(CMD_HF_ICLASS_TEARBL, isok, NULL, 0); - } -} - void iClass_Restore(iclass_restore_req_t *msg) { - bool priv_esc = false; - uint8_t read_check_cc[] = { 0x10 | ICLASS_CMD_READCHECK, 0x18 }; - uint8_t div_cc[8] = {0}; // sanitation if (msg == NULL) { @@ -2625,9 +2103,7 @@ void iClass_Restore(iclass_restore_req_t *msg) { if (res == false) { goto out; } - iclass_calc_div_key(hdr.csn, credit_key, div_cc, false); - read_check_cc[1] = hdr.conf.app_limit + 1; //first block of AA2 // authenticate uint8_t mac[4] = {0}; uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -2657,17 +2133,10 @@ void iClass_Restore(iclass_restore_req_t *msg) { wb[0] = item.blockno; memcpy(wb + 1, item.data, 8); - if (msg->req.use_credit_key) { + if (msg->req.use_credit_key) doMAC_N(wb, sizeof(wb), hdr.key_c, mac); - } else if (msg->req.use_replay) { - priv_esc = do_privilege_escalation(read_check_cc, sizeof(read_check_cc), &eof_time); - if (priv_esc == false) { - goto out; - } - doMAC_N(wb, sizeof(wb), div_cc, mac); - } else { + else doMAC_N(wb, sizeof(wb), hdr.key_d, mac); - } } // data + mac @@ -2691,7 +2160,7 @@ out: static void generate_single_key_block_inverted_opt(const uint8_t *startingKey, uint32_t index, uint8_t *keyBlock) { uint8_t bits_index = index / 16383; - uint8_t ending_bits[] = { // all possible 70 combinations of 4x0 and 4x1 as key ending bits + uint8_t ending_bits[] = { //all possible 70 combinations of 4x0 and 4x1 as key ending bits 0x0F, 0x17, 0x1B, 0x1D, 0x1E, 0x27, 0x2B, 0x2D, 0x2E, 0x33, 0x35, 0x36, 0x39, 0x3A, 0x3C, 0x47, 0x4B, 0x4D, 0x4E, 0x53, 0x55, 0x56, 0x59, 0x5A, 0x5C, 0x63, 0x65, 0x66, 0x69, 0x6A, @@ -2719,7 +2188,7 @@ static void generate_single_key_block_inverted_opt(const uint8_t *startingKey, u // Start from the second byte, index 1 as we're never gonna touch the first byte for (int i = 1; i < PICOPASS_BLOCK_SIZE; i++) { - // Clear the last three bits of the current byte (AND with 0xF8) + // Clear the last bit of the current byte (AND with 0xFE) keyBlock[i] &= 0xF8; // Set the last bit to the corresponding value from binary_endings (OR with binary_endings[i]) keyBlock[i] |= ((binary_mids[i] & 0x03) << 1) | (binary_endings[i] & 0x01); @@ -2731,19 +2200,15 @@ void iClass_Recover(iclass_recover_req_t *msg) { bool shallow_mod = false; uint8_t zero_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; uint8_t genkeyblock[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t fast_restore_key[PICOPASS_BLOCK_SIZE] = {0}; - uint8_t fast_previous_key[PICOPASS_BLOCK_SIZE] = {0}; - uint8_t fast_current_key[PICOPASS_BLOCK_SIZE] = {0}; uint32_t index = msg->index; - bool short_delay = msg->short_delay; int bits_found = -1; bool recovered = false; bool completed = false; - bool interrupted = false; uint8_t div_key2[8] = {0}; uint32_t eof_time = 0; uint32_t start_time = 0; - uint8_t read_check_cc[] = { 0x10 | ICLASS_CMD_READCHECK, 0x18 }; //block 24 with credit key + uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x18 }; //block 24 + read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK; //use credit key uint8_t read_check_cc2[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; //block 2 -> to check Kd macs /* iclass_mac_table is a series of weak macs, those weak macs correspond to the different combinations of the last 3 bits of each key byte. */ @@ -2760,378 +2225,224 @@ void iClass_Recover(iclass_recover_req_t *msg) { }; LED_A_ON(); - DbpString(_RED_("Interrupting this process may render the card unusable!")); + DbpString(_RED_("Interrupting this process will render the card unusable!")); memcpy(div_key2, msg->nfa, 8); //START LOOP uint32_t loops = 1; - bool card_select = false; - bool card_auth = false; - bool priv_esc = false; - int status_message = 0; - int reinit_tentatives = 0; - bool res = false; - picopass_hdr_t hdr = {0}; - uint8_t original_mac[8] = {0}; - uint8_t mac1[4] = {0}; - - while ((card_select == false) || (card_auth == false)) { - - Iso15693InitReader(); //has to be at the top as it starts tracing - if (msg->debug == false) { - set_tracing(false); //disable tracing to prevent crashes - set to true for debugging - } else { - if (loops == 1) { - clear_trace(); //if we're debugging better to clear the trace but do it only on the first loop - } - } - //Step0 Card Select Routine - eof_time = 0; //reset eof time - res = select_iclass_tag(&hdr, false, &eof_time, shallow_mod); - if (res) { - status_message = 1; //card select successful - card_select = true; - } - - //Step 0A - The read_check_cc block has to be in AA2, set it by checking the card configuration - read_check_cc[1] = hdr.conf.app_limit + 1; //first block of AA2 - - //Step1 Authenticate with AA1 using trace - if (card_select) { - memcpy(original_mac, msg->req.key, 8); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); - if (res) { - status_message = 2; //authentication with AA1 macs successful - card_auth = true; - } - } - - if ((card_select == false) || (card_auth == false)) { - reinit_tentatives++; - switch_off(); - } - - if (reinit_tentatives == 5) { - DbpString(""); - DbpString(_RED_("Unable to select or authenticate with card multiple times! Stopping.")); - goto out; - } - } while (bits_found == -1) { - - reinit_tentatives = 0; + bool card_select = false; + bool card_auth = false; + int reinit_tentatives = 0; + uint8_t original_mac[8] = {0}; + uint16_t resp_len = 0; + int res2; + uint8_t resp[10] = {0}; + uint8_t mac1[4] = {0}; uint8_t mac2[4] = {0}; - res = false; + picopass_hdr_t hdr = {0}; + bool res = false; - if (BUTTON_PRESS() || loops > msg->loop) { - if (loops > msg->loop) { - completed = true; + while (!card_select || !card_auth) { + Iso15693InitReader(); //has to be at the top as it starts tracing + if (!msg->debug) { + set_tracing(false); //disable tracing to prevent crashes - set to true for debugging } else { - interrupted = true; + if (loops == 1) { + clear_trace(); //if we're debugging better to clear the trace but do it only on the first loop + } } - if (msg->fast) { - goto fast_restore; + if (msg->test) { + Dbprintf(_YELLOW_("*Cycled Reader*") " ----------------- TEST Index - Loops: "_YELLOW_("%3d / %3d") " --------------*", loops, msg->loop); + } else { + Dbprintf(_YELLOW_("*Cycled Reader*") " ----------------- Index: "_RED_("%3d")" Loops: "_YELLOW_("%3d / %3d") " --------------*", index, loops, msg->loop); } - goto out; - } - - if (msg->test) { - Dbprintf(_YELLOW_("*Cycled Reader*") " TEST Index - Loops: "_YELLOW_("%3d / %3d") " *", loops, msg->loop); - } else if (msg->debug || ((card_select == false) && (card_auth == false))) { - Dbprintf(_YELLOW_("*Cycled Reader*") " Index: "_RED_("%3d")" Loops: "_YELLOW_("%3d / %3d") " *", index, loops, msg->loop); - } else { - DbprintfEx(FLAG_INPLACE, "[" _BLUE_("#") "] Index: "_CYAN_("%3d")" Loops: "_YELLOW_("%3d / %3d")" ", index, loops, msg->loop); - } - - while ((card_select == false) || (card_auth == false)) { - - Iso15693InitReader(); // has to be at the top as it starts tracing - set_tracing(false); // disable tracing to prevent crashes - set to true for debugging - // Step0 Card Select Routine - eof_time = 0; // reset eof time + //Step0 Card Select Routine + eof_time = 0; //reset eof time res = select_iclass_tag(&hdr, false, &eof_time, shallow_mod); - if (res) { - status_message = 1; // card select successful + if (res == false) { + DbpString(_RED_("Unable to select card after reader cycle! Retrying...")); + } else { + DbpString(_GREEN_("Card selected successfully!")); card_select = true; } - // Step1 Authenticate with AA1 using trace + //Step1 Authenticate with AA1 using trace if (card_select) { memcpy(original_mac, msg->req.key, 8); start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); - if (res) { - status_message = 2; //authentication with AA1 macs successful + if (res == false) { + DbpString(_RED_("Unable to authenticate on AA1 using macs! Retrying...")); + } else { + DbpString(_GREEN_("AA1 authentication with macs successful!")); card_auth = true; } } - - if ((card_select == false) || (card_auth == false)) { + if (!card_auth || !card_select) { reinit_tentatives++; switch_off(); } - if (reinit_tentatives == 5) { - DbpString(""); DbpString(_RED_("Unable to select or authenticate with card multiple times! Stopping.")); goto out; } } - // Step2 Privilege Escalation: attempt to read AA2 with credentials for AA1 - if (priv_esc == false) { - priv_esc = do_privilege_escalation(read_check_cc, sizeof(read_check_cc), &eof_time); - if (priv_esc) { - status_message = 3; + //Step2 Privilege Escalation: attempt to read AA2 with credentials for AA1 + uint8_t blockno = 24; + uint8_t cmd_read[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockno, 0x00, 0x00}; + AddCrc(cmd_read + 1, 1); + int priv_esc_tries = 0; + bool priv_esc = false; + while (!priv_esc) { + //The privilege escalation is done with a readcheck and not just a normal read! + iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod); + // expect a 8-byte response here + res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); + if (res2 != PM3_SUCCESS || resp_len != 8) { + DbpString(_YELLOW_("Privilege Escalation -> ")_RED_("Read failed! Trying again...")); + priv_esc_tries++; } else { + DbpString(_YELLOW_("Privilege Escalation -> ")_GREEN_("Response OK!")); + priv_esc = true; + } + if (priv_esc_tries == 5) { + DbpString(_RED_("Unable to complete privilege escalation! Stopping.")); goto out; } } - if (priv_esc && status_message != 3) { - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod); - status_message = 3; - } - - // Step3 Calculate New Key (Optimised Algo V2) + //Step3 Calculate New Key (Optimised Algo V2) generate_single_key_block_inverted_opt(zero_key, index, genkeyblock); if (msg->test) { memcpy(genkeyblock, zero_key, PICOPASS_BLOCK_SIZE); } - if (msg->fast) { // if we're skipping restoring the original key to gain speed, xor the new index key with the previous index key and update the difference and track restore values differently - - if (index > 0 && loops > 1) { - generate_single_key_block_inverted_opt(zero_key, index - 1, fast_previous_key); - } else { - memcpy(fast_previous_key, zero_key, PICOPASS_BLOCK_SIZE); - } - - for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { - fast_current_key[i] = genkeyblock[i] ^ fast_previous_key[i]; - fast_restore_key[i] = fast_restore_key[i] ^ fast_current_key[i]; - } - - memcpy(genkeyblock, fast_current_key, PICOPASS_BLOCK_SIZE); - } - - // Step4 Calculate New Mac + //Step4 Calculate New Mac uint8_t wb[9] = {0}; - uint8_t blockno = 3; + blockno = 3; wb[0] = blockno; memcpy(wb + 1, genkeyblock, 8); doMAC_N(wb, sizeof(wb), div_key2, mac2); + bool use_mac = true; bool written = false; bool write_error = false; - while (written == false && write_error == false) { - // Step5 Perform Write - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time, short_delay)) { - status_message = 4; // wrote new key on the card - unverified + //Step5 Perform Write + if (iclass_writeblock_ext(blockno, genkeyblock, mac2, use_mac, shallow_mod)) { + DbpString("Wrote key: "); + Dbhexdump(8, genkeyblock, false); } - if (msg->fast == false) { // if we're going slow we check at every write that the write actually happened - // Reset cypher state - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); - // try to authenticate with the original mac to verify the write happened - memcpy(msg->req.key, original_mac, 8); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); - if (msg->test) { - if (res) { - DbpString(""); - DbpString(_GREEN_("*** CARD EPURSE IS LOUD! OK TO ATTEMPT KEY RETRIEVAL! RUN AGAIN WITH -notest ***")); - completed = true; - goto out; - } else { - DbpString(""); - DbpString(_RED_("*** CARD EPURSE IS SILENT! RISK OF BRICKING! DO NOT EXECUTE KEY UPDATES! SCAN IT ON READER FOR EPURSE UPDATE, COLLECT NEW TRACES AND TRY AGAIN! ***")); - goto out; - } + //Reset cypher state + iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); + res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); + //try to authenticate with the original mac to verify the write happened + memcpy(msg->req.key, original_mac, 8); + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); + if (msg->test) { + if (res != true) { + DbpString(_RED_("*** CARD EPURSE IS SILENT! RISK OF BRICKING! DO NOT EXECUTE KEY UPDATES! SCAN IT ON READER FOR EPURSE UPDATE, COLLECT NEW TRACES AND TRY AGAIN! ***")); + goto out; } else { - if (res) { - write_error = true; // failed to update the key, the card's key is the original one - } else { - status_message = 5; // verified the card key was updated to the new one - written = true; - } + DbpString(_GREEN_("*** CARD EPURSE IS LOUD! OK TO ATTEMPT KEY RETRIEVAL! RUN AGAIN WITH -notest ***")); + completed = true; + goto out; + } + } else { + if (res != true) { + DbpString("Write Operation : "_GREEN_("VERIFIED! Card Key Updated!")); + written = true; + } else { + DbpString("Write Operation : "_RED_("FAILED! Card Key is the Original. Retrying...")); + write_error = true; } - } else { // if we're going fast we can skip the above checks as we're just xorring the key over and over - status_message = 5; - written = true; } } - if (write_error == false) { - // Step6 Perform 8 authentication attempts + 1 to verify if we found the weak key + if (!write_error) { + //Step6 Perform 8 authentication attempts + 1 to verify if we found the weak key for (int i = 0; i < 8 ; ++i) { - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); - // need to craft the authentication payload accordingly + res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); + //need to craft the authentication payload accordingly memcpy(msg->req.key, iclass_mac_table[i], 8); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); //mac1 here shouldn't matter if (res == true) { bits_found = i; + DbpString(_RED_("--------------------------------------------------------")); + Dbprintf("Decimal Value of last 3 bits: " _GREEN_("[%3d]"), bits_found); + DbpString(_RED_("--------------------------------------------------------")); recovered = true; } } + //regardless of bits being found, restore the original key and verify it bool reverted = false; uint8_t revert_retries = 0; - if (msg->fast) { // if we're going fast only restore the original key at the end - if (recovered) { - goto fast_restore; + while (!reverted) { + //Regain privilege escalation with a readcheck + iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod); + // TODO: check result + GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); + + DbpString(_YELLOW_("Attempting to restore the original key. ")); + if (iclass_writeblock_ext(blockno, genkeyblock, mac2, use_mac, shallow_mod)) { + DbpString("Restore of Original Key "_GREEN_("successful.")); + } else { + DbpString("Restore of Original Key " _RED_("failed.")); } - } else { - // if we're NOT going fast, regardless of bits being found, restore the original key and verify it - while (reverted == false) { - // Regain privilege escalation with a readcheck - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - if (iclass_writeblock_sp(blockno, genkeyblock, mac2, shallow_mod, &start_time, &eof_time, short_delay)) { - status_message = 6; // restore of original key successful but unverified - } - // Do a readcheck first to reset the cypher state - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); + DbpString(_YELLOW_("Verifying Key Restore...")); + //Do a readcheck first to reset the cypher state + iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); + // TODO: check result + GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len); - // need to craft the authentication payload accordingly - memcpy(msg->req.key, original_mac, 8); - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - - res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); - if (res == true) { - status_message = 7; // restore of original key verified - card usable again - reverted = true; - if (recovered) { - goto restore; - } + //need to craft the authentication payload accordingly + memcpy(msg->req.key, original_mac, 8); + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); + if (res == true) { + DbpString("Restore of Original Key "_GREEN_("VERIFIED! Card is usable again.")); + reverted = true; + if (recovered) { + goto restore; } + } else { + DbpString("Restore of Original Key "_RED_("VERIFICATION FAILED! Trying again...")); + } - revert_retries++; - if (revert_retries >= 7) { // must always be an odd number! - DbpString(""); - DbpString(_CYAN_("Last Written Key: ")); - Dbhexdump(8, genkeyblock, false); - Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); - goto out; - } + revert_retries++; + if (revert_retries >= 7) { //must always be an odd number! + Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); + goto out; } } + } - if (msg->debug) { - if (status_message >= 1) { - DbpString(""); - DbpString("Card Select:............."_GREEN_("Ok!")); - } - if (status_message >= 2) { - DbpString("AA1 macs authentication:."_GREEN_("Ok!")); - } - if (status_message >= 3) { - DbpString("Privilege Escalation:...."_GREEN_("Ok!")); - } - if (status_message >= 4) { - DbpString("Wrote key: "); - Dbhexdump(8, genkeyblock, false); - } - if (status_message >= 5) { - DbpString("Key Update:.............."_GREEN_("Verified!")); - } - if (status_message >= 6) { - DbpString("Original Key Restore:...."_GREEN_("Ok!")); - } - if (status_message >= 7) { - DbpString("Original Key Restore:...."_GREEN_("Verified!")); - } - } - - if (write_error && (msg->debug || msg->test)) { // if there was a write error, re-run the loop for the same key index - DbpString("Loop Error: "_RED_("Repeating Loop!")); - card_select = false; - card_auth = false; - priv_esc = false; - } else { - loops++; - index++; - status_message = 2; - } - - }// end while - -fast_restore: - ;// empty statement for compilation - uint8_t mac2[4] = {0}; - uint8_t wb[9] = {0}; - uint8_t blockno = 3; - wb[0] = blockno; - bool reverted = false; - uint8_t revert_retries = 0; - - while (reverted == false) { - // Regain privilege escalation with a readcheck - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod); - memcpy(wb + 1, fast_restore_key, 8); - doMAC_N(wb, sizeof(wb), div_key2, mac2); - - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - if (iclass_writeblock_sp(blockno, fast_restore_key, mac2, shallow_mod, &start_time, &eof_time, short_delay)) { - status_message = 6; // restore of original key successful but unverified - } - - // Do a readcheck first to reset the cypher state - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - iclass_send_as_reader(read_check_cc2, sizeof(read_check_cc2), &start_time, &eof_time, shallow_mod); - - // need to craft the authentication payload accordingly - memcpy(msg->req.key, original_mac, 8); - - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac1); - if (res == true) { - status_message = 7; // restore of original key verified - card usable again - reverted = true; - } - - revert_retries++; - if (revert_retries >= 7) { // must always be an odd number! - DbpString(""); - DbpString(_CYAN_("Last Written Key (fast): ")); - Dbhexdump(8, fast_restore_key, false); - Dbprintf(_RED_("Attempted to restore original key for %3d times and failed. Stopping. Card is likely unusable."), revert_retries); - } - if (recovered) { - goto restore; - } else { + if (loops >= msg->loop) { + completed = true; goto out; } - } + if (!write_error) { //if there was a write error, re-run the loop for the same key index + loops++; + index++; + } + + }//end while + restore: - ;// empty statement for compilation + ;//empty statement for compilation uint8_t partialkey[PICOPASS_BLOCK_SIZE] = {0}; for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { - if (msg->fast) { - partialkey[i] = fast_restore_key[i] ^ bits_found; - } else { - partialkey[i] = genkeyblock[i] ^ bits_found; - } + partialkey[i] = genkeyblock[i] ^ bits_found; } - // Print the bits decimal value - DbpString(""); - DbpString(_RED_("--------------------------------------------------------")); - Dbprintf("Decimal Value of last 3 bits: " _GREEN_("[%3d]"), bits_found); - // Print the 24 bits found from k1 + //Print the 24 bits found from k1 DbpString(_RED_("--------------------------------------------------------")); DbpString(_RED_("SUCCESS! Raw Key Partial Bytes: ")); Dbhexdump(8, partialkey, false); @@ -3145,9 +2456,8 @@ out: switch_off(); if (completed) { reply_ng(CMD_HF_ICLASS_RECOVER, PM3_EINVARG, NULL, 0); - } else if (interrupted) { - reply_ng(CMD_HF_ICLASS_RECOVER, PM3_EOPABORTED, NULL, 0); } else { reply_ng(CMD_HF_ICLASS_RECOVER, PM3_ESOFT, NULL, 0); } + } diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 2d2bf8c42..2185fd794 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -34,7 +34,6 @@ // times in samples @ 212kHz when acting as reader #define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us #define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms -#define ICLASS_READER_TIMEOUT_UPDATE_FAST 1500 // A copy of ICLASS_READER_TIMEOUT_UPDATE with reduced timeout values #define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us // The length of a received command will in most cases be no more than 18 bytes. @@ -73,5 +72,4 @@ uint8_t get_pagemap(const picopass_hdr_t *hdr); void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod); void iClass_Recover(iclass_recover_req_t *msg); -void iClass_TearBlock(iclass_tearblock_req_t *msg); #endif diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 3f1f4595b..5165b5cad 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -36,9 +36,9 @@ #include "protocols.h" #include "generator.h" #include "desfire_crypto.h" // UL-C authentication helpers -#include "mifare.h" // for iso14a_polling_frame_t structure #define MAX_ISO14A_TIMEOUT 524288 + // this timeout is in MS static uint32_t iso14a_timeout; @@ -133,34 +133,6 @@ static uint32_t LastProxToAirDuration; #define SEC_Y 0x00 #define SEC_Z 0xc0 - -static const iso14a_polling_frame_t WUPA_CMD_FRAME = { - .frame = { ISO14443A_CMD_WUPA }, - .frame_length = 1, - .last_byte_bits = 7, - .extra_delay = 0 -}; - -static const iso14a_polling_frame_t MAGWUPA_CMD_FRAMES[] = { - {{ MAGSAFE_CMD_WUPA_1 }, 1, 7, 0}, - {{ MAGSAFE_CMD_WUPA_2 }, 1, 7, 0}, - {{ MAGSAFE_CMD_WUPA_3 }, 1, 7, 0}, - {{ MAGSAFE_CMD_WUPA_4 }, 1, 7, 0} -}; - -// Polling frames and configurations -iso14a_polling_parameters_t WUPA_POLLING_PARAMETERS = { - .frames = { {{ ISO14443A_CMD_WUPA }, 1, 7, 0 }}, - .frame_count = 1, - .extra_timeout = 0, -}; - -iso14a_polling_parameters_t REQA_POLLING_PARAMETERS = { - .frames = { {{ ISO14443A_CMD_REQA }, 1, 7, 0 }}, - .frame_count = 1, - .extra_timeout = 0, -}; - /* Default HF 14a config is set to: forceanticol = 0 (auto) @@ -168,17 +140,21 @@ Default HF 14a config is set to: forcecl2 = 0 (auto) forcecl3 = 0 (auto) forcerats = 0 (auto) - magsafe = 0 (disabled) - polling_loop_annotation = {{0}, 0, 0, 0} (disabled) */ -static hf14a_config_t hf14aconfig = { 0, 0, 0, 0, 0, 0, {{0}, 0, 0, 0} }; +static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ; -static iso14a_polling_parameters_t hf14a_polling_parameters = { - .frames = { {{ ISO14443A_CMD_WUPA }, 1, 7, 0 }}, + +// Polling frames and configurations +iso14a_polling_parameters_t WUPA_POLLING_PARAMETERS = { + .frames = { {{ ISO14443A_CMD_WUPA }, 1, 7, 0} }, .frame_count = 1, - .extra_timeout = 0 + .extra_timeout = 0, +}; +iso14a_polling_parameters_t REQA_POLLING_PARAMETERS = { + .frames = { {{ ISO14443A_CMD_REQA }, 1, 7, 0} }, + .frame_count = 1, + .extra_timeout = 0, }; - // parity isn't used much static uint8_t parity_array[MAX_PARITY_SIZE] = {0}; @@ -190,40 +166,31 @@ struct Crypto1State crypto1_state = {0, 0}; void printHf14aConfig(void) { DbpString(_CYAN_("HF 14a config")); - Dbprintf(" [a] Anticol override........... %s%s%s", + Dbprintf(" [a] Anticol override.... %s%s%s", (hf14aconfig.forceanticol == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forceanticol == 1) ? _RED_("force") " ( always do anticol )" : "", (hf14aconfig.forceanticol == 2) ? _RED_("skip") " ( always skip anticol )" : "" ); - Dbprintf(" [b] BCC override............... %s%s%s", + Dbprintf(" [b] BCC override........ %s%s%s", (hf14aconfig.forcebcc == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forcebcc == 1) ? _RED_("fix") " ( fix bad BCC )" : "", (hf14aconfig.forcebcc == 2) ? _RED_("ignore") " ( ignore bad BCC, always use card BCC )" : "" ); - Dbprintf(" [2] CL2 override............... %s%s%s", + Dbprintf(" [2] CL2 override........ %s%s%s", (hf14aconfig.forcecl2 == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forcecl2 == 1) ? _RED_("force") " ( always do CL2 )" : "", (hf14aconfig.forcecl2 == 2) ? _RED_("skip") " ( always skip CL2 )" : "" ); - Dbprintf(" [3] CL3 override............... %s%s%s", + Dbprintf(" [3] CL3 override........ %s%s%s", (hf14aconfig.forcecl3 == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forcecl3 == 1) ? _RED_("force") " ( always do CL3 )" : "", (hf14aconfig.forcecl3 == 2) ? _RED_("skip") " ( always skip CL3 )" : "" ); - Dbprintf(" [r] RATS override.............. %s%s%s", + Dbprintf(" [r] RATS override....... %s%s%s", (hf14aconfig.forcerats == 0) ? _GREEN_("std") " ( follow standard )" : "", (hf14aconfig.forcerats == 1) ? _RED_("force") " ( always do RATS )" : "", (hf14aconfig.forcerats == 2) ? _RED_("skip") " ( always skip RATS )" : "" ); - Dbprintf(" [m] Magsafe polling............ %s", - (hf14aconfig.magsafe == 1) ? _GREEN_("enabled") : _YELLOW_("disabled") - ); - Dbprintf(" [p] Polling loop annotation.... %s %*D", - (hf14aconfig.polling_loop_annotation.frame_length <= 0) ? _YELLOW_("disabled") : _GREEN_("enabled"), - hf14aconfig.polling_loop_annotation.frame_length, - hf14aconfig.polling_loop_annotation.frame, - "" - ); } /** @@ -234,64 +201,21 @@ void printHf14aConfig(void) { * @brief setSamplingConfig * @param sc */ -void setHf14aConfig(const hf14a_config_t *hc) { - if ((hc->forceanticol >= 0) && (hc->forceanticol <= 2)) { +void setHf14aConfig(const hf14a_config *hc) { + + if ((hc->forceanticol >= 0) && (hc->forceanticol <= 2)) hf14aconfig.forceanticol = hc->forceanticol; - } - - if ((hc->forcebcc >= 0) && (hc->forcebcc <= 2)) { + if ((hc->forcebcc >= 0) && (hc->forcebcc <= 2)) hf14aconfig.forcebcc = hc->forcebcc; - } - - if ((hc->forcecl2 >= 0) && (hc->forcecl2 <= 2)) { + if ((hc->forcecl2 >= 0) && (hc->forcecl2 <= 2)) hf14aconfig.forcecl2 = hc->forcecl2; - } - - if ((hc->forcecl3 >= 0) && (hc->forcecl3 <= 2)) { + if ((hc->forcecl3 >= 0) && (hc->forcecl3 <= 2)) hf14aconfig.forcecl3 = hc->forcecl3; - } - - if ((hc->forcerats >= 0) && (hc->forcerats <= 2)) { + if ((hc->forcerats >= 0) && (hc->forcerats <= 2)) hf14aconfig.forcerats = hc->forcerats; - } - - if ((hc->magsafe >= 0) && (hc->magsafe <= 1)) { - hf14aconfig.magsafe = hc->magsafe; - } - - if (hc->polling_loop_annotation.frame_length >= 0) { - memcpy(&hf14aconfig.polling_loop_annotation, &hc->polling_loop_annotation, sizeof(iso14a_polling_frame_t)); - } - - // iceman: Somehow I think we should memcpy WUPA_CMD and all other hf14a_polling_parameters.frames[xxx] assignments - // right now we are assigning... - - // Derive polling loop configuration based on 14a config - hf14a_polling_parameters.frames[0] = WUPA_CMD_FRAME; - hf14a_polling_parameters.frame_count = 1; - hf14a_polling_parameters.extra_timeout = 0; - - if (hf14aconfig.magsafe == 1) { - - for (int i = 0; i < ARRAYLEN(MAGWUPA_CMD_FRAMES); i++) { - if (hf14a_polling_parameters.frame_count < ARRAYLEN(hf14a_polling_parameters.frames) - 1) { - hf14a_polling_parameters.frames[hf14a_polling_parameters.frame_count] = MAGWUPA_CMD_FRAMES[i]; - hf14a_polling_parameters.frame_count++; - } - } - } - - if (hf14aconfig.polling_loop_annotation.frame_length > 0) { - - if (hf14a_polling_parameters.frame_count < ARRAYLEN(hf14a_polling_parameters.frames) - 1) { - hf14a_polling_parameters.frames[hf14a_polling_parameters.frame_count] = hf14aconfig.polling_loop_annotation; - hf14a_polling_parameters.frame_count++; - } - hf14a_polling_parameters.extra_timeout = 250; - } } -hf14a_config_t *getHf14aConfig(void) { +hf14a_config *getHf14aConfig(void) { return &hf14aconfig; } @@ -370,16 +294,16 @@ tUart14a *GetUart14a(void) { void Uart14aReset(void) { Uart.state = STATE_14A_UNSYNCD; - Uart.shiftReg = 0; // shiftreg to hold decoded data bits Uart.bitCount = 0; Uart.len = 0; // number of decoded data bytes - Uart.posCnt = 0; - Uart.syncBit = 9999; - Uart.parityBits = 0; // holds 8 parity bits Uart.parityLen = 0; // number of decoded parity bytes - Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits + Uart.shiftReg = 0; // shiftreg to hold decoded data bits + Uart.parityBits = 0; // holds 8 parity bits Uart.startTime = 0; Uart.endTime = 0; + Uart.fourBits = 0x00000000; // clear the buffer for 4 Bits + Uart.posCnt = 0; + Uart.syncBit = 9999; } void Uart14aInit(uint8_t *d, uint16_t n, uint8_t *par) { @@ -596,9 +520,6 @@ void Demod14aInit(uint8_t *d, uint16_t n, uint8_t *par) { RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time) { if (Demod.len == Demod.output_len) { - // Flush last parity bits - Demod.parityBits <<= (8 - (Demod.len & 0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them return true; } @@ -671,7 +592,7 @@ RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_t if (Demod.bitCount > 0) { // there are some remaining data bits Demod.shiftReg >>= (9 - Demod.bitCount); // right align the decoded bits - Demod.output[Demod.len++] = (Demod.shiftReg & 0xff); // and add them to the output + Demod.output[Demod.len++] = Demod.shiftReg & 0xff; // and add them to the output Demod.parityBits <<= 1; // add a (void) parity bit Demod.parityBits <<= (8 - (Demod.len & 0x0007)); // left align remaining parity bits Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them @@ -697,9 +618,6 @@ RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_t static RAMFUNC int ManchesterDecoding_Thinfilm(uint8_t bit) { if (Demod.len == Demod.output_len) { - // Flush last parity bits - Demod.parityBits <<= (8 - (Demod.len & 0x0007)); // left align remaining parity bits - Demod.parity[Demod.parityLen++] = Demod.parityBits; // and store them return true; } @@ -811,12 +729,12 @@ void RAMFUNC SniffIso14443a(uint8_t param) { set_tracing(true); // The command (reader -> tag) that we're receiving. - uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE); - uint8_t *receivedCmdPar = BigBuf_calloc(MAX_PARITY_SIZE); + uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE); + uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE); // The response (tag -> reader) that we're receiving. - uint8_t *receivedResp = BigBuf_calloc(MAX_FRAME_SIZE); - uint8_t *receivedRespPar = BigBuf_calloc(MAX_PARITY_SIZE); + uint8_t *receivedResp = BigBuf_malloc(MAX_FRAME_SIZE); + uint8_t *receivedRespPar = BigBuf_malloc(MAX_PARITY_SIZE); uint8_t previous_data = 0; int maxDataLen = 0, dataLen; @@ -1188,24 +1106,9 @@ bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_ } } -static void Simulate_reread_ulc_key(uint8_t *ulc_key) { - // copy UL-C key from emulator memory - - mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr(); - - memcpy(ulc_key, mfu_header->data + (0x2D * 4), 4); - memcpy(ulc_key + 4, mfu_header->data + (0x2C * 4), 4); - memcpy(ulc_key + 8, mfu_header->data + (0x2F * 4), 4); - memcpy(ulc_key + 12, mfu_header->data + (0x2E * 4), 4); - - reverse_array(ulc_key, 4); - reverse_array(ulc_key + 4, 4); - reverse_array(ulc_key + 8, 4); - reverse_array(ulc_key + 12, 4); -} bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_t *ats, size_t ats_len, tag_response_info_t **responses, - uint32_t *cuid, uint8_t *pages, uint8_t *ulc_key) { + uint32_t *cuid, uint32_t counters[3], uint8_t tearings[3], uint8_t *pages) { uint8_t sak = 0; // The first response contains the ATQA (note: bytes are transmitted in reverse order). static uint8_t rATQA[2] = { 0x00 }; @@ -1252,11 +1155,14 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr(); *pages = MAX(mfu_header->pages, 15); - // tearing flags + // counters and tearing flags // for old dumps with all zero headers, we need to set default values. for (uint8_t i = 0; i < 3; i++) { - if (mfu_header->counter_tearing[i][3] == 0x00) { - mfu_header->counter_tearing[i][3] = 0xBD; + + counters[i] = le24toh(mfu_header->counter_tearing[i]); + + if (mfu_header->counter_tearing[i][3] != 0x00) { + tearings[i] = mfu_header->counter_tearing[i][3]; } } @@ -1304,11 +1210,14 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr(); *pages = MAX(mfu_header->pages, 19); - // tearing flags + // counters and tearing flags // for old dumps with all zero headers, we need to set default values. for (uint8_t i = 0; i < 3; i++) { - if (mfu_header->counter_tearing[i][3] == 0x00) { - mfu_header->counter_tearing[i][3] = 0xBD; + + counters[i] = le24toh(mfu_header->counter_tearing[i]); + + if (mfu_header->counter_tearing[i][3] != 0x00) { + tearings[i] = mfu_header->counter_tearing[i][3]; } } @@ -1355,38 +1264,6 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, sak = 0x20; break; } - case 13: { // MIFARE Ultralight-C - - rATQA[0] = 0x44; - sak = 0x00; - - // some first pages of UL/NTAG dump is special data - mfu_dump_t *mfu_header = (mfu_dump_t *) BigBuf_get_EM_addr(); - *pages = MAX(mfu_header->pages, 47); - - // copy UL-C key from emulator memory - memcpy(ulc_key, mfu_header->data + (0x2D * 4), 4); - memcpy(ulc_key + 4, mfu_header->data + (0x2C * 4), 4); - memcpy(ulc_key + 8, mfu_header->data + (0x2F * 4), 4); - memcpy(ulc_key + 12, mfu_header->data + (0x2E * 4), 4); - - reverse_array(ulc_key, 4); - reverse_array(ulc_key + 4, 4); - reverse_array(ulc_key + 8, 4); - reverse_array(ulc_key + 12, 4); - - /* - Dbprintf("UL-C Pages....... %u ( 47 )", *pages); - DbpString("UL-C 3des key... "); - Dbhexdump(16, ulc_key, false); - */ - - if (IS_FLAG_UID_IN_DATA(flags, 7)) { - DbpString("UL-C UID........ "); - Dbhexdump(7, data, false); - } - break; - } default: { if (g_dbglevel >= DBG_ERROR) Dbprintf("Error: unknown tagtype (%d)", tagType); return false; @@ -1412,7 +1289,7 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, // if uid not supplied then get from emulator memory if ((memcmp(data, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 10) == 0) || IS_FLAG_UID_IN_EMUL(flags)) { - if (tagType == 2 || tagType == 7 || tagType == 13) { + if (tagType == 2 || tagType == 7) { uint16_t start = MFU_DUMP_PREFIX_LENGTH; uint8_t emdata[8]; emlGet(emdata, start, sizeof(emdata)); @@ -1579,18 +1456,15 @@ bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, // 'hf 14a sim' //----------------------------------------------------------------------------- void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uint8_t exitAfterNReads, - uint8_t *ats, size_t ats_len, bool ulc_part1, bool ulc_part2) { + uint8_t *ats, size_t ats_len) { #define ATTACK_KEY_COUNT 16 -#define ULC_TAG_NONCE "\x01\x02\x03\x04\x05\x06\x07\x08" tag_response_info_t *responses; uint32_t cuid = 0; uint32_t nonce = 0; - /// Ultralight-C 3des2k - uint8_t ulc_key[16] = { 0x00 }; - uint8_t ulc_iv[8] = { 0x00 }; - bool ulc_reread_key = false; + uint32_t counters[3] = { 0x00, 0x00, 0x00 }; + uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd }; uint8_t pages = 0; // Here, we collect CUID, block1, keytype1, NT1, NR1, AR1, CUID, block2, keytyp2, NT2, NR2, AR2 @@ -1634,24 +1508,12 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin .modulation_n = 0 }; - if (SimulateIso14443aInit(tagType, flags, useruid, ats, ats_len - , &responses, &cuid, &pages - , ulc_key) == false) { + if (SimulateIso14443aInit(tagType, flags, useruid, ats, ats_len, &responses, &cuid, counters, tearings, &pages) == false) { BigBuf_free_keep_EM(); reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0); return; } - mfu_dump_t *mfu_em_dump = NULL; - if (tagType == 2 || tagType == 7) { - mfu_em_dump = (mfu_dump_t *)BigBuf_get_EM_addr(); - if (!mfu_em_dump) { - if (g_dbglevel >= DBG_ERROR) Dbprintf("[-] ERROR: Failed to get EM address for MFU/NTAG operations."); - reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EMALLOC, NULL, 0); - return; - } - } - // We need to listen to the high-frequency, peak-detected path. iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN); @@ -1724,7 +1586,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin order = ORDER_NONE; // back to work state p_response = NULL; - } else if (order == ORDER_AUTH && len == 8 && tagType != 2 && tagType != 7 && tagType != 13) { + } else if (order == ORDER_AUTH && len == 8) { // Received {nr] and {ar} (part of authentication) LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); uint32_t nr = bytes_to_num(receivedCmd, 4); @@ -1814,21 +1676,21 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin } else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ uint8_t block = receivedCmd[1]; // if Ultralight or NTAG (4 byte blocks) - if (tagType == 7 || tagType == 2 || tagType == 13) { + if (tagType == 7 || tagType == 2) { if (block > pages) { // send NACK 0x0 == invalid argument EmSend4bit(CARD_NACK_IV); } else { // first blocks of emu are header uint16_t start = (block * 4) + MFU_DUMP_PREFIX_LENGTH; - uint8_t emdata[MIFARE_BLOCK_SIZE + CRC16_SIZE] = {0}; + uint8_t emdata[MAX_MIFARE_FRAME_SIZE] = {0}; emlGet(emdata, start, MIFARE_BLOCK_SIZE); AddCrc14A(emdata, MIFARE_BLOCK_SIZE); EmSendCmd(emdata, sizeof(emdata)); numReads++; // Increment number of times reader requested a block if (exitAfterNReads > 0 && numReads == exitAfterNReads) { - Dbprintf("[MFUEMUL_WORK] " _YELLOW_("%u") " reads done, exiting", numReads); + Dbprintf("[MFUEMUL_WORK] %d reads done, exiting", numReads); finished = true; } } @@ -1840,7 +1702,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin // block1 = 4byte UID. p_response = &responses[RESP_INDEX_UIDC1]; } else { // all other tags (16 byte block tags) - uint8_t emdata[MIFARE_BLOCK_SIZE + CRC16_SIZE] = {0}; + uint8_t emdata[MAX_MIFARE_FRAME_SIZE] = {0}; emlGet(emdata, block, MIFARE_BLOCK_SIZE); AddCrc14A(emdata, MIFARE_BLOCK_SIZE); EmSendCmd(emdata, sizeof(emdata)); @@ -1863,7 +1725,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin EmSendCmd(emdata, len + 2); } p_response = NULL; - } else if (receivedCmd[0] == MIFARE_ULC_WRITE && len == 8 && (tagType == 2 || tagType == 7 || tagType == 13)) { // Received a WRITE + } else if (receivedCmd[0] == MIFARE_ULC_WRITE && len == 8 && (tagType == 2 || tagType == 7)) { // Received a WRITE p_response = NULL; @@ -1901,15 +1763,12 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin // send ACK EmSend4bit(CARD_ACK); - if (tagType == 13 && block >= 0x2c && block <= 0x2F) { - ulc_reread_key = true; - } } else { // send NACK 0x1 == crc/parity error EmSend4bit(CARD_NACK_PA); } goto jump; - } else if (receivedCmd[0] == MIFARE_ULC_COMP_WRITE && len == 4 && (tagType == 2 || tagType == 7 || tagType == 13)) { + } else if (receivedCmd[0] == MIFARE_ULC_COMP_WRITE && len == 4 && (tagType == 2 || tagType == 7)) { // cmd + block + 2 bytes crc if (CheckCrc14A(receivedCmd, len)) { wrblock = receivedCmd[1]; @@ -1935,8 +1794,8 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin // send NACK 0x0 == invalid argument EmSend4bit(CARD_NACK_IV); } else { - uint8_t cmd[] = {0, 0, 0, 0x14, 0xa5}; - memcpy(cmd, mfu_em_dump->counter_tearing[index], 3); + uint8_t cmd[] = {0x00, 0x00, 0x00, 0x14, 0xa5}; + htole24(counters[index], cmd); AddCrc14A(cmd, sizeof(cmd) - 2); EmSendCmd(cmd, sizeof(cmd)); } @@ -1947,16 +1806,13 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin // send NACK 0x0 == invalid argument EmSend4bit(CARD_NACK_IV); } else { - uint32_t val = le24toh(mfu_em_dump->counter_tearing[index]); // get current counter value - val += le24toh(receivedCmd + 2); // increment in - + uint32_t val = le24toh(receivedCmd + 2) + counters[index]; // if new value + old value is bigger 24bits, fail if (val > 0xFFFFFF) { // send NACK 0x4 == counter overflow EmSend4bit(CARD_NACK_NA); } else { - htole24(val, mfu_em_dump->counter_tearing[index]); - + counters[index] = val; // send ACK EmSend4bit(CARD_ACK); } @@ -1970,7 +1826,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin EmSend4bit(CARD_NACK_IV); } else { uint8_t cmd[3] = {0, 0, 0}; - cmd[0] = mfu_em_dump->counter_tearing[index][3]; + cmd[0] = tearings[index]; AddCrc14A(cmd, sizeof(cmd) - 2); EmSendCmd(cmd, sizeof(cmd)); } @@ -1983,7 +1839,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin p_response = &responses[RESP_INDEX_VERSION]; } else if (receivedCmd[0] == MFDES_GET_VERSION && len == 4 && (tagType == 3)) { p_response = &responses[RESP_INDEX_VERSION]; - } else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7 && tagType != 13) { // Received an authentication request + } else if ((receivedCmd[0] == MIFARE_AUTH_KEYA || receivedCmd[0] == MIFARE_AUTH_KEYB) && len == 4 && tagType != 2 && tagType != 7) { // Received an authentication request cardAUTHKEY = receivedCmd[0] - 0x60; cardAUTHSC = receivedCmd[1] / 4; // received block num @@ -2002,77 +1858,9 @@ void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uin } else { p_response = &responses[RESP_INDEX_ATS]; } - } else if (receivedCmd[0] == MIFARE_ULC_AUTH_1 && len == 4 && tagType == 13) { // ULC authentication, or Desfire Authentication - - // reset IV to all zeros - memset(ulc_iv, 0x00, 8); - - if (ulc_reread_key) { - Simulate_reread_ulc_key(ulc_key); - ulc_reread_key = false; - } - - dynamic_response_info.response[0] = MIFARE_ULC_AUTH_2; - - // our very random TAG NONCE - memcpy(dynamic_response_info.response + 1, ULC_TAG_NONCE, 8); - - if (ulc_part1) { - memset(dynamic_response_info.response + 1, 0, 8); - } else { - // encrypt TAG NONCE - tdes_nxp_send(dynamic_response_info.response + 1, dynamic_response_info.response + 1, 8, ulc_key, ulc_iv, 2); - } - - // Add CRC - AddCrc14A(dynamic_response_info.response, 9); - - // prepare to send - dynamic_response_info.response_n = 1 + 8 + 2; - prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE); - p_response = &dynamic_response_info; - order = ORDER_AUTH; - - } else if (receivedCmd[0] == MIFARE_ULC_AUTH_2 && len == 19 && tagType == 13) { // ULC authentication, or Desfire Authentication - - uint8_t enc_rnd_ab[16] = { 0x00 }; - uint8_t rnd_ab[16] = { 0x00 }; - - // copy reader response - memcpy(enc_rnd_ab, receivedCmd + 1, 16); - - // decrypt - tdes_nxp_receive(enc_rnd_ab, rnd_ab, 16, ulc_key, ulc_iv, 2); - - ror(rnd_ab + 8, 8); - - if (memcmp(rnd_ab + 8, ULC_TAG_NONCE, 8) != 0) { - Dbprintf("failed authentication"); - } - - // OK response - dynamic_response_info.response[0] = 0x00; - - if (ulc_part2) { - // try empty auth but with correct CRC and 0x00 command - memset(dynamic_response_info.response + 1, 0, 8); - } else { - // rol RndA - rol(rnd_ab, 8); - - // encrypt RndA - tdes_nxp_send(rnd_ab, dynamic_response_info.response + 1, 8, ulc_key, ulc_iv, 2); - } - - // Add CRC - AddCrc14A(dynamic_response_info.response, 9); - - dynamic_response_info.response_n = 1 + 8 + 2; - - prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE); - p_response = &dynamic_response_info; - order = ORDER_NONE; - + } else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication + LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true); + p_response = NULL; } else if (receivedCmd[0] == MIFARE_ULEV1_AUTH && len == 7 && tagType == 7) { // NTAG / EV-1 uint8_t pwd[4] = {0, 0, 0, 0}; emlGet(pwd, (pages - 1) * 4 + MFU_DUMP_PREFIX_LENGTH, sizeof(pwd)); @@ -2253,16 +2041,13 @@ jump: // of bits specified in the delay parameter. static void PrepareDelayedTransfer(uint16_t delay) { delay &= 0x07; - if (delay == 0) { - return; - } + if (!delay) return; uint8_t bitmask = 0; uint8_t bits_shifted = 0; - for (uint16_t i = 0; i < delay; i++) { + for (uint16_t i = 0; i < delay; i++) bitmask |= (0x01 << i); - } tosend_t *ts = get_tosend(); @@ -2291,7 +2076,6 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing Dbprintf("Warning: HF field is off"); return; } - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); if (timing) { @@ -2466,7 +2250,7 @@ int EmGetCmd(uint8_t *received, uint16_t received_max_len, uint16_t *len, uint8_ // button press, takes a bit time, might mess with simualtion if (checker-- == 0) { if (BUTTON_PRESS()) { - Dbprintf("----------- " _GREEN_("Button pressed, user aborted") " ----------"); + Dbprintf("----------- " _GREEN_("Breaking / User aborted") " ----------"); return false; } @@ -2576,7 +2360,7 @@ int EmSendCmd14443aRaw(const uint8_t *resp, uint16_t respLen) { int EmSend4bit(uint8_t resp) { Code4bitAnswerAsTag(resp); - const tosend_t *ts = get_tosend(); + tosend_t *ts = get_tosend(); int res = EmSendCmd14443aRaw(ts->buf, ts->max); // do the tracing for the previous reader request and this tag answer: uint8_t par[1] = {0x00}; @@ -2598,7 +2382,7 @@ int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par) { } int EmSendCmdParEx(uint8_t *resp, uint16_t respLen, uint8_t *par, bool collision) { CodeIso14443aAsTagPar(resp, respLen, par, collision); - const tosend_t *ts = get_tosend(); + tosend_t *ts = get_tosend(); int res = EmSendCmd14443aRaw(ts->buf, ts->max); // do the tracing for the previous reader request and this tag answer: @@ -2644,9 +2428,9 @@ int EmSendPrecompiledCmd(tag_response_info_t *p_response) { return ret; } -bool EmLogTrace(const uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, - uint32_t reader_EndTime, const uint8_t *reader_Parity, const uint8_t *tag_data, - uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, const uint8_t *tag_Parity) { +bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, + uint32_t reader_EndTime, uint8_t *reader_Parity, uint8_t *tag_data, + uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity) { // we cannot exactly measure the end and start of a received command from reader. However we know that the delay from // end of the received command to start of the tag's (simulated by us) answer is n*128+20 or n*128+84 resp. @@ -2765,27 +2549,28 @@ static int GetIso14443aAnswerFromTag(uint8_t *receivedResponse, uint16_t rec_max return false; } -void ReaderTransmitBitsPar(const uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing) { +void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing) { + CodeIso14443aBitsAsReaderPar(frame, bits, par); // Send command to tag - const tosend_t *ts = get_tosend(); + tosend_t *ts = get_tosend(); TransmitFor14443a(ts->buf, ts->max, timing); if (g_trigger) LED_A_ON(); LogTrace(frame, nbytes(bits), (LastTimeProxToAirStart << 4) + DELAY_ARM2AIR_AS_READER, ((LastTimeProxToAirStart + LastProxToAirDuration) << 4) + DELAY_ARM2AIR_AS_READER, par, true); } -void ReaderTransmitPar(const uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing) { +void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing) { ReaderTransmitBitsPar(frame, len * 8, par, timing); } -static void ReaderTransmitBits(const uint8_t *frame, uint16_t len, uint32_t *timing) { +static void ReaderTransmitBits(uint8_t *frame, uint16_t len, uint32_t *timing) { // Generate parity and redirect GetParity(frame, len / 8, parity_array); ReaderTransmitBitsPar(frame, len, parity_array, timing); } -void ReaderTransmit(const uint8_t *frame, uint16_t len, uint32_t *timing) { +void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing) { // Generate parity and redirect GetParity(frame, len, parity_array); ReaderTransmitBitsPar(frame, len * 8, parity_array, timing); @@ -2823,9 +2608,9 @@ void iso14443a_antifuzz(uint32_t flags) { int len = 0; // allocate buffers: - uint8_t *received = BigBuf_calloc(MAX_FRAME_SIZE); - uint8_t *receivedPar = BigBuf_calloc(MAX_PARITY_SIZE); - uint8_t *resp = BigBuf_calloc(20); + uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE); + uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE); + uint8_t *resp = BigBuf_malloc(20); memset(received, 0x00, MAX_FRAME_SIZE); memset(received, 0x00, MAX_PARITY_SIZE); @@ -2912,40 +2697,30 @@ static void iso14a_set_ATS_times(const uint8_t *ats) { } -static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, const iso14a_polling_parameters_t *polling_parameters) { -#define RETRY_TIMEOUT 10 +static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, iso14a_polling_parameters_t *polling_parameters) { +#define WUPA_RETRY_TIMEOUT 10 uint32_t save_iso14a_timeout = iso14a_get_timeout(); iso14a_set_timeout(1236 / 128 + 1); // response to WUPA is expected at exactly 1236/fc. No need to wait longer. - // refactored to use local pointer, now no modification of polling_parameters pointer is done - // I don't think the intention was to modify polling_parameters when sending in WUPA_POLLING_PARAMETERS etc. - // Modify polling_params, if null use default values. - iso14a_polling_parameters_t p; - memcpy(&p, (uint8_t *)polling_parameters, sizeof(iso14a_polling_parameters_t)); - - if (polling_parameters == NULL) { - memcpy(&p, (uint8_t *)&hf14a_polling_parameters, sizeof(iso14a_polling_parameters_t)); - } - bool first_try = true; - int len; - uint32_t retry_timeout = ((RETRY_TIMEOUT * p.frame_count) + p.extra_timeout); + uint32_t retry_timeout = WUPA_RETRY_TIMEOUT * polling_parameters->frame_count + polling_parameters->extra_timeout; uint32_t start_time = 0; - uint8_t curr = 0; + int len; + + uint8_t current_frame = 0; - // Use the temporary polling parameters do { - const iso14a_polling_frame_t *frp = &p.frames[curr]; + iso14a_polling_frame_t *frame_parameters = &polling_parameters->frames[current_frame]; - if (frp->last_byte_bits == 8) { - ReaderTransmit(frp->frame, frp->frame_length, NULL); + if (frame_parameters->last_byte_bits == 8) { + ReaderTransmit(frame_parameters->frame, frame_parameters->frame_length, NULL); } else { - ReaderTransmitBitsPar(frp->frame, frp->last_byte_bits, NULL, NULL); + ReaderTransmitBitsPar(frame_parameters->frame, frame_parameters->last_byte_bits, NULL, NULL); } - if (frp->extra_delay) { - SpinDelay(frp->extra_delay); + if (frame_parameters->extra_delay) { + SpinDelay(frame_parameters->extra_delay); } // Receive the ATQA @@ -2954,12 +2729,12 @@ static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, const is // We set the start_time here otherwise in some cases we miss the window and only ever try once if (first_try) { start_time = GetTickCount(); - first_try = false; } - // Go over frame configurations, loop back when we reach the end - curr = (curr < (p.frame_count - 1)) ? curr + 1 : 0; + first_try = false; + // Go over frame configurations, loop back when we reach the end + current_frame = current_frame < (polling_parameters->frame_count - 1) ? current_frame + 1 : 0; } while (len == 0 && GetTickCountDelta(start_time) <= retry_timeout); iso14a_set_timeout(save_iso14a_timeout); @@ -2968,14 +2743,10 @@ static int GetATQA(uint8_t *resp, uint16_t resp_len, uint8_t *resp_par, const is int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats) { - return iso14443a_select_cardEx(uid_ptr, p_card, cuid_ptr, anticollision, num_cascades, no_rats, NULL, false); -} -int iso14443a_select_card_for_magic(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades) { - // Bug fix: When SAK is 0x00, `iso14443a_select_cardEx` would return too early at - // line "if (hf14aconfig.forcerats == 0)".`force_rats` is used to force RATS execution and ATS retrieval. - return iso14443a_select_cardEx(uid_ptr, p_card, cuid_ptr, anticollision, num_cascades, false, NULL, true); + return iso14443a_select_cardEx(uid_ptr, p_card, cuid_ptr, anticollision, num_cascades, no_rats, &WUPA_POLLING_PARAMETERS); } + // performs iso14443a anticollision (optional) and card select procedure // fills the uid and cuid pointer unless NULL // fills the card info record unless NULL @@ -2984,7 +2755,7 @@ int iso14443a_select_card_for_magic(uint8_t *uid_ptr, iso14a_card_select_t *p_ca // requests ATS unless no_rats is true int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats, - const iso14a_polling_parameters_t *polling_parameters, bool force_rats) { + iso14a_polling_parameters_t *polling_parameters) { uint8_t resp[MAX_FRAME_SIZE] = {0}; // theoretically. A usual RATS will be much smaller @@ -3039,9 +2810,8 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint if (anticollision) { // clear uid - if (uid_ptr) { + if (uid_ptr) memset(uid_ptr, 0, 10); - } } if (hf14aconfig.forceanticol == 0) { @@ -3202,18 +2972,18 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint p_card->sak = sak; } - if (hf14aconfig.forcerats == 0 && force_rats == false) { + if (hf14aconfig.forcerats == 0) { // PICC compliant with iso14443a-4 ---> (SAK & 0x20 != 0) if ((sak & 0x20) == 0) { return 2; } - } else if (hf14aconfig.forcerats == 2 && force_rats == false) { + } else if (hf14aconfig.forcerats == 2) { if ((sak & 0x20) != 0) Dbprintf("Skipping RATS according to hf 14a config"); return 2; } // else force RATS - if ((sak & 0x20) == 0 && force_rats == false) Dbprintf("Forcing RATS according to hf 14a config"); + if ((sak & 0x20) == 0) Dbprintf("Forcing RATS according to hf 14a config"); // RATS, Request for answer to select if (no_rats == false) { @@ -3239,14 +3009,14 @@ int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint return 1; } -int iso14443a_fast_select_card(const uint8_t *uid_ptr, uint8_t num_cascades) { +int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades) { uint8_t resp[3] = { 0 }; // theoretically. max 1 Byte SAK, 2 Byte CRC, 3 bytes is enough uint8_t resp_par[1] = {0}; uint8_t sak = 0x04; // cascade uid int cascade_level = 1; - if (GetATQA(resp, sizeof(resp), resp_par, NULL) == 0) { + if (GetATQA(resp, sizeof(resp), resp_par, &WUPA_POLLING_PARAMETERS) == 0) { return 0; } @@ -3479,8 +3249,7 @@ void ReaderIso14443a(PacketCommandNG *c) { true, 0, ((param & ISO14A_NO_RATS) == ISO14A_NO_RATS), - ((param & ISO14A_USE_CUSTOM_POLLING) == ISO14A_USE_CUSTOM_POLLING) ? (iso14a_polling_parameters_t *)cmd : NULL, - false + ((param & ISO14A_USE_CUSTOM_POLLING) == ISO14A_USE_CUSTOM_POLLING) ? (iso14a_polling_parameters_t *)cmd : &WUPA_POLLING_PARAMETERS ); // TODO: Improve by adding a cmd parser pointer and moving it by struct length to allow combining data with polling params FpgaDisableTracing(); @@ -3658,23 +3427,17 @@ OUT: // Therefore try in alternating directions. static int32_t dist_nt(uint32_t nt1, uint32_t nt2) { - if (nt1 == nt2) { - return 0; - } + if (nt1 == nt2) return 0; uint32_t nttmp1 = nt1; uint32_t nttmp2 = nt2; for (uint16_t i = 1; i < 32768; i++) { nttmp1 = prng_successor(nttmp1, 1); - if (nttmp1 == nt2) { - return i; - } + if (nttmp1 == nt2) return i; nttmp2 = prng_successor(nttmp2, 1); - if (nttmp2 == nt1) { - return -i; - } + if (nttmp2 == nt1) return -i; } return (-99999); // either nt1 or nt2 are invalid nonces @@ -3682,8 +3445,8 @@ static int32_t dist_nt(uint32_t nt1, uint32_t nt2) { #define PRNG_SEQUENCE_LENGTH (1 << 16) -#define MAX_UNEXPECTED_RANDOM (4) // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up. -#define MAX_SYNC_TRIES (32) +#define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up. +#define MAX_SYNC_TRIES 32 //----------------------------------------------------------------------------- // Recover several bits of the cypher stream. This implements (first stages of) @@ -3813,9 +3576,8 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); // Receive the (4 Byte) "random" TAG nonce - if (ReaderReceive(receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar) != 4) { + if (ReaderReceive(receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar) != 4) continue; - } previous_nt = nt; nt = bytes_to_num(receivedAnswer, 4); @@ -3838,9 +3600,9 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { // we didn't calibrate our clock yet, // iceman: has to be calibrated every time. - if (previous_nt && (nt_attacked == 0)) { + if (previous_nt && !nt_attacked) { - int32_t nt_distance = dist_nt(previous_nt, nt); + int nt_distance = dist_nt(previous_nt, nt); // if no distance between, then we are in sync. if (nt_distance == 0) { @@ -3866,9 +3628,7 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { sync_cycles = (sync_cycles - nt_distance) / elapsed_prng_sequences; // no negative sync_cycles, and too small sync_cycles will result in continuous misses - if (sync_cycles <= 10) { - sync_cycles += PRNG_SEQUENCE_LENGTH; - } + if (sync_cycles <= 10) sync_cycles += PRNG_SEQUENCE_LENGTH; // reset sync_cycles if (sync_cycles > PRNG_SEQUENCE_LENGTH * 2) { @@ -3876,14 +3636,8 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { sync_time = GetCountSspClk() & 0xfffffff8; } - if (g_dbglevel >= DBG_EXTENDED) { - Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n" - , i - , nt_distance - , elapsed_prng_sequences - , sync_cycles - ); - } + if (g_dbglevel >= DBG_EXTENDED) + Dbprintf("calibrating in cycle %d. nt_distance=%d, elapsed_prng_sequences=%d, new sync_cycles: %d\n", i, nt_distance, elapsed_prng_sequences, sync_cycles); continue; } @@ -3913,9 +3667,8 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { } else { sync_cycles += catch_up_cycles; - if (g_dbglevel >= DBG_EXTENDED) { + if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Lost sync in cycle %d for the fourth time consecutively (nt_distance = %d). Adjusting sync_cycles to %d.\n", i, catch_up_cycles, sync_cycles); - } last_catch_up = 0; catch_up_cycles = 0; @@ -3928,9 +3681,8 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { if (received_nack) { catch_up_cycles = 8; // the PRNG is delayed by 8 cycles due to the NAC (4Bits = 0x05 encrypted) transfer - if (nt_diff == 0) { + if (nt_diff == 0) par_low = par[0] & 0xE0; // there is no need to check all parities for other nt_diff. Parity Bits for mf_nr_ar[0..2] won't change - } par_list[nt_diff] = reflect8(par[0]); ks_list[nt_diff] = receivedAnswer[0] ^ 0x05; // xor with NACK value to get keystream @@ -3949,15 +3701,12 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { } else { // No NACK. if (nt_diff == 0 && first_try) { - par[0]++; - if (par[0] == 0) { // tried all 256 possible parities without success. Card doesn't send NACK. isOK = 2; return_status = PM3_ESOFT; break; } - } else { // Why this? par[0] = ((par[0] & 0x1F) + 1) | par_low; @@ -4008,7 +3757,7 @@ void DetectNACKbug(void) { uint8_t uid[10] = { 0x00 }; uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = { 0x00 }; uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = { 0x00 }; - uint8_t par[2] = {0x00 }; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough + uint8_t par[1] = {0x00 }; // maximum 8 Bytes to be sent here, 1 byte parity is therefore enough uint32_t nt = 0, previous_nt = 0, nt_attacked = 0, cuid = 0; int32_t catch_up_cycles = 0, last_catch_up = 0; @@ -4059,9 +3808,9 @@ void DetectNACKbug(void) { ++checkbtn_cnt; // this part is from Piwi's faster nonce collecting part in Hardnested. - if (have_uid == false) { // need a full select cycle to get the uid first + if (!have_uid) { // need a full select cycle to get the uid first iso14a_card_select_t card_info; - if (iso14443a_select_card(uid, &card_info, &cuid, true, 0, true) == 0) { + if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { if (g_dbglevel >= DBG_INFO) Dbprintf("Mifare: Can't select card (ALL)"); i = 0; continue; @@ -4083,7 +3832,7 @@ void DetectNACKbug(void) { } have_uid = true; } else { // no need for anticollision. We can directly select the card - if (iso14443a_fast_select_card(uid, cascade_levels) == 0) { + if (!iso14443a_fast_select_card(uid, cascade_levels)) { if (g_dbglevel >= DBG_INFO) Dbprintf("Mifare: Can't select card (UID)"); i = 0; have_uid = false; @@ -4236,7 +3985,9 @@ void DetectNACKbug(void) { // i = number of authentications sent. Not always 256, since we are trying to sync but close to it. FpgaDisableTracing(); - uint8_t data[4] = {isOK, num_nacks, 0, 0}; + uint8_t *data = BigBuf_malloc(4); + data[0] = isOK; + data[1] = num_nacks; num_to_bytes(i, 2, data + 2); reply_ng(CMD_HF_MIFARE_NACK_DETECT, status, data, 4); @@ -4257,6 +4008,8 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid, uint8_t *getdata_response, size_t getdata_response_len) { tag_response_info_t *responses; uint32_t cuid = 0; + uint32_t counters[3] = { 0x00, 0x00, 0x00 }; + uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd }; uint8_t pages = 0; // command buffers @@ -4297,7 +4050,7 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid, .modulation_n = 0 }; - if (SimulateIso14443aInit(tagType, flags, uid, ats, ats_len, &responses, &cuid, &pages, NULL) == false) { + if (SimulateIso14443aInit(tagType, flags, uid, ats, ats_len, &responses, &cuid, counters, tearings, &pages) == false) { BigBuf_free_keep_EM(); reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0); return; @@ -4372,9 +4125,8 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid, uint8_t offset = 0; switch (receivedCmd[0]) { case 0x0B: // IBlock with CID - case 0x0A: { + case 0x0A: offset = 1; - } case 0x02: // IBlock without CID case 0x03: { dynamic_response_info.response[0] = receivedCmd[0]; diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 5eb2e81ff..d3463b138 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -125,8 +125,8 @@ typedef enum { #endif void printHf14aConfig(void); -void setHf14aConfig(const hf14a_config_t *hc); -hf14a_config_t *getHf14aConfig(void); +void setHf14aConfig(const hf14a_config *hc); +hf14a_config *getHf14aConfig(void); void iso14a_set_timeout(uint32_t timeout); uint32_t iso14a_get_timeout(void); @@ -143,7 +143,7 @@ RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_t void RAMFUNC SniffIso14443a(uint8_t param); void SimulateIso14443aTag(uint8_t tagType, uint16_t flags, uint8_t *useruid, uint8_t exitAfterNReads, - uint8_t *ats, size_t ats_len, bool ulc_part1, bool ulc_part2); + uint8_t *ats, size_t ats_len); void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid, uint8_t *ats, size_t ats_len, uint8_t *aid, size_t aid_len, @@ -152,25 +152,21 @@ void SimulateIso14443aTagAID(uint8_t tagType, uint16_t flags, uint8_t *uid, bool SimulateIso14443aInit(uint8_t tagType, uint16_t flags, uint8_t *data, uint8_t *ats, size_t ats_len, tag_response_info_t **responses, - uint32_t *cuid, uint8_t *pages, - uint8_t *ulc_key); + uint32_t *cuid, uint32_t counters[3], uint8_t tearings[3], uint8_t *pages); bool GetIso14443aCommandFromReader(uint8_t *received, uint16_t received_maxlen, uint8_t *par, int *len); void iso14443a_antifuzz(uint32_t flags); void ReaderIso14443a(PacketCommandNG *c); -void ReaderTransmit(const uint8_t *frame, uint16_t len, uint32_t *timing); -void ReaderTransmitBitsPar(const uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing); -void ReaderTransmitPar(const uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing); +void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing); +void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing); +void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing); uint16_t ReaderReceive(uint8_t *receivedAnswer, uint16_t answer_maxlen, uint8_t *par); void iso14443a_setup(uint8_t fpga_minor_mode); int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint16_t data_len, uint8_t *res); int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats); -int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, - bool anticollision, uint8_t num_cascades, bool no_rats, - const iso14a_polling_parameters_t *polling_parameters, bool force_rats); -int iso14443a_select_card_for_magic(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades); -int iso14443a_fast_select_card(const uint8_t *uid_ptr, uint8_t num_cascades); +int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats, iso14a_polling_parameters_t *polling_parameters); +int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades); void iso14a_set_trigger(bool enable); int EmSendCmd14443aRaw(const uint8_t *resp, uint16_t respLen); @@ -185,9 +181,8 @@ int EmSendPrecompiledCmd(tag_response_info_t *p_response); bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *max_buffer_size); bool prepare_tag_modulation(tag_response_info_t *response_info, size_t max_buffer_size); -bool EmLogTrace(const uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, - uint32_t reader_EndTime, const uint8_t *reader_Parity, const uint8_t *tag_data, - uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, const uint8_t *tag_Parity); +bool EmLogTrace(uint8_t *reader_data, uint16_t reader_len, uint32_t reader_StartTime, uint32_t reader_EndTime, uint8_t *reader_Parity, + uint8_t *tag_data, uint16_t tag_len, uint32_t tag_StartTime, uint32_t tag_EndTime, uint8_t *tag_Parity); void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype); void DetectNACKbug(void); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index ed440c0c0..0ce6c055d 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -1585,7 +1585,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len, bool framing) { /* * Convenience function to encode, transmit and trace iso 14443b comms */ -void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t *start_time, uint32_t *eof_time, bool framing) { +static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t *start_time, uint32_t *eof_time, bool framing) { const tosend_t *ts = get_tosend(); CodeIso14443bAsReader(cmd, len, framing); TransmitFor14443b_AsReader(start_time); @@ -1800,7 +1800,7 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) { /** * SRx Initialise. */ -int iso14443b_select_srx_card(iso14b_card_select_t *card) { +static int iso14443b_select_srx_card(iso14b_card_select_t *card) { // INITIATE command: wake up the tag using the INITIATE static const uint8_t init_srx[] = { ISO14443B_INITIATE, 0x00, 0x97, 0x5b }; uint8_t r_init[3] = { 0x00 }; @@ -2135,9 +2135,6 @@ static int iso14443b_select_picopass_card(picopass_hdr_t *hdr) { static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY }; static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 }; - - // ICLASS_CMD_SELECT 0x81 tells ISO14443b/BPSK coding/106 kbits/s - // ICLASS_CMD_SELECT 0x41 tells ISO14443b/BPSK coding/423 kbits/s uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; uint8_t read_aia[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64}; uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; @@ -2310,7 +2307,7 @@ void iso14443b_setup(void) { // // I tried to be systematic and check every answer of the tag, every CRC, etc... //----------------------------------------------------------------------------- -int read_14b_srx_block(uint8_t blocknr, uint8_t *block) { +static int read_14b_srx_block(uint8_t blocknr, uint8_t *block) { uint8_t cmd[] = {ISO14443B_READ_BLK, blocknr, 0x00, 0x00}; AddCrc14B(cmd, 2); diff --git a/armsrc/iso14443b.h b/armsrc/iso14443b.h index 7dadda7bd..70455ac15 100644 --- a/armsrc/iso14443b.h +++ b/armsrc/iso14443b.h @@ -45,11 +45,8 @@ int iso14443b_select_card(iso14b_card_select_t *card); void SimulateIso14443bTag(const uint8_t *pupi); void read_14b_st_block(uint8_t blocknr); -int read_14b_srx_block(uint8_t blocknr, uint8_t *block); -int iso14443b_select_srx_card(iso14b_card_select_t *card); void SniffIso14443b(void); void SendRawCommand14443B(iso14b_raw_cmd_t *p); -void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t *start_time, uint32_t *eof_time, bool framing); // States for 14B SIM command #define SIM_POWER_OFF 0 diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index a1ff3c721..dd3ffa865 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -985,11 +985,10 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo DecodeTagFSK_t dtfm = { 0 }; DecodeTagFSK_t *dtf = &dtfm; - if (fsk) { + if (fsk) DecodeTagFSKInit(dtf, response, max_len); - } else { + else DecodeTagInit(dt, response, max_len); - } // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)); @@ -1015,9 +1014,8 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo for (;;) { volatile uint16_t behindBy = ((uint16_t *)AT91C_BASE_PDC_SSC->PDC_RPR - upTo) & (DMA_BUFFER_SIZE - 1); - if (behindBy == 0) { + if (behindBy == 0) continue; - } samples++; if (samples == 1) { @@ -2659,7 +2657,7 @@ void BruteforceIso15693Afi(uint32_t flags) { Dbprintf("AFI = %i UID = %s", i, iso15693_sprintUID(NULL, recv + 2)); } - aborted = (BUTTON_PRESS() || data_available()); + aborted = (BUTTON_PRESS() && data_available()); if (aborted) { break; } diff --git a/armsrc/lfadc.c b/armsrc/lfadc.c index 18712a7bb..38d6558d8 100644 --- a/armsrc/lfadc.c +++ b/armsrc/lfadc.c @@ -236,13 +236,8 @@ void lf_init(bool reader, bool simulate, bool ledcontrol) { FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER); // When in reader mode, give the field a bit of time to settle. - // Optimal timing window for LF ADC measurements to be performed: - // minimum: 313T0 = 313 * 8us = 2504us = 2.50ms - Hitag2 tag internal powerup time - // 280T0 = 280 * 8us = 2240us = 2.24ms - HitagS minimum time before the first command (powerup time) - // maximum: 545T0 = 545 * 8us = 4360us = 4.36ms - Hitag2 command waiting time before it starts transmitting in public mode (if configured so) - // 565T0 = 565 * 8us = 4520us = 4.52ms - HitagS waiting time before entering TTF mode (if configured so) - // Thus (2.50 ms + 4.36 ms) / 2 ~= 3 ms (rounded down to integer), should be a good timing for both tag models - SpinDelay(3); + // 313T0 = 313 * 8us = 2504us = 2.5ms Hitag2 tags needs to be fully powered. + SpinDelay(10); // Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index a9c0f68f1..ac93d149b 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -83,14 +83,14 @@ static bool mifare_wakeup_auth(struct Crypto1State *pcs, MifareWakeupType wakeup break; } case MF_WAKE_WUPA: { - if (iso14443a_select_cardEx(NULL, NULL, &cuid, true, 0, true, &WUPA_POLLING_PARAMETERS, false) == 0) { + if (iso14443a_select_cardEx(NULL, NULL, &cuid, true, 0, true, &WUPA_POLLING_PARAMETERS) == 0) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card"); return false; }; break; } case MF_WAKE_REQA: { - if (iso14443a_select_cardEx(NULL, NULL, &cuid, true, 0, true, &REQA_POLLING_PARAMETERS, false) == 0) { + if (iso14443a_select_cardEx(NULL, NULL, &cuid, true, 0, true, &REQA_POLLING_PARAMETERS) == 0) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Can't select card"); return false; }; @@ -274,7 +274,7 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes) { return; }; - if (mifare_ultra_auth(keybytes) == 0) { + if (!mifare_ultra_auth(keybytes)) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Authentication failed"); OnError(1); return; @@ -304,7 +304,7 @@ void MifareUL_AES_Auth(bool turn_off_field, uint8_t keyno, uint8_t *keybytes) { return; }; - if (mifare_ultra_aes_auth(keyno, keybytes) == 0) { + if (!mifare_ultra_aes_auth(keyno, keybytes)) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Authentication failed"); OnErrorNG(CMD_HF_MIFAREULAES_AUTH, PM3_ESOFT); return; @@ -344,7 +344,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { uint8_t key[16] = {0x00}; memcpy(key, datain, sizeof(key)); - if (mifare_ultra_auth(key) == 0) { + if (!mifare_ultra_auth(key)) { OnError(1); return; } @@ -1947,7 +1947,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da // Now append the SPI flash dictionnary if (SPIFFS_OK == rdv40_spiffs_read_as_filetype(MF_KEYS_FILE, dictkeys + (keyCount * MF_KEY_LENGTH), (key_mem_available - keyCount) * MF_KEY_LENGTH, RDV40_SPIFFS_SAFETY_SAFE)) { if (g_dbglevel >= DBG_ERROR) { - Dbprintf("loaded " _GREEN_("%u") " keys from spiffs file `" _YELLOW_("%s") "`", key_mem_available - keyCount, MF_KEYS_FILE); + Dbprintf("loaded " _GREEN_("%u") " keys from spiffs file `" _YELLOW_("%s") "`", key_mem_available, MF_KEYS_FILE); } } else { Dbprintf("Spiffs file `" _RED_("%s") "` cannot be read", MF_KEYS_FILE); @@ -1955,7 +1955,6 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da } // Replace client provided keys datain = dictkeys; - keyCount = key_mem_available; } #endif @@ -2909,7 +2908,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { } // read block - if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar, NULL) != MIFARE_BLOCK_SIZE + CRC16_SIZE)) { + if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, sizeof(receivedAnswer), receivedAnswerPar, NULL) != MAX_MIFARE_FRAME_SIZE)) { if (g_dbglevel >= DBG_ERROR) Dbprintf("read block send command error"); errormsg = 0; break; @@ -3022,10 +3021,9 @@ void MifareCIdent(bool is_mfc, uint8_t keytype, uint8_t *key) { // reset card mf_reset_card(); - // Use special magic detection function that always attempts RATS regardless of SAK - res = iso14443a_select_card_for_magic(uid, card, &cuid, true, 0); + + res = iso14443a_select_card(uid, card, &cuid, true, 0, false); if (res) { - mf_reset_card(); if (cuid == 0xAA55C396) { flag |= MAGIC_FLAG_GEN_UNFUSED; } @@ -3221,7 +3219,7 @@ void MifareHasStaticNonce(void) { } if (counter) { - Dbprintf("Static nonce....... " _YELLOW_("%08x"), nt); + Dbprintf("Static nonce......... " _YELLOW_("%08x"), nt); data[0] = NONCE_STATIC; } else { data[0] = NONCE_NORMAL; @@ -3516,7 +3514,7 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block) { int retval = PM3_SUCCESS; uint8_t block_cmd[5] = { 0x90, 0xf0, 0xcc, 0xcc, 0x10 }; - uint8_t cmdlen = sizeof(block_cmd) + MIFARE_BLOCK_SIZE + CRC16_SIZE; + uint8_t cmdlen = sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE; uint8_t *cmd = BigBuf_calloc(cmdlen); iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_calloc(sizeof(iso14a_card_select_t)); @@ -3533,7 +3531,7 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block) { bool doReselect = false; if (block_len < MIFARE_BLOCK_SIZE) { - if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, 0, &cmd[sizeof(block_cmd)], MIFARE_BLOCK_SIZE + CRC16_SIZE, NULL, NULL) != MIFARE_BLOCK_SIZE + CRC16_SIZE)) { + if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, 0, &cmd[sizeof(block_cmd)], MAX_MIFARE_FRAME_SIZE, NULL, NULL) != MAX_MIFARE_FRAME_SIZE)) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Read manufacturer block failed"); retval = PM3_ESOFT; goto OUT; @@ -3562,13 +3560,13 @@ void MifareGen3Blk(uint8_t block_len, uint8_t *block) { AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE); if (doReselect) { - if (iso14443a_select_card(NULL, NULL, NULL, true, 0, true) == 0) { + if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { retval = PM3_ESOFT; goto OUT; } } - retval = DoGen3Cmd(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE + CRC16_SIZE); + retval = DoGen3Cmd(cmd, sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE); } OUT: diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index cc2996b23..448f475dd 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -60,7 +60,7 @@ bool InitDesfireCard(void) { iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); set_tracing(true); - if (iso14443a_select_card(NULL, &card, NULL, true, 0, false) == 0) { + if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) { if (g_dbglevel >= DBG_ERROR) DbpString("Can't select card"); OnError(1); return false; @@ -157,7 +157,7 @@ void MifareDesfireGetInformation(void) { pcb_blocknum = 0; // card select - information - if (iso14443a_select_card(NULL, &card, NULL, true, 0, false) == 0) { + if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) { if (g_dbglevel >= DBG_ERROR) { DbpString("Can't select card"); } diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index a276ce28c..c58025473 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -579,6 +579,21 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t counter++; } + /* + // find reader field + if (cardSTATE == MFEMUL_NOFIELD) { + + vHf = (MAX_ADC_HF_VOLTAGE * SumAdc(ADC_CHAN_HF, 32)) >> 15; + + if (vHf > MF_MINFIELDV) { + cardSTATE_TO_IDLE(); + LED_A_ON(); + } + button_pushed = BUTTON_PRESS(); + continue; + } + */ + FpgaEnableTracing(); //Now, get data int res = EmGetCmd(receivedCmd, sizeof(receivedCmd), &receivedCmd_len, receivedCmd_par); @@ -745,6 +760,10 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t // WORK case MFEMUL_WORK: { + if (g_dbglevel >= DBG_EXTENDED) { + // Dbprintf("[MFEMUL_WORK] Enter in case"); + } + if (receivedCmd_len == 0) { if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] NO CMD received"); break; @@ -790,11 +809,10 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] KEY %c: %012" PRIx64, (cardAUTHKEY == 0) ? 'A' : 'B', emlGetKey(cardAUTHSC, cardAUTHKEY)); // sector out of range - do not respond - if ((cardAUTHSC >= cardMaxSEC) && (flags & FLAG_MF_ALLOW_OOB_AUTH) == 0) { + if (cardAUTHSC >= cardMaxSEC) { cardAUTHKEY = AUTHKEYNONE; // not authenticated cardSTATE_TO_IDLE(); - if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Out of range sector %d(0x%02x) >= %d(0x%02x)", cardAUTHSC, cardAUTHSC, cardMaxSEC, cardMaxSEC); - LogTrace(uart->output, uart->len, uart->startTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->endTime * 16 - DELAY_AIR2ARM_AS_TAG, uart->parity, true); + if (g_dbglevel >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Out of range sector %d(0x%02x)", cardAUTHSC, cardAUTHSC); break; } @@ -1021,8 +1039,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t } } AddCrc14A(response, MIFARE_BLOCK_SIZE); - mf_crypto1_encrypt(pcs, response, MIFARE_BLOCK_SIZE + CRC16_SIZE, response_par); - EmSendCmdPar(response, MIFARE_BLOCK_SIZE + CRC16_SIZE, response_par); + mf_crypto1_encrypt(pcs, response, MAX_MIFARE_FRAME_SIZE, response_par); + EmSendCmdPar(response, MAX_MIFARE_FRAME_SIZE, response_par); FpgaDisableTracing(); if (g_dbglevel >= DBG_EXTENDED) { @@ -1034,7 +1052,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t numReads++; if (exitAfterNReads > 0 && numReads == exitAfterNReads) { - Dbprintf("[MFEMUL_WORK] " _YELLOW_("%u") " reads done, exiting", numReads); + Dbprintf("[MFEMUL_WORK] %d reads done, exiting", numReads); finished = true; } break; @@ -1291,7 +1309,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *uid, uint16_t // WRITE BL2 case MFEMUL_WRITEBL2: { - if (receivedCmd_len == MIFARE_BLOCK_SIZE + CRC16_SIZE) { + if (receivedCmd_len == MAX_MIFARE_FRAME_SIZE) { mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec); diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 8c62a7a6a..8247fae69 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -100,7 +100,7 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t uint16_t pos; uint8_t dcmd[4] = {cmd, data, 0x00, 0x00}; uint8_t ecmd[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t par[MAX_MIFARE_PARITY_SIZE] = {0x00}; // used for cmd and answer + uint8_t par[1] = {0x00}; // 1 Byte parity is enough here AddCrc14A(dcmd, 2); memcpy(ecmd, dcmd, sizeof(dcmd)); @@ -440,17 +440,21 @@ int mifare_ultra_aes_auth(uint8_t keyno, uint8_t *keybytes) { uint8_t key[16] = { 0 }; memcpy(key, keybytes, sizeof(key)); + uint16_t len = 0; + // 1 cmd + 16 bytes + 2 crc uint8_t resp[19] = {0x00}; uint8_t respPar[5] = {0}; + // setup AES mbedtls_aes_context actx; mbedtls_aes_init(&actx); + mbedtls_aes_init(&actx); mbedtls_aes_setkey_dec(&actx, key, 128); // Send REQUEST AUTHENTICATION / receive tag nonce - uint16_t len = mifare_sendcmd_short(NULL, CRYPT_NONE, MIFARE_ULAES_AUTH_1, keyno, resp, sizeof(resp), respPar, NULL); + len = mifare_sendcmd_short(NULL, CRYPT_NONE, MIFARE_ULAES_AUTH_1, keyno, resp, sizeof(resp), respPar, NULL); if (len != 19) { if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x - expected 19 got " _RED_("%u"), resp[0], len); return 0; diff --git a/armsrc/sam_common.c b/armsrc/sam_common.c index bfa959bba..ed129134d 100644 --- a/armsrc/sam_common.c +++ b/armsrc/sam_common.c @@ -218,19 +218,17 @@ out: * * @return Status code indicating success or failure of the operation. */ -int sam_get_version(bool info) { +int sam_get_version(void) { int res = PM3_SUCCESS; - if (g_dbglevel >= DBG_DEBUG) { + if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_get_version"); - } - uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME); + uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; uint8_t payload[] = { - 0xa0, // <- SAM command - 0x02, // <- Length + 0xa0, 0x02, // <- SAM command 0x82, 0x00 // <- get version }; uint16_t payload_len = sizeof(payload); @@ -254,9 +252,8 @@ int sam_get_version(bool info) { // 82 01 // 01 // 90 00 - if (g_dbglevel >= DBG_DEBUG) { + if (g_dbglevel >= DBG_DEBUG) DbpString("end sam_get_version"); - } if (response[5] != 0xbd) { Dbprintf("Invalid SAM response"); @@ -269,18 +266,18 @@ int sam_get_version(bool info) { } uint8_t *sam_version_an = sam_find_asn1_node(sam_response_an, 0x80); if (sam_version_an == NULL) { - if (g_dbglevel >= DBG_ERROR) DbpString(_RED_("SAM: get version failed")); + if (g_dbglevel >= DBG_ERROR) DbpString("SAM get version failed"); goto error; } uint8_t *sam_build_an = sam_find_asn1_node(sam_response_an, 0x81); if (sam_build_an == NULL) { - if (g_dbglevel >= DBG_ERROR) DbpString(_RED_("SAM: get firmware ID failed")); + if (g_dbglevel >= DBG_ERROR) DbpString("SAM get firmware ID failed"); goto error; } - if (g_dbglevel >= DBG_INFO || info) { - DbpString(_BLUE_("-- SAM Information --")); - Dbprintf(_YELLOW_("Firmware version: ")"%d.%d", sam_version_an[2], sam_version_an[3]); - Dbprintf(_YELLOW_("Firmware ID: ")); + if (g_dbglevel >= DBG_INFO) { + DbpString("SAM get version successful"); + Dbprintf("Firmware version: %X.%X", sam_version_an[2], sam_version_an[3]); + Dbprintf("Firmware ID: "); Dbhexdump(sam_build_an[1], sam_build_an + 2, false); } goto out; @@ -292,79 +289,8 @@ error: out: BigBuf_free(); - if (g_dbglevel >= DBG_DEBUG) { + if (g_dbglevel >= DBG_DEBUG) DbpString("end sam_get_version"); - } - - return res; -} - -int sam_get_serial_number(void) { - int res = PM3_SUCCESS; - - if (g_dbglevel >= DBG_DEBUG) { - DbpString("start sam_get_serial_number"); - } - - uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME); - uint16_t response_len = ISO7816_MAX_FRAME; - - uint8_t payload[] = { - 0xa0, // <- SAM command - 0x02, // <- Length - 0x96, 0x00 // <- get serial number - }; - uint16_t payload_len = sizeof(payload); - - sam_send_payload( - 0x44, 0x0a, 0x44, - payload, - &payload_len, - response, - &response_len - ); - - //resp: - //c1 64 00 00 00 - // bd 0e <- SAM response - // 8a 0c <- get serial number response - // 61 01 13 51 22 66 6e 15 3e 1b ff ff - //90 00 - - if (g_dbglevel >= DBG_DEBUG) { - DbpString("end sam_get_serial_number"); - } - - if (response[5] != 0xbd) { - Dbprintf("Invalid SAM response"); - goto error; - } else { - uint8_t *sam_response_an = sam_find_asn1_node(response + 5, 0x8a); - if (sam_response_an == NULL) { - if (g_dbglevel >= DBG_ERROR) DbpString(_RED_("SAM: get response failed")); - goto error; - } - uint8_t *sam_serial_an = sam_response_an + 2; - if (sam_serial_an == NULL) { - if (g_dbglevel >= DBG_ERROR) DbpString(_RED_("SAM get serial number failed")); - goto error; - } - - Dbprintf(_YELLOW_("Serial Number: ")); - Dbhexdump(sam_response_an[1], sam_serial_an, false); - - goto out; - } - -error: - res = PM3_ESOFT; - -out: - BigBuf_free(); - - if (g_dbglevel >= DBG_DEBUG) { - DbpString("end sam_get_serial_number"); - } return res; } @@ -424,10 +350,12 @@ void sam_append_asn1_node(const uint8_t *root, const uint8_t *node, uint8_t type } void sam_send_ack(void) { - uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME); + uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; - uint8_t payload[] = { 0xa0, 0 }; + uint8_t payload[] = { + 0xa0, 0 + }; uint16_t payload_len = sizeof(payload); sam_send_payload( diff --git a/armsrc/sam_common.h b/armsrc/sam_common.h index 4cc6e364f..1c3a88e88 100644 --- a/armsrc/sam_common.h +++ b/armsrc/sam_common.h @@ -39,8 +39,7 @@ int sam_send_payload( uint16_t *response_len ); -int sam_get_version(bool info); -int sam_get_serial_number(void); +int sam_get_version(void); uint8_t *sam_find_asn1_node(const uint8_t *root, const uint8_t type); void sam_append_asn1_node(const uint8_t *root, const uint8_t *node, uint8_t type, const uint8_t *const data, uint8_t len); diff --git a/armsrc/sam_picopass.c b/armsrc/sam_picopass.c index 84ddf549b..0bf2379d8 100644 --- a/armsrc/sam_picopass.c +++ b/armsrc/sam_picopass.c @@ -46,12 +46,11 @@ */ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t request_len, uint8_t *response, uint8_t *response_len, const bool shallow_mod, const bool break_on_nr_mac, const bool prevent_epurse_update) { int res = PM3_SUCCESS; - if (g_dbglevel >= DBG_DEBUG) { + if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_send_request_iso14a"); - } - uint8_t *buf1 = BigBuf_calloc(ISO7816_MAX_FRAME); - uint8_t *buf2 = BigBuf_calloc(ISO7816_MAX_FRAME); + uint8_t *buf1 = BigBuf_malloc(ISO7816_MAX_FRAME); + uint8_t *buf2 = BigBuf_malloc(ISO7816_MAX_FRAME); if (buf1 == NULL || buf2 == NULL) { res = PM3_EMALLOC; goto out; @@ -103,13 +102,10 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re nfc_tx_len = sam_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf); - bool is_cmd_check = ((nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_CHECK); - + bool is_cmd_check = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_CHECK; if (is_cmd_check && break_on_nr_mac) { - memcpy(response, nfc_tx_buf, nfc_tx_len); *response_len = nfc_tx_len; - if (g_dbglevel >= DBG_INFO) { DbpString("NR-MAC: "); Dbhexdump((*response_len) - 1, response + 1, false); @@ -118,8 +114,7 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re goto out; } - bool is_cmd_update = ((nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_UPDATE); - + bool is_cmd_update = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_UPDATE; if (is_cmd_update && prevent_epurse_update && nfc_tx_buf[0] == 0x87 && nfc_tx_buf[1] == 0x02) { // block update(2) command and fake the response to prevent update of epurse @@ -227,27 +222,18 @@ static int sam_send_request_iso15(const uint8_t *const request, const uint8_t re // 07 // 90 00 if (request_len == 0) { - - if (!(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0x8a && sam_rx_buf[5 + 4] == 0x03) && - !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0xb3 && sam_rx_buf[5 + 4] == 0xa0)) { - - if (g_dbglevel >= DBG_ERROR) { + if ( + !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0x8a && sam_rx_buf[5 + 4] == 0x03) + && + !(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0xb3 && sam_rx_buf[5 + 4] == 0xa0) + ) { + if (g_dbglevel >= DBG_ERROR) Dbprintf("No PACS data in SAM response"); - } res = PM3_ESOFT; } } - if (sam_rx_buf[6] == 0x81 && sam_rx_buf[8] == 0x8a && sam_rx_buf[9] == 0x81) { //check if the response is an SNMP message - *response_len = sam_rx_buf[5 + 2] + 3; - } else { //if not, use the old logic - *response_len = sam_rx_buf[5 + 1] + 2; - } - - if (sam_rx_buf[5] == 0xBD && sam_rx_buf[4] != 0x00) { //secure channel flag is not 0x00 - Dbprintf(_YELLOW_("Secure channel flag set to: ")"%02x", sam_rx_buf[4]); - } - + *response_len = sam_rx_buf[5 + 1] + 2; memcpy(response, sam_rx_buf + 5, *response_len); goto out; @@ -269,10 +255,10 @@ out: */ static int sam_set_card_detected_picopass(const picopass_hdr_t *card_select) { int res = PM3_SUCCESS; - if (g_dbglevel >= DBG_DEBUG) { + if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_set_card_detected"); - } - uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME); + + uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; // a0 12 @@ -328,9 +314,8 @@ error: out: BigBuf_free(); - if (g_dbglevel >= DBG_DEBUG) { + if (g_dbglevel >= DBG_DEBUG) DbpString("end sam_set_card_detected"); - } return res; } @@ -351,14 +336,11 @@ int sam_picopass_get_pacs(PacketCommandNG *c) { const bool breakOnNrMac = !!(flags & BITMASK(2)); const bool preventEpurseUpdate = !!(flags & BITMASK(3)); const bool shallow_mod = !!(flags & BITMASK(4)); - const bool info = !!(flags & BITMASK(5)); uint8_t *cmd = c->data.asBytes + 1; uint16_t cmd_len = c->length - 1; int res = PM3_EFAILED; - uint8_t sam_response[ISO7816_MAX_FRAME] = { 0x00 }; - uint8_t sam_response_len = 0; clear_trace(); I2C_Reset_EnterMainProgram(); @@ -367,21 +349,16 @@ int sam_picopass_get_pacs(PacketCommandNG *c) { StartTicks(); // step 1: ping SAM - sam_get_version(info); + sam_get_version(); - if (info) { - sam_get_serial_number(); - goto out; - } - - if (skipDetect == false) { + if (!skipDetect) { // step 2: get card information picopass_hdr_t card_a_info; uint32_t eof_time = 0; // implicit StartSspClk() happens here Iso15693InitReader(); - if (select_iclass_tag(&card_a_info, false, &eof_time, shallow_mod) == false) { + if (!select_iclass_tag(&card_a_info, false, &eof_time, shallow_mod)) { goto err; } @@ -392,14 +369,14 @@ int sam_picopass_get_pacs(PacketCommandNG *c) { } // step 3: SamCommand RequestPACS, relay NFC communication + uint8_t sam_response[ISO7816_MAX_FRAME] = { 0x00 }; + uint8_t sam_response_len = 0; res = sam_send_request_iso15(cmd, cmd_len, sam_response, &sam_response_len, shallow_mod, breakOnNrMac, preventEpurseUpdate); if (res != PM3_SUCCESS) { goto err; } - - if (g_dbglevel >= DBG_INFO) { + if (g_dbglevel >= DBG_INFO) print_result("Response data", sam_response, sam_response_len); - } goto out; diff --git a/armsrc/sam_seos.c b/armsrc/sam_seos.c index 3f8c806e9..40846705a 100644 --- a/armsrc/sam_seos.c +++ b/armsrc/sam_seos.c @@ -51,14 +51,13 @@ */ static int sam_set_card_detected_seos(iso14a_card_select_t *card_select) { int res = PM3_SUCCESS; - if (g_dbglevel >= DBG_DEBUG) { + if (g_dbglevel >= DBG_DEBUG) DbpString("start sam_set_card_detected"); - } - uint8_t *request = BigBuf_calloc(ISO7816_MAX_FRAME); + uint8_t *request = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t request_len = ISO7816_MAX_FRAME; - uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME); + uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME); uint16_t response_len = ISO7816_MAX_FRAME; const uint8_t payload[] = { @@ -108,9 +107,8 @@ error: out: BigBuf_free(); - if (g_dbglevel >= DBG_DEBUG) { + if (g_dbglevel >= DBG_DEBUG) DbpString("end sam_set_card_detected"); - } return res; } @@ -282,7 +280,7 @@ int sam_seos_get_pacs(PacketCommandNG *c) { StartTicks(); // step 1: ping SAM - sam_get_version(false); + sam_get_version(); if (skipDetect == false) { // step 2: get card information diff --git a/armsrc/spiffs.c b/armsrc/spiffs.c index 0b2799c5a..71d0cbd12 100644 --- a/armsrc/spiffs.c +++ b/armsrc/spiffs.c @@ -312,7 +312,7 @@ static int is_valid_filename(const char *filename) { */ static void copy_in_spiffs(const char *src, const char *dst) { uint32_t size = size_in_spiffs(src); - uint8_t *mem = BigBuf_calloc(size); + uint8_t *mem = BigBuf_malloc(size); read_from_spiffs(src, (uint8_t *)mem, size); write_to_spiffs(dst, (uint8_t *)mem, size); } diff --git a/armsrc/usart.c b/armsrc/usart.c index 907f47239..1dcaf7517 100644 --- a/armsrc/usart.c +++ b/armsrc/usart.c @@ -218,7 +218,7 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) { } // transfer from device to client -int usart_writebuffer_sync(const uint8_t *data, size_t len) { +int usart_writebuffer_sync(uint8_t *data, size_t len) { // Wait for current PDC bank to be free // (and check next bank too, in case there will be a usart_writebuffer_async) diff --git a/armsrc/usart.h b/armsrc/usart.h index e93f318f8..e33745e00 100644 --- a/armsrc/usart.h +++ b/armsrc/usart.h @@ -25,7 +25,7 @@ extern uint32_t g_usart_baudrate; extern uint8_t g_usart_parity; void usart_init(uint32_t baudrate, uint8_t parity); -int usart_writebuffer_sync(const uint8_t *data, size_t len); +int usart_writebuffer_sync(uint8_t *data, size_t len); uint32_t usart_read_ng(uint8_t *data, size_t len); uint16_t usart_rxdata_available(void); diff --git a/bootrom/Makefile b/bootrom/Makefile index b6825530d..86c785cd1 100644 --- a/bootrom/Makefile +++ b/bootrom/Makefile @@ -56,7 +56,7 @@ OBJS = $(OBJDIR)/bootrom.s19 # version_pm3.c should be checked on every compilation version_pm3.c: default_version_pm3.c .FORCE $(info [=] CHECK $@) - $(Q)$(SH) ../tools/mkversion.sh $@ || $(CP) $< $@ + $(Q)$(CP) $< $@ all: showinfo $(OBJS) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 1f0410e31..615c581cf 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -402,7 +402,6 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdlfvisa2000.c ${PM3_ROOT}/client/src/cmdlfzx8211.c ${PM3_ROOT}/client/src/cmdmain.c - ${PM3_ROOT}/client/src/cmdmqtt.c ${PM3_ROOT}/client/src/cmdnfc.c ${PM3_ROOT}/client/src/cmdparser.c ${PM3_ROOT}/client/src/cmdpiv.c @@ -435,7 +434,7 @@ set (TARGET_SOURCES add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/version_pm3.c - COMMAND sh ${PM3_ROOT}/tools/mkversion.sh ${CMAKE_BINARY_DIR}/version_pm3.c || ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c + COMMAND ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c DEPENDS ${PM3_ROOT}/common/default_version_pm3.c ) @@ -693,7 +692,7 @@ add_executable(proxmark3 ${ADDITIONAL_SRC} ) -target_compile_options(proxmark3 PUBLIC -Wall -Werror -O3) +target_compile_options(proxmark3 PUBLIC -Wall -O3) if (EMBED_READLINE) if (NOT SKIPREADLINE EQUAL 1) add_dependencies(proxmark3 ncurses readline) @@ -773,7 +772,6 @@ target_link_libraries(proxmark3 PRIVATE pm3rrg_rdv4_reveng pm3rrg_rdv4_hardnested pm3rrg_rdv4_id48 - pm3rrg_rdv4_mqtt ${ADDITIONAL_LNK}) if (NOT SKIPPTHREAD EQUAL 1) diff --git a/client/Makefile b/client/Makefile index 777343d07..f3c9f0b67 100644 --- a/client/Makefile +++ b/client/Makefile @@ -17,8 +17,6 @@ ifeq ($(PLTNAME),) -include ../Makefile.platform -include ../.Makefile.options.cache -# Default platform if no platform specified - PLATFORM?=PM3RDV4 ifneq ($(PLATFORM), $(CACHED_PLATFORM)) $(error platform definitions have been changed, please "make clean" at the root of the project) endif @@ -133,12 +131,6 @@ WHEREAMILIBINC = -I$(WHEREAMILIBPATH) WHEREAMILIB = $(WHEREAMILIBPATH)/libwhereami.a WHEREAMILIBLD = -## MQTT -MQTTLIBPATH = ./deps/mqtt -MQTTLIBINC = -I$(MQTTLIBPATH) -MQTTLIB = $(MQTTLIBPATH)/mqtt.a -MQTTLIBLD = - ########################## # common local libraries # ########################## @@ -247,12 +239,6 @@ STATICLIBS += $(WHEREAMILIB) LDLIBS += $(WHEREAMILIBLD) PM3INCLUDES += $(WHEREAMILIBINC) -## MQTT -# not distributed as system library -STATICLIBS += $(MQTTLIB) -LDLIBS += $(MQTTLIBLD) -PM3INCLUDES += $(MQTTLIBINC) - #################### # system libraries # #################### @@ -454,14 +440,13 @@ endif ifeq ($(SWIG_LUA_FOUND),1) PM3CFLAGS += -DHAVE_LUA_SWIG endif - ifeq ($(SWIG_PYTHON_FOUND),1) PM3CFLAGS += -DHAVE_PYTHON_SWIG endif PM3CFLAGS += -DHAVE_SNPRINTF -CXXFLAGS ?= -Wall -Werror +CXXFLAGS ?= -Wall CXXFLAGS += $(MYDEFS) $(MYCXXFLAGS) $(MYINCLUDES) PM3CXXFLAGS = $(CXXFLAGS) @@ -597,7 +582,6 @@ endif ifeq ($(SWIG_LUA_FOUND),1) $(info Lua SWIG: wrapper found) endif - ifeq ($(SWIG_PYTHON_FOUND),1) $(info Python SWIG: wrapper found) endif @@ -698,7 +682,6 @@ SRCS = mifare/aiddesfire.c \ cmdlfvisa2000.c \ cmdlfzx8211.c \ cmdmain.c \ - cmdmqtt.c \ cmdnfc.c \ cmdparser.c \ cmdpiv.c \ @@ -894,7 +877,6 @@ endif $(Q)$(MAKE) --no-print-directory -C $(REVENGLIBPATH) clean $(Q)$(MAKE) --no-print-directory -C $(TINYCBORLIBPATH) clean $(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) clean - $(Q)$(MAKE) --no-print-directory -C $(MQTTLIBPATH) clean @# Just in case someone compiled within these dirs: $(Q)$(MAKE) --no-print-directory -C $(MBEDTLSLIBPATH) clean @@ -907,19 +889,11 @@ endif ifneq (,$(INSTALLSHARE)) $(Q)$(INSTALLSUDO) $(MKDIR) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH) # hack ahead: inject installation path into pm3_resources.py - ifeq ($(platform),Darwin) - $(Q)sed -E -i '' 's|^TOOLS_PATH \?= \?None|TOOLS_PATH="$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)"|' pyscripts/pm3_resources.py - $(Q)sed -E -i '' 's|^DICTS_PATH \?= \?None|DICTS_PATH="$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)/dictionaries"|' pyscripts/pm3_resources.py - $(Q)$(INSTALLSUDO) $(CP) $(INSTALLSHARE) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH) - $(Q)sed -E -i '' 's|^TOOLS_PATH \?=.*|TOOLS_PATH = None|' pyscripts/pm3_resources.py - $(Q)sed -E -i '' 's|^DICTS_PATH \?=.*|DICTS_PATH = None|' pyscripts/pm3_resources.py - else - $(Q)sed -i 's|^TOOLS_PATH \?= \?None|TOOLS_PATH="$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)"|' pyscripts/pm3_resources.py - $(Q)sed -i 's|^DICTS_PATH \?= \?None|DICTS_PATH="$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)/dictionaries"|' pyscripts/pm3_resources.py + $(Q)sed -i 's|^TOOLS_PATH \?= \?None|TOOLS_PATH="$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLTOOLSRELPATH)"|' pyscripts/pm3_resources.py + $(Q)sed -i 's|^DICTS_PATH \?= \?None|DICTS_PATH="$(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)/dictionaries"|' pyscripts/pm3_resources.py $(Q)$(INSTALLSUDO) $(CP) $(INSTALLSHARE) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH) $(Q)sed -i 's|^TOOLS_PATH \?=.*|TOOLS_PATH = None|' pyscripts/pm3_resources.py $(Q)sed -i 's|^DICTS_PATH \?=.*|DICTS_PATH = None|' pyscripts/pm3_resources.py - endif endif @true @@ -992,10 +966,6 @@ ifneq ($(WHEREAMI_FOUND),1) $(Q)$(MAKE) --no-print-directory -C $(WHEREAMILIBPATH) all endif -$(MQTTLIB): .FORCE - $(info [*] MAKE $@) - $(Q)$(MAKE) --no-print-directory -C $(MQTTLIBPATH) all - ######## # SWIG # ######## @@ -1017,7 +987,7 @@ src/pm3_pywrap.c: pm3.i # version_pm3.c should be checked on every compilation src/version_pm3.c: default_version_pm3.c .FORCE $(info [=] CHECK $@) - $(Q)$(SH) ../tools/mkversion.sh $@ || $(CP) $< $@ + $(Q)$(CP) $< $@ # easy printing of MAKE VARIABLES print-%: ; @echo $* = $($*) diff --git a/client/deps/CMakeLists.txt b/client/deps/CMakeLists.txt index c8f5b78c5..99a843d66 100644 --- a/client/deps/CMakeLists.txt +++ b/client/deps/CMakeLists.txt @@ -31,6 +31,3 @@ endif() if (NOT TARGET pm3rrg_rdv4_whereami) include(whereami.cmake) endif() -if (NOT TARGET pm3rrg_rdv4_mqtt) - include(mqtt.cmake) -endif() \ No newline at end of file diff --git a/client/deps/amiibo.cmake b/client/deps/amiibo.cmake index c946c0682..8c524c170 100644 --- a/client/deps/amiibo.cmake +++ b/client/deps/amiibo.cmake @@ -19,7 +19,7 @@ target_link_libraries(pm3rrg_rdv4_amiibo PRIVATE m pm3rrg_rdv4_mbedtls) -target_compile_options(pm3rrg_rdv4_amiibo PRIVATE -Wall -Werror -O3) +target_compile_options(pm3rrg_rdv4_amiibo PRIVATE -Wall -O3) set_property(TARGET pm3rrg_rdv4_amiibo PROPERTY POSITION_INDEPENDENT_CODE ON) target_include_directories(pm3rrg_rdv4_amiibo PRIVATE amiitool diff --git a/client/deps/cliparser.cmake b/client/deps/cliparser.cmake index fccae33b7..a85cc2374 100644 --- a/client/deps/cliparser.cmake +++ b/client/deps/cliparser.cmake @@ -9,5 +9,5 @@ target_include_directories(pm3rrg_rdv4_cliparser PRIVATE ../../include ../src) target_include_directories(pm3rrg_rdv4_cliparser INTERFACE cliparser) -target_compile_options(pm3rrg_rdv4_cliparser PRIVATE -Wall -Werror -O3) +target_compile_options(pm3rrg_rdv4_cliparser PRIVATE -Wall -O3) set_property(TARGET pm3rrg_rdv4_cliparser PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/client/deps/cliparser/argtable3.c b/client/deps/cliparser/argtable3.c index 080d0ad9a..0680e8dc9 100644 --- a/client/deps/cliparser/argtable3.c +++ b/client/deps/cliparser/argtable3.c @@ -3621,12 +3621,12 @@ TRex *trex_compile(const TRexChar *pattern, const TRexChar **error, int flags) { exp->_first = trex_newnode(exp, OP_EXPR); exp->_error = error; exp->_jmpbuf = malloc(sizeof(jmp_buf)); - + if (exp->_jmpbuf == NULL) { trex_free(exp); return NULL; } - + exp->_flags = flags; if (setjmp(*((jmp_buf *)exp->_jmpbuf)) == 0) { int res = trex_list(exp); diff --git a/client/deps/hardnested.cmake b/client/deps/hardnested.cmake index ec545e2a8..468ee4ef2 100644 --- a/client/deps/hardnested.cmake +++ b/client/deps/hardnested.cmake @@ -2,7 +2,7 @@ add_library(pm3rrg_rdv4_hardnested_nosimd OBJECT hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c) -target_compile_options(pm3rrg_rdv4_hardnested_nosimd PRIVATE -Wall -Werror -O3) +target_compile_options(pm3rrg_rdv4_hardnested_nosimd PRIVATE -Wall -O3) set_property(TARGET pm3rrg_rdv4_hardnested_nosimd PROPERTY POSITION_INDEPENDENT_CODE ON) target_include_directories(pm3rrg_rdv4_hardnested_nosimd PRIVATE @@ -32,7 +32,7 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c) - target_compile_options(pm3rrg_rdv4_hardnested_mmx PRIVATE -Wall -Werror -O3) + target_compile_options(pm3rrg_rdv4_hardnested_mmx PRIVATE -Wall -O3) target_compile_options(pm3rrg_rdv4_hardnested_mmx BEFORE PRIVATE -mmmx -mno-sse2 -mno-avx -mno-avx2 -mno-avx512f) set_property(TARGET pm3rrg_rdv4_hardnested_mmx PROPERTY POSITION_INDEPENDENT_CODE ON) @@ -47,7 +47,7 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c) - target_compile_options(pm3rrg_rdv4_hardnested_sse2 PRIVATE -Wall -Werror -O3) + target_compile_options(pm3rrg_rdv4_hardnested_sse2 PRIVATE -Wall -O3) target_compile_options(pm3rrg_rdv4_hardnested_sse2 BEFORE PRIVATE -mmmx -msse2 -mno-avx -mno-avx2 -mno-avx512f) set_property(TARGET pm3rrg_rdv4_hardnested_sse2 PROPERTY POSITION_INDEPENDENT_CODE ON) @@ -62,7 +62,7 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c) - target_compile_options(pm3rrg_rdv4_hardnested_avx PRIVATE -Wall -Werror -O3) + target_compile_options(pm3rrg_rdv4_hardnested_avx PRIVATE -Wall -O3) target_compile_options(pm3rrg_rdv4_hardnested_avx BEFORE PRIVATE -mmmx -msse2 -mavx -mno-avx2 -mno-avx512f) set_property(TARGET pm3rrg_rdv4_hardnested_avx PROPERTY POSITION_INDEPENDENT_CODE ON) @@ -77,7 +77,7 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c) - target_compile_options(pm3rrg_rdv4_hardnested_avx2 PRIVATE -Wall -Werror -O3) + target_compile_options(pm3rrg_rdv4_hardnested_avx2 PRIVATE -Wall -O3) target_compile_options(pm3rrg_rdv4_hardnested_avx2 BEFORE PRIVATE -mmmx -msse2 -mavx -mavx2 -mno-avx512f) set_property(TARGET pm3rrg_rdv4_hardnested_avx2 PROPERTY POSITION_INDEPENDENT_CODE ON) @@ -92,7 +92,7 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS) hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c) - target_compile_options(pm3rrg_rdv4_hardnested_avx512 PRIVATE -Wall -Werror -O3) + target_compile_options(pm3rrg_rdv4_hardnested_avx512 PRIVATE -Wall -O3) target_compile_options(pm3rrg_rdv4_hardnested_avx512 BEFORE PRIVATE -mmmx -msse2 -mavx -mavx2 -mavx512f) set_property(TARGET pm3rrg_rdv4_hardnested_avx512 PROPERTY POSITION_INDEPENDENT_CODE ON) @@ -116,7 +116,7 @@ elseif ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST ARM64_CPUS) hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c) - target_compile_options(pm3rrg_rdv4_hardnested_neon PRIVATE -Wall -Werror -O3) + target_compile_options(pm3rrg_rdv4_hardnested_neon PRIVATE -Wall -O3) set_property(TARGET pm3rrg_rdv4_hardnested_neon PROPERTY POSITION_INDEPENDENT_CODE ON) target_include_directories(pm3rrg_rdv4_hardnested_neon PRIVATE @@ -134,7 +134,7 @@ elseif ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST ARM32_CPUS) hardnested/hardnested_bf_core.c hardnested/hardnested_bitarray_core.c) - target_compile_options(pm3rrg_rdv4_hardnested_neon PRIVATE -Wall -Werror -O3) + target_compile_options(pm3rrg_rdv4_hardnested_neon PRIVATE -Wall -O3) target_compile_options(pm3rrg_rdv4_hardnested_neon BEFORE PRIVATE -mfpu=neon) set_property(TARGET pm3rrg_rdv4_hardnested_neon PROPERTY POSITION_INDEPENDENT_CODE ON) @@ -155,7 +155,7 @@ add_library(pm3rrg_rdv4_hardnested STATIC hardnested/hardnested_bruteforce.c $ ${SIMD_TARGETS}) -target_compile_options(pm3rrg_rdv4_hardnested PRIVATE -Wall -Werror -O3) +target_compile_options(pm3rrg_rdv4_hardnested PRIVATE -Wall -O3) set_property(TARGET pm3rrg_rdv4_hardnested PROPERTY POSITION_INDEPENDENT_CODE ON) target_include_directories(pm3rrg_rdv4_hardnested PRIVATE ../../common diff --git a/client/deps/hardnested/hardnested_bruteforce.c b/client/deps/hardnested/hardnested_bruteforce.c index c5d6aef43..655ef9dbb 100644 --- a/client/deps/hardnested/hardnested_bruteforce.c +++ b/client/deps/hardnested/hardnested_bruteforce.c @@ -177,15 +177,14 @@ crack_states_thread(void *x) { char progress_text[80]; char keystr[19]; - snprintf(keystr, sizeof(keystr), "%012" PRIX64, key); + snprintf(keystr, sizeof(keystr), "%012" PRIX64 " ", key); snprintf(progress_text, sizeof(progress_text), "Brute force phase completed. Key found: " _GREEN_("%s"), keystr); hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0); - PrintAndLogEx(INFO, "---------+---------+---------------------------------------------------------+-----------------+-------"); break; } else if (keys_found) { break; } else { - if (thread_arg->silent == false) { + if (!thread_arg->silent) { char progress_text[80]; snprintf(progress_text, sizeof(progress_text), "Brute force phase: %6.02f%% ", 100.0 * (float)num_keys_tested / (float)(thread_arg->maximum_states)); float remaining_bruteforce = thread_arg->nonces[thread_arg->best_first_bytes[0]].expected_num_brute_force - (float)num_keys_tested / 2; @@ -338,7 +337,7 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint bucket_count = 0; for (statelist_t *p = candidates; p != NULL; p = p->next) { if (p->states[ODD_STATE] != NULL && p->states[EVEN_STATE] != NULL) { - if (ensure_buckets_alloc(bucket_count + 1) == false) { + if (!ensure_buckets_alloc(bucket_count + 1)) { PrintAndLogEx(ERR, "Can't allocate buckets, abort!"); return false; } @@ -376,7 +375,6 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint thread_args[i].best_first_bytes = best_first_bytes; pthread_create(&threads[i], NULL, crack_states_thread, (void *)&thread_args[i]); } - for (uint32_t i = 0; i < num_brute_force_threads; i++) { pthread_join(threads[i], 0); } @@ -387,13 +385,11 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint uint64_t elapsed_time = msclock() - start_time; - if (bf_rate != NULL) { + if (bf_rate != NULL) *bf_rate = (float)num_keys_tested / ((float)elapsed_time / 1000.0); - } - if (keys_found > 0) { + if (keys_found > 0) *found_key = found_bs_key; - } return (keys_found != 0); } diff --git a/client/deps/id48lib.cmake b/client/deps/id48lib.cmake index 47205d494..fa57d7855 100644 --- a/client/deps/id48lib.cmake +++ b/client/deps/id48lib.cmake @@ -3,7 +3,7 @@ add_library(pm3rrg_rdv4_id48 STATIC id48/id48_generator.c id48/id48_recover.c ) -target_compile_options( pm3rrg_rdv4_id48 PRIVATE -Wpedantic -Wall -Werror -O3 -Wno-unknown-pragmas -Wno-inline -Wno-unused-function -DID48_NO_STDIO) +target_compile_options( pm3rrg_rdv4_id48 PRIVATE -Wpedantic -Wall -O3 -Wno-unknown-pragmas -Wno-inline -Wno-unused-function -DID48_NO_STDIO) target_include_directories(pm3rrg_rdv4_id48 PRIVATE id48) target_include_directories(pm3rrg_rdv4_id48 INTERFACE id48) set_property(TARGET pm3rrg_rdv4_id48 PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/client/deps/jansson.cmake b/client/deps/jansson.cmake index c91a47047..42c701d5e 100644 --- a/client/deps/jansson.cmake +++ b/client/deps/jansson.cmake @@ -14,5 +14,5 @@ add_library(pm3rrg_rdv4_jansson STATIC target_compile_definitions(pm3rrg_rdv4_jansson PRIVATE HAVE_STDINT_H) target_include_directories(pm3rrg_rdv4_jansson INTERFACE jansson) -target_compile_options(pm3rrg_rdv4_jansson PRIVATE -Wall -Werror -Wno-unused-function -O3) +target_compile_options(pm3rrg_rdv4_jansson PRIVATE -Wall -Wno-unused-function -O3) set_property(TARGET pm3rrg_rdv4_jansson PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/client/deps/jansson/dump.c b/client/deps/jansson/dump.c index 9c04063e0..afdec8f7a 100644 --- a/client/deps/jansson/dump.c +++ b/client/deps/jansson/dump.c @@ -440,32 +440,33 @@ int json_dumpfd(const json_t *json, int output, size_t flags) { } int json_dump_file(const json_t *json, const char *path, size_t flags) { + int result; - FILE *f = fopen(path, "w"); - if (f == NULL) { - return -1; - } - - int res = json_dumpf(json, f, flags); - - if (fclose(f) != 0) + FILE *output = fopen(path, "w"); + if (!output) return -1; - return res; + result = json_dumpf(json, output, flags); + + if (fclose(output) != 0) + return -1; + + return result; } int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) { + int res; + hashtable_t parents_set; + if (!(flags & JSON_ENCODE_ANY)) { - if (!json_is_array(json) && !json_is_object(json)) { + if (!json_is_array(json) && !json_is_object(json)) return -1; - } } - hashtable_t parents_set; - if (hashtable_init(&parents_set)) { + if (hashtable_init(&parents_set)) return -1; - } - int res = do_dump(json, flags, 0, &parents_set, callback, data); + res = do_dump(json, flags, 0, &parents_set, callback, data); hashtable_close(&parents_set); + return res; } diff --git a/client/deps/lua.cmake b/client/deps/lua.cmake index d89275be6..3bf85e1ce 100644 --- a/client/deps/lua.cmake +++ b/client/deps/lua.cmake @@ -52,5 +52,5 @@ if (NOT MINGW) endif (NOT MINGW) target_include_directories(pm3rrg_rdv4_lua INTERFACE liblua) -target_compile_options(pm3rrg_rdv4_lua PRIVATE -Wall -Werror -O3) +target_compile_options(pm3rrg_rdv4_lua PRIVATE -Wall -O3) set_property(TARGET pm3rrg_rdv4_lua PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/client/deps/mbedtls.cmake b/client/deps/mbedtls.cmake index f33d5ac51..7c72925ab 100644 --- a/client/deps/mbedtls.cmake +++ b/client/deps/mbedtls.cmake @@ -44,10 +44,10 @@ add_library(pm3rrg_rdv4_mbedtls STATIC ../../common/mbedtls/x509.c ../../common/mbedtls/x509_crl.c ../../common/mbedtls/x509_crt.c - ../../common/mbedtls/net_sockets.c + ../../common/mbedtls/net_sockets.c ) target_include_directories(pm3rrg_rdv4_mbedtls PRIVATE ../../common) target_include_directories(pm3rrg_rdv4_mbedtls INTERFACE ../../common/mbedtls) -target_compile_options(pm3rrg_rdv4_mbedtls PRIVATE -Wall -Werror -O3) +target_compile_options(pm3rrg_rdv4_mbedtls PRIVATE -Wall -O3) set_property(TARGET pm3rrg_rdv4_mbedtls PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/client/deps/mqtt.cmake b/client/deps/mqtt.cmake deleted file mode 100644 index f30e761c3..000000000 --- a/client/deps/mqtt.cmake +++ /dev/null @@ -1,9 +0,0 @@ -add_library(pm3rrg_rdv4_mqtt STATIC - mqtt/mqtt.c - mqtt/mqtt_pal.c - ) - -target_compile_definitions(pm3rrg_rdv4_mqtt PRIVATE WAI_PM3_TUNED) -target_include_directories(pm3rrg_rdv4_mqtt INTERFACE mqtt) -target_compile_options(pm3rrg_rdv4_mqtt PRIVATE -Wall -Werror -O3) -set_property(TARGET pm3rrg_rdv4_mqtt PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/client/deps/mqtt/LICENSE b/client/deps/mqtt/LICENSE deleted file mode 100644 index 0bbb84557..000000000 --- a/client/deps/mqtt/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2018 Liam Bindle - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/client/deps/mqtt/Makefile b/client/deps/mqtt/Makefile deleted file mode 100644 index af4679674..000000000 --- a/client/deps/mqtt/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -MYSRCPATHS = -MYINCLUDES = -MYCFLAGS = -Wno-bad-function-cast -Wno-switch-enum -MYDEFS = -DWAI_PM3_TUNED -MYSRCS = \ - mqtt.c \ - mqtt_pal.c \ - -LIB_A = mqtt.a - -# Transition: remove old directories and objects -MYCLEANOLDPATH = ../../mqtt - -include ../../../Makefile.host diff --git a/client/deps/mqtt/mbedtls_sockets.h b/client/deps/mqtt/mbedtls_sockets.h deleted file mode 100644 index 1295152f9..000000000 --- a/client/deps/mqtt/mbedtls_sockets.h +++ /dev/null @@ -1,152 +0,0 @@ -#if !defined(__MBEDTLS_SOCKET_TEMPLATE_H__) -#define __MBEDTLS_SOCKET_TEMPLATE_H__ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#if !defined(MBEDTLS_NET_POLL_READ) -/* compat for older mbedtls */ -#define MBEDTLS_NET_POLL_READ 1 -#define MBEDTLS_NET_POLL_WRITE 1 - -int mbedtls_net_poll(mbedtls_net_context *ctx, uint32_t rw, uint32_t timeout) { - /* XXX this is not ideal but good enough for an example */ - msleep(300); - return 1; -} -#endif - -struct mbedtls_context { - mbedtls_net_context net_ctx; - mbedtls_ssl_context ssl_ctx; - mbedtls_ssl_config ssl_conf; - mbedtls_x509_crt ca_crt; - mbedtls_entropy_context entropy; - mbedtls_ctr_drbg_context ctr_drbg; -}; - -void failed(const char *fn, int rv); -void cert_verify_failed(uint32_t rv); -void open_nb_socket(struct mbedtls_context *ctx, - const char *hostname, - const char *port, - const char *ca_file); - - -void failed(const char *fn, int rv) { - char buf[100]; - mbedtls_strerror(rv, buf, sizeof(buf)); - printf("%s failed with %x (%s)\n", fn, -rv, buf); - exit(1); -} - -void cert_verify_failed(uint32_t rv) { - char buf[512]; - mbedtls_x509_crt_verify_info(buf, sizeof(buf), "\t", rv); - printf("Certificate verification failed (%0" PRIx32 ")\n%s\n", rv, buf); - exit(1); -} - -/* - A template for opening a non-blocking mbed TLS connection. -*/ -void open_nb_socket(struct mbedtls_context *ctx, - const char *hostname, - const char *port, - const char *ca_file) { - - const unsigned char *additional = (const unsigned char *)"Pm3 Client"; - size_t additional_len = 6; - int rv; - - mbedtls_net_context *net_ctx = &ctx->net_ctx; - mbedtls_ssl_context *ssl_ctx = &ctx->ssl_ctx; - mbedtls_ssl_config *ssl_conf = &ctx->ssl_conf; - mbedtls_x509_crt *ca_crt = &ctx->ca_crt; - mbedtls_entropy_context *entropy = &ctx->entropy; - mbedtls_ctr_drbg_context *ctr_drbg = &ctx->ctr_drbg; - - mbedtls_entropy_init(entropy); - mbedtls_ctr_drbg_init(ctr_drbg); - rv = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, - additional, additional_len); - if (rv != 0) { - failed("mbedtls_ctr_drbg_seed", rv); - } - - mbedtls_x509_crt_init(ca_crt); - rv = mbedtls_x509_crt_parse_file(ca_crt, ca_file); - if (rv != 0) { - failed("mbedtls_x509_crt_parse_file", rv); - } - - mbedtls_ssl_config_init(ssl_conf); - rv = mbedtls_ssl_config_defaults(ssl_conf, MBEDTLS_SSL_IS_CLIENT, - MBEDTLS_SSL_TRANSPORT_STREAM, - MBEDTLS_SSL_PRESET_DEFAULT); - if (rv != 0) { - failed("mbedtls_ssl_config_defaults", rv); - } - mbedtls_ssl_conf_ca_chain(ssl_conf, ca_crt, NULL); - mbedtls_ssl_conf_authmode(ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL); - mbedtls_ssl_conf_rng(ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg); - - mbedtls_net_init(net_ctx); - rv = mbedtls_net_connect(net_ctx, hostname, port, MBEDTLS_NET_PROTO_TCP); - if (rv != 0) { - failed("mbedtls_net_connect", rv); - } - rv = mbedtls_net_set_nonblock(net_ctx); - if (rv != 0) { - failed("mbedtls_net_set_nonblock", rv); - } - - mbedtls_ssl_init(ssl_ctx); - rv = mbedtls_ssl_setup(ssl_ctx, ssl_conf); - if (rv != 0) { - failed("mbedtls_ssl_setup", rv); - } - rv = mbedtls_ssl_set_hostname(ssl_ctx, hostname); - if (rv != 0) { - failed("mbedtls_ssl_set_hostname", rv); - } - mbedtls_ssl_set_bio(ssl_ctx, net_ctx, - mbedtls_net_send, mbedtls_net_recv, NULL); - - for (;;) { - rv = mbedtls_ssl_handshake(ssl_ctx); - uint32_t want = 0; - if (rv == MBEDTLS_ERR_SSL_WANT_READ) { - want |= MBEDTLS_NET_POLL_READ; - } else if (rv == MBEDTLS_ERR_SSL_WANT_WRITE) { - want |= MBEDTLS_NET_POLL_WRITE; - } else { - break; - } - rv = mbedtls_net_poll(net_ctx, want, (uint32_t) -1); - if (rv < 0) { - failed("mbedtls_net_poll", rv); - } - } - if (rv != 0) { - failed("mbedtls_ssl_handshake", rv); - } - uint32_t result = mbedtls_ssl_get_verify_result(ssl_ctx); - if (result != 0) { - if (result == (uint32_t) -1) { - failed("mbedtls_ssl_get_verify_result", (int)result); - } else { - cert_verify_failed(result); - } - } -} - -#endif diff --git a/client/deps/mqtt/mqtt.c b/client/deps/mqtt/mqtt.c deleted file mode 100644 index b29f9d9d4..000000000 --- a/client/deps/mqtt/mqtt.c +++ /dev/null @@ -1,1770 +0,0 @@ -/* -MIT License - -Copyright(c) 2018 Liam Bindle - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "mqtt.h" - -/** - * @file - * @brief Implements the functionality of MQTT-C. - * @note The only files that are included are mqtt.h and mqtt_pal.h. - * - * @cond Doxygen_Suppress - */ - -enum MQTTErrors mqtt_sync(struct mqtt_client *client) { - /* Recover from any errors */ - enum MQTTErrors err; - int reconnecting = 0; - MQTT_PAL_MUTEX_LOCK(&client->mutex); - if (client->error != MQTT_ERROR_RECONNECTING && client->error != MQTT_OK && client->reconnect_callback != NULL) { - client->reconnect_callback(client, &client->reconnect_state); - if (client->error != MQTT_OK) { - client->error = MQTT_ERROR_RECONNECT_FAILED; - - /* normally unlocked during CONNECT */ - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - } - err = client->error; - - if (err != MQTT_OK) return err; - } else { - /* mqtt_reconnect will have queued the disconnect packet - that needs to be sent and then call reconnect */ - if (client->error == MQTT_ERROR_RECONNECTING) { - reconnecting = 1; - client->error = MQTT_OK; - } - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - } - - /* Call inspector callback if necessary */ - - if (client->inspector_callback != NULL) { - MQTT_PAL_MUTEX_LOCK(&client->mutex); - err = client->inspector_callback(client); - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - if (err != MQTT_OK) return err; - } - - /* Call receive */ - err = (enum MQTTErrors)__mqtt_recv(client); - if (err != MQTT_OK) return err; - - /* Call send */ - err = (enum MQTTErrors)__mqtt_send(client); - - /* mqtt_reconnect will essentially be a disconnect if there is no callback */ - if (reconnecting && client->reconnect_callback != NULL) { - MQTT_PAL_MUTEX_LOCK(&client->mutex); - client->reconnect_callback(client, &client->reconnect_state); - } - - return err; -} - -uint16_t __mqtt_next_pid(struct mqtt_client *client) { - int pid_exists = 0; - if (client->pid_lfsr == 0) { - client->pid_lfsr = 163u; - } - /* LFSR taps taken from: https://en.wikipedia.org/wiki/Linear-feedback_shift_register */ - - do { - struct mqtt_queued_message *curr; - unsigned lsb = client->pid_lfsr & 1; - (client->pid_lfsr) >>= 1; - if (lsb) { - client->pid_lfsr ^= 0xB400u; - } - - /* check that the PID is unique */ - pid_exists = 0; - for (curr = mqtt_mq_get(&(client->mq), 0); curr >= client->mq.queue_tail; --curr) { - if (curr->packet_id == client->pid_lfsr) { - pid_exists = 1; - break; - } - } - - } while (pid_exists); - return client->pid_lfsr; -} - -enum MQTTErrors mqtt_init(struct mqtt_client *client, - mqtt_pal_socket_handle sockfd, - uint8_t *sendbuf, size_t sendbufsz, - uint8_t *recvbuf, size_t recvbufsz, - void (*publish_response_callback)(void **state, struct mqtt_response_publish *publish)) { - if (client == NULL || sendbuf == NULL || recvbuf == NULL) { - return MQTT_ERROR_NULLPTR; - } - - /* initialize mutex */ - MQTT_PAL_MUTEX_INIT(&client->mutex); - MQTT_PAL_MUTEX_LOCK(&client->mutex); /* unlocked during CONNECT */ - - client->socketfd = sockfd; - - mqtt_mq_init(&client->mq, sendbuf, sendbufsz); - - client->recv_buffer.mem_start = recvbuf; - client->recv_buffer.mem_size = recvbufsz; - client->recv_buffer.curr = client->recv_buffer.mem_start; - client->recv_buffer.curr_sz = client->recv_buffer.mem_size; - - client->error = MQTT_ERROR_CONNECT_NOT_CALLED; - client->response_timeout = 30; - client->number_of_timeouts = 0; - client->number_of_keep_alives = 0; - client->typical_response_time = -1.0f; - client->publish_response_callback = publish_response_callback; - client->pid_lfsr = 0; - client->send_offset = 0; - - client->inspector_callback = NULL; - client->reconnect_callback = NULL; - client->reconnect_state = NULL; - - return MQTT_OK; -} - -void mqtt_init_reconnect(struct mqtt_client *client, - void (*reconnect)(struct mqtt_client *, void **), - void *reconnect_state, - void (*publish_response_callback)(void **state, struct mqtt_response_publish *publish)) { - /* initialize mutex */ - MQTT_PAL_MUTEX_INIT(&client->mutex); - - client->socketfd = (mqtt_pal_socket_handle) - 1; - - mqtt_mq_init(&client->mq, NULL, 0uL); - - client->recv_buffer.mem_start = NULL; - client->recv_buffer.mem_size = 0; - client->recv_buffer.curr = NULL; - client->recv_buffer.curr_sz = 0; - - client->error = MQTT_ERROR_INITIAL_RECONNECT; - client->response_timeout = 30; - client->number_of_timeouts = 0; - client->number_of_keep_alives = 0; - client->typical_response_time = -1.0f; - client->publish_response_callback = publish_response_callback; - client->pid_lfsr = 0; - client->send_offset = 0; - - client->inspector_callback = NULL; - client->reconnect_callback = reconnect; - client->reconnect_state = reconnect_state; -} - -void mqtt_reinit(struct mqtt_client *client, - mqtt_pal_socket_handle socketfd, - uint8_t *sendbuf, size_t sendbufsz, - uint8_t *recvbuf, size_t recvbufsz) { - client->error = MQTT_ERROR_CONNECT_NOT_CALLED; - client->socketfd = socketfd; - - mqtt_mq_init(&client->mq, sendbuf, sendbufsz); - - client->recv_buffer.mem_start = recvbuf; - client->recv_buffer.mem_size = recvbufsz; - client->recv_buffer.curr = client->recv_buffer.mem_start; - client->recv_buffer.curr_sz = client->recv_buffer.mem_size; -} - -/** - * A macro function that: - * 1) Checks that the client isn't in an error state. - * 2) Attempts to pack to client's message queue. - * a) handles errors - * b) if mq buffer is too small, cleans it and tries again - * 3) Upon successful pack, registers the new message. - */ -#define MQTT_CLIENT_TRY_PACK(tmp, msg, client, pack_call, release) \ - if (client->error < 0) { \ - if (release) MQTT_PAL_MUTEX_UNLOCK(&client->mutex); \ - return client->error; \ - } \ - tmp = pack_call; \ - if (tmp < 0) { \ - client->error = (enum MQTTErrors)tmp; \ - if (release) MQTT_PAL_MUTEX_UNLOCK(&client->mutex); \ - return (enum MQTTErrors)tmp; \ - } else if (tmp == 0) { \ - mqtt_mq_clean(&client->mq); \ - tmp = pack_call; \ - if (tmp < 0) { \ - client->error = (enum MQTTErrors)tmp; \ - if (release) MQTT_PAL_MUTEX_UNLOCK(&client->mutex); \ - return (enum MQTTErrors)tmp; \ - } else if(tmp == 0) { \ - client->error = MQTT_ERROR_SEND_BUFFER_IS_FULL; \ - if (release) MQTT_PAL_MUTEX_UNLOCK(&client->mutex); \ - return (enum MQTTErrors)MQTT_ERROR_SEND_BUFFER_IS_FULL; \ - } \ - } \ - msg = mqtt_mq_register(&client->mq, (size_t)tmp); \ - - -enum MQTTErrors mqtt_connect(struct mqtt_client *client, - const char *client_id, - const char *will_topic, - const void *will_message, - size_t will_message_size, - const char *user_name, - const char *password, - uint8_t connect_flags, - uint16_t keep_alive) { - ssize_t rv; - struct mqtt_queued_message *msg; - - /* Note: Current thread already has mutex locked. */ - - /* update the client's state */ - client->keep_alive = keep_alive; - if (client->error == MQTT_ERROR_CONNECT_NOT_CALLED) { - client->error = MQTT_OK; - } - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK(rv, msg, client, - mqtt_pack_connection_request( - client->mq.curr, client->mq.curr_sz, - client_id, will_topic, will_message, - will_message_size, user_name, password, - connect_flags, keep_alive - ), - 1 - ); - /* save the control type of the message */ - msg->control_type = MQTT_CONTROL_CONNECT; - - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return MQTT_OK; -} - -enum MQTTErrors mqtt_publish(struct mqtt_client *client, - const char *topic_name, - const void *application_message, - size_t application_message_size, - uint8_t publish_flags) { - struct mqtt_queued_message *msg; - ssize_t rv; - uint16_t packet_id; - MQTT_PAL_MUTEX_LOCK(&client->mutex); - packet_id = __mqtt_next_pid(client); - - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_publish_request( - client->mq.curr, client->mq.curr_sz, - topic_name, - packet_id, - application_message, - application_message_size, - publish_flags - ), - 1 - ); - /* save the control type and packet id of the message */ - msg->control_type = MQTT_CONTROL_PUBLISH; - msg->packet_id = packet_id; - - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return MQTT_OK; -} - -ssize_t __mqtt_puback(struct mqtt_client *client, uint16_t packet_id) { - ssize_t rv; - struct mqtt_queued_message *msg; - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_pubxxx_request( - client->mq.curr, client->mq.curr_sz, - MQTT_CONTROL_PUBACK, - packet_id - ), - 0 - ); - /* save the control type and packet id of the message */ - msg->control_type = MQTT_CONTROL_PUBACK; - msg->packet_id = packet_id; - - return MQTT_OK; -} - -ssize_t __mqtt_pubrec(struct mqtt_client *client, uint16_t packet_id) { - ssize_t rv; - struct mqtt_queued_message *msg; - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_pubxxx_request( - client->mq.curr, client->mq.curr_sz, - MQTT_CONTROL_PUBREC, - packet_id - ), - 0 - ); - /* save the control type and packet id of the message */ - msg->control_type = MQTT_CONTROL_PUBREC; - msg->packet_id = packet_id; - - return MQTT_OK; -} - -ssize_t __mqtt_pubrel(struct mqtt_client *client, uint16_t packet_id) { - ssize_t rv; - struct mqtt_queued_message *msg; - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_pubxxx_request( - client->mq.curr, client->mq.curr_sz, - MQTT_CONTROL_PUBREL, - packet_id - ), - 0 - ); - /* save the control type and packet id of the message */ - msg->control_type = MQTT_CONTROL_PUBREL; - msg->packet_id = packet_id; - - return MQTT_OK; -} - -ssize_t __mqtt_pubcomp(struct mqtt_client *client, uint16_t packet_id) { - ssize_t rv; - struct mqtt_queued_message *msg; - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_pubxxx_request( - client->mq.curr, client->mq.curr_sz, - MQTT_CONTROL_PUBCOMP, - packet_id - ), - 0 - ); - /* save the control type and packet id of the message */ - msg->control_type = MQTT_CONTROL_PUBCOMP; - msg->packet_id = packet_id; - - return MQTT_OK; -} - -enum MQTTErrors mqtt_subscribe(struct mqtt_client *client, - const char *topic_name, - int max_qos_level) { - ssize_t rv; - uint16_t packet_id; - struct mqtt_queued_message *msg; - MQTT_PAL_MUTEX_LOCK(&client->mutex); - packet_id = __mqtt_next_pid(client); - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_subscribe_request( - client->mq.curr, client->mq.curr_sz, - packet_id, - topic_name, - max_qos_level, - (const char *)NULL - ), - 1 - ); - /* save the control type and packet id of the message */ - msg->control_type = MQTT_CONTROL_SUBSCRIBE; - msg->packet_id = packet_id; - - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return MQTT_OK; -} - -enum MQTTErrors mqtt_unsubscribe(struct mqtt_client *client, - const char *topic_name) { - uint16_t packet_id = __mqtt_next_pid(client); - ssize_t rv; - struct mqtt_queued_message *msg; - MQTT_PAL_MUTEX_LOCK(&client->mutex); - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_unsubscribe_request( - client->mq.curr, client->mq.curr_sz, - packet_id, - topic_name, - (const char *)NULL - ), - 1 - ); - /* save the control type and packet id of the message */ - msg->control_type = MQTT_CONTROL_UNSUBSCRIBE; - msg->packet_id = packet_id; - - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return MQTT_OK; -} - -enum MQTTErrors mqtt_ping(struct mqtt_client *client) { - enum MQTTErrors rv; - MQTT_PAL_MUTEX_LOCK(&client->mutex); - rv = __mqtt_ping(client); - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return rv; -} - -enum MQTTErrors __mqtt_ping(struct mqtt_client *client) { - ssize_t rv; - struct mqtt_queued_message *msg; - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_ping_request( - client->mq.curr, client->mq.curr_sz - ), - 0 - ); - /* save the control type and packet id of the message */ - msg->control_type = MQTT_CONTROL_PINGREQ; - - - return MQTT_OK; -} - -enum MQTTErrors mqtt_reconnect(struct mqtt_client *client) { - enum MQTTErrors err = mqtt_disconnect(client); - - if (err == MQTT_OK) { - MQTT_PAL_MUTEX_LOCK(&client->mutex); - client->error = MQTT_ERROR_RECONNECTING; - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - } - return err; -} - -enum MQTTErrors mqtt_disconnect(struct mqtt_client *client) { - ssize_t rv; - struct mqtt_queued_message *msg; - MQTT_PAL_MUTEX_LOCK(&client->mutex); - - /* try to pack the message */ - MQTT_CLIENT_TRY_PACK( - rv, msg, client, - mqtt_pack_disconnect( - client->mq.curr, client->mq.curr_sz - ), - 1 - ); - /* save the control type and packet id of the message */ - msg->control_type = MQTT_CONTROL_DISCONNECT; - - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return MQTT_OK; -} - -ssize_t __mqtt_send(struct mqtt_client *client) { - uint8_t inspected; - ssize_t len; - int inflight_qos2 = 0; - int i = 0; - - MQTT_PAL_MUTEX_LOCK(&client->mutex); - - if (client->error < 0 && client->error != MQTT_ERROR_SEND_BUFFER_IS_FULL) { - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return client->error; - } - - /* loop through all messages in the queue */ - len = mqtt_mq_length(&client->mq); - for (; i < len; ++i) { - struct mqtt_queued_message *msg = mqtt_mq_get(&client->mq, i); - int resend = 0; - if (msg->state == MQTT_QUEUED_UNSENT) { - /* message has not been sent to lets send it */ - resend = 1; - } else if (msg->state == MQTT_QUEUED_AWAITING_ACK) { - /* check for timeout */ - if (MQTT_PAL_TIME() > msg->time_sent + client->response_timeout) { - resend = 1; - client->number_of_timeouts += 1; - client->send_offset = 0; - } - } - - /* only send QoS 2 message if there are no inflight QoS 2 PUBLISH messages */ - if (msg->control_type == MQTT_CONTROL_PUBLISH - && (msg->state == MQTT_QUEUED_UNSENT || msg->state == MQTT_QUEUED_AWAITING_ACK)) { - inspected = 0x03 & ((msg->start[0]) >> 1); /* qos */ - if (inspected == 2) { - if (inflight_qos2) { - resend = 0; - } - inflight_qos2 = 1; - } - } - - /* goto next message if we don't need to send */ - if (!resend) { - continue; - } - - /* we're sending the message */ - { - ssize_t tmp = mqtt_pal_sendall(client->socketfd, msg->start + client->send_offset, msg->size - client->send_offset, 0); - if (tmp < 0) { - client->error = (enum MQTTErrors)tmp; - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return tmp; - } else { - client->send_offset += (unsigned long)tmp; - if (client->send_offset < msg->size) { - /* partial sent. Await additional calls */ - break; - } else { - /* whole message has been sent */ - client->send_offset = 0; - } - - } - - } - - /* update timeout watcher */ - client->time_of_last_send = MQTT_PAL_TIME(); - msg->time_sent = client->time_of_last_send; - - /* - Determine the state to put the message in. - Control Types: - MQTT_CONTROL_CONNECT -> awaiting - MQTT_CONTROL_CONNACK -> n/a - MQTT_CONTROL_PUBLISH -> qos == 0 ? complete : awaiting - MQTT_CONTROL_PUBACK -> complete - MQTT_CONTROL_PUBREC -> awaiting - MQTT_CONTROL_PUBREL -> awaiting - MQTT_CONTROL_PUBCOMP -> complete - MQTT_CONTROL_SUBSCRIBE -> awaiting - MQTT_CONTROL_SUBACK -> n/a - MQTT_CONTROL_UNSUBSCRIBE -> awaiting - MQTT_CONTROL_UNSUBACK -> n/a - MQTT_CONTROL_PINGREQ -> awaiting - MQTT_CONTROL_PINGRESP -> n/a - MQTT_CONTROL_DISCONNECT -> complete - */ - switch (msg->control_type) { - case MQTT_CONTROL_PUBACK: - case MQTT_CONTROL_PUBCOMP: - case MQTT_CONTROL_DISCONNECT: - msg->state = MQTT_QUEUED_COMPLETE; - break; - case MQTT_CONTROL_PUBLISH: - inspected = (MQTT_PUBLISH_QOS_MASK & (msg->start[0])) >> 1; /* qos */ - if (inspected == 0) { - msg->state = MQTT_QUEUED_COMPLETE; - } else if (inspected == 1) { - msg->state = MQTT_QUEUED_AWAITING_ACK; - /*set DUP flag for subsequent sends [Spec MQTT-3.3.1-1] */ - msg->start[0] |= MQTT_PUBLISH_DUP; - } else { - msg->state = MQTT_QUEUED_AWAITING_ACK; - } - break; - case MQTT_CONTROL_CONNECT: - case MQTT_CONTROL_PUBREC: - case MQTT_CONTROL_PUBREL: - case MQTT_CONTROL_SUBSCRIBE: - case MQTT_CONTROL_UNSUBSCRIBE: - case MQTT_CONTROL_PINGREQ: - msg->state = MQTT_QUEUED_AWAITING_ACK; - break; - default: - client->error = MQTT_ERROR_MALFORMED_REQUEST; - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return MQTT_ERROR_MALFORMED_REQUEST; - } - } - - /* check for keep-alive */ - { - mqtt_pal_time_t keep_alive_timeout = client->time_of_last_send + (mqtt_pal_time_t)((float)(client->keep_alive)); - if (MQTT_PAL_TIME() > keep_alive_timeout) { - ssize_t rv = __mqtt_ping(client); - if (rv != MQTT_OK) { - client->error = (enum MQTTErrors)rv; - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return rv; - } - } - } - - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return MQTT_OK; -} - -ssize_t __mqtt_recv(struct mqtt_client *client) { - struct mqtt_response response; - ssize_t mqtt_recv_ret = MQTT_OK; - MQTT_PAL_MUTEX_LOCK(&client->mutex); - - /* read until there is nothing left to read, or there was an error */ - while (mqtt_recv_ret == MQTT_OK) { - /* read in as many bytes as possible */ - ssize_t rv, consumed; - struct mqtt_queued_message *msg = NULL; - - rv = mqtt_pal_recvall(client->socketfd, client->recv_buffer.curr, client->recv_buffer.curr_sz, 0); - if (rv < 0) { - /* an error occurred */ - client->error = (enum MQTTErrors)rv; - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return rv; - } else { - client->recv_buffer.curr += rv; - client->recv_buffer.curr_sz -= (unsigned long)rv; - } - - /* attempt to parse */ - consumed = mqtt_unpack_response(&response, client->recv_buffer.mem_start, (size_t)(client->recv_buffer.curr - client->recv_buffer.mem_start)); - - if (consumed < 0) { - client->error = (enum MQTTErrors)consumed; - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return consumed; - } else if (consumed == 0) { - /* if curr_sz is 0 then the buffer is too small to ever fit the message */ - if (client->recv_buffer.curr_sz == 0) { - client->error = MQTT_ERROR_RECV_BUFFER_TOO_SMALL; - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return MQTT_ERROR_RECV_BUFFER_TOO_SMALL; - } - - /* just need to wait for the rest of the data */ - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return MQTT_OK; - } - - /* response was unpacked successfully */ - - /* - The switch statement below manages how the client responds to messages from the broker. - - Control Types (that we expect to receive from the broker): - MQTT_CONTROL_CONNACK: - -> release associated CONNECT - -> handle response - MQTT_CONTROL_PUBLISH: - -> stage response, none if qos==0, PUBACK if qos==1, PUBREC if qos==2 - -> call publish callback - MQTT_CONTROL_PUBACK: - -> release associated PUBLISH - MQTT_CONTROL_PUBREC: - -> release PUBLISH - -> stage PUBREL - MQTT_CONTROL_PUBREL: - -> release associated PUBREC - -> stage PUBCOMP - MQTT_CONTROL_PUBCOMP: - -> release PUBREL - MQTT_CONTROL_SUBACK: - -> release SUBSCRIBE - -> handle response - MQTT_CONTROL_UNSUBACK: - -> release UNSUBSCRIBE - MQTT_CONTROL_PINGRESP: - -> release PINGREQ - */ - switch (response.fixed_header.control_type) { - case MQTT_CONTROL_CONNACK: - /* release associated CONNECT */ - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_CONNECT, NULL); - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - /* initialize typical response time */ - client->typical_response_time = (float)(MQTT_PAL_TIME() - msg->time_sent); - /* check that connection was successful */ - if (response.decoded.connack.return_code != MQTT_CONNACK_ACCEPTED) { - if (response.decoded.connack.return_code == MQTT_CONNACK_REFUSED_IDENTIFIER_REJECTED) { - client->error = MQTT_ERROR_CONNECT_CLIENT_ID_REFUSED; - mqtt_recv_ret = MQTT_ERROR_CONNECT_CLIENT_ID_REFUSED; - } else { - client->error = MQTT_ERROR_CONNECTION_REFUSED; - mqtt_recv_ret = MQTT_ERROR_CONNECTION_REFUSED; - } - break; - } - break; - case MQTT_CONTROL_PUBLISH: - /* stage response, none if qos==0, PUBACK if qos==1, PUBREC if qos==2 */ - if (response.decoded.publish.qos_level == 1) { - rv = __mqtt_puback(client, response.decoded.publish.packet_id); - if (rv != MQTT_OK) { - client->error = (enum MQTTErrors)rv; - mqtt_recv_ret = rv; - break; - } - } else if (response.decoded.publish.qos_level == 2) { - /* check if this is a duplicate */ - if (mqtt_mq_find(&client->mq, MQTT_CONTROL_PUBREC, &response.decoded.publish.packet_id) != NULL) { - break; - } - - rv = __mqtt_pubrec(client, response.decoded.publish.packet_id); - if (rv != MQTT_OK) { - client->error = (enum MQTTErrors)rv; - mqtt_recv_ret = rv; - break; - } - } - /* call publish callback */ - client->publish_response_callback(&client->publish_response_callback_state, &response.decoded.publish); - break; - case MQTT_CONTROL_PUBACK: - /* release associated PUBLISH */ - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_PUBLISH, &response.decoded.puback.packet_id); - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - /* update response time */ - client->typical_response_time = 0.875f * (client->typical_response_time) + 0.125f * (float)(MQTT_PAL_TIME() - msg->time_sent); - break; - case MQTT_CONTROL_PUBREC: - /* check if this is a duplicate */ - if (mqtt_mq_find(&client->mq, MQTT_CONTROL_PUBREL, &response.decoded.pubrec.packet_id) != NULL) { - break; - } - /* release associated PUBLISH */ - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_PUBLISH, &response.decoded.pubrec.packet_id); - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - /* update response time */ - client->typical_response_time = 0.875f * (client->typical_response_time) + 0.125f * (float)(MQTT_PAL_TIME() - msg->time_sent); - /* stage PUBREL */ - rv = __mqtt_pubrel(client, response.decoded.pubrec.packet_id); - if (rv != MQTT_OK) { - client->error = (enum MQTTErrors)rv; - mqtt_recv_ret = rv; - break; - } - break; - case MQTT_CONTROL_PUBREL: - /* release associated PUBREC */ - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_PUBREC, &response.decoded.pubrel.packet_id); - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - /* update response time */ - client->typical_response_time = 0.875f * (client->typical_response_time) + 0.125f * (float)(MQTT_PAL_TIME() - msg->time_sent); - /* stage PUBCOMP */ - rv = __mqtt_pubcomp(client, response.decoded.pubrec.packet_id); - if (rv != MQTT_OK) { - client->error = (enum MQTTErrors)rv; - mqtt_recv_ret = rv; - break; - } - break; - case MQTT_CONTROL_PUBCOMP: - /* release associated PUBREL */ - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_PUBREL, &response.decoded.pubcomp.packet_id); - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - /* update response time */ - client->typical_response_time = 0.875f * (client->typical_response_time) + 0.125f * (float)(MQTT_PAL_TIME() - msg->time_sent); - break; - case MQTT_CONTROL_SUBACK: - /* release associated SUBSCRIBE */ - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_SUBSCRIBE, &response.decoded.suback.packet_id); - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - /* update response time */ - client->typical_response_time = 0.875f * (client->typical_response_time) + 0.125f * (float)(MQTT_PAL_TIME() - msg->time_sent); - /* check that subscription was successful (not currently only one subscribe at a time) */ - if (response.decoded.suback.return_codes[0] == MQTT_SUBACK_FAILURE) { - client->error = MQTT_ERROR_SUBSCRIBE_FAILED; - mqtt_recv_ret = MQTT_ERROR_SUBSCRIBE_FAILED; - break; - } - break; - case MQTT_CONTROL_UNSUBACK: - /* release associated UNSUBSCRIBE */ - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_UNSUBSCRIBE, &response.decoded.unsuback.packet_id); - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - /* update response time */ - client->typical_response_time = 0.875f * (client->typical_response_time) + 0.125f * (float)(MQTT_PAL_TIME() - msg->time_sent); - break; - case MQTT_CONTROL_PINGRESP: - /* release associated PINGREQ */ - msg = mqtt_mq_find(&client->mq, MQTT_CONTROL_PINGREQ, NULL); - if (msg == NULL) { - client->error = MQTT_ERROR_ACK_OF_UNKNOWN; - mqtt_recv_ret = MQTT_ERROR_ACK_OF_UNKNOWN; - break; - } - msg->state = MQTT_QUEUED_COMPLETE; - /* update response time */ - client->typical_response_time = 0.875f * (client->typical_response_time) + 0.125f * (float)(MQTT_PAL_TIME() - msg->time_sent); - break; - default: - client->error = MQTT_ERROR_MALFORMED_RESPONSE; - mqtt_recv_ret = MQTT_ERROR_MALFORMED_RESPONSE; - break; - } - { - /* we've handled the response, now clean the buffer */ - void *dest = (unsigned char *)client->recv_buffer.mem_start; - void *src = (unsigned char *)client->recv_buffer.mem_start + consumed; - size_t n = (size_t)(client->recv_buffer.curr - client->recv_buffer.mem_start - consumed); - memmove(dest, src, n); - client->recv_buffer.curr -= consumed; - client->recv_buffer.curr_sz += (unsigned long)consumed; - } - } - - /* In case there was some error handling the (well formed) message, we end up here */ - MQTT_PAL_MUTEX_UNLOCK(&client->mutex); - return mqtt_recv_ret; -} - -/* FIXED HEADER */ - -#define MQTT_BITFIELD_RULE_VIOLOATION(bitfield, rule_value, rule_mask) ((bitfield ^ rule_value) & rule_mask) - -struct mqtt_fixed_header_rules_s { - uint8_t control_type_is_valid[16]; - uint8_t required_flags[16]; - uint8_t mask_required_flags[16]; -} ; - -static const struct mqtt_fixed_header_rules_s mqtt_fixed_header_rules = { - { - /* boolean value, true if type is valid */ - 0x00, /* MQTT_CONTROL_RESERVED */ - 0x01, /* MQTT_CONTROL_CONNECT */ - 0x01, /* MQTT_CONTROL_CONNACK */ - 0x01, /* MQTT_CONTROL_PUBLISH */ - 0x01, /* MQTT_CONTROL_PUBACK */ - 0x01, /* MQTT_CONTROL_PUBREC */ - 0x01, /* MQTT_CONTROL_PUBREL */ - 0x01, /* MQTT_CONTROL_PUBCOMP */ - 0x01, /* MQTT_CONTROL_SUBSCRIBE */ - 0x01, /* MQTT_CONTROL_SUBACK */ - 0x01, /* MQTT_CONTROL_UNSUBSCRIBE */ - 0x01, /* MQTT_CONTROL_UNSUBACK */ - 0x01, /* MQTT_CONTROL_PINGREQ */ - 0x01, /* MQTT_CONTROL_PINGRESP */ - 0x01, /* MQTT_CONTROL_DISCONNECT */ - 0x00 /* MQTT_CONTROL_RESERVED */ - }, - { - /* flags that must be set for the associated control type */ - 0x00, /* MQTT_CONTROL_RESERVED */ - 0x00, /* MQTT_CONTROL_CONNECT */ - 0x00, /* MQTT_CONTROL_CONNACK */ - 0x00, /* MQTT_CONTROL_PUBLISH */ - 0x00, /* MQTT_CONTROL_PUBACK */ - 0x00, /* MQTT_CONTROL_PUBREC */ - 0x02, /* MQTT_CONTROL_PUBREL */ - 0x00, /* MQTT_CONTROL_PUBCOMP */ - 0x02, /* MQTT_CONTROL_SUBSCRIBE */ - 0x00, /* MQTT_CONTROL_SUBACK */ - 0x02, /* MQTT_CONTROL_UNSUBSCRIBE */ - 0x00, /* MQTT_CONTROL_UNSUBACK */ - 0x00, /* MQTT_CONTROL_PINGREQ */ - 0x00, /* MQTT_CONTROL_PINGRESP */ - 0x00, /* MQTT_CONTROL_DISCONNECT */ - 0x00 /* MQTT_CONTROL_RESERVED */ - }, - { - /* mask of flags that must be specific values for the associated control type*/ - 0x00, /* MQTT_CONTROL_RESERVED */ - 0x0F, /* MQTT_CONTROL_CONNECT */ - 0x0F, /* MQTT_CONTROL_CONNACK */ - 0x00, /* MQTT_CONTROL_PUBLISH */ - 0x0F, /* MQTT_CONTROL_PUBACK */ - 0x0F, /* MQTT_CONTROL_PUBREC */ - 0x0F, /* MQTT_CONTROL_PUBREL */ - 0x0F, /* MQTT_CONTROL_PUBCOMP */ - 0x0F, /* MQTT_CONTROL_SUBSCRIBE */ - 0x0F, /* MQTT_CONTROL_SUBACK */ - 0x0F, /* MQTT_CONTROL_UNSUBSCRIBE */ - 0x0F, /* MQTT_CONTROL_UNSUBACK */ - 0x0F, /* MQTT_CONTROL_PINGREQ */ - 0x0F, /* MQTT_CONTROL_PINGRESP */ - 0x0F, /* MQTT_CONTROL_DISCONNECT */ - 0x00 /* MQTT_CONTROL_RESERVED */ - } -}; - -static ssize_t mqtt_fixed_header_rule_violation(const struct mqtt_fixed_header *fixed_header) { - uint8_t control_type; - uint8_t control_flags; - uint8_t required_flags; - uint8_t mask_required_flags; - - /* get value and rules */ - control_type = (uint8_t)fixed_header->control_type; - control_flags = fixed_header->control_flags; - required_flags = mqtt_fixed_header_rules.required_flags[control_type]; - mask_required_flags = mqtt_fixed_header_rules.mask_required_flags[control_type]; - - /* check for valid type */ - if (!mqtt_fixed_header_rules.control_type_is_valid[control_type]) { - return MQTT_ERROR_CONTROL_FORBIDDEN_TYPE; - } - - /* check that flags are appropriate */ - if (MQTT_BITFIELD_RULE_VIOLOATION(control_flags, required_flags, mask_required_flags)) { - return MQTT_ERROR_CONTROL_INVALID_FLAGS; - } - - return 0; -} - -ssize_t mqtt_unpack_fixed_header(struct mqtt_response *response, const uint8_t *buf, size_t bufsz) { - struct mqtt_fixed_header *fixed_header; - const uint8_t *start = buf; - int lshift; - ssize_t errcode; - - /* check for null pointers or empty buffer */ - if (response == NULL || buf == NULL) { - return MQTT_ERROR_NULLPTR; - } - fixed_header = &(response->fixed_header); - - /* check that bufsz is not zero */ - if (bufsz == 0) return 0; - - /* parse control type and flags */ - fixed_header->control_type = (enum MQTTControlPacketType)(*buf >> 4); - fixed_header->control_flags = (uint8_t)(*buf & 0x0F); - - /* parse remaining size */ - fixed_header->remaining_length = 0; - - lshift = 0; - do { - - /* MQTT spec (2.2.3) says the maximum length is 28 bits */ - if (lshift == 28) - return MQTT_ERROR_INVALID_REMAINING_LENGTH; - - /* consume byte and assert at least 1 byte left */ - --bufsz; - ++buf; - if (bufsz == 0) return 0; - - /* parse next byte*/ - fixed_header->remaining_length += (uint32_t)((*buf & 0x7F) << lshift); - lshift += 7; - } while (*buf & 0x80); /* while continue bit is set */ - - /* consume last byte */ - --bufsz; - ++buf; - - /* check that the fixed header is valid */ - errcode = mqtt_fixed_header_rule_violation(fixed_header); - if (errcode) { - return errcode; - } - - /* check that the buffer size if GT remaining length */ - if (bufsz < fixed_header->remaining_length) { - return 0; - } - - /* return how many bytes were consumed */ - return buf - start; -} - -ssize_t mqtt_pack_fixed_header(uint8_t *buf, size_t bufsz, const struct mqtt_fixed_header *fixed_header) { - const uint8_t *start = buf; - ssize_t errcode; - uint32_t remaining_length; - - /* check for null pointers or empty buffer */ - if (fixed_header == NULL || buf == NULL) { - return MQTT_ERROR_NULLPTR; - } - - /* check that the fixed header is valid */ - errcode = mqtt_fixed_header_rule_violation(fixed_header); - if (errcode) { - return errcode; - } - - /* check that bufsz is not zero */ - if (bufsz == 0) return 0; - - /* pack control type and flags */ - *buf = (uint8_t)((((uint8_t) fixed_header->control_type) << 4) & 0xF0); - *buf = (uint8_t)(*buf | (((uint8_t) fixed_header->control_flags) & 0x0F)); - - remaining_length = fixed_header->remaining_length; - - /* MQTT spec (2.2.3) says maximum remaining length is 2^28-1 */ - if (remaining_length >= 256 * 1024 * 1024) - return MQTT_ERROR_INVALID_REMAINING_LENGTH; - - do { - /* consume byte and assert at least 1 byte left */ - --bufsz; - ++buf; - if (bufsz == 0) return 0; - - /* pack next byte */ - *buf = remaining_length & 0x7F; - if (remaining_length > 127) *buf |= 0x80; - remaining_length = remaining_length >> 7; - } while (*buf & 0x80); - - /* consume last byte */ - --bufsz; - ++buf; - - /* check that there's still enough space in buffer for packet */ - if (bufsz < fixed_header->remaining_length) { - return 0; - } - - /* return how many bytes were consumed */ - return buf - start; -} - -/* CONNECT */ -ssize_t mqtt_pack_connection_request(uint8_t *buf, size_t bufsz, - const char *client_id, - const char *will_topic, - const void *will_message, - size_t will_message_size, - const char *user_name, - const char *password, - uint8_t connect_flags, - uint16_t keep_alive) { - struct mqtt_fixed_header fixed_header; - size_t remaining_length; - const uint8_t *const start = buf; - ssize_t rv; - - /* pack the fixed headr */ - fixed_header.control_type = MQTT_CONTROL_CONNECT; - fixed_header.control_flags = 0x00; - - /* calculate remaining length and build connect_flags at the same time */ - connect_flags = (uint8_t)(connect_flags & ~MQTT_CONNECT_RESERVED); - remaining_length = 10; /* size of variable header */ - - if (client_id == NULL) { - client_id = ""; - } - /* For an empty client_id, a clean session is required */ - if (client_id[0] == '\0' && !(connect_flags & MQTT_CONNECT_CLEAN_SESSION)) { - return MQTT_ERROR_CLEAN_SESSION_IS_REQUIRED; - } - /* mqtt_string length is strlen + 2 */ - remaining_length += __mqtt_packed_cstrlen(client_id); - - if (will_topic != NULL) { - uint8_t temp; - /* there is a will */ - connect_flags |= MQTT_CONNECT_WILL_FLAG; - remaining_length += __mqtt_packed_cstrlen(will_topic); - - if (will_message == NULL) { - /* if there's a will there MUST be a will message */ - return MQTT_ERROR_CONNECT_NULL_WILL_MESSAGE; - } - remaining_length += 2 + will_message_size; /* size of will_message */ - - /* assert that the will QOS is valid (i.e. not 3) */ - temp = connect_flags & 0x18; /* mask to QOS */ - if (temp == 0x18) { - /* bitwise equality with QoS 3 (invalid)*/ - return MQTT_ERROR_CONNECT_FORBIDDEN_WILL_QOS; - } - } else { - /* there is no will so set all will flags to zero */ - connect_flags &= (uint8_t)~MQTT_CONNECT_WILL_FLAG; - connect_flags &= (uint8_t)~0x18; - connect_flags &= (uint8_t)~MQTT_CONNECT_WILL_RETAIN; - } - - if (user_name != NULL) { - /* a user name is present */ - connect_flags |= MQTT_CONNECT_USER_NAME; - remaining_length += __mqtt_packed_cstrlen(user_name); - } else { - connect_flags &= (uint8_t)~MQTT_CONNECT_USER_NAME; - } - - if (password != NULL) { - /* a password is present */ - connect_flags |= MQTT_CONNECT_PASSWORD; - remaining_length += __mqtt_packed_cstrlen(password); - } else { - connect_flags &= (uint8_t)~MQTT_CONNECT_PASSWORD; - } - - /* fixed header length is now calculated*/ - fixed_header.remaining_length = (uint32_t)remaining_length; - - /* pack fixed header and perform error checks */ - rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); - if (rv <= 0) { - /* something went wrong */ - return rv; - } - buf += rv; - bufsz -= (size_t)rv; - - /* check that the buffer has enough space to fit the remaining length */ - if (bufsz < fixed_header.remaining_length) { - return 0; - } - - /* pack the variable header */ - *buf++ = 0x00; - *buf++ = 0x04; - *buf++ = (uint8_t) 'M'; - *buf++ = (uint8_t) 'Q'; - *buf++ = (uint8_t) 'T'; - *buf++ = (uint8_t) 'T'; - *buf++ = MQTT_PROTOCOL_LEVEL; - *buf++ = connect_flags; - buf += __mqtt_pack_uint16(buf, keep_alive); - - /* pack the payload */ - buf += __mqtt_pack_str(buf, client_id); - if (will_topic != NULL) { - buf += __mqtt_pack_str(buf, will_topic); - buf += __mqtt_pack_uint16(buf, (uint16_t)will_message_size); - memcpy(buf, will_message, will_message_size); - buf += will_message_size; - } - if (user_name != NULL) { - buf += __mqtt_pack_str(buf, user_name); - } - if (password != NULL) { - buf += __mqtt_pack_str(buf, password); - } - - /* return the number of bytes that were consumed */ - return buf - start; -} - -/* CONNACK */ -ssize_t mqtt_unpack_connack_response(struct mqtt_response *mqtt_response, const uint8_t *buf) { - const uint8_t *const start = buf; - struct mqtt_response_connack *response; - - /* check that remaining length is 2 */ - if (mqtt_response->fixed_header.remaining_length != 2) { - return MQTT_ERROR_MALFORMED_RESPONSE; - } - - response = &(mqtt_response->decoded.connack); - /* unpack */ - if (*buf & 0xFE) { - /* only bit 1 can be set */ - return MQTT_ERROR_CONNACK_FORBIDDEN_FLAGS; - } else { - response->session_present_flag = *buf++; - } - - if (*buf > 5u) { - /* only bit 1 can be set */ - return MQTT_ERROR_CONNACK_FORBIDDEN_CODE; - } else { - response->return_code = (enum MQTTConnackReturnCode) * buf++; - } - return buf - start; -} - -/* DISCONNECT */ -ssize_t mqtt_pack_disconnect(uint8_t *buf, size_t bufsz) { - struct mqtt_fixed_header fixed_header; - fixed_header.control_type = MQTT_CONTROL_DISCONNECT; - fixed_header.control_flags = 0; - fixed_header.remaining_length = 0; - return mqtt_pack_fixed_header(buf, bufsz, &fixed_header); -} - -/* PING */ -ssize_t mqtt_pack_ping_request(uint8_t *buf, size_t bufsz) { - struct mqtt_fixed_header fixed_header; - fixed_header.control_type = MQTT_CONTROL_PINGREQ; - fixed_header.control_flags = 0; - fixed_header.remaining_length = 0; - return mqtt_pack_fixed_header(buf, bufsz, &fixed_header); -} - -/* PUBLISH */ -ssize_t mqtt_pack_publish_request(uint8_t *buf, size_t bufsz, - const char *topic_name, - uint16_t packet_id, - const void *application_message, - size_t application_message_size, - uint8_t publish_flags) { - const uint8_t *const start = buf; - ssize_t rv; - struct mqtt_fixed_header fixed_header; - uint32_t remaining_length; - uint8_t inspected_qos; - - /* check for null pointers */ - if (buf == NULL || topic_name == NULL) { - return MQTT_ERROR_NULLPTR; - } - - /* inspect QoS level */ - inspected_qos = (publish_flags & MQTT_PUBLISH_QOS_MASK) >> 1; /* mask */ - - /* build the fixed header */ - fixed_header.control_type = MQTT_CONTROL_PUBLISH; - - /* calculate remaining length */ - remaining_length = (uint32_t)__mqtt_packed_cstrlen(topic_name); - if (inspected_qos > 0) { - remaining_length += 2; - } - remaining_length += (uint32_t)application_message_size; - fixed_header.remaining_length = remaining_length; - - /* force dup to 0 if qos is 0 [Spec MQTT-3.3.1-2] */ - if (inspected_qos == 0) { - publish_flags &= (uint8_t)~MQTT_PUBLISH_DUP; - } - - /* make sure that qos is not 3 [Spec MQTT-3.3.1-4] */ - if (inspected_qos == 3) { - return MQTT_ERROR_PUBLISH_FORBIDDEN_QOS; - } - fixed_header.control_flags = publish_flags & 0x7; - - /* pack fixed header */ - rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); - if (rv <= 0) { - /* something went wrong */ - return rv; - } - buf += rv; - bufsz -= (size_t)rv; - - /* check that buffer is big enough */ - if (bufsz < remaining_length) { - return 0; - } - - /* pack variable header */ - buf += __mqtt_pack_str(buf, topic_name); - if (inspected_qos > 0) { - buf += __mqtt_pack_uint16(buf, packet_id); - } - - /* pack payload */ - memcpy(buf, application_message, application_message_size); - buf += application_message_size; - - return buf - start; -} - -ssize_t mqtt_unpack_publish_response(struct mqtt_response *mqtt_response, const uint8_t *buf) { - const uint8_t *const start = buf; - struct mqtt_fixed_header *fixed_header; - struct mqtt_response_publish *response; - - fixed_header = &(mqtt_response->fixed_header); - response = &(mqtt_response->decoded.publish); - - /* get flags */ - response->dup_flag = (fixed_header->control_flags & MQTT_PUBLISH_DUP) >> 3; - response->qos_level = (fixed_header->control_flags & MQTT_PUBLISH_QOS_MASK) >> 1; - response->retain_flag = fixed_header->control_flags & MQTT_PUBLISH_RETAIN; - - /* make sure that remaining length is valid */ - if (mqtt_response->fixed_header.remaining_length < 4) { - return MQTT_ERROR_MALFORMED_RESPONSE; - } - - /* parse variable header */ - response->topic_name_size = __mqtt_unpack_uint16(buf); - buf += 2; - response->topic_name = buf; - buf += response->topic_name_size; - - if (response->qos_level > 0) { - response->packet_id = __mqtt_unpack_uint16(buf); - buf += 2; - } - - /* get payload */ - response->application_message = buf; - if (response->qos_level == 0) { - response->application_message_size = fixed_header->remaining_length - response->topic_name_size - 2; - } else { - response->application_message_size = fixed_header->remaining_length - response->topic_name_size - 4; - } - buf += response->application_message_size; - - /* return number of bytes consumed */ - return buf - start; -} - -/* PUBXXX */ -ssize_t mqtt_pack_pubxxx_request(uint8_t *buf, size_t bufsz, - enum MQTTControlPacketType control_type, - uint16_t packet_id) { - const uint8_t *const start = buf; - struct mqtt_fixed_header fixed_header; - ssize_t rv; - if (buf == NULL) { - return MQTT_ERROR_NULLPTR; - } - - /* pack fixed header */ - fixed_header.control_type = control_type; - if (control_type == MQTT_CONTROL_PUBREL) { - fixed_header.control_flags = 0x02; - } else { - fixed_header.control_flags = 0; - } - fixed_header.remaining_length = 2; - rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); - if (rv <= 0) { - return rv; - } - buf += rv; - bufsz -= (size_t)rv; - - if (bufsz < fixed_header.remaining_length) { - return 0; - } - - buf += __mqtt_pack_uint16(buf, packet_id); - - return buf - start; -} - -ssize_t mqtt_unpack_pubxxx_response(struct mqtt_response *mqtt_response, const uint8_t *buf) { - const uint8_t *const start = buf; - uint16_t packet_id; - - /* assert remaining length is correct */ - if (mqtt_response->fixed_header.remaining_length != 2) { - return MQTT_ERROR_MALFORMED_RESPONSE; - } - - /* parse packet_id */ - packet_id = __mqtt_unpack_uint16(buf); - buf += 2; - - if (mqtt_response->fixed_header.control_type == MQTT_CONTROL_PUBACK) { - mqtt_response->decoded.puback.packet_id = packet_id; - } else if (mqtt_response->fixed_header.control_type == MQTT_CONTROL_PUBREC) { - mqtt_response->decoded.pubrec.packet_id = packet_id; - } else if (mqtt_response->fixed_header.control_type == MQTT_CONTROL_PUBREL) { - mqtt_response->decoded.pubrel.packet_id = packet_id; - } else { - mqtt_response->decoded.pubcomp.packet_id = packet_id; - } - - return buf - start; -} - -/* SUBACK */ -ssize_t mqtt_unpack_suback_response(struct mqtt_response *mqtt_response, const uint8_t *buf) { - const uint8_t *const start = buf; - uint32_t remaining_length = mqtt_response->fixed_header.remaining_length; - - /* assert remaining length is at least 3 (for packet id and at least 1 topic) */ - if (remaining_length < 3) { - return MQTT_ERROR_MALFORMED_RESPONSE; - } - - /* unpack packet_id */ - mqtt_response->decoded.suback.packet_id = __mqtt_unpack_uint16(buf); - buf += 2; - remaining_length -= 2; - - /* unpack return codes */ - mqtt_response->decoded.suback.num_return_codes = (size_t) remaining_length; - mqtt_response->decoded.suback.return_codes = buf; - buf += remaining_length; - - return buf - start; -} - -/* SUBSCRIBE */ -ssize_t mqtt_pack_subscribe_request(uint8_t *buf, size_t bufsz, unsigned int packet_id, ...) { - va_list args; - const uint8_t *const start = buf; - ssize_t rv; - struct mqtt_fixed_header fixed_header; - unsigned int num_subs = 0; - unsigned int i; - const char *topic[MQTT_SUBSCRIBE_REQUEST_MAX_NUM_TOPICS]; - uint8_t max_qos[MQTT_SUBSCRIBE_REQUEST_MAX_NUM_TOPICS]; - - /* parse all subscriptions */ - va_start(args, packet_id); - for (;;) { - topic[num_subs] = va_arg(args, const char *); - if (topic[num_subs] == NULL) { - /* end of list */ - break; - } - - max_qos[num_subs] = (uint8_t) va_arg(args, unsigned int); - - ++num_subs; - if (num_subs >= MQTT_SUBSCRIBE_REQUEST_MAX_NUM_TOPICS) { - va_end(args); - return MQTT_ERROR_SUBSCRIBE_TOO_MANY_TOPICS; - } - } - va_end(args); - - /* build the fixed header */ - fixed_header.control_type = MQTT_CONTROL_SUBSCRIBE; - fixed_header.control_flags = 2u; - fixed_header.remaining_length = 2u; /* size of variable header */ - for (i = 0; i < num_subs; ++i) { - /* payload is topic name + max qos (1 byte) */ - fixed_header.remaining_length += __mqtt_packed_cstrlen(topic[i]) + 1; - } - - /* pack the fixed header */ - rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); - if (rv <= 0) { - return rv; - } - buf += rv; - bufsz -= (unsigned long)rv; - - /* check that the buffer has enough space */ - if (bufsz < fixed_header.remaining_length) { - return 0; - } - - - /* pack variable header */ - buf += __mqtt_pack_uint16(buf, (uint16_t)packet_id); - - - /* pack payload */ - for (i = 0; i < num_subs; ++i) { - buf += __mqtt_pack_str(buf, topic[i]); - *buf++ = max_qos[i]; - } - - return buf - start; -} - -/* UNSUBACK */ -ssize_t mqtt_unpack_unsuback_response(struct mqtt_response *mqtt_response, const uint8_t *buf) { - const uint8_t *const start = buf; - - if (mqtt_response->fixed_header.remaining_length != 2) { - return MQTT_ERROR_MALFORMED_RESPONSE; - } - - /* parse packet_id */ - mqtt_response->decoded.unsuback.packet_id = __mqtt_unpack_uint16(buf); - buf += 2; - - return buf - start; -} - -/* UNSUBSCRIBE */ -ssize_t mqtt_pack_unsubscribe_request(uint8_t *buf, size_t bufsz, unsigned int packet_id, ...) { - va_list args; - const uint8_t *const start = buf; - ssize_t rv; - struct mqtt_fixed_header fixed_header; - unsigned int num_subs = 0; - unsigned int i; - const char *topic[MQTT_UNSUBSCRIBE_REQUEST_MAX_NUM_TOPICS]; - - /* parse all subscriptions */ - va_start(args, packet_id); - for (;;) { - topic[num_subs] = va_arg(args, const char *); - if (topic[num_subs] == NULL) { - /* end of list */ - break; - } - - ++num_subs; - if (num_subs >= MQTT_UNSUBSCRIBE_REQUEST_MAX_NUM_TOPICS) { - va_end(args); - return MQTT_ERROR_UNSUBSCRIBE_TOO_MANY_TOPICS; - } - } - va_end(args); - - /* build the fixed header */ - fixed_header.control_type = MQTT_CONTROL_UNSUBSCRIBE; - fixed_header.control_flags = 2u; - fixed_header.remaining_length = 2u; /* size of variable header */ - for (i = 0; i < num_subs; ++i) { - /* payload is topic name */ - fixed_header.remaining_length += __mqtt_packed_cstrlen(topic[i]); - } - - /* pack the fixed header */ - rv = mqtt_pack_fixed_header(buf, bufsz, &fixed_header); - if (rv <= 0) { - return rv; - } - buf += rv; - bufsz -= (unsigned long)rv; - - /* check that the buffer has enough space */ - if (bufsz < fixed_header.remaining_length) { - return 0; - } - - /* pack variable header */ - buf += __mqtt_pack_uint16(buf, (uint16_t)packet_id); - - - /* pack payload */ - for (i = 0; i < num_subs; ++i) { - buf += __mqtt_pack_str(buf, topic[i]); - } - - return buf - start; -} - -/* MESSAGE QUEUE */ -void mqtt_mq_init(struct mqtt_message_queue *mq, void *buf, size_t bufsz) { - mq->mem_start = buf; - mq->mem_end = (uint8_t *)buf + bufsz; - mq->curr = (uint8_t *)buf; - mq->queue_tail = (struct mqtt_queued_message *)mq->mem_end; - mq->curr_sz = buf == NULL ? 0 : mqtt_mq_currsz(mq); -} - -struct mqtt_queued_message *mqtt_mq_register(struct mqtt_message_queue *mq, size_t nbytes) { - /* make queued message header */ - --(mq->queue_tail); - mq->queue_tail->start = mq->curr; - mq->queue_tail->size = nbytes; - mq->queue_tail->state = MQTT_QUEUED_UNSENT; - - /* move curr and recalculate curr_sz */ - mq->curr += nbytes; - mq->curr_sz = (size_t)(mqtt_mq_currsz(mq)); - - return mq->queue_tail; -} - -void mqtt_mq_clean(struct mqtt_message_queue *mq) { - struct mqtt_queued_message *new_head; - - for (new_head = mqtt_mq_get(mq, 0); new_head >= mq->queue_tail; --new_head) { - if (new_head->state != MQTT_QUEUED_COMPLETE) break; - } - - /* check if everything can be removed */ - if (new_head < mq->queue_tail) { - mq->curr = (uint8_t *)mq->mem_start; - mq->queue_tail = (struct mqtt_queued_message *)mq->mem_end; - mq->curr_sz = (size_t)(mqtt_mq_currsz(mq)); - return; - } else if (new_head == mqtt_mq_get(mq, 0)) { - /* do nothing */ - return; - } - - /* move buffered data */ - { - size_t n = (size_t)(mq->curr - new_head->start); - size_t removing = (size_t)(new_head->start - (uint8_t *) mq->mem_start); - memmove(mq->mem_start, new_head->start, n); - mq->curr = (unsigned char *)mq->mem_start + n; - - - /* move queue */ - { - ssize_t new_tail_idx = new_head - mq->queue_tail; - memmove(mqtt_mq_get(mq, new_tail_idx), mq->queue_tail, sizeof(struct mqtt_queued_message) * (size_t)((new_tail_idx + 1))); - mq->queue_tail = mqtt_mq_get(mq, new_tail_idx); - - { - /* bump back start's */ - ssize_t i = 0; - for (; i < new_tail_idx + 1; ++i) { - mqtt_mq_get(mq, i)->start -= removing; - } - } - } - } - - /* get curr_sz */ - mq->curr_sz = (size_t)(mqtt_mq_currsz(mq)); -} - -struct mqtt_queued_message *mqtt_mq_find(const struct mqtt_message_queue *mq, enum MQTTControlPacketType control_type, const uint16_t *packet_id) { - struct mqtt_queued_message *curr; - for (curr = mqtt_mq_get(mq, 0); curr >= mq->queue_tail; --curr) { - if (curr->control_type == control_type) { - if ((packet_id == NULL && curr->state != MQTT_QUEUED_COMPLETE) || - (packet_id != NULL && *packet_id == curr->packet_id)) { - return curr; - } - } - } - return NULL; -} - - -/* RESPONSE UNPACKING */ -ssize_t mqtt_unpack_response(struct mqtt_response *response, const uint8_t *buf, size_t bufsz) { - const uint8_t *const start = buf; - ssize_t rv = mqtt_unpack_fixed_header(response, buf, bufsz); - if (rv <= 0) return rv; - else buf += rv; - switch (response->fixed_header.control_type) { - case MQTT_CONTROL_CONNACK: - rv = mqtt_unpack_connack_response(response, buf); - break; - case MQTT_CONTROL_PUBLISH: - rv = mqtt_unpack_publish_response(response, buf); - break; - case MQTT_CONTROL_PUBACK: - rv = mqtt_unpack_pubxxx_response(response, buf); - break; - case MQTT_CONTROL_PUBREC: - rv = mqtt_unpack_pubxxx_response(response, buf); - break; - case MQTT_CONTROL_PUBREL: - rv = mqtt_unpack_pubxxx_response(response, buf); - break; - case MQTT_CONTROL_PUBCOMP: - rv = mqtt_unpack_pubxxx_response(response, buf); - break; - case MQTT_CONTROL_SUBACK: - rv = mqtt_unpack_suback_response(response, buf); - break; - case MQTT_CONTROL_UNSUBACK: - rv = mqtt_unpack_unsuback_response(response, buf); - break; - case MQTT_CONTROL_PINGRESP: - return rv; - default: - return MQTT_ERROR_RESPONSE_INVALID_CONTROL_TYPE; - } - - if (rv < 0) return rv; - buf += rv; - return buf - start; -} - -/* EXTRA DETAILS */ -ssize_t __mqtt_pack_uint16(uint8_t *buf, uint16_t integer) { - uint16_t integer_htons = MQTT_PAL_HTONS(integer); - memcpy(buf, &integer_htons, 2uL); - return 2; -} - -uint16_t __mqtt_unpack_uint16(const uint8_t *buf) { - uint16_t integer_htons; - memcpy(&integer_htons, buf, 2uL); - return MQTT_PAL_NTOHS(integer_htons); -} - -ssize_t __mqtt_pack_str(uint8_t *buf, const char *str) { - uint16_t length = (uint16_t)strlen(str); - int i = 0; - /* pack string length */ - buf += __mqtt_pack_uint16(buf, length); - - /* pack string */ - for (; i < length; ++i) { - *(buf++) = (uint8_t)str[i]; - } - - /* return number of bytes consumed */ - return length + 2; -} - -static const char *const MQTT_ERRORS_STR[] = { - "MQTT_UNKNOWN_ERROR", - __ALL_MQTT_ERRORS(GENERATE_STRING) -}; - -const char *mqtt_error_str(enum MQTTErrors error) { - int offset = error - MQTT_ERROR_UNKNOWN; - if (offset >= 0) { - return MQTT_ERRORS_STR[offset]; - } else if (error == 0) { - return "MQTT_ERROR: Buffer too small."; - } else if (error > 0) { - return "MQTT_OK"; - } else { - return MQTT_ERRORS_STR[0]; - } -} - -/** @endcond*/ diff --git a/client/deps/mqtt/mqtt.h b/client/deps/mqtt/mqtt.h deleted file mode 100644 index d3467cd27..000000000 --- a/client/deps/mqtt/mqtt.h +++ /dev/null @@ -1,1640 +0,0 @@ -#if !defined(__MQTT_H__) -#define __MQTT_H__ - -/* -MIT License - -Copyright(c) 2018 Liam Bindle - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#if defined(__cplusplus) -extern "C" { -#endif - -// Users can override mqtt_pal.h with their own configuration by defining -// MQTTC_PAL_FILE as a header file to include (-DMQTTC_PAL_FILE=my_mqtt_pal.h). -// -// If MQTTC_PAL_FILE is used, none of the default utils will be emitted and must be -// provided by the config file. To start, I would suggest copying mqtt_pal.h -// and modifying as needed. -#if defined(MQTTC_PAL_FILE) -#define MQTTC_STR2(x) #x -#define MQTTC_STR(x) MQTTC_STR2(x) -#include MQTTC_STR(MQTTC_PAL_FILE) -#else -#include "mqtt_pal.h" -#endif /* MQTT_PAL_FILE */ - -/** - * @file - * @brief Declares all the MQTT-C functions and datastructures. - * - * @note You should \#include . - * - * @example simple_publisher.c - * A simple program to that publishes the current time whenever ENTER is pressed. - * - * Usage: - * \code{.sh} - * ./bin/simple_publisher [address [port [topic]]] - * \endcode - * - * Where \c address is the address of the MQTT broker, \c port is the port number the - * MQTT broker is running on, and \c topic is the name of the topic to publish with. Note - * that all these arguments are optional and the defaults are \c address = \c "test.mosquitto.org", - * \c port = \c "1883", and \c topic = "datetime". - * - * @example simple_subscriber.c - * A simple program that subscribes to a single topic and prints all updates that are received. - * - * Usage: - * \code{.sh} - * ./bin/simple_subscriber [address [port [topic]]] - * \endcode - * - * Where \c address is the address of the MQTT broker, \c port is the port number the - * MQTT broker is running on, and \c topic is the name of the topic subscribe to. Note - * that all these arguments are optional and the defaults are \c address = \c "test.mosquitto.org", - * \c port = \c "1883", and \c topic = "datetime". - * - * @example reconnect_subscriber.c - * Same program as \ref simple_subscriber.c, but using the automatic reconnect functionality. - * - * @example bio_publisher.c - * Same program as \ref simple_publisher.c, but uses a unencrypted BIO socket. - * - * @example openssl_publisher.c - * Same program as \ref simple_publisher.c, but over an encrypted connection using OpenSSL. - * - * Usage: - * \code{.sh} - * ./bin/openssl_publisher ca_file [address [port [topic]]] - * \endcode - * - * - * @defgroup api API - * @brief Documentation of everything you need to know to use the MQTT-C client. - * - * This module contains everything you need to know to use MQTT-C in your application. - * For usage examples see: - * - @ref simple_publisher.c - * - @ref simple_subscriber.c - * - @ref reconnect_subscriber.c - * - @ref bio_publisher.c - * - @ref openssl_publisher.c - * - * @note MQTT-C can be used in both single-threaded and multi-threaded applications. All - * the functions in \ref api are thread-safe. - * - * @defgroup packers Control Packet Serialization - * @brief Developer documentation of the functions and datastructures used for serializing MQTT - * control packets. - * - * @defgroup unpackers Control Packet Deserialization - * @brief Developer documentation of the functions and datastructures used for deserializing MQTT - * control packets. - * - * @defgroup details Utilities - * @brief Developer documentation for the utilities used to implement the MQTT-C client. - * - * @note To deserialize a packet from a buffer use \ref mqtt_unpack_response (it's the only - * function you need). - */ - - -/** - * @brief An enumeration of the MQTT control packet types. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: MQTT Control Packet Types - * - */ -enum MQTTControlPacketType { - MQTT_CONTROL_CONNECT = 1u, - MQTT_CONTROL_CONNACK = 2u, - MQTT_CONTROL_PUBLISH = 3u, - MQTT_CONTROL_PUBACK = 4u, - MQTT_CONTROL_PUBREC = 5u, - MQTT_CONTROL_PUBREL = 6u, - MQTT_CONTROL_PUBCOMP = 7u, - MQTT_CONTROL_SUBSCRIBE = 8u, - MQTT_CONTROL_SUBACK = 9u, - MQTT_CONTROL_UNSUBSCRIBE = 10u, - MQTT_CONTROL_UNSUBACK = 11u, - MQTT_CONTROL_PINGREQ = 12u, - MQTT_CONTROL_PINGRESP = 13u, - MQTT_CONTROL_DISCONNECT = 14u -}; - -/** - * @brief A structure that I will use to keep track of some data needed - * to setup the connection to the broker. - * - * An instance of this struct will be created in my \c main(). Then, whenever - * \ref reconnect_client is called, this instance will be passed. - */ -struct reconnect_state_t { - const char *hostname; - const char *port; - const char *topic; - uint8_t *sendbuf; - size_t sendbufsz; - uint8_t *recvbuf; - size_t recvbufsz; -}; - -/** - * @brief The fixed header of an MQTT control packet. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: Fixed Header - * - */ -struct mqtt_fixed_header { - /** The type of packet. */ - enum MQTTControlPacketType control_type; - - /** The packets control flags.*/ - uint32_t control_flags: 4; - - /** The remaining size of the packet in bytes (i.e. the size of variable header and payload).*/ - uint32_t remaining_length; -}; - -/** - * @brief The protocol identifier for MQTT v3.1.1. - * @ingroup packers - * - * @see - * MQTT v3.1.1: CONNECT Variable Header. - * - */ -#define MQTT_PROTOCOL_LEVEL 0x04 - -/** - * @brief A macro used to declare the enum MQTTErrors and associated - * error messages (the members of the num) at the same time. - */ -#define __ALL_MQTT_ERRORS(MQTT_ERROR) \ - MQTT_ERROR(MQTT_ERROR_NULLPTR) \ - MQTT_ERROR(MQTT_ERROR_CONTROL_FORBIDDEN_TYPE) \ - MQTT_ERROR(MQTT_ERROR_CONTROL_INVALID_FLAGS) \ - MQTT_ERROR(MQTT_ERROR_CONTROL_WRONG_TYPE) \ - MQTT_ERROR(MQTT_ERROR_CONNECT_CLIENT_ID_REFUSED) \ - MQTT_ERROR(MQTT_ERROR_CONNECT_NULL_WILL_MESSAGE) \ - MQTT_ERROR(MQTT_ERROR_CONNECT_FORBIDDEN_WILL_QOS) \ - MQTT_ERROR(MQTT_ERROR_CONNACK_FORBIDDEN_FLAGS) \ - MQTT_ERROR(MQTT_ERROR_CONNACK_FORBIDDEN_CODE) \ - MQTT_ERROR(MQTT_ERROR_PUBLISH_FORBIDDEN_QOS) \ - MQTT_ERROR(MQTT_ERROR_SUBSCRIBE_TOO_MANY_TOPICS) \ - MQTT_ERROR(MQTT_ERROR_MALFORMED_RESPONSE) \ - MQTT_ERROR(MQTT_ERROR_UNSUBSCRIBE_TOO_MANY_TOPICS) \ - MQTT_ERROR(MQTT_ERROR_RESPONSE_INVALID_CONTROL_TYPE) \ - MQTT_ERROR(MQTT_ERROR_CONNECT_NOT_CALLED) \ - MQTT_ERROR(MQTT_ERROR_SEND_BUFFER_IS_FULL) \ - MQTT_ERROR(MQTT_ERROR_SOCKET_ERROR) \ - MQTT_ERROR(MQTT_ERROR_MALFORMED_REQUEST) \ - MQTT_ERROR(MQTT_ERROR_RECV_BUFFER_TOO_SMALL) \ - MQTT_ERROR(MQTT_ERROR_ACK_OF_UNKNOWN) \ - MQTT_ERROR(MQTT_ERROR_NOT_IMPLEMENTED) \ - MQTT_ERROR(MQTT_ERROR_CONNECTION_REFUSED) \ - MQTT_ERROR(MQTT_ERROR_SUBSCRIBE_FAILED) \ - MQTT_ERROR(MQTT_ERROR_CONNECTION_CLOSED) \ - MQTT_ERROR(MQTT_ERROR_INITIAL_RECONNECT) \ - MQTT_ERROR(MQTT_ERROR_INVALID_REMAINING_LENGTH) \ - MQTT_ERROR(MQTT_ERROR_CLEAN_SESSION_IS_REQUIRED) \ - MQTT_ERROR(MQTT_ERROR_RECONNECT_FAILED) \ - MQTT_ERROR(MQTT_ERROR_RECONNECTING) - -/* todo: add more connection refused errors */ - -/** - * @brief A macro used to generate the enum MQTTErrors from - * \ref __ALL_MQTT_ERRORS - * @see __ALL_MQTT_ERRORS -*/ -#define GENERATE_ENUM(ENUM) ENUM, - -/** - * @brief A macro used to generate the error messages associated with - * MQTTErrors from \ref __ALL_MQTT_ERRORS - * @see __ALL_MQTT_ERRORS -*/ -#define GENERATE_STRING(STRING) #STRING, - - -/** - * @brief An enumeration of error codes. Error messages can be retrieved by calling \ref mqtt_error_str. - * @ingroup api - * - * @see mqtt_error_str - */ -enum MQTTErrors { - MQTT_ERROR_UNKNOWN = INT_MIN, - __ALL_MQTT_ERRORS(GENERATE_ENUM) - MQTT_OK = 1 -}; - -/** - * @brief Returns an error message for error code, \p error. - * @ingroup api - * - * @param[in] error the error code. - * - * @returns The associated error message. - */ -const char *mqtt_error_str(enum MQTTErrors error); - -/** - * @brief Pack a MQTT 16 bit integer, given a native 16 bit integer . - * - * @param[out] buf the buffer that the MQTT integer will be written to. - * @param[in] integer the native integer to be written to \p buf. - * - * @warning This function provides no error checking. - * - * @returns 2 -*/ -ssize_t __mqtt_pack_uint16(uint8_t *buf, uint16_t integer); - -/** - * @brief Unpack a MQTT 16 bit integer to a native 16 bit integer. - * - * @param[in] buf the buffer that the MQTT integer will be read from. - * - * @warning This function provides no error checking and does not modify \p buf. - * - * @returns The native integer -*/ -uint16_t __mqtt_unpack_uint16(const uint8_t *buf); - -/** - * @brief Pack a MQTT string, given a c-string \p str. - * - * @param[out] buf the buffer that the MQTT string will be written to. - * @param[in] str the c-string to be written to \p buf. - * - * @warning This function provides no error checking. - * - * @returns strlen(str) + 2 -*/ -ssize_t __mqtt_pack_str(uint8_t *buf, const char *str); - -/** @brief A macro to get the MQTT string length from a c-string. */ -#define __mqtt_packed_cstrlen(x) (2 + (unsigned int)strlen(x)) - -/* RESPONSES */ - -/** - * @brief An enumeration of the return codes returned in a CONNACK packet. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: CONNACK return codes. - * - */ -enum MQTTConnackReturnCode { - MQTT_CONNACK_ACCEPTED = 0u, - MQTT_CONNACK_REFUSED_PROTOCOL_VERSION = 1u, - MQTT_CONNACK_REFUSED_IDENTIFIER_REJECTED = 2u, - MQTT_CONNACK_REFUSED_SERVER_UNAVAILABLE = 3u, - MQTT_CONNACK_REFUSED_BAD_USER_NAME_OR_PASSWORD = 4u, - MQTT_CONNACK_REFUSED_NOT_AUTHORIZED = 5u -}; - -/** - * @brief A connection response datastructure. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: CONNACK - Acknowledgement connection response. - * - */ -struct mqtt_response_connack { - /** - * @brief Allows client and broker to check if they have a consistent view about whether there is - * already a stored session state. - */ - uint8_t session_present_flag; - - /** - * @brief The return code of the connection request. - * - * @see MQTTConnackReturnCode - */ - enum MQTTConnackReturnCode return_code; -}; - -/** - * @brief A publish packet received from the broker. - * @ingroup unpackers - * - * A publish packet is received from the broker when a client publishes to a topic that the - * \em {local client} is subscribed to. - * - * @see - * MQTT v3.1.1: PUBLISH - Publish Message. - * - */ -struct mqtt_response_publish { - /** - * @brief The DUP flag. DUP flag is 0 if its the first attempt to send this publish packet. A DUP flag - * of 1 means that this might be a re-delivery of the packet. - */ - uint8_t dup_flag; - - /** - * @brief The quality of service level. - * - * @see - * MQTT v3.1.1: QoS Definitions - * - */ - uint8_t qos_level; - - /** @brief The retain flag of this publish message. */ - uint8_t retain_flag; - - /** @brief Size of the topic name (number of characters). */ - uint16_t topic_name_size; - - /** - * @brief The topic name. - * @note topic_name is not null terminated. Therefore topic_name_size must be used to get the - * string length. - */ - const void *topic_name; - - /** @brief The publish message's packet ID. */ - uint16_t packet_id; - - /** @brief The publish message's application message.*/ - const void *application_message; - - /** @brief The size of the application message in bytes. */ - size_t application_message_size; -}; - -/** - * @brief A publish acknowledgement for messages that were published with QoS level 1. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: PUBACK - Publish Acknowledgement. - * - * - */ -struct mqtt_response_puback { - /** @brief The published messages packet ID. */ - uint16_t packet_id; -}; - -/** - * @brief The response packet to a PUBLISH packet with QoS level 2. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: PUBREC - Publish Received. - * - * - */ -struct mqtt_response_pubrec { - /** @brief The published messages packet ID. */ - uint16_t packet_id; -}; - -/** - * @brief The response to a PUBREC packet. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: PUBREL - Publish Release. - * - * - */ -struct mqtt_response_pubrel { - /** @brief The published messages packet ID. */ - uint16_t packet_id; -}; - -/** - * @brief The response to a PUBREL packet. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: PUBCOMP - Publish Complete. - * - * - */ -struct mqtt_response_pubcomp { - /** T@brief he published messages packet ID. */ - uint16_t packet_id; -}; - -/** - * @brief An enumeration of subscription acknowledgement return codes. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: SUBACK Return Codes. - * - */ -enum MQTTSubackReturnCodes { - MQTT_SUBACK_SUCCESS_MAX_QOS_0 = 0u, - MQTT_SUBACK_SUCCESS_MAX_QOS_1 = 1u, - MQTT_SUBACK_SUCCESS_MAX_QOS_2 = 2u, - MQTT_SUBACK_FAILURE = 128u -}; - -/** - * @brief The response to a subscription request. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: SUBACK - Subscription Acknowledgement. - * - */ -struct mqtt_response_suback { - /** @brief The published messages packet ID. */ - uint16_t packet_id; - - /** - * Array of return codes corresponding to the requested subscribe topics. - * - * @see MQTTSubackReturnCodes - */ - const uint8_t *return_codes; - - /** The number of return codes. */ - size_t num_return_codes; -}; - -/** - * @brief The brokers response to a UNSUBSCRIBE request. - * @ingroup unpackers - * - * @see - * MQTT v3.1.1: UNSUBACK - Unsubscribe Acknowledgement. - * - */ -struct mqtt_response_unsuback { - /** @brief The published messages packet ID. */ - uint16_t packet_id; -}; - -/** - * @brief The response to a ping request. - * @ingroup unpackers - * - * @note This response contains no members. - * - * @see - * MQTT v3.1.1: PINGRESP - Ping Response. - * - */ -struct mqtt_response_pingresp { - int dummy; -}; - -/** - * @brief A struct used to deserialize/interpret an incoming packet from the broker. - * @ingroup unpackers - */ -struct mqtt_response { - /** @brief The mqtt_fixed_header of the deserialized packet. */ - struct mqtt_fixed_header fixed_header; - - /** - * @brief A union of the possible responses from the broker. - * - * @note The fixed_header contains the control type. This control type corresponds to the - * member of this union that should be accessed. For example if - * fixed_header#control_type == \c MQTT_CONTROL_PUBLISH then - * decoded#publish should be accessed. - */ - union { - struct mqtt_response_connack connack; - struct mqtt_response_publish publish; - struct mqtt_response_puback puback; - struct mqtt_response_pubrec pubrec; - struct mqtt_response_pubrel pubrel; - struct mqtt_response_pubcomp pubcomp; - struct mqtt_response_suback suback; - struct mqtt_response_unsuback unsuback; - struct mqtt_response_pingresp pingresp; - } decoded; -}; - -/** - * @brief Deserialize the contents of \p buf into an mqtt_fixed_header object. - * @ingroup unpackers - * - * @note This function performs complete error checking and a positive return value - * means the entire mqtt_response can be deserialized from \p buf. - * - * @param[out] response the response who's \ref mqtt_response.fixed_header will be initialized. - * @param[in] buf the buffer. - * @param[in] bufsz the total number of bytes in the buffer. - * - * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough - * bytes to parse the packet, or a negative value if there was a protocol violation. - */ -ssize_t mqtt_unpack_fixed_header(struct mqtt_response *response, const uint8_t *buf, size_t bufsz); - -/** - * @brief Deserialize a CONNACK response from \p buf. - * @ingroup unpackers - * - * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the control packet type - * must be \c MQTT_CONTROL_CONNACK. - * - * @param[out] mqtt_response the mqtt_response that will be initialized. - * @param[in] buf the buffer that contains the variable header and payload of the packet. The - * first byte of \p buf should be the first byte of the variable header. - * - * @relates mqtt_response_connack - * - * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough - * bytes to parse the packet, or a negative value if there was a protocol violation. - */ -ssize_t mqtt_unpack_connack_response(struct mqtt_response *mqtt_response, const uint8_t *buf); - -/** - * @brief Deserialize a publish response from \p buf. - * @ingroup unpackers - * - * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the mqtt_response must - * have a control type of \c MQTT_CONTROL_PUBLISH. - * - * @param[out] mqtt_response the response that is initialized from the contents of \p buf. - * @param[in] buf the buffer with the incoming data. - * - * @relates mqtt_response_publish - * - * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough - * bytes to parse the packet, or a negative value if there was a protocol violation. - */ -ssize_t mqtt_unpack_publish_response(struct mqtt_response *mqtt_response, const uint8_t *buf); - -/** - * @brief Deserialize a PUBACK/PUBREC/PUBREL/PUBCOMP packet from \p buf. - * @ingroup unpackers - * - * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the mqtt_response must - * have a control type of \c MQTT_CONTROL_PUBACK, \c MQTT_CONTROL_PUBREC, \c MQTT_CONTROL_PUBREL - * or \c MQTT_CONTROL_PUBCOMP. - * - * @param[out] mqtt_response the response that is initialized from the contents of \p buf. - * @param[in] buf the buffer with the incoming data. - * - * @relates mqtt_response_puback mqtt_response_pubrec mqtt_response_pubrel mqtt_response_pubcomp - * - * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough - * bytes to parse the packet, or a negative value if there was a protocol violation. - */ -ssize_t mqtt_unpack_pubxxx_response(struct mqtt_response *mqtt_response, const uint8_t *buf); - -/** - * @brief Deserialize a SUBACK packet from \p buf. - * @ingroup unpacker - * - * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the mqtt_response must - * have a control type of \c MQTT_CONTROL_SUBACK. - * - * @param[out] mqtt_response the response that is initialized from the contents of \p buf. - * @param[in] buf the buffer with the incoming data. - * - * @relates mqtt_response_suback - * - * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough - * bytes to parse the packet, or a negative value if there was a protocol violation. - */ -ssize_t mqtt_unpack_suback_response(struct mqtt_response *mqtt_response, const uint8_t *buf); - -/** - * @brief Deserialize an UNSUBACK packet from \p buf. - * @ingroup unpacker - * - * @pre \ref mqtt_unpack_fixed_header must have returned a positive value and the mqtt_response must - * have a control type of \c MQTT_CONTROL_UNSUBACK. - * - * @param[out] mqtt_response the response that is initialized from the contents of \p buf. - * @param[in] buf the buffer with the incoming data. - * - * @relates mqtt_response_unsuback - * - * @returns The number of bytes that were consumed, or 0 if the buffer does not contain enough - * bytes to parse the packet, or a negative value if there was a protocol violation. - */ -ssize_t mqtt_unpack_unsuback_response(struct mqtt_response *mqtt_response, const uint8_t *buf); - -/** - * @brief Deserialize a packet from the broker. - * @ingroup unpackers - * - * @param[out] response the mqtt_response that will be initialize from \p buf. - * @param[in] buf the incoming data buffer. - * @param[in] bufsz the number of bytes available in the buffer. - * - * @relates mqtt_response - * - * @returns The number of bytes consumed on success, zero \p buf does not contain enough bytes - * to deserialize the packet, a negative value if a protocol violation was encountered. - */ -ssize_t mqtt_unpack_response(struct mqtt_response *response, const uint8_t *buf, size_t bufsz); - -/* REQUESTS */ - -/** -* @brief Serialize an mqtt_fixed_header and write it to \p buf. -* @ingroup packers -* -* @note This function performs complete error checking and a positive return value -* guarantees the entire packet will fit into the given buffer. -* -* @param[out] buf the buffer to write to. -* @param[in] bufsz the maximum number of bytes that can be put in to \p buf. -* @param[in] fixed_header the fixed header that will be serialized. -* -* @returns The number of bytes written to \p buf, or 0 if \p buf is too small, or a -* negative value if there was a protocol violation. -*/ -ssize_t mqtt_pack_fixed_header(uint8_t *buf, size_t bufsz, const struct mqtt_fixed_header *fixed_header); - -/** - * @brief An enumeration of CONNECT packet flags. - * @ingroup packers - * - * @see - * MQTT v3.1.1: CONNECT Variable Header. - * - */ -enum MQTTConnectFlags { - MQTT_CONNECT_RESERVED = 1u, - MQTT_CONNECT_CLEAN_SESSION = 2u, - MQTT_CONNECT_WILL_FLAG = 4u, - MQTT_CONNECT_WILL_QOS_0 = (0u & 0x03) << 3, - MQTT_CONNECT_WILL_QOS_1 = (1u & 0x03) << 3, - MQTT_CONNECT_WILL_QOS_2 = (2u & 0x03) << 3, - MQTT_CONNECT_WILL_RETAIN = 32u, - MQTT_CONNECT_PASSWORD = 64u, - MQTT_CONNECT_USER_NAME = 128u -}; - -/** - * @brief Serialize a connection request into a buffer. - * @ingroup packers - * - * @param[out] buf the buffer to pack the connection request packet into. - * @param[in] bufsz the number of bytes left in \p buf. - * @param[in] client_id the ID that identifies the local client. \p client_id can be NULL or an empty - * string for Anonymous clients. - * @param[in] will_topic the topic under which the local client's will message will be published. - * Set to \c NULL for no will message. If \p will_topic is not \c NULL a - * \p will_message must also be provided. - * @param[in] will_message the will message to be published upon a unsuccessful disconnection of - * the local client. Set to \c NULL if \p will_topic is \c NULL. - * \p will_message must \em not be \c NULL if \p will_topic is not - * \c NULL. - * @param[in] will_message_size The size of \p will_message in bytes. - * @param[in] user_name the username to be used to connect to the broker with. Set to \c NULL if - * no username is required. - * @param[in] password the password to be used to connect to the broker with. Set to \c NULL if - * no password is required. - * @param[in] connect_flags additional MQTTConnectFlags to be set. The only flags that need to be - * set manually are \c MQTT_CONNECT_CLEAN_SESSION, - * \c MQTT_CONNECT_WILL_QOS_X (for \c X ∈ {0, 1, 2}), and - * \c MQTT_CONNECT_WILL_RETAIN. Set to 0 if no additional flags are - * required. - * @param[in] keep_alive the keep alive time in seconds. It is the responsibility of the clinet - * to ensure packets are sent to the server \em {at least} this frequently. - * - * @note If there is a \p will_topic and no additional \p connect_flags are given, then by - * default \p will_message will be published at QoS level 0. - * - * @see - * MQTT v3.1.1: CONNECT - Client Requests a Connection to a Server. - * - * - * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the CONNECT - * packet, a negative value if there was a protocol violation. - */ -ssize_t mqtt_pack_connection_request(uint8_t *buf, size_t bufsz, - const char *client_id, - const char *will_topic, - const void *will_message, - size_t will_message_size, - const char *user_name, - const char *password, - uint8_t connect_flags, - uint16_t keep_alive); - -/** - * @brief An enumeration of the PUBLISH flags. - * @ingroup packers - * - * @see - * MQTT v3.1.1: PUBLISH - Publish Message. - * - */ -enum MQTTPublishFlags { - MQTT_PUBLISH_DUP = 8u, - MQTT_PUBLISH_QOS_0 = ((0u << 1) & 0x06), - MQTT_PUBLISH_QOS_1 = ((1u << 1) & 0x06), - MQTT_PUBLISH_QOS_2 = ((2u << 1) & 0x06), - MQTT_PUBLISH_QOS_MASK = ((3u << 1) & 0x06), - MQTT_PUBLISH_RETAIN = 0x01 -}; - -/** - * @brief Serialize a PUBLISH request and put it in \p buf. - * @ingroup packers - * - * @param[out] buf the buffer to put the PUBLISH packet in. - * @param[in] bufsz the maximum number of bytes that can be put into \p buf. - * @param[in] topic_name the topic to publish \p application_message under. - * @param[in] packet_id this packets packet ID. - * @param[in] application_message the application message to be published. - * @param[in] application_message_size the size of \p application_message in bytes. - * @param[in] publish_flags The flags to publish \p application_message with. These include - * the \c MQTT_PUBLISH_DUP flag, \c MQTT_PUBLISH_QOS_X (\c X ∈ - * {0, 1, 2}), and \c MQTT_PUBLISH_RETAIN flag. - * - * @note The default QoS is level 0. - * - * @see - * MQTT v3.1.1: PUBLISH - Publish Message. - * - * - * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the PUBLISH - * packet, a negative value if there was a protocol violation. - */ -ssize_t mqtt_pack_publish_request(uint8_t *buf, size_t bufsz, - const char *topic_name, - uint16_t packet_id, - const void *application_message, - size_t application_message_size, - uint8_t publish_flags); - -/** - * @brief Serialize a PUBACK, PUBREC, PUBREL, or PUBCOMP packet and put it in \p buf. - * @ingroup packers - * - * @param[out] buf the buffer to put the PUBXXX packet in. - * @param[in] bufsz the maximum number of bytes that can be put into \p buf. - * @param[in] control_type the type of packet. Must be one of: \c MQTT_CONTROL_PUBACK, - * \c MQTT_CONTROL_PUBREC, \c MQTT_CONTROL_PUBREL, - * or \c MQTT_CONTROL_PUBCOMP. - * @param[in] packet_id the packet ID of the packet being acknowledged. - * - * - * @see - * MQTT v3.1.1: PUBACK - Publish Acknowledgement. - * - * @see - * MQTT v3.1.1: PUBREC - Publish Received. - * - * @see - * MQTT v3.1.1: PUBREL - Publish Released. - * - * @see - * MQTT v3.1.1: PUBCOMP - Publish Complete. - * - * - * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the PUBXXX - * packet, a negative value if there was a protocol violation. - */ -ssize_t mqtt_pack_pubxxx_request(uint8_t *buf, size_t bufsz, - enum MQTTControlPacketType control_type, - uint16_t packet_id); - -/** - * @brief The maximum number topics that can be subscribed to in a single call to - * mqtt_pack_subscribe_request. - * @ingroup packers - * - * @see mqtt_pack_subscribe_request - */ -#define MQTT_SUBSCRIBE_REQUEST_MAX_NUM_TOPICS 8 - -/** - * @brief Serialize a SUBSCRIBE packet and put it in \p buf. - * @ingroup packers - * - * @param[out] buf the buffer to put the SUBSCRIBE packet in. - * @param[in] bufsz the maximum number of bytes that can be put into \p buf. - * @param[in] packet_id the packet ID to be used. - * @param[in] ... \c NULL terminated list of (\c {const char *topic_name}, \c {int max_qos_level}) - * pairs. - * - * @note The variadic arguments, \p ..., \em must be followed by a \c NULL. For example: - * @code - * ssize_t n = mqtt_pack_subscribe_request(buf, bufsz, 1234, "topic_1", 0, "topic_2", 2, NULL); - * @endcode - * - * @see - * MQTT v3.1.1: SUBSCRIBE - Subscribe to Topics. - * - * - * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the SUBSCRIBE - * packet, a negative value if there was a protocol violation. - */ -ssize_t mqtt_pack_subscribe_request(uint8_t *buf, size_t bufsz, - unsigned int packet_id, - ...); /* null terminated */ - -/** - * @brief The maximum number topics that can be subscribed to in a single call to - * mqtt_pack_unsubscribe_request. - * @ingroup packers - * - * @see mqtt_pack_unsubscribe_request - */ -#define MQTT_UNSUBSCRIBE_REQUEST_MAX_NUM_TOPICS 8 - -/** - * @brief Serialize a UNSUBSCRIBE packet and put it in \p buf. - * @ingroup packers - * - * @param[out] buf the buffer to put the UNSUBSCRIBE packet in. - * @param[in] bufsz the maximum number of bytes that can be put into \p buf. - * @param[in] packet_id the packet ID to be used. - * @param[in] ... \c NULL terminated list of \c {const char *topic_name}'s to unsubscribe from. - * - * @note The variadic arguments, \p ..., \em must be followed by a \c NULL. For example: - * @code - * ssize_t n = mqtt_pack_unsubscribe_request(buf, bufsz, 4321, "topic_1", "topic_2", NULL); - * @endcode - * - * @see - * MQTT v3.1.1: UNSUBSCRIBE - Unsubscribe from Topics. - * - * - * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the UNSUBSCRIBE - * packet, a negative value if there was a protocol violation. - */ -ssize_t mqtt_pack_unsubscribe_request(uint8_t *buf, size_t bufsz, - unsigned int packet_id, - ...); /* null terminated */ - -/** - * @brief Serialize a PINGREQ and put it into \p buf. - * @ingroup packers - * - * @param[out] buf the buffer to put the PINGREQ packet in. - * @param[in] bufsz the maximum number of bytes that can be put into \p buf. - * - * @see - * MQTT v3.1.1: PINGREQ - Ping Request. - * - * - * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the PINGREQ - * packet, a negative value if there was a protocol violation. - */ -ssize_t mqtt_pack_ping_request(uint8_t *buf, size_t bufsz); - -/** - * @brief Serialize a DISCONNECT and put it into \p buf. - * @ingroup packers - * - * @param[out] buf the buffer to put the DISCONNECT packet in. - * @param[in] bufsz the maximum number of bytes that can be put into \p buf. - * - * @see - * MQTT v3.1.1: DISCONNECT - Disconnect Notification. - * - * - * @returns The number of bytes put into \p buf, 0 if \p buf is too small to fit the DISCONNECT - * packet, a negative value if there was a protocol violation. - */ -ssize_t mqtt_pack_disconnect(uint8_t *buf, size_t bufsz); - - -/** - * @brief An enumeration of queued message states. - * @ingroup details - */ -enum MQTTQueuedMessageState { - MQTT_QUEUED_UNSENT, - MQTT_QUEUED_AWAITING_ACK, - MQTT_QUEUED_COMPLETE -}; - -/** - * @brief A message in a mqtt_message_queue. - * @ingroup details - */ -struct mqtt_queued_message { - /** @brief A pointer to the start of the message. */ - uint8_t *start; - - /** @brief The number of bytes in the message. */ - size_t size; - - - /** @brief The state of the message. */ - enum MQTTQueuedMessageState state; - - /** - * @brief The time at which the message was sent.. - * - * @note A timeout will only occur if the message is in - * the MQTT_QUEUED_AWAITING_ACK \c state. - */ - mqtt_pal_time_t time_sent; - - /** - * @brief The control type of the message. - */ - enum MQTTControlPacketType control_type; - - /** - * @brief The packet id of the message. - * - * @note This field is only used if the associate \c control_type has a - * \c packet_id field. - */ - uint16_t packet_id; -}; - -/** - * @brief A message queue. - * @ingroup details - * - * @note This struct is used internally to manage sending messages. - * @note The only members the user should use are \c curr and \c curr_sz. - */ -struct mqtt_message_queue { - /** - * @brief The start of the message queue's memory block. - * - * @warning This member should \em not be manually changed. - */ - void *mem_start; - - /** @brief The end of the message queue's memory block. */ - void *mem_end; - - /** - * @brief A pointer to the position in the buffer you can pack bytes at. - * - * @note Immediately after packing bytes at \c curr you \em must call - * mqtt_mq_register. - */ - uint8_t *curr; - - /** - * @brief The number of bytes that can be written to \c curr. - * - * @note curr_sz will decrease by more than the number of bytes you write to - * \c curr. This is because the mqtt_queued_message structs share the - * same memory (and thus, a mqtt_queued_message must be allocated in - * the message queue's memory whenever a new message is registered). - */ - size_t curr_sz; - - /** - * @brief The tail of the array of mqtt_queued_messages's. - * - * @note This member should not be used manually. - */ - struct mqtt_queued_message *queue_tail; -}; - -/** - * @brief Initialize a message queue. - * @ingroup details - * - * @param[out] mq The message queue to initialize. - * @param[in] buf The buffer for this message queue. - * @param[in] bufsz The number of bytes in the buffer. - * - * @relates mqtt_message_queue - */ -void mqtt_mq_init(struct mqtt_message_queue *mq, void *buf, size_t bufsz); - -/** - * @brief Clear as many messages from the front of the queue as possible. - * @ingroup details - * - * @note Calls to this function are the \em only way to remove messages from the queue. - * - * @param mq The message queue. - * - * @relates mqtt_message_queue - */ -void mqtt_mq_clean(struct mqtt_message_queue *mq); - -/** - * @brief Register a message that was just added to the buffer. - * @ingroup details - * - * @note This function should be called immediately following a call to a packer function - * that returned a positive value. The positive value (number of bytes packed) should - * be passed to this function. - * - * @param mq The message queue. - * @param[in] nbytes The number of bytes that were just packed. - * - * @note This function will step mqtt_message_queue::curr and update mqtt_message_queue::curr_sz. - * @relates mqtt_message_queue - * - * @returns The newly added struct mqtt_queued_message. - */ -struct mqtt_queued_message *mqtt_mq_register(struct mqtt_message_queue *mq, size_t nbytes); - -/** - * @brief Find a message in the message queue. - * @ingroup details - * - * @param mq The message queue. - * @param[in] control_type The control type of the message you want to find. - * @param[in] packet_id The packet ID of the message you want to find. Set to \c NULL if you - * don't want to specify a packet ID. - * - * @relates mqtt_message_queue - * @returns The found message. \c NULL if the message was not found. - */ -struct mqtt_queued_message *mqtt_mq_find(const struct mqtt_message_queue *mq, enum MQTTControlPacketType control_type, const uint16_t *packet_id); - -/** - * @brief Returns the mqtt_queued_message at \p index. - * @ingroup details - * - * @param mq_ptr A pointer to the message queue. - * @param index The index of the message. - * - * @returns The mqtt_queued_message at \p index. - */ -#define mqtt_mq_get(mq_ptr, index) (((struct mqtt_queued_message*) ((mq_ptr)->mem_end)) - 1 - index) - -/** - * @brief Returns the number of messages in the message queue, \p mq_ptr. - * @ingroup details - */ -#define mqtt_mq_length(mq_ptr) (((struct mqtt_queued_message*) ((mq_ptr)->mem_end)) - (mq_ptr)->queue_tail) - -/** - * @brief Used internally to recalculate the \c curr_sz. - * @ingroup details - */ -#define mqtt_mq_currsz(mq_ptr) (((mq_ptr)->curr >= (uint8_t*) ((mq_ptr)->queue_tail - 1)) ? 0 : ((uint8_t*) ((mq_ptr)->queue_tail - 1)) - (mq_ptr)->curr) - -/* CLIENT */ - -/** - * @brief An MQTT client. - * @ingroup details - * - * @note All members can be manipulated via the related functions. - */ -struct mqtt_client { - /** @brief The socket connecting to the MQTT broker. */ - mqtt_pal_socket_handle socketfd; - - /** @brief The LFSR state used to generate packet ID's. */ - uint16_t pid_lfsr; - - /** @brief The keep-alive time in seconds. */ - uint16_t keep_alive; - - /** - * @brief A counter counting pings that have been sent to keep the connection alive. - * @see keep_alive - */ - int number_of_keep_alives; - - /** - * @brief The current sent offset. - * - * This is used to allow partial send commands. - */ - size_t send_offset; - - /** - * @brief The timestamp of the last message sent to the buffer. - * - * This is used to detect the need for keep-alive pings. - * - * @see keep_alive - */ - mqtt_pal_time_t time_of_last_send; - - /** - * @brief The error state of the client. - * - * error should be MQTT_OK for the entirety of the connection. - * - * @note The error state will be MQTT_ERROR_CONNECT_NOT_CALLED until - * you call mqtt_connect. - */ - enum MQTTErrors error; - - /** - * @brief The timeout period in seconds. - * - * If the broker doesn't return an ACK within response_timeout seconds a timeout - * will occur and the message will be retransmitted. - * - * @note The default value is 30 [seconds] but you can change it at any time. - */ - int response_timeout; - - /** @brief A counter counting the number of timeouts that have occurred. */ - int number_of_timeouts; - - /** - * @brief Approximately much time it has typically taken to receive responses from the - * broker. - * - * @note This is tracked using a exponential-averaging. - */ - float typical_response_time; - - /** - * @brief The callback that is called whenever a publish is received from the broker. - * - * Any topics that you have subscribed to will be returned from the broker as - * mqtt_response_publish messages. All the publishes received from the broker will - * be passed to this function. - * - * @note A pointer to publish_response_callback_state is always passed to the callback. - * Use publish_response_callback_state to keep track of any state information you - * need. - */ - void (*publish_response_callback)(void **state, struct mqtt_response_publish *publish); - - /** - * @brief A pointer to any publish_response_callback state information you need. - * - * @note A pointer to this pointer will always be publish_response_callback upon - * receiving a publish message from the broker. - */ - void *publish_response_callback_state; - - /** - * @brief A user-specified callback, triggered on each \ref mqtt_sync, allowing - * the user to perform state inspections (and custom socket error detection) - * on the client. - * - * This callback is triggered on each call to \ref mqtt_sync. If it returns MQTT_OK - * then \ref mqtt_sync will continue normally (performing reads and writes). If it - * returns an error then \ref mqtt_sync will not call reads and writes. - * - * This callback can be used to perform custom error detection, namely platform - * specific socket error detection, and force the client into an error state. - * - * This member is always initialized to NULL but it can be manually set at any - * time. - */ - enum MQTTErrors(*inspector_callback)(struct mqtt_client *); - - /** - * @brief A callback that is called whenever the client is in an error state. - * - * This callback is responsible for: application level error handling, closing - * previous sockets, and reestabilishing the connection to the broker and - * session configurations (i.e. subscriptions). - */ - void (*reconnect_callback)(struct mqtt_client *, void **); - - /** - * @brief A pointer to some state. A pointer to this member is passed to - * \ref mqtt_client.reconnect_callback. - */ - void *reconnect_state; - - /** - * @brief The buffer where ingress data is temporarily stored. - */ - struct { - /** @brief The start of the receive buffer's memory. */ - uint8_t *mem_start; - - /** @brief The size of the receive buffer's memory. */ - size_t mem_size; - - /** @brief A pointer to the next writable location in the receive buffer. */ - uint8_t *curr; - - /** @brief The number of bytes that are still writable at curr. */ - size_t curr_sz; - } recv_buffer; - - /** - * @brief A variable passed to support thread-safety. - * - * A pointer to this variable is passed to \c MQTT_PAL_MUTEX_LOCK, and - * \c MQTT_PAL_MUTEX_UNLOCK. - */ - mqtt_pal_mutex_t mutex; - - /** @brief The sending message queue. */ - struct mqtt_message_queue mq; -}; - -/** - * @brief Generate a new next packet ID. - * @ingroup details - * - * Packet ID's are generated using a max-length LFSR. - * - * @param client The MQTT client. - * - * @returns The new packet ID that should be used. - */ -uint16_t __mqtt_next_pid(struct mqtt_client *client); - -/** - * @brief Handles egress client traffic. - * @ingroup details - * - * @param client The MQTT client. - * - * @returns MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -ssize_t __mqtt_send(struct mqtt_client *client); - -/** - * @brief Handles ingress client traffic. - * @ingroup details - * - * @param client The MQTT client. - * - * @returns MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -ssize_t __mqtt_recv(struct mqtt_client *client); - -/** - * @brief Function that does the actual sending and receiving of - * traffic from the network. - * @ingroup api - * - * All the other functions in the @ref api simply stage messages for - * being sent to the broker. This function does the actual sending of - * those messages. Additionally this function receives traffic (responses and - * acknowledgements) from the broker and responds to that traffic accordingly. - * Lastly this function also calls the \c publish_response_callback when - * any \c MQTT_CONTROL_PUBLISH messages are received. - * - * @pre mqtt_init must have been called. - * - * @param[in,out] client The MQTT client. - * - * @attention It is the responsibility of the application programmer to - * call this function periodically. All functions in the @ref api are - * thread-safe so it is perfectly reasonable to have a thread dedicated - * to calling this function every 200 ms or so. MQTT-C can be used in single - * threaded application though by simply calling this functino periodically - * inside your main thread. See @ref simple_publisher.c and @ref simple_subscriber.c - * for examples (specifically the \c client_refresher functions). - * - * @returns MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -enum MQTTErrors mqtt_sync(struct mqtt_client *client); - -/** - * @brief Initializes an MQTT client. - * @ingroup api - * - * This function \em must be called before any other API function calls. - * - * @pre None. - * - * @param[out] client The MQTT client. - * @param[in] sockfd The socket file descriptor (or equivalent socket handle, e.g. BIO pointer - * for OpenSSL sockets) connected to the MQTT broker. - * @param[in] sendbuf A buffer that will be used for sending messages to the broker. - * @param[in] sendbufsz The size of \p sendbuf in bytes. - * @param[in] recvbuf A buffer that will be used for receiving messages from the broker. - * @param[in] recvbufsz The size of \p recvbuf in bytes. - * @param[in] publish_response_callback The callback to call whenever application messages - * are received from the broker. - * - * @post mqtt_connect must be called. - * - * @note \p sockfd is a non-blocking TCP connection. - * @note If \p sendbuf fills up completely during runtime a \c MQTT_ERROR_SEND_BUFFER_IS_FULL - * error will be set. Similarly if \p recvbuf is ever to small to receive a message from - * the broker an MQTT_ERROR_RECV_BUFFER_TOO_SMALL error will be set. - * @note A pointer to \ref mqtt_client.publish_response_callback_state is always passed as the - * \c state argument to \p publish_response_callback. Note that the second argument is - * the mqtt_response_publish that was received from the broker. - * - * @attention Only initialize an MQTT client once (i.e. don't call \ref mqtt_init or - * \ref mqtt_init_reconnect more than once per client). - * @attention \p sendbuf internally mapped to client's message-to-send queue that actively uses - * pointer access. In the case of unaligned \p sendbuf, that may lead to - * Segmentation/Hard/Memory Faults on systems that do not support unaligned pointer - * access (e.g. ARMv6, ARMv7-M). To avoid that, you may use the following technique: - * \code{.c} - * // example for ARMv7-M that requires pointers to be word aligned (4 byte boundary) - * static unsigned char mqtt_tx_buffer[MAX_TX_BUFFER_SIZE] __attribute__((aligned(4))); - * static unsigned char mqtt_rx_buffer[MAX_RX_BUFFER_SIZE]; - * // ... - * int main(void) { - * // ... - * mqtt_init(p_client, p_client->socketfd, mqtt_tx_buffer, sizeof mqtt_tx_buffer, mqtt_rx_buffer, - * sizeof mqtt_rx_buffer, message_callback); - * // ... - * } - * \endcode - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -enum MQTTErrors mqtt_init(struct mqtt_client *client, - mqtt_pal_socket_handle sockfd, - uint8_t *sendbuf, size_t sendbufsz, - uint8_t *recvbuf, size_t recvbufsz, - void (*publish_response_callback)(void **state, struct mqtt_response_publish *publish)); - -/** - * @brief Initializes an MQTT client and enables automatic reconnections. - * @ingroup api - * - * An alternative to \ref mqtt_init that allows the client to automatically reconnect to the - * broker after an error occurs (e.g. socket error or internal buffer overflows). - * - * This is accomplished by calling the \p reconnect_callback whenever the client enters an error - * state. The job of the \p reconnect_callback is to: (1) perform error handling/logging, - * (2) clean up the old connection (i.e. close client->socketfd), (3) \ref mqtt_reinit the - * client, and (4) reconfigure the MQTT session by calling \ref mqtt_connect followed by other - * API calls such as \ref mqtt_subscribe. - * - * The first argument to the \p reconnect_callback is the client (which will be in an error - * state) and the second argument is a pointer to a void pointer where you can store some state - * information. Internally, MQTT-C calls the reconnect callback like so: - * - * \code - * client->reconnect_callback(client, &client->reconnect_state) - * \endcode - * - * Note that the \p reconnect_callback is also called to setup the initial session. After - * calling \ref mqtt_init_reconnect the client will be in the error state - * \c MQTT_ERROR_INITIAL_RECONNECT. - * - * @pre None. - * - * @param[in,out] client The MQTT client that will be initialized. - * @param[in] reconnect_callback The callback that will be called to connect/reconnect the - * client to the broker and perform application level error handling. - * @param[in] reconnect_state A pointer to some state data for your \p reconnect_callback. - * If your \p reconnect_callback does not require any state information set this - * to NULL. A pointer to the memory address where the client stores a copy of this - * pointer is passed as the second argumnet to \p reconnect_callback. - * @param[in] publish_response_callback The callback to call whenever application messages - * are received from the broker. - * - * @post Call \p reconnect_callback yourself, or call \ref mqtt_sync - * (which will trigger the call to \p reconnect_callback). - * - * @attention Only initialize an MQTT client once (i.e. don't call \ref mqtt_init or - * \ref mqtt_init_reconnect more than once per client). - * - */ -void mqtt_init_reconnect(struct mqtt_client *client, - void (*reconnect_callback)(struct mqtt_client *client, void **state), - void *reconnect_state, - void (*publish_response_callback)(void **state, struct mqtt_response_publish *publish)); - -/** - * @brief Safely assign/reassign a socket and buffers to an new/existing client. - * @ingroup api - * - * This function also clears the \p client error state. Upon exiting this function - * \c client->error will be \c MQTT_ERROR_CONNECT_NOT_CALLED (which will be cleared) - * as soon as \ref mqtt_connect is called. - * - * @pre This function must be called BEFORE \ref mqtt_connect. - * - * @param[in,out] client The MQTT client. - * @param[in] socketfd The new socket connected to the broker. - * @param[in] sendbuf The buffer that will be used to buffer egress traffic to the broker. - * @param[in] sendbufsz The size of \p sendbuf in bytes. - * @param[in] recvbuf The buffer that will be used to buffer ingress traffic from the broker. - * @param[in] recvbufsz The size of \p recvbuf in bytes. - * - * @post Call \ref mqtt_connect. - * - * @attention This function should be used in conjunction with clients that have been - * initialzed with \ref mqtt_init_reconnect. - */ -void mqtt_reinit(struct mqtt_client *client, - mqtt_pal_socket_handle socketfd, - uint8_t *sendbuf, size_t sendbufsz, - uint8_t *recvbuf, size_t recvbufsz); - -/** - * @brief Establishes a session with the MQTT broker. - * @ingroup api - * - * @pre mqtt_init must have been called. - * - * @param[in,out] client The MQTT client. - * @param[in] client_id The unique name identifying the client. (or NULL) - * @param[in] will_topic The topic name of client's \p will_message. If no will message is - * desired set to \c NULL. - * @param[in] will_message The application message (data) to be published in the event the - * client ungracefully disconnects. Set to \c NULL if \p will_topic is \c NULL. - * @param[in] will_message_size The size of \p will_message in bytes. - * @param[in] user_name The username to use when establishing the session with the MQTT broker. - * Set to \c NULL if a username is not required. - * @param[in] password The password to use when establishing the session with the MQTT broker. - * Set to \c NULL if a password is not required. - * @param[in] connect_flags Additional \ref MQTTConnectFlags to use when establishing the connection. - * These flags are for forcing the session to start clean, - * \c MQTT_CONNECT_CLEAN_SESSION, the QOS level to publish the \p will_message with - * (provided \c will_message != \c NULL), MQTT_CONNECT_WILL_QOS_[0,1,2], and whether - * or not the broker should retain the \c will_message, MQTT_CONNECT_WILL_RETAIN. - * @param[in] keep_alive The keep-alive time in seconds. A reasonable value for this is 400 [seconds]. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -enum MQTTErrors mqtt_connect(struct mqtt_client *client, - const char *client_id, - const char *will_topic, - const void *will_message, - size_t will_message_size, - const char *user_name, - const char *password, - uint8_t connect_flags, - uint16_t keep_alive); - -/* - todo: will_message should be a void* -*/ - -/** - * @brief Publish an application message. - * @ingroup api - * - * Publishes an application message to the MQTT broker. - * - * @pre mqtt_connect must have been called. - * - * @param[in,out] client The MQTT client. - * @param[in] topic_name The name of the topic. - * @param[in] application_message The data to be published. - * @param[in] application_message_size The size of \p application_message in bytes. - * @param[in] publish_flags \ref MQTTPublishFlags to be used, namely the QOS level to - * publish at (MQTT_PUBLISH_QOS_[0,1,2]) or whether or not the broker should - * retain the publish (MQTT_PUBLISH_RETAIN). - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -enum MQTTErrors mqtt_publish(struct mqtt_client *client, - const char *topic_name, - const void *application_message, - size_t application_message_size, - uint8_t publish_flags); - -/** - * @brief Acknowledge an ingree publish with QOS==1. - * @ingroup details - * - * @param[in,out] client The MQTT client. - * @param[in] packet_id The packet ID of the ingress publish being acknowledged. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -ssize_t __mqtt_puback(struct mqtt_client *client, uint16_t packet_id); - -/** - * @brief Acknowledge an ingree publish with QOS==2. - * @ingroup details - * - * @param[in,out] client The MQTT client. - * @param[in] packet_id The packet ID of the ingress publish being acknowledged. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -ssize_t __mqtt_pubrec(struct mqtt_client *client, uint16_t packet_id); - -/** - * @brief Acknowledge an ingree PUBREC packet. - * @ingroup details - * - * @param[in,out] client The MQTT client. - * @param[in] packet_id The packet ID of the ingress PUBREC being acknowledged. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -ssize_t __mqtt_pubrel(struct mqtt_client *client, uint16_t packet_id); - -/** - * @brief Acknowledge an ingree PUBREL packet. - * @ingroup details - * - * @param[in,out] client The MQTT client. - * @param[in] packet_id The packet ID of the ingress PUBREL being acknowledged. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -ssize_t __mqtt_pubcomp(struct mqtt_client *client, uint16_t packet_id); - - -/** - * @brief Subscribe to a topic. - * @ingroup api - * - * @pre mqtt_connect must have been called. - * - * @param[in,out] client The MQTT client. - * @param[in] topic_name The name of the topic to subscribe to. - * @param[in] max_qos_level The maximum QOS level with which the broker can send application - * messages for this topic. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -enum MQTTErrors mqtt_subscribe(struct mqtt_client *client, - const char *topic_name, - int max_qos_level); - -/** - * @brief Unsubscribe from a topic. - * @ingroup api - * - * @pre mqtt_connect must have been called. - * - * @param[in,out] client The MQTT client. - * @param[in] topic_name The name of the topic to unsubscribe from. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -enum MQTTErrors mqtt_unsubscribe(struct mqtt_client *client, - const char *topic_name); - -/** - * @brief Ping the broker. - * @ingroup api - * - * @pre mqtt_connect must have been called. - * - * @param[in,out] client The MQTT client. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -enum MQTTErrors mqtt_ping(struct mqtt_client *client); - -/** - * @brief Ping the broker without locking/unlocking the mutex. - * @see mqtt_ping - */ -enum MQTTErrors __mqtt_ping(struct mqtt_client *client); - -/** - * @brief Terminate the session with the MQTT broker. - * @ingroup api - * - * @pre mqtt_connect must have been called. - * - * @param[in,out] client The MQTT client. - * - * @note To re-establish the session, mqtt_connect must be called. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -enum MQTTErrors mqtt_disconnect(struct mqtt_client *client); - -/** - * @brief Terminate the session with the MQTT broker and prepare to - * reconnect. Client code should call \ref mqtt_sync immediately - * after this call to prevent message loss. - * @ingroup api - * - * @note The user must provide a reconnect callback function for this to - * work as expected. See \r mqtt_client_reconnect. - * - * @pre mqtt_connect must have been called -* - * @param[in,out] client The MQTT client. - * - * @returns \c MQTT_OK upon success, an \ref MQTTErrors otherwise. - */ -enum MQTTErrors mqtt_reconnect(struct mqtt_client *client); - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/client/deps/mqtt/mqtt_pal.c b/client/deps/mqtt/mqtt_pal.c deleted file mode 100644 index 9ebab98b6..000000000 --- a/client/deps/mqtt/mqtt_pal.c +++ /dev/null @@ -1,235 +0,0 @@ -/* -MIT License - -Copyright(c) 2018 Liam Bindle - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#include "mqtt.h" - -/** - * @file - * @brief Implements @ref mqtt_pal_sendall and @ref mqtt_pal_recvall and - * any platform-specific helpers you'd like. - * @cond Doxygen_Suppress - */ - -#if defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) - -/* - * In case of MQTT_USE_CUSTOM_SOCKET_HANDLE, a pal implemantation is - * provided by the user. - */ - -/* Note: Some toolchains complain on an object without symbols */ - -int _mqtt_pal_dummy; - -#else /* defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) */ - -#if defined(MQTT_USE_MBEDTLS) -#include - -ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags) { - enum MQTTErrors error = 0; - size_t sent = 0; - while (sent < len) { - int rv = mbedtls_ssl_write(fd, (const unsigned char *)buf + sent, len - sent); - if (rv < 0) { - if (rv == MBEDTLS_ERR_SSL_WANT_READ || - rv == MBEDTLS_ERR_SSL_WANT_WRITE -#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) - || rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS -#endif -#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) - || rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -#endif - ) { - /* should call mbedtls_ssl_write later again */ - break; - } - error = MQTT_ERROR_SOCKET_ERROR; - break; - } - /* - * Note: rv can be 0 here eg. when mbedtls just flushed - * the previous incomplete record. - * - * Note: we never send an empty TLS record. - */ - sent += (size_t) rv; - } - if (sent == 0) { - return error; - } - return (ssize_t)sent; -} - -ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags) { - const void *const start = buf; - enum MQTTErrors error = 0; - int rv; - do { - rv = mbedtls_ssl_read(fd, (unsigned char *)buf, bufsz); - if (rv == 0) { - /* - * Note: mbedtls_ssl_read returns 0 when the underlying - * transport was closed without CloseNotify. - * - * Raise an error to trigger a reconnect. - */ - error = MQTT_ERROR_SOCKET_ERROR; - break; - } - if (rv < 0) { - if (rv == MBEDTLS_ERR_SSL_WANT_READ || - rv == MBEDTLS_ERR_SSL_WANT_WRITE -#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS) - || rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS -#endif -#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS) - || rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS -#endif - ) { - /* should call mbedtls_ssl_read later again */ - break; - } - /* Note: MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY is handled here. */ - error = MQTT_ERROR_SOCKET_ERROR; - break; - } - buf = (char *)buf + rv; - bufsz -= (unsigned long)rv; - } while (bufsz > 0); - if (buf == start) { - return error; - } - return (const char *)buf - (const char *)start; -} - -#elif defined(__unix__) || defined(__APPLE__) || defined(__NuttX__) - -#include - -ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags) { - enum MQTTErrors error = 0; - size_t sent = 0; - while (sent < len) { - ssize_t rv = send(fd, (const char *)buf + sent, len - sent, flags); - if (rv < 0) { - if (errno == EAGAIN) { - /* should call send later again */ - break; - } - error = MQTT_ERROR_SOCKET_ERROR; - break; - } - if (rv == 0) { - /* is this possible? maybe OS bug. */ - error = MQTT_ERROR_SOCKET_ERROR; - break; - } - sent += (size_t) rv; - } - if (sent == 0) { - return error; - } - return (ssize_t)sent; -} - -ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags) { - const void *const start = buf; - enum MQTTErrors error = 0; - ssize_t rv; - do { - rv = recv(fd, buf, bufsz, flags); - if (rv == 0) { - /* - * recv returns 0 when the socket is (half) closed by the peer. - * - * Raise an error to trigger a reconnect. - */ - error = MQTT_ERROR_SOCKET_ERROR; - break; - } - if (rv < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - /* should call recv later again */ - break; - } - /* an error occurred that wasn't "nothing to read". */ - error = MQTT_ERROR_SOCKET_ERROR; - break; - } - buf = (char *)buf + rv; - bufsz -= (unsigned long)rv; - } while (bufsz > 0); - if (buf == start) { - return error; - } - return (char *)buf - (const char *)start; -} - -#elif defined(_MSC_VER) || defined(WIN32) - -#include - -ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags) { - size_t sent = 0; - while (sent < len) { - ssize_t tmp = send(fd, (char *)buf + sent, len - sent, flags); - if (tmp < 1) { - return MQTT_ERROR_SOCKET_ERROR; - } - sent += (size_t) tmp; - } - return sent; -} - -ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags) { - const char *const start = buf; - ssize_t rv; - do { - rv = recv(fd, buf, bufsz, flags); - if (rv > 0) { - /* successfully read bytes from the socket */ - buf = (char *)buf + rv; - bufsz -= rv; - } else if (rv < 0) { - int err = WSAGetLastError(); - if (err != WSAEWOULDBLOCK) { - /* an error occurred that wasn't "nothing to read". */ - return MQTT_ERROR_SOCKET_ERROR; - } - } - } while (rv > 0 && bufsz > 0); - - return (ssize_t)((char *)buf - start); -} - -#else - -#error No PAL! - -#endif - -#endif /* defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) */ - -/** @endcond */ diff --git a/client/deps/mqtt/mqtt_pal.h b/client/deps/mqtt/mqtt_pal.h deleted file mode 100644 index 87b84500b..000000000 --- a/client/deps/mqtt/mqtt_pal.h +++ /dev/null @@ -1,173 +0,0 @@ -#if !defined(__MQTT_PAL_H__) -#define __MQTT_PAL_H__ - -/* -MIT License - -Copyright(c) 2018 Liam Bindle - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files(the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions : - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -#if defined(__cplusplus) -extern "C" { -#endif - -/** - * @file - * @brief Includes/supports the types/calls required by the MQTT-C client. - * - * @note This is the \em only file included in mqtt.h, and mqtt.c. It is therefore - * responsible for including/supporting all the required types and calls. - * - * @defgroup pal Platform abstraction layer - * @brief Documentation of the types and calls required to port MQTT-C to a new platform. - * - * mqtt_pal.h is the \em only header file included in mqtt.c. Therefore, to port MQTT-C to a - * new platform the following types, functions, constants, and macros must be defined in - * mqtt_pal.h: - * - Types: - * - \c size_t, \c ssize_t - * - \c uint8_t, \c uint16_t, \c uint32_t - * - \c va_list - * - \c mqtt_pal_time_t : return type of \c MQTT_PAL_TIME() - * - \c mqtt_pal_mutex_t : type of the argument that is passed to \c MQTT_PAL_MUTEX_LOCK and - * \c MQTT_PAL_MUTEX_RELEASE - * - Functions: - * - \c memcpy, \c strlen - * - \c va_start, \c va_arg, \c va_end - * - Constants: - * - \c INT_MIN - * - * Additionally, three macro's are required: - * - \c MQTT_PAL_HTONS(s) : host-to-network endian conversion for uint16_t. - * - \c MQTT_PAL_NTOHS(s) : network-to-host endian conversion for uint16_t. - * - \c MQTT_PAL_TIME() : returns [type: \c mqtt_pal_time_t] current time in seconds. - * - \c MQTT_PAL_MUTEX_LOCK(mtx_pointer) : macro that locks the mutex pointed to by \c mtx_pointer. - * - \c MQTT_PAL_MUTEX_RELEASE(mtx_pointer) : macro that unlocks the mutex pointed to by - * \c mtx_pointer. - * - * Lastly, \ref mqtt_pal_sendall and \ref mqtt_pal_recvall, must be implemented in mqtt_pal.c - * for sending and receiving data using the platforms socket calls. - */ - - -/* UNIX-like platform support */ -#if defined(__unix__) || defined(__APPLE__) || defined(__NuttX__) -#include -#include -#include -#include -#include -#include - -#define MQTT_PAL_HTONS(s) htons(s) -#define MQTT_PAL_NTOHS(s) ntohs(s) - -#define MQTT_PAL_TIME() time(NULL) - -typedef time_t mqtt_pal_time_t; -typedef pthread_mutex_t mqtt_pal_mutex_t; - -#define MQTT_PAL_MUTEX_INIT(mtx_ptr) pthread_mutex_init(mtx_ptr, NULL) -#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) pthread_mutex_lock(mtx_ptr) -#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) pthread_mutex_unlock(mtx_ptr) - -#if !defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) -#if defined(MQTT_USE_MBEDTLS) -struct mbedtls_ssl_context; -typedef struct mbedtls_ssl_context *mqtt_pal_socket_handle; -#else -typedef int mqtt_pal_socket_handle; -#endif -#endif - -#elif defined(_MSC_VER) || defined(WIN32) -#include -#include -#include -#include -#include - -typedef SSIZE_T ssize_t; -#define MQTT_PAL_HTONS(s) htons(s) -#define MQTT_PAL_NTOHS(s) ntohs(s) - -#define MQTT_PAL_TIME() time(NULL) - -typedef time_t mqtt_pal_time_t; -typedef CRITICAL_SECTION mqtt_pal_mutex_t; - -#define MQTT_PAL_MUTEX_INIT(mtx_ptr) InitializeCriticalSection(mtx_ptr) -#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) EnterCriticalSection(mtx_ptr) -#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) LeaveCriticalSection(mtx_ptr) - - -#if !defined(MQTT_USE_CUSTOM_SOCKET_HANDLE) -typedef SOCKET mqtt_pal_socket_handle; -#endif - -#endif - -/** - * @brief Sends all the bytes in a buffer. - * @ingroup pal - * - * @param[in] fd The file-descriptor (or handle) of the socket. - * @param[in] buf A pointer to the first byte in the buffer to send. - * @param[in] len The number of bytes to send (starting at \p buf). - * @param[in] flags Flags which are passed to the underlying socket. - * - * @returns The number of bytes sent if successful, an \ref MQTTErrors otherwise. - * - * Note about the error handling: - * - On an error, if some bytes have been processed already, - * this function should return the number of bytes successfully - * processed. (partial success) - * - Otherwise, if the error is an equivalent of EAGAIN, return 0. - * - Otherwise, return MQTT_ERROR_SOCKET_ERROR. - */ -ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void *buf, size_t len, int flags); - -/** - * @brief Non-blocking receive all the byte available. - * @ingroup pal - * - * @param[in] fd The file-descriptor (or handle) of the socket. - * @param[in] buf A pointer to the receive buffer. - * @param[in] bufsz The max number of bytes that can be put into \p buf. - * @param[in] flags Flags which are passed to the underlying socket. - * - * @returns The number of bytes received if successful, an \ref MQTTErrors otherwise. - * - * Note about the error handling: - * - On an error, if some bytes have been processed already, - * this function should return the number of bytes successfully - * processed. (partial success) - * - Otherwise, if the error is an equivalent of EAGAIN, return 0. - * - Otherwise, return MQTT_ERROR_SOCKET_ERROR. - */ -ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void *buf, size_t bufsz, int flags); - -#if defined(__cplusplus) -} -#endif - - -#endif diff --git a/client/deps/mqtt/posix_sockets.h b/client/deps/mqtt/posix_sockets.h deleted file mode 100644 index 42954f640..000000000 --- a/client/deps/mqtt/posix_sockets.h +++ /dev/null @@ -1,73 +0,0 @@ -#if !defined(__POSIX_SOCKET_TEMPLATE_H__) -#define __POSIX_SOCKET_TEMPLATE_H__ - -#ifndef _WIN32 - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// A template for opening a non-blocking POSIX socket. - -void close_nb_socket(int sockfd); -int open_nb_socket(const char *addr, const char *port); - -int open_nb_socket(const char *addr, const char *port) { - - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - - hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */ - hints.ai_socktype = SOCK_STREAM; /* Must be TCP */ - - struct addrinfo *p, *servinfo; - - /* get address information */ - int rv = getaddrinfo(addr, port, &hints, &servinfo); - if (rv != 0) { - fprintf(stderr, "Failed to open socket (getaddrinfo): %s\n", gai_strerror(rv)); - return -1; - } - - /* open the first possible socket */ - int sockfd = -1; - for (p = servinfo; p != NULL; p = p->ai_next) { - sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - if (sockfd == -1) { - continue; - } - - /* connect to server */ - rv = connect(sockfd, p->ai_addr, p->ai_addrlen); - if (rv == -1) { - close(sockfd); - sockfd = -1; - continue; - } - break; - } - - // free servinfo - freeaddrinfo(servinfo); - - // make non-blocking - if (sockfd != -1) { - fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK); - } - - return sockfd; -} - -void close_nb_socket(int sockfd) { - if (sockfd != -1) { - close(sockfd); - } -} -#endif -#endif diff --git a/client/deps/mqtt/readme.md b/client/deps/mqtt/readme.md deleted file mode 100644 index c7e437b7e..000000000 --- a/client/deps/mqtt/readme.md +++ /dev/null @@ -1,15 +0,0 @@ - -# Information -Source: https://github.com/LiamBindle/MQTT-C -License: MIT -Authors: - -MQTT-C was initially developed as a CMPT 434 (Winter Term, 2018) final project at the University of Saskatchewan by: - - - Liam Bindle - - Demilade Adeoye - - -# about -MQTT-C is an MQTT v3.1.1 client written in C. MQTT is a lightweight publisher-subscriber-based messaging protocol that is commonly used in IoT and networking applications where high-latency and low data-rate links are expected. The purpose of MQTT-C is to provide a portable MQTT client, written in C, for embedded systems and PC's alike. MQTT-C does this by providing a transparent Platform Abstraction Layer (PAL) which makes porting to new platforms easy. MQTT-C is completely thread-safe but can also run perfectly fine on single-threaded systems making MQTT-C well-suited for embedded systems and microcontrollers. Finally, MQTT-C is small; there are only two source files totalling less than 2000 lines. - diff --git a/client/deps/mqtt/win32_sockets.h b/client/deps/mqtt/win32_sockets.h deleted file mode 100644 index 4775bb851..000000000 --- a/client/deps/mqtt/win32_sockets.h +++ /dev/null @@ -1,92 +0,0 @@ -#if !defined(__WIN32_SOCKET_TEMPLATE_H__) -#define __WIN32_SOCKET_TEMPLATE_H__ - -#include -#include - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -void close_nb_socket(mqtt_pal_socket_handle sockfd); -mqtt_pal_socket_handle open_nb_socket(const char *addr, const char *port); - -mqtt_pal_socket_handle open_nb_socket(const char *addr, const char *port) { - - WSADATA wsaData; - int res = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (res != 0) { - fprintf(stderr, "error: WSAStartup failed with error: %i", res); - return INVALID_SOCKET; - } - - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; // IPv4 or IPv6 - hints.ai_socktype = SOCK_STREAM; // Must be TCP - hints.ai_protocol = IPPROTO_TCP; // - - struct addrinfo *p, *servinfo; - // get address information - int rv = getaddrinfo(addr, port, &hints, &servinfo); - if (rv != 0) { - fprintf(stderr, "error: getaddrinfo: %s", gai_strerror(rv)); - WSACleanup(); - return INVALID_SOCKET; - } - - /* open the first possible socket */ - SOCKET hSocket = INVALID_SOCKET; - for (p = servinfo; p != NULL; p = p->ai_next) { - hSocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol); - - if (hSocket == INVALID_SOCKET) { - continue; - } - - // connect to server - if (connect(hSocket, p->ai_addr, (int)p->ai_addrlen) != INVALID_SOCKET) { - break; - } - - closesocket(hSocket); - hSocket = INVALID_SOCKET; - - } - - // free servinfo - freeaddrinfo(servinfo); - - if (p == NULL) { // No address succeeded - fprintf(stderr, "error: Could not connect"); - WSACleanup(); - return INVALID_SOCKET; - } - - // make non-blocking - if (hSocket != INVALID_SOCKET) { - u_long mode = 1; // FIONBIO returns size on 32b - ioctlsocket(hSocket, FIONBIO, &mode); - } - - int flag = 1; - res = setsockopt(hSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag)); - if (res != 0) { - closesocket(hSocket); - WSACleanup(); - return INVALID_SOCKET; - } - - return hSocket; -} - -void close_nb_socket(mqtt_pal_socket_handle sockfd) { - if (sockfd != INVALID_SOCKET) { - closesocket(sockfd); - } -} -#endif - -#endif diff --git a/client/deps/reveng.cmake b/client/deps/reveng.cmake index d7e3cfd8a..1040730f1 100644 --- a/client/deps/reveng.cmake +++ b/client/deps/reveng.cmake @@ -13,5 +13,5 @@ target_include_directories(pm3rrg_rdv4_reveng PRIVATE ../src ../../include) target_include_directories(pm3rrg_rdv4_reveng INTERFACE reveng) -target_compile_options(pm3rrg_rdv4_reveng PRIVATE -Wall -Werror -O3) +target_compile_options(pm3rrg_rdv4_reveng PRIVATE -Wall -O3) set_property(TARGET pm3rrg_rdv4_reveng PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/client/deps/tinycbor.cmake b/client/deps/tinycbor.cmake index 5a6abda25..c74618149 100644 --- a/client/deps/tinycbor.cmake +++ b/client/deps/tinycbor.cmake @@ -11,5 +11,5 @@ add_library(pm3rrg_rdv4_tinycbor STATIC target_include_directories(pm3rrg_rdv4_tinycbor INTERFACE tinycbor) # Strange errors on Mingw when compiling with -O3 -target_compile_options(pm3rrg_rdv4_tinycbor PRIVATE -Wall -Werror -O2) +target_compile_options(pm3rrg_rdv4_tinycbor PRIVATE -Wall -O2) set_property(TARGET pm3rrg_rdv4_tinycbor PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/client/deps/tinycbor/compilersupport_p.h b/client/deps/tinycbor/compilersupport_p.h index 3223324d9..91d88229e 100644 --- a/client/deps/tinycbor/compilersupport_p.h +++ b/client/deps/tinycbor/compilersupport_p.h @@ -179,9 +179,7 @@ #ifndef unlikely # define unlikely(x) __builtin_expect(!!(x), 0) #endif -#ifndef unreachable # define unreachable() __builtin_unreachable() -#endif #elif defined(_MSC_VER) # define likely(x) (x) # define unlikely(x) (x) diff --git a/client/deps/whereami.cmake b/client/deps/whereami.cmake index d2d6a5b2a..721873066 100644 --- a/client/deps/whereami.cmake +++ b/client/deps/whereami.cmake @@ -2,5 +2,5 @@ add_library(pm3rrg_rdv4_whereami STATIC whereami/whereami.c) target_compile_definitions(pm3rrg_rdv4_whereami PRIVATE WAI_PM3_TUNED) target_include_directories(pm3rrg_rdv4_whereami INTERFACE whereami) -target_compile_options(pm3rrg_rdv4_whereami PRIVATE -Wall -Werror -O3) +target_compile_options(pm3rrg_rdv4_whereami PRIVATE -Wall -O3) set_property(TARGET pm3rrg_rdv4_whereami PROPERTY POSITION_INDEPENDENT_CODE ON) diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index d6db9392b..e5af9c766 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -1905,14 +1905,15 @@ FF16014FEFC7 # Food GEM 6686FADE5566 # -# Samsung Data Systems (SDS) -# 10-11 A/B (Gen 2) -9B7C25052FC3 +# Samsung Data Systems (SDS) — Electronic Locks +# Gen 1 S10 KA/KB is FFFFFFFFFFFF, incompatible with Gen 2 locks +# +# SDS Gen 2 S10 KB C22E04247D9A -6C4F77534170 -704153564F6C # # Data from Discord, French pool +# SDS Gen 2 S10 KA +9B7C25052FC3 494446555455 # # Data from Discord, seems to be related to ASSA @@ -2542,7 +2543,7 @@ FAB943906E9C # R.A.T.T transport card key A/B AA034F342A55 456776908C48 -# + # BusFacil - Brazilian public transport card for some cities fae9b14365a9 c567dd4a6004 @@ -3107,106 +3108,3 @@ AB921CF0752C 265A5F32DE73 567D734C403C 2426217B3B3B -# -# German Aral Gas Station Car-Wash cards -080507020706 -0100815D8D00 -2459514AED5B -5D493F6B0352 -1CEC0F0ACC0E -922B5D1BF2BC -2D7E76C7B8EC -5E59896806FF -097EEA4FE51B -688FC86BAB79 -C01D1DBEEE79 -2529BF8544C2 -C6052FBAA150 -A1D7B3A95605 -00D0BF748E77 -C082C0F35CE6 -3C86C78541A7 -5632DCC517E1 -9310191C338F -2761858C02D7 -8C64B49C7638 -B1BA3E778930 -2037627D9260 -28C4D7170FCD -# -# Card keys from Andalusian public transport system (Consorcio de Transportes) -1848A8D1E4C5 -16EE1FE134E4 -5246B8F4ACFC -515A8209843C -0EF7636AA829 -E59D0F78C413 -5AF68604DD6B -B0BCB22DCBA3 -51B3EF60BF56 -99100225D83B -63C88F562B97 -B30B6A5AD434 -D33E4A4A0041 -9C0A4CC89D61 -5204D83D8CD3 -A662F9DC0D3D -# -# Card keys from EMT Malaga (Spain) bus system -41534E354936 -454D41343253 -4541444C4130 -46305234324E -505444505232 -5239425A3546 -454449434631 -414F4544384C -344E4F4E4937 -45444E413254 -3255534D3033 -4F554D523935 -3141544D3735 -494E47463539 -32414F4E3341 -41534C473637 -534E41395430 -41364C38364F -525241414D39 -41304532334F -4D4545494F35 -4E324C453045 -394143494E32 -5352554E3245 -324553553036 -444D414E3539 -324745413232 -4E4E41455236 -394C52493639 -4D4941413236 -414D504F3243 -434C414E3639 -# Key for Waferlock shadow programming card and shadow user card -333030313536 -# -# Poland Warsaw public transport card keys -2481118e5355 -b6f0fc87f57f -e4fdac292bed -5888180adbe6 -d572c9491137 -64ea317b7abd -a39a286285db -898989890823 -898989891789 -898989893089 -b6e56bad206a -8fe6fa230c69 -4d1095f1af34 -1ad2f99bb9e9 -891089898989 -896389898989 -890163898989 -898927638989 -898989063889 -898989428989 -898989048989 diff --git a/client/dictionaries/mfdes_default_keys.dic b/client/dictionaries/mfdes_default_keys.dic index 3b4e1dc28..8611f2de9 100644 --- a/client/dictionaries/mfdes_default_keys.dic +++ b/client/dictionaries/mfdes_default_keys.dic @@ -4,12 +4,10 @@ ffffffffffffffff 0011223344556677 1122334455667788 a0a1a2a3a4a5a6a7 -d3f7d3f7d3f7d3f7 00000000000000000000000000000000 #NXP Default 3DES/AES 000000000000000000000000000000000000000000000000 #NXP Default 3K3DES 00112233445566778899AABBCCDDEEFF0102030405060708 ffffffffffffffffffffffffffffffffffffffffffffffff -d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 425245414B4D454946594F5543414E21 # default UL-C key 00112233445566778899AABBCCDDEEFF #TI TRF7970A sloa213 79702553797025537970255379702553 #TI TRF7970A sloa213 diff --git a/client/experimental_lib/CMakeLists.txt b/client/experimental_lib/CMakeLists.txt index 7d0c952b1..6d4a9d9c8 100644 --- a/client/experimental_lib/CMakeLists.txt +++ b/client/experimental_lib/CMakeLists.txt @@ -434,7 +434,7 @@ set (TARGET_SOURCES add_custom_command( OUTPUT ${CMAKE_BINARY_DIR}/version_pm3.c - COMMAND sh ${PM3_ROOT}/tools/mkversion.sh ${CMAKE_BINARY_DIR}/version_pm3.c || ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c + COMMAND ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c DEPENDS ${PM3_ROOT}/common/default_version_pm3.c ) diff --git a/client/luascripts/hf_mf_keycheck.lua b/client/luascripts/hf_mf_keycheck.lua index 53a003ebc..29eb46072 100644 --- a/client/luascripts/hf_mf_keycheck.lua +++ b/client/luascripts/hf_mf_keycheck.lua @@ -216,7 +216,7 @@ local function perform_check(uid, numsectors) for sector = 0, #keys do -- Check if user aborted if core.kbd_enter_pressed() then - print('Aborted via keyboard!') + print('Aborted by user') break end diff --git a/client/luascripts/hf_mfu_ultra.lua b/client/luascripts/hf_mfu_ultra.lua deleted file mode 100644 index ed6a2b974..000000000 --- a/client/luascripts/hf_mfu_ultra.lua +++ /dev/null @@ -1,357 +0,0 @@ -local ansicolors = require('ansicolors') -local cmds = require('commands') -local getopt = require('getopt') -local lib14a = require('read14a') -local utils = require('utils') - --- globals -copyright = '' -author = 'Dmitry Malenok' -version = 'v1.0.0' -desc = [[ -The script provides functionality for writing Mifare Ultralight Ultra/UL-5 tags. -]] -example = [[ - -- restpre (write) dump to tag - ]]..ansicolors.yellow..[[script run hf_mfu_ultra -f hf-mfu-3476FF1514D866-dump.bin -k ffffffff -r]]..ansicolors.reset..[[ - - -- wipe tag (]]..ansicolors.red..[[Do not use it with UL-5!]]..ansicolors.reset..[[) - ]]..ansicolors.yellow..[[script run hf_mfu_ultra -k 1d237f76 -w ]]..ansicolors.reset..[[ -]] -usage = [[ -script run hf_mfu_ultra -h -f -k -w -r -]] -arguments = [[ - -h this help - -f filename for the datadump to read (bin) - -k pwd to use with the restore and wipe operations - -r restore a binary dump to tag - -w wipe tag (]]..ansicolors.red..[[Do not use it with UL-5!]]..ansicolors.reset..[[) - -]] - - -local _password = nil -local _defaultPassword = 'FFFFFFFF' -local _dumpstart = 0x38*2 + 1 ---- - ---- Handles errors -local function error(err) - print(ansicolors.red.."ERROR:"..ansicolors.reset, err) - core.clearCommandBuffer() - return nil, err -end ---- - --- sets the global password variable -local function setPassword(password) - if password == nil or #password == 0 then - _password = nil; - elseif #password ~= 8 then - return false, 'Password must be 4 hex bytes' - else - _password = password - end - return true, 'Sets' -end - - ---- Parses response data -local function parseResponse(rawResponse) - local resp = Command.parse(rawResponse) - local len = tonumber(resp.arg1) * 2 - return string.sub(tostring(resp.data), 0, len); -end ---- - ---- Sends raw data to PM3 and returns raw response if any -local function sendRaw(rawdata, options) - - local flags = lib14a.ISO14A_COMMAND.ISO14A_RAW - - if options.keep_signal then - flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT - end - - if options.connect then - flags = flags + lib14a.ISO14A_COMMAND.ISO14A_CONNECT - end - - if options.no_select then - flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_SELECT - end - - if options.append_crc then - flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC - end - - local arg2 = #rawdata / 2 - if options.bits7 then - arg2 = arg2 | tonumber(bit32.lshift(7, 16)) - end - - local command = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER, - arg1 = flags, - arg2 = arg2, - data = rawdata} - return command:sendMIX(options.ignore_response) -end ---- - ---- Sends raw data to PM3 and returns parsed response -local function sendWithResponse(payload, options) - local opts; - if options then - opts = options - else - opts = {ignore_response = false, keep_signal = true, append_crc = true} - end - local rawResp, err = sendRaw(payload, opts) - if err then return err end - return parseResponse(rawResp) -end ---- - --- Authenticates if password is provided -local function authenticate(password) - if password then - local resp, err = sendWithResponse('1B'..password) - if err then return err end - -- looking for 2 bytes (4 symbols) of PACK and 2 bytes (4 symbols) of CRC - if not resp or #resp ~=8 then return false, 'It seems that password is wrong' end - return true - end - return true -end --- - --- selects tag and authenticates if password is provided -local function connect() - core.clearCommandBuffer() - local info, err = lib14a.read(true, true) - if err then - lib14a.disconnect() - return false, err - end - core.clearCommandBuffer() - - return authenticate(_password) -end --- - --- reconnects and selects tag again -local function reconnect() - lib14a.disconnect() - utils.Sleep(1) - local info, err = connect() - if not info then return false, "Unable to select tag: "..err end - return true -end --- - --- checks tag version -local function checkTagVersion() - local resp, err = sendWithResponse('60'); - if err or resp == nil then return false, err end - if string.find(resp, '0034210101000E03') ~= 1 then return false, 'Wrong tag version: '..string.sub(resp,1,-5) end - return true -end --- - --- sends magic wakeup command -local function magicWakeup() - io.write('Sending magic wakeup command...') - local resp, err = sendRaw('5000', {ignore_response = false, append_crc = true}) - if err or resp == nil then return false, "Unable to send first magic wakeup command: "..err end - resp, err = sendRaw('40', {connect = true, no_select = true, ignore_response = false, keep_signal = true, append_crc = false, bits7 = true}) - if err or resp == nil then return false, "Unable to send first magic wakeup command: "..err end - resp, err = sendRaw('43', {ignore_response = false, keep_signal = true, append_crc = false}) - if err or resp == nil then return false, "Unable to send second magic wakeup command: "..err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - return true -end --- - --- Writes dump to tag -local function writeDump(filename) - print(string.rep('--',20)) - local info, err = connect() - if not info then return false, "Unable to select tag: "..err end - info, err = checkTagVersion() - if not info then return info, err end - - -- load dump from file - if not filename then return false, 'No dump filename provided' end - io.write('Loading dump from file '..filename..'...') - local dump - dump, err = utils.ReadDumpFile(filename) - if not dump then return false, err end - if #dump ~= _dumpstart - 1 + 0xa4*2 then return false, 'Invalid dump file' end - print(ansicolors.green..'done'..ansicolors.reset..'.') - - local resp - for i = 3, 0x23 do - local blockStart = i * 8 + _dumpstart - local block = string.sub(dump, blockStart, blockStart + 7) - local cblock = string.format('%02x',i) - io.write('Writing block 0x'..cblock..'...') - resp, err = sendWithResponse('A2'..cblock..block) - if err ~= nil then return false, err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - end - - -- set password - io.write('Setting password and pack ') - info, err = reconnect() - if not info then return false, err end - local passwordStart = 0x27*8 + _dumpstart - local password = string.sub(dump, passwordStart, passwordStart + 7) - local packBlock = string.sub(dump, passwordStart+8, passwordStart + 15) - io.write('(password: '..password..') (pack block: '..packBlock..')...') - resp, err = sendWithResponse('A227'..password) - if err ~= nil then return false, err end - resp, err = sendWithResponse('A228'..packBlock) - if err ~= nil then return false, err end - if not setPassword(password) then return false, 'Unable to set password' end - info, err = reconnect() - if not info then return false, err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - - -- set configs and locks - for i = 0x24, 0x26 do - local blockStart = i * 8 + _dumpstart - local block = string.sub(dump, blockStart, blockStart + 7) - local cblock = string.format('%02x',i) - io.write('Writing block 0x'..cblock..'...') - resp, err = sendWithResponse('A2'..cblock..block) - if err ~= nil then return false, err end - info, err = reconnect() - if not info then return false, err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - end - - info, err = magicWakeup() - if not info then return false, err end - -- set uid and locks - for i = 0x2, 0x0, -1 do - local blockStart = i * 8 + _dumpstart - local block = string.sub(dump, blockStart, blockStart + 7) - local cblock = string.format('%02x',i) - io.write('Writing block 0x'..cblock..'...') - resp, err = sendWithResponse('A2'..cblock..block, {connect = i == 0x2, ignore_response = false, keep_signal = i ~= 0, append_crc = true}) - if err ~= nil then return false, err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - end - - print(ansicolors.green..'The dump has been written to the tag.'..ansicolors.reset) - return true -end --- - --- Wipes tag -local function wipe() - print(string.rep('--',20)) - print('Wiping tag') - - local info, err = connect() - if not info then return false, "Unable to select tag: "..err end - info, err = checkTagVersion() - if not info then return info, err end - - - local resp - -- clear lock bytes on page 0x02 - resp, err = sendWithResponse('3000') - if err or resp == nil then return false, err end - local currentLowLockPage = string.sub(resp,17,24) - if(string.sub(currentLowLockPage,5,8) ~= '0000') then - info, err = magicWakeup() - if not info then return false, err end - local newLowLockPage = string.sub(currentLowLockPage,1,4)..'0000' - io.write('Clearing lock bytes on page 0x02...') - resp, err = sendWithResponse('A202'..newLowLockPage, {connect = true, ignore_response = false, keep_signal = true, append_crc = true}) - if err ~= nil then return false, err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - end - - -- clear lock bytes on page 0x24 - io.write('Clearing lock bytes on page 0x24...') - info, err = reconnect() - if not info then return false, err end - resp, err = sendWithResponse('A224000000BD') - if err ~= nil then return false, err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - - -- clear configs - io.write('Clearing cfg0 and cfg1...') - resp, err = sendWithResponse('A225000000FF') - if err ~= nil then return false, err end - resp, err = sendWithResponse('A22600050000') - if err ~= nil then return false, err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - - -- clear password - io.write('Reseting password (and pack) to default ('.._defaultPassword..') and 0000...') - info, err = reconnect() - if not info then return false, err end - resp, err = sendWithResponse('A227'.._defaultPassword) - if err ~= nil then return false, err end - resp, err = sendWithResponse('A22800000000') - if err ~= nil then return false, err end - if not setPassword(_defaultPassword) then return false, 'Unable to set password' end - info, err = reconnect() - if not info then return false, err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - - -- clear other blocks - for i = 3, 0x23 do - local cblock = string.format('%02x',i) - io.write('Clearing block 0x'..cblock..'...') - resp, err = sendWithResponse('A2'..cblock..'00000000') - if err ~= nil then return false, err end - print(ansicolors.green..'done'..ansicolors.reset..'.') - end - - print(ansicolors.green..'The tag has been wiped.'..ansicolors.reset) - - lib14a.disconnect() - return true -end --- - --- Prints help -local function help() - print(copyright) - print(author) - print(version) - print(desc) - print(ansicolors.cyan..'Usage'..ansicolors.reset) - print(usage) - print(ansicolors.cyan..'Arguments'..ansicolors.reset) - print(arguments) - print(ansicolors.cyan..'Example usage'..ansicolors.reset) - print(example) -end ---- - --- The main entry point -local function main(args) - if #args == 0 then return help() end - - local dumpFilename = nil - - for opt, value in getopt.getopt(args, 'hf:k:rw') do - local res, err - res = true - if opt == "h" then return help() end - if opt == "f" then dumpFilename = value end - if opt == 'k' then res, err = setPassword(value) end - if opt == 'r' then res, err = writeDump(dumpFilename) end - if opt == 'w' then res, err = wipe() end - if not res then return error(err) end - end - -end - -main(args) diff --git a/client/luascripts/kybercrystals.lua b/client/luascripts/kybercrystals.lua deleted file mode 100644 index 1b707768b..000000000 --- a/client/luascripts/kybercrystals.lua +++ /dev/null @@ -1,747 +0,0 @@ ---[[ - Simple script to program DIY kyber crystals - works on real kyber crystals and EM4305 2.12x12mm chips - simply run the program and select a profile via a number - - issues - if you are getting errors when trying to read or write a chip - run the cmd "lf tune" with no chip on the device, then move the chip over the coils till you see the lowest voltage. try different angles and in the center and or the edge of the antenna ring. - once you find the lowest voltage then try running the script again. - if thats still not working run "lf tune" again and put the chip in the best position like before - the total voltage may be too high to reduce it slowly lower tin foil over the antenna and watch the voltage. - the foil should be a bit bigger than the coil exact size does not matter. - - data pulled from here - https://docs.google.com/spreadsheets/d/13P_GE6tNYpGvoVUTEQvA3SQzMqpZ-SoiWaTNoJoTV9Q/edit?usp=sharing ---]] - -local cmds = require('commands') -local utils = require('utils') - - -function send_command(cmd) - core.console(cmd) - return "" -end - -function get_profile_data(profile_name) - local profiles = { - ["wipe chip"] = { - [0] = "00000000", - [1] = "00000000", - [2] = "00000000", - [3] = "00000000", - [4] = "00000000", - [5] = "00000000", - [6] = "00000000", - [7] = "00000000", - [8] = "00000000", - [9] = "00000000" - }, - ["Qui-Gon Jinn"] = { - [0] = "00040072", - [1] = "6147FBB3", - [2] = "00000000", - [3] = "000064FC", - [4] = "0001805F", - [5] = "000001FF", - [6] = "0C803000", - [7] = "00000000", - [8] = "00000000", - [9] = "00000000" - }, - ["Qui-Gon Jinn 2"] = { - [0] = "00040072", - [1] = "6148C1EF", - [2] = "00000000", - [3] = "000050C2", - [4] = "0001805F", - [5] = "000001FF", - [6] = "0C803000", - [7] = "00000000", - [8] = "10000040", - [9] = "00000000" - }, - ["Yoda"] = { - [0] = "00040072", - [1] = "660A50D6", - [2] = "00000000", - [3] = "0000379F", - [4] = "0001805F", - [5] = "000001FF", - [6] = "00C03000", - [7] = "00000000", - [8] = "00100040", - [9] = "00000000" - }, - ["Yoda 2"] = { - [0] = "00040072", - [1] = "667B2FEE", - [2] = "00000000", - [3] = "0000BDB6", - [4] = "0001805F", - [5] = "000001FF", - [6] = "00C03000", - [7] = "00000000", - [8] = "00100040", - [9] = "00000000" - }, - ["Yoda 8-Ball"] = { - [0] = "00040072", - [1] = "67AD7FC8", - [2] = "00000000", - [3] = "0000E0FE", - [4] = "0001805F", - [5] = "000001FF", - [6] = "5D183000", - [7] = "00000000", - [8] = "00000140", - [9] = "00000000" - }, - ["Old Obi-Wan"] = { - [0] = "00040072", - [1] = "6147BBB9", - [2] = "00000000", - [3] = "0000BE24", - [4] = "0001805F", - [5] = "000001FF", - [6] = "29803000", - [7] = "00000000", - [8] = "00000000", - [9] = "00000000" - }, - ["Old Luke"] = { - [0] = "00040072", - [1] = "614097AE", - [2] = "00000000", - [3] = "0000C134", - [4] = "0001805F", - [5] = "000001FF", - [6] = "25C03000", - [7] = "00000000", - [8] = "00100060", - [9] = "00000000" - }, - ["Old Obi-Wan 2"] = { - [0] = "00040072", - [1] = "614009A2", - [2] = "00000000", - [3] = "0000CF62", - [4] = "0001805F", - [5] = "000001FF", - [6] = "29803000", - [7] = "00000000", - [8] = "01000060", - [9] = "00000000" - }, - ["Old Luke 2"] = { - [0] = "00040072", - [1] = "75952DE5", - [2] = "00000000", - [3] = "00009988", - [4] = "0001805F", - [5] = "000001FF", - [6] = "25C03000", - [7] = "00000000", - [8] = "00010060", - [9] = "00000000" - }, - ["Old Obi-Wan 3"] = { - [0] = "00040072", - [1] = "65413B42", - [2] = "00000000", - [3] = "00001702", - [4] = "0001805F", - [5] = "000001FF", - [6] = "29803000", - [7] = "00000000", - [8] = "01000060", - [9] = "00000000" - }, - ["Mace Windu"] = { - [0] = "00040072", - [1] = "6147CCD4", - [2] = "00000000", - [3] = "0000A092", - [4] = "0001805F", - [5] = "000001FF", - [6] = "63C03000", - [7] = "00000000", - [8] = "00000000", - [9] = "00000000" - }, - ["Mace Windu 2"] = { - [0] = "00040072", - [1] = "6609B150", - [2] = "00000000", - [3] = "0000287E", - [4] = "0001805F", - [5] = "000001FF", - [6] = "63C03000", - [7] = "00000000", - [8] = "00010070", - [9] = "00000000" - }, - ["Mace Windu 3"] = { - [0] = "00040072", - [1] = "613F42AD", - [2] = "00000000", - [3] = "00002147", - [4] = "0001805F", - [5] = "000001FF", - [6] = "6F803000", - [7] = "00000000", - [8] = "01000070", - [9] = "00000000" - }, - ["Mace Windu 4"] = { - [0] = "00040072", - [1] = "667B5B82", - [2] = "00000000", - [3] = "000050DF", - [4] = "0001805F", - [5] = "000001FF", - [6] = "6F803000", - [7] = "00000000", - [8] = "10000070", - [9] = "00000000" - }, - ["Mace Windu 5"] = { - [0] = "00040072", - [1] = "614869C4", - [2] = "00000000", - [3] = "0000D691", - [4] = "0001805F", - [5] = "000001FF", - [6] = "6F803000", - [7] = "00000000", - [8] = "01000070", - [9] = "00000000" - }, - ["Mace Windu 6"] = { - [0] = "00040072", - [1] = "759BEA43", - [2] = "00000000", - [3] = "00006CA0", - [4] = "0001805F", - [5] = "000001FF", - [6] = "63C03000", - [7] = "00000000", - [8] = "00100070", - [9] = "00000000" - }, - ["Mace Windu 7"] = { - [0] = "00040072", - [1] = "768E0D9D", - [2] = "00000000", - [3] = "0000668C", - [4] = "0001805F", - [5] = "000001FF", - [6] = "6F803000", - [7] = "00000000", - [8] = "01000070", - [9] = "00000000" - }, - ["Temple Guard"] = { - [0] = "00040072", - [1] = "60954FDA", - [2] = "00000000", - [3] = "0000905A", - [4] = "0001805F", - [5] = "000001FF", - [6] = "7B003000", - [7] = "00000000", - [8] = "00000000", - [9] = "00000000" - }, - ["Maz Kanata"] = { - [0] = "00040072", - [1] = "6679DFF4", - [2] = "00000000", - [3] = "0000D691", - [4] = "0001805F", - [5] = "000001FF", - [6] = "77403000", - [7] = "00000000", - [8] = "00100030", - [9] = "00000000" - }, - ["Maz Kanata 2"] = { - [0] = "00040072", - [1] = "60953999", - [2] = "00000000", - [3] = "0000F521", - [4] = "0001805F", - [5] = "000001FF", - [6] = "77403000", - [7] = "00000000", - [8] = "00100030", - [9] = "00000000" - }, - ["Temple Guard 2"] = { - [0] = "00040072", - [1] = "667A67C5", - [2] = "00000000", - [3] = "00002B9C", - [4] = "0001805F", - [5] = "000001FF", - [6] = "7B003000", - [7] = "00000000", - [8] = "10000030", - [9] = "00000000" - }, - ["Maz Kanata 3"] = { - [0] = "00040072", - [1] = "7A213721", - [2] = "00000000", - [3] = "000083AB", - [4] = "0001805F", - [5] = "000001FF", - [6] = "77403000", - [7] = "00000000", - [8] = "00010030", - [9] = "00000000" - }, - ["Chirrut Îmwe"] = { - [0] = "00040072", - [1] = "6094F399", - [2] = "00000000", - [3] = "00009519", - [4] = "0001805F", - [5] = "000001FF", - [6] = "14403000", - [7] = "00000000", - [8] = "00000000", - [9] = "00000000" - }, - ["Chirrut Îmwe 2"] = { - [0] = "00040072", - [1] = "667A9AB7", - [2] = "00000000", - [3] = "00003BE4", - [4] = "0001805F", - [5] = "000001FF", - [6] = "14403000", - [7] = "00000000", - [8] = "00010000", - [9] = "00000000" - }, - ["Ahsoka Tano"] = { - [0] = "00040072", - [1] = "667B1626", - [2] = "00000000", - [3] = "00007907", - [4] = "0001805F", - [5] = "000001FF", - [6] = "18003000", - [7] = "00000000", - [8] = "10000000", - [9] = "00000000" - }, - ["Chirrut Îmwe 3"] = { - [0] = "00040072", - [1] = "667B7E07", - [2] = "00000000", - [3] = "00002960", - [4] = "0001805F", - [5] = "000001FF", - [6] = "14403000", - [7] = "00000000", - [8] = "00100000", - [9] = "00000000" - }, - ["Darth Vader"] = { - [0] = "00040072", - [1] = "6148C4F8", - [2] = "00000000", - [3] = "0000FDFF", - [4] = "0001805F", - [5] = "000001FF", - [6] = "5E003000", - [7] = "00000000", - [8] = "00000000", - [9] = "00000000" - }, - ["Darth Sidious"] = { - [0] = "00040072", - [1] = "613F8964", - [2] = "00000000", - [3] = "0000C0C1", - [4] = "0001805F", - [5] = "000001FF", - [6] = "52403000", - [7] = "00000000", - [8] = "00000000", - [9] = "00000000" - }, - ["Darth Maul"] = { - [0] = "00040072", - [1] = "613FD2A9", - [2] = "00000000", - [3] = "0000DAD2", - [4] = "0001805F", - [5] = "000001FF", - [6] = "46C03000", - [7] = "00000000", - [8] = "00000000", - [9] = "00000000" - }, - ["Count Dooku"] = { - [0] = "00040072", - [1] = "6140880C", - [2] = "00000000", - [3] = "0000952D", - [4] = "0001805F", - [5] = "000001FF", - [6] = "31403000", - [7] = "00000000", - [8] = "00010010", - [9] = "00000000" - }, - ["Darth Vader 2"] = { - [0] = "00040072", - [1] = "667B33DC", - [2] = "00000000", - [3] = "0000E804", - [4] = "0001805F", - [5] = "000001FF", - [6] = "5E003000", - [7] = "00000000", - [8] = "01000010", - [9] = "00000000" - }, - ["Darth Maul 2"] = { - [0] = "00040072", - [1] = "667B26E9", - [2] = "00000000", - [3] = "00007689", - [4] = "0001805F", - [5] = "000001FF", - [6] = "46C03000", - [7] = "00000000", - [8] = "00100010", - [9] = "00000000" - }, - ["Vader 8-Ball"] = { - [0] = "00040072", - [1] = "6A92B478", - [2] = "00000000", - [3] = "00004CD1", - [4] = "0001805F", - [5] = "000001FF", - [6] = "3E183000", - [7] = "00000000", - [8] = "00000110", - [9] = "00000000" - }, - ["Darth Maul 3"] = { - [0] = "00040072", - [1] = "7597EF7E", - [2] = "00000000", - [3] = "00003BC0", - [4] = "0001805F", - [5] = "000001FF", - [6] = "46C03000", - [7] = "00000000", - [8] = "00100010", - [9] = "00000000" - }, - ["Darth Sidious 2"] = { - [0] = "00040072", - [1] = "768E4402", - [2] = "00000000", - [3] = "0000A0D2", - [4] = "0001805F", - [5] = "000001FF", - [6] = "52403000", - [7] = "00000000", - [8] = "10000010", - [9] = "00000000" - }, - ["Snoke"] = { - [0] = "00040072", - [1] = "6540BD8F", - [2] = "00000000", - [3] = "000064B9", - [4] = "0001805F", - [5] = "000001FF", - [6] = "1B183000", - [7] = "00000000", - [8] = "00001010", - [9] = "00000000" - }, - ["Luke Skywalker"] = { - [0] = "00040072", - [1] = "804B08F0", - [2] = "00000000", - [3] = "00006BF1", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "0C803000", - [7] = "00000000", - [8] = "00000000", - [9] = "050D0000" - }, - ["Luminara Unduli"] = { - [0] = "00040072", - [1] = "7B83C85A", - [2] = "00000000", - [3] = "000052CE", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "0C803000", - [7] = "00000000", - [8] = "00000000", - [9] = "180D0000" - }, - ["Plo Koon"] = { - [0] = "00040072", - [1] = "7B8998F3", - [2] = "00000000", - [3] = "00007703", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "29803000", - [7] = "00000000", - [8] = "00000000", - [9] = "040D0000" - }, - ["Plo Koon 2"] = { - [0] = "00040072", - [1] = "7B8413EA", - [2] = "00000000", - [3] = "0000D8F3", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "29803000", - [7] = "00000000", - [8] = "00000000", - [9] = "040D0000" - }, - ["Plo Koon 3"] = { - [0] = "00040072", - [1] = "7B84222B", - [2] = "00000000", - [3] = "000023E3", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "29803000", - [7] = "00000000", - [8] = "00000000", - [9] = "040D0000" - }, - ["Mace Windu S2"] = { - [0] = "00040072", - [1] = "7B8936EA", - [2] = "00000000", - [3] = "0000520D", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "6F803000", - [7] = "00000000", - [8] = "00000000", - [9] = "070D0000" - }, - ["General Grievous"] = { - [0] = "00040072", - [1] = "7B896284", - [2] = "00000000", - [3] = "00008529", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "6F803000", - [7] = "00000000", - [8] = "00000000", - [9] = "060D0000" - }, - ["Rey Skywalker"] = { - [0] = "00040072", - [1] = "7B88F3F4", - [2] = "00000000", - [3] = "00001511", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "7B003000", - [7] = "00000000", - [8] = "00000000", - [9] = "170D0000" - }, - ["Rey Skywalker 2"] = { - [0] = "00040072", - [1] = "7B841039", - [2] = "00000000", - [3] = "0000EA22", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "7B003000", - [7] = "00000000", - [8] = "00000000", - [9] = "170D0000" - }, - ["Krin Dagbard"] = { - [0] = "00040072", - [1] = "7B894F46", - [2] = "00000000", - [3] = "00007BC2", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "18003000", - [7] = "00000000", - [8] = "00000000", - [9] = "140D0000" - }, - ["Krin Dagbard 2"] = { - [0] = "00040072", - [1] = "7B841797", - [2] = "00000000", - [3] = "00006A58", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "18003000", - [7] = "00000000", - [8] = "00000000", - [9] = "140D0000" - }, - ["Grand Inquisitor"] = { - [0] = "00040072", - [1] = "7B841185", - [2] = "00000000", - [3] = "00004656", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "5E003000", - [7] = "00000000", - [8] = "00000000", - [9] = "130D0000" - }, - ["Maul"] = { - [0] = "00040072", - [1] = "7B895525", - [2] = "00000000", - [3] = "00003104", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "5E003000", - [7] = "00000000", - [8] = "00000000", - [9] = "110D0000" - }, - ["Grand Inquisitor 2"] = { - [0] = "00040072", - [1] = "804B091A", - [2] = "00000000", - [3] = "00005909", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "5E003000", - [7] = "00000000", - [8] = "00000000", - [9] = "130D0000" - }, - ["Asajj Ventress"] = { - [0] = "00040072", - [1] = "7A1C1F46", - [2] = "00000000", - [3] = "00008E4D", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "5E003000", - [7] = "00000000", - [8] = "00000000", - [9] = "080D0000" - }, - ["Darth Sidious s2"] = { - [0] = "00040072", - [1] = "00000000", - [2] = "00000000", - [3] = "00000000", - [4] = "0001805F", - [5] = "18C631FF", - [6] = "5E003000", - [7] = "00000000", - [8] = "00000000", - [9] = "010D0000" - } - } - - -- When called without arguments, return the whole table - if not profile_name then - return profiles - end - - -- Otherwise return the specific profile or wipe chip - return profiles[profile_name] or profiles["wipe chip"] -end - -function get_profile_names() - -- Get the complete profiles table from get_profile_data - local all_profiles = get_profile_data() - - local names = {} - for name, _ in pairs(all_profiles) do - table.insert(names, name) - end - table.sort(names) - return names -end - -function select_profile() - local profile_names = get_profile_names() - - print("\nAvailable profiles:") - for i, name in ipairs(profile_names) do - print(string.format("%d. %s", i, name)) - end - - while true do - io.write("\nSelect profile (1-" .. #profile_names .. "): ") - local choice = tonumber(io.read()) - - if choice and choice >= 1 and choice <= #profile_names then - return profile_names[choice] - else - print("Invalid selection. Please try again.") - end - end -end - -function main() - print("\n[=== kyber crystal programmer ===]") - - -- Get profile from command line argument or prompt user - local profile_name = args and args[1] - if not profile_name then - --print("\nNo profile specified as argument.") - profile_name = select_profile() - end - - local data_to_write = get_profile_data(profile_name) - print("\n[+] Using profile: " .. profile_name) - - -- Display what will be written - print("\n[+] Data to be written:") - for addr, data in pairs(data_to_write) do - print(string.format("Address %d: %s", addr, data)) - end - - -- Step 1: Wipe the tag - print("\n[+] Wiping tag...") - send_command("lf em 4x05 wipe --4305") - - -- Step 2: Write data - print("\n[+] Writing data...") - for addr, data in pairs(data_to_write) do - send_command("lf em 4x05 write -a " .. addr .. " -d " .. data) - utils.Sleep(0.5) - end - - -- Step 3: Read back and display data for verification - print("\n[+] Verifying writes by reading back data...") - for addr, expected_data in pairs(data_to_write) do - local output = send_command("lf em 4x05 read -a " .. addr) - end - - print("\n[+] Read complete. Review output above.") -end - -main() diff --git a/client/luascripts/lf_awid_bulkclone.lua b/client/luascripts/lf_awid_bulkclone.lua index 3fa145ec2..0085a09c9 100644 --- a/client/luascripts/lf_awid_bulkclone.lua +++ b/client/luascripts/lf_awid_bulkclone.lua @@ -1,128 +1,128 @@ -local getopt = require('getopt') - - -copyright = '' -author = "TheChamp669" -version = 'v1.0.0' -desc = [[ -Perform bulk enrollment of 26 bit AWID style RFID Tags -For more info, check the comments in the code -]] -example = [[ - -- - script run lf_awid_bulkclone.lua -f 1 -b 1000 -]] -usage = [[ -script run lf_awid_bulkclone.lua -f facility -b base_id_num -]] -arguments = [[ - -h : this help - -f : facility id - -b : starting card id -]] -local DEBUG = true ---- --- A debug printout-function -local function dbg(args) - if not DEBUG then return end - if type(args) == 'table' then - local i = 1 - while args[i] do - dbg(args[i]) - i = i+1 - end - else - print('###', args) - end -end ---- --- This is only meant to be used when errors occur -local function oops(err) - print('ERROR:', err) - core.clearCommandBuffer() - return nil, errr -end ---- --- Usage help -local function help() - print(copyright) - print(author) - print(version) - print(desc) - print(ansicolors.cyan..'Usage'..ansicolors.reset) - print(usage) - print(ansicolors.cyan..'Arguments'..ansicolors.reset) - print(arguments) - print(ansicolors.cyan..'Example usage'..ansicolors.reset) - print(example) -end ---- --- Exit message -local function exitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() -end - -local function showHelp() - print("Usage: script run [-h]") - print("Options:") - print("-h \t This help") -end - -local function main(args) - - - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() - - if #args == 0 then return help() end - - for o, a in getopt.getopt(args, 'f:b:c:h') do - if o == 'h' then return help() end - if o == 'f' then - if isempty(a) then - print('You did not supply a facility code, using 255') - fc = 255 - else - fc = a - end - end - if o == 'b' then - if isempty(a) then - print('You did not supply a starting card number, using 59615') - cn = 59615 - else - cn = a - end - end - end - - -- Example starting values - local sessionStart = os.date("%Y_%m_%d_%H_%M_%S") -- Capture the session start time - - print("Session Start: " .. sessionStart) - print("Facility Code,Card Number") - - while true do - print(string.format("Preparing to Write: Facility Code %d, Card Number %d", fc, cn)) - - local command = string.format("lf awid clone --fmt 26 --fc %d --cn %d", fc, cn) - core.console(command) - - print(string.format("%d,%d", fc, cn)) - - print("Press Enter to continue with the next card number or type 'q' and press Enter to quit.") - local user_input = io.read() - - if user_input:lower() == 'q' then - break - else - cn = cn + 1 - end - end -end - +local getopt = require('getopt') + + +copyright = '' +author = "TheChamp669" +version = 'v1.0.0' +desc = [[ +Perform bulk enrollment of 26 bit AWID style RFID Tags +For more info, check the comments in the code +]] +example = [[ + -- + script run lf_awid_bulkclone.lua -f 1 -b 1000 +]] +usage = [[ +script run lf_awid_bulkclone.lua -f facility -b base_id_num +]] +arguments = [[ + -h : this help + -f : facility id + -b : starting card id +]] +local DEBUG = true +--- +-- A debug printout-function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print('###', args) + end +end +--- +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR:', err) + core.clearCommandBuffer() + return nil, errr +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print(ansicolors.cyan..'Usage'..ansicolors.reset) + print(usage) + print(ansicolors.cyan..'Arguments'..ansicolors.reset) + print(arguments) + print(ansicolors.cyan..'Example usage'..ansicolors.reset) + print(example) +end +--- +-- Exit message +local function exitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end + +local function showHelp() + print("Usage: script run [-h]") + print("Options:") + print("-h \t This help") +end + +local function main(args) + + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + if #args == 0 then return help() end + + for o, a in getopt.getopt(args, 'f:b:c:h') do + if o == 'h' then return help() end + if o == 'f' then + if isempty(a) then + print('You did not supply a facility code, using 255') + fc = 255 + else + fc = a + end + end + if o == 'b' then + if isempty(a) then + print('You did not supply a starting card number, using 59615') + cn = 59615 + else + cn = a + end + end + end + + -- Example starting values + local sessionStart = os.date("%Y_%m_%d_%H_%M_%S") -- Capture the session start time + + print("Session Start: " .. sessionStart) + print("Facility Code,Card Number") + + while true do + print(string.format("Preparing to Write: Facility Code %d, Card Number %d", fc, cn)) + + local command = string.format("lf awid clone --fmt 26 --fc %d --cn %d", fc, cn) + core.console(command) + + print(string.format("%d,%d", fc, cn)) + + print("Press Enter to continue with the next card number or type 'q' and press Enter to quit.") + local user_input = io.read() + + if user_input:lower() == 'q' then + break + else + cn = cn + 1 + end + end +end + main(args) diff --git a/client/luascripts/lf_electra.lua b/client/luascripts/lf_electra.lua index 2c130ba7a..5b0886aa4 100644 --- a/client/luascripts/lf_electra.lua +++ b/client/luascripts/lf_electra.lua @@ -145,7 +145,7 @@ local function readfile() local f = io.open(ID_STATUS, "r") for line in f:lines() do id = line:match"^(%x+)" - if id then break end + if id then break end end f:close() if not id then @@ -299,7 +299,7 @@ local function main(args) if answer == 'n' then core.console('clear') print( string.rep('--',39) ) - print(ac.red..' Aborted via keyboard!'..ac.reset) + print(ac.red..' USER ABORTED'..ac.reset) print( string.rep('--',39) ) break end diff --git a/client/luascripts/lf_em4100_bulk.lua b/client/luascripts/lf_em4100_bulk.lua index 8a2ff399e..87d8bc91b 100644 --- a/client/luascripts/lf_em4100_bulk.lua +++ b/client/luascripts/lf_em4100_bulk.lua @@ -198,7 +198,7 @@ local function main(args) core.console('lf em 410x reader') end else - print(ac.red..'aborted via keyboard!'..ac.reset) + print(ac.red..'User aborted'..ac.reset) low = i break end diff --git a/client/luascripts/lf_hid_bulkclone_v2.lua b/client/luascripts/lf_hid_bulkclone_v2.lua index 50762e8f1..33d084dd8 100644 --- a/client/luascripts/lf_hid_bulkclone_v2.lua +++ b/client/luascripts/lf_hid_bulkclone_v2.lua @@ -1,131 +1,131 @@ -local getopt = require('getopt') -local ansicolors = require('ansicolors') -local cmds = require('commands') - -copyright = '' -author = "TheChamop669" -version = 'v1.0.1' -desc = [[ -Perform bulk enrollment of 26 bit H10301 style RFID Tags -For more info, check the comments in the code -]] -example = [[ - -- - script run lf_hid_bulkclone_v2.lua -f 1 -b 1000 -]] -usage = [[ -script run lf_hid_bulkclone_v2.lua -f facility -b base_id_num -]] -arguments = [[ - -h : this help - -f : facility id - -b : starting card id -]] -local DEBUG = true ---- --- A debug printout-function -local function dbg(args) - if not DEBUG then return end - if type(args) == 'table' then - local i = 1 - while args[i] do - dbg(args[i]) - i = i+1 - end - else - print('###', args) - end -end ---- --- This is only meant to be used when errors occur -local function oops(err) - print('ERROR:', err) - core.clearCommandBuffer() - return nil, errr -end ---- --- Usage help -local function help() - print(copyright) - print(author) - print(version) - print(desc) - print(ansicolors.cyan..'Usage'..ansicolors.reset) - print(usage) - print(ansicolors.cyan..'Arguments'..ansicolors.reset) - print(arguments) - print(ansicolors.cyan..'Example usage'..ansicolors.reset) - print(example) -end ---- --- Exit message -local function exitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() -end - -local function main(args) - - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() - - if #args == 0 then return help() end - - for o, a in getopt.getopt(args, 'f:b:h') do - if o == 'h' then return help() end - if o == 'f' then - if isempty(a) then - print('You did not supply a facility code, using 0') - fc = 10 - else - fc = a - end - end - if o == 'b' then - if isempty(a) then - print('You did not supply a starting card number, using 1000') - cn = 1000 - else - cn = a - end - end - end - - local successful_writes = {} - local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time()) - - while true do - print(string.format("Writing Facility Code: %d, Card Number: %d", fc, cn)) - - local command = string.format("lf hid clone -w H10301 --fc %d --cn %d", fc, cn) - core.console(command) - - table.insert(successful_writes, string.format("%d,%d", fc, cn)) - - print("Press Enter to write the next card, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.") - local user_input = io.read() - - if user_input:lower() == 'q' then - print("Timestamp: ", timestamp) - print("Successful Writes:") - for _, v in ipairs(successful_writes) do print(v) end - break - elseif user_input:lower() ~= 'r' then - cn = cn + 1 - end - end -end - -main(args) - ---[[ -Notes: -1. The `lf hid clone` command is used to write HID formatted data to T5577 cards, using the H10301 format. -2. The script prompts the user for the initial facility code and card number at the start of the session. -3. Users can continue to write to the next card, retry the current write, or quit the session by responding to the prompts. -4. Upon quitting, the script prints all successful writes along with a timestamp. -5. Password-related features have been removed in this version of the script as they are not supported by the `lf hid clone` command. -]] +local getopt = require('getopt') +local ansicolors = require('ansicolors') +local cmds = require('commands') + +copyright = '' +author = "TheChamop669" +version = 'v1.0.1' +desc = [[ +Perform bulk enrollment of 26 bit H10301 style RFID Tags +For more info, check the comments in the code +]] +example = [[ + -- + script run lf_hid_bulkclone_v2.lua -f 1 -b 1000 +]] +usage = [[ +script run lf_hid_bulkclone_v2.lua -f facility -b base_id_num +]] +arguments = [[ + -h : this help + -f : facility id + -b : starting card id +]] +local DEBUG = true +--- +-- A debug printout-function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print('###', args) + end +end +--- +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR:', err) + core.clearCommandBuffer() + return nil, errr +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print(ansicolors.cyan..'Usage'..ansicolors.reset) + print(usage) + print(ansicolors.cyan..'Arguments'..ansicolors.reset) + print(arguments) + print(ansicolors.cyan..'Example usage'..ansicolors.reset) + print(example) +end +--- +-- Exit message +local function exitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end + +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + if #args == 0 then return help() end + + for o, a in getopt.getopt(args, 'f:b:h') do + if o == 'h' then return help() end + if o == 'f' then + if isempty(a) then + print('You did not supply a facility code, using 0') + fc = 10 + else + fc = a + end + end + if o == 'b' then + if isempty(a) then + print('You did not supply a starting card number, using 1000') + cn = 1000 + else + cn = a + end + end + end + + local successful_writes = {} + local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time()) + + while true do + print(string.format("Writing Facility Code: %d, Card Number: %d", fc, cn)) + + local command = string.format("lf hid clone -w H10301 --fc %d --cn %d", fc, cn) + core.console(command) + + table.insert(successful_writes, string.format("%d,%d", fc, cn)) + + print("Press Enter to write the next card, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.") + local user_input = io.read() + + if user_input:lower() == 'q' then + print("Timestamp: ", timestamp) + print("Successful Writes:") + for _, v in ipairs(successful_writes) do print(v) end + break + elseif user_input:lower() ~= 'r' then + cn = cn + 1 + end + end +end + +main(args) + +--[[ +Notes: +1. The `lf hid clone` command is used to write HID formatted data to T5577 cards, using the H10301 format. +2. The script prompts the user for the initial facility code and card number at the start of the session. +3. Users can continue to write to the next card, retry the current write, or quit the session by responding to the prompts. +4. Upon quitting, the script prints all successful writes along with a timestamp. +5. Password-related features have been removed in this version of the script as they are not supported by the `lf hid clone` command. +]] diff --git a/client/luascripts/lf_ioprox_bulkclone.lua b/client/luascripts/lf_ioprox_bulkclone.lua index 31fb91e76..46e33c63a 100644 --- a/client/luascripts/lf_ioprox_bulkclone.lua +++ b/client/luascripts/lf_ioprox_bulkclone.lua @@ -1,125 +1,125 @@ -local getopt = require('getopt') -local cmds = require('commands') - - -copyright = '' -author = "TheChamp669" -version = 'v1.0.0' -desc = [[ -Perform bulk enrollment of 26 bit IO Prox / Kantech style RFID Tags -The vnc is set to 2. -For more info, check the comments in the code -]] -example = [[ - -- - script run lf_ioprox_bulkclone.lua -f 1 -b 1000 -]] -usage = [[ -script run lf_ioprox_bulkclone.lua -f facility -b base_id_num -]] -arguments = [[ - -h : this help - -f : facility id - -b : starting card id -]] -local DEBUG = true - ---- --- A debug printout-function -local function dbg(args) - if not DEBUG then return end - if type(args) == 'table' then - local i = 1 - while args[i] do - dbg(args[i]) - i = i+1 - end - else - print('###', args) - end -end ---- --- This is only meant to be used when errors occur -local function oops(err) - print('ERROR:', err) - core.clearCommandBuffer() - return nil, errr -end ---- --- Usage help -local function help() - print(copyright) - print(author) - print(version) - print(desc) - print(ansicolors.cyan..'Usage'..ansicolors.reset) - print(usage) - print(ansicolors.cyan..'Arguments'..ansicolors.reset) - print(arguments) - print(ansicolors.cyan..'Example usage'..ansicolors.reset) - print(example) -end ---- --- Exit message -local function exitMsg(msg) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print(msg) - print() -end - -local function main(args) - - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() - - if #args == 0 then return help() end - - for o, a in getopt.getopt(args, 'f:b:h') do - if o == 'h' then return help() end - if o == 'f' then - if isempty(a) then - print('You did not supply a facility code, using 0') - fc = 0 - else - fc = a - end - end - if o == 'b' then - if isempty(a) then return oops('You must supply the flag -b (starting card number)') end - cn = a - end - end - - local successful_writes = {} - local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time()) - - while true do - print(string.format("Setting fob to Facility Code: %d, Card Number: %d", fc, cn)) - - -- Writing to block 0 with the specific data for ioProx card format - core.console("lf t55xx write -b 0 -d 00147040") - - -- Command to set facility code and card number on the fob - local command = string.format("lf io clone --vn 2 --fc %d --cn %d", fc, cn) - core.console(command) - - table.insert(successful_writes, string.format("%d,%d", fc, cn)) - print("Fob created successfully.") - - print("Press Enter to create the next fob, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.") - local user_input = io.read() - - if user_input:lower() == 'q' then - print("Timestamp: ", timestamp) - print("Successful Writes:") - for _, v in ipairs(successful_writes) do print(v) end - break - elseif user_input:lower() ~= 'r' then - cn = cn + 1 - end - end -end - -main(args) +local getopt = require('getopt') +local cmds = require('commands') + + +copyright = '' +author = "TheChamp669" +version = 'v1.0.0' +desc = [[ +Perform bulk enrollment of 26 bit IO Prox / Kantech style RFID Tags +The vnc is set to 2. +For more info, check the comments in the code +]] +example = [[ + -- + script run lf_ioprox_bulkclone.lua -f 1 -b 1000 +]] +usage = [[ +script run lf_ioprox_bulkclone.lua -f facility -b base_id_num +]] +arguments = [[ + -h : this help + -f : facility id + -b : starting card id +]] +local DEBUG = true + +--- +-- A debug printout-function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print('###', args) + end +end +--- +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR:', err) + core.clearCommandBuffer() + return nil, errr +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print(ansicolors.cyan..'Usage'..ansicolors.reset) + print(usage) + print(ansicolors.cyan..'Arguments'..ansicolors.reset) + print(arguments) + print(ansicolors.cyan..'Example usage'..ansicolors.reset) + print(example) +end +--- +-- Exit message +local function exitMsg(msg) + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print(msg) + print() +end + +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + if #args == 0 then return help() end + + for o, a in getopt.getopt(args, 'f:b:h') do + if o == 'h' then return help() end + if o == 'f' then + if isempty(a) then + print('You did not supply a facility code, using 0') + fc = 0 + else + fc = a + end + end + if o == 'b' then + if isempty(a) then return oops('You must supply the flag -b (starting card number)') end + cn = a + end + end + + local successful_writes = {} + local timestamp = os.date('%Y-%m-%d %H:%M:%S', os.time()) + + while true do + print(string.format("Setting fob to Facility Code: %d, Card Number: %d", fc, cn)) + + -- Writing to block 0 with the specific data for ioProx card format + core.console("lf t55xx write -b 0 -d 00147040") + + -- Command to set facility code and card number on the fob + local command = string.format("lf io clone --vn 2 --fc %d --cn %d", fc, cn) + core.console(command) + + table.insert(successful_writes, string.format("%d,%d", fc, cn)) + print("Fob created successfully.") + + print("Press Enter to create the next fob, type 'r' and press Enter to retry, or type 'q' and press Enter to quit.") + local user_input = io.read() + + if user_input:lower() == 'q' then + print("Timestamp: ", timestamp) + print("Successful Writes:") + for _, v in ipairs(successful_writes) do print(v) end + break + elseif user_input:lower() ~= 'r' then + cn = cn + 1 + end + end +end + +main(args) diff --git a/client/luascripts/lf_t55xx_fix.lua b/client/luascripts/lf_t55xx_fix.lua index b793cf629..cfdffc8f0 100644 --- a/client/luascripts/lf_t55xx_fix.lua +++ b/client/luascripts/lf_t55xx_fix.lua @@ -18,7 +18,7 @@ desc = [[ is found, it uses the wipe command to erase the T5577. Then the reanimation procedure is applied. If the password is not found or doesn't exist the script only performs the reanimation procedure. The script revives 99% of blocked tags. - ]] +]] usage = [[ script run lf_t55xx_fix ]] @@ -87,7 +87,7 @@ local function reanimate_t5577(password) p:console('lf t55 wipe -p ' .. password) print("T5577 wiped using a password: " ..ac.green.. password ..ac.reset) else - print(ac.yellow.." No valid password found, proceeding with reanimation."..ac.reset) + print(ac.yellow.."No valid password found, proceeding with reanimation."..ac.reset) end p:console('lf t55 write -b 0 -d 000880E8 -p 00000000') diff --git a/client/luascripts/paxton_clone.lua b/client/luascripts/paxton_clone.lua index 5e9076c9f..fd3beb280 100644 --- a/client/luascripts/paxton_clone.lua +++ b/client/luascripts/paxton_clone.lua @@ -1,497 +1,488 @@ -local getopt = require('getopt') -local utils = require('utils') -local ac = require('ansicolors') -local os = require('os') -local dash = string.rep('--', 32) -local dir = os.getenv('HOME') .. '/.proxmark3/logs/' -local logfilecmd - ---Determine platform for logfile handling (Windows vs Unix/Linux) -if package.config:sub(1,1) == "\\" then - logfilecmd = 'dir /a-d /o-d /tw /b/s "' .. dir .. '" 2>nul:' -else - logfilecmd = 'find "' .. dir .. '" -type f -printf "%T@ %p\\n" | sort -nr | cut -d" " -f2-' -end - -local logfile = (io.popen(logfilecmd):read("*a"):match("%C+")) -local log_file_path = dir .. "Paxton_log.txt" -local nam = "" -local pm3 = require('pm3') -p = pm3.pm3() -local command = core.console -command('clear') - -author = ' Author: jareckib - 30.01.2025' -tutorial = ' Based on Equipter tutorial - Downgrade Paxton to EM4102' -version = ' version v1.20' -desc = [[ - The script automates the copying of Paxton fobs read - write. - It also allows manual input of data for blocks 4-7. - The third option is reading data stored in the log file and create new fob. - Additionally, the script calculates the ID for downgrading Paxton to EM4102. - - ]] -usage = [[ - script run paxton_clone -]] -arguments = [[ - script run paxton_clone -h : this help -]] - -local debug = true - -local function dbg(args) - if not DEBUG then return end - if type(args) == 'table' then - local i = 1 - while args[i] do - dbg(args[i]) - i = i+1 - end - else - print('###', args) - end -end - -local function help() - print() - print(author) - print(tutorial) - print(version) - print(desc) - print(ac.cyan..' Usage'..ac.reset) - print(usage) - print(ac.cyan..' Arguments'..ac.reset) - print(arguments) -end - -local function reset_log_file() - local file = io.open(logfile, "w+") - file:write("") - file:close() -end - -local function read_log_file(logfile) - local file = io.open(logfile, "r") - if not file then - error(" Could not open the file") - end - local content = file:read("*all") - file:close() - return content -end - -local function parse_blocks(result) - local blocks = {} - for line in result:gmatch("[^\r\n]+") do - local block_num, block_data = line:match("%[%=%]%s+%d/0x0([4-7])%s+%|%s+([0-9A-F ]+)") - if block_num and block_data then - block_num = tonumber(block_num) - block_data = block_data:gsub("%s+", "") - blocks[block_num] = block_data - end - end - return blocks -end - -local function hex_to_bin(hex_string) - local bin_string = "" - local hex_to_bin_map = { - ['0'] = "0000", ['1'] = "0001", ['2'] = "0010", ['3'] = "0011", - ['4'] = "0100", ['5'] = "0101", ['6'] = "0110", ['7'] = "0111", - ['8'] = "1000", ['9'] = "1001", ['A'] = "1010", ['B'] = "1011", - ['C'] = "1100", ['D'] = "1101", ['E'] = "1110", ['F'] = "1111" - } - for i = 1, #hex_string do - bin_string = bin_string .. hex_to_bin_map[hex_string:sub(i, i)] - end - return bin_string -end - -local function remove_last_two_bits(binary_str) - return binary_str:sub(1, #binary_str - 2) -end - -local function split_into_5bit_chunks(binary_str) - local chunks = {} - for i = 1, #binary_str, 5 do - table.insert(chunks, binary_str:sub(i, i + 4)) - end - return chunks -end - -local function remove_parity_bit(chunks) - local no_parity_chunks = {} - for _, chunk in ipairs(chunks) do - if #chunk == 5 then - table.insert(no_parity_chunks, chunk:sub(2)) - end - end - return no_parity_chunks -end - -local function convert_to_hex(chunks) - local hex_values = {} - for _, chunk in ipairs(chunks) do - if #chunk > 0 then - table.insert(hex_values, string.format("%X", tonumber(chunk, 2))) - end - end - return hex_values -end - -local function convert_to_decimal(chunks) - local decimal_values = {} - for _, chunk in ipairs(chunks) do - table.insert(decimal_values, tonumber(chunk, 2)) - end - return decimal_values -end - -local function find_until_before_f(hex_values) - local result = {} - for _, value in ipairs(hex_values) do - if value == 'F' then - break - end - table.insert(result, value) - end - return result -end - -local function process_block(block) - local binary_str = hex_to_bin(block) - binary_str = remove_last_two_bits(binary_str) - local chunks = split_into_5bit_chunks(binary_str) - local no_parity_chunks = remove_parity_bit(chunks) - return no_parity_chunks -end - -local function calculate_id_net(blocks) - local all_hex_values = {} - for _, block in ipairs(blocks) do - local hex_values = convert_to_hex(process_block(block)) - for _, hex in ipairs(hex_values) do - table.insert(all_hex_values, hex) - end - end - local selected_hex_values = find_until_before_f(all_hex_values) - if #selected_hex_values == 0 then - error(ac.red..' Error: '..ac.reset..'No valid data found in blocks 4 and 5') - end - local combined_hex = table.concat(selected_hex_values) - if not combined_hex:match("^%x+$") then - error(ac.red..' Error: '..ac.reset..'Invalid data in blocks 4 and 5') - end - local decimal_id = tonumber(combined_hex) - local stripped_hex_id = string.format("%X", decimal_id) - local padded_hex_id = string.format("%010X", decimal_id) - return decimal_id, padded_hex_id -end - -local function calculate_id_switch(blocks) - local all_decimal_values = {} - for _, block in ipairs(blocks) do - local decimal_values = convert_to_decimal(process_block(block)) - for _, dec in ipairs(decimal_values) do - table.insert(all_decimal_values, dec) - end - end - if #all_decimal_values < 15 then - error(ac.red..' Error:'..ac.reset..' Not enough data after processing blocks 4, 5, 6, and 7') - end - local id_positions = {9, 11, 13, 15, 2, 4, 6, 8} - local id_numbers = {} - for _, pos in ipairs(id_positions) do - table.insert(id_numbers, all_decimal_values[pos]) - end - local decimal_id = tonumber(table.concat(id_numbers)) - local padded_hex_id = string.format("%010X", decimal_id) - return decimal_id, padded_hex_id -end - -local function name_exists_in_log(name) - local file = io.open(log_file_path, "r") - if not file then - return false - end - local pattern = "^Name:%s*" .. name .. "%s*$" - for line in file:lines() do - if line:match(pattern) then - file:close() - return true - end - end - file:close() - return false -end - -local function log_result(blocks, em410_id, name) - local log_file = io.open(log_file_path, "a") - if log_file then - log_file:write("Name: " .. name .. "\n") - log_file:write("Date: ", os.date("%Y-%m-%d %H:%M:%S"), "\n") - for i = 4, 7 do - log_file:write(string.format("Block %d: %s\n", i, blocks[i] or "nil")) - end - log_file:write(string.format('EM4102 ID: %s\n', em410_id or "nil")) - log_file:write('--------------------------\n') - log_file:close() - print(' Log saved as: pm3/.proxmark3/logs/' ..ac.yellow..' Paxton_log.txt'..ac.reset) - else - print(" Failed to open log file for writing.") - end -end - -local function verify_written_data(original_blocks) - p:console('lf hitag read --ht2 -k BDF5E846') - local result = read_log_file(logfile) - local verified_blocks = parse_blocks(result) - local success = true - for i = 4, 7 do - if original_blocks[i] ~= verified_blocks[i] then - print(' Verification failed.. Block '..ac.green.. i ..ac.reset.. ' inconsistent.') - success = false - end - end - - if success then - print(ac.green..' Verification successful. Data was written correctly.' .. ac.reset) - else - print(ac.yellow.. ' Adjust the position of the Paxton fob on the coil.' .. ac.reset) - end -end - -local function handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3) - while true do - io.write(" Create Paxton choose " .. ac.cyan .. "1" .. ac.reset .. " or EM4102 choose " .. ac.cyan .. "2 " .. ac.reset) - local choice = io.read() - if choice == "1" then - io.write(" Place the" .. ac.cyan .. " Paxton " .. ac.reset .. "Fob on the coil to write.." .. ac.green .. " ENTER " .. ac.reset .. "to continue..") - io.read() - print(dash) - p:console("lf hitag wrbl --ht2 -p 4 -d " .. blocks[4] .. " -k BDF5E846") - p:console("lf hitag wrbl --ht2 -p 5 -d " .. blocks[5] .. " -k BDF5E846") - p:console("lf hitag wrbl --ht2 -p 6 -d " .. blocks[6] .. " -k BDF5E846") - p:console("lf hitag wrbl --ht2 -p 7 -d " .. blocks[7] .. " -k BDF5E846") - reset_log_file() - --timer(5) - verify_written_data(blocks) - elseif choice == "2" then - io.write(" Place the" .. ac.cyan .. " T5577 " .. ac.reset .. "tag on the coil and press" .. ac.green .. " ENTER " .. ac.reset .. "to continue..") - io.read() - p:console("lf em 410x clone --id " .. padded_hex_id) - print(' Cloned EM4102 to T5577 with ID ' ..ac.green.. padded_hex_id ..ac.reset) - else - print(ac.yellow .. " Invalid choice." .. ac.reset .. " Please enter " .. ac.cyan .. "1" .. ac.reset .. " or " .. ac.cyan .. "2" .. ac.reset) - goto ask_again - end - while true do - print(dash) - io.write(" Make next RFID Fob"..ac.cyan.." (y/n) "..ac.reset) - local another = io.read() - if another:lower() == "n" then - if was_option_3 then - print(" No writing to Paxton_log.txt - Name: " ..ac.green.. nam .. ac.reset.. " exist") - return - end - print() - print(ac.green .. " Saving Paxton_log file..." .. ac.reset) - while true do - io.write(" Enter a name for database (cannot be empty/duplicate): "..ac.yellow) - name = io.read() - io.write(ac.reset..'') - if name == nil or name:match("^%s*$") then - print(ac.red .. ' ERROR:'..ac.reset..' Name cannot be empty.') - else - if name_exists_in_log(name) then - print(ac.yellow .. ' Name exists!!! '..ac.reset.. 'Please choose a different name.') - else - break - end - end - end - log_result(blocks, padded_hex_id, name) - print(ac.green .. " Log saved successfully!" .. ac.reset) - reset_log_file() - return - elseif another:lower() == "y" then - goto ask_again - else - print(ac.yellow.." Invalid response."..ac.reset.." Please enter"..ac.cyan.." y"..ac.reset.." or"..ac.cyan.." n"..ac.reset) - end - end - ::ask_again:: - end -end - -local function is_valid_hex(input) - return #input == 8 and input:match("^[0-9A-Fa-f]+$") -end - -local function main(args) - while true do - for o, a in getopt.getopt(args, 'h') do - if o == 'h' then return help() end - end - command('clear') - print(dash) - print(ac.green .. ' Select option: ' .. ac.reset) - print(ac.cyan .. ' 1' .. ac.reset .. ' - Read Paxton blocks 4-7 to make a copy') - print(ac.cyan .. ' 2' .. ac.reset .. ' - Manually input data for Paxton blocks 4-7') - print(ac.cyan .. " 3" .. ac.reset .. " - Search in Paxton_log by name and use the data") - print(dash) - while true do - io.write(' Your choice '..ac.cyan..'(1/2/3): ' .. ac.reset) - input_option = io.read() - if input_option == "1" or input_option == "2" or input_option == "3" then - break - else - print(ac.yellow .. ' Invalid choice.' .. ac.reset .. ' Please enter ' .. ac.cyan .. '1' .. ac.reset .. ' or ' .. ac.cyan .. '2' .. ac.reset..' or'..ac.cyan..' 3'..ac.reset) - end - end - local was_option_3 = false - if input_option == "1" then - local show_place_message = true - while true do - if show_place_message then - io.write(' Place the' .. ac.cyan .. ' Paxton' .. ac.reset .. ' Fob on the coil to read..' .. ac.green .. 'ENTER' .. ac.reset .. ' to continue..') - end - io.read() - print(dash) - p:console('lf hitag read --ht2 -k BDF5E846') - if not logfile then - error(" No files in this directory") - end - local result = read_log_file(logfile) - local blocks = parse_blocks(result) - local empty_block = false - for i = 4, 7 do - if not blocks[i] then - empty_block = true - break - end - end - if empty_block then - io.write(ac.yellow .. ' Adjust the Fob position on the coil.' .. ac.reset .. ' Press' .. ac.green .. ' ENTER' .. ac.reset .. ' to continue..') - show_place_message = false - else - print(' Readed blocks:') - print() - for i = 4, 7 do - if blocks[i] then - print(string.format(" Block %d: %s%s%s", i, ac.yellow, blocks[i], ac.reset)) - end - end - local decimal_id, padded_hex_id - if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then - print(dash) - print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset) - decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]}) - else - print(dash) - print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset) - decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]}) - end - print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset)) - print(dash) - handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3) - break - end - end - elseif input_option == "2" then - local blocks = {} - for i = 4, 7 do - while true do - io.write(ac.reset..' Enter data for block ' .. i .. ': ' .. ac.yellow) - local input = io.read() - input = input:upper() - if is_valid_hex(input) then - blocks[i] = input - break - else - print(ac.yellow .. ' Invalid input.' .. ac.reset .. ' Each block must be 4 bytes (8 hex characters).') - end - end - end - local decimal_id, padded_hex_id - if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then - print(ac.reset.. dash) - print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset) - decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]}) - else - print(ac.reset.. dash) - print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset) - decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]}) - end - print(dash) - print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset)) - print(dash) - if not padded_hex_id then - print(ac.red..' ERROR: '..ac.reset.. 'Invalid block data provided') - return - end - handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3) - break - elseif input_option == "3" then - was_option_3 = true - local retries = 3 - while retries > 0 do - io.write(' Enter the name to search ('..retries..' attempts) : '..ac.yellow) - local user_input = io.read() - io.write(ac.reset..'') - if user_input == nil or user_input:match("^%s*$") then - print(ac.yellow..' Error: '..ac.reset.. 'Empty name !!!') - end - local name_clean = "^Name:%s*" .. user_input:gsub("%s", "%%s") .. "%s*$" - local file = io.open(log_file_path, "r") - if not file then - print(ac.red .. ' Error:'..ac.reset.. 'Could not open log file.') - return - end - local lines = {} - for line in file:lines() do - table.insert(lines, line) - end - file:close() - local found = false - for i = 1, #lines do - if lines[i]:match(name_clean) then - nam = user_input - local blocks = { - [4] = lines[i + 2]:match("Block 4: (.+)"), - [5] = lines[i + 3]:match("Block 5: (.+)"), - [6] = lines[i + 4]:match("Block 6: (.+)"), - [7] = lines[i + 5]:match("Block 7: (.+)") - } - local em4102_id = lines[i + 6]:match("EM4102 ID: (.+)") - print(dash) - print(' I found the data under the name: '..ac.yellow ..nam.. ac.reset) - for j = 4, 7 do - print(string.format(" Block %d: %s%s%s", j, ac.yellow, blocks[j] or "N/A", ac.reset)) - end - print(" EM4102 ID: " .. ac.green .. (em4102_id or "N/A") .. ac.reset) - print(dash) - local decimal_id, padded_hex_id = em4102_id, em4102_id - handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3, nam) - found = true - break - end - end - if not found then - retries = retries - 1 - else - break - end - end - if retries == 0 then - print(ac.yellow .. " Name not found after 3 attempts." .. ac.reset) - end - end - print(dash) - print(' Exiting script Lua...') - return - end -end - +local getopt = require('getopt') +local utils = require('utils') +local ac = require('ansicolors') +local os = require('os') +local dash = string.rep('--', 32) +local dir = os.getenv('HOME') .. '/.proxmark3/logs/' +local logfile = (io.popen('dir /a-d /o-d /tw /b/s "' .. dir .. '" 2>nul:'):read("*a"):match("%C+")) +local log_file_path = dir .. "Paxton_log.txt" +local nam = "" +local pm3 = require('pm3') +p = pm3.pm3() +local command = core.console +command('clear') + +author = ' Author: jareckib - 30.01.2025' +tutorial = ' Based on Equipter tutorial - Downgrade Paxton to EM4102' +version = ' version v1.20' +desc = [[ + The script automates the copying of Paxton fobs read - write. + It also allows manual input of data for blocks 4-7. + The third option is reading data stored in the log file and create new fob. + Additionally, the script calculates the ID for downgrading Paxton to EM4102. + + ]] +usage = [[ + script run paxton_clone +]] +arguments = [[ + script run paxton_clone -h : this help +]] + +local debug = true + +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print('###', args) + end +end + +local function help() + print() + print(author) + print(tutorial) + print(version) + print(desc) + print(ac.cyan..' Usage'..ac.reset) + print(usage) + print(ac.cyan..' Arguments'..ac.reset) + print(arguments) +end + +local function reset_log_file() + local file = io.open(logfile, "w+") + file:write("") + file:close() +end + +local function read_log_file(logfile) + local file = io.open(logfile, "r") + if not file then + error(" Could not open the file") + end + local content = file:read("*all") + file:close() + return content +end + +local function parse_blocks(result) + local blocks = {} + for line in result:gmatch("[^\r\n]+") do + local block_num, block_data = line:match("%[%=%]%s+%d/0x0([4-7])%s+%|%s+([0-9A-F ]+)") + if block_num and block_data then + block_num = tonumber(block_num) + block_data = block_data:gsub("%s+", "") + blocks[block_num] = block_data + end + end + return blocks +end + +local function hex_to_bin(hex_string) + local bin_string = "" + local hex_to_bin_map = { + ['0'] = "0000", ['1'] = "0001", ['2'] = "0010", ['3'] = "0011", + ['4'] = "0100", ['5'] = "0101", ['6'] = "0110", ['7'] = "0111", + ['8'] = "1000", ['9'] = "1001", ['A'] = "1010", ['B'] = "1011", + ['C'] = "1100", ['D'] = "1101", ['E'] = "1110", ['F'] = "1111" + } + for i = 1, #hex_string do + bin_string = bin_string .. hex_to_bin_map[hex_string:sub(i, i)] + end + return bin_string +end + +local function remove_last_two_bits(binary_str) + return binary_str:sub(1, #binary_str - 2) +end + +local function split_into_5bit_chunks(binary_str) + local chunks = {} + for i = 1, #binary_str, 5 do + table.insert(chunks, binary_str:sub(i, i + 4)) + end + return chunks +end + +local function remove_parity_bit(chunks) + local no_parity_chunks = {} + for _, chunk in ipairs(chunks) do + if #chunk == 5 then + table.insert(no_parity_chunks, chunk:sub(2)) + end + end + return no_parity_chunks +end + +local function convert_to_hex(chunks) + local hex_values = {} + for _, chunk in ipairs(chunks) do + if #chunk > 0 then + table.insert(hex_values, string.format("%X", tonumber(chunk, 2))) + end + end + return hex_values +end + +local function convert_to_decimal(chunks) + local decimal_values = {} + for _, chunk in ipairs(chunks) do + table.insert(decimal_values, tonumber(chunk, 2)) + end + return decimal_values +end + +local function find_until_before_f(hex_values) + local result = {} + for _, value in ipairs(hex_values) do + if value == 'F' then + break + end + table.insert(result, value) + end + return result +end + +local function process_block(block) + local binary_str = hex_to_bin(block) + binary_str = remove_last_two_bits(binary_str) + local chunks = split_into_5bit_chunks(binary_str) + local no_parity_chunks = remove_parity_bit(chunks) + return no_parity_chunks +end + +local function calculate_id_net(blocks) + local all_hex_values = {} + for _, block in ipairs(blocks) do + local hex_values = convert_to_hex(process_block(block)) + for _, hex in ipairs(hex_values) do + table.insert(all_hex_values, hex) + end + end + local selected_hex_values = find_until_before_f(all_hex_values) + if #selected_hex_values == 0 then + error(ac.red..' Error: '..ac.reset..'No valid data found in blocks 4 and 5') + end + local combined_hex = table.concat(selected_hex_values) + if not combined_hex:match("^%x+$") then + error(ac.red..' Error: '..ac.reset..'Invalid data in blocks 4 and 5') + end + local decimal_id = tonumber(combined_hex) + local stripped_hex_id = string.format("%X", decimal_id) + local padded_hex_id = string.format("%010X", decimal_id) + return decimal_id, padded_hex_id +end + +local function calculate_id_switch(blocks) + local all_decimal_values = {} + for _, block in ipairs(blocks) do + local decimal_values = convert_to_decimal(process_block(block)) + for _, dec in ipairs(decimal_values) do + table.insert(all_decimal_values, dec) + end + end + if #all_decimal_values < 15 then + error(ac.red..' Error:'..ac.reset..' Not enough data after processing blocks 4, 5, 6, and 7') + end + local id_positions = {9, 11, 13, 15, 2, 4, 6, 8} + local id_numbers = {} + for _, pos in ipairs(id_positions) do + table.insert(id_numbers, all_decimal_values[pos]) + end + local decimal_id = tonumber(table.concat(id_numbers)) + local padded_hex_id = string.format("%010X", decimal_id) + return decimal_id, padded_hex_id +end + +local function name_exists_in_log(name) + local file = io.open(log_file_path, "r") + if not file then + return false + end + local pattern = "^Name:%s*" .. name .. "%s*$" + for line in file:lines() do + if line:match(pattern) then + file:close() + return true + end + end + file:close() + return false +end + +local function log_result(blocks, em410_id, name) + local log_file = io.open(log_file_path, "a") + if log_file then + log_file:write("Name: " .. name .. "\n") + log_file:write("Date: ", os.date("%Y-%m-%d %H:%M:%S"), "\n") + for i = 4, 7 do + log_file:write(string.format("Block %d: %s\n", i, blocks[i] or "nil")) + end + log_file:write(string.format('EM4102 ID: %s\n', em410_id or "nil")) + log_file:write('--------------------------\n') + log_file:close() + print(' Log saved as: pm3/.proxmark3/logs/' ..ac.yellow..' Paxton_log.txt'..ac.reset) + else + print(" Failed to open log file for writing.") + end +end + +local function verify_written_data(original_blocks) + p:console('lf hitag read --ht2 -k BDF5E846') + local result = read_log_file(logfile) + local verified_blocks = parse_blocks(result) + local success = true + for i = 4, 7 do + if original_blocks[i] ~= verified_blocks[i] then + print(' Verification failed.. Block '..ac.green.. i ..ac.reset.. ' inconsistent.') + success = false + end + end + + if success then + print(ac.green..' Verification successful. Data was written correctly.' .. ac.reset) + else + print(ac.yellow.. ' Adjust the position of the Paxton fob on the coil.' .. ac.reset) + end +end + +local function handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3) + while true do + io.write(" Create Paxton choose " .. ac.cyan .. "1" .. ac.reset .. " or EM4102 choose " .. ac.cyan .. "2 " .. ac.reset) + local choice = io.read() + if choice == "1" then + io.write(" Place the" .. ac.cyan .. " Paxton " .. ac.reset .. "Fob on the coil to write.." .. ac.green .. " ENTER " .. ac.reset .. "to continue..") + io.read() + print(dash) + p:console("lf hitag wrbl --ht2 -p 4 -d " .. blocks[4] .. " -k BDF5E846") + p:console("lf hitag wrbl --ht2 -p 5 -d " .. blocks[5] .. " -k BDF5E846") + p:console("lf hitag wrbl --ht2 -p 6 -d " .. blocks[6] .. " -k BDF5E846") + p:console("lf hitag wrbl --ht2 -p 7 -d " .. blocks[7] .. " -k BDF5E846") + reset_log_file() + --timer(5) + verify_written_data(blocks) + elseif choice == "2" then + io.write(" Place the" .. ac.cyan .. " T5577 " .. ac.reset .. "tag on the coil and press" .. ac.green .. " ENTER " .. ac.reset .. "to continue..") + io.read() + p:console("lf em 410x clone --id " .. padded_hex_id) + print(' Cloned EM4102 to T5577 with ID ' ..ac.green.. padded_hex_id ..ac.reset) + else + print(ac.yellow .. " Invalid choice." .. ac.reset .. " Please enter " .. ac.cyan .. "1" .. ac.reset .. " or " .. ac.cyan .. "2" .. ac.reset) + goto ask_again + end + while true do + print(dash) + io.write(" Make next RFID Fob"..ac.cyan.." (y/n) "..ac.reset) + local another = io.read() + if another:lower() == "n" then + if was_option_3 then + print(" No writing to Paxton_log.txt - Name: " ..ac.green.. nam .. ac.reset.. " exist") + return + end + print() + print(ac.green .. " Saving Paxton_log file..." .. ac.reset) + while true do + io.write(" Enter a name for database (cannot be empty/duplicate): "..ac.yellow) + name = io.read() + io.write(ac.reset..'') + if name == nil or name:match("^%s*$") then + print(ac.red .. ' ERROR:'..ac.reset..' Name cannot be empty.') + else + if name_exists_in_log(name) then + print(ac.yellow .. ' Name exists!!! '..ac.reset.. 'Please choose a different name.') + else + break + end + end + end + log_result(blocks, padded_hex_id, name) + print(ac.green .. " Log saved successfully!" .. ac.reset) + reset_log_file() + return + elseif another:lower() == "y" then + goto ask_again + else + print(ac.yellow.." Invalid response."..ac.reset.." Please enter"..ac.cyan.." y"..ac.reset.." or"..ac.cyan.." n"..ac.reset) + end + end + ::ask_again:: + end +end + +local function is_valid_hex(input) + return #input == 8 and input:match("^[0-9A-Fa-f]+$") +end + +local function main(args) + while true do + for o, a in getopt.getopt(args, 'h') do + if o == 'h' then return help() end + end + command('clear') + print(dash) + print(ac.green .. ' Select option: ' .. ac.reset) + print(ac.cyan .. ' 1' .. ac.reset .. ' - Read Paxton blocks 4-7 to make a copy') + print(ac.cyan .. ' 2' .. ac.reset .. ' - Manually input data for Paxton blocks 4-7') + print(ac.cyan .. " 3" .. ac.reset .. " - Search in Paxton_log by name and use the data") + print(dash) + while true do + io.write(' Your choice '..ac.cyan..'(1/2/3): ' .. ac.reset) + input_option = io.read() + if input_option == "1" or input_option == "2" or input_option == "3" then + break + else + print(ac.yellow .. ' Invalid choice.' .. ac.reset .. ' Please enter ' .. ac.cyan .. '1' .. ac.reset .. ' or ' .. ac.cyan .. '2' .. ac.reset..' or'..ac.cyan..' 3'..ac.reset) + end + end + local was_option_3 = false + if input_option == "1" then + local show_place_message = true + while true do + if show_place_message then + io.write(' Place the' .. ac.cyan .. ' Paxton' .. ac.reset .. ' Fob on the coil to read..' .. ac.green .. 'ENTER' .. ac.reset .. ' to continue..') + end + io.read() + print(dash) + p:console('lf hitag read --ht2 -k BDF5E846') + if not logfile then + error(" No files in this directory") + end + local result = read_log_file(logfile) + local blocks = parse_blocks(result) + local empty_block = false + for i = 4, 7 do + if not blocks[i] then + empty_block = true + break + end + end + if empty_block then + io.write(ac.yellow .. ' Adjust the Fob position on the coil.' .. ac.reset .. ' Press' .. ac.green .. ' ENTER' .. ac.reset .. ' to continue..') + show_place_message = false + else + print(' Readed blocks:') + print() + for i = 4, 7 do + if blocks[i] then + print(string.format(" Block %d: %s%s%s", i, ac.yellow, blocks[i], ac.reset)) + end + end + local decimal_id, padded_hex_id + if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then + print(dash) + print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset) + decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]}) + else + print(dash) + print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset) + decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]}) + end + print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset)) + print(dash) + handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3) + break + end + end + elseif input_option == "2" then + local blocks = {} + for i = 4, 7 do + while true do + io.write(ac.reset..' Enter data for block ' .. i .. ': ' .. ac.yellow) + local input = io.read() + input = input:upper() + if is_valid_hex(input) then + blocks[i] = input + break + else + print(ac.yellow .. ' Invalid input.' .. ac.reset .. ' Each block must be 4 bytes (8 hex characters).') + end + end + end + local decimal_id, padded_hex_id + if blocks[5] and (blocks[5]:sub(4, 4) == 'F' or blocks[5]:sub(4, 4) == 'f') then + print(ac.reset.. dash) + print(' Identified Paxton ' .. ac.cyan .. 'Net2' .. ac.reset) + decimal_id, padded_hex_id = calculate_id_net({blocks[4], blocks[5]}) + else + print(ac.reset.. dash) + print(' Identified Paxton ' .. ac.cyan .. 'Switch2' .. ac.reset) + decimal_id, padded_hex_id = calculate_id_switch({blocks[4], blocks[5], blocks[6], blocks[7]}) + end + print(dash) + print(string.format(" ID for EM4102 is: %s", ac.green .. padded_hex_id .. ac.reset)) + print(dash) + if not padded_hex_id then + print(ac.red..' ERROR: '..ac.reset.. 'Invalid block data provided') + return + end + handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3) + break + elseif input_option == "3" then + was_option_3 = true + local retries = 3 + while retries > 0 do + io.write(' Enter the name to search ('..retries..' attempts) : '..ac.yellow) + local user_input = io.read() + io.write(ac.reset..'') + if user_input == nil or user_input:match("^%s*$") then + print(ac.yellow..' Error: '..ac.reset.. 'Empty name !!!') + end + local name_clean = "^Name:%s*" .. user_input:gsub("%s", "%%s") .. "%s*$" + local file = io.open(log_file_path, "r") + if not file then + print(ac.red .. ' Error:'..ac.reset.. 'Could not open log file.') + return + end + local lines = {} + for line in file:lines() do + table.insert(lines, line) + end + file:close() + local found = false + for i = 1, #lines do + if lines[i]:match(name_clean) then + nam = user_input + local blocks = { + [4] = lines[i + 2]:match("Block 4: (.+)"), + [5] = lines[i + 3]:match("Block 5: (.+)"), + [6] = lines[i + 4]:match("Block 6: (.+)"), + [7] = lines[i + 5]:match("Block 7: (.+)") + } + local em4102_id = lines[i + 6]:match("EM4102 ID: (.+)") + print(dash) + print(' I found the data under the name: '..ac.yellow ..nam.. ac.reset) + for j = 4, 7 do + print(string.format(" Block %d: %s%s%s", j, ac.yellow, blocks[j] or "N/A", ac.reset)) + end + print(" EM4102 ID: " .. ac.green .. (em4102_id or "N/A") .. ac.reset) + print(dash) + local decimal_id, padded_hex_id = em4102_id, em4102_id + handle_cloning(decimal_id, padded_hex_id, blocks, was_option_3, nam) + found = true + break + end + end + if not found then + retries = retries - 1 + else + break + end + end + if retries == 0 then + print(ac.yellow .. " Name not found after 3 attempts." .. ac.reset) + end + end + print(dash) + print(' Exiting script Lua...') + return + end +end + main(args) diff --git a/client/pyscripts/des_talk.py b/client/pyscripts/des_talk.py index 97d7d5e72..5624f592d 100644 --- a/client/pyscripts/des_talk.py +++ b/client/pyscripts/des_talk.py @@ -28,7 +28,6 @@ Full license text: import subprocess import time -import sys import os import re @@ -101,33 +100,24 @@ def send_proxmark_command(command): def authenticate_and_menu(): - com_mode = input("Enter communication mode (PLAIN, MAC, ENCRYPT) (Default: PLAIN): ").strip() or "plain" key_type = input("Enter key type (DES, 2TDEA, 3TDEA, AES): ").strip() - key = input("Enter 8, 16, or 24-byte hex key (no spaces): ").strip() + key = input("Enter 8, 16, 24 or 32-byte hex key (no spaces): ").strip() # Authenticate - auth_command = f"hf mfdes auth -t {key_type} -k {key} -m {com_mode}" + auth_command = f"hf mfdes auth -t {key_type} -k {key}" auth_response = send_proxmark_command(auth_command) print(auth_response) - # print("DEBUG: Raw Proxmark response:\n", repr(auth_response)) # Check for Proxmark failure messages if "error" in auth_response.lower() or "must have" in auth_response.lower(): - print("❌ Authentication failed. Check your connection, mode, key type, and key.") + print("❌ Authentication failed. Check your connection, key, and key type.") return while True: + # Get AIDs - aids_command = f"hf mfdes getaids -n 0 -t {key_type} -k {key} -m {com_mode}" + aids_command = f"hf mfdes getaids -n 0 -t {key_type} -k {key}" aids_response = send_proxmark_command(aids_command) - - # Check for communication mode errors - com_mode_error_match = re.search(r"Wrong communication mode", aids_response) - crc_error_match = re.search(r"CRC32 error", aids_response) - if com_mode_error_match or crc_error_match: - print("❌ Incorrect communication mode.\n") - return - print(aids_response) # Regex to match valid 6-character hex AIDs @@ -154,8 +144,7 @@ def authenticate_and_menu(): print("3. Delete an AID") print("4. Format PICC") print("5. Show free memory") - print("6. Change keys") - print("7. Exit") + print("6. Exit") choice = input("Enter your choice: ").strip() @@ -168,39 +157,32 @@ def authenticate_and_menu(): selected_aid = aids[selected_index] print(f"\nSelecting AID: {selected_aid}") - select_command = f"hf mfdes selectapp --aid {selected_aid} -t {key_type} -k {key} -m {com_mode}" + select_command = f"hf mfdes selectapp --aid {selected_aid} -t {key_type} -k {key}" select_response = send_proxmark_command(select_command) print(select_response) - # Retrieve AID key 0 - aid_key_type = input(f"Enter AID encryption algorithm (DES, 2TDEA, 3TDEA, AES) (Default: {key_type.upper()}): ").strip() or key_type - aid_key = input(f"Enter AID key (Default: {key}): ").strip() or key - # Show file menu - aid_file_menu(selected_aid, key_type, key, com_mode, aid_key_type, aid_key) + aid_file_menu(selected_aid, key_type, key) elif choice == "2": - create_aid(key_type, key, com_mode) + create_aid(key_type, key) elif choice == "3": - delete_aid(key_type, key, com_mode) + delete_aid(key_type, key) elif choice == "4": - format_picc(key_type, key, com_mode) + format_picc(key_type, key) elif choice == "5": - free_memory(key_type, key, com_mode) + free_memory(key_type, key) elif choice == "6": - change_key(key_type, key, com_mode) - - elif choice == "7": print("Exiting...") break else: print("Invalid choice, please try again.") -def aid_file_menu(selected_aid, key_type, key, com_mode, aid_key_type, aid_key): +def aid_file_menu(selected_aid, key_type, key): while True: print(f"\n[ AID {selected_aid} is open ]") @@ -209,52 +191,50 @@ def aid_file_menu(selected_aid, key_type, key, com_mode, aid_key_type, aid_key): print("2. Read a File") print("3. Create a File") print("4. Write to a File") - print("5. Edit File Restrictions") - print("6. Delete a File") - print("7. Back") + print("5. Delete a File") + print("6. Exit") choice = input("Enter your choice: ").strip() if choice == "1": - list_files(selected_aid, key_type, key, com_mode, aid_key_type, aid_key) + list_files(selected_aid, key_type, key) elif choice == "2": - read_file(selected_aid, key_type, key, com_mode, aid_key_type, aid_key) + read_file(selected_aid, key_type, key) elif choice == "3": - create_file(selected_aid, key_type, key, com_mode, aid_key_type, aid_key) + create_file(selected_aid, key_type, key) elif choice == "4": - write_to_file(selected_aid, key_type, key, com_mode, aid_key_type, aid_key) + write_to_file(selected_aid, key_type, key) elif choice == "5": - edit_file_restriction(selected_aid, key_type, key, com_mode, aid_key_type, aid_key) + delete_file(selected_aid, key_type, key) elif choice == "6": - delete_file(selected_aid, key_type, key, com_mode, aid_key_type, aid_key) - elif choice == "7": print("Returning to AID selection...") break else: print("Invalid choice, please try again.") -def create_aid(key_type, key, com_mode): +def create_aid(key_type, key): aid = input("Enter new AID (6 hex characters, e.g., 112233): ").strip() iso_fid = input("Enter ISO File ID (4 hex characters, e.g., 1234): ").strip() - dstalgo = input(f"Enter encryption algorithm (DES, 2TDEA, 3TDEA, AES) (Default: {key_type.upper()}): ").strip() or key_type - create_command = f"hf mfdes createapp -n 0 --aid {aid} --fid {iso_fid} --dstalgo {dstalgo} -t {key_type} -k {key} -m {com_mode} -a" + dstalgo = input("Enter encryption algorithm (DES, 2TDEA, 3TDEA, AES): ").strip().upper() + + create_command = f"hf mfdes createapp -n 0 --aid {aid} --fid {iso_fid} --dstalgo {dstalgo} -t {key_type} -k {key} -a" response = send_proxmark_command(create_command) print(response) -def delete_aid(key_type, key, com_mode): +def delete_aid(key_type, key): aid = input("Enter AID to delete (6 hex characters): ").strip() - delete_command = f"hf mfdes deleteapp --aid {aid} -n 0 -t {key_type} -k {key} -m {com_mode}" + delete_command = f"hf mfdes deleteapp --aid {aid} -n 0 -t {key_type} -k {key}" response = send_proxmark_command(delete_command) print(response) -def format_picc(key_type, key, com_mode): +def format_picc(key_type, key): confirm = input("Are you sure you want to format the PICC? This will erase all data. (y/n): ").strip().lower() if confirm == "y": - format_command = f"hf mfdes formatpicc -t {key_type} -k {key} -m {com_mode} -v" + format_command = f"hf mfdes formatpicc -t {key_type} -k {key} -v" response = send_proxmark_command(format_command) print(response) elif confirm == "n": @@ -262,9 +242,9 @@ def format_picc(key_type, key, com_mode): else: print("Invalid input. Please enter 'y' or 'n'.") -def free_memory(key_type, key, com_mode): +def free_memory(key_type, key): - memory_command = f"hf mfdes freemem -t {key_type} -k {key} -m {com_mode}" + memory_command = f"hf mfdes freemem -t {key_type} -k {key}" response = send_proxmark_command(memory_command) for line in response.splitlines(): @@ -274,54 +254,10 @@ def free_memory(key_type, key, com_mode): print("❌ Unable to retrieve free memory information.") -def change_key(key_type, key, com_mode): - print("\nChange Key - Choose Target:") - print("1. PICC (Card Master Key)") - print("2. Application Key") +def list_files(aid, key_type, key): - target = input("Change key for (1/2)? (Default: 1): ").strip() or "1" - aid = "" - - if target == "2": - aid = input("Enter 6-digit AID (e.g., 010203): ").strip() - - print("\n!! Verify and securely store the new key !!") - print("Key length guide:") - print(" DES : 8 bytes (16 hex chars)") - print(" 2TDEA : 16 bytes (32 hex chars)") - print(" 3TDEA : 24 bytes (48 hex chars)") - print(" AES : 16 bytes (32 hex chars)") - - newalgo = input(f"Enter new key encryption algorithm (DES, 2TDEA, 3TDEA, AES) " - f"(Default: {key_type.upper()}): ").strip() or key_type - newkey = input(f"Enter new 8, 16, or 24-byte hex key (no spaces) (Default: {key}): ").strip() or key - - confirm = input("Are you sure you want to change the key? (Key 0) (y or n): ").strip().lower() - - if confirm == "y": - changekey_command = f"hf mfdes changekey -n 0 -t {key_type} -k {key} -m {com_mode} " \ - f"--newalgo {newalgo} --newkey {newkey} --newver 00 -v" - if aid: - app_key_type = input(f"Enter original application encryption algorithm (DES, 2TDEA, 3TDEA, AES) " - f"(Default: DES): ").strip() or "DES" - app_key = input(f"Enter original application key " - f"(Default: 0000000000000000): ").strip() or "0000000000000000" - changekey_command = f"hf mfdes changekey -n 0 -t {app_key_type} -k {app_key} -m {com_mode} " \ - f"--newalgo {newalgo} --newkey {newkey} --newver 00 --aid {aid} -v" - - response = send_proxmark_command(changekey_command) - print(response) - print("\nReauthenticate with the master key.") - sys.exit() - - elif confirm == "n": - print("Cancelled.") - else: - print("Invalid input. Please enter 'y' or 'n'.") - -def list_files(aid, key_type, key, com_mode, aid_key_type, aid_key): print("\nFetching file list...") - command = f"hf mfdes getfileids --aid {aid} -t {aid_key_type} -k {aid_key} -m {com_mode}" + command = f"hf mfdes getfileids --aid {aid} -t {key_type} -k {key}" response = send_proxmark_command(command) # Extract file IDs by looking for "File ID:" regex @@ -340,7 +276,7 @@ def list_files(aid, key_type, key, com_mode, aid_key_type, aid_key): print("No files found in this AID.") return [] -def read_file(aid, key_type, key, com_mode, aid_key_type, aid_key): +def read_file(aid, key_type, key): file_id = input("Enter file ID to read: ").strip() @@ -352,8 +288,7 @@ def read_file(aid, key_type, key, com_mode, aid_key_type, aid_key): length_input = input("Enter length to read (e.g., 16 for 16 bytes, 64 for 64 bytes, default full read): ").strip() or "0" length_hex = format(int(length_input), '06X') # Convert to 3-byte hex - read_command = f"hf mfdes read --aid {aid} --fid {file_id} -t {aid_key_type} -k {aid_key} " \ - f"--offset {offset_hex} --length {length_hex} -m {com_mode}" + read_command = f"hf mfdes read --aid {aid} --fid {file_id} -t {key_type} -k {key} --offset {offset_hex} --length {length_hex}" response = send_proxmark_command(read_command) # Extract and display file content @@ -364,7 +299,7 @@ def read_file(aid, key_type, key, com_mode, aid_key_type, aid_key): return response -def create_file(aid, key_type, key, com_mode, aid_key_type, aid_key): +def create_file(aid, key_type, key): # Prompt for file ID in hex format file_id = input("Enter file ID (2 hex characters, e.g., 01, 02): ").strip() @@ -397,17 +332,16 @@ def create_file(aid, key_type, key, com_mode, aid_key_type, aid_key): print(f"Invalid file size: {e}") return - create_command = f"hf mfdes createfile --aid {aid} --fid {file_id} --isofid {iso_file_id} " \ - f"--size {file_size_hex} -t {aid_key_type} -k {aid_key} -m {com_mode}" + create_command = f"hf mfdes createfile --aid {aid} --fid {file_id} --isofid {iso_file_id} --size {file_size_hex} -t {key_type} -k {key}" response = send_proxmark_command(create_command) print(response) -def write_to_file(aid, key_type, key, com_mode, aid_key_type, aid_key): +def write_to_file(aid, key_type, key): file_id = input("Enter file ID to write to: ").strip() # Get file size - file_size_command = f"hf mfdes getfilesettings --aid {aid} --fid {file_id} -t {aid_key_type} -k {aid_key} -m {com_mode}" + file_size_command = f"hf mfdes getfilesettings --aid {aid} --fid {file_id} -t {key_type} -k {key}" response = send_proxmark_command(file_size_command) # Extract the file size from the response @@ -442,49 +376,15 @@ def write_to_file(aid, key_type, key, com_mode, aid_key_type, aid_key): else: print("❌ Invalid choice. Please choose 1 for text or 2 for hex.") - write_command = f"hf mfdes write --aid {aid} --fid {file_id} -t {aid_key_type} -k {aid_key} -d {write_data_hex} -m {com_mode}" + write_command = f"hf mfdes write --aid {aid} --fid {file_id} -t {key_type} -k {key} -d {write_data_hex}" response = send_proxmark_command(write_command) print(response) -def edit_file_restriction(aid, key_type, key, com_mode, aid_key_type, aid_key): - while True: - print("\nNOTE: This only works if you have changed the default keys.") - print("The Proxmark3 and other tools will automatically attempt to read files using DESFire default keys.") - print("\nWould you like to apply or remove a key from the file?") - print("1. Apply key 0 (Requires authentication for access)") - print("2. Remove key (Make file freely accessible)") - print("3. Back") - - choice = input("Enter your choice (1, 2, or 3): ").strip() - - if choice == "3": - print("Returning to the previous menu.") - break - - file_id = input("Enter file ID to update: ").strip() - - if choice == "1": - edit_file_command = f"hf mfdes chfilesettings --rawrights 0000 --aid {aid} --fid {file_id} -t {aid_key_type} -k {aid_key} -m {com_mode}" - print("Applying key 0 for read, write, and change access. This ensures authentication is required to access the file.") - - elif choice == "2": - # Must use encrypt communications mode to remove restrictions - edit_file_command = f"hf mfdes chfilesettings --rawrights EEEE --aid {aid} --fid {file_id} -t {aid_key_type} -k {aid_key} -m encrypt" - print("Removing key restrictions. File will be freely accessible.") - - else: - print("❌ Invalid choice. Please enter 1, 2, or 3.") - continue - - response = send_proxmark_command(edit_file_command) - print(response) - break - -def delete_file(aid, key_type, key, com_mode, aid_key_type, aid_key): +def delete_file(aid, key_type, key): file_id = input("Enter file ID to delete: ").strip() - delete_command = f"hf mfdes deletefile --aid {aid} --fid {file_id} -t {aid_key_type} -k {aid_key} -m {com_mode}" + delete_command = f"hf mfdes deletefile --aid {aid} --fid {file_id} -t {key_type} -k {key}" response = send_proxmark_command(delete_command) print(response) diff --git a/client/pyscripts/fm11rf08s_full.py b/client/pyscripts/fm11rf08s_full.py index 8d1765b84..714d1acaf 100644 --- a/client/pyscripts/fm11rf08s_full.py +++ b/client/pyscripts/fm11rf08s_full.py @@ -90,14 +90,13 @@ def lprint(s='', end='\n', flush=False, prompt="[" + color("=", fg="yellow") + - logfile (R) """ s = f"{prompt}" + f"\n{prompt}".join(s.split('\n')) - safe_s = s.encode('utf-8', errors='ignore').decode('utf-8') - print(safe_s, end=end, flush=flush) + print(s, end=end, flush=flush) if log is True: global logbuffer if logfile is not None: - with open(logfile, 'a', encoding='utf-8') as f: - f.write(safe_s + end) + with open(logfile, 'a') as f: + f.write(s + end) else: # buffering logbuffer += s + end diff --git a/client/pyscripts/fm11rf08s_recovery.py b/client/pyscripts/fm11rf08s_recovery.py index 8b7eaffd8..cbb7246d5 100755 --- a/client/pyscripts/fm11rf08s_recovery.py +++ b/client/pyscripts/fm11rf08s_recovery.py @@ -216,7 +216,7 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, with open(dict_path, 'r', encoding='utf-8') as file: for line in file: if line[0] != '#' and len(line) >= 12: - DEFAULT_KEYS.add(line[:12].lower()) + DEFAULT_KEYS.add(line[:12]) show(f"Loaded {dict_def}") except FileNotFoundError: show(f"Warning, {dict_def} not found.") @@ -226,7 +226,6 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, dict_dnwd = None def_nt = ["" for _ in range(NUM_SECTORS)] if supply_chain: - default_nonces = '' try: default_nonces = f'{save_path}hf-mf-{uid:04X}-default_nonces.json' with open(default_nonces, 'r') as file: @@ -585,6 +584,8 @@ def recovery(init_check=False, final_check=False, keep=False, no_oob=False, if "Found keys have been dumped to" in line: keyfile = line[line.index("`"):].strip("`") else: + show() + show(color("found keys:", fg="green"), prompt=plus) show(prompt=plus) show("-----+-----+--------------+---+--------------+----", prompt=plus) show(" Sec | Blk | key A |res| key B |res", prompt=plus) diff --git a/client/pyscripts/intertic.py b/client/pyscripts/intertic.py index 6ccfaee2b..2793aee43 100644 --- a/client/pyscripts/intertic.py +++ b/client/pyscripts/intertic.py @@ -211,37 +211,6 @@ def Describe_Usage_2_1(Usage, ContractMediumEndDate, Certificate): print(' left... :', Usage.nom_bits_left()) print(' [CER] Usage : {:04x}'.format(Certificate.nom(16))) -def Describe_Usage_2_2(Usage, ContractMediumEndDate, Certificate): - EventDateStamp = Usage.nom(10) - EventTimeStamp = Usage.nom(11) - unk0 = Usage.nom_bits(8) - EventCode_Nature = Usage.nom(5) - EventCode_Type = Usage.nom(5) - unk1 = Usage.nom_bits(11) - EventGeoRouteId = Usage.nom(14) - EventGeoRoute_Direction = Usage.nom(2) - EventGeoVehicleId = Usage.nom(16) - unk2 = Usage.nom_bits(4) - EventValidityTimeFirstStamp = Usage.nom(11) - unk3 = Usage.nom_bits(3) - EventCountPassengers_mb = Usage.nom(4) - - print(' DateStamp : {} ({})'.format(EventDateStamp, (datetime(1997, 1, 1) + timedelta(days = ContractMediumEndDate - EventDateStamp)).strftime('%Y-%m-%d'))) - print(' TimeStamp : {} ({:02d}:{:02d})'. format(EventTimeStamp, EventTimeStamp // 60, EventTimeStamp % 60)) - print(' unk0... :', unk0) - print(' Code/Nature : 0x{:x} ({})'.format(EventCode_Nature, TYPE_EventCode_Nature.get(EventCode_Nature, '?'))) - print(' Code/Type : 0x{:x} ({})'.format(EventCode_Type, TYPE_EventCode_Type.get(EventCode_Type, '?'))) - print(' unk1... :', unk1) - print(' GeoRouteId : {}'. format(EventGeoRouteId)) - print(' Direction : {} ({})'. format(EventGeoRoute_Direction, TYPE_EventGeoRoute_Direction.get(EventGeoRoute_Direction, '?'))) - print(' GeoVehicleId : {}'. format(EventGeoVehicleId)) - print(' unk2... :', unk2) - print(' ValidityTimeFirstStamp: {} ({:02d}:{:02d})'. format(EventValidityTimeFirstStamp, EventValidityTimeFirstStamp // 60, EventValidityTimeFirstStamp % 60)) - print(' unk3... :', unk3) - print(' Passengers(?) : {}'. format(EventCountPassengers_mb)) - print(' left... :', Usage.nom_bits_left()) - print(' [CER] Usage : {:04x}'.format(Certificate.nom(16))) - def Describe_Usage_3(Usage, ContractMediumEndDate, Certificate): EventDateStamp = Usage.nom(10) EventTimeStamp = Usage.nom(11) @@ -289,7 +258,6 @@ ISO_Countries = { FRA_OrganizationalAuthority_Contract_Provider = { 0x000: { - 1: InterticHelper('Valenciennes', 'Transvilles / Keolis', Describe_Usage_1_1), 5: InterticHelper('Lille', 'Ilévia / Keolis', Describe_Usage_1_1), 7: InterticHelper('Lens-Béthune', 'Tadao / Transdev', Describe_Usage_1_1), }, @@ -305,9 +273,6 @@ FRA_OrganizationalAuthority_Contract_Provider = { 0x021: { 1: InterticHelper('Bordeaux', 'TBM / Keolis', Describe_Usage_1_1), }, - 0x040: { - 28: InterticHelper('Colmar', 'Trace / Keolis', Describe_Usage_1_1), - }, 0x057: { 1: InterticHelper('Lyon', 'TCL / Keolis', Describe_Usage_1), # Strange usage ?, kept on generic 1 }, @@ -324,7 +289,7 @@ FRA_OrganizationalAuthority_Contract_Provider = { 0x502: { 83: InterticHelper('Annecy', 'Sibra', Describe_Usage_2), 84: InterticHelper('Bourg-en-Bresse', 'Rubis / Keolis'), - 10: InterticHelper('Clermont-Ferrand', 'T2C', Describe_Usage_2_2), + 10: InterticHelper('Clermont-Ferrand', 'T2C'), }, 0x907: { 1: InterticHelper('Dijon', 'Divia / Keolis'), @@ -338,7 +303,6 @@ FRA_OrganizationalAuthority_Contract_Provider = { }, 0x912: { 3: InterticHelper('Le Havre', 'Lia / Transdev', Describe_Usage_1_1), - 29: InterticHelper('Caen', 'Twisto / RATP', Describe_Usage_2), 35: InterticHelper('Cherbourg-en-Cotentin', 'Cap Cotentin / Transdev'), }, 0x913: { @@ -351,9 +315,6 @@ FRA_OrganizationalAuthority_Contract_Provider = { 4: InterticHelper('Angers', 'Irigo / RATP', Describe_Usage_1_2), 7: InterticHelper('Saint-Nazaire', 'Stran'), }, - 0x920: { - 9: InterticHelper('Aix-en-Provence', 'Aixenbus / Keolis', Describe_Usage_2_1), - }, } MAR_OrganizationalAuthority_Contract_Provider = { diff --git a/client/pyscripts/pm3_resources.py b/client/pyscripts/pm3_resources.py index a31069dbd..c50ede801 100644 --- a/client/pyscripts/pm3_resources.py +++ b/client/pyscripts/pm3_resources.py @@ -36,7 +36,7 @@ DIR_PATH = os.path.dirname(os.path.abspath(__file__)) if TOOLS_PATH is None: if os.path.basename(os.path.dirname(DIR_PATH)) == 'client': # dev setup - DEV_TOOLS_PATH = os.path.normpath(os.path.join(DIR_PATH, "..", "..", "tools")) + DEV_TOOLS_PATH = os.path.normpath(os.path.join(DIR_PATH, "..", "..", "tools", "mfc", "card_only")) if os.path.isdir(DEV_TOOLS_PATH): TOOLS_PATH = DEV_TOOLS_PATH @@ -62,11 +62,11 @@ def find_tool(tool_name): str: The full path to the tool if found, otherwise None. """ if TOOLS_PATH is not None: - for root, _, files in os.walk(TOOLS_PATH): - if tool_name in files: - return os.path.join(root, tool_name) - elif tool_name + ".exe" in files: - return os.path.join(root, tool_name + ".exe") + tool = os.path.join(TOOLS_PATH, tool_name) + if os.path.isfile(tool): + return tool + elif os.path.isfile(tool + ".exe"): + return tool + ".exe" # if not found, search in the user PATH for path in os.environ["PATH"].split(os.pathsep): env_tool = os.path.join(path, tool_name) diff --git a/client/resources/aid_desfire.json b/client/resources/aid_desfire.json index df68b254e..c88482f4a 100644 --- a/client/resources/aid_desfire.json +++ b/client/resources/aid_desfire.json @@ -36,7 +36,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -44,7 +44,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -52,7 +52,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -60,7 +60,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -68,7 +68,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -76,7 +76,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -84,7 +84,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -92,7 +92,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -100,7 +100,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -108,7 +108,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -116,7 +116,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -124,7 +124,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Cardax Card Data Application", + "Description": "Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -132,7 +132,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Unused Cardax Card Data Application", + "Description": "Unused Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -140,7 +140,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Unused Cardax Card Data Application", + "Description": "Unused Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -148,7 +148,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Unused Cardax Card Data Application", + "Description": "Unused Cardax Card Data Application (Alternative Endian)", "Type": "pacs" }, { @@ -156,7 +156,7 @@ "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", "Country": "NZ", "Name": "Gallagher Security Credential", - "Description": "Card Application Directory (CAD)", + "Description": "Card Application Directory (CAD) (Alternative Endian)", "Type": "pacs" }, { @@ -223,6 +223,134 @@ "Description": "Securitron DESFire EV2 Credential", "Type": "pacs" }, + { + "AID": "F48120", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F48121", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F48122", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F48123", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F48124", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F48125", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F48126", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F48127", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F48128", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F48129", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F4812A", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F4812B", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F4812C", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Unused Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F4812D", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Unused Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F4812E", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Unused Cardax Card Data Application", + "Type": "pacs" + }, + { + "AID": "F4812F", + "Vendor": "Gallagher Group Limited via PEC (New Zealand) Limited", + "Country": "NZ", + "Name": "Gallagher Security Credential", + "Description": "Card Application Directory (CAD)", + "Type": "pacs" + }, { "AID": "F484D1", "Vendor": "HID", @@ -263,20 +391,12 @@ "Description": "Key as a Service // FID 01: Standard Data", "Type": "pacs" }, - { - "AID": "F51780", - "Vendor": "ASSA ABLOY", - "Country": "SE", - "Name": "SMARTair", - "Description": "SMARTair Credential", - "Type": "pacs" - }, { "AID": "F51BC0", "Vendor": "STid Group", "Country": "FR", "Name": "CCT Card / DTA Tag / PCG Fob", - "Description": "STid Easyline / Architect Access Credentials", + "Description": "STid Easyline / Architect Access Credetials", "Type": "pacs" }, { @@ -772,15 +892,7 @@ "Vendor": "Invalid / Reserved", "Country": "", "Name": "Invalid / Reserved", - "Description": "Used by ATL Breeze, PHL FREEDOM, and YVR Compass", - "Type": "transport" - }, - { - "AID": "000005", - "Vendor": "Transports Metropolitans de Barcelona (TMB)", - "Country": "ES", - "Name": "T-mobilitat (BCN)", - "Description": "BCN T-mobilitat", + "Description": "Used by ATL Breeze, MAD Tarjeta Transporte Publico, and YVR Compass", "Type": "transport" }, { @@ -793,7 +905,7 @@ }, { "AID": "002000", - "Vendor": "Metrolinx via Accenture", + "Vendor": "Metrolinx", "Country": "CA", "Name": "PRESTO Card (YYZ/YHM/YOW)", "Description": "FIDs 00,0F: Backup Data; 08-0E,10-14: Standard Data", @@ -803,7 +915,7 @@ "AID": "010000", "Vendor": "Consorcio Regional de Transportes Publicos Regulares de Madrid (CRTM)", "Country": "ES", - "Name": "Tarjeta Transporte Publico (MAD)", + "Name": "Tarjeta Transporte Publico (MAD) (Alternative Endian)", "Description": "MAD Public Transport Card", "Type": "transport" }, @@ -1071,22 +1183,6 @@ "Description": "DUB Leap Card // Transport for Ireland // FIDs: 01,1F: Backup Data; 02-0A: Standard Data", "Type": "transport" }, - { - "AID": "402301", - "Vendor": "Ministry of Transport, Communications and Works of the Republic of Cyprus", - "Country": "CY", - "Name": "motion BUS CARD (ECN)", - "Description": "ECN motion BUS CARD (App 1)", - "Type": "transport" - }, - { - "AID": "415431", - "Vendor": "Athens Urban Transport Organisation (OASA)", - "Country": "GR", - "Name": "ATH.ENA CARD (ATH)", - "Description": "ATH ATH.ENA CARD", - "Type": "transport" - }, { "AID": "444D01", "Vendor": "Delhi Metro Rail Corporation Limited", @@ -1153,23 +1249,15 @@ }, { "AID": "4F5931", - "Vendor": "Transport for London (TfL) via Cubic Transportation Systems", + "Vendor": "Transport for London (TfL)", "Country": "UK", "Name": "Oyster Card (LHR)", "Description": "FIDs: 00-07: Standard Data", "Type": "transport" }, - { - "AID": "502301", - "Vendor": "Ministry of Transport, Communications and Works of the Republic of Cyprus", - "Country": "CY", - "Name": "motion BUS CARD (ECN)", - "Description": "ECN motion BUS CARD (App 2)", - "Type": "transport" - }, { "AID": "534531", - "Vendor": "Transport for New South Wales (TfNSW) via Pearl Consortium", + "Vendor": "Transport for New South Wales (TfNSW)", "Country": "AU", "Name": "Opal Card (SYD)", "Description": "FIDs 00-06: Standard Data; 07: Card Balance/Number and Trip History", @@ -1177,7 +1265,7 @@ }, { "AID": "554000", - "Vendor": "Auckland Transport via Thales Group", + "Vendor": "Auckland Transport", "Country": "NZ", "Name": "AT HOP Card (AKL)", "Description": "FIDs: 00: Backup Data; 08/09/0A", @@ -1199,14 +1287,6 @@ "Description": "FIDs 01: Product Retailer; 02: Service Provider; 03: Special Event; 04: Stored Value; 05: General Event Log; 06: SV Reload Log; 0A: Environment; 0C: Card Holder", "Type": "transport" }, - { - "AID": "602301", - "Vendor": "Ministry of Transport, Communications and Works of the Republic of Cyprus", - "Country": "CY", - "Name": "motion BUS CARD (ECN)", - "Description": "ECN motion BUS CARD (App 3)", - "Type": "transport" - }, { "AID": "634000", "Vendor": "Doha Metro and Lusail Tram via Qatar Rail", @@ -1223,14 +1303,6 @@ "Description": "Umo Mobility Card", "Type": "transport" }, - { - "AID": "7A007A", - "Vendor": "Regional Transportation Commission of Southern Nevada (RTC) via Masabi Ltd", - "Country": "US", - "Name": "RTC TAP & GO (LAS)", - "Description": "LAS TAP & GO; Masabi Justride Tap and Ride DESFire Smartcard", - "Type": "transport" - }, { "AID": "784000", "Vendor": "Roads & Transport Authority (Government of Dubai)", @@ -1263,14 +1335,6 @@ "Description": "Umo Mobility Card", "Type": "transport" }, - { - "AID": "C1B1A1", - "Vendor": "AHORROBUS via MOBILITY ADO", - "Country": "MX", - "Name": "AHORROBUS Card (MEX)", - "Description": "MEX AHORROBUS Card", - "Type": "transport" - }, { "AID": "C65B80", "Vendor": "Umo Mobility via Cubic Transportation Systems", @@ -1345,7 +1409,7 @@ }, { "AID": "F21050", - "Vendor": "Metro Christchurch via INIT / Arc via Vix Technologies", + "Vendor": "Metro Christchurch via INIT / Arc", "Country": "NZ / CA", "Name": "Metrocard (CHC) / Arc (YEG)", "Description": "CHC FIDs: 00: Backup Data; 01/02: Trip History; 03: Card Balance", @@ -1353,7 +1417,7 @@ }, { "AID": "F210E0", - "Vendor": "TriMet via INIT", + "Vendor": "TriMet", "Country": "US", "Name": "hop fastpass (PDX)", "Description": "PDX hop fastpass Card", @@ -1401,7 +1465,7 @@ }, { "AID": "F21201", - "Vendor": "Green Bay Metro Transit via Genfare / Winnipeg Transit via Genfare", + "Vendor": "Green Bay Metro Transit via Genfare / Winnipeg Transit", "Country": "US / CA", "Name": "Tap-N-Go Card (GRB) / peggo card (YWG)", "Description": "GRB Tap-N-Go Card / YWG peggo card", @@ -1417,7 +1481,7 @@ }, { "AID": "F212A0", - "Vendor": "CTtransit via Genfare", + "Vendor": "CTtransit", "Country": "US", "Name": "Go CT Card (BDL)", "Description": "BDL Go CT Card", @@ -1425,7 +1489,7 @@ }, { "AID": "F21360", - "Vendor": "The City and County of Honolulu via INIT", + "Vendor": "INIT", "Country": "US", "Name": "HOLO Card (HNL)", "Description": "HNL HOLO Card", @@ -1441,7 +1505,7 @@ }, { "AID": "F21390", - "Vendor": "Otago Regional Council via INIT", + "Vendor": "Multiple NZ Transit Agencies via Otago Regional Council", "Country": "NZ", "Name": "Bee Card (DUD)", "Description": "Multi-Modal Transit #0 // FIDs 00: Backup Data; 01-02: Trip History; 03: Card Balance", @@ -1463,14 +1527,6 @@ "Description": "One Regional Card for All // FIDs 00: Standard Data; 01: Backup Data", "Type": "transport" }, - { - "AID": "F21400", - "Vendor": "Spokane Transit Authority (STA) via INIT", - "Country": "US", - "Name": "Connect Card (GEG)", - "Description": "GEG Connect Card", - "Type": "transport" - }, { "AID": "F40110", "Vendor": "ITSO Ltd", @@ -1505,7 +1561,7 @@ }, { "AID": "FF30FF", - "Vendor": "Metrolinx via Accenture", + "Vendor": "Metrolinx", "Country": "CA", "Name": "PRESTO Card (YYZ/YHM/YOW)", "Description": "FID 08: Standard Data", diff --git a/client/resources/aidlist.json b/client/resources/aidlist.json index 53828dbc1..9b6d58317 100644 --- a/client/resources/aidlist.json +++ b/client/resources/aidlist.json @@ -1247,6 +1247,14 @@ "Description": "PIV End Point Applet. Last 2 bytes designate version", "Type": "" }, + { + "AID": "A000000308000010000100", + "Vendor": "National Institute of Standards and Technology", + "Country": "United States", + "Name": "Personal Identity Verification (PIV) / ID-ONE PIV BIO", + "Description": "PIV End Point Applet. Last 2 bytes designate version", + "Type": "" + }, { "AID": "A00000031510100528", "Vendor": "Currence Holding/PIN BV", @@ -2462,37 +2470,5 @@ "Name": "Navigo", "Description": "CALYPSO-based transit card", "Type": "transport" - }, - { - "AID": "A0000000791000", - "Vendor": "HID Global", - "Country": "", - "Name": "Crescendo ACA", - "Description": "HID Crescendo ACA", - "Type": "access" - }, - { - "AID": "A0000000792300", - "Vendor": "HID Global", - "Country": "", - "Name": "Crescendo OATH #0 (HOTP)", - "Description": "HID Crescendo Key OATH instance 0 (default HOTP slot)", - "Type": "access" - }, - { - "AID": "A0000000792301", - "Vendor": "HID Global", - "Country": "", - "Name": "Crescendo OATH #1", - "Description": "HID Crescendo Key OATH instance 1", - "Type": "access" - }, - { - "AID": "A0000000792302", - "Vendor": "HID Global", - "Country": "", - "Name": "Crescendo OATH #2", - "Description": "HID Crescendo Key OATH instance 2", - "Type": "access" } ] diff --git a/client/resources/iceman.txt b/client/resources/iceman.txt deleted file mode 100644 index ad58ac814..000000000 --- a/client/resources/iceman.txt +++ /dev/null @@ -1,8 +0,0 @@ -$$$$$$\ $$$$$$\ $$$$$$$$\ $$\ $$\ $$$$$$\ $$\ $$\  -\_$$ _|$$ __$$\ $$ _____|$$$\ $$$ |$$ __$$\ $$$\ $$ | - $$ | $$ / \__|$$ | $$$$\ $$$$ |$$ / $$ |$$$$\ $$ | - $$ | $$ | $$$$$\ $$\$$\$$ $$ |$$$$$$$$ |$$ $$\$$ | - $$ | $$ | $$ __| $$ \$$$ $$ |$$ __$$ |$$ \$$$$ | - $$ | $$ | $$\ $$ | $$ |\$ /$$ |$$ | $$ |$$ |\$$$ | -$$$$$$\ \$$$$$$ |$$$$$$$$\ $$ | \_/ $$ |$$ | $$ |$$ | \$$ | -\______| \______/ \________|\__| \__|\__| \__|\__| \__| \ No newline at end of file diff --git a/client/resources/mad.json b/client/resources/mad.json index 6b8465f55..66a592e44 100644 --- a/client/resources/mad.json +++ b/client/resources/mad.json @@ -4130,13 +4130,6 @@ "service_provider": "HID Corporation", "system_integrator": "HID Corporation" }, - { - "application": "Access Control (SIO Elite)", - "company": "HID Global", - "mad": "0x3D05", - "service_provider": "HID Corporation", - "system_integrator": "HID Corporation" - }, { "application": "City transport, prepaid ticket, cardholder, servicespass", "company": "Ridango AS", diff --git a/client/src/atrs.h b/client/src/atrs.h index 73ebb857d..95a24e997 100644 --- a/client/src/atrs.h +++ b/client/src/atrs.h @@ -44,7 +44,6 @@ const static atr_t AtrTable[] = { { "3B003B28003441454130323030", "Cryptoguard card used for pay tv Plustelka (DVB-T2 - Slovak) (Pay TV)\nhttps://www.plustelka.sk/" }, { "3B021050", "Visa (Bank)" }, { "3B02141C", "UAE (United Arab Emirates) (eID)" }, - { "3B021425", "Nk (Bank)" }, { "3B021435", "cartao cidadao (eID)" }, { "3B021450", "Schlumberger Multiflex 3k" }, { "3B02145011", "Maste visa card (Bank)" }, @@ -163,7 +162,6 @@ const static atr_t AtrTable[] = { { "3B1618D0000B010300", "Cellular SIM (Telecommunication)" }, { "3B169420020120010D", "Rogers SIM Card (phone / cable provider in Canada)" }, { "3B16942006010C0100", "Vodafone Romania (Telecommunication)" }, - { "3B1694588000010203", "Thales PayShield 9000 Test Local Master Key (hardware key) card (Other)" }, { "3B1694618000010603", "Thales PayShield9000 Local Master Key (hardware key) card (Other)" }, { "3B1694710101002700", "Cingular GSM SIM Card" }, { "3B1694710101010200", "Iridium SIM Card (Telecommunication)" }, @@ -183,7 +181,6 @@ const static atr_t AtrTable[] = { { "3B16959B0007011803", "Thai GSM UICC (Telecommunication)" }, { "3B1695D00045F70100", "Telefonica O2 Czech Republic, a.s. - O2 sim card - 173285 / SIM64ND.GO0\nhttp://www.o2.cz" }, { "3B1695D0016CFD0D00", "Virgin Mobile SIM card (SIM)" }, - { "3B1695D0016EF40C00", "SIM card (Telecommunication)" }, { "3B1695D0017B010E00", "Vivo Brasil - SIM Card (Telecommunication)" }, { "3B1695D0017BDA0D00", "Verizon GSM SIM (Telecommunication)" }, { "3B16962A000E010103", "RW SIM card for mobile forensics (Telecommunication)" }, @@ -220,7 +217,6 @@ const static atr_t AtrTable[] = { { "3B1894530D06772407FF02", "GSM SIM Tele2 Estonia, prepaid (Telecommunication)" }, { "3B1894532007AD0A05FF02", "GSM SIM Beeline Kazakhstan (Telecommunication)\nhttp://beeline.kz/" }, { "3B18962621550401030001", "OBILedit Forensic SIM Cloning card (Telecommunication)\nhttps://www.mobiledit.com/connection-kit" }, - { "3B18968921A00120240716", "Token2 T2F2-NFC-Card PIN+ Release3 (Other)\nhttps://www.token2.com/shop/product/t2f2-nfc-card-pin-release3" }, { "3B19145590010101000508B0", "Schlumberger Multiflex 8k" }, { "3B19145590010201000504B0", "Schlumberger Multiflex 4k" }, { "3B19145901010F01000508B0", "Schlumberger Multiflex 8k" }, @@ -377,7 +373,6 @@ const static atr_t AtrTable[] = { { "3B3B9600914110205709A000339000", "old vodafone romania sim (Telecommunication)\nhttps://vodafone.ro" }, { "3B3B9600924210105A02E000339000", "Roaming Test SIM (Telecommunication)" }, { "3B3B9600A74C90000090AC33339000", "Brazilian TIM GSM SIM" }, - { "3B3BD6970081B1FE451F078031C152", "US government PIV card eID\nOberthur ID One PIV eID\nNASA Personal Identity Verification (PIV) card (eID)\nIDEMIA Cosmo V8.0 with a PIV applet eID" }, { "3B3BF71800008031FE45736674652D", "Serasa Experian (PKI)\nhttps://serasa.certificadodigital.com.br/" }, { "3B3BFF1800FF8131FE55006B020903", "Smart card commercial chamber - Tuscan region - Aruba (eID)" }, { "3B3C110040AF13F31200068783809000", "SIM GSM Orange Fr" }, @@ -387,7 +382,6 @@ const static atr_t AtrTable[] = { { "3B3C9400423111A21202095183809000", "Omnitel IT 16K GSM SIM card" }, { "3B3C9400443111F000002CAE83839000", "Movistar Spain (Telecommunication)" }, { "3B3C94004B3125A21013144783839000", "GSM SFR" }, - { "3B3C94004B3125A7240C027E80809000", "D2 mannesmann mobilphone-card (Other)" }, { "3B3C94004C3125A7201B001583839000", "GSM-SIM (900MHz) card of the carrier vodafone for their cellular\nnetwork (phase 2+ with 3V)" }, { "3B3C9400633112F00000464083839000", "Old russian 'beeline' sim" }, { "3B3D9400010F0036000086601804000107", "Vodafone GSM / Turkey" }, @@ -438,7 +432,6 @@ const static atr_t AtrTable[] = { { "3B4F00536C653434322D34343DA2131091", "Debit card (Bank)" }, { "3B4F00536C65343433322D34323D30000000", "Blank card (Other)" }, { "3B4F00536C65343433322D34323DA2131091", "VISA (Bank)" }, - { "3B4F00536C65343433322D34323DFFFFFFFF", "LTE Testing (Telecommunication)" }, { "3B501100", "JAVA (JavaCard)" }, { "3B57180293020101019000", "Easyflex FastOS 2.0 / Schlumberger" }, { "3B5B96000031C064BAFC10000F9000", "SERGAS - Galician Healthcare Service (Spain) (HealthCare)\nhttps://www.sergas.gal" }, @@ -459,19 +452,14 @@ const static atr_t AtrTable[] = { { "3B5F9600805A3F0608201223C4427698829000", "Opus Card for public transportation in the Greater Montreal Area, and in Quebec City. It uses the Calypso Standard. (Transport)\nhttps://en.wikipedia.org/wiki/OPUS_card" }, { "3B5F9600805A3F0608201223C44CFB30829000", "OPUS Card, used for transit in Greater Montreal and Quebec City, Canada (Transport)\nhttps://www.carteopus.info/?language=en" }, { "3B5F9600805A3F0608201223C44E6F25829000", "OPUS Metro card from Quebec, Canada (Transport)\nhttps://en.wikipedia.org/wiki/Opus_card" }, - { "3B5F9600805A3F1330141001C568504E829000", "OURA transport French (Transport)" }, { "3B5F9600805A3F1330141001C5D3ADC1829000", "OURA card (Transport)" }, { "3B5F9600805A3F1330141001C5D7A7E9829000", "<< Oura >> transport card (Transport)\nhttps://www.oura.com/" }, { "3B5F9600805A3F1330141001C656B5AA829000", "Oura Auvergne Rhone Alpes (Transport)\nhttps://oura.com" }, { "3B5F9600805A3F1330141001C6619BEA829000", "Oura card for Auvergne-Rhone-Alpes region in France. Using for several public transport (Transport)\nhttps://www.oura.com/" }, - { "3B5F9600805A3F2BC4141001C52E6FD3829000", "Mobib basic (Brussels transit card) (contact interface) (Transport)\nhttps://www.stib-mivb.be/buy/all-your-journeys-with-mobib" }, { "3B5F9600805A3F2BC4141001C5826963829000", "MOBIB Personal Travel Card, Brussels | STIB-MIVB (Transport)\nhttps://www.stib-mivb.be/article.html?_guid=d02c7fb6-3e9c-3810-248e-eec4ee5ebc8c&l=en" }, { "3B5F9600805AFFFF00FFFF0178724041829000", "Oura Card SNCF Transport - France Auvergne Rhone-Alpes (Transport)\nhttps://www.oura.com/xbi/boutique/card" }, - { "3B5F9600805AFFFF00FFFF0178728A57829000", "France Rhone-Alpes Region 'Carte Oura' 2nd generation (Transport)\nhttps://www.oura.com/la-demarche-oura/" }, { "3B600000", "Meano (Bank)" }, - { "3B61000041", "SBERKARTA MOMENTUM (Bank)" }, { "3B61000080", "blank A40CR card (JavaCard)" }, - { "3B6200004744", "UnionPay Debit card issued by Bank of China (Contact) (Bank)\nhttps://www.boc.cn/" }, { "3B630000364180", "Schlumberger Payflex 4k User" }, { "3B64..FF8062..A2", "JCOP20" }, { "3B64000080620.51", "Setec SetCOS 5.1.0 EMV" }, @@ -481,7 +469,6 @@ const static atr_t AtrTable[] = { { "3B6500002063CB3040", "Credit Mutuel Debit card (Bank)" }, { "3B6500002063CB3220", "Societe Generale CB Visa Debit (Bank)" }, { "3B6500002063CB3240", "Fnac MasterCard (contact interface) (Bank)\nhttps://www.fnac.com/carte-fnac-mastercard" }, - { "3B6500002063CB32A1", "MONABANQ (Bank - France) (Bank)" }, { "3B6500002063CB32C1", "Credit Card Credit Mutuel (Bank)\nhttps://www.creditmutuel.fr/partage/fr/CC/telechargements/communiques-de-presse/CM/2021/2021-03-17_CP-Carte_PVC_recycle.pdf" }, { "3B6500002063CB4700", "Orga SmartyPlus DATA STORE issued by MORPHO CARDS PERU" }, { "3B6500002063CB6300", "Bank card from Societe Generale (Oberthur)" }, @@ -641,7 +628,7 @@ const static atr_t AtrTable[] = { { "3B6800000073C84010009000", "Icelandic Banking scheme Issued by the Ministry of Treasure in Iceland\nhttp://www.islandsrot.is/" }, { "3B6800000073C84011009000", "Woolworths Everyday Money prepaid Mastercard\nNordea Bank Norway Visa + national debet card [BankAxept]\nVISA Classic - Nordlandsbanken (Norway)\nCiti Double Cash MasterCard\nWescom Credit Union Visa Debit Card (Bank)\nhttps://www.wescom.org/CHECKING/CHECK-CARD.ASP" }, { "3B6800000073C84012009000", "Brazilian 'e-CPF' card" }, - { "3B6800000073C84013009000", "MASTERCARD issued by MLP (Marschollek, Lautenschlager and Partner)\nG&D 12696-GDM-10/11 DEBIT CARD issued by BANCO DE CREDITO DEL PERU\nVisa from Caisse populaire Desjardins (Canada) (Bank)\nhttps://www.desjardins.com/\nMasterCard issued by President's Choice Bank (Canada)\nhttp://pcfinancial.ca/mastercard\nMasterCard issued by CIBC (Canada)\nhttp://www.cibc.com/\nMasterCard issued by The Bank of Nova Scotia (Canada)\nhttp://www.scotiabank.com/\nMasterCard issued by JPMorgan Chase Bank, N.A.\nhttps://www.chase.com/\nCaixaBank Visa Electron (Bank)\nhttps://www.lacaixa.cat/\nAmerican Express Canada Credit Card (Bank)\nAlfa-bank Russia Visa\nPNC Bank Visa debit card (Bank)\nhttps://www.pnc.com/en/personal-banking/banking/debit-and-prepaid-cards/pnc-bank-visa-debit-card.html" }, + { "3B6800000073C84013009000", "MASTERCARD issued by MLP (Marschollek, Lautenschlager and Partner)\nG&D 12696-GDM-10/11 DEBIT CARD issued by BANCO DE CREDITO DEL PERU\nVisa from Caisse populaire Desjardins (Canada) (Bank)\nhttps://www.desjardins.com/\nMasterCard issued by President's Choice Bank (Canada)\nhttp://pcfinancial.ca/mastercard\nMasterCard issued by CIBC (Canada)\nhttp://www.cibc.com/\nMasterCard issued by The Bank of Nova Scotia (Canada)\nhttp://www.scotiabank.com/\nMasterCard issued by JPMorgan Chase Bank, N.A.\nhttps://www.chase.com/\nCaixaBank Visa Electron (Bank)\nhttps://www.lacaixa.cat/\nAmerican Express Canada Credit Card (Bank)\nAlfa-bank Russia Visa" }, { "3B6800000073C8401300907D", "NextCard - Mastercard Debit card - Intesa Sanpaolo Bank (Italy) (Bank)\nhttps://www.intesasanpaolo.com/it/persone-e-famiglie/prodotti/carte/carte-di-debito/next-card.html" }, { "3B68000000DE511001019000", "Itau Bank Mastercard Debit Card (Brazil) (Bank)\nhttps://www.itau.com.br" }, { "3B6800000101309600009000", "Edenred - French Restoration e-Ticket card (2013) (Other)\nhttps://www.edenred.fr/ticket-restaurant" }, @@ -653,8 +640,6 @@ const static atr_t AtrTable[] = { { "3B6800004D4343434C322E31", "Mastercard debit card from FIO bank, CZ (Bank)\nhttps://www.fio.cz/bankovni-sluzby/platebni-karty/mastercard-debit-contactless" }, { "3B68000053430660010F9000", "Credit Card Credicard (Bank)\nhttp://www.credicard.com.br" }, { "3B68000053430660010F9090", "Discount (Bank)" }, - { "3B68000053430662010F9000", "LINE Bank by Hana Bank Sally Debit Visa (Bank)" }, - { "3B68000053430663010F9000", "Maybank ID Debit Mastercard (Bank)\nBank BRI Blue Debit GPN (Bank)" }, { "3B68000053432D3031324A53", "Blue (Bank)" }, { "3B6800005448204E49442036", "Thai id card (Other)" }, { "3B680000565344434C433130", "VISA (Estonian), made by www.trueb.ch\nLatvian bank 'Latvijas Krajbanka' (VISA Electron)" }, @@ -686,7 +671,6 @@ const static atr_t AtrTable[] = { { "3B6900002494010000000001A9", "Kazakhstan Helios gas station debit card\nhttp://helios.kz/" }, { "3B6900002494010201000101A9", "Chipcard from SUN to be used in SunRay's\n370-4328-01 (31091)" }, { "3B6900002494010301000100A9", "Schlumberger MicroPayflex S card" }, - { "3B69000047445F44695F54504E", "ICBC (Bank)" }, { "3B6900004944353056312E....", "eID Card to user authenticate and save passwords in the Card. Product ID50 Password manager from IDENTOS GmbH (eID)\nhttps://identos.com/id50-password-manager/" }, { "3B6900004944363056312E....", "token appidkey ID60-USB (Other)\nhttps://identsmart.com/en/products/id60-datasafe/" }, { "3B6900004A434F503331563232", "Visa Europe Sample Card / Axalto" }, @@ -729,7 +713,6 @@ const static atr_t AtrTable[] = { { "3B6A00008066A1090201630E9000", "Danish Visa/Dankort\nUK MBNA MasterCard\nVisa Card - Worldcard - YapiKredi / Turkey\nVISA - Lloyds TSB DEBIT\nUK Halifax Visa Debit" }, { "3B6A00008066A20A01018B0E9000", "CAP-EMV demo card" }, { "3B6A0000813F017511010281010A", "Huada CIU9872B (Java Card 2.2.2) (JavaCard)" }, - { "3B6A00008141019810000000000A", "UnionPay Debit card issued by Bank of China (Contact) (Bank)\nhttps://www.boc.cn/" }, { "3B6A0000866500A758C046009000", "China Merchants Bank card (Bank)" }, { "3B6A0000866500A758C055009000", "Credit card (Bank)" }, { "3B6A00FF0031C173C84000009000", "Paypal EMV debit card (Bank)\nAmerican Express Canada Credit Card (Bank)\nhttps://www.americanexpress.com/ca/en/credit-cards/all-cards/?intlink=ca-en-hp-product1-cm-personalcards-03242021" }, @@ -801,15 +784,12 @@ const static atr_t AtrTable[] = { { "3B6B00000031C164086032200F9000", "Twisto (Bank)" }, { "3B6B00000031C16408603221079000", "DSK Bank Debit Mastercard (Bank)" }, { "3B6B00000031C164086032220F9000", "Universidade de Aveiro (ID Card) (eID)\nhttps://www.ua.pt/pt/sas/cartao" }, - { "3B6B00000031C16408603242079000", "CIMB BANK MALAYSIA (Bank)" }, { "3B6B00000031C164086032420F9000", "Westpac Handybank EFTPOS/ATM Card (Bank)" }, { "3B6B00000031C164087771300F9000", "Apple Card (from launch) (Bank)\nhttps://www.apple.com/apple-card/" }, { "3B6B00000031C16408777156079000", "American Express UK Euro ICC charge card (Bank)\nhttps://www.americanexpress.com/icc/cards/the-basic-international-currency-card.html" }, { "3B6B00000031C16408986200079000", "EquaBank Master Card (Bank)\nhttps://equabank.cz" }, { "3B6B00000031C164089862000F9000", "NovaKBM Visa Debit (Bank)" }, { "3B6B00000031C164089862010F9000", "Sodexo Czech Gastro/Multipass (Other)\nhttps://www.sodexo.cz/" }, - { "3B6B00000031C164089862020F9000", "Blu BCA Digital Debit Mastercard (Bank)" }, - { "3B6B00000031C16408986213079000", "Stravenka (Other)" }, { "3B6B00000031C1640924331E0F9000", "Cembra Money Bank - Certo! Mastercard credit card (Bank)\nhttps://certo-card.ch/certo/de/" }, { "3B6B00000031C164092962250F9000", "SANTANDER BASIC CASH CARD (Bank)\nhttps://www.santander.co.uk/assets/s3fs-public/2018-09/Basic%20Current%20Account%20KFD.pdf" }, { "3B6B00000031C16409644136079000", "HSBC UK Visa Debit Card (Bank)\nhttps://www.hsbc.co.uk/content/dam/hsbc/gb/pdf/help/hsbc-visa-debit-card-guide.pdf" }, @@ -834,7 +814,6 @@ const static atr_t AtrTable[] = { { "3B6B000081007226010010000F9000", "Debit card issued by Falabella Bank of Peru from IDEMIA (Bank)\nhttp://www.bancofalabella.pe" }, { "3B6B000081007226020040000F9000", "Yuna To Go prepaid MasterCard (PaySafeCard) (Bank)\nhttp://yunacard.com\nPaygoo Reload Mastercard" }, { "3B6B000081007226020041000F9000", "Wave Crest Holding (Bank)" }, - { "3B6B000081007230050070000F9000", "Postbank VISA card prepaid (Bank)\nhttps://www.postbank.de/privatkunden/services/konten-und-karten/visa-card-prepaid-aufladen.html" }, { "3B6B000081007843040241010F9000", "Max Mastercard (Bank)\nhttps://www.aumax.fr" }, { "3B6B0000FF86885A48544430322011", "CMB UnionPay Debit (Bank)" }, { "3B6B00FF33000009FA10008001FFFF", "Atmel 6464C PRO 64K" }, @@ -889,10 +868,7 @@ const static atr_t AtrTable[] = { { "3B6D00000080318065B0893501F183009000", "MasterCard (Bank)" }, { "3B6D000000814D22088660200811000001", "BANK OF HEBEI Debit Card (Bank)" }, { "3B6D000000814D22088660222228400001", "Unipay Credit Card Issued by CITIC (Bank)" }, - { "3B6D0000008500001086880000001DA844", "UnionPay Debit card issued by China Construction Bank (Bank)\nhttps://www.ccb.com/" }, - { "3B6D0000008C430101868821014015D856", "UnionPay Debit card issued by Industrial and Commercial Bank of China (Contact) (Bank)\nhttps://www.icbc.com.cn/" }, { "3B6D0000009008209000900000FFFFFFFF", "Student college card" }, - { "3B6D000004008688010001626A79686963", "UnionPay Debit card issued by China Minsheng Bank (Contact) (Bank)\nhttps://www.cmbc.com.cn/" }, { "3B6D00004946582D6A6333303167703232", "MasterCard Debit card of N26 bank (Bank)" }, { "3B6D00005744285746035062136568541F", "Card for decrypt encrypted tv channels made in china (Pay TV)" }, { "3B6D00005744296C808693D1271F13323D", "SCSTA (Transport)" }, @@ -924,7 +900,6 @@ const static atr_t AtrTable[] = { { "3B6D00FF80655343010D067394211B810[15]", "Giesecke & Devrient CardToken 350 (ICCD)" }, { "3B6D00FF8073002113574A544861314700", "ActiveKey SIM" }, { "3B6D00FF8073002113574A544861314800", "Spanish Medical College Card" }, - { "3B6E00000000814D22088660300020E00007", "Mastercard Debit card issued by Bank of China (Contact) (Bank)\nhttps://www.boc.cn/" }, { "3B6E00000031807186650164022232809000", "MasterCard Card - bonus plus (paypass) - Garanti Bank / Turkey" }, { "3B6E00000031807186650164022232839000", "MasterCard Card - bonus YKM - Garanti Bank / Turkey" }, { "3B6E0000003180718665016702A00A839000", "Australian ANZ First Visa Card from the ANZ\n(Australia and New Zealand) Bank" }, @@ -1041,7 +1016,7 @@ const static atr_t AtrTable[] = { { "3B6E000080318065B00301015E8300009000", "FirstUSA Visa" }, { "3B6E000080318065B00302015E8300009000", "Gemplus GemXpresso 211is" }, { "3B6E000080318066B0070300AC0183009000", "e-payment card with topup system, propreteary by local bank\nhttp://www.klikbca.com/individual/silver/product.html?s=69" }, - { "3B6E000080318066B0840C016E0183009000", "Optelio Cards (D72 R4 WR)\nNordea (a Skandinavian bank) eID card\nhttp://linux.fi/wiki/Nordea_eID\nNordea Mastercard card\nNordea Visa card\nRBC Royal Bank Client Card (bank in Canada)\nBanco Santander TUI/USC R7\nGemalto Optelio/Desineo D72 (JavaCard) with WG10 and Maestro (JavaCard) (Bank)\nCarte Ticket Restaurant with MasterCard\nCitigold VISA Debit for Citibank, Australia\nPlatinum VISA card for Citibank, Australia\nVISA Infinite issued by RBC Royal Bank (Canada)\nhttp://www.rbc.com/\nPostepay Evolution - Poste Italiane (mastercard)\n'la Caixa' (Spain) (VISA Electron) debit card (Bank)\nhttps://www.lacaixa.es/\nItalian Webank.it BPM Banca Popolare di Milano Bancomat & Maestro Card (Bank)\nSberbank of Russia MIR debit card (Bank)\nMasterCard bank card by OTP Bank (Hungary)\nUniCredit Bank in Serbia" }, + { "3B6E000080318066B0840C016E0183009000", "Optelio Cards (D72 R4 WR)\nNordea (a Skandinavian bank) eID card\nhttp://linux.fi/wiki/Nordea_eID\nNordea Mastercard card\nNordea Visa card\nRBC Royal Bank Client Card (bank in Canada)\nBanco Santander TUI/USC R7\nGemalto Optelio/Desineo D72 (JavaCard) with WG10 and Maestro (JavaCard) (Bank)\nCarte Ticket Restaurant with MasterCard\nCitigold VISA Debit for Citibank, Australia\nPlatinum VISA card for Citibank, Australia\nVISA Infinite issued by RBC Royal Bank (Canada)\nhttp://www.rbc.com/\nPostepay Evolution - Poste Italiane (mastercard)\n'la Caixa' (Spain) (VISA Electron) debit card (Bank)\nhttps://www.lacaixa.es/\nItalian Webank.it BPM Banca Popolare di Milano Bancomat & Maestro Card (Bank)\nSberbank of Russia MIR debit card (Bank)\nMasterCard bank card by OTP Bank (Hungary)" }, { "3B6E000080318066B08412016E0183009000", "Barclaycard Platinum VISA\nInteligo debit card\nVISA issued by ING (Poland)\nVISA Debit card for ING Direct, Australia\nVISA Gold issued by RBC Royal Bank (Canada)\nhttp://www.rbc.com/\nGas Natural Fenosa Visa (issued by CaixaBank) (Bank)\nhttp://www.clubfenosa.gasnaturalfenosa.es/ca/1285341160257/targeta+gas+natural+fenosa.html" }, { "3B6E000080318066B08416016E0183009000", "UK 'Barclaycard Gold VISA' with RFID" }, { "3B6E000080318066B0870C016E0183009000", "Banco Santander TUI/USC R7 - Gemalto Optelio/Desineo D72 (JavaCard)\nhttp://www.observatoriotui.com/home" }, @@ -1052,8 +1027,6 @@ const static atr_t AtrTable[] = { { "3B6E000080318066B1A50102321983009000", "Meeza BDC (Bank)" }, { "3B6E000080318066B1A60101011383009000", "Finnish Smartum benefit card (Other)\nhttps://www.smartum.fi/" }, { "3B6E00008066B1A30401110B83009000", "Bank of America (Bank)\nhttps://www.bankofamerica.com/" }, - { "3B6E00008066B1A30401110B830090000000", "Bank of America (Bank)\nhttps://www.bankofamerica.com/" }, - { "3B6E000086881102010100004748F1FF5550", "UnionPay Debit card issued by Industrial and Commercial Bank of China (Contact) (Bank)\nhttps://www.icbc.com.cn/" }, { "3B6E00FF00620000574156414E5410819000", "debit card (Visa Electron) issued by Nordea bank" }, { "3B6E00FF4573744549442076657220312E30", "Estonian Identity Card (EstEID v1.0 warm)" }, { "3B6E00FF47442D47502D333256342D444553", "Mastercard Ourocard Platinum from Banco do Brasil" }, @@ -1072,7 +1045,6 @@ const static atr_t AtrTable[] = { { "3B6F00000031C173C8211064474D3332009000", "td debit visa card (Bank)\nScotiabank ScotiaCard Interac/Visa debit card (Bank)\nhttps://www.scotiabank.com/ca/en/personal/ways-to-bank/debit-credit-prepaid-cards/debit-cards/scotiacards.html" }, { "3B6F00000031C173C8211064474D3338009000", "ING Direct Debit Card (Bank)" }, { "3B6F00000031C173C8211064474D3341009000", "Fineco debit card (Bancomat, Visa Debit) (Bank)\nhttps://finecobank.com/it/online/conto-e-carte/carte-e-bancomat/" }, - { "3B6F00000031C173C8211064474D3342009000", "Visa Debit card issued by Bank of China (Contact) (Bank)\nhttps://www.boc.cn/" }, { "3B6F00000031C173C8211064474D3435009000", "VISA card, issued by OP Financial Group, Finland (Bank)\nVISA card, issued by S-Pankki, Finland (Bank)" }, { "3B6F00000031C173C8211064474D3437009000", "Visa credit card, issued by Klarna (Bank) (Bank)\nhttps://www.klarna.com/se/kort/" }, { "3B6F00000031C173C8211064474D3533009000", "American Express Platinum Card Mexico (Bank)\nhttps://www.americanexpress.com/mx/tarjetas-de-credito/the-platinum-credit-card/" }, @@ -1099,7 +1071,6 @@ const static atr_t AtrTable[] = { { "3B6F00003101F1564011001900000000000000", "Postepay Evolution (Bank)\nhttps://postepay.poste.it/prodotti/postepay-evolution.html" }, { "3B6F000057694C4C5700000000000020190328", "meza classic card (Bank)" }, { "3B6F000057694C4C5700000000000020200429", "AMEX CHINA Debit card, Java Card version 2.2, Global Platform version 2.1.1, Visa card manager (Bank)" }, - { "3B6F000057694C4C5700000000000020200430", "Mastercard China Debit card issued by Postal Savings Bank of China (Contact) (Bank)\nhttps://www.psbc.com/" }, { "3B6F0000626C75636172642031364B422F7634", "eID Blutronics Blucard 16K\nhttp://blucard.blutronics.com" }, { "3B6F00008031C0520083640219083283839000", "Bancomer Mexican Bank" }, { "3B6F00008031C05205B5640200647183839000", "Read Card in USB, used for application in Java. (JavaCard)" }, @@ -1131,12 +1102,12 @@ const static atr_t AtrTable[] = { { "3B6F00008031E06B0421050261555555555555", "NORSK TIPPING NORWAY\nhttp://www.norsk-tipping.no/" }, { "3B6F00008031E06B042105026C555555555555", "Icelandic Electronic ID (eID)\nhttps://www.audkenni.is/rafraen-skilriki/einkaskilriki/" }, { "3B6F00008031E06B0421050272555555555555", "Card CAA Quebec (Mastercard) (Bank)\nhttps://www.caaquebec.com/en/your-privileges/caa-dollars/earning/caa-quebec-dollars-mastercardr-credit-card/" }, - { "3B6F00008031E06B04310502A6555555555555", "USAA EMV Mastercard Creditcard (Bank)\nhttps://www.usaa.com/inet/pages/bk_cc_chipcardLP_landing_mkt?adID=VURL_chipcard\nTarget REDcard debit\nhttps://target.com/myREDcard" }, + { "3B6F00008031E06B04310502A6555555555555", "USAA EMV Mastercard Creditcard (Bank)\nhttps://www.usaa.com/inet/pages/bk_cc_chipcardLP_landing_mkt?adID=VURL_chipcard" }, { "3B6F00008031E06B04310502AC555555555555", "Diners Club Credit card (British Airways, Switzerland) (Bank)\nhttps://dinersclub.ch/en/private-customers/all-credit-cards/british-airways-card/" }, { "3B6F00008031E06B04310502AF555555555555", "debit card (Bank)\nhttps://www.usaa.com/inet/wc/banking" }, { "3B6F00008031E06B04310502D1555555555555", "Pockit Pre-Paid Mastercard (Contact Chip). (Bank)\nhttps://revolut.com/" }, { "3B6F00008031E06B04310502D6555555555555", "Bank IN - Slovenian bank (Bank)\nhttps://www.bankain.si/BIN/vstopna.seam" }, - { "3B6F00008031E06B04520502BB555555555555", "AlfaBROU - Mastercard (prepaid card emitted by Banco Republica - Uruguay) (Bank)\nhttps://www.brou.com.uy/personas/tarjetas/prepaga-alfabrou\nCapital One - Mastercard debit card (Bank)\nhttps://www.capitalone.com/bank/debit-card/" }, + { "3B6F00008031E06B04520502BB555555555555", "AlfaBROU - Mastercard (prepaid card emitted by Banco Republica - Uruguay) (Bank)\nhttps://www.brou.com.uy/personas/tarjetas/prepaga-alfabrou" }, { "3B6F00008031E06B04520502FD555555555555", "C6 Bank Mastercard Global Account (Bank)\nhttps://www.c6bank.com.br/conta-global\nC6 Bank Mastercard Brazil Account (Bank)\nhttps://www.c6bank.com.br/nossos-produtos" }, { "3B6F00008031E06B04520502FE555555555555", "CITIBanamex 'Perfiles' debit card (Bank)\nhttps://www.banamex.com/es/personas/cuentas/cuenta-perfiles.html" }, { "3B6F00008031E06B04546B026D555555555555", "Mastercard Credit/Debit Card (Bank)" }, @@ -1230,7 +1201,6 @@ const static atr_t AtrTable[] = { { "3B6F0000805A0A070620042C0490EFCB829000", "Rav-Kav Israel (Transport)\nhttps://ravkavonline.co.il" }, { "3B6F0000805A0A070620042C04940F18829000", "Israeli anonymous rail road Rav Kav 2022 model (Transport)\nhttps://en.wikipedia.org/wiki/Rav-Kav" }, { "3B6F0000805A0A070620042C0494625E829000", "Israeli rail road rav card (Transport)\nhttps://en.wikipedia.org/wiki/Rav-Kav" }, - { "3B6F0000805A0A070620042D9363A22B829000", "Rav-Kav Transport\nhttps://ravkavonline.co.il/en/" }, { "3B6F0000805A0A070620042DC1660B73829000", "Rav-Kav: Israel's Travel Card (Transport)" }, { "3B6F0000805A0A070620042DC169517A829000", "Card for bus (Transport)" }, { "3B6F0000805A0A070620042DC2E8E270829000", "ravkav (Transport)" }, @@ -1277,7 +1247,6 @@ const static atr_t AtrTable[] = { { "3B6F0000805A28114210122B27AE59B9829000", "French 'Navigo' transport card (Transport)\nhttp://www.navigo.fr/" }, { "3B6F0000805A28114210122B4C09310D829000", "Pass Navigo personnalise (Paris) (Transport)\nhttp://www.navigo.fr/titres/le-forfait-navigo-mois-choix-carte-navigo-carte-decouverte/" }, { "3B6F0000805A28114210122B4C0EFAD0829000", "Ile-de-France Mobilites (Navigo Nominative) (Transport)\nhttps://www.iledefrance-mobilites.fr/titres-et-tarifs/supports/passe-navigo" }, - { "3B6F0000805A28130210122B034BA194829000", "Korrigo (Brittany transit card) (contact interface) (Transport)\nhttps://www.korrigo.bzh/" }, { "3B6F0000805A28130210122B034BEB8D829000", "Korigo card transport for star company (France) (Transport)\nhttp://www.star.fr/titres-et-tarifs/carte-korrigo/" }, { "3B6F0000805A28130210122B03CF898A829000", "Korrigo Card (Rennes Metropole bus network) (Transport)\nhttps://www.star.fr/" }, { "3B6F0000805A28130210122B03D99C6F829000", "KorriGo (Brittany) transport card (Transport)" }, @@ -1333,9 +1302,7 @@ const static atr_t AtrTable[] = { { "3B6F0000805A2D06081010027835EDCE829000", "Lisbon Transportation SmartCard (Transport)" }, { "3B6F0000805A2D06081010027848BBCC829000", "Lisbon Metro Monthly Student Pass (Transport)\nhttps://www.metrolisboa.pt/" }, { "3B6F0000805A2D0608101005935C42FB829000", "Comboios de Portugal Transit Card (Transport)\nhttps://www.cp.pt/passageiros/pt/consultar-horarios/precos/cartao-cp" }, - { "3B6F0000805A2D06081010059468C083829000", "Comboios de Portugal Transit Card (Transport)\nhttps://www.cp.pt/passageiros/pt/consultar-horarios/precos/cartao-cp" }, { "3B6F0000805A2E130200010104EF8342829000", "Oura Auvergne-Rhone-Alpes (Transport)\nhttps://www.oura.com" }, - { "3B6F0000805A2E1302000101055CA7E3829000", "OURA card, FRench isere transport (Transport)\nhttps://www.oura.com" }, { "3B6F0000805A3407061500017917A7E2829000", "Rav-Kav multi-line travel ticket used in the public transportation system in Israel (Transport)\nhttps://www.gov.il/en/departments/guides/multi_line_card" }, { "3B6F0000805A340706150001792A4B5C829000", "Rav Kav Transit Payment Card (Israel) (Transport)\nhttps://ravkavonline.co.il/" }, { "3B6F0000805A3B0102151201798DE8C9829000", "TAM Montpellier France (Transport)" }, @@ -1344,8 +1311,6 @@ const static atr_t AtrTable[] = { { "3B6F0000805A3B070615010279537211829000", "Israeli public transport card ('RavKav') (Transport)\nhttps://ravkavonline.co.il" }, { "3B6F0000805A3B07061501027956C5F4829000", "RAVKAV - Israel dual interface transport card (Calypso standard) (Transport)\nhttps://en.wikipedia.org/wiki/Rav-Kav" }, { "3B6F0000805A3B070615010279C3C331829000", "Rav-Kav Israel (Transport)\nhttps://ravkavonline.co.il" }, - { "3B6F0000805A3B070615010279ED6905829000", "rav-kav (Transport)" }, - { "3B6F0000805A3C0608140101C2F8B0EF829000", "Navegante Lisboa Viva (Transport)\nhttps://www.portalviva.pt/" }, { "3B6F0000805A3C0608140101C3805E38829000", "Lisboa VIVA - Lisbon public transport card (Transport)\nhttps://www.portalviva.pt/" }, { "3B6F0000805A3C0608140101C4D4FEC4829000", "Metropolitan Transports of Lisbon NAVEGANTE Card (Transport)\nhttps://www.navegante.pt/viajar/cartoes" }, { "3B6F0000805A3C0608140101C4D522FB829000", "Navegant Perdonal Card - Transportes Metropolitanos de Lisboa (Transport)\nhttps://www.navegante.pt/" }, @@ -1380,7 +1345,6 @@ const static atr_t AtrTable[] = { { "3B6F0000805A3D23C415010279376C64829000", "Brussel public transport NFC card (Transport)\nhttps://www.stib-mivb.be/mystib" }, { "3B6F0000805A3D23C41501027937D7AE829000", "MOBIB - Brussels (Transport)\nhttps://www.stib-mivb.be/article.html?_guid=d02c7fb6-3e9c-3810-248e-eec4ee5ebc8c&l=fr" }, { "3B6F0000805A3D23C41501027949789C829000", "MOBIB basic (Transport)\nhttp://www.stib-mivb.be/article.html?_guid=30af0085-2483-3410-5394-a71daf08acd1&l=en#contentBodyList1" }, - { "3B6F0000805A3D23C41501027949B7D5829000", "MOBIB basic card (Transport)\nhttps://www.stib-mivb.be/buy/all-your-journeys-with-mobib" }, { "3B6F0000805A3D23C4150102795A863C829000", "mobib transportation card (Transport)" }, { "3B6F0000805A3D23C415010279748A25829000", "Mobib (Brussels transport card) for the STIB-MIVB network (Transport)\nhttps://www.stib-mivb.be/article.html?_guid=d02c7fb6-3e9c-3810-248e-eec4ee5ebc8c&l=fr" }, { "3B6F0000805A3D23C415010279A9E567829000", "MoBIB card, a medium for the transport tickets of the four Belgian public transport operators (Transport)\nhttps://mobib.be/" }, @@ -1400,7 +1364,6 @@ const static atr_t AtrTable[] = { { "3B6F00008066B0070101770753023110829000", "University ID card (issued by Banco Santander Central Hispano)\n.\nUniversidad Nacional de Educacion a Distancia (UNED, Spain)\nhttp://www.uned.es/tarjeta\n.\nUniversitat Politecnica de Catalunya (UPC.edu)\nhttps://www.upc.edu/identitatdigital\n.\nUniversitat Ramon Llull (URL)\nhttp://www.url.edu/cont/url/carnet.php" }, { "3B6F00008066B0070101770753023124829000", "Santander 4B Maestro\nUniversity of Santiago de Compostela. Spain\nPolytechnical University of Madrid, Spain" }, { "3B6F00018031E06B0406050211555555555555", "American Express 'Entourage' credit card issued by CIBC\nhttp://www.cibc.com" }, - { "3B6F00FF0031C173C8211064414D3137079000", "Mastercard ING (Bank)" }, { "3B6F00FF0031C173C8211064414D3348079000", "BNP (Bank)" }, { "3B6F00FF0031C173C82110644930424E079000", "National Bank Card (Bank)" }, { "3B6F00FF00567275546F6B6E73302000009000", "Aktiv Rutoken S\nhttps://www.rutoken.ru/products/all/rutoken-s/" }, @@ -1418,7 +1381,6 @@ const static atr_t AtrTable[] = { { "3B751300004709EA9000", "Carte Vitale (HealthCare)" }, { "3B751300004809EA9000", "Carte Vitale (HealthCare)\nhttps://en.wikipedia.org/wiki/Carte_Vitale" }, { "3B751300004909EA9000", "Vitale Card French Healthcare (HealthCare)\nhttps://www.service-public.fr/particuliers/vosdroits/F265" }, - { "3B751300004B09EA9000", "Carte Vitale d'assurance maladie, France (HealthCare)\nhttps://www.service-public.fr/particuliers/vosdroits/F265" }, { "3B751300009C02020102", "Cyberflex Access 32k v2" }, { "3B759400006202020[1-3]01", "Schlumberger Cyberflex 32K e-gate\nGemalto TOP US (product code HWP115278A)" }, { "3B76110000009C11010202", "Schlumberger Cyberflex Access 32K" }, @@ -1461,7 +1423,6 @@ const static atr_t AtrTable[] = { { "3B789600005343066001079000", "Bank of America Travel Rewards Credit Card (Bank)\nhttps://www.bankofamerica.com/credit-cards/products/travel-rewards-credit-card/" }, { "3B789600005343066101079000", "Bank of America Cash Rewards World Mastercard (Bank)" }, { "3B789600005343066201079000", "ATM Card (Bank)" }, - { "3B789600005343066301079000", "Bank Saqu Debit GPN (Bank)" }, { "3B789600008100035001079000", "RMA BMCE BANK CARD (Bank)" }, { "3B791100008054434F4C44829000", "amazon.de / VISA / LBB Debit Card (Bank)" }, { "3B79130000806416030183829000", "Raiffeisen VPay Debit Card (Bank)\nhttp://raiffeisen.ch" }, @@ -1537,7 +1498,6 @@ const static atr_t AtrTable[] = { { "3B7D180002805759505349443033837F9000", "Sagem YpsID s2 (SafeSign)\nBrazilian 'e-CNPJ' card, issued by Certisign (Safesign)" }, { "3B7D180002805759505349443034837F9000", "Morpho e-CPF YpsID S2-11/11 (PKI)\nhttp://safeweb.com.br" }, { "3B7D9400005555530A7486930B247C4D5468", "SIM from sysmocom sysmoSIM-GR2" }, - { "3B7D94000057442101181207010000000000", "mir (Bank)" }, { "3B7D94000057442908308693070565182B56", "Canal Digitaal (Pay TV)\nhttp://webshop.canaldigitaal.nl/nl/smartcards-2" }, { "3B7D9400005744295A2186930332EF174607", "Chevrolet Club Card (Loyalty)\nhttps://my.chevrolet.com/login" }, { "3B7D940000574429615086930351462501DC", "Sodexo Meal Card (Other)\nhttps://www.sodexoavantaj.com" }, @@ -1545,7 +1505,6 @@ const static atr_t AtrTable[] = { { "3B7D94000057445324658693020581741057", "kyivstar (Telecommunication)" }, { "3B7D940000574453246586930210B7251297", "Kyivstar (Telecommunication)" }, { "3B7D94000057445363968693009DF710009D", "China Mobile SIM card" }, - { "3B7D94000057445364968693049DF710009D", "oiran-sim-card (Telecommunication)" }, { "3B7D94000057445372FD8693110106755B0F", "China Telecom UIM 64K" }, { "3B7D94000057445396FA869303B7BFBF5F63", "Airtel India SIM" }, { "3B7D94000057445399648693120300006346", "Dtac (Telecommunication)" }, @@ -1743,7 +1702,6 @@ const static atr_t AtrTable[] = { { "3B7F96000080318065B085040120F20002829000", "Health Insurance Institute of Slovenia - Professional Card Gen. 3 (HealthCare)" }, { "3B7F96000080318065B085050011120FFF829000", "LuxTrust card (Luxembourg qualified electronic signature / authentication system) (Other)\nhttps://www.luxtrust.com/en/professionals/smartcard" }, { "3B7F96000080318065B085050039120FFE829000", "SafeNet IDPrime 940C (eID)\nhttps://data-protection-updates.gemalto.com/2023/10/05/safenet-etoken-5110-cc-940c-release-announcement/" }, - { "3B7F96000080318065B085051024120FFF829000", "Swedish ID card from Skatteverket with an Electronic ID from AB Svenska Pass (eID)\nhttps://www.thalesgroup.com/sv/europe/sweden/digital-identity-services-sweden/svensk-elegitimation/skatteverkets-id" }, { "3B7F96000080318065B0855956FB120268829000", "qualified certificate (eID)\nhttps://www.elektronicznypodpis.pl/en/offer/qualified-certificates/" }, { "3B7F96000080318065B0855956FB1202C1829000", "Gemalto USB (eID)" }, { "3B7F96000080318065B0855956FB120FFE829000", "Thales (Gemalto) IDPrime 941 (PKI)\nhttps://cpl.thalesgroup.com/de/access-management/idprime-md-pki-smart-cards\nThales SafeNet IDPrime 940B (PKI)\nhttps://cpl.thalesgroup.com/resources/access-management/idprime-940-product-brief" }, @@ -1862,10 +1820,8 @@ const static atr_t AtrTable[] = { { "3B868001801434373000A0", "Malta eID Identity Card (eID)\nhttps://www.identitymalta.com/" }, { "3B8680018031C15211182C", "IDEMIA Cosmo V8.0 with a PIV applet (contactless) (PKI)" }, { "3B8680018031C152411A7E", "IDEMIA Cosmo V8.1 with a PIV applet (contactless) (PKI)" }, - { "3B868001804F03F001003A", "Second-generation Resident Identity Card of the People's Republic of China (eID)\nhttps://www.gov.cn/zhengce/2011-10/29/content_2602263.htm" }, { "3B86800180540410010FC9", "Nickel.eu prepaid account (Bank)\nhttps://nickel.eu" }, { "3B86800180540420010FF9", "advance medical expenses in France (consultation, medications, hospitalization, etc.). commercial name is 'Avance Sante'. (HealthCare)" }, - { "3B86800187870202000007", "Nano USIM card of 'LG U+' in South Korea. (model name U2720) (Telecommunication)" }, { "3B868001C1052F2F01BC7E", "Contactless interface to St. Petersburg unified card, Russia (Edinaia karta peterburzhtsa) (Other)\nhttps://ekp.spb.ru/" }, { "3B868001F04938DE0C3064", "blyt mtrw (Transport)\nhttps://ezpay.ir/" }, { "3B868131703445504120454B08", "Austrian Quick E-purse 'Einreichkarte' (transfer card)\nhttp://www.quick.at/" }, @@ -1873,7 +1829,6 @@ const static atr_t AtrTable[] = { { "3B8780014D525444312E3026", "Russian Foreign Passport (passport)" }, { "3B8780014D525444322E3025", "Biometric Passport of the Russian Federation (passport)" }, { "3B8780015A4350757273655E", "ZCPurse RFID card (ATR created by PCSC-Reader) (Transport)\nhttp://www.zeitcontrol.de/en/zcpurse" }, - { "3B87800169536869656C6450", "SwissBit iShield Key Security Key (FIDO2) (Other)\nhttps://www.swissbit.com/en/products/ishield-key/" }, { "3B87800173C840000090006D", "Amazon.de VISA Card (Bank)\nhttp://lbb.de/amazon\nCIBC Visa" }, { "3B8780017743324C0101004C", "CiPurse L profile with 304 bytes user memory (Other)\nhttps://www.infineon.com/cms/en/product/security-smart-card-solutions/cipurse-products/" }, { "3B878001774332530008005B", "CiPurse S profile (Other)\nhttps://www.infineon.com/cms/en/product/security-smart-card-solutions/cipurse-products/" }, @@ -1922,19 +1877,16 @@ const static atr_t AtrTable[] = { { "3B888001000000008081710079", "Apple Pay card - Usually EMV" }, { "3B88800100000000808175007D", "Singapore SimplyGo EZ-Link Card (Transport)\nhttps://simplygo.com.sg" }, { "3B888001000000009171710098", "Public transportation fare card (Morocco CAS: Urban bus) (Transport)" }, - { "3B888001000000009181710068", "PassPass card (Transport)\nhttps://www.passpass.fr/fr/e-boutique/achat-carte" }, { "3B888001000000009181C100D8", "Driving License card of Japan (NFC type-B) (eID)" }, { "3B88800100000000B37171.0.A", "Public transportation card in Riga, Latvia, called 'e-Talons'\nhttp://etalons.rigassatiksme.lv/en/payments/activating_the_e-ticket/\nBelgian MOBIB (transport)" }, - { "3B88800100000000B3717100BA", "Pastel (transport card in Occitania and Toulouse, France) (Transport)\nhttps://www.ter.sncf.com/occitanie/services-contacts/souscription-carte-pastel" }, { "3B88800100000000F781C100BE", "Italian Health Insurance card (eID)\nhttps://en.wikipedia.org/wiki/Italian_health_insurance_card" }, { "3B88800100000011778183006D", "Taglio PIVKey C980 - RFID I/F (PKI)" }, { "3B88800100000011F7818100EF", "MOBIB card (Transport)\nhttps://mobib.be/en.html\nPasse Navigo Easy (Transport Ile de France) (Transport)\nhttps://www.iledefrance-mobilites.fr/titres-et-tarifs/supports/passe-navigo-easy" }, { "3B8880010000010701729000EC", "Belgian passport (2008-2009)" }, - { "3B888001000005E0B381A1007F", "Japanese Public Key Infrastructure (PKI)\nhttps://www.jpki.go.jp/\nJapanese Individual Number Card (My Number Card) (eID)\nhttps://www.kojinbango-card.go.jp/en" }, + { "3B888001000005E0B381A1007F", "Japanese JPKI card (aka JINC card) (eID)\nhttps://github.com/jpki/myna" }, { "3B888001000014E0B38191005E", "'JUKICARD', the Basic Resident Registration Card in Japan (eID)" }, - { "3B888001000041E0B381A1003B", "Japanese Public Key Infrastructure (PKI)\nhttps://www.jpki.go.jp/\nJapanese Individual Number Card (My Number Card) (eID)\nhttps://www.kojinbango-card.go.jp/en" }, + { "3B888001000041E0B381A1003B", "ID card issued by Japan government (eID)\nhttps://www.kojinbango-card.go.jp/mynumber/index.html" }, { "3B8880010000C9047781730041", "D-TRUST Card 4.1, qualified signature card (eID)\nhttps://www.d-trust.net" }, - { "3B888001004B51FFB381D1000F", "Japanese Individual Number Card (My Number Card) (eID)\nhttps://www.kojinbango-card.go.jp/en/" }, { "3B8880010073C8400000900062", "NXP JCOP 31 V2.2 36K - RFID I/F\nBarclaycard Visa Wave & Pay - RFID I/F\nCIBC Visa" }, { "3B8880010073C8401300900071", "Nokia 6131 NFC phone\nhttp://wiki.forum.nokia.com/index.php/Nokia_6131_NFC_-_FAQs\nGiesecke & Devrient's (G&D) Sm@rtCafe Expert 3.1\nAmex Bank of Canada American Express\nTD Canada Trust Visa\nTD Canada Trust Access Card (Visa Debit)" }, { "3B88800100883C1F77819500C1", "Polish Passport (passport)" }, @@ -1943,7 +1895,6 @@ const static atr_t AtrTable[] = { { "3B8880011000000000817000E8", "Tap&Go MasterCard Sim Card (Bank)\nhttps://www.tapngo.com.hk" }, { "3B88800111000011008184000C", "OCBC bank card (Bank)" }, { "3B888001110000113381A38098", "casatramway rechargeable card (Transport)\nhttps://www.casatramway.ma/" }, - { "3B88800111000011778181007E", "Transport card of Bordeaux, France (Transport)\nhttps://www.infotbm.com/fr" }, { "3B88800111000011778183007C", "Passport of citizen of Ukraine, Passport of citizen of Ukraine for traveling abroad (passport)" }, { "3B88800111223344808171003D", "FIME Card Emulator (Other)\nhttps://www.fime.com/products/terminal-integration/savvi.html" }, { "3B8880011BE1F35E11778100B9", "Uruguyan persona ID. Nowadays a eID. (eID)\nhttps://www.gub.uy/agencia-gobierno-electronico-sociedad-informacion-conocimiento/firma-digital/es-cedula-identidad-digital" }, @@ -1964,9 +1915,7 @@ const static atr_t AtrTable[] = { { "3B88800143433169AA200000DB", "PostFinance Switzerland (Bank)\nhttp://www.postfinance.ch" }, { "3B888001434C6169726520360F", "VISA credit card with NFC payment function (Bank)\nhttp://www.visa.ca/en/personal/visa-paywave/index.jsp" }, { "3B8880014431314352322E3070", "javacard.pro card (JavaCard)\nhttps://javacard.pro/" }, - { "3B8880014553434F5331303071", "Legic Prime and Legic Advant (Other)\nhttps://www.legic.com/de/products/smartcards/legic-smartcard-ics" }, { "3B88800146494445534D4F3167", "Fidesmo card (install or uninstall JavaCard applets or Mifare-based services on the field, using the Fidesmo Android App. (JavaCard))\nhttps://developer.fidesmo.com/" }, - { "3B8880014A434F50424D423260", "emoney (Bank)" }, { "3B8880014A434F50763234315E", "RFID - ISO 14443 Type A - NXP JCOP\nNXP J3A081 JavaCard (contactless interface)" }, { "3B88800150FFFF117783D50069", "Gematik TSYS eHBA G2.1 (HealthCare)" }, { "3B88800152744D430081C10061", "Rutoken 2151 smart card (eID)\nhttps://www.rutoken.ru/products/catalogue/id_50.html" }, @@ -1974,12 +1923,10 @@ const static atr_t AtrTable[] = { { "3B888001534B55500100000015", "Silesian public services card (Transport)\nhttp://www.kartaskup.pl" }, { "3B888001534C4A01305023100E", "bunq Credit MasterCard (contactless interface) (Bank)" }, { "3B888001536D61727441707011", "national Lithuania ID card (eID)\nhttps://www.dokumentai.lt/viewpage.php?page_id=77" }, - { "3B888001595A52434F53030004", "Waveshare 4.2inch Passive NFC-Powered e-Paper 400x300 Screen (Other)\nhttps://www.amazon.com/dp/B0CNR5KGZN?ref=ppx_yo2ov_dt_b_fed_asin_title&th=1" }, { "3B8880017661756C746974315F", "ID06 2.0 (eID)" }, { "3B8880017661756C746974325C", "Vaultit Identity Card (eID)" }, { "3B8880018066B007010107....", "Gemalto Santander Optelio TUI R7 with WG10 using Contactless interface" }, { "3B8880018073C8211052B81DF4", "Arculus AuthentiKey (via NFC) (Other)" }, - { "3B8880018921A0012024071615", "Token2 T2F2-NFC-Card PIN+ Release3 (via NFC) (Other)\nhttps://www.token2.com/shop/product/t2f2-nfc-card-pin-release3" }, { "3B888001990200D10304220167", "Debit card (Bank)" }, { "3B888001C91207520200811014", "electronic Tickes from the german Transport Association VGN (Verkehrsgemeinschaft Niederrhein)" }, { "3B888001D10386050080800058", "Resident Identity Card of People Republic of China (Second Generation with RF Feature) (eID)\nhttp://www.gov.cn/banshi/2005-08/02/content_19457.htm" }, @@ -2005,7 +1952,6 @@ const static atr_t AtrTable[] = { { "3B888001E1F35E11B381A500C3", "Australian Passport (passport)\nhttps://www.passports.gov.au/" }, { "3B888001E1F35E1377830000A2", "ePerso - German ID card (issued 2013)" }, { "3B888001E1F35E137783D50077", "ePerso - German ID card (issued 2011)" }, - { "3B888001FD01102020103000C5", "Changsha Xiaoxiang TU Transport Card issued by China Mobile (Transport)\nhttps://www.xxka.com/" }, { "3B88813120550057696E4361726429", "SmartCard for Windows 1.0" }, { "3B888EFE532A031E049280004132360111E4", "German C-Netz SIM card / TeleKarte for mobile phones or phone boxes - 1990s (Telecommunication)\nhttp://download.eversberg.eu/mobilfunk/C-Netz-Dokus/" }, { "3B890056434152445F4E5353", "Coolkey emulated card using virtual viewer with nssdb (eID)" }, @@ -2019,7 +1965,6 @@ const static atr_t AtrTable[] = { { "3B8980013233324353435333363E", "CSCS Smartcard (passport)\nhttp://getgosmart.io" }, { "3B89800141434F534A763130311A", "ACS ACOSJ (Combi) (JavaCard)\nhttp://www.acs.com.hk/en/products/405/acosj-java-card-combi/" }, { "3B89800141434F534A763230351D", "ACOSJ dual interface Java card 95K (JavaCard)" }, - { "3B89800143323330302D4B455930", "HID(r) Crescendo(r) Key (PKI)\nhttps://www.hidglobal.com/documents/hid-crescendo-key-datasheet" }, { "3B8980014341524441474146435E", "Student ID of University Duisburg-Essen (Other)\nhttps://www.uni-due.de/studierendensekretariat/studierendenausweis.shtml" }, { "3B898001434C616972653220363C", "Fidor Smartcard Mastercard/Maestro (Bank)\nhttps://www.fidor.eu" }, { "3B898001434C616972653320363D", "MasterCard with PayPass issued by Commerbank AG (Germany) (Bank)\nhttps://www.commerzbank.de/portal/de/privatkunden/produkte/bezahlen/kreditkarten/mastercard-classic/mastercardclassic.html" }, @@ -2049,8 +1994,6 @@ const static atr_t AtrTable[] = { { "3B8980018064160402828290006C", "Maestro card (from Mastercard) used by BCGE (switzerland) bank (Bank)" }, { "3B89800180642004018382900058", "Raiffeisen Debit Card / Master (Bank)" }, { "3B89800180670412B0030501024C", "Austrian Passport" }, - { "3B8980018684105430343131317B", "e-CNY hard wallet issued by Bank of China & Meituan (Bank)\nhttps://www.mpaypass.com.cn/news/202209/01101324.html" }, - { "3B89800186885550504849434B5A", "UnionPay Debit card issued by Industrial and Commercial Bank of China (Contactless) (Bank)\nhttps://www.icbc.com.cn/" }, { "3B8A0091010016000116010096", "GSM-SIM T-Mobil D1 (900MHz)" }, { "3B8A0091010016000120010096", "GSM-SIM T-D1 prepaid (Xtra)" }, { "3B8A0091010016000120020096", "GSM-SIM (900MHz) card of the carrier t-mobile for their cellular\nnetwork (phase 2+ with 3V)" }, @@ -2075,7 +2018,6 @@ const static atr_t AtrTable[] = { { "3B8A80014A434F503331563233327A", "Snapper New Zealand (JCOP)" }, { "3B8A80014A434F503431563232317F", "JCOP41 Cards (not supported, but recognized by Classic Client)\nNXP JCOP 41 v2.2.1 72k RFID I/F" }, { "3B8A80014D540005002086640001D4", "Beijing Municipal Administration & Communication Card (Transport)\nhttps://www.bmac.com.cn/" }, - { "3B8A80014D54000500308693695B00", "Beijing Municipal Administration & Communication Card (Transport)\nhttps://www.bmac.com.cn/" }, { "3B8A800150564A434F5033454D5676", "NXP JCOP3 J3H082 Java Card 3.0.4 Dual-Interface (JavaCard) (JavaCard)\nhttps://www.cardlogix.com/product/nxp-jcop3-j3h082-java-card-3-0-4-j3h081-dual-interface/" }, { "3B8A800150564A434F503453494471", "J3R180 via ifdnfc (JavaCard)" }, { "3B8A80015345204445534669726557", "NXP-Mifare DESFire EV1 2k (used as a company ID card) (eID)" }, @@ -2110,7 +2052,6 @@ const static atr_t AtrTable[] = { { "3B8B80010031C1640840223000900054", "IDEMIA Cosmo v8.1-n (Other)" }, { "3B8B80010031C1640860320600900052", "Banco CTT (Portugal) contactless VISA Debit card (Bank) (Bank)\nhttps://www.bancoctt.pt/home/abrir-conta.html" }, { "3B8B80010031C1640860321200900046", "AMEX Silver Credit (Bank)" }, - { "3B8B80010031C1640860321A0090004E", "UnionPay Debit card issued by HSBC CN (Contactless) (Bank)\nhttps://www.hsbc.com.cn/debit-cards/" }, { "3B8B80010031C1640860321F0090004B", "Hanseatic Bank Visa Card (Bank)\nhttps://www.hanseaticbank.de/kreditkarte/genialcard" }, { "3B8B80010031C1640860322000900074", "IDEMIA (Other)" }, { "3B8B80010031C1640860324200900016", "Westpac Handybank EFTPOS/ATM Card - Contactless (Bank)" }, @@ -2121,18 +2062,14 @@ const static atr_t AtrTable[] = { { "3B8B80010031C1640924331E0090000E", "Cumulus Mastercard (Bank)\nhttps://www.migros.ch/cumulus/mastercard" }, { "3B8B80010031C164092914540090006E", "Italian State National Card (eID)\nhttps://www.inps.it/it/it/assistenza/cns---carta-nazionale-dei-servizi.html" }, { "3B8B80010031C1640937721300900051", "French ID Card 2021 (contactless interface) (eID)\nhttps://ants.gouv.fr/Les-titres/Carte-nationale-d-identite/La-puce-de-la-nouvelle-carte-nationale-d-identite" }, - { "3B8B80010031C1640946012A0090006A", "Zwipe Access badge with HID Seos applet (eID)\nhttps://www.zwipe.com/access" }, { "3B8B80010031C1640958213600900048", "American Express Corporate Card (Bank)\nhttps://www.americanexpress.com/es-es/negocios/corporativa/tarjetas/corporate-card/" }, { "3B8B80010031C1640964413600900014", "Monzo (Bank)\nhttps://monzo.com/" }, { "3B8B80010031C164097861310090002F", "BBVA credit card (Bank)\nhttps://www.bbva.es/personas/productos/tarjetas/credito.html" }, { "3B8B800100640411010131800090005A", "German Passport (issued Nov 2006)\nUnited Kingdom e-Passport\nLuxembourg passport (2007)" }, { "3B8B80010B7880820244492030324D1B", "Mastercard Debit issued by Raiffeisen bank in Czech Republic" }, - { "3B8B800120555F4A434152445F532052", "Universal JCard S (C-UJC080-PCG-101) (JavaCard)\nhttps://www.usmartcards.co.uk/universal-j-cards" }, - { "3B8B800120700100000000071C615170", "Residence Permit for Residents of Liaoning, China (eID)\nhttps://www.gov.cn/xinwen/2018-04/02/content_5279248.htm" }, { "3B8B80012085008B030FE09AA0E04052", "Shanghai Public Transportation Card (Transport)\nhttp://www.sptcc.com/" }, { "3B8B80012090000000000008EE277F04", "Hungarian eID (2024) (eID)\nhttps://eszemelyi.hu/en/" }, { "3B8B8001209000000000001614CDAADF", "JCOP 41 IBM card for Guizhou Normal University (JavaCard)" }, - { "3B8B800120900000000000995D583016", "Northeastern University (China) student ID card (Other)\nhttp://ecard.neu.edu.cn/" }, { "3B8B800120900000000000C3A4CC0918", "ID card (Other)" }, { "3B8B80012A26A7A10C804100000709C3", "T-Mobilitat (Transport)\nhttps://t-mobilitat.cat/" }, { "3B8B80012A26A7A10C804100019AB1E7", "T-Mobilitat (Transport)\nhttps://t-mobilitat.atm.cat/" }, @@ -2149,9 +2086,7 @@ const static atr_t AtrTable[] = { { "3B8B80018066475000B8007F8290002E", "Italian Card Identity (eID)\nhttps://www.cartaidentita.interno.gov.it/" }, { "3B8B80018066475000B80094829000C5", "Italian Electronic Contactless Identity Card v. 3.0 (CIE 3.0) (eID)\nhttps://www.cartaidentita.interno.gov.it/" }, { "3B8B800180F9A00000030800001000C8", "Probably the same as 'JCOP3 SecID P60 CS (JavaCard)' but mated with a contactless Identiv reader (JavaCard)" }, - { "3B8B8001868602563390314F8BB98F3E", "Macau Pass (Transport)\nhttps://www.macaupass.com/" }, { "3B8B80018688FF6F391E743C200800D3", "Chinese ICBC (bank)" }, - { "3B8B80018688FF8511BBBD2120080060", "UnionPay Debit card issued by China Minsheng Bank (Contactless) (Bank)\nhttps://www.cmbc.com.cn/" }, { "3B8B81314034534D41525453434F5045316D", "Zeeland kaart (Telecommunication)" }, { "3B8C014D79536D6172744C6F676F6EA5", "EIDVirtual (USB key emulated as a virtual smart card) (PKI)\nhttp://www.mysmartlogon.com/eidvirtual/" }, { "3B8C01805A4E6974726F6B657920337D", "'Nitrokey 3C NFC' USB authentication and security token (Other)\nhttps://shop.nitrokey.com/shop/product/nk3cn-nitrokey-3c-nfc-148" }, @@ -2217,7 +2152,6 @@ const static atr_t AtrTable[] = { { "3B8C800150710CF3C800000000B37171A8", "MOBIB CARD BELGIUM (Transport)" }, { "3B8C800150773B2DBD0000001100818594", "Texas Instruments Dynamic NFC Interface Transponder (RF430CL330H)" }, { "3B8C800150784B2CCB00000000B371713A", "... (Transport)\nhttps://www.portalviva.pt/" }, - { "3B8C800150787182D400000000118171E3", "BUS Synchro in Grand Chambery (Transport)\nhttps://synchro.grandchambery.fr" }, { "3B8C80015078F87217E1F35E117781A5B6", "US (passport)" }, { "3B8C8001507919600100DDA611F7718535", "Transport Traway Montpellier France (Transport)" }, { "3B8C8001507AA44007231801007781979F", "Indonesian Driver License" }, @@ -2253,9 +2187,7 @@ const static atr_t AtrTable[] = { { "3B8C800150C2B936860000000000717196", "Passe Navigo (Transport)\nhttps://www.iledefrance-mobilites.fr/titres-et-tarifs/supports/passe-navigo-decouverte" }, { "3B8C800150C326AF0C000000000071711B", "Navigo Mobility Paris transport's Card (Transport)\nhttps://www.iledefrance-mobilites.fr/titres-et-tarifs/liste?d=forfaits" }, { "3B8C800150C41466C30000000000717128", "Navigo easy (Transport)\nhttps://www.iledefrance-mobilites.fr/titres-et-tarifs/supports/passe-navigo-easy" }, - { "3B8C800150C464D71200000000118171D9", "Carte Opus (Montreal) (Transport)\nhttps://www.carteopus.info/" }, { "3B8C800150C51770F0000000008081717F", "SumUp Limited Apple Pay Virtual Card (Bank)\nhttps://sumup.co.uk" }, - { "3B8C800150C5FD630D00000000008171FB", "Navigo Easy (Transport)\nhttps://www.iledefrance-mobilites.fr/en/tickets-fares/media/navigo-easy-travel-card" }, { "3B8C800150C7251C5A00000011F781811F", "MOBIB Belgian public transport Card (Transport)\nhttps://mobib.be/fr.html" }, { "3B8C800150CA24513E00000011F781813A", "belgian mobib transportation card (Transport)" }, { "3B8C800150CBFB077E000000008081E1F4", "Samsung Digital Center in Seul Access ID card for guests (eID)" }, @@ -2263,7 +2195,6 @@ const static atr_t AtrTable[] = { { "3B8C800150D94E7D0000000000008180B6", "Chicago CTA Ventra Transit card (Transport)\nhttps://www.ventrachicago.com/" }, { "3B8C800150DF4C852C0000000000817791", "SNS Bank Netherlands (Bank)" }, { "3B8C800150E2F8282E0000000000818747", "ING Maestro Debit Card (Bank)\nhttps://www.ing.nl/particulier/index.html" }, - { "3B8C800150EA5A3F1930AAAA017781D7DB", "Indonesia's Official Citizenship/Identity Card (e-KTP) (eID)\nhttps://en.wikipedia.org/wiki/Indonesian_identity_card" }, { "3B8C800150EB5E6A120000000000817766", "Maestro card (Bank)" }, { "3B8C800150F2AD19D7000000000081773A", "ING Maestro Debit Card (Bank)\nhttps://www.ing.nl/particulier/index.html" }, { "3B8C800150F56FF82BE1F35E113381C73C", "ID of the Republic of Kazakhstan Ministry of Internal Affairs of the Republic of Kazakhstan (eID)" }, @@ -2299,7 +2230,6 @@ const static atr_t AtrTable[] = { { "3B8D80010073C80013645437443300900044", "master cRD (Bank)\nTD MasterCard\nTangerine MasterCard" }, { "3B8D80010073C80013645437473100900045", "Tangerine ATM/ABM Card" }, { "3B8D800100851410108501112002759000CF", "Sahl Payment Card (Other)\nhttps://www.english.sahlpay.app/" }, - { "3B8D8001008C430101868821014015D85636", "UnionPay Debit card issued by Industrial and Commercial Bank of China (Contactless) (Bank)\nhttps://www.icbc.com.cn/" }, { "3B8D80010D788084020073C840130090FFF8", "Nokia 6212 phone seen as NFC device" }, { "3B8D80010D78F7B1024A434F50763234316A", "Electronic Identity For Students at university (eID)" }, { "3B8D80014946582D6A63333031677032325A", "Degussa Bank Corporate MasterCard (Bank)\nhttps://firmenkarten.degussa-bank.de/" }, @@ -2315,7 +2245,6 @@ const static atr_t AtrTable[] = { { "3B8D80018091E165D0005B010273D44140B7", "Portuguese Passport (passport)\nhttp://www.pep.pt/PagesPT/Caracteristicas.aspx" }, { "3B8D80018091E165D0005B010373D44140B6", "French passport (2010-2011)" }, { "3B8E0100738020C006534C434F530590004F", "idex (JavaCard)" }, - { "3B8E80010000814D22088660300020E00007F8", "Mastercard Debit card issued by Bank of China (Contactless) (Bank)\nhttps://www.boc.cn/" }, { "3B8E8001005100631F6D01739F20C0C0900012", "Identity card (eID) Republic of Latvia (eID)\nhttps://www.pmlp.gov.lv/en/home/services/personal-certificates-%28eid%29/" }, { "3B8E8001005131631F5901739F20C0C0900017", "Identity card (eID) Republic of Latvia (eID)\nhttp://www.pmlp.gov.lv/en/home/services/personal-certificates-%28eid%29/\nFrench driving license (eID) (contactless)" }, { "3B8E80010E7833C4020064041501020090FF95", "Spanish Passport" }, @@ -2326,11 +2255,9 @@ const static atr_t AtrTable[] = { { "3B8E8001137880800246494F4D4B5F3030314E", "MasterCard/PayPass Card issued by Czech FIO Banka a.s. (contactless chip)\nnote the ASCII string 'FIOK_001N' embedded in ATR" }, { "3B8E8001410543000000000000000000900098", "ACOS5-EVO PKI Smart Card (Combi) (PKI)\nhttps://www.acs.com.hk/en/products/471/acos5-evo-pki-smart-card/" }, { "3B8E800152464944494F74204A434F5038305A", "RFIDIOt G&D SmartCafe 80K" }, - { "3B8E800153434520382E302D433256320D0A63", "ePassport (passport)\nhttps://www.veridos.com/en/" }, { "3B8E800153434520382E302D433356300D0A60", "Latvian passport (2024) (passport)" }, { "3B8E800153434536302D43443038312D6E464A", "SmartCafe Expert 6.0 80K Dual (JavaCard)\nhttp://www.smartcardfocus.com/shop/ilp/id~684/smartcafe-expert-6-0-80k-dual-/p/index.shtml" }, { "3B8E8001544A4F50323144303431563232311B", "China Construction Bank Lutong Card Type A (Credit) with ETC (Bank)\nhttp://ccb.com/sd/cn/fhgg/20200122_1579670876.html" }, - { "3B8E80015644562D4B41204944333720464D6E", "'VBB-fahrCard' time and season tickets on public transports in Berlin and Brandenburg - eTicket (Transport)\nhttps://www.vbb.de/tickets/tarifinformationen-services/vbb-fahrcard/" }, { "3B8E80015644562D4B412049443337204A341B", "eTicket (Transport)\nhttps://www.eticket-deutschland.de/" }, { "3B8E80018031806549544E5850120FFF8290F0", "Italian Electronic Contactless Identity Card v. 3.0 (CIE 3.0) - ICAO 9303 Compliant (eID)\nhttps://www.cartaidentita.interno.gov.it/caratteristiche-del-documento/" }, { "3B8E80018031806549544E5850120FFFFFFFE2", "Italian identity card, 2nd version (eID)\nhttps://www.cartaidentita.interno.gov.it/" }, @@ -2367,12 +2294,9 @@ const static atr_t AtrTable[] = { { "3B8F80010031C173C8211064414D333107900089", "NAB VISA Debit (Bank)\nhttps://www.nab.com.au/" }, { "3B8F80010031C173C8211064414D3341079000F9", "Ukrainian International resere bank (ex Sberbak RF) debit card (Bank)\nhttps://www.sbrf.com.ua/" }, { "3B8F80010031C173C8211064414D3348079000F0", "Consorsbank VISA debit card (Bank)" }, - { "3B8F80010031C173C8211064474D31360090008D", "Mastercard Debit card issued by China Construction Bank (Contactless) (Bank)\nhttps://www.ccb.com/" }, - { "3B8F80010031C173C8211064474D3342009000FB", "Visa Debit card issued by Bank of China (Contactless) (Bank)\nhttps://www.boc.cn/" }, { "3B8F80010031C173C8211064474D34350090008B", "S-Etukortti Visa (Bank)\nhttps://www.s-pankki.fi/fi/s-etukortti-visa" }, { "3B8F80010031C173C8211064474D343700900089", "SpareBank Visa Card, Norway (Bank)" }, { "3B8F80010031C173C82110644D30424E079000F6", "Debit Card (Deutsche Bank Card Plus) (Bank)\nhttps://www.deutsche-bank.de/pk/konto-und-karte/karten-im-ueberblick/deutsche-bank-card-plus.html" }, - { "3B8F80010031C173C82110645630434E079000EC", "Amazon VISA Card (Bank)" }, { "3B8F80010031C173C82110645631434E079000ED", "Tarjeta Despues BBVA Espana (contact interface) (Bank)\nhttps://www.bbva.es/personas/productos/tarjetas/tarjeta-despues.html" }, { "3B8F80010031C173C8211064574B31330090009E", "TIM Pay - HYPE (Mastercard debit card) (Bank)\nhttps://www.tim.it/fisso-e-mobile/mobile/servizi/tim-pay" }, { "3B8F80010031C173C8211064574B313400900099", "G&D Sm@rtCafe Card embedded in a wristband (Bank)\nhttps://www.gi-de.com/en/au/mobile-security/industries/financial-institutions/wearables/" }, @@ -2384,7 +2308,6 @@ const static atr_t AtrTable[] = { { "3B8F800101654E434F532D4D43412D434C30373C", "eNCOS + MCA, MchipAdvance 123 bundled with eNCOS (Bank)" }, { "3B8F80013101F1564011001900000000000000D1", "Revolut Mastercard (Bank)" }, { "3B8F80013101F1564011001900000000FFFFFF2E", "BVG Guthabenkarte (Prepaid Payment Card for Berlin/Brandenburg Public Transport) (Transport)\nhttps://www.bvg.de/de/service-und-kontakt/guthabenkarte" }, - { "3B8F80013101F1564011001D00000000FFFFFF2A", "n26 (Bank)" }, { "3B8F800141434F53204449616E6131204C63365B", "DKB-VISA-Card (Bank)\nhttps://produkte.dkb.de/?&page=girokonto#kreditkarte" }, { "3B8F800141434F53204449616E613120FFFFFFBD", "DKB Visa Credit Card (Bank)\nhttps://www.dkb.de" }, { "3B8F800141434F53204449616E6132204C633658", "comdirect Visa debit (Bank)\nhttps://www.comdirect.de" }, @@ -2395,14 +2318,10 @@ const static atr_t AtrTable[] = { { "3B8F800143553269AA20202020202020202020E9", "UBS Access Card (Mobile Online Banking, NFC, Switzerland)" }, { "3B8F800145504100000000........00........", "Austrian Quick E-purse contactless\nhttp://www.quick.at/" }, { "3B8F80014A434F50332041545320434841525326", "Samsung Galaxy Watch Active NFC (Other)" }, - { "3B8F80014D5400020100FFFF0114013422071100", "HK Octopus - China T-Union Card (Felica/ISO-14443A combo 14443A section) (Transport)\nhttps://www.octopus.com.hk/en/consumer/octopus-cards/products/cross-border/china-t-union.html" }, { "3B8F800152464944494F74204A434F5020333676", "RFIDIOt JCOP 36K Blank\nhttp://rfidiot.org" }, { "3B8F800152464944494F74204A434F5020373276", "RFIDIOt JCOP 72K Blank\nhttp://rfidiot.org" }, { "3B8F800152464944494F74204A434F5037327224", "RFIDIOt JCOP 72K RANDOM_UID Blank\nhttp://rfidiot.org" }, { "3B8F800156696E5061795379732050757273652F", "JCOP (Other)" }, - { "3B8F800157694C4C570000000000002019032875", "Mastercard Debit card issued by Industrial and Commercial Bank of China (Contactless) (Bank)\nhttps://www.icbc.com.cn/" }, - { "3B8F800157694C4C57000000000000202004294A", "Amex China bank card (Contactless) (Bank)\nhttps://www.americanexpress.com.cn/" }, - { "3B8F800157694C4C570000000000002020043053", "Mastercard China Debit card issued by Postal Savings Bank of China (Contactless) (Bank)\nhttps://www.psbc.com/" }, { "3B8F80018031806549544A3441120FFF82900088", "CIE - Carta di Identita Elettronica - Italian ID Card (eID)\nhttps://www.cartaidentita.interno.gov.it" }, { "3B8F80018031806549544A3442120FFF829000", "Italian Identity Card CIE (eID) (eID)\nhttps://www.cartaidentita.interno.gov.it/en/home/" }, { "3B8F80018031806549544A3442120FFF8290008B", "Identity Card (eID)" }, @@ -2549,7 +2468,6 @@ const static atr_t AtrTable[] = { { "3B8F80018091E1319865B0850300EF739441C08D", "Italian Passport (passport)\nhttps://www.passaportonline.poliziadistato.it/" }, { "3B8F80018091E1319865B0850300EF739441FFB2", "Italian Passport (passport)" }, { "3B8F80018091E131D865B28C01000773C441E05C", "Portuguese epassport (passport)" }, - { "3B8F80018091E131D865B28C01002673C441E07D", "ePassport chip of South Korea (passport)" }, { "3B8F800186384D574F4850CF1E4D2B1211291070", "Hangzhou Tong (Hangzhou Public Transport Card) (Transport)\nhttps://www.96225.com/smknet/service/show_allGet.action?chanageCrd=3" }, { "3B8F800186844354444E409F3EC40D682804007D", "Access card to the underground network of guangzhou (Transport)" }, { "3B8F8001FF43727970746E6F784649444F3230C2", "Fast Identification Online card (FIDO2) from Cryptnox manufacturer (Other)\nhttps://www.cryptnox.ch" }, @@ -2671,17 +2589,14 @@ const static atr_t AtrTable[] = { { "3B9C95801FC78031E073FE211B6457444946CF", "MTC (Moscow) phone SIM card (Telecommunication)\nhttps://moskva.mts.ru/personal" }, { "3B9C9580811F039067464A01005404F272FE00C0", "Feitian Technologies Java Card A22CR (JavaCard)\nhttps://www.javacardos.com/store/javacard-a22cr.php" }, { "3B9C9580811F039067464A01011706F2727E0000", "A40CR (JavaCard)" }, - { "3B9C958101505343502D53435356312E308E", "SSE Carte a puce Inc. : PIV - GIDS - FIDO2.1 - OPENPGP 2.1 Identity Services for Corporation (eID)\nhttps://www.smartcardsecurity.ca" }, { "3B9C958131FE9F9067464A010253050172FE00FB", "Feitian Biopass K27 (PKI)\nhttps://www.ftsafe.com/Products/FIDO/Bio" }, { "3B9C958131FE9F9067464A010400050172FE00AE", "ePass FIDO-NFC Plus (eID)\nhttps://www.ftsafe.com/products/FIDO/NFC" }, { "3B9C96005275746F6B656E4543507363", "Aktiv Rutoken ECP SC T0\nhttps://www.rutoken.ru/products/all/rutoken-ecp-sc/" }, { "3B9C960058442403020020010A009005", "Ticket Restaurant Card (Other)\nhttp://www.edenred.it/buoni-pasto-welfare-benefit/ticket-restaurant-card/" }, { "3B9C978011405275746F6B656E4543507363C0", "Aktiv Rutoken ECP 3.0 NFC (PKI)\nhttps://www.rutoken.ru/products/all/rutoken-ecp-nfc/" }, { "3B9D114023006810114D696F434F53009000", "MioCOS 1.0" }, - { "3B9D13813160378031C0694D54434F537302020440", "DPI Card Guatemala (eID)\nhttp://www.masktech.de/\nSerbian ID (eID)" }, + { "3B9D13813160378031C0694D54434F537302020440", "DPI Card Guatemala (eID)\nhttp://www.masktech.de/" }, { "3B9D13813160378031C0694D54434F537302020541", "MTCOS (eID)\nhttp://www.masktech.com/Products/MTCOS-Professional/11/en" }, - { "3B9D13813160378031C0694D54434F537302050447", "Serbian vehicle card (Other)" }, - { "3B9D188131FC358031C0694D54434F5373020502D4", "Serbian vehicle card (Other)" }, { "3B9D188131FC358031C0694D54434F5373020505D3", "Lithuanian e-ID Card (eID)\nhttps://www.nsc.vrm.lt/default_en.htm" }, { "3B9D188131FC358031C0694D54434F5373020604D1", "Lithuanian ID card (MaskTech, 2024) (eID)" }, { "3B9D944023006820014D696F434F53009000", "Miotec smartcard running Miocos 2.0 on an Atmel AT90SC646\nhttp://www.miotec.fi" }, @@ -2697,7 +2612,6 @@ const static atr_t AtrTable[] = { { "3B9D95801FC780731A211B63AF09A9830F9000F3", "Estonian GSM operator TELE2 (WPKI eID support)" }, { "3B9D95803FC7A08031A073BE21135105830590007C", "NTT docomo Xi(LTE) DN05(DNP) Pink SIM (Telecommunication)" }, { "3B9D960053492303030020000400F59000", "shell (Transport)" }, - { "3B9D9600534D4152545041524B20464B43", "T token (Russia) (Other)" }, { "3B9D96801FC78031E073FE2113654C0404020096", "China umion 5G SIM (Telecommunication)" }, { "3B9D96803FC7A08031E073FE211B65534130112546", "KT MVNO Baro USIM (Telecommunication)\nhttps://ktmyr.com/fe/service/svc/usimGuide.do?menuNo=F0604" }, { "3B9D96813160378031C0694D54434F5373020204C5", "Mozambique ID Card (eID)" }, @@ -2726,7 +2640,6 @@ const static atr_t AtrTable[] = { { "3B9E95801FC38031E073FE211B66D000490000004E", "UK O2 Unlimited Prepay GSM/UMTS USIM" }, { "3B9E95801FC3804B434F5320566572012E0190001C", "Vehicular License Veracruz, Mexico (Transport)" }, { "3B9E95801FC68031E073FE211B66D0019FBD100031", "H3G (Three UK) Prepaid USIM (Telecommunication)" }, - { "3B9E95801FC68031E073FE211B66D0025E73150038", "albert heijn prepaid SIM netherlands (Telecommunication)" }, { "3B9E95801FC78031E073FE211B66D00007001E001A", "H3G (Ireland, UK) UMTS USIM card" }, { "3B9E95801FC78031E073FE211B66D000261C010038", "GSM-SIM Telefonica Movistar, contract (Spain)\nhttp://www.movistar.es/" }, { "3B9E95801FC78031E073FE211B66D00028C40000EF", "H3G (Italy) UMTS USIM card" }, @@ -2773,8 +2686,6 @@ const static atr_t AtrTable[] = { { "3B9E96800141054300000000000000000090001E", "ACS CryptoMate EVO PKI token (PKI)\nhttps://www.acs.com.hk/en/products/494/cryptomate-evo-cryptographic-usb-tokens/" }, { "3B9E96801F478031A073BE211366868802101D1049", "Maroc Telecom USIM" }, { "3B9E96801F838031E073FE21126655574E41323391", "TDC mobile UICC (Telecommunication)" }, - { "3B9E96801F878031E073FE2119664A5543140110CB", "SIM card for 5G exploration (Telecommunication)" }, - { "3B9E96801F878031E073FE2119664A556021AA1670", "telkomsel (Telecommunication)" }, { "3B9E96801FC38031E073FE211B66D0016C040D0060", "toggle GSM SIM\nhttp://www.togglemobile.co.uk" }, { "3B9E96801FC38031E073FE211B66D0017B980D00EB", "Lycamobile Pay As You Go SIM" }, { "3B9E96801FC68031E073FE211B66D0019F134D00C1", "Telus Mobility Tri-SIM card (Telecommunication)\nhttps://www.telus.com/en/mobility/sim-cards" }, @@ -2817,7 +2728,6 @@ const static atr_t AtrTable[] = { { "3B9E96801FC78031E073FE211B66D00199C80F005F", "OneSimCard (Telecommunication)\nhttp://www.onesimcard.com/" }, { "3B9E96801FC78031E073FE211B66D00199FE0E0068", "Finnish Sonera SIM-card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A0041100B4", "Aldi Talk SIM card, Germany (Telecommunication)\nhttps://www.alditalk.de/talk" }, - { "3B9E96801FC78031E073FE211B66D001A00F1100BF", "Vodafone UK SIM card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A01E1100AE", "Zevvle SIM Card (Telecommunication)\nhttps://zevvle.com" }, { "3B9E96801FC78031E073FE211B66D001A0741000C5", "USIM of Vodafone Germany (MCC 262, MNC 2) (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A0DD12006E", "USIM (Telecommunication)" }, @@ -2825,32 +2735,27 @@ const static atr_t AtrTable[] = { { "3B9E96801FC78031E073FE211B66D001A1121000A2", "OpenAirInerface (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A1181100A9", "WinEMP NRI License Card (Other)" }, { "3B9E96801FC78031E073FE211B66D001A122110093", "Lebara (Telecommunication)" }, - { "3B9E96801FC78031E073FE211B66D001A1421000F2", "SIM card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A1581100E9", "Vodafone CZ: SIMPLUS V128 LTE (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A1680F00C7", "Free Mobile SIM card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A1721000C2", "Vodafone (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D001A1731000C3", "Prepaid public telephone card from Lidl Connect, Germany (Telecommunication)\nhttps://www.lidl.de/de/lidl-connect/s7373597" }, { "3B9E96801FC78031E073FE211B66D001A1771000C7", "SIM Card Model X1 for Ting Mobile Carrier (Telecommunication)\nhttps://tingmobile.com/" }, { "3B9E96801FC78031E073FE211B66D001A1A70F0008", "Spanish Movistar Mobile phone SIM card (Telecommunication)\nhttp://www.movistar.es/" }, - { "3B9E96801FC78031E073FE211B66D001A1B8100008", "Bancorp (Bank)" }, { "3B9E96801FC78031E073FE211B66D001A1E60F0049", "SIM O2 CZ (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D002170912000E", "SIM/USIM (SPAIN) - ORANGE ESPAGNE VIRTUAL, S.A.U. (Orange / Jazztel / SIMYO) (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0021759140058", "USIM card of of Ukrainian Telecommunications Operator Kyivstar, emitted after 2016 (Kyivstar GSM) (GSM/UMTS/LTE services) (Telecommunication) (Telecommunication)\nhttps://kyivstar.ua/uk/4g" }, { "3B9E96801FC78031E073FE211B66D002175B12005C", "Cellcom Israel USIM (micro FF) (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0021760130066", "Vodafone spain barcelona (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0021762120065", "Free Mobile (Telecommunication)\nhttp://mobile.free.fr" }, - { "3B9E96801FC78031E073FE211B66D0021762130064", "SIM Card (possibly Gemalto/Thales) Telecommunication" }, { "3B9E96801FC78031E073FE211B66D0021795120092", "Twilio SIM (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D00217A01200A7", "USIM Card (Etisalat) (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D00217BF1100BB", "Telkom (Telecommunication)" }, - { "3B9E96801FC78031E073FE211B66D00217C41100C0", "STC Telecommunication" }, { "3B9E96801FC78031E073FE211B66D00217C91100CD", "Vivo 4G (Other)" }, { "3B9E96801FC78031E073FE211B66D00217CD1100C9", "O2 4G SIM card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D00217D91200DE", "telenor (swedish mobile provider) SIM card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D00217F41200F3", "SIM card for Swedish operator Vimla! (Telecommunication)\nhttps://www.vimla.se" }, { "3B9E96801FC78031E073FE211B66D002194B120042", "halebop (swedish mobile provider) SIM card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0022436140004", "SIM (Telecommunication)" }, - { "3B9E96801FC78031E073FE211B66D00224B3140081", "Drei AT Prepaid SIM Card (Telecommunication)\nhttps://www.drei.at/de/shop/wertkarte/" }, { "3B9E96801FC78031E073FE211B66D00224DE1400EC", "Romanian Vodafone SIM Card (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0022A3215000F", "Bell 5G/LTE multi SIM card, Canada (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0022A6D130056", "USIM card (JavaCard)" }, @@ -2862,13 +2767,10 @@ const static atr_t AtrTable[] = { { "3B9E96801FC78031E073FE211B66D0022AB714008B", "AT&T Prepaid UICC (Telecommunication)" }, { "3B9E96801FC78031E073FE211B66D0022AD31300E8", "sim card from Mobilcom Debitel Telefonica (Telecommunication)\nhttps://md.de" }, { "3B9E96801FC78031E073FE211B66D0022AD91300E2", "sim (Telecommunication)" }, - { "3B9E96801FC78031E073FE211B66D0022ADA1300E1", "Zevvle SIM Card (Telecommunication) Telecommunication\nhttps://zevvle.com" }, { "3B9E96801FC78031E073FE211B66D0022AE81300D3", "Twilio Super SIM card (Telecommunication)\nhttps://www.twilio.com/iot/super-sim-card" }, { "3B9E96801FC78031E073FE211B66D0022AF21400CE", "Tello (Telecommunication)\nhttps://tello.com/" }, { "3B9E96801FC78031E073FE211B66D00233AD140088", "4G-LTE (Telecommunication)" }, - { "3B9E96801FC78031E073FE211B66D002390D150023", "Orange Belgium Hello (Telecommunication)" }, { "3B9E968031FE4553434520382E302D433156300D0A6F", "Serbian Identity Card (eID) (eID)" }, - { "3B9E968031FE4553434520382E302D433256300D0A6C", "Serbian Identity Card (eID) (eID)" }, { "3B9E96803F47A08031E073EE211366868842185221EF", "SIM card (Telecommunication)" }, { "3B9E96803FC3A08031E073FE211B630801140F9000D3", "KT Olleh LTE Warp SA-L 1670 (Telecommunication)" }, { "3B9E97801FC68031E073FE211B66D0019F7A1200F6", "Spectrun USA Sim Card (Telecommunication)" }, @@ -2880,11 +2782,9 @@ const static atr_t AtrTable[] = { { "3B9E97801FC68031E073FE211B66D002402F150078", "Free Mobile (French carrier) SIM card (Telecommunication)\nhttps://mobile.free.fr/" }, { "3B9E97801FC68031E073FE211B66D0025E7315003A", "Twilio Super SIM (Telecommunication)\nhttps://www.twilio.com/iot/super-sim-card" }, { "3B9E97801FC68031E073FE211B66D0025E901500D9", "SMARTY (a subsidiary of Three UK) 4G SIM Card (Telecommunication)" }, - { "3B9E97801FC68031E073FE211B66D0025EAE1500E7", "kiwisim (Telecommunication)" }, { "3B9E97801FC68031E073FE211B66D0025EC0150089", "Orange France Postpaid SIM Card (Telecommunication)" }, { "3B9E97801FC78031E073FE211B66D0006B951100EE", "TracFone SIM Verizon Wireless LTE supported (Telecommunication)\nhttps://www.tracfone.com" }, { "3B9E97801FC78031E073FE211B66D0022AB3130089", "SIM T-MObile (Telecommunication)" }, - { "3B9E978031FE4553434520382E302D433156300D0A6E", "Serbian Health Care card (HealthCare)\nhttps://www.rfzo.rs/index.php/osiguranalica/ekartica" }, { "3B9F..801FC300681.4405014649534531C8..9000..", "Setec SetCOS 4.4.1" }, { "3B9F1110804154393853433033324354312E3535", "'ID Vault' brand device (Other)\nhttp://www.idvault.com/index.html" }, { "3B9F1110805661756C74494320343630312E3032", "Inside Secure VaultIC 460 Smart Object [ICCD 1.00] (Other)\nhttp://www.insidesecure.com/Products-Technologies/Secure-Solutions/VaultIC460" }, @@ -2962,7 +2862,6 @@ const static atr_t AtrTable[] = { { "3B9F94801FC78031E073FE211B573786609BA182109B", "U Mobile POWER Prepaid (Telecommunication)\nhttp://www.u.com.my/prepaid" }, { "3B9F94801FC78031E073FE211B573786609C8080802F", "Telenor (Telecommunication)\nhttps://www.telenor.com.pk/" }, { "3B9F94801FC78031E073FE211B573C8660AF030070E4", "MTS Russia (Telecommunication)\nhttps://www.mts.ru" }, - { "3B9F94801FC78031E073FE211B573C8660BEB2001024", "SIM card issued by Telenor Serbia (Telecommunication)" }, { "3B9F94801FC78031E073FE211B573C8660CDA1001246", "Beeline SIM card (RUS) (Telecommunication)\nhttps://beeline.ru" }, { "3B9F94801FC78031E073FE211B573F86604D03000075", "Prepaid SIM card MOCHE (Portugal) (Telecommunication)" }, { "3B9F94801FC78031E073FE211B573F866083020000BA", "GSM-SIM Beeline RU (Telecommunication)\nhttp://beeline.ru" }, @@ -3031,7 +2930,6 @@ const static atr_t AtrTable[] = { { "3B9F95801FC78031E073FE2113574A330E1A32330087", "Rohde and Schwarz CMW-Z04. Mini-UICC Test Card (Telecommunication)" }, { "3B9F95801FC78031E073FE2113574A330E1A32360082", "TELUS 3G SIM Card" }, { "3B9F95801FC78031E073FE2113574A330E1E32360086", "SIM Enreach (Telecommunication)" }, - { "3B9F95801FC78031E073FE21135786810686984000B4", "China Mobile LTE USIM Card (Telecommunication)" }, { "3B9F95801FC78031E073FE2113635510888307900006", "SHOW or UPlus USIM (Telecommunication)" }, { "3B9F95801FC78031E073FE2113635510AA8307900024", "2degrees NFC (Telecommunication)\nhttp://www.2degreesmobile.co.nz/home" }, { "3B9F95801FC78031E073FE2113672228004001000191", "Lycamobile Prepaid SIM-Card (Telecommunication)\nhttp://lycamobile.at" }, @@ -3071,11 +2969,9 @@ const static atr_t AtrTable[] = { { "3B9F958131FE9F006646530501001171DF0000........", "Feitian ePass2003 token" }, { "3B9F958131FE9F00664653051000FF71DF0000000000EC", "JavaCOS A22 dual interface Java card - 150K (JavaCard)\nhttp://www.smartcardfocus.us/shop/ilp/id~709/javacos-a22-dual-interface-java-card-150k/p/index.shtml" }, { "3B9F958131FE9F006646530510043171DF000000000026", "ePass2003 (PKI)" }, - { "3B9F958131FE9F006646530510043171DF0000036A82CD", "ePass2003 Auto (eID)" }, { "3B9F958131FE9F006646530510043171DF000006000020", "FEITIAN ePASS 2003 Auto (PKI)" }, { "3B9F958131FE9F006646530510043171DF00003900001F", "Feitian ePass2003 (PKI)" }, { "3B9F958131FE9F006646530510063171DF000000000024", "FT ePass2003Auto USB Token (PKI)" }, - { "3B9F958131FE9F006646530510113171DF000000000033", "Epass 2003 (PKI)" }, { "3B9F958131FE9F006646530510113171DF0000039000A0", "Feitian ePass2003 PKI Token (PKI)" }, { "3B9F958131FE9F006646530510113171DF0000860000B5", "HYPERSECU HYP2003 (PKI)\nhttps://www.hypersecu.com/hyperpki" }, { "3B9F958131FE9F006646530510323871DF00000600001F", "token (PKI)" }, @@ -3088,7 +2984,6 @@ const static atr_t AtrTable[] = { { "3B9F958131FE9F006646530523002571DF000003900096", "Feitian USB Cryptographic token (FIPS 140-2 Level 3) (PKI)\nhttp://www.ftsafe.com/product/epass/epass2003" }, { "3B9F958131FE9F006646530532022571DF000006000010", "ePass 3003 Auto (PKI)\nhttps://www.ftsafe.com/products/PKI/Standard/Specification" }, { "3B9F958131FE9F006646530534002571DF0000036A82F9", "Feitian ePass2003Auto (PKI)\nhttps://www.ftsafe.com/Products/PKI/Standard/Specification" }, - { "3B9F958131FE9F006646530540231871DF000000000078", "Feitian ePass2003 (PKI)\nhttps://www.ftsafe.com/store/product/epass2003-pki-token/" }, { "3B9F958131FE9F006646530551003371DF000000000061", "FT ePass2003Auto 00 00 (PKI)" }, { "3B9F958131FE9F006646530551003371DF0000036A828A", "Feitian epass2003 Auto (PKI)" }, { "3B9F958131FE9F006646530551003371DF0000039000F2", "HyperPKI USB Token (PKI)\nhttps://www.hypersecu.com/hyperpki" }, @@ -3115,8 +3010,6 @@ const static atr_t AtrTable[] = { { "3B9F96801F878031E073FE211B674A357530350265F8", "sysmoISIM-SJA5 (Telecommunication)\nhttps://sysmocom.de/products/sim/sysmoisim-sja5/index.html" }, { "3B9F96801F878031E073FE211B674A4C5275310451D5", "Test card provided with 4G/5G network from Amarisoft (Telecommunication)" }, { "3B9F96801F878031E073FE211B674A4C7530300248A9", "Cardcentrics (Telecommunication)" }, - { "3B9F96801F878031E073FE211B674A4C753030064BAE", "USIM (Telecommunication)" }, - { "3B9F96801F878031E073FE211B674A4C7530311359A8", "IR MCI simcard (Telecommunication)\nhttps://mci.ir/" }, { "3B9F96801F878031E073FE211B674A4C753034054BA9", "sysmoISIM-SJA2 (Telecommunication)\nhttps://osmocom.org/projects/cellular-infrastructure/wiki/SysmoISIM-SJA2" }, { "3B9F96801F878031E073FE211B674A4C75313305688C", "Somtel SIM (Telecommunication)" }, { "3B9F96801F878031E073FE211B674A55527531054BD7", "Softbank (C2) USIM card (Telecommunication)" }, @@ -3157,7 +3050,6 @@ const static atr_t AtrTable[] = { { "3B9F96801FC68031E073FE211B66D00221AB11180180", "Telekom Germany Triple SIM issued in 2018 (Telecommunication)" }, { "3B9F96801FC68031E073FE211B66D00221AB11180786", "telekom HU nano sim card (Telecommunication)\nhttps://www.telekom.hu" }, { "3B9F96801FC68031E073FE211B66D00224DB141005FC", "CZ KAKTUS SIM CARD (Telecommunication)" }, - { "3B9F96801FC68031E073FE211B66D0023BFE141001C2", "Freenet SIM Card (Deutsche Telekom, green LTE) (Telecommunication)\nhttps://www.freenet-mobilfunk.de/handytarife/green-lte-tarife/" }, { "3B9F96801FC68031E073FE211C6441193100829000AE", "SORACOM SIM (plan unknown) (Telecommunication)" }, { "3B9F96801FC78031A073BE21136742470111000001CC", "Bank of Hawai'i (Bank)\nhttps://www.boh.com/" }, { "3B9F96801FC78031A073BE2113674320071800000100", "sysmoUSIM-SJS1 (Telecommunication) (Telecommunication)\nhttp://www.sysmocom.de/products/sysmousim-sjs1-sim-usim" }, @@ -3274,27 +3166,20 @@ const static atr_t AtrTable[] = { { "3B9F96801FC78031E073FE211B6441447300829000B7", "Bouygues Telecom (French Mobile Provider SIM card) (Telecommunication)\nhttps://www.bouyguestelecom.fr" }, { "3B9F96801FC78031E073FE211B6441503100829000E1", "telcel sim card (Telecommunication)" }, { "3B9F96801FC78031E073FE211B644163940082900077", "EMnify SIMcard (Telecommunication)\nhttps://www.emnify.com/global-iot-sim" }, - { "3B9F96801FC78031E073FE211B6441703100829000C1", "Slovak Railways (Telecommunication)" }, { "3B9F96801FC78031E073FE211B6441725100829000A3", "Free Mobile (French wireless service provider) SIM card (mini-SIM with micro-SIM cutout) received in 2020-09 (Telecommunication)\nhttps://mobile.free.fr/" }, { "3B9F96801FC78031E073FE211B6441725200829000A0", "Woolworths Mobile Prepaid SIM (Telecommunication)\nhttps://mobile.woolworths.com.au/" }, { "3B9F96801FC78031E073FE211B6441763200829000C4", "T-Mobile SIM card issued April 2021 (Telecommunication)" }, - { "3B9F96801FC78031E073FE211B644183710082900072", "SIM card (Telecommunication)" }, { "3B9F96801FC78031E073FE211B644183720082900071", "Ucom Armenia (Telecommunication)\nhttps://www.ucom.am" }, { "3B9F96801FC78031E073FE211B644187210082900026", "French SIM card from MVNO Phenix Partners, host operator Orange (Telecommunication)" }, { "3B9F96801FC78031E073FE211B644187950082900092", "Dish Wireless 5G (Telecommunication)\nhttps://help.boostmobile.com/docs/boost-mobile-network" }, - { "3B9F96801FC78031E073FE211B64418892008290009A", "VIVO pre SIM card (Telecommunication)" }, - { "3B9F96801FC78031E073FE211B644189610082900068", "SIM card of a MEO subsidiary 'UZO' (Telecommunication)\nhttps://www.uzo.pt/uzo/" }, - { "3B9F96801FC78031E073FE211B6450016600829000F6", "SIM card (manufactured by IDEMIA) Telecommunication" }, { "3B9F96801FC78031E073FE211B6450040100826A82EC", "SIM (Telecommunication)" }, - { "3B9F96801FC78031E073FE211B6450055100829000C5", "Sim card Team Telecom Armenia (Telecommunication)\nhttps://www.telecomarmenia.am/hy/\nSIM card issued by Serbian MTS (Telecommunication)" }, - { "3B9F96801FC78031E073FE211B6450094300829000DB", "Czech Railways (Telecommunication)" }, + { "3B9F96801FC78031E073FE211B6450055100829000C5", "Sim card Team Telecom Armenia (Telecommunication)\nhttps://www.telecomarmenia.am/hy/" }, { "3B9F96801FC78031E073FE211B65240109010081057B", "Lycamobile (UK) GSM SIM card" }, { "3B9F96801FC78031E073FE211B65260109000781057F", "EMT WPKI 2015 (ECC) subscription (Telecommunication)\nhttps://www.emt.ee/en/pakkumised/mobiil-id" }, { "3B9F96801FC78031E073FE211B65270109010381057B", "slarmy (Telecommunication)" }, { "3B9F96801FC78031E073FE211B652A01090101810574", "9mobile Nigeria (Telecommunication)\nhttp://www.9mobile.com.ng" }, { "3B9F96801FC78031E073FE211B652A010A0102810574", "Thailand AIS SIM Card (Telecommunication)" }, { "3B9F96801FC78031E073FE211B652A010E0201810570", "gsm (Telecommunication)" }, - { "3B9F96801FC78031E073FE211B652B010E010981057A", "Standard SIM card (Telecommunication)" }, { "3B9F96801FC78031E073FE211B652D010C0400810572", "Tri Indonesia Bima+ SIM Card (Telecommunication)\nhttps://beta.tri.co.id/3digiworld/Bimaplus" }, { "3B9F96801FC78031E073FE211B652F0109020A810579", "cellcom israel sim (Telecommunication)" }, { "3B9F96801FC78031E073FE211B652F01090602810575", "Indosat SIM Card (Telecommunication)" }, @@ -3311,26 +3196,20 @@ const static atr_t AtrTable[] = { { "3B9F96801FC78031E073FE211BB3E20394830F90006D", "GemXplore 3G v2.2" }, { "3B9F96801FC78031E073FE211BB3E204A5830F90005B", "Tre Italia Gemplus (Telecommunication)" }, { "3B9F96801FC78031E073FEA117574A33058C33390096", "1NCE SIM card (Telecommunication)\nhttps://1nce.com/en-eu/1nce-os/our-architecture" }, - { "3B9F96801FC78031E073FEA11F6441805100829000D5", "Smartjac smaot500b234ff (Telecommunication)\nhttps://www.smartjac.biz" }, - { "3B9F96803F87828031E073FE211B67454D753034024B02", "Hologram Global G1 eUICC SIM (Telecommunication)\nhttps://www.hologram.io/products/global-iot-sim-card/" }, + { "3B9F96803F87828031E073FE211B67454D753034024B02", "Hologram Global G1 eUICC SIM(Telecommunication)\nhttps: //www.hologram.io/products/global-iot-sim-card/" }, { "3B9F96803F87828031E073FE211F574543753130136502", "sysmoEUICC1-Cxx - eUCICC for econsumer eSIM RSP (Telecommunication)\nhttps://sysmocom.de/products/sim/sysmocom-euicc/index.html" }, - { "3B9F96803F87828031E073FE211F574543753130266F3D", "eSIM physical card, you can write eSIM profiles into it and use it as a general SIM (Telecommunication)\nhttps://www.9esim.com/" }, - { "3B9F96803F87828031E073FE211F574543753130276F3C", "An eSIM physical card, you can write eSIM profiles into it and use it as a general SIM Telecommunication\nhttps://www.9esim.com/" }, + { "3B9F96803F87828031E073FE211F574543753130266F3D", "An eSIM physical card, you can write eSIM profiles into it and use it as a general SIM (Telecommunication)\nhttps://www.9esim.com/" }, { "3B9F96803FC3A08031E073F62113574A4D0E1D31300071", "Telenor SIM card (Norway)" }, { "3B9F96803FC6A08031E073F62116574A4D020B34546369", "SIM card Wingo operator (Switzerland) (Telecommunication)" }, - { "3B9F96803FC7008031E073FE21136767A002D9000001E5", "Kcell (Telecommunication)" }, { "3B9F96803FC7008031E073FE211B6408050300829000EF", "Multipurpose UICC card for 2G, 3G, 4G/LTE, CDMA, ISIM & NFC (Telecommunication)\nhttp://www.smartjac.biz/index.php/component/eshop/telecom/test-uicc-sim-cards/2ff-mini-sim-cards/4g-open-multipurpose-uicc-card-3ff?Itemid=0" }, { "3B9F96803FC7008031E073FE211F6441262100829000A3", "Smartjac SMAOT100A234FF (Telecommunication)\nhttps://smartjac.com" }, { "3B9F96803FC7828031E073F62157574A330581053000CE", "COMPRION M2M eUICC (Telecommunication)" }, - { "3B9F96803FC7828031E073F62157574A4D020B3446007A", "cosmo one 9.1 (eID)" }, { "3B9F96803FC7828031E073F62157574A4D020B60010069", "eSIM GSMA Card (Telecommunication)\nhttps://www.gsma.com/newsroom/wp-content/uploads/SGP.22_v2.2.pdf" }, { "3B9F96803FC7828031E073F62157574A4D020B60610009", "ting (Telecommunication)" }, { "3B9F96803FC7828031E073FE211B57AA8660F0010004FB", "The eSIM.me Card (Telecommunication)\nhttps://esim.me/" }, { "3B9F96803FC7828031E073FE211B57AA8660F0010011EE", "eSIM.me pluggable eSIM (Telecommunication)\nhttps://esim.me/" }, { "3B9F96803FC7828031E073FE211B57AA8660F0010017E8", "eSim.me Orange Setup (Telecommunication)" }, { "3B9F96803FC7828031E073FE211B57AA8660F001001EE1", "5Ber (Telecommunication)\nhttps://esim.5ber.com" }, - { "3B9F96803FC7828031E073FE211B57AA8660F0010027D8", "5ber physical eUICC / eSIM (Standard Version) (Telecommunication)\nhttps://esim.5ber.com/order?language=en-US" }, - { "3B9F96803FC7828031E073FE211B57AA8660F3030002FC", "Xesim X2 (Telecommunication)\nhttps://xesim.cc/products/xesim?VariantsId=10004" }, { "3B9F96803FC7828031E073FE211B633A204E8300900031", "eSIM (Telecommunication)" }, { "3B9F96803FC7828031E075F62157200355020B60500018", "iPhone 11 SIM Slot eUICC chip. Identified by eSTK.me. (Telecommunication)" }, { "3B9F96803FC7828031E075F62157200355020C608000CF", "ST33J2M0STL9DZB0 (Telecommunication)\nhttps://www.st.com/en/secure-mcus/st33j2m0.html" }, @@ -3340,14 +3219,12 @@ const static atr_t AtrTable[] = { { "3B9F96803FC7828031E075F621573C0455020C61010054", "euicc from iphone14 (Telecommunication)" }, { "3B9F96803FC7A08031E073F62116574A4D020233456377", "ISIS-Ready T-Mobile Sim Card (Telecommunication)" }, { "3B9F96803FC7A08031E073F62156574A4D020B3444005B", "Norwegian telenor (Telecommunication)\nhttp://www.telenor.no" }, - { "3B9F96803FC7A08031E073F62157574A4D020B3444005A", "Verizon 4G SIM (Telecommunication)" }, { "3B9F96803FC7A08031E073F62157574A4D020B34546329", "Orange FR - opa (Telecommunication)" }, { "3B9F96803FC7A08031E073FE211B63F100E8830090005E", "UICC CARD (Telecommunication)" }, { "3B9F96803FC7A08031E073FE211B6407689A00829000B4", "Orange SIM Card (Telecommunication)" }, { "3B9F96803FC7A08031E073FE211B64080503008290004F", "NFC-enabled SIM card of MTS Russia. (Telecommunication)" }, { "3B9F96803FC7A08031E073FE211F6300690083819000AB", "GSM file system and SWP sample supplied with STMicro development kit (Other)" }, { "3B9F96803FC7A08031E073FE211F6441269100829000B3", "LTE Lab SIM Ver 1.3 (Telecommunication)" }, - { "3B9F968131FE454F52434C2D4A43332E324750322E3323", "Oracle JavaCard simulator (25.0) (Other)" }, { "3B9F968131FE458065544312210831C073F6218081059A", "Scientific and Technological Research Council of Turkey (test card) (eID)" }, { "3B9F968131FE45806755454B41451212318073B3A180EA", "AKiS v1.2 on nxp chip" }, { "3B9F968131FE45806755454B41451252318073B3A180AA", "AKiS v1.2.1 on infineon chip" }, @@ -3376,7 +3253,6 @@ const static atr_t AtrTable[] = { { "3B9F96C00A3FC6A08031E073FE211F65D001900F3B810FE6", "Verizon US USIM card (Telecommunication)" }, { "3B9F96C00A3FC6A08031E073FE211F65D00209107C810F24", "GSM SIM Vodafone NL postpaid NFC+ (Telecommunication)" }, { "3B9F96C00A3FC6A08031E073FE211F65D0021B12B7810FFF", "SIM Card Fastweb IT GSM mobile network (Telecommunication)" }, - { "3B9F96C00A3FC6A08031E073FE211F65D0023314E0810F86", "Verizon 5G sim card (Telecommunication)" }, { "3B9F96C00A3FC7828031E073FE211F65D00209146C810F13", "euicc (eID)" }, { "3B9F96C00A3FC7A08031E073FE211B65D001740E8D810FB0", "USIM" }, { "3B9F96C00A3FC7A08031E073FE211B65D001740EE3810FDE", "EE (UK) Mobile Phone SIM Card circa 2016 (Telecommunication)" }, @@ -3401,10 +3277,8 @@ const static atr_t AtrTable[] = { { "3B9F97C00A1FC78031E073FE211B65D0011009228100F2", "'ultra fast card, max speed supported for telecom'? (transport)" }, { "3B9F97C00A1FC78031E073FE211B65D001900F3B810F62", "Gemalto Multi-SIM consumer 4.2 (ST33I1M2) (Telecommunication)" }, { "3B9F97C00A3FC6828031E073FE211B65D0023314A5810FE4", "Thales eUICC French Ministry BAP v2 (Telecommunication)" }, - { "3B9F97C00A3FC6828031E073FE211F65D0023314A5810FE0", "Flexiroam SIM card (Telecommunication)\nhttps://www.flexiroam.com/" }, { "3B9F97C00A3FC6A08031E073FE211B65D001740EEB810FD6", "Verizon 4G LTE Micro SIM (Telecommunication)" }, { "3B9F97C00A3FC6A08031E073FE211F65D0021B13F6810FBE", "Verizon SIM Card (Telecommunication)" }, - { "3B9F97C00A3FC6A08031E073FE211F65D0023314E0810F87", "Verizon 5G SIM Card (Telecommunication)\nhttps://www.verizon.com/" }, { "3B9F97C00A3FC7A08031E073FE211F65D001900FEE810F33", "AT&T Mobility LLC MicroSIM Card (Telecommunication)\nhttps://www.att.com/wireless/" }, { "3B9F97C00AB1FE453FC6828031E073FE211B65D0023A14C9810F8B", "SIM (Telecommunication)" }, { "3B9F97C0FF1FC78031E073FE211B63F100AD830F90002A", "Gemalto Speed Enhancement 97 (Telecommunication)" }, @@ -3450,11 +3324,10 @@ const static atr_t AtrTable[] = { { "3BB794008131FE6553504B32339000D1", "Giesecke & Devrient Starcos 2.3\nDeutsche Bank WebSign (RSA-Card)\nG&D StarSign Token\nOsakidetza ONA (eID)\nhttp://www.osakidetza.euskadi.eus/r85-ckserv01/es/contenidos/nota_prensa/ruedasanidad35/es_rs/ruedasanidad35_c.html" }, { "3BB813008131205D0057696E4361726402", "SmartCard for Windows 1.1" }, { "3BB813008131FA524348544D4F494341A5", "citizen digital certificate (PKI)\nhttp://moica.nat.gov.tw/" }, - { "3BB89600C00831FE45FFFF1154305023006A", "Infineon SECORA ID S, SLJ52GDT120CS (JavaCard)" }, { "3BB897008131FE45FFFF148230502300F1", "UAE Emirates ID (eID)\nhttps://www.icp.gov.ae" }, { "3BB89700813FE45FFFF148230502300F", "UAE Emirates ID (eID)" }, { "3BB89700C00831FE45FFFF148230502300B8", "Infineon SECORA ID X (JavaCard)" }, - { "3BB918008131FE9E8073FF614083000000DF", "Serbian Identity Card\n1st Serbian biometric identity card (every adult cityzen must have).\nThe chip contains owners picture, name, date and place of birth, current\naddress, unique ID number and fingerprint." }, + { "3BB918008131FE9E8073FF614083000000DF", "Serbian Identity Card\nThis is the new Serbian biometric identity card (every adult cityzen\nmust have). The chip contains owners picture, name, date and place\nof birth, current address, unique ID number and fingerprint." }, { "3BB9940040144747334D4838353330", "T D1 GSM card (Telecommunication)" }, { "3BB9940040144747334E4838363430", "GSM-SIM card of the Austrian mobile phone provider One\nhttp://www.one.at\nProximus SIM - Belgium (SetCOS?)\no2 GSM-SIM card Germany 2003" }, { "3BBA11001000434C5F53414D00133800", "Planeta Informatica CL-SAM (Other)\nhttp://www.planeta.inf.br/" }, @@ -3548,7 +3421,6 @@ const static atr_t AtrTable[] = { { "3BBF1800C02031705253544152434F5320533231204390009C", "Giesecke & Devrient SPK 2.1 C" }, { "3BBF9300801FC68031E073FE2113576573746B2E6D65E3", "eSTK.me v1.2.5 or later (Telecommunication)\nhttps://eSTK.me" }, { "3BBF9300803FC6828031E073FE2113576573746B2E6D6541", "eSTK.me v1.2.4 (Telecommunication)\nhttps://eSTK.me" }, - { "3BBF9400801FC68031E073FE2113576573746B2E6D65E4", "eSTK.me SGP.22 consumer card T001V06 (3.4.3) (Telecommunication)" }, { "3BBF94008131FE65454C55204175737472696120312E3238", "A-Trust: trust-sign (Old Version, ca. 2002) for Digital Signature etc.\nA-Trust: a-sign-premium (ca. 2004) 'Burgerkarte' ('Citizen-Card')\nfor Identifikation, Digital Signature etc.\n('should be' Starcos 2.3)" }, { "3BBF9500801FC68031E073FE2113576573746B2E6D65E5", "eSTK.me v3.1.1 or later (Telecommunication)\nhttps://estk.me" }, { "3BBF9500803FC6828031E073FE2113576573746B2E6D6547", "eSTK.me v3.1.1 (Telecommunication)\nhttps://eSTK.me" }, @@ -3556,7 +3428,7 @@ const static atr_t AtrTable[] = { { "3BBF96008131FE5D00640411000031C073F701D0009000", "DATEV eG, Nuernberg, Bavaria, Germany (PKI)\nhttp://www.datev.de" }, { "3BBF96008131FE5D00640411030131C07301D000900000", "DATEV eG, Nuernberg, Bavaria, Germany (PKI)\nhttp://www.datev.de" }, { "3BBF96008131FE5D00640411030131C073F701D0009000", "DATEV eG, Nuernberg, Bavaria, Germany (PKI)\nhttp://www.datev.de" }, - { "3BC5FF8131FB458073C6010000", "Japanese Public Key Infrastructure (PKI)\nhttps://www.jpki.go.jp/\nJapanese Individual Number Card (My Number Card) (eID)\nhttps://www.kojinbango-card.go.jp/en/" }, + { "3BC5FF8131FB458073C6010000", "Japanese Individual Number Card (eID)\nhttps://www.kojinbango-card.go.jp/en/kojinbango/index.html" }, { "3BC800000073C84000000000", "verve (Bank)" }, { "3BCDFF8031FE450068D276000028040481009000CD", "Tachograph company test card (Transport)" }, { "3BD096FF81B1FE451F032E", "New european health insurance card of the German health insurance (G2) (HealthCare)\nhttps://de.wikipedia.org/wiki/Elektronische_Gesundheitskarte" }, @@ -3574,13 +3446,10 @@ const static atr_t AtrTable[] = { { "3BD218008131FE58CB0116", "D-Trust Card 5.1/5.4 (contact based)\nhttps://www.d-trust.net/de/support/signatur-und-siegelkarten" }, { "3BD21802C10A31FE58C80D51", "Siemens Card CardOS M4.4" }, { "3BD296FF81B1FE451F870102AB", "Electronic Vehicle Registration (eVR) from RDW.nl (The Netherlands), open sourced at [URL], demo (Windows / Linux Wine Mono) (Transport)\nhttps://github.com/eVRMTV/eVR" }, - { "3BD396FF81B1FE451F0380810529", "German Health Insurance Card 'Gesundheitskarte' (HealthCare)\nhttps://www.bahn-bkk.de/" }, { "3BD396FF81B1FE451F078081052D", "German public health insurance card (Elektronische Gesundheitskarte eGK), 2nd generation (G2) (HealthCare)" }, - { "3BD49500400A5348434C", "Rc book (Transport)" }, { "3BD5180081313A7D8073C8211030", "Aladdin eToken NG-Flash with 256MB of flash memory\nAladdin eToken PRO (72KB)\nhttp://www.aladdin.com/etoken/devices/default.aspx" }, { "3BD518008131FE7D8073C82110F4", "Bank of Lithuania Identification card\nGemalto SafeNet eToken Java Based Cards\nhttps://safenet.gemalto.com/multi-factor-authentication/authenticators/pki-usb-authentication/" }, { "3BD518FF8091FE1FC38073C8211308", "Athena IDProtect (JavaCard 2.2.2)\nhttp://www.athena-scs.com/product.asp?pid=32\nThales nShield Security World Card - Remote Administration Ready\nhttps://www.thalesesecurity.fr/products/hsm-management-and-monitoring/nshield-remote-administration" }, - { "3BD518FF8191FE1FC34A434F503422", "algerian driving licence (eID)" }, { "3BD518FF8191FE1FC38073C821100A", "ComSign digital signature card (eID)\nhttps://www.comsign.co.uk/" }, { "3BD518FF8191FE1FC38073C8211309", "Athena IDProtect Key (v2)\nhttp://www.athena-scs.com/product.asp?pid=33" }, { "3BD518FF81B1FE451FC38073C821106F", "DPI Card ID Guatemala Version 2024 (eID)\nhttps://www.renap.gob.gt/" }, @@ -3675,12 +3544,10 @@ const static atr_t AtrTable[] = { { "3BDB960080B1FE451F830031C164084022300F90000A", "Oberthur v7 - in a Gemalto (was Gemplus) GemPC Key SmartCard Reader (grey USB dongle) - bought at ChamberSign (PKI)" }, { "3BDB960080B1FE451F830031E85427E6040007900084", "Polish encard (eID)" }, { "3BDB960080B1FE451F830031E85427E604000F90008C", "Token card from iBRE CompanyNet (mbank) (Bank)" }, - { "3BDB960080B1FE451F830031E85427E6050007900085", "Polish qualified signature card by CenCert (Other)\nhttps://www.cencert.pl/produkt/podpis-elektroniczny-kwalifikowany-na-karcie-2024/" }, { "3BDB960080B1FE451F834553544F4E49412D65494455", "Estonian Identity Card (ID-One Cosmo v8.1) (eID)" }, { "3BDB960080B1FE451F870031C1640958223607900019", "Idemia Solvo Fly 40 (JavaCard)" }, { "3BDB960081B1FE451F0380F9A0000003080000100018", "Oberthur CS PIV End Point v1.08 FIPS201 Certified" }, { "3BDB960081B1FE451F0380F9A0000003480000000149", "Fly Clear card" }, - { "3BDB960081B1FE451F830031C064FC2910000190009B", "Sm@rtCafe Expert 7.0 (SCE7.0) SAM card (Transport)" }, { "3BDB960081B1FE451F8380F9A0000003080000100098", "Oberthur Cosmo v7 128K with PIV applet\nhttp://www.smartcardfocus.com/shop/ilp/id~410/p/index.shtml" }, { "3BDB96FF80B1FE451F870031C164093364490F9000BC", "cnie Carte Nationale d'Identite Electronique (eID)" }, { "3BDB96FF80B1FE451F870031C164093772130F9000F4", "French ID Card 2021 (eID)\nhttps://ants.gouv.fr/nos-missions/les-titres-produits-par-l-ants/les-documents-d-identite/la-puce-de-la-nouvelle-carte-nationale-didentite" }, @@ -3713,7 +3580,6 @@ const static atr_t AtrTable[] = { { "3BDD18008191FE1FC3006646530803003671DF00008097", "Feitian K9Plus - ePass FIDO-NFC with PIV (Other)\nhttps://ftsafe.com/products/FIDO/NFC" }, { "3BDD18FF8191FE1FC3006646530803003671DF00008068", "Feitian FIDO NFC Plus K9 Security Key (Other)\nhttps://www.ftsafe.com/products/FIDO/NFC" }, { "3BDD18FF8191FE1FC3FF4F70656E506879736963616CF6", "Open Physical PIV-Compatible NXP SECID P60 (eID)\nhttps://openphysical.org/" }, - { "3BDD18FF81B1FE451FC39E414B442D43657274696C6961BD", "Certilia Gen2 Card (eID)\nhttps://www.certilia.com/" }, { "3BDD18FFC080B1FE451FC30068D276000028040411009000C9", "Russian Federation driver card for the digital tachograph\nPolish driver card for digital tachograph" }, { "3BDD18FFC080B1FE451FC30068D276000028040971009000A4", "Worktime/driving style monitoring card (Transport)\nhttp://www.paetronics.fi/en/" }, { "3BDD96008010FE8031806301FFC073B3211B8105", "BIFIT iBank 2 USB Key (Bank)\nhttp://bifit.ua" }, @@ -3778,8 +3644,6 @@ const static atr_t AtrTable[] = { { "3BDF960080B1FE451F870031C16408923201738421E0059000C5", "Company Card for Transport companies (Transport)" }, { "3BDF96008131FE4541434F532D4944303032382E3031366F", "Sri Lankan driving license [ web: motortraffic.gov.lk ] (eID)\nhttp://www.motortraffic.gov.lk/web/index.php?option=com_content&view=article&id=83&Itemid=140&lang=en" }, { "3BDF96008131FE4580738421E0554978000080830F90000C", "Idemia Cosmo X (eID)\nhttps://cyber.gouv.fr/sites/default/files/2021/08/anssi-cible-cc-2021_36n.pdf" }, - { "3BDF96008131FE4580738421E05569780000808307900024", "Romanian Electronic Identity Card (eID)" }, - { "3BDF96008131FE4580738421E0556978540001830F9000F9", "National ID Card of Peru issued by RENIEC (eID)\nhttps://identidad.reniec.gob.pe/dni-electronico" }, { "3BDF96008131FE588031B05202056405A100AC73D622C020", "Austrian health insurance card 'e-card' (HealthCare)\nhttps://de.wikipedia.org/wiki/E-card_(Chipkarte)" }, { "3BDF960081B1FE451F838073CC91CBF9A0000003080000100079", "Test PIV Cards available for sale from NIST\nhttp://csrc.nist.gov/groups/SNS/piv/testcards.html" }, { "3BDF960090103F07008031E0677377696363000073FE210006", "swsim card (Telecommunication)" }, @@ -3790,9 +3654,6 @@ const static atr_t AtrTable[] = { { "3BDF96FF8131FE45805B44452E424E4F544B3130308105A0", "BeA - Certification Card for German Solicitors (Other)\nhttps://bea.bnotk.de/" }, { "3BDF96FF81B1FE451F870031B96409377213738401E000000000", "National Identity Card of Slovakia (eID) (eID)\nhttps://en.wikipedia.org/wiki/Slovak_identity_card" }, { "3BDF96FF910131FE4680319052410264050200AC73D622C017", "Acos-ID (AUSTRIACARD's Operating System) (Other)\nhttps://www.austriacard.com/digital-security/solutions/card-solutions/acos-id/" }, - { "3BDF97008131FE4541434F5300030001020001010001015D", "Academic ID (Other)\nhttps://submit-academicid.minedu.gov.gr/" }, - { "3BDF97008131FE4680319052410364050201AC73D622C0F8", "A-Trust ACOS-ID v3 (AustriaCard Operating System), used for Austrian RKSV fiscal signature cards (Other)\nhttps://github.com/A-Trust/RKSV" }, - { "3BDF97008131FE4680319052410464050401AC73D622C0F9", "A-Trust ACOS-ID v4.1 (AustriaCard Operating System), used for Austrian RKSV fiscal signature cards (Other)\nhttps://github.com/A-Trust/RKSV" }, { "3BDF97008131FE588031B05202056405A100AC73D622C021", "Austrian healthcare insurance identification card (HealthCare)\nhttps://www.chipkarte.at" }, { "3BDF970081B1FE451F838073CC91CBF9A0000003080000100078", "NASA PIV Card (Other)" }, { "3BE000008131104505", "Emoney indonesia (Bank)" }, @@ -3804,7 +3665,6 @@ const static atr_t AtrTable[] = { { "3BE2000040204907", "Schlumberger Cryptoflex Key Generation" }, { "3BE200FFC11031FE55C8029C", "Aladdin eToken PRO (USB token)\nSiemens CardOS M4.0" }, { "3BE300FF9181712644000113202D", "Metrebus Card\n(used in Rome to store personal information and Atac subscription.\nAtac is the public transport company of the city of Rome.)\nhttp://www.atac.roma.it/smart/smart.asp?A=2&S=22&PR=4&LNG=2" }, - { "3BE400008121459C1000800D", "JCP2040 (JavaCard)" }, { "3BE500008121459C100100800D", "BIN 470132 -- BANK OF AMERICA VISA DEBIT -- GEMALTO MGY 0 U1090788B - 12/14 F8 00 89 (Bank)" }, { "3BE500008131FE45D00037008089", "ATM card for Standard Chartered, Taiwan" }, { "3BE500FF8131FE458073C601082D", "MUFG (.jp) (Bank)" }, @@ -3835,7 +3695,6 @@ const static atr_t AtrTable[] = { { "3BE800008131FE450073C8400000900088", "VISA Card (Skandinaviska Enskilda Banken) with Swedish BankID\nVISA card (Chinatrust Bank (Taiwan), dual-interface card with a Taipei Metro e-purse function)" }, { "3BE800008131FE454A434F50763234....", "NXP JCOP v2.4.x (see hist bytes for more info)" }, { "3BE800008131FE454A434F5076323431B4", "VISA Debit card for NAB, Australia" }, - { "3BE800FF8131FE41534C4A01305023101F", "Cashapp Card - WIP arduino apdu interface (Bank)" }, { "3BE800FF8131FE43AA00000000000000B0", "Secure Signing Token (eID)" }, { "3BE800FF8131FE45434C6169726520361A", "DKB Visa card with PayWave" }, { "3BE90000812145454D565F41545220066C", "VISA card, issued by HVB Bank Czech Republic or austrian BankAustria\nhttp://www.hvb.cz" }, @@ -3885,7 +3744,6 @@ const static atr_t AtrTable[] = { { "3BED00008131FE450031C071C6644D3533560F900046", "Kostadin (Bank)" }, { "3BED00008131FE450031C071C6644D35354D0F9000", "ING Credit Card (Bank)\nhttps://www.ing.nl/particulier/betalen/creditcards/index.html" }, { "3BED00FF813120754D424320534D502056312E3130BD", "Used to Control a Laser Device" }, - { "3BEE00008131804180318066B0840C016E01830090008D", "CTBC Bank Co., Ltd. debit VISA card (Bank)\nhttps://www.ctbcbank.com/twrbo/zh_tw/cc_index/cc_product/cc_debitcard_index.html" }, { "3BEE00008131804280318066B0840C016E01830090008E", "MultiApp Cards (Easy 72K Type B and Combi 72K Type B)\nE.SUN Commercial bank debit master card (Bank)\nTaiwan EasyCard (Transport)\nhttps://www.easycard.com.tw/english/index.asp" }, { "3BEE00008131804380318066B1A1110100F683009000", "Optelio/Desineo Cards (D72 FXR1)" }, { "3BEE00008131804380318066B1A11101A0F683009000", "Optelio D72 FXR1 (MD) T=1" }, @@ -3978,7 +3836,6 @@ const static atr_t AtrTable[] = { { "3BEF00FF8131FE456563111562025000100A002EFC0720C6", "maestro BankCard (Bank)" }, { "3BEF00FF8131FE456563111562025000100A09AC030720B2", "Girocard Sparkasse Darmstadt (Bank)" }, { "3BEF00FF8131FE4565631901620280000F003500420620BB", "Credit card (Germany, Postbank AG): VISA" }, - { "3BEF00FF8131FE4565631D028401560024140B60E401016E", "EthikBank Giro Card (Bank)\nhttps://www.ethikbank.de/privatkunden/konten-karten/karten-zum-konto/girocard" }, { "3BEF00FF8131FE4565631D0284025000230509A0D9010182", "Debit card (Bank)" }, { "3BEF00FF8131FE4565631D028402500023180920E7010121", "Deutsche Kreditbank AG (DKB AG) bank card (Bank)\nhttps://www.dkb.de/info/tan-verfahren/chipTAN/" }, { "3BEF00FF8131FE458031C06B49424D204A65745A204D3239", "UBS Internet Card (IBM JetZ M2)" }, @@ -4001,14 +3858,11 @@ const static atr_t AtrTable[] = { { "3BF29800FFC11031FE55C80315", "Siemens CardOS M 4.01 (SLE66CX320P)" }, { "3BF29800FFC11031FE55C80412", "CardOS M4.01a (SLE66CX322P)" }, { "3BF39600FFC00A31FE4D8031E083", "MARX Cryptoken (supported by RaakSign)" }, - { "3BF41300008131FE45004E0000A2", "Japanese HPKI card (PKI)\nhttps://www.medis.or.jp/8_hpki/index.html" }, { "3BF41300008131FE4552465A4FED", "Serbian Health Care electronic card (HealthCare)\nhttp://www.rfzo.rs/index.php/osiguranalica/ekartica" }, { "3BF4180002C10A31FE5856346376C5", "Eutron CryptoIdentity (reader + card token)" }, { "3BF41800FF8131805500318000C7", "Identity card of Italian Republic" }, { "3BF49800FFC11031FE554D346376B4", "Eutron Digipass 860 (reader + card token)" }, - { "3BF513000010002063CB12C1", "CB Master Carte du Credit Mutuel (Bank)" }, { "3BF51300008131FE4573746431308F", "card for NF-e in Brazil (PKI)\nhttps://certificadodigital.imprensaoficial.com.br/certificados-digitais/e-cnpj/a3/e-cnpj-a3-cartao" }, - { "3BF51320060E49424D0101B3", "User Identity card for TeleGuide, a Swedish terminal from the 90's similar to the French minitel. (eID)" }, { "3BF51800008131FE454D794549449A", "Aventra ActiveSecurity MyEID\nhttp://www.aventra.fi/pdf/ActiveSecurity%20MyEID%20Tokens%20white%20paper%20(2p)%20EN.pdf" }, { "3BF518000210804F73454944", "Atmega 128 microcontroller based open source EID smartcard with RSA and ECC. (eID)\nhttps://oseid.sourceforge.io/" }, { "3BF57100FFFE2400011E0F3339320103", "Mydo IC Card from Japan, based on NTTDATA CARD (Loyalty)\nhttps://www.idemitsu.com/company/history/13.html" }, @@ -4018,9 +3872,9 @@ const static atr_t AtrTable[] = { { "3BF59100FF918171FE400041180000001D", "Contactless Mifare 4k" }, { "3BF59100FF918171FE400041880000008D", "Contactless Mifare 1k or 4k" }, { "3BF59100FF918171FE4000420001008186", "American Express Blue RFID" }, - { "3BF59100FF918171FE400042000100D1D6", "Japanese Public Key Infrastructure (PKI)\nhttps://www.jpki.go.jp/\nJapanese Individual Number Card (My Number Card) (eID)\nhttps://www.kojinbango-card.go.jp/en/" }, + { "3BF59100FF918171FE400042000100D1D6", "Japanese Public Key Infrastructure (PKI)\nhttps://www.jpki.go.jp/\nMy Number Card (The Social Security and Tax Number System in JAPAN) (eID)\nhttps://www.cao.go.jp/bangouseido/" }, { "3BF59100FF918171FE400042000177D1A1", "German Passport (ePass) (issued May 2008)" }, - { "3BF59100FF918171FE4000420001B3A115", "Japanese Public Key Infrastructure (PKI)\nhttps://www.jpki.go.jp/\nJapanese Individual Number Card (My Number Card) (eID)\nhttps://www.kojinbango-card.go.jp/en" }, + { "3BF59100FF918171FE4000420001B3A115", "Individual Number Card (eID)\nhttps://www.kojinbango-card.go.jp/" }, { "3BF59600008.31FE454D794549441.", "MyEID card (Infineon chip) (PKI)\nhttps://services.aventra.fi/English/products_MyEID_E.php" }, { "3BF61300FF1080434849503232", "PostFinance debit (Bank)\nhttps://www.postfinance.ch" }, { "3BF61300FF910131FE4080640F7000009E", "JA Bank Cash Card (Bank)\nhttps://www.jabank.org/" }, @@ -4141,7 +3995,6 @@ const static atr_t AtrTable[] = { { "3BFA1300008131FE454A434F5034315632333197", "JCOP41 /72K (eID)" }, { "3BFA1300008131FE454A434F50763234........", "NXP JCOP v2.4.x (see hist bytes for more info)" }, { "3BFA1300008131FE54A434F503233191", "Jcop (JavaCard)" }, - { "3BFA1300008171FE4200434F4946433256312E31AF", "Castles Technology Partner Self Signing Card (Other)" }, { "3BFA1300FF813180450031C173C00100009000B1", "OpenPGP" }, { "3BFA1300FF918131FE478012392F31C073C7014907", "MITSUBISHI Standard-9M (PKI)\nhttps://www.mdis.co.jp/service/standard-9m/" }, { "3BFA1800008031FE45FE654944202F20504B4903", "Estonian Identity Card (EstEID v3.5 (10.2014) cold) (eID)\nhttp://id.ee/" }, @@ -4157,8 +4010,7 @@ const static atr_t AtrTable[] = { { "3BFA1800008131FE454D4F54494F4E0000900760", "SIM card (Telecommunication)" }, { "3BFA1800008131FE4550564A434F5033454D5694", "NXP JCOP3 J3H082 Java Card 3.0.4 Dual-Interface (JavaCard)\nhttps://www.cardlogix.com/product/nxp-jcop3-j3h082-java-card-3-0-4-j3h081-dual-interface/" }, { "3BFA1800008131FE4550564A434F503453494493", "National Health Insurance (Taiwan) (HealthCare)" }, - { "3BFA1800008131FE45534C4A35324778787979FC", "National Health Insurance of Taiwan (HealthCare)\nhttps://www.nhi.gov.tw/" }, - { "3BFA180000910131FE454A33523138302D323535F5", "Cardlogix J3R180 NXP JCOP 4 Java Card 3.0.5 Classic Dual Interface (JavaCard)\nhttps://www.cardlogix.com/product/nxp-jcop-4-java-card-3-0-5-classic/" }, + { "3BFA180000910131FE454A33523138302D323535F5", "Cardlogix J3R180 NXP JCOP 4 Java Card 3.0.5 Classic Dual Interface (JavaCard) (JavaCard)\nhttps://www.cardlogix.com/product/nxp-jcop-4-java-card-3-0-5-classic/" }, { "3BFA180000910131FE454A33523331302D333535FF", "NXP JCOP 4 Java Card 3.0.5 Classic (JavaCard)\nhttps://www.cardlogix.com/product/nxp-jcop-4-java-card-3-0-5-classic/" }, { "3BFA180000910131FE4550564A434F503453494482", "Supposed P71 SecID purchased from a Chinese manufacturer (JavaCard)" }, { "3BFA180000910131FE456BD1936AC2F28547E164CC", "J3R180, NXP JCOP4 JC3.0.5 Classic, GP2.3, SECID (JavaCard)\nhttps://www.cardlogix.com/product/nxp-jcop-4-java-card-3-0-5-classic/" }, @@ -4181,18 +4033,12 @@ const static atr_t AtrTable[] = { { "3BFB1300008131FE454A434F50533.3.56323332..", "JCOP-Sxx/yy v2.3.2 (see hist bytes for more info)" }, { "3BFB1300008131FE456368617269736D6174657884", "Charismathics smart card JCOP and Qualified electronic signature CHJCOP-xxx (PKI)\nhttps://www.stampit.org/en/page/808" }, { "3BFB1300FF10000031C164099511380F9000", "Mastercard World Elite (CapitalOne Venture) (Bank)\nhttps://www.mastercard.us/en-us/personal/find-a-card/world-elite-mastercard-credit.html" }, - { "3BFB1300FF10800031C16408603206079000", "America First Credit Union Visa Credit Card (Bank)\nhttps://www.americafirst.com/" }, { "3BFB1300FF10800031C164086032060F9000", "Stripe Issuing Card (Bank)" }, { "3BFB1300FF10800031C164086032100F9000", "Varo (Bank)" }, - { "3BFB1300FF10800031C164087771300F9000", "Apple Card (Bank)" }, { "3BFB1300FF10800031C164089862210F9000", "Visa Debit (Bank)" }, { "3BFB1300FF10800031C164089862290F9000", "Bank Card (Bank)" }, { "3BFB1300FF10800031C1640924331E0F9000", "TransferWise Debit Card (Bank)\nhttps://wise.com/" }, - { "3BFB1300FF10800031C164092962250F9000", "Apple Credit Card (Bank)" }, - { "3BFB1300FF10800031C164095821360F9000", "American Express issued by American Express Europe S.A. (Germany branch) (Bank)\nhttps://www.americanexpress.com/de-de/" }, - { "3BFB1300FF10800031C164095822360F9000", "LINE Bank by Hana Bank BT21 Debit Visa (Bank)" }, { "3BFB1300FF10800031C164096441360F9000", "Truist Business Debit (Bank)" }, - { "3BFB1300FF10800031C164097861310F9000", "Deel Visa Business Debit Card (Bank)\nhttps://help.letsdeel.com/hc/en-gb/articles/4407737595409-What-is-the-Deel-Card" }, { "3BFB1300FF813180755A43352E3520524556204763", "ZeitControl BasicCard 5.5" }, { "3BFB1300FF813180755A43352E3620524556204D6A", "ZeitControl BasicCard ZC5.6 user-programmable smart card\nhttp://www.basiccard.com/index.html?overview.htm" }, { "3BFB1300FF813180755A43362E3520524556204364", "ZeitControl BasicCard 6.5, multiapplication with 30 kByte EEPROM" }, @@ -4213,7 +4059,6 @@ const static atr_t AtrTable[] = { { "3BFB9600008131FE450031E85427E60100079000BC", "Gemalto (PKI)" }, { "3BFB9600008131FE4556445349354001000400011F", "Vasco DIGIPASS KEY 200 usb token\nhttp://www.vasco.com/products/digipass/digipass_pki/digipass_pki_keys/digipass_key_200.aspx\nShould contain a 'Oberthur cosmo v 5.4 or V7.0D' smartcard" }, { "3BFB9800FFC11031FE550064052047033180009000F3", "Gemplus GemGate 32K\ndistributed by Postecert (www.postecert.it) to legally sign documents" }, - { "3BFC130000108081000300203002220100140C", "SberBank card (Bank)" }, { "3BFC1300008131FE15597562696B65794E454F7233E1", "YubiKey NEO (PKI)\nhttp://www.yubico.com/" }, { "3BFC1300008131FE45597562696B65794E454F7233B1", "Yubikey Neo\nhttp://www.yubico.com/products/yubikey-hardware/yubikey-neo/" }, { "3BFC180000813180459067464A00641606F2727E00E0", "PIVKey C910 PKI Smart Card (eID)\nhttp://pivkey.com/" }, @@ -4237,7 +4082,6 @@ const static atr_t AtrTable[] = { { "3BFD1300008131FE4580318153534431738421C0810730", "Personal Info Card (eID)" }, { "3BFD1300FF10000031C173C8400052A1C5009000", "IBKR Prepaid MasterCard, Issued by Peoples Trust Company (Bank)\nhttps://www.interactivebrokers.com/en/index.php?f=26451" }, { "3BFD1300FF10000031C173C8400052A1D5009000", "PayPal Business Debit Mastercard (Bank)\nhttps://www.paypal.com/merchantapps/appcenter/makepayments/bdmc" }, - { "3BFD1300FF10000031C173C8400052A37B009000", "Payoneer Card - USD Currency (Bank)\nhttps://payoneer.custhelp.com/app/answers/detail/a_id/18226/~/account-with-card---faq" }, { "3BFD1800008031FE45003180718E6452D904008190005B", "Oberthur Card Systems, authentIC" }, { "3BFD1800008031FE4553434536302D43443038312D46C4", "Panama Electronic Signature (JavaCard)" }, { "3BFD1800008031FE45736674652063643134342D6E66D8", "SmartCafe Expert 3.2 144K Dual is a contact and contactless technology Java card from G&D with 144K on-board EEPROM for application and data storage. Certified to FIPS 140-2 Level 3 and Common Criteria EAL 5+. Supports specifications ISO 14443A T=CL and ISO 7816 T=1/0. (PKI)\nhttp://www.smartcardfocus.us/shop/ilp/id~523/smartcafe-expert-3-2-144k-dual/p/index.shtml" }, @@ -4332,12 +4176,10 @@ const static atr_t AtrTable[] = { { "3BFF1300FF10000031C173C8211064414D3348079000", "BBVA blue VISA Debit Card (Bank)\nhttps://www.bbva.es/en/personas/productos/tarjetas/tarjeta-joven-ahora.html\nDesjardins Bonus Visa credit card (Bank)\nhttps://www.desjardins.com/ca/personal/loans-credit/credit-cards/bonus-visa/index.jsp" }, { "3BFF1300FF10000031C173C8211064414D3430079000", "PNC BUSINESS VISA DEBIT (Bank)\nhttps://www.pnc.com/en/small-business/payments-and-processing/payment-cards/pnc-bank-visa-business-debit-card.html" }, { "3BFF1300FF10000031C173C8211064414D3531079000", "Discover It Credit Card (Bank)" }, - { "3BFF1300FF10000031C173C82110644230434E079000", "Unicredit debit Card MasterCard (Italy) (Bank)" }, { "3BFF1300FF10000031C173C82110644930424E079000", "National Bank Debit Card with expiration date and cvv code (Bank)" }, { "3BFF1300FF10000031C173C82110644932424E079000", "Interact, Visa Debit Bank of Novia Scotia (Bank)\nhttps://www.scotiabank.com/global/en/credit-card-terms-and-conditions.html" }, { "3BFF1300FF10000031C173C82110644D30424E079000", "Debit payment card (Rabobank NL) (Bank)\nhttps://www.rabobank.nl/en/business/making-and-receiving-payments/payments/paying-with-your-bank-card" }, { "3BFF1300FF10000031C173C82110644D30434E079000", "Huntington (Bank)" }, - { "3BFF1300FF10000031C173C82110645530434E079000", "caixa bank debit card (Bank)" }, { "3BFF1300FF10000031C173C82110645630424E079000", "Rabobank Netherlands VISA debit (Bank)" }, { "3BFF1300FF10000031C173C82110645631424E079000", "Portuguese 'BancoCTT' Bank Card (Bank)\nhttps://www.bancoctt.pt/o-seu-dia-a-dia/cartao-de-credito-banco-ctt" }, { "3BFF1300FF10000031C173C82110645631434E079000", "Chase Freedom Unlimited Credit Card (Bank)" }, @@ -4352,12 +4194,9 @@ const static atr_t AtrTable[] = { { "3BFF1300FF8131FE45656311045002800008540004230502A5", "Maestrocard/Geldkarte (Stadtsparkasse Haltern, Germany)" }, { "3BFF1300FF8131FE5D8025A00000005657444B33323005003F", "Datakey DCOS model 320" }, { "3BFF1300FF910131FE210031C173C82110644D30434E07900094", "AirPlus MasterCard Commercial (Bank)\nhttps://www.airplus.com/us/en/products-solutions/products/corporate-cards/corporate-cards.html" }, - { "3BFF1300FF910131FE210031C173C82110645630434E0790008F", "Girocard for ING bank in germany (Bank)\nhttps://www.ing.de/girokonto/" }, - { "3BFF1300FF910131FE413101F1564012002200000000000000EA", "JCB T-CARD PLUS (eID)\nhttps://www.aplus.co.jp/creditcard/use/tcardplus_t/index.html" }, { "3BFF1300FF910131FE4141434F5320486F6C6C7931204C633665", "OEAMTC Visa Club Card (Bank)\nhttps://www.oeamtc.at/mitgliedschaft/leistungen/die-oeamtc-kreditkarte-31091443" }, - { "3BFF1300FF910131FE4145504100000001068135890000000063", "Austrian Bank Card for kids, teens and young adults Bank\nhttps://www.sparkasse.at/sgruppe/spark7" }, { "3BFF1300FF910131FE41455041000000010833995600000000AC", "Austrian Sparkasse ISIC debit card (Mastercard) (eID)\nhttps://isic.at/" }, - { "3BFF1300FF918131FE4141434F532046696F6E6131204C6336F4", "Deutsche Kreditbank Debit (Bank)\nBanca Intesa Visa card (Bank)" }, + { "3BFF1300FF918131FE4141434F532046696F6E6131204C6336F4", "Deutsche Kreditbank Debit (Bank)" }, { "3BFF1300FF918131FE4141434F53204769756C6961204C6336B5", "revolut debit visa (Bank)\nhttps://www.revolut.com/" }, { "3BFF1300FF918131FE4541434F53204449616E6132204C6336DF", "Alior Bank MasterCard debit (Bank)\nComdirect (Deutsch Bank) debit VISA (AUSTRIACARD 56015/001) (Bank)" }, { "3BFF1400FF8131FE458025A000000056575343363530010039", "SafeNet SC650 (PKI)\nhttp://www.safenet-inc.com/data-protection/authentication/smartcard-650/" }, @@ -4368,13 +4207,11 @@ const static atr_t AtrTable[] = { { "3BFF1800008131FE45006B0405010001210143494510318048", "hybrid card for various health services and regional services (access to various organizations and digital signatures)" }, { "3BFF1800008131FE45006B04050100012101434E5310318059", "CNS - Carta Nazionale dei Servizi (Italia)\nPA emittente: Regione Autonoma della Sardegna\nCarta del Servizio Sanitario Regionale - Emilia Romagna" }, { "3BFF1800008131FE45006B05051017012101434E531031805E", "Regional Card - Regione Liguria, Veneto - Italy (eID)\nTessera Sanitaria - Carta Regionale dei Servizi" }, - { "3BFF1800008131FE45006B050520000112024850431031804C", "CARTA SISS (HealthCare)" }, { "3BFF1800008131FE45006B05052000012101434E5310318079", "health card (HealthCare)\nhttps://tscns.regione.sardegna.it/" }, { "3BFF1800008131FE45006B0505200001F101434E53103180A9", "national health service card (HealthCare)\nhttps://ca.arubapec.it/downloads/MU_LINUX.zip" }, { "3BFF1800008131FE45006B0505912001F101434E5310318038", "Italian Health Card (TS) and Citizen's Card (CNS) based on IDEMIA ID-One CNS v2 on Cosmo 9.1 (HealthCare)" }, { "3BFF1800008131FE45006B11050700011101434E531131807B", "Italian National Fire Corps -special identification card (eID)" }, { "3BFF1800008131FE45006B11050700012101434E531031804A", "Oberthur ID-One Cosmo V7-n it's a java card 2.2.2\nIzenpe Certificado Ciudadano (eID)\nhttps://www.izenpe.eus/informacion/certificado-ciudadano/s15-content/es/" }, - { "3BFF1800008131FE45006B150C03020101014234441031800D", "bit4id (PKI)" }, { "3BFF1800008131FE45006B150C0302010101434E5310318061", "Bit4id Digital-DNA Key (eID)" }, { "3BFF1800008131FE4D8025A00000005657444B3430300600DD", "DataKey 400 (DK400)" }, { "3BFF1800008131FE55006B02090403010101434E5310318065", "Italian Chambers of Commerce CNS (PKI)\nhttp://www.card.infocamere.it/infocard/pub/" }, @@ -4402,19 +4239,13 @@ const static atr_t AtrTable[] = { { "3BFF1800FF8131FE4165630608710156000FB81026204712CD", "Fyrst Bank Card (Bank)\nhttps://fyrst.de" }, { "3BFF1800FF8131FE4165630608710156000FB85073204712D8", "Commerzbank maestro (Bank)\nhttps://www.commerzbank.de/konten-zahlungsverkehr/produkte/girokonten/kostenloses-girokonto/" }, { "3BFF1800FF8131FE4165630608710156000FB8602AA0471231", "Debit card (Germany): Postbank - GeldKarte (EUR), girocard, V-PAY (Bank)\nhttps://www.postbank.de/" }, - { "3BFF1800FF8131FE4165630608710156000FB8C040C047129B", "Maestro Bank card (aka. Giro card) of the Kreissparkasse (German bank) (Bank)" }, { "3BFF1800FF8131FE4165630608710156000FB8C0442147127E", "Commerzbank Classic Kreditkarte Mastercard (Bank)\nhttps://www.commerzbank.de/konten-zahlungsverkehr/produkte/kreditkarten/classic-kreditkarte/" }, { "3BFF1800FF8131FE4165630608710156000FB8D044A04712EF", "Debitcard (Bank)" }, - { "3BFF1800FF8131FE4165630608710156000FB8D09B604712F0", "Kreissparkasse Girocard (Germany) (Bank)" }, - { "3BFF1800FF8131FE4165630608710156000FB8F0BD204712B6", "Postbank Girocard Vpay Debit (Bank)\nhttps://postbank.de/privatkunden/services.html" }, { "3BFF1800FF8131FE41656306087102500023B80080C04712B2", "1822direct Bank Card (Bank)\nhttps://www.1822direkt.de" }, { "3BFF1800FF8131FE41656306087102500023B8907360471271", "Debit card (Germany): Deutsche Kreditbank (DKB), ec-cash, (Bank)\nhttps://www.dkb.de/privatkunden/karten/girocard" }, { "3BFF1800FF8131FE4165631116710156000F0308B09957115B", "Debit card Sparkasse (Germany) (Bank)" }, - { "3BFF1800FF8131FE4165631116710156000F030CD0435711E5", "Commerzbank AG (Bank)\nhttps://www.commerzbank.de/portal/de/privatkunden/produkte/bezahlen/kreditkarten" }, { "3BFF1800FF8131FE4165631116710156000F0902904E5711AC", "German Bank Card IDEMIA 9 Maestro/Girocard (Sparkasse S-Payment TPY 1974693D) (Bank)" }, { "3BFF1800FF8131FE4165631116710156000F0908309A5711D2", "Bank card from German Bank 'Sparkasse', issued by manufacturer 'S-Payment GmbH' (Bank)" }, - { "3BFF1800FF8131FE4165631116710156000F1606A09457115D", "GLS Bank MasterCard Debit (Bank)\nhttps://www.gls.de/konten-karten/karten/bankcard/" }, - { "3BFF1800FF8131FE4165631116710156000F1607F08D571115", "comdirect girocard (Bank)" }, { "3BFF1800FF8131FE4165631116710156000F16082024571163", "German Sparkasse with visa (Bank)\nhttps://www.sparkasse.de/lp/echtesmultitalent.html#alle-funktionen" }, { "3BFF1800FF8131FE450031C573C00180547615020105900074", "SIGILANCE NFC OpenPGP Smart Card (JavaCard)\nhttps://www.sigilance.com/" }, { "3BFF1800FF8131FE455448434331305445434F4744484E3224", "National Health Insurance Card, Taiwan" }, @@ -4454,7 +4285,6 @@ const static atr_t AtrTable[] = { { "3BFF1800FF8131FE4565631108660280001156000318062092", "Geldkarte [ec, Maestro] (Sparkasse Langen-Seligenstadt, Germany)" }, { "3BFF1800FF8131FE4565631901500280000F........0512..", "SAGEM ORGA GmbH\nROM Mask=SecV1.5.3\nInit-Table=SDR0O1G0.A_B (BES0), SWR0O1H0.A_5 (CS0)\nSignaturerstellungseinheit ZKA SECCOS Sig v1.5.3\nBSI.02076.TE.12.2006" }, { "3BFF1800FF8131FE4565631A01410250001052090567051021", "Maestro/Geldkarte (BBBank Karlsruhe, Germany)" }, - { "3BFF1800FF8131FE4D006B0404B85B01F101434E531031809D", "Italian CNS (HealthCare)" }, { "3BFF1800FF8131FE55006B02090200010101434E531031809F", "Carta Nazionale dei Servizi - InfoCamere" }, { "3BFF1800FF8131FE55006B0209020001010144534410318092", "Postcom S.P.A. (digital certificate)" }, { "3BFF1800FF8131FE55006B02090200011101434E531031808F", "Carta Regionale dei Servizi - Regione Lombardia" }, @@ -4469,7 +4299,7 @@ const static atr_t AtrTable[] = { { "3BFF1800FF8131FE55006B0209130301000150534510318094", "Italian Electronic ID Card (eID)\nhttp://www.interno.gov.it/mininterno/site/it/temi/servizi_demografici/scheda_006.html" }, { "3BFF1800FF8131FE55006B02091303010101434E531031808D", "Aruba Digital Signature (Other)\nhttps://www.pec.it/offerta-firma-digitale.aspx" }, { "3BFF1800FF8131FE55006B02091303011101434E531131809C", "Politecnico di Torino Student Card (eID)\nhttp://www.polito.it/" }, - { "3BFF1800FF8131FE55006B02091617011101434E531131808D", "Tessera Sanitaria - Carta Nazionale dei Servizi (TS-CNS)\nItalian Health Insurance Card (healthcare)" }, + { "3BFF1800FF8131FE55006B02091617011101434E531131808D", "Carta Regionale dei Servizi - Regione Autonoma Friuli Venezia Giulia (HealthCare)\nhttps://www.regione.fvg.it/rafvg/cms/RAFVG/GEN/carta-regionale-servizi/" }, { "3BFF1800FF8131FE55006B02091717011101434E531131808C", "european health insurance card and Regional (ItalY - Provincia Autonoma di Trento) Service Card (CPS) (eID)\nhttps://www.provincia.tn.it/Servizi/Attivare-la-Carta-Provinciale-dei-Servizi-CPS#cos_e" }, { "3BFF1800FF8131FE55006B42495434494420312E3000900091", "Touch&Sign 2048 (PKI)" }, { "3BFF1800FF8131FE55006B42495434494420322E3000900092", "Izenpe Green Card (Citizen Certificate) (eID)\nhttp://www.izenpe.com/s15-12020/en/contenidos/informacion/ciudadano/en_def/index.shtml" }, @@ -4536,22 +4366,15 @@ const static atr_t AtrTable[] = { { "3BFF9600008131FE4380318065B085040120120FFF829000D0", "Portuguese National Identity Card (eID) (eID)\nhttps://www.autenticacao.gov.pt/o-cartao-de-cidadao" }, { "3BFF9600008131FE4380318065B085050011120FFF829000E1", "Portuguese autentication card (eID)\nhttps://www.autenticacao.gov.pt/web/guest/cc-aplicacao" }, { "3BFF9600008131FE4380318065B08505003912017882900040", "Identicard for french advocates (eID)\nhttps://doc.ubuntu-fr.org/avocats_sur_ubuntu" }, - { "3BFF9600008131FE4380318065B085050039120FFE829000C8", "SafeNet IDPrime 3940C (PKI)\nhttps://cpl.thalesgroup.com/resources/access-management/safenet-idprime-940c-3940c-smart-cards-product-brief" }, { "3BFF9600008131FE4380318065B0855956FB12017882900088", "SafeNet 5110 token for eSignature (eID)\nhttps://www.certsign.ro/en/support/safenet-installing-the-device-on-windows/" }, { "3BFF9600008131FE4380318065B0855956FB120FFC82900002", "THALES SafeNet IDPrime 3940 Fido (PKI)\nhttps://cpl.thalesgroup.com/fr/resources/access-management/idprime-3940-product-brief" }, { "3BFF9600008131FE4380318065B0855956FB120FFE82900000", "SafeNet eToken 5110 SC (PKI)\nhttps://cpl.thalesgroup.com/access-management/authenticators/pki-usb-authentication/etoken-5110-usb-token" }, { "3BFF9600008131FE4580F9A0000003080000100053454E54AC", "cac (eID)" }, { "3BFF9600008131FE55006B02090403010101434E53103180EB", "Aruba PEC SpA digital signature card made by Incard (eID)\nhttps://www.pec.it/download-software-driver.aspx" }, { "3BFF960000C00A31FE4380318065B085040011120FFF829000AB", "French National Identity Card (eID) (eID)\nhttps://www.interieur.gouv.fr/actualites/actu-du-ministere/nouvelle-carte-nationale-didentite" }, - { "3BFF9600FF8131FE406563111562025000100A0169C9073026", "Kreissparkasse Mastercard (Germany) (Bank)" }, { "3BFF9600FF8131FE406563111562025000100A0190A90730BF", "girocard Sparkasse Ansbach, Germany BLZ 76550000 (Bank)" }, - { "3BFF9600FF8131FE406563111562025000100A01BF860730BF", "German Bank Verbundvolksbank-OWL Bank" }, { "3BFF9600FF8131FE406563111562025000100A0271500730A4", "Debitcard Sparkasse Duesseldorf (Bank) (Bank)\nhttps://www.sskduesseldorf.de/" }, { "3BFF9600FF8131FE406563111665025000100B22BBEB074080", "girocard contactless (Bank)" }, - { "3BFF9600FF8131FE406563111665025000100B238131074061", "Debit card (Germany): girocard, V-Pay (Bank)" }, - { "3BFF9600FF8131FE406563111665025000100B23B7B20740D4", "Hannoversche Volksbank girocard / Visa Debit Card (Bank)\nhttps://www.hannoversche-volksbank.de/privatkunden/girokonto-kreditkarten/girocards/hannover-girocard.html" }, - { "3BFF9600FF8131FE406563111665025000100B246D780740C3", "Mastercard Debit Card from the Kreissparkasse (German bank) (Bank)" }, - { "3BFF9600FF8131FE4065631D02840156001F1007C0BC020024", "sparda-bank (Bank)" }, { "3BFF9600FF8131FE4065631D02840156001F190850E10200EF", "Raiffeiesenbank Girocard Maestro (Bank)" }, { "3BFF9600FF8131FE4065631D02840156001F2108B0A902007F", "Debit Card Sparda-Bank Baden-Wurttemberg eG (Bank)" }, { "3BFF9600FF8131FE4065631D028401560024090A10CC0200AB", "Postbank Germany (Bank)\nhttps://www.postbank.de/privatkunden/services.html" }, @@ -4565,9 +4388,6 @@ const static atr_t AtrTable[] = { { "3BFF9600FF8131FE4065631D0284025000232106F0ED02004C", "DKB Girocard (Bank)" }, { "3BFF9600FF8131FE4065631D028402500023230900A80200F4", "Kreissparkasse girocard (Bank)" }, { "3BFF9600FF8131FE4065631D038601560002130B90FE011034", "EC card from Raiffeisenbank im Hochtaunus, Germany (Bank)" }, - { "3BFF9600FF8131FE4065631D03860156000220093138011062", "GLS Bank MasterCard (Bank)\nhttps://www.gls.de/konten-karten/karten/kreditkarte/" }, - { "3BFF9600FF8131FE4065631D038601560002210B612401102D", "Girocard (Bank)\nhttps://www.muenchner-bank.de" }, - { "3BFF9600FF8131FE4065631D038602500023020B20DD011092", "DKB Visa (Debit) (Bank)\nhttps://www.dkb.de/" }, { "3BFF9600FF8131FE4065631D0386025000230808914F0110B8", "Debit card (Germany): ec-cash, GeldKarte(EUR), Visa, Cirrus (Bank)" }, { "3BFF9600FF8131FE4065631D038602500023130981390110C4", "girocard contactless (Bank)" }, { "3BFF9600FF8131FE456563060752025000103025411A064082", "DKB (Deutsche Kreditbank) girocard (V-PAY, GeldKarte) (Bank)\nhttps://www.dkb.de/privatkunden/karten/girocard" }, @@ -4599,7 +4419,6 @@ const static atr_t AtrTable[] = { { "3F2F008069AF03070352000D0A0E833E9F16", "GSM-SIM Debitel D2 (900MHz)" }, { "3F2F008069AF0307035A00150A0E833E9F16", "Virgin Mobile SIM (Gemplus)" }, { "3F36110053495B015153", "Sodexo Pass Lunch Card. An employee benefits card to provide meal tickets to workers. (Other)\nhttps://www.sodexo-benefits.it/prodotto/aziende/pausa-pranzo-aziende/pass-lunch-card/#tabsoluzioni" }, - { "3F3B11004B494154325F5253079000", "singe-use Smart Card from Indesit/Whirlpool containing dishwasher EEPROM data (spare part no C00277010, containing the file 28655190905.eep) (Other)\nhttps://fixpart.co.uk/product/whirlpool-indesit-c00277010-programming-card" }, { "3F3BF81300008131FE454A434F5076", "District6 Group employee ID (eID)" }, { "3F3D1100806728500402200000838E9000", "GSM SIM card of the Austrian provider A1" }, { "3F3E110046524543434941524F5353419000", "Trenitalia (Italy) fidelity card 'CartaFreccia' (Smartcard)" }, @@ -4680,7 +4499,6 @@ const static atr_t AtrTable[] = { { "3F7F13250240B01269FF4A509054560000000000", "NDS Smartcard (Pay TV)" }, { "3F7F13250241B004FFFF4A508080000000475806", "NDS card DIRECTV (Other)" }, { "3F7F13250241B00EFFFF4A508080000000474C07", "SKY BRASIL (Pay TV)" }, - { "3F7F13250241B00EFFFF4A508080000000485507", "DirecTV Access Card (as of 2016) (Pay TV)" }, { "3F7F13250333B00669FF4A50D000005359000000", "Sky 2005/6 (DSS satellite TV card)" }, { "3F7F13250333B01169FF4A505000004956010000", "Indonesia Videoguard 2 card" }, { "3F7F13250333B01169FF4A505000005344010000", "STAR TV (Pay TV)" }, @@ -4736,7 +4554,6 @@ const static atr_t AtrTable[] = { { "3FFF142503108041B00769FF4A5070800058440100FF", "Provider Vivacom Bulgaria NDS (Pay TV)\nhttp://www.vivacom.bg/en/satellite-services" }, { "3FFF142503108041B00769FF4A507080005845010014", "Sat TV (Other)" }, { "3FFF142503108054B00169FF4A507000004B57010000", "PayTV Card Kabel BW (www.kabelbw.de), Encryption: NDS by Videoguard, Distribution Standard: DVB-C" }, - { "3FFF152503108041B00769FF4A507000005031010011", "V13 or V14 (NDS) (Pay TV)" }, { "3FFF152503108041B00769FF4A507000005031010015", "Sky (Germany) VideoGuard CAM card (www.sky.de) in Fast Mode (ins7e11=15) (Pay TV)" }, { "3FFF3F3F3F3F003F3FFF3F3F3F3F3FFF3FFF953FFF953FFF", "Premium joker card to see Spanish TDT premium (goltv)" }, { "3FFF9500FF918171..4700..4.4.....3.3.3.20..657.........", "Nagravision TV CAM card\nhttp://en.wikipedia.org/wiki/Nagravision" }, @@ -4772,7 +4589,6 @@ const static atr_t AtrTable[] = { { "3FFF9500FF918171FE5700444E4153503431302052657651323715", "New Digi Slovakia (Pay TV)\nhttps://www.lyngsat.com/packages/Digi.html" }, { "3FFF9500FF918171FE5700444E4153503431302052657651324260", "Nagravision Kudelski Generation 7 card Rom410 MerQ2B (Pay TV)" }, { "3FFF9500FF918171FE5700444E4153503431302052657651325371", "Slovak and Czech pay TV provider Slovak Telecom (Pay TV)\nhttp://www.flysat.com/novadigi-sk.php" }, - { "3FFF9500FF918171FE5700444E4153503432302052657653323615", "bank comercial do huambo (Bank)" }, { "3FFF9500FF918171FE5700444E4153503432302052657653363017", "HD+ HD04b Card (Pay TV)" }, { "3FFF9500FF918171FE5700444E4153503432302052657653363413", "claro card honduras central america 'NAGRA' (Pay TV)" }, { "3FFF9500FF918171FE5700444E4153503432302052657653364166", "NAGRA KUDELSKI (Pay TV)" }, diff --git a/client/src/cmddata.c b/client/src/cmddata.c index df05e9084..a8e285b7f 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -3527,8 +3527,8 @@ static int CmdAtrLookup(const char *Cmd) { static int CmdCryptography(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "data crypto", - "This command lets you encrypt or decrypt data using DES/3DES/AES.\n" - "Supply data, key, IV (needed for des MAC or aes), and cryptography action.\n", + "Encrypt data, right here, right now. Or decrypt.", + "Supply data, key, IV (needed for des MAC or aes), and cryptography action.\n" "To calculate a MAC for FMCOS, supply challenge as IV, data as data, and session/line protection key as key.\n" "To calculate a MAC for FeliCa, supply first RC as IV, BLE+data as data and session key as key.\n" "data crypto -d 04D6850E06AABB80 -k FFFFFFFFFFFFFFFF --iv 9EA0401A00000000 --des -> Calculate a MAC for FMCOS chip. The result should be ED3A0133\n" @@ -3544,97 +3544,76 @@ static int CmdCryptography(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t dati[250] = {0}; uint8_t dato[250] = {0}; int datilen = 0; CLIGetHexWithReturn(ctx, 1, dati, &datilen); - - uint8_t key[33] = {0}; + uint8_t key[25] = {0}; int keylen = 0; CLIGetHexWithReturn(ctx, 2, key, &keylen); - - uint8_t type = 0; - if (arg_get_lit(ctx, 3)) { - type ^= 0x08; - } - - if (arg_get_lit(ctx, 4)) { - type ^= 0x04; - } - - if (arg_get_lit(ctx, 5)) { - type ^= 0x02; - } - + int type = 0; + if (arg_get_lit(ctx, 3)) type ^= 8; + if (arg_get_lit(ctx, 4)) type ^= 4; + if (arg_get_lit(ctx, 5)) type ^= 2; uint8_t iv[250] = {0}; int ivlen = 0; CLIGetHexWithReturn(ctx, 6, iv, &ivlen); CLIParserFree(ctx); // Do data length check - if ((type & 0x04) == 0x04) { // Use AES(0) or DES(1)? + if ((type & 0x4) >> 2) { // Use AES(0) or DES(1)? if (datilen % 8 != 0) { PrintAndLogEx(ERR, " length must be a multiple of 8. Got %d", datilen); return PM3_EINVARG; } - if (keylen != 8 && keylen != 16 && keylen != 24 && keylen != 32) { - PrintAndLogEx(ERR, " must be 8, 16, 24, 32 bytes. Got %d", keylen); + if (keylen != 8 && keylen != 16 && keylen != 24) { + PrintAndLogEx(ERR, " must be 8, 16 or 24 bytes. Got %d", keylen); return PM3_EINVARG; } } else { - if (datilen % 16 != 0 && ((type & 0x02) == 0)) { + if (datilen % 16 != 0 && ((type & 0x2) >> 1 == 0)) { PrintAndLogEx(ERR, " length must be a multiple of 16. Got %d", datilen); return PM3_EINVARG; } - if (keylen != 16 && keylen != 32) { - PrintAndLogEx(ERR, " must be 16 or 32 bytes. Got %d", keylen); + if (keylen != 16) { + PrintAndLogEx(ERR, " must be 16 bytes. Got %d", keylen); return PM3_EINVARG; } } // Encrypt(0) or decrypt(1)? - if ((type & 0x08) == 0x08) { + if ((type & 0x8) >> 3) { - if ((type & 0x04) == 0x04) { // AES or DES? + if ((type & 0x4) >> 2) { // AES or DES? if (keylen > 8) { + PrintAndLogEx(INFO, "Called 3DES decrypt"); des3_decrypt(dato, dati, key, keylen / 8); - PrintAndLogEx(INFO, "3DES decrypt... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); } else { - + PrintAndLogEx(INFO, "Called DES decrypt"); if (ivlen == 0) { // If there's an IV, use CBC des_decrypt_ecb(dato, dati, datilen, key); - PrintAndLogEx(INFO, "DES ECB decrypt... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); } else { des_decrypt_cbc(dato, dati, datilen, key, iv); - PrintAndLogEx(INFO, "DES CBC decrypt... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); } } - } else { - if (keylen == 32) { - aes256_decode(iv, key, dati, dato, datilen); - PrintAndLogEx(INFO, "AES-256 decrypt... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); - } else { - aes_decode(iv, key, dati, dato, datilen); - PrintAndLogEx(INFO, "AES-128 decrypt... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); - } + PrintAndLogEx(INFO, "Called AES decrypt"); + aes_decode(iv, key, dati, dato, datilen); } } else { - - if ((type & 0x04) == 0x04) { // AES or DES? - if ((type & 0x02) == 0x02) { // If we will calculate a MAC + if (type & 0x4) { // AES or DES? + if (type & 0x02) { // If we will calculate a MAC /*PrintAndLogEx(INFO, "Called FeliCa MAC"); // For DES all I know useful is the felica and fudan MAC algorithm.This is just des-cbc, but felica needs it in its way. for (int i = 0; i < datilen; i+=8){ // For all 8 byte sequences @@ -3658,42 +3637,37 @@ static int CmdCryptography(const char *Cmd) { } else { if (keylen > 8) { + PrintAndLogEx(INFO, "Called 3DES encrypt keysize: %i", keylen / 8); des3_encrypt(dato, dati, key, keylen / 8); - PrintAndLogEx(INFO, "3DES encrypt keysize ( %d )... " _YELLOW_("%s"), (keylen / 8), sprint_hex_inrow(dato, datilen)); } else { + PrintAndLogEx(INFO, "Called DES encrypt"); + if (ivlen == 0) { // If there's an IV, use ECB des_encrypt_ecb(dato, dati, datilen, key); - PrintAndLogEx(INFO, "DES ECB encrypt... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); } else { des_encrypt_cbc(dato, dati, datilen, key, iv); char pad[250]; memset(pad, ' ', 4 + 8 + (datilen - 8) * 3); pad[8 + (datilen - 8) * 3] = 0; // Make a padding to insert FMCOS macing algorithm guide PrintAndLogEx(INFO, "%sVV VV VV VV FMCOS MAC", pad); - PrintAndLogEx(INFO, "DES CBC encrypt... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); } } } } else { - if ((type & 0x02) == 0x02) { + if (type & 0x02) { + PrintAndLogEx(INFO, "Called AES CMAC"); // If we will calculate a MAC aes_cmac8(iv, key, dati, dato, datilen); - PrintAndLogEx(INFO, "AES CMAC... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); } else { - if (keylen == 32) { - aes256_encode(iv, key, dati, dato, datilen); - PrintAndLogEx(INFO, "AES-256 encrypt... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); - } else { - aes_encode(iv, key, dati, dato, datilen); - PrintAndLogEx(INFO, "AES-128 encrypt... " _YELLOW_("%s"), sprint_hex_inrow(dato, datilen)); - } + PrintAndLogEx(INFO, "Called AES encrypt"); + aes_encode(iv, key, dati, dato, datilen); } } } - + PrintAndLogEx(SUCCESS, "Result: %s", sprint_hex(dato, datilen)); return PM3_SUCCESS; } diff --git a/client/src/cmddata.h b/client/src/cmddata.h index 5f70516ff..5b19b0f4e 100644 --- a/client/src/cmddata.h +++ b/client/src/cmddata.h @@ -67,6 +67,7 @@ int CmdLtrim(const char *Cmd); int CmdNorm(const char *Cmd); // used by cmd lf data (!) int CmdPlot(const char *Cmd); // used by cmd lf cotag int CmdSave(const char *Cmd); // used by cmd auto +int CmdTuneSamples(const char *Cmd); // used by cmd lf hw int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose); // used by cmd lf em4x, lf fdxb, lf guard, lf jablotron, lf nedap, lf t55xx int ASKDemod(int clk, int invert, int maxErr, size_t maxlen, bool amplify, bool verbose, bool emSearch, uint8_t askType); // used by cmd lf em4x, lf t55xx, lf viking diff --git a/client/src/cmdflashmem.c b/client/src/cmdflashmem.c index 607a36b31..fa88549f7 100644 --- a/client/src/cmdflashmem.c +++ b/client/src/cmdflashmem.c @@ -192,24 +192,21 @@ static int CmdFlashMemLoad(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "mem load", "Loads binary file into flash memory on device\n" - "Warning! - mem area to be written must have been wiped first\n\n" - "OBS! - dictionaries are serviced as files in spiffs so no wipe is needed", - "mem load -f myfile -> upload file myfile values at default offset 0\n" - "mem load -f myfile -o 1024 -> upload file myfile values at offset 1024\n" - "mem load -f mfc_default_keys -m -> upload MIFARE Classic keys\n" - "mem load -f t55xx_default_pwds -t -> upload T55XX passwords\n" - "mem load -f iclass_default_keys -i -> upload iCLASS keys\n" - "mem load -f mfulc_default_keys --ulc -> upload MIFARE UL-C keys\n" + "Warning: mem area to be written must have been wiped first\n" + "( dictionaries are serviced as files in spiffs so no wipe is needed )", + "mem load -f myfile -> upload file myfile values at default offset 0\n" + "mem load -f myfile -o 1024 -> upload file myfile values at offset 1024\n" + "mem load -f mfc_default_keys -m -> upload MFC keys\n" + "mem load -f t55xx_default_pwds -t -> upload T55XX passwords\n" + "mem load -f iclass_default_keys -i -> upload iCLASS keys\n" ); void *argtable[] = { arg_param_begin, arg_int0("o", "offset", "", "offset in memory"), - arg_lit0("m", "mfc", "upload 6 bytes keys (MIFARE Classic dictionary)"), - arg_lit0("i", "iclass", "upload 8 bytes keys (iClass dictionary)"), - arg_lit0("t", "t55xx", "upload 4 bytes keys (T55xx dictionary)"), - arg_lit0(NULL, "ulc", "upload 16 bytes keys (MIFARE UL-C dictionary)"), - arg_lit0(NULL, "aes", "upload 16 bytes keys (MIFARE UL-AES dictionary)"), + arg_lit0("m", "mifare,mfc", "upload 6 bytes keys (mifare key dictionary)"), + arg_lit0("i", "iclass", "upload 8 bytes keys (iClass key dictionary)"), + arg_lit0("t", "t55xx", "upload 4 bytes keys (password dictionary)"), arg_str1("f", "file", "", "file name"), arg_param_end }; @@ -219,35 +216,28 @@ static int CmdFlashMemLoad(const char *Cmd) { bool is_mfc = arg_get_lit(ctx, 2); bool is_iclass = arg_get_lit(ctx, 3); bool is_t55xx = arg_get_lit(ctx, 4); - bool is_ulc = arg_get_lit(ctx, 5); - bool is_ulaes = arg_get_lit(ctx, 6); int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + char spiffsDest[32] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); Dictionary_t d = DICTIONARY_NONE; if (is_mfc) { d = DICTIONARY_MIFARE; - PrintAndLogEx(INFO, "Treating file as MIFARE Classic keys"); + PrintAndLogEx(INFO, "treating file as MIFARE Classic keys"); } else if (is_iclass) { d = DICTIONARY_ICLASS; - PrintAndLogEx(INFO, "Treating file as iCLASS keys"); + PrintAndLogEx(INFO, "treating file as iCLASS keys"); } else if (is_t55xx) { d = DICTIONARY_T55XX; - PrintAndLogEx(INFO, "Treating file as T55xx passwords"); - } else if (is_ulc) { - d = DICTIONARY_MIFARE_ULC; - PrintAndLogEx(INFO, "Treating file as MIFARE Ultralight-C keys"); - } else if (is_ulaes) { - d = DICTIONARY_MIFARE_ULAES; - PrintAndLogEx(INFO, "Treating file as MIFARE Ultralight AES keys"); + PrintAndLogEx(INFO, "treating file as T55xx passwords"); } uint8_t spi_flash_pages = 0; int res = rdv4_get_flash_pages64k(&spi_flash_pages); if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Failed to get flash pages count (%x)", res); + PrintAndLogEx(ERR, "failed to get flash pages count (%x)", res); return res; } @@ -256,8 +246,6 @@ static int CmdFlashMemLoad(const char *Cmd) { uint8_t keylen = 0; uint8_t *data = calloc(FLASH_MEM_MAX_SIZE_P(spi_flash_pages), sizeof(uint8_t)); - char spiffsDest[32] = {0}; - switch (d) { case DICTIONARY_MIFARE: { keylen = MF_KEY_LENGTH; @@ -304,36 +292,6 @@ static int CmdFlashMemLoad(const char *Cmd) { strcpy(spiffsDest, ICLASS_KEYS_FILE); break; } - case DICTIONARY_MIFARE_ULC: { - keylen = MFULC_KEY_LENGTH; - res = loadFileDICTIONARY(filename, data, &datalen, keylen, &keycount); - if (res || !keycount) { - free(data); - return PM3_EFILE; - } - if (datalen > FLASH_MEM_MAX_SIZE_P(spi_flash_pages)) { - PrintAndLogEx(ERR, "error, filesize is larger than available memory"); - free(data); - return PM3_EOVFLOW; - } - strcpy(spiffsDest, MFULC_KEYS_FILE); - break; - } - case DICTIONARY_MIFARE_ULAES: { - keylen = MFULAES_KEY_LENGTH; - res = loadFileDICTIONARY(filename, data, &datalen, keylen, &keycount); - if (res || !keycount) { - free(data); - return PM3_EFILE; - } - if (datalen > FLASH_MEM_MAX_SIZE_P(spi_flash_pages)) { - PrintAndLogEx(ERR, "error, filesize is larger than available memory"); - free(data); - return PM3_EOVFLOW; - } - strcpy(spiffsDest, MFULAES_KEYS_FILE); - break; - } case DICTIONARY_NONE: { res = loadFile_safe(filename, ".bin", (void **)&data, &datalen); if (res != PM3_SUCCESS) { @@ -372,12 +330,7 @@ static int CmdFlashMemLoad(const char *Cmd) { free(data); return res; } - - if (d == DICTIONARY_T55XX) { - PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%u")" passwords to file "_GREEN_("%s"), keycount, spiffsDest); - } else { - PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%u")" keys to file "_GREEN_("%s"), keycount, spiffsDest); - } + PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%u")" passwords to file "_GREEN_("%s"), keycount, spiffsDest); SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0); SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0); } else { @@ -776,7 +729,6 @@ static int CmdFlashMemInfo(const char *Cmd) { static command_t CommandTable[] = { {"spiffs", CmdFlashMemSpiFFS, IfPm3Flash, "{ SPI File system }"}, {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"-----------", CmdHelp, IfPm3Flash, "------------------- " _CYAN_("Operations") " -------------------"}, {"baudrate", CmdFlashmemSpiBaud, IfPm3Flash, "Set Flash memory Spi baudrate"}, {"dump", CmdFlashMemDump, IfPm3Flash, "Dump data from flash memory"}, {"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information"}, diff --git a/client/src/cmdflashmem.h b/client/src/cmdflashmem.h index f47547166..ad8727204 100644 --- a/client/src/cmdflashmem.h +++ b/client/src/cmdflashmem.h @@ -26,9 +26,7 @@ typedef enum { DICTIONARY_NONE = 0, DICTIONARY_MIFARE, DICTIONARY_T55XX, - DICTIONARY_ICLASS, - DICTIONARY_MIFARE_ULC, - DICTIONARY_MIFARE_ULAES, + DICTIONARY_ICLASS } Dictionary_t; int CmdFlashMem(const char *Cmd); diff --git a/client/src/cmdflashmemspiffs.c b/client/src/cmdflashmemspiffs.c index e2d5417ff..8149236af 100644 --- a/client/src/cmdflashmemspiffs.c +++ b/client/src/cmdflashmemspiffs.c @@ -576,11 +576,10 @@ static int CmdFlashMemSpiFFSView(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"-----------", CmdHelp, IfPm3Flash, "------------------- " _CYAN_("Operations") " -------------------"}, {"copy", CmdFlashMemSpiFFSCopy, IfPm3Flash, "Copy a file to another (destructively) in SPIFFS file system"}, {"check", CmdFlashMemSpiFFSCheck, IfPm3Flash, "Check/try to defrag faulty/fragmented file system"}, {"dump", CmdFlashMemSpiFFSDump, IfPm3Flash, "Dump a file from SPIFFS file system"}, - {"info", CmdFlashMemSpiFFSInfo, IfPm3Flash, "File system information and usage statistics"}, + {"info", CmdFlashMemSpiFFSInfo, IfPm3Flash, "Print file system info and usage statistics"}, {"mount", CmdFlashMemSpiFFSMount, IfPm3Flash, "Mount the SPIFFS file system if not already mounted"}, {"remove", CmdFlashMemSpiFFSRemove, IfPm3Flash, "Remove a file from SPIFFS file system"}, {"rename", CmdFlashMemSpiFFSRename, IfPm3Flash, "Rename/move a file in SPIFFS file system"}, diff --git a/client/src/cmdhf.c b/client/src/cmdhf.c index 13c10d863..ea0c47993 100644 --- a/client/src/cmdhf.c +++ b/client/src/cmdhf.c @@ -231,60 +231,60 @@ int CmdHFSearch(const char *Cmd) { } */ - DropField(); - PROMPT_CLEARLINE; if (res != PM3_SUCCESS) { PrintAndLogEx(WARNING, _RED_("No known/supported 13.56 MHz tags found")); - return res; - } - - // no need to print 14A hints, since it will print itself - - if (success[THINFILM]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf thinfilm") "` commands\n"); - } - - if (success[LTO]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf lto") "` commands\n"); - } - - if (success[LEGIC]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf legic") "` commands\n"); - } - - if (success[TOPAZ]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf topaz") "` commands\n"); - } - - if (success[PROTO_TEXKOM]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf texkom") "` commands\n"); - } - - if (success[PROTO_XEROX]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf xerox") "` commands\n"); - } - - if (success[ISO_14443B]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf 14b") "` commands\n"); - } - - if (success[ISO_15693]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf 15") "` commands\n"); - } - - if (success[ICLASS]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf iclass") "` commands\n"); - } - - if (success[FELICA]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf felica") "` commands\n"); - } - - if (success[PROTO_CRYPTORF]) { - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf cryptorf") "` commands\n"); + res = PM3_ESOFT; + } else { + + // no need to print 14A hints, since it will print itself + + if (success[THINFILM]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf thinfilm") "` commands\n"); + } + + if (success[LTO]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf lto") "` commands\n"); + } + + if (success[LEGIC]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf legic") "` commands\n"); + } + + if (success[TOPAZ]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf topaz") "` commands\n"); + } + + if (success[PROTO_TEXKOM]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf texkom") "` commands\n"); + } + + if (success[PROTO_XEROX]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf xerox") "` commands\n"); + } + + if (success[ISO_14443B]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf 14b") "` commands\n"); + } + + if (success[ISO_15693]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf 15") "` commands\n"); + } + + if (success[ICLASS]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf iclass") "` commands\n"); + } + + if (success[FELICA]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf felica") "` commands\n"); + } + + if (success[PROTO_CRYPTORF]) { + PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf cryptorf") "` commands\n"); + } } + DropField(); return res; } @@ -477,7 +477,7 @@ int CmdHFSniff(const char *Cmd) { if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(WARNING, "\naborted via keyboard!"); + PrintAndLogEx(INFO, "User aborted"); break; } @@ -600,7 +600,7 @@ static command_t CommandTable[] = { {"texkom", CmdHFTexkom, AlwaysAvailable, "{ Texkom RFIDs... }"}, {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"}, {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, - {"vas", CmdHFVAS, AlwaysAvailable, "{ Apple Value Added Service... }"}, + {"vas", CmdHFVAS, AlwaysAvailable, "{ Apple Value Added Service }"}, #ifdef HAVE_GD {"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"}, #endif diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 42bee9388..3174cc47e 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -43,8 +43,6 @@ #include "mifare/desfirecore.h" // desfire context #include "mifare/mifaredefault.h" #include "preferences.h" // get/set device debug level -#include "pm3_cmd.h" - static bool g_apdu_in_framing_enable = true; bool Get_apdu_in_framing(void) { @@ -58,6 +56,34 @@ static int CmdHelp(const char *Cmd); static int waitCmd(bool i_select, uint32_t timeout, bool verbose); +static const iso14a_polling_frame_t WUPA_FRAME = { + { 0x52 }, 1, 7, 0, +}; + +static const iso14a_polling_frame_t MAGWUPA1_FRAME = { + { 0x7A }, 1, 7, 0 +}; + +static const iso14a_polling_frame_t MAGWUPA2_FRAME = { + { 0x7B }, 1, 7, 0 +}; + +static const iso14a_polling_frame_t MAGWUPA3_FRAME = { + { 0x7C }, 1, 7, 0 +}; + +static const iso14a_polling_frame_t MAGWUPA4_FRAME = { + { 0x7D }, 1, 7, 0 +}; + +static const iso14a_polling_frame_t ECP_FRAME = { + .frame = { 0x6a, 0x02, 0xC8, 0x01, 0x00, 0x03, 0x00, 0x02, 0x79, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xD8}, + .frame_length = 15, + .last_byte_bits = 8, + .extra_delay = 0 +}; + + // based on ISO/IEC JTC1/SC17 STANDING DOCUMENT 5 (Updated 20 September 2024) Register of IC manufacturers static const manufactureName_t manufactureMapping[] = { // ID, "Vendor Country" @@ -246,54 +272,11 @@ static uint16_t gs_frame_len = 0; static uint8_t gs_frames_num = 0; static uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256}; -int hf14a_getversion_data(iso14a_card_select_t *card, uint64_t select_status, version_hw_t *hw) { - - // field on, card selected if select_status is 1 or 4, not selected if 2 - int res = PM3_EFAILED; - - // if 4b UID or NXP, try to get version - if ((card->uidlen == 4) || ((card->uidlen == 7) && (card->uid[0] == 0x04))) { - // GetVersion - if ((select_status == 1) || (select_status == 4)) { // L4 - - uint8_t response[PM3_CMD_DATA_SIZE] = {0}; - int resp_len = 0; - uint8_t getVersion[5] = {0x90, 0x60, 0x00, 0x00, 0x00}; - res = ExchangeAPDU14a(getVersion, sizeof(getVersion), false, false, response, sizeof(response), &resp_len); - DropField(); - - if (res == PM3_ETIMEOUT) { - PrintAndLogEx(DEBUG, "iso14443a card select timeout"); - return PM3_ETIMEOUT; - } - - if (resp_len == 9) { - memcpy(hw, response, sizeof(version_hw_t)); - return PM3_SUCCESS; - } - return PM3_EFAILED; - - } - - // select_status = 2, L3 - uint8_t version[8] = {0}; - uint8_t uid[7] = {0}; - res = mfu_get_version_uid(version, uid); - DropField(); - if (res == PM3_SUCCESS) { - memcpy(hw, version + 1, sizeof(version_hw_t)); - } - } - - DropField(); - return res; -} - static int CmdHF14AList(const char *Cmd) { return CmdTraceListAlias(Cmd, "hf 14a", "14a -c"); } -int hf14a_getconfig(hf14a_config_t *config) { +int hf14a_getconfig(hf14a_config *config) { if (!g_session.pm3_present) return PM3_ENOTTY; if (config == NULL) { @@ -308,16 +291,16 @@ int hf14a_getconfig(hf14a_config_t *config) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } - memcpy(config, resp.data.asBytes, sizeof(hf14a_config_t)); + memcpy(config, resp.data.asBytes, sizeof(hf14a_config)); return PM3_SUCCESS; } -int hf14a_setconfig(hf14a_config_t *config, bool verbose) { +int hf14a_setconfig(hf14a_config *config, bool verbose) { if (!g_session.pm3_present) return PM3_ENOTTY; clearCommandBuffer(); if (config != NULL) { - SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)config, sizeof(hf14a_config_t)); + SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)config, sizeof(hf14a_config)); if (verbose) { SendCommandNG(CMD_HF_ISO14443A_PRINT_CONFIG, NULL, 0); } @@ -350,15 +333,6 @@ static int hf_14a_config_example(void) { PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --atqa force --bcc ignore --cl2 force --cl3 skip -rats skip")); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setuid --uid 04112233445566")); PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --std")); - - PrintAndLogEx(NORMAL, "\nExamples of polling loop annotations used to enable anticollision on mobile targets:"); - PrintAndLogEx(NORMAL, _CYAN_(" ECP Express Transit EMV")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --pla 6a02c801000300027900000000")); - PrintAndLogEx(NORMAL, _CYAN_(" ECP VAS Only")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --pla 6a01000002")); - PrintAndLogEx(NORMAL, _CYAN_(" ECP Access Wildcard")":"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config --pla 6a02c3020002ffff")); - return PM3_SUCCESS; } static int CmdHf14AConfig(const char *Cmd) { @@ -367,28 +341,25 @@ static int CmdHf14AConfig(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a config", "Configure 14a settings (use with caution)\n" - " `-v` also prints examples for reviving Gen2 cards & configuring polling loop annotations", - "hf 14a config -> Print current configuration\n" - "hf 14a config --std -> Reset default configuration (follow standard)\n" - "hf 14a config --atqa std -> Follow standard\n" - "hf 14a config --atqa force -> Force execution of anticollision\n" - "hf 14a config --atqa skip -> Skip anticollision\n" - "hf 14a config --bcc std -> Follow standard\n" - "hf 14a config --bcc fix -> Fix bad BCC in anticollision\n" - "hf 14a config --bcc ignore -> Ignore bad BCC and use it as such\n" - "hf 14a config --cl2 std -> Follow standard\n" - "hf 14a config --cl2 force -> Execute CL2\n" - "hf 14a config --cl2 skip -> Skip CL2\n" - "hf 14a config --cl3 std -> Follow standard\n" - "hf 14a config --cl3 force -> Execute CL3\n" - "hf 14a config --cl3 skip -> Skip CL3\n" - "hf 14a config --rats std -> Follow standard\n" - "hf 14a config --rats force -> Execute RATS\n" - "hf 14a config --rats skip -> Skip RATS\n" - "hf 14a config --mag on -> Enable Apple magsafe polling\n" - "hf 14a config --mag off -> Disable Apple magsafe polling\n" - "hf 14a config --pla -> Set polling loop annotation (max 22 bytes)\n" - "hf 14a config --pla off -> Disable polling loop annotation\n"); + " `-v` also prints examples for reviving Gen2 cards", + "hf 14a config -> Print current configuration\n" + "hf 14a config --std -> Reset default configuration (follow standard)\n" + "hf 14a config --atqa std -> Follow standard\n" + "hf 14a config --atqa force -> Force execution of anticollision\n" + "hf 14a config --atqa skip -> Skip anticollision\n" + "hf 14a config --bcc std -> Follow standard\n" + "hf 14a config --bcc fix -> Fix bad BCC in anticollision\n" + "hf 14a config --bcc ignore -> Ignore bad BCC and use it as such\n" + "hf 14a config --cl2 std -> Follow standard\n" + "hf 14a config --cl2 force -> Execute CL2\n" + "hf 14a config --cl2 skip -> Skip CL2\n" + "hf 14a config --cl3 std -> Follow standard\n" + "hf 14a config --cl3 force -> Execute CL3\n" + "hf 14a config --cl3 skip -> Skip CL3\n" + "hf 14a config --rats std -> Follow standard\n" + "hf 14a config --rats force -> Execute RATS\n" + "hf 14a config --rats skip -> Skip RATS"); + void *argtable[] = { arg_param_begin, arg_str0(NULL, "atqa", "", "Configure ATQA<>anticollision behavior"), @@ -396,18 +367,14 @@ static int CmdHf14AConfig(const char *Cmd) { arg_str0(NULL, "cl2", "", "Configure SAK<>CL2 behavior"), arg_str0(NULL, "cl3", "", "Configure SAK<>CL3 behavior"), arg_str0(NULL, "rats", "", "Configure RATS behavior"), - arg_str0(NULL, "mag", "", "Configure Apple MagSafe polling"), - arg_str0(NULL, "pla", "", "Configure polling loop annotation"), arg_lit0(NULL, "std", "Reset default configuration: follow all standard"), arg_lit0("v", "verbose", "verbose output"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - bool defaults = arg_get_lit(ctx, 8); - bool verbose = arg_get_lit(ctx, 9); - + bool defaults = arg_get_lit(ctx, 6); int vlen = 0; - char value[64]; + char value[10]; int atqa = defaults ? 0 : -1; CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)value, sizeof(value), &vlen); if (vlen > 0) { @@ -468,62 +435,12 @@ static int CmdHf14AConfig(const char *Cmd) { return PM3_EINVARG; } } - int magsafe = defaults ? 0 : -1; - CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)value, sizeof(value), &vlen); - if (vlen > 0) { - if (strcmp(value, "std") == 0) magsafe = 0; - else if (strcmp(value, "skip") == 0) magsafe = 0; - else if (strcmp(value, "disable") == 0) magsafe = 0; - else if (strcmp(value, "off") == 0) magsafe = 0; - else if (strcmp(value, "enable") == 0) magsafe = 1; - else if (strcmp(value, "on") == 0) magsafe = 1; - else { - PrintAndLogEx(ERR, "magsafe argument must be 'std', 'skip', 'off', 'disable', 'on' or 'enable'"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - } - // Handle polling loop annotation parameter - iso14a_polling_frame_t pla = { - // 0 signals that PLA has to be disabled, -1 signals that no change has to be made - .frame_length = defaults ? 0 : -1, - .last_byte_bits = 8, - .extra_delay = 5 - }; - CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)value, sizeof(value), &vlen); - if (vlen > 0) { - if (strncmp((char *)value, "std", 3) == 0) pla.frame_length = 0; - else if (strncmp((char *)value, "skip", 4) == 0) pla.frame_length = 0; - else if (strncmp((char *)value, "disable", 3) == 0) pla.frame_length = 0; - else if (strncmp((char *)value, "off", 3) == 0) pla.frame_length = 0; - else { - // Convert hex string to bytes - int length = 0; - if (param_gethex_to_eol((char *)value, 0, pla.frame, sizeof(pla.frame), &length) != 0) { - PrintAndLogEx(ERR, "Error parsing polling loop annotation bytes"); - CLIParserFree(ctx); - return PM3_EINVARG; - } - pla.frame_length = length; - // Validate length before adding CRC - if (pla.frame_length < 1 || pla.frame_length > 22) { - PrintAndLogEx(ERR, "Polling loop annotation length invalid: min %d; max %d", 1, 22); - CLIParserFree(ctx); - return PM3_EINVARG; - } - - uint8_t first, second; - compute_crc(CRC_14443_A, pla.frame, pla.frame_length, &first, &second); - pla.frame[pla.frame_length++] = first; - pla.frame[pla.frame_length++] = second; - PrintAndLogEx(INFO, "Added CRC16A to polling loop annotation: %s", sprint_hex(pla.frame, pla.frame_length)); - } - } + bool verbose = arg_get_lit(ctx, 7); CLIParserFree(ctx); - // Handle empty command + // validations if (strlen(Cmd) == 0) { return hf14a_setconfig(NULL, verbose); } @@ -532,15 +449,12 @@ static int CmdHf14AConfig(const char *Cmd) { hf_14a_config_example(); } - // Initialize config with all parameters - hf14a_config_t config = { + hf14a_config config = { .forceanticol = atqa, .forcebcc = bcc, .forcecl2 = cl2, .forcecl3 = cl3, - .forcerats = rats, - .magsafe = magsafe, - .polling_loop_annotation = pla + .forcerats = rats }; return hf14a_setconfig(&config, verbose); @@ -632,12 +546,48 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) { return PM3_SUCCESS; } +iso14a_polling_parameters_t iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe) { + // Extra 100ms give enough time for Apple (ECP) devices to proccess field info and make a decision + + if (use_ecp && use_magsafe) { + iso14a_polling_parameters_t full_polling_parameters = { + .frames = { WUPA_FRAME, ECP_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, + .frame_count = 6, + .extra_timeout = 100 + }; + return full_polling_parameters; + } else if (use_ecp) { + iso14a_polling_parameters_t ecp_polling_parameters = { + .frames = { WUPA_FRAME, ECP_FRAME }, + .frame_count = 2, + .extra_timeout = 100 + }; + return ecp_polling_parameters; + } else if (use_magsafe) { + iso14a_polling_parameters_t magsafe_polling_parameters = { + .frames = { WUPA_FRAME, MAGWUPA1_FRAME, MAGWUPA2_FRAME, MAGWUPA3_FRAME, MAGWUPA4_FRAME }, + .frame_count = 5, + .extra_timeout = 0 + }; + return magsafe_polling_parameters; + } + + iso14a_polling_parameters_t wupa_polling_parameters = { + .frames = { WUPA_FRAME }, + .frame_count = 1, + .extra_timeout = 0, + }; + return wupa_polling_parameters; +} + static int CmdHF14AReader(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14a reader", "Act as a ISO-14443a reader to identify tag. Look for ISO-14443a tags until Enter or the pm3 button is pressed", "hf 14a reader\n" "hf 14a reader -@ -> Continuous mode\n" + "hf 14a reader --ecp -> trigger apple enhanced contactless polling\n" + "hf 14a reader --mag -> trigger apple magsafe polling\n" ); void *argtable[] = { @@ -646,6 +596,8 @@ static int CmdHF14AReader(const char *Cmd) { arg_lit0("s", "silent", "silent (no messages)"), arg_lit0(NULL, "drop", "just drop the signal field"), arg_lit0(NULL, "skip", "ISO14443-3 select only (skip RATS)"), + arg_lit0(NULL, "ecp", "Use enhanced contactless polling"), + arg_lit0(NULL, "mag", "Use Apple magsafe polling"), arg_lit0("@", NULL, "continuous reader mode"), arg_lit0("w", "wait", "wait for card"), arg_param_end @@ -668,8 +620,18 @@ static int CmdHF14AReader(const char *Cmd) { cm |= ISO14A_NO_RATS; } - bool continuous = arg_get_lit(ctx, 5); - bool wait = arg_get_lit(ctx, 6); + bool use_ecp = arg_get_lit(ctx, 5); + bool use_magsafe = arg_get_lit(ctx, 6); + + iso14a_polling_parameters_t *polling_parameters = NULL; + iso14a_polling_parameters_t parameters = iso14a_get_polling_parameters(use_ecp, use_magsafe); + if (use_ecp || use_magsafe) { + cm |= ISO14A_USE_CUSTOM_POLLING; + polling_parameters = ¶meters; + } + + bool continuous = arg_get_lit(ctx, 7); + bool wait = arg_get_lit(ctx, 8); CLIParserFree(ctx); bool found = false; @@ -684,7 +646,12 @@ static int CmdHF14AReader(const char *Cmd) { int res = PM3_SUCCESS; do { clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0); + + if ((cm & ISO14A_USE_CUSTOM_POLLING) == ISO14A_USE_CUSTOM_POLLING) { + SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, (uint8_t *)polling_parameters, sizeof(iso14a_polling_parameters_t)); + } else { + SendCommandMIX(CMD_HF_ISO14443A_READER, cm, 0, 0, NULL, 0); + } if ((cm & ISO14A_CONNECT) == ISO14A_CONNECT) { PacketResponseNG resp; @@ -880,7 +847,6 @@ int CmdHF14ASim(const char *Cmd) { "hf 14a sim -t 10 -> ST25TA IKEA Rothult\n" "hf 14a sim -t 11 -> Javacard (JCOP)\n" "hf 14a sim -t 12 -> 4K Seos card\n" - "hf 14a sim -t 13 -> MIFARE Ultralight C" ); void *argtable[] = { @@ -891,8 +857,6 @@ int CmdHF14ASim(const char *Cmd) { arg_lit0("x", NULL, "Performs the 'reader attack', nr/ar attack against a reader"), arg_lit0(NULL, "sk", "Fill simulator keys from found keys"), arg_lit0("v", "verbose", "verbose output"), - arg_lit0(NULL, "c1", "UL-C Auth - all zero handshake part 1"), - arg_lit0(NULL, "c2", "UL-C Auth - all zero handshake part 2"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -926,12 +890,9 @@ int CmdHF14ASim(const char *Cmd) { bool setEmulatorMem = arg_get_lit(ctx, 5); bool verbose = arg_get_lit(ctx, 6); - bool ulc_p1 = arg_get_lit(ctx, 7); - bool ulc_p2 = arg_get_lit(ctx, 8); - CLIParserFree(ctx); - if (tagtype > 13) { + if (tagtype > 12) { PrintAndLogEx(ERR, "Undefined tag %d", tagtype); return PM3_EINVARG; } @@ -945,16 +906,11 @@ int CmdHF14ASim(const char *Cmd) { uint16_t flags; uint8_t uid[10]; uint8_t exitAfter; - uint8_t rats[20]; - bool ulc_p1; - bool ulc_p2; } PACKED payload; payload.tagtype = tagtype; payload.flags = flags; payload.exitAfter = exitAfterNReads; - payload.ulc_p1 = ulc_p1; - payload.ulc_p2 = ulc_p2; memcpy(payload.uid, uid, uid_len); clearCommandBuffer(); @@ -968,17 +924,14 @@ int CmdHF14ASim(const char *Cmd) { bool keypress = kbd_enter_pressed(); while (keypress == false) { - if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false) { + if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) continue; - } - if (resp.status != PM3_SUCCESS) { + if (resp.status != PM3_SUCCESS) break; - } - if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) { + if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK) break; - } const nonces_t *data = (nonces_t *)resp.data.asBytes; readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose); @@ -1330,7 +1283,7 @@ static int CmdExchangeAPDU(bool chainingin, const uint8_t *datain, int datainlen // Button pressed / user cancelled if (iLen == -3) { - PrintAndLogEx(DEBUG, "\naborted via keyboard!"); + PrintAndLogEx(DEBUG, "ERR: APDU: User aborted"); return PM3_EAPDU_FAIL; } return PM3_SUCCESS; @@ -1460,7 +1413,6 @@ static int CmdHF14AAPDU(const char *Cmd) { CLIParserFree(ctx); return PM3_EINVARG; } - bool extendedAPDU = arg_get_lit(ctx, 6); int le = arg_get_int_def(ctx, 7, 0); @@ -1545,6 +1497,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) { "Sends raw bytes over ISO14443a. With option to use TOPAZ 14a mode.", "hf 14a raw -sc 3000 -> select, crc, where 3000 == 'read block 00'\n" "hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40\n" + "hf 14a raw --ecp -s -> send ECP before select\n" "Crypto1 session example, with special auth shortcut 6xxx:\n" "hf 14a raw --crypto1 -skc 6000FFFFFFFFFFFF\n" "hf 14a raw --crypto1 -kc 3000\n" @@ -1563,6 +1516,8 @@ static int CmdHF14ACmdRaw(const char *Cmd) { arg_int0("t", "timeout", "", "Timeout in milliseconds"), arg_int0("b", NULL, "", "Number of bits to send. Useful for send partial byte"), arg_lit0("v", "verbose", "Verbose output"), + arg_lit0(NULL, "ecp", "Use enhanced contactless polling"), + arg_lit0(NULL, "mag", "Use Apple magsafe polling"), arg_lit0(NULL, "topaz", "Use Topaz protocol to send command"), arg_lit0(NULL, "crypto1", "Use crypto1 session"), arg_strx1(NULL, NULL, "", "Raw bytes to send"), @@ -1579,12 +1534,14 @@ static int CmdHF14ACmdRaw(const char *Cmd) { uint32_t timeout = (uint32_t)arg_get_int_def(ctx, 7, 0); uint16_t numbits = (uint16_t)arg_get_int_def(ctx, 8, 0); bool verbose = arg_get_lit(ctx, 9); - bool topazmode = arg_get_lit(ctx, 10); - bool crypto1mode = arg_get_lit(ctx, 11); + bool use_ecp = arg_get_lit(ctx, 10); + bool use_magsafe = arg_get_lit(ctx, 11); + bool topazmode = arg_get_lit(ctx, 12); + bool crypto1mode = arg_get_lit(ctx, 13); int datalen = 0; uint8_t data[PM3_CMD_DATA_SIZE_MIX] = {0}; - CLIGetHexWithReturn(ctx, 12, data, &datalen); + CLIGetHexWithReturn(ctx, 14, data, &datalen); CLIParserFree(ctx); bool bTimeout = (timeout) ? true : false; @@ -1640,7 +1597,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) { if (crypto1mode) { flags |= ISO14A_CRYPTO1MODE; - if (numbits > 0 || topazmode) { + if (numbits > 0 || topazmode || use_ecp || use_magsafe) { PrintAndLogEx(FAILED, "crypto1 mode cannot be used with other modes or partial bytes"); return PM3_EINVARG; } @@ -1650,6 +1607,13 @@ static int CmdHF14ACmdRaw(const char *Cmd) { flags |= ISO14A_NO_RATS; } + // TODO: allow to use reader command with both data and polling configuration + if (use_ecp || use_magsafe) { + PrintAndLogEx(WARNING, "ECP and Magsafe not supported with this command at this moment. Instead use 'hf 14a reader -sk --ecp/--mag'"); + // flags |= ISO14A_USE_MAGSAFE; + // flags |= ISO14A_USE_ECP; + } + // Max buffer is PM3_CMD_DATA_SIZE_MIX datalen = (datalen > PM3_CMD_DATA_SIZE_MIX) ? PM3_CMD_DATA_SIZE_MIX : datalen; @@ -1792,678 +1756,259 @@ static void printTag(const char *tag) { PrintAndLogEx(SUCCESS, " " _YELLOW_("%s"), tag); } -// Based on NXP AN10833 Rev 3.8 and NXP AN10834 Rev 4.2 -int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status, - uint8_t ats_hist_len, uint8_t *ats_hist, - bool version_hw_available, version_hw_t *version_hw) { +int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status) { + int type = MTNONE; - if (version_hw_available) { + if ((sak & 0x02) != 0x02) { + if ((sak & 0x19) == 0x19) { + type |= MTCLASSIC; + } else if ((sak & 0x40) == 0x40) { + type |= MTISO18092; + } else if ((sak & 0x38) == 0x38) { + type |= MTCLASSIC; + } else if ((sak & 0x18) == 0x18) { + if (select_status == 1) { + type |= MTPLUS; + } else { + type |= MTCLASSIC; + } + } else if ((sak & 0x09) == 0x09) { + type |= MTMINI; + } else if ((sak & 0x28) == 0x28) { + type |= MTCLASSIC; + } else if ((sak & 0x08) == 0x08) { + if (select_status == 1) { + type |= MTPLUS; + } else { + type |= MTCLASSIC; + } + } else if ((sak & 0x11) == 0x11) { + type |= MTPLUS; + } else if ((sak & 0x10) == 0x10) { + type |= MTPLUS; + } else if ((sak & 0x01) == 0x01) { + type |= MTCLASSIC; + } else if ((sak & 0x24) == 0x24) { + type |= MTDESFIRE; + } else if ((sak & 0x20) == 0x20) { + if (select_status == 1) { + if ((atqa & 0x0040) == 0x0040) { + if ((atqa & 0x0300) == 0x0300) { + type |= MTDESFIRE; + } else { + type |= MTPLUS; + } + } else { - switch (version_hw->product_type & 0x0F) { - case 0x1: { - type |= MTDESFIRE; + if ((atqa & 0x0001) == 0x0001) { + type |= HID_SEOS; + } else { + type |= MTPLUS; + } - // special cases, override major_product_version_str when needed - switch (version_hw->major_product_version) { - case 0x42: + if ((atqa & 0x0004) == 0x0004) { type |= MTEMV; - break; - case 0xA0: - type |= MTDUOX; - break; + } } - break; - } - case 0x2: { - type |= MTPLUS; - break; - } - case 0x3: { - type |= MTULTRALIGHT; - break; - } - case 0x4: { - type |= MTNTAG; - break; - } - case 0x7: { - type |= MTNTAG; - break; - } - case 0x8: { - type |= MTDESFIRE; - break; - } - case 0x9: { - break; - } - default: { - break; + type |= (MTDESFIRE | MT424); } + } else if ((sak & 0x04) == 0x04) { + type |= MTDESFIRE; + } else { + type |= MTULTRALIGHT; } + } else if ((sak & 0x0A) == 0x0A) { - } - - if ((sak & 0x44) == 0x40) { - // ISO18092 Table 15: Target compliant with NFC transport protocol - type |= MTISO18092; - } - - if ((sak & 0x02) == 0x00) { // SAK b2=0 - - if ((sak & 0x08) == 0x08) { // SAK b2=0 b4=1 - - if ((sak & 0x10) == 0x10) { // SAK b2=0 b4=1 b5=1 - - if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=1 b5=1 b1=1, SAK=0x19 - type |= MTCLASSIC; - - } else { // SAK b2=0 b4=1 b5=1 b1=0 - - if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=1 b5=1 b1=0 b6=1, SAK=0x38 - type |= MTCLASSIC; - - } else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 - - if (select_status == 4) { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS - - if (version_hw_available) { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS GetVersion - type |= MTPLUS; - - } else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS No_GetVersion - - if (ats_hist_len > 0) { - - if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) { - type |= MTPLUS; - } else { - type |= MTCLASSIC; - } - } - } - - } else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 no_ATS, SAK=0x18 - type |= MTCLASSIC; - } - } - } - - } else { // SAK b2=0 b4=1 b5=0 - - if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=1 b5=0 b1=1, SAK=0x09 - type |= MTMINI; - - } else { // SAK b2=0 b4=1 b5=0 b1=0 - - if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=1 b5=0 b1=0 b6=1, SAK=0x28 - type |= MTCLASSIC; - - } else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 - - if (select_status == 4) { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS - - if (version_hw_available) { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS GetVersion - type |= MTPLUS; - - } else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS No_GetVersion - - if (ats_hist_len > 0) { - - if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) { - type |= MTPLUS; - - } else if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x21\x30", 4) == 0)) { - type |= MTPLUS; - - } else { - type |= MTCLASSIC; - } - } - } - } else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 no_ATS, SAK=0x08 - type |= MTCLASSIC; - } - } - } - } - - } else { // SAK b2=0 b4=0 - - if ((sak & 0x10) == 0x10) { // SAK b2=0 b4=0 b5=1 - - // if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=1 b1=1, SAK=0x11 - // } else { // SAK b2=0 b4=0 b5=1 b1=0, SAK=0x10 - // } - type |= MTPLUS; - - } else { // SAK b2=0 b4=0 b5=0 - - if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=0 b1=1 - type |= MTCLASSIC; - - } else { // SAK b2=0 b4=0 b5=0 b1=0 - - if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1, SAK=0x20 - - if (select_status == 1) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS - - if (version_hw_available) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS GetVersion - - if ((version_hw->product_type & 0x7F) == 0x02) { - type |= MTPLUS; - - } else if (((version_hw->product_type & 0x7F) == 0x01) || - (version_hw->product_type == 0x08) || - (version_hw->product_type == 0x91)) { - type |= MTDESFIRE; - - } else if (version_hw->product_type == 0x04) { - type |= (MTDESFIRE | MT424); - } - - } else { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS No GetVersion - - if (ats_hist_len > 0) { - - if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) { - type |= MTPLUS; - - } else { - - if ((atqa == 0x0001) || (atqa == 0x0004)) { - type |= HID_SEOS; - } - - if (atqa == 0x0004) { - type |= MTEMV; - } - } - } - } - } - - } else { // SAK b2=0 b4=0 b5=0 b1=0 b6=0, SAK=0x00 - - if (version_hw_available == false) { - // SAK b2=0 b4=0 b5=0 b1=0 b6=0 No_GetVersion - int status = mfuc_test_authentication_support(); - if (status == PM3_SUCCESS) { - type |= MTULTRALIGHT_C; - } - } - type |= MTULTRALIGHT; - } - } - } - } - } else { // SAK b2=1 - - if (sak == 0x0A) { - - if (atqa == 0x0003) { - // Uses Shanghai algo - type |= MTFUDAN; - - } else if (atqa == 0x0005) { - type |= MTFUDAN; - } - - } else if (sak == 0x53) { + if ((atqa & 0x0003) == 0x0003) { + type |= MTFUDAN; + } else if ((atqa & 0x0005) == 0x0005) { type |= MTFUDAN; } + } else if ((sak & 0x53) == 0x53) { + type |= MTFUDAN; } return type; } -// Based on NXP AN10833 Rev 3.8 and NXP AN10834 Rev 4.2 -static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_status, - uint8_t ats_hist_len, uint8_t *ats_hist, - bool version_hw_available, version_hw_t *version_hw) { + +// Based on NXP AN10833 Rev 3.6 and NXP AN10834 Rev 4.1 +static int detect_nxp_card_print(uint8_t sak, uint16_t atqa, uint64_t select_status) { int type = MTNONE; - const char *product_type_str = ""; - const char *major_product_version_str = ""; - const char *storage_size_str = ""; - if (version_hw_available) { + PrintAndLogEx(SUCCESS, "Possible types:"); - switch (version_hw->product_type & 0x0F) { - case 0x1: { - product_type_str = "MIFARE DESFire"; - // special cases, override product_type_str when needed - if (version_hw->product_type == 0x91) { - product_type_str = "Apple Wallet DESFire Applet"; - } + if ((sak & 0x02) != 0x02) { - // general rule - switch (version_hw->major_product_version & 0x0F) { - case 0x01: - major_product_version_str = "EV1"; - break; - case 0x02: - major_product_version_str = "EV2"; - break; - case 0x03: - major_product_version_str = "EV3"; - break; - } + if ((sak & 0x19) == 0x19) { + printTag("MIFARE Classic 2K"); + type |= MTCLASSIC; - // special cases, override major_product_version_str when needed - switch (version_hw->major_product_version) { - case 0x00: - major_product_version_str = "MF3ICD40"; - break; - case 0x42: - major_product_version_str = "EV2 + EMV"; - break; - case 0xA0: - product_type_str = "MIFARE DUOX"; - break; - } - break; - } - case 0x2: { - product_type_str = "MIFARE Plus"; - switch (version_hw->major_product_version) { - case 0x11: - major_product_version_str = "EV1"; - break; - case 0x22: - major_product_version_str = "EV2"; - break; - default: - major_product_version_str = "n/a"; - } - break; - } - case 0x3: { - product_type_str = "MIFARE Ultralight"; - switch (version_hw->major_product_version) { - case 0x01: { - major_product_version_str = "EV1"; - - if (version_hw->storage_size == 0x0B) { - storage_size_str = "48b"; - } else if (version_hw->storage_size == 0x0E) { - storage_size_str = "128b"; - } - break; - } - case 0x02: - major_product_version_str = "Nano"; - break; - case 0x04: - major_product_version_str = "AES"; - break; - default: - major_product_version_str = "n/a"; - } - break; - } - case 0x4: { - product_type_str = "NTAG"; - switch (version_hw->major_product_version) { - case 0x01: - major_product_version_str = "2xx"; - break; - case 0x02: - major_product_version_str = "210µ"; - break; - case 0x03: - major_product_version_str = "213 TT"; - break; - case 0x10: - // Not sure about its product type = 4 - major_product_version_str = "413 DNA"; - break; - case 0x30: - major_product_version_str = "4xx"; - break; - default: - major_product_version_str = "n/a"; - } - break; - } - case 0x7: { - product_type_str = "NTAG I2C"; - break; - } - case 0x8: { - product_type_str = "MIFARE DESFire Light"; - break; - } - case 0x9: { - product_type_str = "MIFARE Hospitality"; - switch (version_hw->major_product_version) { - case 0x01: - major_product_version_str = "AES"; - break; - default: - major_product_version_str = "n/a"; - } - break; - } - default: { - product_type_str = "Unknown NXP tag"; - break; - } - } - - if (storage_size_str == NULL) { - static char size_str[16]; - uint16_t usize = 1 << ((version_hw->storage_size >> 1) + 1); - uint16_t lsize = 1 << (version_hw->storage_size >> 1); - - // is LSB set? - if ((version_hw->storage_size & 0x01) == 1) { - - // if set, its a range between upper size and lower size - - if (lsize < 1024) { - snprintf(size_str, sizeof(size_str), "%u - %uB", usize, lsize); - } else { - snprintf(size_str, sizeof(size_str), "%d - %dK", (usize / 1024), (lsize / 1024)); - } + } else if ((sak & 0x40) == 0x40) { + if ((atqa & 0x0110) == 0x0110) { + printTag("P2P Support / Proprietary"); } else { + printTag("P2P Support / Android"); + } + type |= MTISO18092; - // if not set, it's lower size - if (lsize < 1024) { - snprintf(size_str, sizeof(size_str), "%uB", lsize); + } else if ((sak & 0x38) == 0x38) { + printTag("SmartMX with MIFARE Classic 4K"); + type |= MTCLASSIC; + + } else if ((sak & 0x18) == 0x18) { + + if (select_status == 1) { + + if ((atqa & 0x0040) == 0x0040) { + printTag("MIFARE Plus EV1 4K CL2 in SL1"); + printTag("MIFARE Plus S 4K CL2 in SL1"); + printTag("MIFARE Plus X 4K CL2 in SL1"); } else { - snprintf(size_str, sizeof(size_str), "%dK", (lsize / 1024)); - } - } - - storage_size_str = size_str; - - } - } - - char tag_info[128]; - - if ((sak & 0x44) == 0x40) { - // ISO18092 Table 15: Target compliant with NFC transport protocol - if ((atqa & 0x0110) == 0x0110) { - printTag("P2P Support / Proprietary"); - } else { - printTag("P2P Support / Android"); - } - type |= MTISO18092; - } - - if ((sak & 0x02) == 0x00) { // SAK b2=0 - - if ((sak & 0x08) == 0x08) { // SAK b2=0 b4=1 - - if ((sak & 0x10) == 0x10) { // SAK b2=0 b4=1 b5=1 - - if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=1 b5=1 b1=1, SAK=0x19 - printTag("MIFARE Classic 2K"); - type |= MTCLASSIC; - } else { // SAK b2=0 b4=1 b5=1 b1=0 - - if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=1 b5=1 b1=0 b6=1, SAK=0x38 - printTag("SmartMX with MIFARE Classic 4K"); - type |= MTCLASSIC; - } else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 - - if (select_status == 4) { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS - - if (version_hw_available) { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS GetVersion - snprintf(tag_info, sizeof(tag_info), "%s %s %s in SL1", product_type_str, major_product_version_str, storage_size_str); - printTag(tag_info); - type |= MTPLUS; - - } else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 ATS No_GetVersion - - if (ats_hist_len > 0) { - - if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) { - - if (memcmp(ats_hist + 4, "\x00\x35\xC7", 3) == 0) { - printTag("MIFARE Plus S 4K in SL1"); - } else if (memcmp(ats_hist + 4, "\x01\xBC\xD6", 3) == 0) { - printTag("MIFARE Plus X 4K in SL1"); - } else { - printTag("Unrecognized MIFARE Plus??"); - } - type |= MTPLUS; - } else { - if ((atqa & 0x0040) == 0x0040) { - printTag("MIFARE Classic 4K CL2 with ATS!"); - } else { - printTag("MIFARE Classic 4K with ATS!"); - } - type |= MTCLASSIC; - } - } - } - - } else { // SAK b2=0 b4=1 b5=1 b1=0 b6=0 no_ATS, SAK=0x18 - - if ((atqa & 0x0040) == 0x0040) { - printTag("MIFARE Classic 4K CL2"); - } else { - printTag("MIFARE Classic 4K"); - } - type |= MTCLASSIC; - } - } - } - - } else { // SAK b2=0 b4=1 b5=0 - - if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=1 b5=0 b1=1, SAK=0x09 - - if ((atqa & 0x0040) == 0x0040) { - printTag("MIFARE Mini 0.3K CL2"); - } else { - printTag("MIFARE Mini 0.3K"); - } - type |= MTMINI; - - } else { // SAK b2=0 b4=1 b5=0 b1=0 - - if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=1 b5=0 b1=0 b6=1, SAK=0x28 - printTag("SmartMX with MIFARE Classic 1K"); - printTag("FM1208-10 with MIFARE Classic 1K"); - printTag("FM1216-137 with MIFARE Classic 1K"); - type |= MTCLASSIC; - } else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 - - if (select_status == 4) { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS - - if (version_hw_available) { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS GetVersion - snprintf(tag_info, sizeof(tag_info), "%s %s %s in SL1", product_type_str, major_product_version_str, storage_size_str); - printTag(tag_info); - type |= MTPLUS; - - } else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 ATS No_GetVersion - - if (ats_hist_len > 0) { - - if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) { - - if (memcmp(ats_hist + 4, "\x00\x35\xC7", 3) == 0) { - printTag("MIFARE Plus S 2K in SL1"); - } else if (memcmp(ats_hist + 4, "\x01\xBC\xD6", 3) == 0) { - printTag("MIFARE Plus X 2K in SL1"); - } else { - printTag("Unrecognized MIFARE Plus??"); - } - type |= MTPLUS; - - } else if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x21\x30", 4) == 0)) { - - if (memcmp(ats_hist + 4, "\x00\xF6\xD1", 3) == 0) { - printTag("MIFARE Plus SE 1K 17pF"); - } else if (memcmp(ats_hist + 4, "\x10\xF6\xD1", 3) == 0) { - printTag("MIFARE Plus SE 1K 70pF"); - } else { - printTag("Unrecognized MIFARE Plus SE??"); - } - type |= MTPLUS; - - } else { - - if ((atqa & 0x0040) == 0x0040) { - printTag("MIFARE Classic 1K CL2 with ATS!"); - } else { - printTag("MIFARE Classic 1K with ATS!"); - } - type |= MTCLASSIC; - } - } - } - } else { // SAK b2=0 b4=1 b5=0 b1=0 b6=0 no_ATS, SAK=0x08 - if ((atqa & 0x0040) == 0x0040) { - printTag("MIFARE Classic 1K CL2"); - } else { - printTag("MIFARE Classic 1K"); - } - type |= MTCLASSIC; - } - } - } - } - - } else { // SAK b2=0 b4=0 - - if ((sak & 0x10) == 0x10) { // SAK b2=0 b4=0 b5=1 - - if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=1 b1=1, SAK=0x11 - printTag("MIFARE Plus 4K in SL2"); - } else { // SAK b2=0 b4=0 b5=1 b1=0, SAK=0x10 - printTag("MIFARE Plus 2K in SL2"); + printTag("MIFARE Plus EV1 4K in SL1"); + printTag("MIFARE Plus S 4K in SL1"); + printTag("MIFARE Plus X 4K in SL1"); } type |= MTPLUS; - } else { // SAK b2=0 b4=0 b5=0 + } else { - if ((sak & 0x01) == 0x01) { // SAK b2=0 b4=0 b5=0 b1=1 - printTag("TNP3xxx (TagNPlay, Activision Game Appliance)"); - type |= MTCLASSIC; + if ((atqa & 0x0040) == 0x0040) { + printTag("MIFARE Classic 4K CL2"); + } else { + printTag("MIFARE Classic 4K"); + } + type |= MTCLASSIC; + } - } else { // SAK b2=0 b4=0 b5=0 b1=0 + } else if ((sak & 0x09) == 0x09) { - if ((sak & 0x20) == 0x20) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1, SAK=0x20 + if ((atqa & 0x0040) == 0x0040) { + printTag("MIFARE Mini 0.3K CL2"); + } else { + printTag("MIFARE Mini 0.3K"); + } + type |= MTMINI; - if (select_status == 1) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS + } else if ((sak & 0x28) == 0x28) { + printTag("SmartMX with MIFARE Classic 1K"); + printTag("FM1208-10 with MIFARE Classic 1K"); + printTag("FM1216-137 with MIFARE Classic 1K"); + type |= MTCLASSIC; + } else if ((sak & 0x08) == 0x08) { - if (version_hw_available) { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS GetVersion + if (select_status == 1) { - if ((version_hw->product_type & 0x7F) == 0x02) { - snprintf(tag_info, sizeof(tag_info), "%s %s %s in SL0/SL3", product_type_str, major_product_version_str, storage_size_str); - type |= MTPLUS; + if ((atqa & 0x0040) == 0x0040) { + printTag("MIFARE Plus EV1 2K CL2 in SL1"); + printTag("MIFARE Plus S 2K CL2 in SL1"); + printTag("MIFARE Plus X 2K CL2 in SL1"); + printTag("MIFARE Plus SE 1K CL2"); + } else { + printTag("MIFARE Plus EV1 2K in SL1"); + printTag("MIFARE Plus S 2K in SL1"); + printTag("MIFARE Plus X 2K in SL1"); + printTag("MIFARE Plus SE 1K"); + } + type |= MTPLUS; - } else if (((version_hw->product_type & 0x7F) == 0x01) || - (version_hw->product_type == 0x08) || - (version_hw->product_type == 0x91)) { - snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str); - type |= MTDESFIRE; + } else { + if ((atqa & 0x0040) == 0x0040) { + printTag("MIFARE Classic 1K CL2"); + } else { + printTag("MIFARE Classic 1K"); + } + type |= MTCLASSIC; + } - } else if (version_hw->product_type == 0x04) { - snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str); - type |= (MTDESFIRE | MT424); + } else if ((sak & 0x11) == 0x11) { + printTag("MIFARE Plus 4K in SL2"); + type |= MTPLUS; + } else if ((sak & 0x10) == 0x10) { + printTag("MIFARE Plus 2K in SL2"); + type |= MTPLUS; + } else if ((sak & 0x01) == 0x01) { + printTag("TNP3xxx (TagNPlay, Activision Game Appliance)"); + type |= MTCLASSIC; + } else if ((sak & 0x24) == 0x24) { + printTag("MIFARE DESFire CL1"); + printTag("MIFARE DESFire EV1 CL1"); + type |= MTDESFIRE; + } else if ((sak & 0x20) == 0x20) { - } else { - snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str); - } - printTag(tag_info); + if (select_status == 1) { - } else { // SAK b2=0 b4=0 b5=0 b1=0 b6=1 ATS No GetVersion + if ((atqa & 0x0040) == 0x0040) { - if (ats_hist_len > 0) { + if ((atqa & 0x0300) == 0x0300) { + printTag("MIFARE DESFire CL2"); + printTag("MIFARE DESFire EV1 256B/2K/4K/8K CL2"); + printTag("MIFARE DESFire EV2 2K/4K/8K/16K/32K"); + printTag("MIFARE DESFire EV3 2K/4K/8K"); + printTag("MIFARE DESFire Light 640B"); + printTag("MIFARE Duox"); + type |= MTDESFIRE; + } else { + printTag("MIFARE Plus EV1 2K/4K CL2 in SL3"); + printTag("MIFARE Plus S 2K/4K CL2 in SL3"); + printTag("MIFARE Plus X 2K/4K CL2 in SL3"); + printTag("MIFARE Plus SE 1K CL2"); + type |= MTPLUS; + } + } else { - if ((ats_hist_len == 9) && (memcmp(ats_hist, "\xC1\x05\x2F\x2F", 4) == 0)) { + if ( + ((atqa & 0x0001) == 0x0001) || + ((atqa & 0x0004) == 0x0004) + ) { + printTag("HID SEOS (smartmx / javacard)"); + type |= HID_SEOS; - if (memcmp(ats_hist + 4, "\x00\x35\xC7", 3) == 0) { + } else { + printTag("MIFARE Plus EV1 2K/4K in SL3"); + printTag("MIFARE Plus S 2K/4K in SL3"); + printTag("MIFARE Plus X 2K/4K in SL3"); + printTag("MIFARE Plus SE 1K"); + type |= MTPLUS; + } - if ((atqa & 0xFF0F) == 0x0004) { - printTag("MIFARE Plus S 2K in SL0/SL3"); - } else if ((atqa & 0xFF0F) == 0x0002) { - printTag("MIFARE Plus S 4K in SL0/SL3"); - } else { - printTag("Unrecognized MIFARE Plus??"); - } - - } else if (memcmp(ats_hist + 4, "\x01\xBC\xD6", 3) == 0) { - printTag("MIFARE Plus X 2K/4K in SL0/SL3"); - - } else if (memcmp(ats_hist + 4, "\x00\xF6\xD1", 3) == 0) { - printTag("MIFARE Plus SE 1K 17pF"); - - } else if (memcmp(ats_hist + 4, "\x10\xF6\xD1", 3) == 0) { - printTag("MIFARE Plus SE 1K 70pF"); - - } else { - printTag("Unknown MIFARE Plus"); - } - type |= MTPLUS; - - } else { - - if ((atqa == 0x0001) || (atqa == 0x0004)) { - printTag("HID SEOS (smartmx / javacard)"); - type |= HID_SEOS; - } - - if (atqa == 0x0004) { - printTag("EMV"); - type |= MTEMV; - } - } - } - } - } else { - printTag("Unknown tag claims to support RATS in SAK but does not..."); - } - - } else { // SAK b2=0 b4=0 b5=0 b1=0 b6=0, SAK=0x00 - - if (version_hw_available) { // SAK b2=0 b4=0 b5=0 b1=0 b6=0 GetVersion - snprintf(tag_info, sizeof(tag_info), "%s %s %s", product_type_str, major_product_version_str, storage_size_str); - printTag(tag_info); - - } else { // SAK b2=0 b4=0 b5=0 b1=0 b6=0 No_GetVersion - - int status = mfuc_test_authentication_support(); - if (status == PM3_SUCCESS) { - // TODO: read page 2/3, then ?? - printTag("MIFARE Ultralight C"); - printTag("MIFARE Hospitality"); - type |= MTULTRALIGHT_C; - - } else { - printTag("MIFARE Ultralight"); - } - - } - type |= MTULTRALIGHT; + if ((atqa & 0x0004) == 0x0004) { + printTag("EMV"); + type |= MTEMV; } } + + printTag("NTAG 4xx"); + type |= (MTDESFIRE | MT424); } + } else if ((sak & 0x04) == 0x04) { + printTag("Any MIFARE CL1"); + type |= MTDESFIRE; + } else { + printTag("MIFARE Ultralight"); + printTag("MIFARE Ultralight C"); + printTag("MIFARE Ultralight EV1"); + printTag("MIFARE Ultralight Nano"); + printTag("MIFARE Ultralight AES"); + printTag("MIFARE Hospitality"); + printTag("NTAG 2xx"); + type |= MTULTRALIGHT; } - } else { // SAK b2=1 + } else if ((sak & 0x0A) == 0x0A) { - if (sak == 0x0A) { - - if (atqa == 0x0003) { - // Uses Shanghai algo - printTag("FM11RF005SH (FUDAN Shanghai Metro)"); - type |= MTFUDAN; - - } else if (atqa == 0x0005) { - printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)"); - type |= MTFUDAN; - } - - } else if (sak == 0x53) { - printTag("FM11RF08SH (FUDAN)"); + if ((atqa & 0x0003) == 0x0003) { + // Uses Shanghai algo + printTag("FM11RF005SH (FUDAN Shanghai Metro)"); + type |= MTFUDAN; + } else if ((atqa & 0x0005) == 0x0005) { + printTag("FM11RF005M (FUDAN ISO14443A w Crypto-1 algo)"); type |= MTFUDAN; } + } else if ((sak & 0x53) == 0x53) { + printTag("FM11RF08SH (FUDAN)"); + type |= MTFUDAN; } if (type == MTNONE) { @@ -2586,7 +2131,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { PrintAndLogEx(DEBUG, "iso14443a card select timeout"); DropField(); - return PM3_ETIMEOUT; + return 0; } iso14a_card_select_t card; @@ -2597,7 +2142,6 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { 1: OK, with ATS 2: OK, no ATS 3: proprietary Anticollision - 4: OK, SAK = no ATS but RATS possible (tested below) */ uint64_t select_status = resp.oldarg[0]; @@ -2625,43 +2169,10 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { return select_status; } - // 2: try to request ATS even if tag claims not to support it. If yes => 4 - if (select_status == 2) { - uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, sizeof(rats)); - if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { - PrintAndLogEx(WARNING, "timeout while waiting for reply"); - return PM3_ETIMEOUT; - } - - memcpy(card.ats, resp.data.asBytes, resp.oldarg[0]); - card.ats_len = resp.oldarg[0]; // note: ats_len includes CRC Bytes - if (card.ats_len > 3) { - select_status = 4; - } - } - uint8_t ats_hist_pos = 0; - if ((card.ats_len > 3) && (card.ats[0] > 1)) { - ats_hist_pos = 2; - ats_hist_pos += (card.ats[1] & 0x10) == 0x10; - ats_hist_pos += (card.ats[1] & 0x20) == 0x20; - ats_hist_pos += (card.ats[1] & 0x40) == 0x40; - } - - - version_hw_t version_hw = {0}; - // if 4b UID or NXP, try to get version - int res = hf14a_getversion_data(&card, select_status, &version_hw); - bool version_hw_available = (res == PM3_SUCCESS); - PrintAndLogEx(INFO, "---------- " _CYAN_("ISO14443-A Information") " ----------"); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s") " %s", sprint_hex(card.uid, card.uidlen), get_uid_type(&card)); PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, select_status); - if (version_hw_available) { - PrintAndLogEx(DEBUG, "GetV: " _GREEN_("%s"), sprint_hex((uint8_t *)&version_hw, sizeof(version_hw))); - } bool isMifareMini = false; bool isMifareClassic = true; @@ -2677,12 +2188,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { int nxptype = MTNONE; if (card.uidlen <= 4) { - - PrintAndLogEx(SUCCESS, "Possible types:"); - nxptype = detect_nxp_card_print(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), - select_status, card.ats_len - ats_hist_pos, card.ats + ats_hist_pos, - version_hw_available, &version_hw - ); + nxptype = detect_nxp_card_print(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status); isMifareMini = ((nxptype & MTMINI) == MTMINI); isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC); @@ -2701,8 +2207,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } else { // Double & triple sized UID, can be mapped to a manufacturer. - PrintAndLogEx(SUCCESS, " " _YELLOW_("%s"), getTagInfo(card.uid[0])); - PrintAndLogEx(SUCCESS, "Possible types:"); + PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0])); switch (card.uid[0]) { case 0x02: { // ST @@ -2711,10 +2216,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { break; } case 0x04: { // NXP - nxptype = detect_nxp_card_print(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), - select_status, card.ats_len - ats_hist_pos, card.ats + ats_hist_pos, - version_hw_available, &version_hw - ); + nxptype = detect_nxp_card_print(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status); isMifareMini = ((nxptype & MTMINI) == MTMINI); isMifareClassic = ((nxptype & MTCLASSIC) == MTCLASSIC); @@ -2849,9 +2351,26 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } } + // try to request ATS even if tag claims not to support it + if (select_status == 2) { + uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, sizeof(rats)); + if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { + PrintAndLogEx(WARNING, "timeout while waiting for reply"); + return PM3_ETIMEOUT; + } + + memcpy(card.ats, resp.data.asBytes, resp.oldarg[0]); + card.ats_len = resp.oldarg[0]; // note: ats_len includes CRC Bytes + if (card.ats_len > 3) { + select_status = 1; + } + } + if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLogEx(INFO, "-------------------------- " _CYAN_("ATS") " ----------------------------------"); + PrintAndLogEx(INFO, "-------------------------- " _CYAN_("ATS") " --------------------------"); bool ta1 = 0, tb1 = 0, tc1 = 0; if (select_status == 2) { @@ -2944,12 +2463,61 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { // ATS - Historial bytes and identify based on it if ((card.ats[0] > pos) && (card.ats_len >= card.ats[0] + 2)) { + char tip[60]; + tip[0] = '\0'; + if (card.ats[0] - pos >= 7) { + + snprintf(tip, sizeof(tip), " "); + + if ((card.sak & 0x70) == 0x40) { // and no GetVersion().. + + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus X 2K/4K (SL3)"); + + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + + if ((card.atqa[0] & 0x02) == 0x02) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 2K (SL3)"); + } else if ((card.atqa[0] & 0x04) == 0x04) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 4K (SL3)"); + } + + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (17pF)"); + + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (70pF)"); + } + + } else { //SAK B4,5,6 + + if ((card.sak & 0x20) == 0x20) { // and no GetVersion().. + + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus X 2K (SL1)"); + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 2K (SL1)"); + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (17pF)"); + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus SE 1K (70pF)"); + } + } else { + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus X 4K (SL1)"); + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + snprintf(tip + strlen(tip), sizeof(tip) - strlen(tip), _GREEN_("%s"), "MIFARE Plus S 4K (SL1)"); + } + } + } + } + uint8_t calen = card.ats[0] - pos; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "-------------------- " _CYAN_("Historical bytes") " ----------------------------"); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("Historical bytes") " --------------------"); if (card.ats[pos] == 0xC1) { - PrintAndLogEx(INFO, " %s", sprint_hex(card.ats + pos, calen)); + PrintAndLogEx(INFO, " %s%s", sprint_hex(card.ats + pos, calen), tip); PrintAndLogEx(SUCCESS, " C1..................... Mifare or (multiple) virtual cards of various type"); PrintAndLogEx(SUCCESS, " %02X.................. length is " _YELLOW_("%d") " bytes", card.ats[pos + 1], card.ats[pos + 1]); switch (card.ats[pos + 2] & 0xf0) { @@ -3051,7 +2619,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { uint16_t sw = 0; uint8_t result[1024] = {0}; size_t resultlen = 0; - res = Iso7816Select(CC_CONTACTLESS, ActivateField, true, vaid, vaidlen, result, sizeof(result), &resultlen, &sw); + int res = Iso7816Select(CC_CONTACTLESS, ActivateField, true, vaid, vaidlen, result, sizeof(result), &resultlen, &sw); ActivateField = false; if (res) continue; @@ -3103,9 +2671,8 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } DropField(); - if (verbose == false && found) { + if (verbose == false && found) PrintAndLogEx(INFO, "----------------------------------------------------"); - } } } @@ -3115,9 +2682,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { PrintAndLogEx(INFO, "proprietary iso18092 card found"); } else { - PrintAndLogEx(INFO, ""); - PrintAndLogEx(INFO, "Proprietary non iso14443-4 card found"); - PrintAndLogEx(INFO, "RATS not supported"); + PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported"); if ((card.sak & 0x20) == 0x20) { PrintAndLogEx(INFO, "--> SAK incorrectly claims that card supports RATS <--"); } @@ -3132,7 +2697,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { return PM3_EFAILED; } -// PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, ""); uint16_t isMagic = 0; @@ -3145,20 +2710,20 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } if (isMifareClassic || isMifareMini) { - res = detect_classic_static_nonce(); + int res = detect_classic_static_nonce(); if (res == NONCE_STATIC) { - PrintAndLogEx(SUCCESS, "Static nonce....... " _YELLOW_("yes")); + PrintAndLogEx(SUCCESS, "Static nonce......... " _YELLOW_("yes")); } if (res == NONCE_NORMAL) { // not static res = detect_classic_prng(); if (res == 1) { - PrintAndLogEx(SUCCESS, "Prng detection..... " _GREEN_("weak")); + PrintAndLogEx(SUCCESS, "Prng detection....... " _GREEN_("weak")); } else if (res == 0) { - PrintAndLogEx(SUCCESS, "Prng detection..... " _YELLOW_("hard")); + PrintAndLogEx(SUCCESS, "Prng detection....... " _YELLOW_("hard")); } else { - PrintAndLogEx(FAILED, "Prng detection...... " _RED_("fail")); + PrintAndLogEx(FAILED, "Prng detection........ " _RED_("fail")); } if (do_nack_test) { @@ -4340,7 +3905,7 @@ int CmdHF14AAIDSim(const char *Cmd) { bool keypress = kbd_enter_pressed(); while (keypress == false) { - if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false) { + if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) { continue; } diff --git a/client/src/cmdhf14a.h b/client/src/cmdhf14a.h index 2e438a2d6..21b33fc13 100644 --- a/client/src/cmdhf14a.h +++ b/client/src/cmdhf14a.h @@ -20,7 +20,7 @@ #define CMDHF14A_H__ #include "common.h" -#include "pm3_cmd.h" //hf14a_config_t +#include "pm3_cmd.h" //hf14a_config #include "mifare.h" // structs // structure and database for uid -> tagtype lookups @@ -36,16 +36,6 @@ typedef struct { const char *hint; } hintAIDList_t; -typedef struct { - uint8_t vendor_id; - uint8_t product_type; - uint8_t product_subtype; - uint8_t major_product_version; - uint8_t minor_product_version; - uint8_t storage_size; - uint8_t protocol_type; -} version_hw_t; - typedef enum { MTNONE = 0, MTCLASSIC = 1, @@ -59,9 +49,6 @@ typedef enum { MTFUDAN = 256, MTISO18092 = 512, MT424 = 1024, - MTULTRALIGHT_C = 2048, - MTDUOX = 4096, - MTNTAG = 8192, } nxp_mifare_type_t; int CmdHF14A(const char *Cmd); @@ -72,13 +59,10 @@ int CmdHF14ANdefRead(const char *Cmd); // used by cmdnfc.c int CmdHF14ANdefFormat(const char *Cmd); // used by cmdnfc.c int CmdHF14ANdefWrite(const char *Cmd); // used by cmdnfc.c +int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status); -int detect_nxp_card(uint8_t sak, uint16_t atqa, uint64_t select_status, - uint8_t ats_hist_len, uint8_t *ats_hist, - bool version_hw_available, version_hw_t *version_hw); - -int hf14a_getconfig(hf14a_config_t *config); -int hf14a_setconfig(hf14a_config_t *config, bool verbose); +int hf14a_getconfig(hf14a_config *config); +int hf14a_setconfig(hf14a_config *config, bool verbose); int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search); int infoHF14A4Applications(bool verbose); const char *getTagInfo(uint8_t uid); @@ -86,11 +70,10 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card); int ExchangeAPDU14a(const uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode); +iso14a_polling_parameters_t iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe); int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card); int SelectCard14443A_4_WithParameters(bool disconnect, bool verbose, iso14a_card_select_t *card, iso14a_polling_parameters_t *polling_parameters); bool Get_apdu_in_framing(void); void Set_apdu_in_framing(bool v); -int hf14a_getversion_data(iso14a_card_select_t *card, uint64_t select_status, version_hw_t *hw); - #endif diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index d64d200a7..cb0482cc3 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -1411,7 +1411,7 @@ static bool HF14B_ask_ct_reader(bool verbose) { return false; } -static bool HF14B_picopass_reader(bool verbose) { +bool HF14B_picopass_reader(bool verbose, bool info) { iso14b_raw_cmd_t packet = { .flags = (ISO14B_CONNECT | ISO14B_SELECT_PICOPASS | ISO14B_DISCONNECT), @@ -1437,8 +1437,10 @@ static bool HF14B_picopass_reader(bool verbose) { return false; } memcpy(card, resp.data.asBytes, sizeof(picopass_hdr_t)); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn))); + if (info) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn))); + } free(card); return true; } @@ -2708,32 +2710,25 @@ static int CmdHF14BCalypsoRead(const char *Cmd) { CLIParserFree(ctx); transport_14b_apdu_t cmds[] = { - {"01.Select ICC ", "\x94\xa4\x08\x00\x04\x3f\x00\x00\x02", 9}, - {"02.ICC ", "\x94\xb2\x01\x04\x1d", 5}, - {"03.Select EnvHol ", "\x94\xa4\x08\x00\x04\x20\x00\x20\x01", 9}, - {"04.EnvHol1 ", "\x94\xb2\x01\x04\x1d", 5}, - {"05.Select EvLog ", "\x94\xa4\x08\x00\x04\x20\x00\x20\x10", 9}, - {"06.EvLog1 ", "\x94\xb2\x01\x04\x1d", 5}, - {"07.EvLog2 ", "\x94\xb2\x02\x04\x1d", 5}, - {"08.EvLog3 ", "\x94\xb2\x03\x04\x1d", 5}, - {"09.Select ConList ", "\x94\xa4\x08\x00\x04\x20\x00\x20\x50", 9}, - {"10.ConList ", "\x94\xb2\x01\x04\x1d", 5}, - {"11.Select Contra ", "\x94\xa4\x08\x00\x04\x20\x00\x20\x20", 9}, - {"12.Contra1 ", "\x94\xb2\x01\x04\x1d", 5}, - {"13.Contra2 ", "\x94\xb2\x02\x04\x1d", 5}, - {"14.Contra3 ", "\x94\xb2\x03\x04\x1d", 5}, - {"15.Contra4 ", "\x94\xb2\x04\x04\x1d", 5}, - {"16.Select Counter ", "\x94\xa4\x08\x00\x04\x20\x00\x20\x69", 9}, - {"17.Counter ", "\x94\xb2\x01\x04\x1d", 5}, - {"18.Select SpecEv ", "\x94\xa4\x08\x00\x04\x20\x00\x20\x40", 9}, - {"19.SpecEv1 ", "\x94\xb2\x01\x04\x1d", 5}, - {"20.Select Purse ", "\x00\xa4\x00\x00\x02\x10\x15", 7}, - {"21.Purse1 ", "\x00\xb2\x01\x04\x1d", 5}, - {"22.Purse2 ", "\x00\xb2\x02\x04\x1d", 5}, - {"23.Purse3 ", "\x00\xb2\x03\x04\x1d", 5}, - {"24.Select Top Up ", "\x00\xa4\x00\x00\x02\x10\x14", 7}, - {"25.Topup1 ", "\x00\xb2\x01\x04\x1d", 5}, - {"26.Select 1TIC.ICA", "\x00\xa4\x04\x00\x08\x31\x54\x49\x43\x2e\x49\x43\x41", 13}, + {"01.Select ICC file", "\x94\xa4\x08\x00\x04\x3f\x00\x00\x02", 9}, + {"02.ICC", "\x94\xb2\x01\x04\x1d", 5}, + {"03.Select EnvHol file", "\x94\xa4\x08\x00\x04\x20\x00\x20\x01", 9}, + {"04.EnvHol1", "\x94\xb2\x01\x04\x1d", 5}, + {"05.Select EvLog file", "\x94\xa4\x08\x00\x04\x20\x00\x20\x10", 9}, + {"06.EvLog1", "\x94\xb2\x01\x04\x1d", 5}, + {"07.EvLog2", "\x94\xb2\x02\x04\x1d", 5}, + {"08.EvLog3", "\x94\xb2\x03\x04\x1d", 5}, + {"09.Select ConList file", "\x94\xa4\x08\x00\x04\x20\x00\x20\x50", 9}, + {"10.ConList", "\x94\xb2\x01\x04\x1d", 5}, + {"11.Select Contra file", "\x94\xa4\x08\x00\x04\x20\x00\x20\x20", 9}, + {"12.Contra1", "\x94\xb2\x01\x04\x1d", 5}, + {"13.Contra2", "\x94\xb2\x02\x04\x1d", 5}, + {"14.Contra3", "\x94\xb2\x03\x04\x1d", 5}, + {"15.Contra4", "\x94\xb2\x04\x04\x1d", 5}, + {"16.Select Counter file", "\x94\xa4\x08\x00\x04\x20\x00\x20\x69", 9}, + {"17.Counter", "\x94\xb2\x01\x04\x1d", 5}, + {"18.Select SpecEv file", "\x94\xa4\x08\x00\x04\x20\x00\x20\x40", 9}, + {"19.SpecEv1", "\x94\xb2\x01\x04\x1d", 5}, }; /* @@ -2787,8 +2782,9 @@ static int CmdHF14BCalypsoRead(const char *Cmd) { uint16_t sw = get_sw(response, resplen); if (sw != ISO7816_OK) { - PrintAndLogEx(INFO, "%s - command failed (%04x - %s).", cmds[i].desc, sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); - continue; + PrintAndLogEx(ERR, "Sending command failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + switch_off_field_14b(); + return PM3_ESOFT; } PrintAndLogEx(INFO, "%s - %s", cmds[i].desc, sprint_hex(response, resplen)); @@ -3033,15 +3029,14 @@ int infoHF14B(bool verbose, bool do_aid_search) { // try unknown 14b read commands (to be identified later) // could be read of calypso, CEPAS, moneo, or pico pass. - if (verbose) { - PrintAndLogEx(FAILED, "no 14443-B tag found"); - } + if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); return PM3_EOPABORTED; } // get and print general info about all known 14b chips int readHF14B(bool loop, bool verbose, bool read_plot) { bool found = false; + bool info = true; int res = PM3_SUCCESS; do { found = false; @@ -3057,7 +3052,7 @@ int readHF14B(bool loop, bool verbose, bool read_plot) { goto plot; // Picopass - found |= HF14B_picopass_reader(verbose); + found |= HF14B_picopass_reader(verbose, info); if (found) goto plot; @@ -3079,7 +3074,7 @@ plot: } } - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); if (verbose && found == false) { PrintAndLogEx(FAILED, "no ISO 14443-B tag found"); diff --git a/client/src/cmdhf14b.h b/client/src/cmdhf14b.h index 065dbc29c..067718507 100644 --- a/client/src/cmdhf14b.h +++ b/client/src/cmdhf14b.h @@ -31,5 +31,6 @@ int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card); int infoHF14B(bool verbose, bool do_aid_search); int readHF14B(bool loop, bool verbose, bool read_plot); +bool HF14B_picopass_reader(bool verbose, bool info); #endif diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index d27c8d049..25ee0a84f 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -50,6 +50,22 @@ #define Logic1 Iso15693Logic1 #define FrameEOF Iso15693FrameEOF #define CARD_MEMORY_SIZE 4096 +#define HF15_UID_LENGTH 8 + +#ifndef Crc15 +# define Crc15(data, len) Crc16ex(CRC_15693, (data), (len)) +#endif +#ifndef CheckCrc15 +# define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) +#endif +#ifndef AddCrc15 +#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) +#endif + +#ifndef ISO15_RAW_LEN +#define ISO15_RAW_LEN(x) (sizeof(iso15_raw_cmd_t) + (x)) +#endif + #ifndef ISO15_ERROR_HANDLING_RESPONSE #define ISO15_ERROR_HANDLING_RESPONSE { \ @@ -82,11 +98,6 @@ } #endif -typedef struct { - uint8_t lock; - uint8_t block[8]; -} t15memory_t; - // structure and database for uid -> tagtype lookups typedef struct { uint64_t uid; @@ -268,22 +279,22 @@ static int CmdHF15Help(const char *Cmd); static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) { int reason = 0; - int index = originality_check_verify(uid, 8, signature, 32, PK_15); + int index = originality_check_verify(uid, 8, signature, 32, PK_MFC); if (index >= 0) { reason = 1; } else { // try with sha256 - index = originality_check_verify_ex(uid, 8, signature, 32, PK_15, false, true); + index = originality_check_verify_ex(uid, 8, signature, 32, PK_MFC, false, true); if (index >= 0) { reason = 2; } else { // try with reversed uid / signature - index = originality_check_verify_ex(uid, 8, signature, 32, PK_15, true, false); + index = originality_check_verify_ex(uid, 8, signature, 32, PK_MFC, true, false); if (index >= 0) { reason = 3; } else { // try with sha256 and reversed uid / signature - index = originality_check_verify_ex(uid, 8, signature, 32, PK_15, true, true); + index = originality_check_verify_ex(uid, 8, signature, 32, PK_MFC, true, true); if (index >= 0) { reason = 3; } @@ -463,7 +474,7 @@ static int getUID(bool verbose, bool loop, uint8_t *buf) { // used with 'hf search' bool readHF15Uid(bool loop, bool verbose) { - uint8_t uid[ISO15693_UID_LENGTH] = {0}; + uint8_t uid[HF15_UID_LENGTH] = {0}; if (getUID(verbose, loop, uid) != PM3_SUCCESS) { return false; } @@ -654,7 +665,7 @@ static int NxpTestEAS(const uint8_t *uid) { return PM3_EINVARG; } - uint8_t approxlen = 3 + ISO15693_UID_LENGTH + 2; + uint8_t approxlen = 3 + HF15_UID_LENGTH + 2; iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); if (packet == NULL) { PrintAndLogEx(WARNING, "Failed to allocate memory"); @@ -666,8 +677,8 @@ static int NxpTestEAS(const uint8_t *uid) { packet->raw[packet->rawlen++] = ISO15693_EAS_ALARM; packet->raw[packet->rawlen++] = 0x04; // IC manufacturer code - memcpy(packet->raw + packet->rawlen, uid, ISO15693_UID_LENGTH); // add UID - packet->rawlen += ISO15693_UID_LENGTH; + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); // add UID + packet->rawlen += HF15_UID_LENGTH; AddCrc15(packet->raw, packet->rawlen); packet->rawlen += 2; @@ -709,7 +720,7 @@ static int NxpCheckSig(uint8_t *uid) { return PM3_EINVARG; } - uint8_t approxlen = 3 + ISO15693_UID_LENGTH + 2; + uint8_t approxlen = 3 + HF15_UID_LENGTH + 2; iso15_raw_cmd_t *packet = (iso15_raw_cmd_t *)calloc(1, sizeof(iso15_raw_cmd_t) + approxlen); if (packet == NULL) { PrintAndLogEx(WARNING, "Failed to allocate memory"); @@ -722,8 +733,8 @@ static int NxpCheckSig(uint8_t *uid) { packet->raw[packet->rawlen++] = ISO15693_READ_SIGNATURE; packet->raw[packet->rawlen++] = 0x04; // IC manufacturer code - memcpy(packet->raw + packet->rawlen, uid, ISO15693_UID_LENGTH); // add UID - packet->rawlen += ISO15693_UID_LENGTH; + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); // add UID + packet->rawlen += HF15_UID_LENGTH; AddCrc15(packet->raw, packet->rawlen); packet->rawlen += 2; @@ -776,7 +787,7 @@ static int NxpSysInfo(uint8_t *uid) { packet->raw[packet->rawlen++] = 0x04; // IC manufacturer code memcpy(packet->raw + 3, uid, 8); // add UID - packet->rawlen += ISO15693_UID_LENGTH; + packet->rawlen += HF15_UID_LENGTH; AddCrc15(packet->raw, packet->rawlen); packet->rawlen += 2; @@ -889,11 +900,11 @@ static int StCheckSig(uint8_t *uid) { } // ISO15693 Protocol params - packet->raw[packet->rawlen++] = arg_get_raw_flag(ISO15693_UID_LENGTH, false, false, false); + packet->raw[packet->rawlen++] = arg_get_raw_flag(HF15_UID_LENGTH, false, false, false); packet->raw[packet->rawlen++] = ISO15693_READBLOCK; // add UID (scan, uid) - memcpy(packet->raw + packet->rawlen, uid, ISO15693_UID_LENGTH); - packet->rawlen += ISO15693_UID_LENGTH; + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); + packet->rawlen += HF15_UID_LENGTH; packet->flags = (ISO15_CONNECT | ISO15_READ_RESPONSE | ISO15_NO_DISCONNECT); uint16_t blkoff = packet->rawlen; char signature_hex[65] = {0}; @@ -932,9 +943,9 @@ static int StCheckSig(uint8_t *uid) { uint8_t signature[16]; size_t signature_len; hexstr_to_byte_array(signature_hex, signature, &signature_len); - uint8_t uid_swap[ISO15693_UID_LENGTH]; - reverse_array_copy(uid, ISO15693_UID_LENGTH, uid_swap); - int index = originality_check_verify_ex(uid_swap, ISO15693_UID_LENGTH, signature, signature_len, PK_ST25TV, false, true); + uint8_t uid_swap[HF15_UID_LENGTH]; + reverse_array_copy(uid, HF15_UID_LENGTH, uid_swap); + int index = originality_check_verify_ex(uid_swap, HF15_UID_LENGTH, signature, signature_len, PK_ST25TV, false, true); PrintAndLogEx(NORMAL, ""); return originality_check_print(signature, signature_len, index); } @@ -959,7 +970,7 @@ static int CmdHF15Info(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); - uint8_t uid[ISO15693_UID_LENGTH]; + uint8_t uid[HF15_UID_LENGTH]; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); bool unaddressed = arg_get_lit(ctx, 2); @@ -976,7 +987,7 @@ static int CmdHF15Info(const char *Cmd) { } // default fallback to scan for tag. - if (unaddressed == false && uidlen != ISO15693_UID_LENGTH) { + if (unaddressed == false && uidlen != HF15_UID_LENGTH) { scan = true; } @@ -1003,10 +1014,10 @@ static int CmdHF15Info(const char *Cmd) { free(packet); return PM3_EINVARG; } - uidlen = ISO15693_UID_LENGTH; + uidlen = HF15_UID_LENGTH; } - if (uidlen == ISO15693_UID_LENGTH) { + if (uidlen == HF15_UID_LENGTH) { // add UID (scan, uid) memcpy(packet->raw + packet->rawlen, uid, uidlen); packet->rawlen += uidlen; @@ -1240,11 +1251,8 @@ static int CmdHF15ELoad(const char *Cmd) { ((tag->pagesCount * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE) || (tag->pagesCount == 0) || (tag->bytesPerPage == 0)) { - PrintAndLogEx(FAILED, "Tag size error: pagesCount=%d, bytesPerPage=%d", - tag->pagesCount, - tag->bytesPerPage - ); + tag->pagesCount, tag->bytesPerPage); free(tag); return PM3_EINVARG; } @@ -1478,7 +1486,7 @@ static int CmdHF15Sim(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); struct { - uint8_t uid[ISO15693_UID_LENGTH]; + uint8_t uid[HF15_UID_LENGTH]; uint8_t block_size; } PACKED payload; memset(&payload, 0, sizeof(payload)); @@ -1489,7 +1497,7 @@ static int CmdHF15Sim(const char *Cmd) { CLIParserFree(ctx); // sanity checks - if (uidlen != 0 && uidlen != ISO15693_UID_LENGTH) { + if (uidlen != 0 && uidlen != HF15_UID_LENGTH) { PrintAndLogEx(WARNING, "UID must include 8 hex bytes, got ( " _RED_("%i") " )", uidlen); return PM3_EINVARG; } @@ -1616,7 +1624,7 @@ static int CmdHF15WriteAfi(const char *Cmd) { struct { uint8_t pwd[4]; bool use_pwd; - uint8_t uid[ISO15693_UID_LENGTH]; + uint8_t uid[HF15_UID_LENGTH]; bool use_uid; uint8_t afi; } PACKED payload; @@ -1637,7 +1645,7 @@ static int CmdHF15WriteAfi(const char *Cmd) { } payload.use_uid = false; - if (uidlen == ISO15693_UID_LENGTH) { + if (uidlen == HF15_UID_LENGTH) { payload.use_uid = true; } @@ -1695,7 +1703,7 @@ static int CmdHF15WriteDsfid(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t uid[ISO15693_UID_LENGTH] = {0}; + uint8_t uid[HF15_UID_LENGTH] = {0}; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); @@ -1734,10 +1742,10 @@ static int CmdHF15WriteDsfid(const char *Cmd) { free(packet); return PM3_EINVARG; } - uidlen = ISO15693_UID_LENGTH; + uidlen = HF15_UID_LENGTH; } - if (uidlen == ISO15693_UID_LENGTH) { + if (uidlen == HF15_UID_LENGTH) { // add UID (scan, uid) memcpy(packet->raw + packet->rawlen, uid, uidlen); packet->rawlen += uidlen; @@ -1799,7 +1807,7 @@ static int CmdHF15Dump(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); - uint8_t uid[ISO15693_UID_LENGTH] = {0}; + uint8_t uid[HF15_UID_LENGTH] = {0}; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); @@ -1830,7 +1838,7 @@ static int CmdHF15Dump(const char *Cmd) { } // default fallback to scan for tag. - if (uidlen != ISO15693_UID_LENGTH && !unaddressed) { + if (uidlen != HF15_UID_LENGTH && !unaddressed) { scan = true; } @@ -1866,11 +1874,11 @@ static int CmdHF15Dump(const char *Cmd) { return PM3_EINVARG; } } else { - reverse_array(uid, ISO15693_UID_LENGTH); + reverse_array(uid, HF15_UID_LENGTH); } // add UID (scan, uid) - memcpy(packet->raw + packet->rawlen, uid, ISO15693_UID_LENGTH); - packet->rawlen += ISO15693_UID_LENGTH; + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); + packet->rawlen += HF15_UID_LENGTH; used_uid = true; } else { PrintAndLogEx(INFO, "Using unaddressed mode"); @@ -1907,49 +1915,35 @@ static int CmdHF15Dump(const char *Cmd) { uint8_t dCpt = 10; int res = iso15_error_handling_card_response(d, resp.length); - if (res == PM3_ECRC) { + if (res != PM3_SUCCESS) { free(tag); free(packet); return res; } - if (res == PM3_SUCCESS) { - memcpy(tag->uid, d + 2, 8); + memcpy(tag->uid, &d[2], 8); - if (d[1] & 0x01) { - tag->dsfid = d[dCpt]; - } - dCpt++; + if (d[1] & 0x01) { + tag->dsfid = d[dCpt++]; + } - if (d[1] & 0x02) { - tag->afi = d[dCpt]; - } - dCpt++; - - if (d[1] & 0x04) { - tag->pagesCount = d[dCpt] + 1; - tag->bytesPerPage = d[dCpt + 1] + 1; - } else { - // Set tag memory layout values (if can't be read in SYSINFO) - tag->bytesPerPage = blocksize; - tag->pagesCount = 128; - } - dCpt += 2; - - if (d[1] & 0x08) { - tag->ic = d[dCpt]; - } - dCpt++; + if (d[1] & 0x02) { + tag->afi = d[dCpt++]; + } + if (d[1] & 0x04) { + tag->pagesCount = d[dCpt++] + 1; + tag->bytesPerPage = d[dCpt++] + 1; } else { - tag->uid[0] = 0xE0; - tag->dsfid = 0; - tag->afi = 0; // Set tag memory layout values (if can't be read in SYSINFO) tag->bytesPerPage = blocksize; tag->pagesCount = 128; } + if (d[1] & 0x08) { + tag->ic = d[dCpt++]; + } + // add length for blockno (1) packet->rawlen++; packet->raw[0] |= ISO15_REQ_OPTION; // Add option to dump lock status @@ -2184,10 +2178,10 @@ static int CmdHF15Readmulti(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t uid[ISO15693_UID_LENGTH] = {0x00}; + uint8_t uid[HF15_UID_LENGTH] = {0x00}; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); - bool uid_set = (uidlen == ISO15693_UID_LENGTH) ? true : false; + bool uid_set = (uidlen == HF15_UID_LENGTH) ? true : false; bool unaddressed = arg_get_lit(ctx, 2); bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; //Default fallback to scan for tag. Overriding unaddressed parameter. @@ -2245,11 +2239,11 @@ static int CmdHF15Readmulti(const char *Cmd) { return PM3_EINVARG; } } else { - reverse_array(uid, ISO15693_UID_LENGTH); + reverse_array(uid, HF15_UID_LENGTH); } // add UID (scan, uid) - memcpy(packet->raw + packet->rawlen, uid, ISO15693_UID_LENGTH); - packet->rawlen += ISO15693_UID_LENGTH; + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); + packet->rawlen += HF15_UID_LENGTH; } else { PrintAndLogEx(INFO, "Using unaddressed mode"); @@ -2261,9 +2255,7 @@ static int CmdHF15Readmulti(const char *Cmd) { // 0 means 1 page, // 1 means 2 pages, ... - if (blockcnt > 0) { - blockcnt--; - } + if (blockcnt > 0) blockcnt--; packet->raw[packet->rawlen++] = blockno; packet->raw[packet->rawlen++] = blockcnt; @@ -2293,7 +2285,7 @@ static int CmdHF15Readmulti(const char *Cmd) { ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length) // 1 byte cmd, 1 lock byte, 4 / 8 bytes block size, 2 crc - if (resp.length > (1 + ((blockcnt + 1) * (blocksize + 1)) + 2)) { + if (resp.length > (1 + (blockcnt * (blocksize + 1)) + 2)) { PrintAndLogEx(WARNING, "got longer response. Check block size!"); } @@ -2344,10 +2336,10 @@ static int CmdHF15Readblock(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t uid[ISO15693_UID_LENGTH]; + uint8_t uid[HF15_UID_LENGTH]; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); - bool uid_set = (uidlen == ISO15693_UID_LENGTH) ? true : false; + bool uid_set = (uidlen == HF15_UID_LENGTH) ? true : false; bool unaddressed = arg_get_lit(ctx, 2); bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; // Default fallback to scan for tag. Overriding unaddressed parameter. @@ -2401,11 +2393,11 @@ static int CmdHF15Readblock(const char *Cmd) { return PM3_EINVARG; } } else { - reverse_array(uid, ISO15693_UID_LENGTH); + reverse_array(uid, HF15_UID_LENGTH); } // add UID (scan, uid) - memcpy(packet->raw + packet->rawlen, uid, ISO15693_UID_LENGTH); - packet->rawlen += ISO15693_UID_LENGTH; + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); + packet->rawlen += HF15_UID_LENGTH; } else { PrintAndLogEx(INFO, "Using unaddressed mode"); @@ -2498,8 +2490,8 @@ static int hf_15_write_blk(const uint8_t *pm3flags, uint16_t flags, const uint8_ // add UID if (uid) { - memcpy(packet->raw + packet->rawlen, uid, ISO15693_UID_LENGTH); - packet->rawlen += ISO15693_UID_LENGTH; + memcpy(packet->raw + packet->rawlen, uid, HF15_UID_LENGTH); + packet->rawlen += HF15_UID_LENGTH; } packet->raw[packet->rawlen++] = blockno; @@ -2558,10 +2550,10 @@ static int CmdHF15Write(const char *Cmd) { argtable[arglen++] = arg_param_end; CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t uid[ISO15693_UID_LENGTH]; + uint8_t uid[HF15_UID_LENGTH]; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); - bool uid_set = (uidlen == ISO15693_UID_LENGTH) ? true : false; + bool uid_set = (uidlen == HF15_UID_LENGTH) ? true : false; bool unaddressed = arg_get_lit(ctx, 2); bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; // Default fallback to scan for tag. Overriding unaddressed parameter. @@ -2597,7 +2589,7 @@ static int CmdHF15Write(const char *Cmd) { return PM3_EINVARG; } } else { - reverse_array(uid, ISO15693_UID_LENGTH); + reverse_array(uid, HF15_UID_LENGTH); } } else { PrintAndLogEx(INFO, "Using unaddressed mode"); @@ -2632,7 +2624,7 @@ static int CmdHF15Restore(const char *Cmd) { "hf 15 restore -u E011223344556677 -f hf-15-my-dump.bin" ); - void *argtable[6 + 4] = {0}; + void *argtable[6 + 5] = {0}; uint8_t arglen = arg_add_default(argtable); argtable[arglen++] = arg_str0("f", "file", "", "Specify a filename for dump file"); argtable[arglen++] = arg_int0("r", "retry", "", "number of retries (def 3)"); @@ -2640,7 +2632,7 @@ static int CmdHF15Restore(const char *Cmd) { argtable[arglen++] = arg_param_end; CLIExecWithReturn(ctx, Cmd, argtable, true); - uint8_t uid[ISO15693_UID_LENGTH]; + uint8_t uid[HF15_UID_LENGTH]; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); @@ -2670,7 +2662,7 @@ static int CmdHF15Restore(const char *Cmd) { // default fallback to scan for tag. // overriding unaddress parameter :) - if (uidlen != ISO15693_UID_LENGTH) { + if (uidlen != HF15_UID_LENGTH) { scan = true; } @@ -2682,7 +2674,7 @@ static int CmdHF15Restore(const char *Cmd) { return PM3_EINVARG; } } else { - reverse_array(uid, ISO15693_UID_LENGTH); + reverse_array(uid, HF15_UID_LENGTH); } } else { PrintAndLogEx(INFO, "Using unaddressed mode"); @@ -2721,11 +2713,8 @@ static int CmdHF15Restore(const char *Cmd) { ((tag->pagesCount * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE) || (tag->pagesCount == 0) || (tag->bytesPerPage == 0)) { - PrintAndLogEx(FAILED, "Tag size error: pagesCount=%d, bytesPerPage=%d", - tag->pagesCount, - tag->bytesPerPage - ); + tag->pagesCount, tag->bytesPerPage); free(tag); return PM3_EINVARG; } @@ -2756,8 +2745,8 @@ static int CmdHF15Restore(const char *Cmd) { for (tried = 0; tried < retries; tried++) { - retval = hf_15_write_blk(&pm3flags, flags, uid, fast, i, data, tag->bytesPerPage); - + retval = hf_15_write_blk(&pm3flags, flags, uid, fast + , i, data, tag->bytesPerPage); if (retval == PM3_SUCCESS) { PrintAndLogEx(INPLACE, "blk %3d", i); @@ -2820,7 +2809,7 @@ static int CmdHF15CSetUID(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, false); struct { - uint8_t uid[ISO15693_UID_LENGTH]; + uint8_t uid[HF15_UID_LENGTH]; } PACKED payload; int uidlen = 0; @@ -2828,7 +2817,7 @@ static int CmdHF15CSetUID(const char *Cmd) { bool use_v2 = arg_get_lit(ctx, 2); CLIParserFree(ctx); - if (uidlen != ISO15693_UID_LENGTH) { + if (uidlen != HF15_UID_LENGTH) { PrintAndLogEx(WARNING, "UID must include 8 hex bytes, got " _RED_("%i"), uidlen); return PM3_EINVARG; } @@ -2842,7 +2831,7 @@ static int CmdHF15CSetUID(const char *Cmd) { PrintAndLogEx(INFO, "Get current tag"); - uint8_t carduid[ISO15693_UID_LENGTH] = {0x00}; + uint8_t carduid[HF15_UID_LENGTH] = {0x00}; if (getUID(true, false, carduid) != PM3_SUCCESS) { PrintAndLogEx(FAILED, "no tag found"); return PM3_ESOFT; @@ -2872,10 +2861,10 @@ static int CmdHF15CSetUID(const char *Cmd) { } // reverse cardUID to compare - uint8_t revuid[ISO15693_UID_LENGTH] = {0}; + uint8_t revuid[HF15_UID_LENGTH] = {0}; reverse_array_copy(carduid, sizeof(carduid), revuid); - if (memcmp(revuid, payload.uid, ISO15693_UID_LENGTH) == 0) { + if (memcmp(revuid, payload.uid, HF15_UID_LENGTH) == 0) { PrintAndLogEx(SUCCESS, "Setting new UID ( " _GREEN_("ok") " )"); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS;; @@ -3489,11 +3478,8 @@ static int CmdHF15View(const char *Cmd) { ((tag->pagesCount * tag->bytesPerPage) > ISO15693_TAG_MAX_SIZE) || (tag->pagesCount == 0) || (tag->bytesPerPage == 0)) { - PrintAndLogEx(FAILED, "Tag size error: pagesCount=%d, bytesPerPage=%d", - tag->pagesCount, - tag->bytesPerPage - ); + tag->pagesCount, tag->bytesPerPage); free(tag); return PM3_EINVARG; } @@ -3512,15 +3498,15 @@ static int CmdHF15Wipe(const char *Cmd) { ); void *argtable[6 + 3] = {0}; uint8_t arglen = arg_add_default(argtable); - argtable[arglen++] = arg_int0(NULL, "bs", "", "block size (def 4)"); - argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); + argtable[arglen++] = arg_int0(NULL, "bs", "", "block size (def 4)"), + argtable[arglen++] = arg_lit0("v", "verbose", "verbose output"); argtable[arglen++] = arg_param_end; CLIExecWithReturn(ctx, Cmd, argtable, true); - uint8_t uid[ISO15693_UID_LENGTH]; + uint8_t uid[HF15_UID_LENGTH]; int uidlen = 0; CLIGetHexWithReturn(ctx, 1, uid, &uidlen); - bool uid_set = (uidlen == ISO15693_UID_LENGTH) ? true : false; + bool uid_set = (uidlen == HF15_UID_LENGTH) ? true : false; bool unaddressed = arg_get_lit(ctx, 2); bool scan = (arg_get_lit(ctx, 3) || (!uid_set && !unaddressed)) ? true : false; // Default fallback to scan for tag. Overriding unaddressed parameter. @@ -3552,7 +3538,7 @@ static int CmdHF15Wipe(const char *Cmd) { return PM3_EINVARG; } } else { - reverse_array(uid, ISO15693_UID_LENGTH); + reverse_array(uid, HF15_UID_LENGTH); } } else { PrintAndLogEx(INFO, "Using unaddressed mode"); diff --git a/client/src/cmdhf15.h b/client/src/cmdhf15.h index b6f7d250b..8803a58b4 100644 --- a/client/src/cmdhf15.h +++ b/client/src/cmdhf15.h @@ -20,24 +20,9 @@ #define CMDHF15_H__ #include "common.h" -#include "crc16.h" -#include "iso15.h" // typedef structs / enum - -#ifndef Crc15 -# define Crc15(data, len) Crc16ex(CRC_15693, (data), (len)) -#endif -#ifndef CheckCrc15 -# define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) -#endif -#ifndef AddCrc15 -#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) -#endif - -#ifndef ISO15_RAW_LEN -#define ISO15_RAW_LEN(x) (sizeof(iso15_raw_cmd_t) + (x)) -#endif int CmdHF15(const char *Cmd); + bool readHF15Uid(bool loop, bool verbose); #endif diff --git a/client/src/cmdhfcipurse.c b/client/src/cmdhfcipurse.c index 9e0ad8976..3f6e76ec2 100644 --- a/client/src/cmdhfcipurse.c +++ b/client/src/cmdhfcipurse.c @@ -1888,8 +1888,7 @@ static int CmdHFCipurseDefault(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help."}, - {"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("Operations") " -------------------"}, - {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Tag information"}, + {"info", CmdHFCipurseInfo, IfPm3Iso14443a, "Get info about CIPURSE tag"}, {"select", CmdHFCipurseSelect, IfPm3Iso14443a, "Select CIPURSE application or file"}, {"auth", CmdHFCipurseAuth, IfPm3Iso14443a, "Authenticate CIPURSE tag"}, {"read", CmdHFCipurseReadFile, IfPm3Iso14443a, "Read binary file"}, diff --git a/client/src/cmdhfcryptorf.c b/client/src/cmdhfcryptorf.c index 1a00881e1..af703e511 100644 --- a/client/src/cmdhfcryptorf.c +++ b/client/src/cmdhfcryptorf.c @@ -232,7 +232,8 @@ int readHFCryptoRF(bool loop, bool verbose) { PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex_inrow(card.uid, card.uidlen)); set_last_known_card(card); } - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); + DropField(); return res; } diff --git a/client/src/cmdhfemrtd.c b/client/src/cmdhfemrtd.c index 5d0182d56..896877a74 100644 --- a/client/src/cmdhfemrtd.c +++ b/client/src/cmdhfemrtd.c @@ -2449,9 +2449,8 @@ static int CmdHFeMRTDList(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"-----------", CmdHelp, IfPm3Iso14443, "------------------- " _CYAN_("Operations") " -------------------"}, {"dump", CmdHFeMRTDDump, IfPm3Iso14443, "Dump eMRTD files to binary files"}, - {"info", CmdHFeMRTDInfo, AlwaysAvailable, "Tag information"}, + {"info", CmdHFeMRTDInfo, AlwaysAvailable, "Display info about an eMRTD"}, {"list", CmdHFeMRTDList, AlwaysAvailable, "List ISO 14443A/7816 history"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhffelica.c b/client/src/cmdhffelica.c index 5c48bbefe..d52cb52da 100644 --- a/client/src/cmdhffelica.c +++ b/client/src/cmdhffelica.c @@ -29,28 +29,9 @@ #include "ui.h" #include "iso18.h" // felica_card_select_t struct #include "des.h" -#include "platform_util.h" #include "cliparser.h" // cliparser #include "util_posix.h" // msleep - -#define FELICA_BLK_SIZE 16 -#define FELICA_BLK_HALF (FELICA_BLK_SIZE/2) - -#define FELICA_BLK_NUMBER_RC 0x80 -#define FELICA_BLK_NUMBER_ID 0x82 -#define FELICA_BLK_NUMBER_WCNT 0x90 -#define FELICA_BLK_NUMBER_MACA 0x91 -#define FELICA_BLK_NUMBER_STATE 0x92 - -#define FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ (0b000001) -#define FELICA_SERVICE_ATTRIBUTE_READ_ONLY (0b000010) -#define FELICA_SERVICE_ATTRIBUTE_RANDOM_ACCESS (0b001000) -#define FELICA_SERVICE_ATTRIBUTE_CYCLIC (0b001100) -#define FELICA_SERVICE_ATTRIBUTE_PURSE (0b010000) -#define FELICA_SERVICE_ATTRIBUTE_PURSE_SUBFIELD (0b000110) - - #define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len)) static int CmdHelp(const char *Cmd); @@ -269,7 +250,6 @@ static const char *felica_model_name(uint8_t rom_type, uint8_t ic_type) { return "FeliCa Standard RC-S919"; case 0x0B: case 0x31: - case 0x36: return "Suica card (FeliCa Standard RC-S ?)"; default: break; @@ -368,7 +348,7 @@ int read_felica_uid(bool loop, bool verbose) { res = PM3_SUCCESS; } - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); DropField(); return res; @@ -493,7 +473,7 @@ static void print_rd_plain_response(felica_read_without_encryption_response_t *r temp = sprint_hex(rd_noCry_resp->block_element_number, sizeof(rd_noCry_resp->block_element_number)); strncpy(bl_element_number, temp, sizeof(bl_element_number) - 1); - PrintAndLogEx(INFO, " %s | %s ", bl_element_number, bl_data); + PrintAndLogEx(INFO, " %s | %s ", bl_element_number, bl_data); } else { PrintAndLogEx(SUCCESS, "IDm... %s", sprint_hex_inrow(rd_noCry_resp->frame_response.IDm, sizeof(rd_noCry_resp->frame_response.IDm))); PrintAndLogEx(SUCCESS, " Status flag 1... %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); @@ -551,28 +531,6 @@ int send_rd_plain(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose, } } -/** - * Sends a dump_service frame to the pm3 and prints response. - * @param flags to use for pm3 communication. - * @param datalen frame length. - * @param data frame to be send. - * @param verbose display additional output. - * @param dump_sv_resp frame in which the response will be saved. - * @param is_area true if the service is an area, false if it is a service. - * @return success if response was received. - */ -int send_dump_sv_plain(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose, felica_service_dump_response_t *dump_sv_resp, bool is_area) { - clear_and_send_command(flags, datalen, data, verbose); - PacketResponseNG resp; - if (waitCmdFelica(false, &resp, verbose) == false) { - PrintAndLogEx(ERR, "No response from card"); - return PM3_ERFTRANS; - } else { - memcpy(dump_sv_resp, (felica_service_dump_response_t *)resp.data.asBytes, sizeof(felica_service_dump_response_t)); - return PM3_SUCCESS; - } -} - /** * Checks if last known card can be added to data and adds it if possible. * @param custom_IDm @@ -1676,152 +1634,6 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) { return PM3_SUCCESS; } -/** - * Command parser for rqservice. - * @param Cmd input data of the user. - * @return client result code. - */ -static int CmdHFFelicaDump(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf felica dump", - "Dump all existing Area Code and Service Code.\n" - "Only works on services that do not require authentication yet.\n", - "hf felica dump"); - void *argtable[] = { - arg_param_begin, - arg_lit0(NULL, "no-auth", "read public services"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - - // bool no_auth = arg_get_lit(ctx, 1); - - uint8_t data_service_dump[PM3_CMD_DATA_SIZE] = {0}; - data_service_dump[0] = 0x0C; - data_service_dump[1] = 0x0A; - uint16_t service_datalen = 12; - if (!check_last_idm(data_service_dump, service_datalen)) - return PM3_EINVARG; - - uint8_t data_block_dump[PM3_CMD_DATA_SIZE] = {0}; - data_block_dump[0] = 0x10; // Static length - data_block_dump[1] = 0x06; // unauth read block command - data_block_dump[10] = 0x01; // read one service at a time - data_block_dump[13] = 0x01; // read one block at a time - data_block_dump[14] = 0x80; // block list element first byte - uint16_t block_datalen = 16; // Length (1), Command ID (1), IDm (8), Number of Service (1), Service Code List(2), Number of Block(1), Block List(3) - if (!check_last_idm(data_block_dump, block_datalen)) { - return PM3_EINVARG; - } - - uint8_t flags = FELICA_APPEND_CRC | FELICA_RAW; - - uint16_t cursor = 0x0000; - - felica_service_dump_response_t resp; - - while (true) { - - data_service_dump[10] = cursor & 0xFF; - data_service_dump[11] = cursor >> 8; - AddCrc(data_service_dump, service_datalen); - - if (send_dump_sv_plain(flags, service_datalen + 2, data_service_dump, 0, - &resp, false) != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "No response at cursor 0x%04X", cursor); - return PM3_ERFTRANS; - } - if (resp.frame_response.cmd_code[0] != 0x0B) { - PrintAndLogEx(FAILED, "Bad response cmd 0x%02X @ 0x%04X.", - resp.frame_response.cmd_code[0], cursor); - PrintAndLogEx(INFO, "This is a normal signal issue. Please try again."); - PrintAndLogEx(INFO, "If the issue persists, move the card around and check signal strength. FeliCa can be hard to keep in field."); - return PM3_ERFTRANS; - } - uint8_t len = resp.frame_response.length[0]; - uint16_t node_code = resp.payload[0] | (resp.payload[1] << 8); - if (node_code == 0xFFFF) break; - char attrib_str[64] = ""; - switch (len) { - case 0x0E: - break; - case 0x0C: { - uint8_t attribute = node_code & 0x3F; - bool is_public = (attribute & FELICA_SERVICE_ATTRIBUTE_UNAUTH_READ) != 0; - strcat(attrib_str, is_public ? "| Public " : "| Private "); - - bool is_purse = (attribute & FELICA_SERVICE_ATTRIBUTE_PURSE) != 0; - // Subfield bitwise attributes are applicable depending on is PURSE or not - - if (is_purse) { - strcat(attrib_str, "| Purse |"); - switch ((attribute & FELICA_SERVICE_ATTRIBUTE_PURSE_SUBFIELD) >> 1) { - case 0: - strcat(attrib_str, " Direct |"); - break; - case 1: - strcat(attrib_str, " Cashback |"); - break; - case 2: - strcat(attrib_str, " Decrement |"); - break; - case 3: - strcat(attrib_str, " Read Only |"); - break; - default: - strcat(attrib_str, " Unknown |"); - break; - } - } else { - bool is_random = (attribute & FELICA_SERVICE_ATTRIBUTE_RANDOM_ACCESS) != 0; - strcat(attrib_str, is_random ? "| Random |" : "| Cyclic |"); - bool is_readonly = (attribute & FELICA_SERVICE_ATTRIBUTE_READ_ONLY) != 0; - strcat(attrib_str, is_readonly ? " Read Only |" : " Read/Write |"); - } - - PrintAndLogEx(INFO, "Service %04X %s", node_code, attrib_str); - - if (is_public) { - // dump blocks here - PrintAndLogEx(INFO, " block | data "); - PrintAndLogEx(INFO, "-------+----------------------------------------"); - - data_block_dump[11] = resp.payload[0]; // convert service code to little endian - data_block_dump[12] = resp.payload[1]; - - uint16_t last_blockno = 0xFF; - for (uint16_t i = 0x00; i < last_blockno; i++) { - data_block_dump[15] = i; - AddCrc(data_block_dump, block_datalen); - felica_read_without_encryption_response_t rd_noCry_resp; - if ((send_rd_plain(flags, block_datalen + 2, data_block_dump, 0, &rd_noCry_resp) == PM3_SUCCESS)) { - if (rd_noCry_resp.status_flags.status_flag1[0] == 0 && rd_noCry_resp.status_flags.status_flag2[0] == 0) { - print_rd_plain_response(&rd_noCry_resp); - } else { - break; // no more blocks to read - } - } else { - break; - } - } - } - break; - } - default: - PrintAndLogEx(FAILED, "Unexpected length 0x%02X @ 0x%04X", - len, cursor); - return PM3_ERFTRANS; - } - cursor++; - if (cursor == 0) break; - } - - PrintAndLogEx(SUCCESS, "Unauth service dump complete."); - return PM3_SUCCESS; -} - - /** * Command parser for rqservice. * @param Cmd input data of the user. @@ -1931,119 +1743,18 @@ static int CmdHFFelicaRequestService(const char *Cmd) { return PM3_SUCCESS; } -/** - * Command parser for rqservice. - * @param Cmd input data of the user. - * @return client result code. - */ -static int CmdHFFelicaDumpServiceArea(const char *Cmd) { - /* -- CLI boilerplate (unchanged) ------------------------------- */ +static int CmdHFFelicaNotImplementedYet(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf felica scsvcode", - "Dump all existing Area Code and Service Code.\n", - "hf felica scsvcode"); - void *argtable[] = { arg_param_begin, arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); + "Feature not implemented yet. Feel free to contribute!", + "hf felica scsvcode" + ); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); CLIParserFree(ctx); - - /* -- build static part of Search-Service frame ---------------- */ - uint8_t data[PM3_CMD_DATA_SIZE] = {0}; - data[0] = 0x0C; /* LEN */ - data[1] = 0x0A; /* CMD = 0x0A */ - uint16_t datalen = 12; /* LEN + CMD + IDm + cursor */ - - if (!check_last_idm(data, datalen)) - return PM3_EINVARG; - - PrintAndLogEx(HINT, "Area and service code are printed in big endian."); - PrintAndLogEx(HINT, "Don't forget to convert to little endian when using hf felica rdbl."); - PrintAndLogEx(INFO, "┌───────────────────────────────────────────────"); - - uint8_t flags = FELICA_APPEND_CRC | FELICA_RAW; - - /* -- traversal state ------------------------------------------ */ - uint16_t cursor = 0x0000; - uint16_t area_end_stack[8] = {0xFFFF}; /* root “end” = 0xFFFF */ - int depth = 0; /* current stack depth */ - - felica_service_dump_response_t resp; - - while (true) { - - /* insert cursor LE */ - data[10] = cursor & 0xFF; - data[11] = cursor >> 8; - AddCrc(data, datalen); - - if (send_dump_sv_plain(flags, datalen + 2, data, 0, - &resp, false) != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "No response at cursor 0x%04X", cursor); - return PM3_ERFTRANS; - } - if (resp.frame_response.cmd_code[0] != 0x0B) { - PrintAndLogEx(FAILED, "Bad response cmd 0x%02X @ 0x%04X.", - resp.frame_response.cmd_code[0], cursor); - PrintAndLogEx(INFO, "This is a normal signal issue. Please try again."); - PrintAndLogEx(INFO, "If the issue persists, move the card around and check signal strength. FeliCa can be hard to keep in field."); - return PM3_ERFTRANS; - } - - uint8_t len = resp.frame_response.length[0]; - uint16_t node_code = resp.payload[0] | (resp.payload[1] << 8); - - if (node_code == 0xFFFF) break; /* end-marker */ - - /* pop finished areas */ - while (depth && node_code > area_end_stack[depth]) depth--; - - - /* ----- compose nice prefix ------------------------------------ */ - char prefix[64] = ""; - for (int i = 1; i < depth; i++) { - bool more_siblings = (cursor < area_end_stack[i]); - strcat(prefix, more_siblings ? "│ " : " "); - } - /* decide glyph for this line (areas always use └──) */ - const char *line_glyph = "├── "; - strcat(prefix, line_glyph); - - /* ----- print --------------------------------------------------- */ - if (len == 0x0E) { /* AREA node */ - uint16_t end_code = resp.payload[2] | (resp.payload[3] << 8); - PrintAndLogEx(INFO, "%sAREA_%04X", prefix, node_code >> 6); - - if (depth < 7) { - area_end_stack[++depth] = end_code; - } - } else if (len == 0x0C) { /* SERVICE */ - PrintAndLogEx(INFO, "%ssvc_%04X", prefix, node_code); - } else { - PrintAndLogEx(FAILED, "Unexpected length 0x%02X @ 0x%04X", - len, cursor); - return PM3_ERFTRANS; - } - cursor++; - if (cursor == 0) break; /* overflow safety */ - } - - /* draw closing bar └─┴─... based on final depth */ - char bar[128]; /* large enough for depth ≤ 7 */ - size_t pos = 0; - - /* leading corner */ - pos += snprintf(bar + pos, sizeof(bar) - pos, "└"); - - /* one segment per level-1 */ - for (int i = 0; i < depth - 1 && pos < sizeof(bar); i++) - pos += snprintf(bar + pos, sizeof(bar) - pos, "───┴"); - - /* tail */ - snprintf(bar + pos, sizeof(bar) - pos, "───────────────────────"); - - PrintAndLogEx(INFO, "%s", bar); - - - PrintAndLogEx(SUCCESS, "Service code and area dump complete."); return PM3_SUCCESS; } @@ -2092,7 +1803,7 @@ static int CmdHFFelicaSniff(const char *Cmd) { for (;;) { if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(DEBUG, "\naborted via keyboard!"); + PrintAndLogEx(DEBUG, "User aborted"); msleep(300); break; } @@ -2140,7 +1851,7 @@ static int CmdHFFelicaSimLite(const char *Cmd) { for (;;) { if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(DEBUG, "\naborted via keyboard!"); + PrintAndLogEx(DEBUG, "User aborted"); msleep(300); break; } @@ -2157,613 +1868,6 @@ static int CmdHFFelicaSimLite(const char *Cmd) { return PM3_SUCCESS; } -static int felica_make_block_list(uint16_t *out, const uint8_t *blk_numbers, const size_t length) { - if (length > 4) { - PrintAndLogEx(ERR, "felica_make_block_list: exceeds max size"); - return PM3_EINVARG; - } - - uint16_t tmp[4]; - memset(tmp, 0, sizeof(tmp)); - - for (size_t i = 0; i < length; i++) { - tmp[i] = (uint16_t)(blk_numbers[i] << 8) | 0x80; - } - memcpy(out, tmp, length * sizeof(uint16_t)); - - return PM3_SUCCESS; -} - -static int read_without_encryption( - const uint8_t *idm, - const uint8_t num, - const uint8_t *blk_numbers, - uint8_t *out, - uint16_t *n) { - - felica_read_request_haeder_t request = { - .command_code = { 0x06 }, - .number_of_service = { 1 }, - .service_code_list = { 0x00B }, - .number_of_block = { num }, - }; - memcpy(request.IDm, idm, sizeof(request.IDm)); - - uint16_t svc[num]; - int ret = felica_make_block_list(svc, blk_numbers, num); - if (ret) { - return PM3_EINVARG; - } - - size_t hdr_size = sizeof(request); - uint16_t size = hdr_size + sizeof(svc) + 1; - *n = size; - - memcpy(out, &(uint8_t) { size }, sizeof(uint8_t)); - memcpy(out + 1, &request, hdr_size); - memcpy(out + hdr_size + 1, &svc, sizeof(svc)); - - return PM3_SUCCESS; -} - -static bool check_write_req_data(const felica_write_request_haeder_t *hdr, const uint8_t datalen) { - if (!hdr || !datalen) - return false; - - uint8_t num = *(hdr->number_of_block); - if (num != 1 && num != 2) - return false; - - // Check Block data size - if (num * 16 != datalen) - return false; - - return true; -} - -static int write_without_encryption( - const uint8_t *idm, - uint8_t num, - uint8_t *blk_numbers, - const uint8_t *data, - size_t datalen, - uint8_t *out, - uint16_t *n) { - - felica_write_request_haeder_t hdr = { - .command_code = { 0x08 }, - .number_of_service = { 1 }, - .service_code_list = { 0x009 }, - .number_of_block = { num }, - }; - memcpy(hdr.IDm, idm, sizeof(hdr.IDm)); - - uint8_t dl = (uint8_t)(datalen); - - if (check_write_req_data(&hdr, dl) == false) { - PrintAndLogEx(FAILED, "invalid request"); - return PM3_EINVARG; - } - - uint16_t blk[num]; - int ret = felica_make_block_list(blk, blk_numbers, num); - if (ret) { - return PM3_EINVARG; - } - - - size_t hdr_size = sizeof(hdr); - size_t offset = hdr_size + (num * 2) + 1; - - uint8_t size = hdr_size + sizeof(blk) + dl + 1; - *n = size; - - memcpy(out, &(uint8_t) { size }, sizeof(uint8_t)); - memcpy(out + 1, &hdr, hdr_size); - memcpy(out + hdr_size + 1, &blk, sizeof(blk)); - memcpy(out + offset, data, dl); - - return PM3_SUCCESS; -} - -static int parse_multiple_block_data(const uint8_t *data, const size_t datalen, uint8_t *out, uint8_t *outlen) { - if (datalen < 3) { - PrintAndLogEx(ERR, "\ndata size must be at least 3 bytes"); - return PM3_EINVARG; - } - - felica_status_response_t res; - memcpy(&res, data, sizeof(res)); - - uint8_t empty[8] = {0}; - - if (!memcmp(res.frame_response.IDm, empty, sizeof(empty))) { - PrintAndLogEx(ERR, "internal error"); - return PM3_ERFTRANS; - } - - - if (res.status_flags.status_flag1[0] != 0x00 || res.status_flags.status_flag2[0] != 0x00) { - PrintAndLogEx(ERR, "error status"); - return PM3_ERFTRANS; - } - - size_t res_size = sizeof(res); - - uint8_t num = 0; - memcpy(&num, data + res_size, sizeof(uint8_t)); - res_size++; - - memcpy(out, data + res_size, num * FELICA_BLK_SIZE); - - if (outlen) { - *outlen = num * FELICA_BLK_SIZE; - } - - return PM3_SUCCESS; -} - -static int send_rd_multiple_plain(uint8_t flags, uint16_t datalen, uint8_t *data, uint8_t *out) { - clear_and_send_command(flags, datalen, data, false); - PacketResponseNG res; - if (waitCmdFelica(false, &res, false) == false) { - PrintAndLogEx(ERR, "\nGot no response from card"); - return PM3_ERFTRANS; - } - - uint8_t block_data[FELICA_BLK_SIZE * 4]; - memset(block_data, 0, sizeof(block_data)); - - uint8_t outlen = 0; - - int ret = parse_multiple_block_data(res.data.asBytes, sizeof(res.data.asBytes), block_data, &outlen); - if (ret) { - return PM3_ERFTRANS; - } - - memcpy(out, block_data, outlen); - - return PM3_SUCCESS; -} - -static int felica_auth_context_init( - mbedtls_des3_context *ctx, - const uint8_t *rc, - const size_t rclen, - const uint8_t *key, - const size_t keylen, - felica_auth_context_t *auth_ctx) { - - int ret = PM3_SUCCESS; - - uint8_t rev_rc[16], rev_key[16]; - uint8_t encrypted_sk[16], rev_sk[16]; - uint8_t iv[8] = {0}; - - if (!ctx || !auth_ctx || rclen != 16 || keylen != 16) { - PrintAndLogEx(ERR, "\nfelica_auth_context_init: invalid parameters"); - return PM3_EINVARG; - } - - SwapEndian64ex(rc, sizeof(rev_rc), 8, rev_rc); - memcpy(auth_ctx->random_challenge, rev_rc, sizeof(auth_ctx->random_challenge)); - - SwapEndian64ex(key, sizeof(rev_key), 8, rev_key); - - if (mbedtls_des3_set2key_enc(ctx, rev_key) != 0) { - ret = PM3_ECRYPTO; - goto cleanup; - } - - if (mbedtls_des3_crypt_cbc(ctx, MBEDTLS_DES_ENCRYPT, 16, iv, rev_rc, encrypted_sk) != 0) { - ret = PM3_ECRYPTO; - goto cleanup; - } - - SwapEndian64ex(encrypted_sk, sizeof(encrypted_sk), 8, rev_sk); - - memcpy(auth_ctx->session_key, rev_sk, sizeof(auth_ctx->session_key)); - -cleanup: - mbedtls_platform_zeroize(rev_rc, sizeof(rev_rc)); - mbedtls_platform_zeroize(rev_key, sizeof(rev_key)); - mbedtls_platform_zeroize(iv, sizeof(iv)); - mbedtls_platform_zeroize(encrypted_sk, sizeof(encrypted_sk)); - mbedtls_platform_zeroize(rev_sk, sizeof(rev_sk)); - - return ret; -} - -static void felica_auth_context_free(felica_auth_context_t *auth_ctx) { - if (!auth_ctx) { - return; - } - - mbedtls_platform_zeroize(auth_ctx->session_key, sizeof(auth_ctx->session_key)); - mbedtls_platform_zeroize(auth_ctx->random_challenge, sizeof(auth_ctx->random_challenge)); -} - -static int felica_generate_mac( - mbedtls_des3_context *ctx, - const felica_auth_context_t *auth_ctx, - const uint8_t *initialize_block, - const uint8_t *block_data, - const size_t length, - bool use_read_key, - uint8_t *mac) { - - int ret = PM3_SUCCESS; - - uint8_t rev_sk[FELICA_BLK_SIZE]; - uint8_t iv[8], rev_block[8], out[8]; - - if (!ctx || !auth_ctx || !initialize_block || !block_data || !mac) { - return PM3_EINVARG; - } - - if (length % FELICA_BLK_HALF != 0) { - return PM3_EINVARG; - } - - uint8_t sk[FELICA_BLK_SIZE]; - - if (use_read_key == false) { - memcpy(sk, auth_ctx->session_key + 8, 8); - memcpy(sk + 8, auth_ctx->session_key, 8); - } else { - memcpy(sk, auth_ctx->session_key, sizeof(auth_ctx->session_key)); - } - - SwapEndian64ex(sk, sizeof(sk), 8, rev_sk); - - memcpy(iv, auth_ctx->random_challenge, sizeof(iv)); - - SwapEndian64ex(initialize_block, sizeof(rev_block), 8, rev_block); - - if (mbedtls_des3_set2key_enc(ctx, rev_sk) != 0) { - ret = PM3_ECRYPTO; - goto cleanup; - } - - for (int i = 0; i <= length; i += 8) { - if (mbedtls_des3_crypt_cbc(ctx, MBEDTLS_DES_ENCRYPT, sizeof(rev_block), iv, rev_block, out) != 0) { - ret = PM3_ECRYPTO; - goto cleanup; - } - memcpy(iv, out, sizeof(iv)); - SwapEndian64ex(block_data + i, 8, 8, rev_block); - } - - SwapEndian64ex(out, FELICA_BLK_HALF, 8, mac); - -cleanup: - mbedtls_platform_zeroize(sk, sizeof(sk)); - mbedtls_platform_zeroize(rev_sk, sizeof(rev_sk)); - mbedtls_platform_zeroize(iv, sizeof(iv)); - mbedtls_platform_zeroize(out, sizeof(out)); - mbedtls_platform_zeroize(rev_block, sizeof(rev_block)); - - return ret; -} - -static int write_with_mac( - mbedtls_des3_context *ctx, - const felica_auth_context_t *auth_ctx, - const uint8_t *counter, - const uint8_t blk_number, - const uint8_t *block_data, - uint8_t *out) { - - uint8_t initialize_blk[FELICA_BLK_HALF]; - memset(initialize_blk, 0, sizeof(initialize_blk)); - - uint8_t wcnt[3]; - memcpy(wcnt, counter, 3); - - memcpy(initialize_blk, wcnt, sizeof(wcnt)); - initialize_blk[4] = blk_number; - initialize_blk[6] = 0x91; - - uint8_t mac[FELICA_BLK_HALF]; - - int ret = felica_generate_mac(ctx, auth_ctx, initialize_blk, block_data, FELICA_BLK_SIZE, false, mac); - if (ret != PM3_SUCCESS) { - return ret; - } - - uint8_t payload[FELICA_BLK_SIZE * 2]; - memset(payload, 0, sizeof(payload)); - - memcpy(payload, block_data, FELICA_BLK_SIZE); - memcpy(payload + FELICA_BLK_SIZE, mac, sizeof(mac)); - memcpy(payload + FELICA_BLK_SIZE + sizeof(mac), wcnt, sizeof(wcnt)); - - memcpy(out, payload, sizeof(payload)); - - return PM3_SUCCESS; -} - -static int felica_internal_authentication( - const uint8_t *idm, - const uint8_t *rc, - const size_t rclen, - mbedtls_des3_context *ctx, - const felica_auth_context_t *auth_ctx, - bool verbose) { - - uint8_t data[PM3_CMD_DATA_SIZE]; - memset(data, 0, sizeof(data)); - - uint8_t blk_numbers[1] = {FELICA_BLK_NUMBER_RC}; - - uint16_t datalen = 0; - - int ret = write_without_encryption(idm, (uint8_t)sizeof(blk_numbers), blk_numbers, rc, rclen, data, &datalen); - if (ret) { - return PM3_ERFTRANS; - } - - AddCrc(data, datalen); - datalen += 2; - - uint8_t flags = (FELICA_APPEND_CRC | FELICA_RAW | FELICA_NO_DISCONNECT); - - felica_status_response_t res; - if (send_wr_plain(flags, datalen, data, false, &res) != PM3_SUCCESS) { - return PM3_ERFTRANS; - } - - if (res.status_flags.status_flag1[0] != 0x00 && res.status_flags.status_flag2[0] != 0x00) { - PrintAndLogEx(ERR, "\nError RC Write"); - return PM3_ERFTRANS; - } - - memset(data, 0, sizeof(data)); - - uint8_t blk_numbers2[2] = {FELICA_BLK_NUMBER_ID, FELICA_BLK_NUMBER_MACA}; - - ret = read_without_encryption(idm, (uint8_t)sizeof(blk_numbers2), blk_numbers2, data, &datalen); - if (ret) { - return PM3_ERFTRANS; - } - - AddCrc(data, datalen); - datalen += 2; - - uint8_t pd[FELICA_BLK_SIZE * sizeof(blk_numbers2)]; - memset(pd, 0, sizeof(pd)); - - ret = send_rd_multiple_plain(flags, datalen, data, pd); - if (ret) { - return PM3_ERFTRANS; - } - - uint8_t id_blk[FELICA_BLK_SIZE]; - memcpy(id_blk, pd, FELICA_BLK_SIZE); - - uint8_t mac_blk[FELICA_BLK_SIZE]; - memcpy(mac_blk, pd + FELICA_BLK_SIZE, FELICA_BLK_SIZE); - - uint8_t initialize_blk[8]; - memset(initialize_blk, 0xFF, sizeof(initialize_blk)); - - initialize_blk[0] = FELICA_BLK_NUMBER_ID; - initialize_blk[1] = 0x00; - initialize_blk[2] = FELICA_BLK_NUMBER_MACA; - initialize_blk[3] = 0x00; - - uint8_t mac[FELICA_BLK_HALF]; - - ret = felica_generate_mac(ctx, auth_ctx, initialize_blk, id_blk, sizeof(id_blk), true, mac); - if (ret) { - return PM3_ERFTRANS; - } - - if (verbose) { - PrintAndLogEx(SUCCESS, "MAC_A: %s", sprint_hex(mac, sizeof(mac))); - } - - if (memcmp(mac_blk, mac, FELICA_BLK_HALF) != 0) { - PrintAndLogEx(ERR, "\nInternal Authenticate: " _RED_("Failed")); - return PM3_ERFTRANS; - } - - PrintAndLogEx(SUCCESS, "Internal Authenticate: " _GREEN_("OK")); - - return PM3_SUCCESS; -} - -static int felica_external_authentication( - const uint8_t *idm, - mbedtls_des3_context *ctx, - const felica_auth_context_t *auth_ctx, - bool keep) { - - uint8_t data[PM3_CMD_DATA_SIZE_MIX]; - memset(data, 0, sizeof(data)); - - uint8_t flags = (FELICA_APPEND_CRC | FELICA_RAW | FELICA_NO_DISCONNECT); - - uint16_t datalen = 0; - - uint8_t blk_numbers[1] = {FELICA_BLK_NUMBER_WCNT}; - - int ret = read_without_encryption(idm, (uint8_t)sizeof(blk_numbers), blk_numbers, data, &datalen); - if (ret) { - return PM3_ERFTRANS; - } - - AddCrc(data, datalen); - datalen += 2; - - uint8_t wcnt_blk[FELICA_BLK_SIZE]; - ret = send_rd_multiple_plain(flags, datalen, data, wcnt_blk); - if (ret) { - return PM3_ERFTRANS; - } - - uint8_t ext_auth[FELICA_BLK_SIZE]; - memset(ext_auth, 0, sizeof(ext_auth)); - - ext_auth[0] = 1; // After Authenticate - - uint8_t mac_w[FELICA_BLK_SIZE * 2]; - - ret = write_with_mac(ctx, auth_ctx, wcnt_blk, FELICA_BLK_NUMBER_STATE, ext_auth, mac_w); - if (ret) { - return PM3_ERFTRANS; - } - - uint8_t blk_numbers2[2] = {FELICA_BLK_NUMBER_STATE, FELICA_BLK_NUMBER_MACA}; - - ret = write_without_encryption(idm, (uint8_t)sizeof(blk_numbers2), blk_numbers2, mac_w, sizeof(mac_w), data, &datalen); - if (ret) { - return PM3_ERFTRANS; - } - - AddCrc(data, datalen); - datalen += 2; - - if (keep == false) { - flags &= ~FELICA_NO_DISCONNECT; - } - - felica_status_response_t res; - if (send_wr_plain(flags, datalen, data, false, &res) != PM3_SUCCESS) { - return PM3_ERFTRANS; - } - - if (res.status_flags.status_flag1[0] != 0x00 && res.status_flags.status_flag2[0] != 0x00) { - PrintAndLogEx(ERR, "\nExternal Authenticate: " _RED_("Failed")); - return PM3_ERFTRANS; - } - - PrintAndLogEx(SUCCESS, "External Authenticate: " _GREEN_("OK")); - - return PM3_SUCCESS; -} - -static int felica_mutual_authentication( - const uint8_t *idm, - const uint8_t *rc, - const size_t rclen, - const uint8_t *key, - const size_t keylen, - bool keep, - bool verbose) { - - int ret = PM3_SUCCESS; - - mbedtls_des3_context des3_ctx; - mbedtls_des3_init(&des3_ctx); - - felica_auth_context_t auth_ctx; - - ret = felica_auth_context_init(&des3_ctx, rc, rclen, key, keylen, &auth_ctx); - if (ret) { - goto cleanup; - } - - if (verbose) { - PrintAndLogEx(INFO, "Session Key(SK): %s", sprint_hex(auth_ctx.session_key, sizeof(auth_ctx.session_key))); - } - - ret = felica_internal_authentication(idm, rc, rclen, &des3_ctx, &auth_ctx, verbose); - if (ret) { - goto cleanup; - } - - ret = felica_external_authentication(idm, &des3_ctx, &auth_ctx, keep); - if (ret) { - goto cleanup; - } - -cleanup: - mbedtls_des3_free(&des3_ctx); - felica_auth_context_free(&auth_ctx); - - return ret; -} - -/** - * Command parser for liteauth. - * @param Cmd input data of the user. - * @return client result code. - */ -static int CmdHFFelicaAuthenticationLite(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf felica liteauth", - "Authenticate", - "hf felica liteauth -i 11100910C11BC407\n" - "hf felica liteauth --key 46656c69436130313233343536616263\n" - "hf felica liteauth --key 46656c69436130313233343536616263 -k\n" - "hf felica liteauth -c 701185c59f8d30afeab8e4b3a61f5cc4 --key 46656c69436130313233343536616263" - ); - void *argtable[] = { - arg_param_begin, - arg_str0(NULL, "key", "", "set card key, 16 bytes"), - arg_str0("c", "", "", "set random challenge, 16 bytes"), - arg_str0("i", "", "", "set custom IDm"), - arg_lit0("k", "", "keep signal field ON after receive"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - uint8_t key[FELICA_BLK_SIZE]; - memset(key, 0, sizeof(key)); - int keylen = 0; - int res = CLIParamHexToBuf(arg_get_str(ctx, 1), key, sizeof(key), &keylen); - if (res) { - CLIParserFree(ctx); - return PM3_EINVARG; - } - - uint8_t rc[FELICA_BLK_SIZE]; - memset(rc, 0, sizeof(rc)); - int rclen = 0; - res = CLIParamHexToBuf(arg_get_str(ctx, 2), rc, sizeof(rc), &rclen); - if (res) { - CLIParserFree(ctx); - return PM3_EINVARG; - } - - uint8_t idm[8]; - memset(idm, 0, sizeof(idm)); - int ilen = 0; - res = CLIParamHexToBuf(arg_get_str(ctx, 3), idm, sizeof(idm), &ilen); - if (res) { - CLIParserFree(ctx); - return PM3_EINVARG; - } - - bool keep_field_on = arg_get_lit(ctx, 4); - - CLIParserFree(ctx); - - if (!ilen) { - if (last_known_card.IDm[0] != 0 && last_known_card.IDm[1] != 0) { - memcpy(idm, last_known_card.IDm, sizeof(idm)); - } else { - PrintAndLogEx(WARNING, "No last known card! Use `" _YELLOW_("hf felica reader") "` first or set a custom IDm"); - return PM3_EINVARG; - } - } - - int ret = PM3_SUCCESS; - - PrintAndLogEx(INFO, "Card Key: %s", sprint_hex(key, sizeof(key))); - PrintAndLogEx(INFO, "Random Challenge(RC): %s", sprint_hex(rc, sizeof(rc))); - - PrintAndLogEx(SUCCESS, "FeliCa lite - auth started"); - - ret = felica_mutual_authentication(idm, rc, sizeof(rc), key, sizeof(key), keep_field_on, true); - if (ret) { - return PM3_EINVARG; - } - - return PM3_SUCCESS; -} - static void printSep(void) { PrintAndLogEx(INFO, "------------------------------------------------------------------------------------"); } @@ -2777,15 +1881,9 @@ static uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t trac uint8_t status1 = trace[1]; uint8_t status2 = trace[2]; - bool error = (status1 != 0x00 && (status2 == 0xB1 || status2 == 0xB2)); - char line[110] = {0}; for (int j = 0; j < 16; j++) { - if (error) { - snprintf(line + (j * 4), sizeof(line) - 1 - (j * 4), "?? "); - } else { - snprintf(line + (j * 4), sizeof(line) - 1 - (j * 4), "%02x ", trace[j + 3]); - } + snprintf(line + (j * 4), sizeof(line) - 1 - (j * 4), "%02x ", trace[j + 3]); } PrintAndLogEx(NORMAL, "block number %02x, status: %02x %02x", blocknum, status1, status2); @@ -2833,17 +1931,13 @@ static uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t trac PrintAndLogEx(NORMAL, "S_PAD13: %s", line); break; case 0x0E: { - uint32_t regA = trace[3] | trace[4] << 8 | trace[5] << 16 | trace[6] << 24; + uint32_t regA = trace[3] | trace[4] << 8 | trace[5] << 16 | trace[ 6] << 24; uint32_t regB = trace[7] | trace[8] << 8 | trace[9] << 16 | trace[10] << 24; line[0] = 0; for (int j = 0; j < 8; j++) snprintf(line + (j * 2), sizeof(line) - 1 - (j * 2), "%02x", trace[j + 11]); - if (error) { - PrintAndLogEx(NORMAL, "REG: regA: ???????? regB: ???????? regC: ???????????????? "); - } else { - PrintAndLogEx(NORMAL, "REG: regA: %d regB: %d regC: %s ", regA, regB, line); - } + PrintAndLogEx(NORMAL, "REG: regA: %d regB: %d regC: %s ", regA, regB, line); } break; case 0x80: @@ -2903,7 +1997,7 @@ static uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t trac } break; case 0x90: { - PrintAndLogEx(NORMAL, "Write counter, RO: %02x %02x %02x ", trace[3], trace[4], trace[5]); + PrintAndLogEx(NORMAL, "Write count, RO: %02x %02x %02x ", trace[3], trace[4], trace[5]); } break; case 0x91: { @@ -2942,52 +2036,11 @@ static int CmdHFFelicaDumpLite(const char *Cmd) { ); void *argtable[] = { arg_param_begin, - arg_str0("i", "", "", "set custom IDm"), - arg_str0(NULL, "key", "", "set card key, 16 bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - - uint8_t idm[8]; - memset(idm, 0, sizeof(idm)); - int ilen = 0; - int res = CLIParamHexToBuf(arg_get_str(ctx, 1), idm, sizeof(idm), &ilen); - if (res) { - CLIParserFree(ctx); - return PM3_EINVARG; - } - - uint8_t key[FELICA_BLK_SIZE]; - memset(key, 0, sizeof(key)); - int keylen = 0; - res = CLIParamHexToBuf(arg_get_str(ctx, 2), key, sizeof(key), &keylen); - if (res) { - CLIParserFree(ctx); - return PM3_EINVARG; - } - CLIParserFree(ctx); - if (keylen != 0) { - if (!ilen) { - if (last_known_card.IDm[0] != 0 && last_known_card.IDm[1] != 0) { - memcpy(idm, last_known_card.IDm, sizeof(idm)); - } else { - PrintAndLogEx(WARNING, "No last known card! Use `" _YELLOW_("hf felica reader") "` first or set a custom IDm"); - return PM3_EINVARG; - } - } - - uint8_t rc[FELICA_BLK_SIZE] = {0}; - - int ret = felica_mutual_authentication(idm, rc, sizeof(rc), key, sizeof(key), true, false); - if (ret) { - PrintAndLogEx(WARNING, "Authenticate Failed"); - } - } - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "FeliCa lite - dump started"); clearCommandBuffer(); @@ -3001,7 +2054,7 @@ static int CmdHFFelicaDumpLite(const char *Cmd) { if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(DEBUG, "\naborted via keyboard!"); + PrintAndLogEx(DEBUG, "User aborted"); return PM3_EOPABORTED; } @@ -3158,10 +2211,10 @@ static command_t CommandTable[] = { {"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"}, {"wrbl", CmdHFFelicaWritePlain, IfPm3Felica, "write block data to an authentication-not-required Service."}, {"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("FeliCa Standard") " -----------------------"}, - {"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"}, + //{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"}, {"rqservice", CmdHFFelicaRequestService, IfPm3Felica, "verify the existence of Area and Service, and to acquire Key Version."}, {"rqresponse", CmdHFFelicaRequestResponse, IfPm3Felica, "verify the existence of a card and its Mode."}, - {"scsvcode", CmdHFFelicaDumpServiceArea, IfPm3Felica, "acquire Area Code and Service Code."}, + {"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."}, {"rqsyscode", CmdHFFelicaRequestSystemCode, IfPm3Felica, "acquire System Code registered to the card."}, {"auth1", CmdHFFelicaAuthentication1, IfPm3Felica, "authenticate a card. Start mutual authentication with Auth1"}, {"auth2", CmdHFFelicaAuthentication2, IfPm3Felica, "allow a card to authenticate a Reader/Writer. Complete mutual authentication"}, @@ -3178,7 +2231,6 @@ static command_t CommandTable[] = { //{"uprandomid", CmdHFFelicaNotImplementedYet, IfPm3Felica, "update Random ID (IDr)."}, {"-----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("FeliCa Light") " -----------------------"}, {"litesim", CmdHFFelicaSimLite, IfPm3Felica, "Emulating ISO/18092 FeliCa Lite tag"}, - {"liteauth", CmdHFFelicaAuthenticationLite, IfPm3Felica, "authenticate a card."}, {"litedump", CmdHFFelicaDumpLite, IfPm3Felica, "Wait for and try dumping FelicaLite"}, // {"sim", CmdHFFelicaSim, IfPm3Felica, " -- Simulate ISO 18092/FeliCa tag"} {NULL, NULL, NULL, NULL} diff --git a/client/src/cmdhffelica.h b/client/src/cmdhffelica.h index 6ab42aa36..9cb524814 100644 --- a/client/src/cmdhffelica.h +++ b/client/src/cmdhffelica.h @@ -26,6 +26,5 @@ int CmdHFFelica(const char *Cmd); int read_felica_uid(bool loop, bool verbose); int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose); int send_rd_plain(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose, felica_read_without_encryption_response_t *rd_noCry_resp); -int send_dump_sv_plain(uint8_t flags, uint16_t datalen, uint8_t *data, bool verbose, felica_service_dump_response_t *dump_sv_resp, bool is_area); #endif diff --git a/client/src/cmdhffido.c b/client/src/cmdhffido.c index 54560354b..2032dca95 100644 --- a/client/src/cmdhffido.c +++ b/client/src/cmdhffido.c @@ -913,8 +913,7 @@ static int CmdHFFido2GetAssertion(const char *cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help."}, {"list", CmdHFFidoList, AlwaysAvailable, "List ISO 14443A history"}, - {"-----------", CmdHelp, IfPm3Iso14443a, "------------------- " _CYAN_("Operations") " -------------------"}, - {"info", CmdHFFidoInfo, IfPm3Iso14443a, "Tag information"}, + {"info", CmdHFFidoInfo, IfPm3Iso14443a, "Info about FIDO tag."}, {"reg", CmdHFFidoRegister, IfPm3Iso14443a, "FIDO U2F Registration Message."}, {"auth", CmdHFFidoAuthenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."}, {"make", CmdHFFido2MakeCredential, IfPm3Iso14443a, "FIDO2 MakeCredential command."}, diff --git a/client/src/cmdhffudan.c b/client/src/cmdhffudan.c index 817749353..52ed3bc5f 100644 --- a/client/src/cmdhffudan.c +++ b/client/src/cmdhffudan.c @@ -199,7 +199,7 @@ int read_fudan_uid(bool loop, bool verbose) { PrintAndLogEx(NORMAL, ""); } - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); return PM3_SUCCESS; diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index d4bc1da45..b21282ce2 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -40,21 +40,19 @@ #include "crypto/asn1utils.h" // ASN1 decoder #include "preferences.h" #include "generator.h" +#include "cmdhf14b.h" #include "cmdhw.h" #include "hidsio.h" -#define ICLASS_DEBIT_KEYTYPE ( 0x88 ) -#define ICLASS_CREDIT_KEYTYPE ( 0x18 ) - #define NUM_CSNS 9 #define MAC_ITEM_SIZE 24 // csn(8) + epurse(8) + nr(4) + mac(4) = 24 bytes #define ICLASS_KEYS_MAX 8 #define ICLASS_AUTH_RETRY 10 #define ICLASS_CFG_BLK_SR_BIT 0xA0 // indicates SIO present when set in block6[0] (legacy tags) -#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin" -#define ICLASS_DEFAULT_KEY_DIC "iclass_default_keys.dic" -#define ICLASS_DEFAULT_KEY_ELITE_DIC "iclass_elite_keys.dic" +#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin" +#define ICLASS_DEFAULT_KEY_DIC "iclass_default_keys.dic" +#define ICLASS_DEFAULT_KEY_ELITE_DIC "iclass_elite_keys.dic" static void print_picopass_info(const picopass_hdr_t *hdr); void print_picopass_header(const picopass_hdr_t *hdr); @@ -327,29 +325,6 @@ static const iclass_config_card_item_t *get_config_card_item(int idx) { static void print_config_cards(void) { PrintAndLogEx(INFO, "---- " _CYAN_("Config cards options") " ------------"); for (int i = 0; i < ARRAYLEN(iclass_config_options) ; ++i) { - switch (i) { - case 0: - PrintAndLogEx(INFO, _YELLOW_("---- LED Operations ----")); - break; - case 16: - PrintAndLogEx(INFO, _YELLOW_("---- BEEP Operations ----")); - break; - case 18: - PrintAndLogEx(INFO, _YELLOW_("---- Mifare Operations ----")); - break; - case 22: - PrintAndLogEx(INFO, _YELLOW_("---- Keypad Operations ----")); - break; - case 25: - PrintAndLogEx(INFO, _YELLOW_("---- iClass Operations ----")); - break; - case 29: - PrintAndLogEx(INFO, _YELLOW_("---- Reset Operations ----")); - break; - case 31: - PrintAndLogEx(INFO, _YELLOW_("---- iClass Master Key Operations ----")); - break; - } PrintAndLogEx(INFO, "%2d, %s", i, iclass_config_options[i].desc); } PrintAndLogEx(NORMAL, ""); @@ -609,14 +584,14 @@ static void fuse_config(const picopass_hdr_t *hdr) { uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]); - PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8)); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit); - PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas); - PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses); + PrintAndLogEx(INFO, " Raw... " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8)); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit); + PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses); uint8_t fuses = hdr->conf.fuses; @@ -727,7 +702,7 @@ static void mem_app_config(const picopass_hdr_t *hdr) { uint8_t app2_limit = card_app2_limit[type]; uint8_t pagemap = get_pagemap(hdr); - PrintAndLogEx(INFO, "------------------------ " _CYAN_("Memory") " -------------------------"); + PrintAndLogEx(INFO, "-------------------------- " _CYAN_("Memory") " --------------------------"); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { PrintAndLogEx(INFO, " %u KBits ( " _YELLOW_("%u") " bytes )", kb, app2_limit * 8); @@ -756,7 +731,7 @@ static void mem_app_config(const picopass_hdr_t *hdr) { [=] AA2 blocks 5 { 0x100 - 0xFF (256 - 255) } */ - PrintAndLogEx(INFO, "----------------------- " _CYAN_("KeyAccess") " -----------------------"); + PrintAndLogEx(INFO, "------------------------- " _CYAN_("KeyAccess") " ------------------------"); PrintAndLogEx(INFO, " * Kd, Debit key, AA1 Kc, Credit key, AA2 *"); uint8_t keyAccess = isset(mem, 0x01); if (keyAccess) { @@ -777,13 +752,13 @@ static void mem_app_config(const picopass_hdr_t *hdr) { } void print_picopass_info(const picopass_hdr_t *hdr) { - PrintAndLogEx(INFO, "------------------- " _CYAN_("Card configuration") " ------------------"); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("Card configuration") " --------------------"); fuse_config(hdr); mem_app_config(hdr); } void print_picopass_header(const picopass_hdr_t *hdr) { - PrintAndLogEx(INFO, "-------------------------- " _CYAN_("Card") " -------------------------"); + PrintAndLogEx(INFO, "--------------------------- " _CYAN_("Card") " ---------------------------"); PrintAndLogEx(SUCCESS, " CSN... " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); PrintAndLogEx(SUCCESS, " Config... %s card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); PrintAndLogEx(SUCCESS, "E-purse... %s card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); @@ -791,13 +766,13 @@ void print_picopass_header(const picopass_hdr_t *hdr) { if (memcmp(hdr->key_d, zeros, sizeof(zeros)) && memcmp(hdr->key_d, empty, sizeof(empty))) { PrintAndLogEx(SUCCESS, " Kd... " _YELLOW_("%s") " debit key", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); } else { - PrintAndLogEx(SUCCESS, " Kd... -- -- -- -- -- -- -- -- debit key ( hidden )"); + PrintAndLogEx(SUCCESS, " Kd... %s debit key ( hidden )", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); } if (memcmp(hdr->key_c, zeros, sizeof(zeros)) && memcmp(hdr->key_c, empty, sizeof(empty))) { PrintAndLogEx(SUCCESS, " Kc... " _YELLOW_("%s") " credit key", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); } else { - PrintAndLogEx(SUCCESS, " Kc... -- -- -- -- -- -- -- -- credit key ( hidden )"); + PrintAndLogEx(SUCCESS, " Kc... %s credit key ( hidden )", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); } PrintAndLogEx(SUCCESS, " AIA... %s application issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); @@ -867,9 +842,7 @@ static int CmdHFiClassSim(const char *Cmd) { "hf iclass sim -t 1 --> simulate with default CSN\n" "hf iclass sim -t 2 --> execute loclass attack online part\n" "hf iclass sim -t 3 --> simulate full iCLASS 2k tag\n" - "hf iclass sim -t 4 --> Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key\n" - "hf iclass sim -t 6 --> simulate full iCLASS 2k tag that doesn't respond to r/w requests to the last SIO block\n" - "hf iclass sim -t 7 --> simulate full iCLASS 2k tag that doesn't XOR or respond to r/w requests on block 3"); + "hf iclass sim -t 4 --> Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key"); void *argtable[] = { arg_param_begin, @@ -900,7 +873,7 @@ static int CmdHFiClassSim(const char *Cmd) { CLIParserFree(ctx); - if (sim_type > 4 && sim_type != 6 && sim_type != 7) { + if (sim_type > 4) { PrintAndLogEx(ERR, "Undefined simtype %d", sim_type); return PM3_EINVARG; } @@ -1053,8 +1026,6 @@ static int CmdHFiClassSim(const char *Cmd) { case ICLASS_SIM_MODE_CSN: case ICLASS_SIM_MODE_CSN_DEFAULT: case ICLASS_SIM_MODE_FULL: - case ICLASS_SIM_MODE_FULL_GLITCH: - case ICLASS_SIM_MODE_FULL_GLITCH_KEY: default: { PrintAndLogEx(INFO, "Starting iCLASS simulation"); PrintAndLogEx(INFO, "Press " _GREEN_("`pm3 button`") " to abort"); @@ -1062,7 +1033,7 @@ static int CmdHFiClassSim(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, numberOfCSNs, 1, csn, 8); - if (sim_type == ICLASS_SIM_MODE_FULL || sim_type == ICLASS_SIM_MODE_FULL_GLITCH || sim_type == ICLASS_SIM_MODE_FULL_GLITCH_KEY) + if (sim_type == ICLASS_SIM_MODE_FULL) PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf iclass esave -h") "` to save the emulator memory to file"); break; } @@ -1135,7 +1106,7 @@ int read_iclass_csn(bool loop, bool verbose, bool shallow_mod) { res = PM3_EMALLOC; } } - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); DropField(); return res; @@ -1496,9 +1467,8 @@ static void iclass_decode_credentials(uint8_t *data) { bool has_values = (memcmp(b7, empty, PICOPASS_BLOCK_SIZE) != 0) && (memcmp(b7, zeros, PICOPASS_BLOCK_SIZE) != 0); if (has_values && encryption == None) { - PrintAndLogEx(INFO, "------------------------ " _CYAN_("Block 7 decoder") " --------------------------"); - // todo: remove preamble/sentinel + PrintAndLogEx(INFO, "------------------------ " _CYAN_("Block 7 decoder") " --------------------------"); if (has_new_pacs) { iclass_decode_credentials_new_pacs(b7); } else { @@ -1517,6 +1487,9 @@ static void iclass_decode_credentials(uint8_t *data) { PrintAndLogEx(NORMAL, ""); decode_wiegand(top, mid, bot, 0); } + + } else { + PrintAndLogEx(INFO, "No unencrypted legacy credential found"); } } @@ -1883,17 +1856,15 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose, bool shallow_ return false; } - if (CSN != NULL) { - memcpy(CSN, hdr->csn, PICOPASS_BLOCK_SIZE); - } + if (CSN != NULL) + memcpy(CSN, hdr->csn, 8); - if (CCNR != NULL) { - memcpy(CCNR, hdr->epurse, PICOPASS_BLOCK_SIZE); - } + if (CCNR != NULL) + memcpy(CCNR, hdr->epurse, 8); if (verbose) { - PrintAndLogEx(SUCCESS, "CSN............ %s", sprint_hex_inrow(CSN, PICOPASS_BLOCK_SIZE)); - PrintAndLogEx(SUCCESS, "E-purse........ %s", sprint_hex_inrow(CCNR, PICOPASS_BLOCK_SIZE)); + PrintAndLogEx(SUCCESS, "CSN %s", sprint_hex(CSN, 8)); + PrintAndLogEx(SUCCESS, "epurse %s", sprint_hex(CCNR, 8)); } return true; } @@ -1932,32 +1903,15 @@ static int CmdHFiClassDump(const char *Cmd) { int key_len = 0; uint8_t key[8] = {0}; + bool auth = false; + CLIGetHexWithReturn(ctx, 2, key, &key_len); int deb_key_nr = arg_get_int_def(ctx, 3, -1); - int credit_key_len = 0; - uint8_t credit_key[8] = {0}; - CLIGetHexWithReturn(ctx, 4, credit_key, &credit_key_len); - - int credit_key_nr = arg_get_int_def(ctx, 5, -1); - bool elite = arg_get_lit(ctx, 6); - bool rawkey = arg_get_lit(ctx, 7); - bool use_replay = arg_get_lit(ctx, 8); - bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9); - bool force = arg_get_lit(ctx, 10); - bool shallow_mod = arg_get_lit(ctx, 11); - bool nosave = arg_get_lit(ctx, 12); - - CLIParserFree(ctx); - - bool auth = false; - bool have_credit_key = false; - - // Sanity checks - if (key_len > 0 && deb_key_nr >= 0) { PrintAndLogEx(ERR, "Please specify debit key or index, not both"); + CLIParserFree(ctx); return PM3_EINVARG; } @@ -1965,6 +1919,7 @@ static int CmdHFiClassDump(const char *Cmd) { auth = true; if (key_len != 8) { PrintAndLogEx(ERR, "Debit key is incorrect length"); + CLIParserFree(ctx); return PM3_EINVARG; } } @@ -1976,12 +1931,22 @@ static int CmdHFiClassDump(const char *Cmd) { PrintAndLogEx(SUCCESS, "Using AA1 (debit) key[%d] " _GREEN_("%s"), deb_key_nr, sprint_hex(iClass_Key_Table[deb_key_nr], 8)); } else { PrintAndLogEx(ERR, "Key number is invalid"); + CLIParserFree(ctx); return PM3_EINVARG; } } + int credit_key_len = 0; + uint8_t credit_key[8] = {0}; + bool have_credit_key = false; + + CLIGetHexWithReturn(ctx, 4, credit_key, &credit_key_len); + + int credit_key_nr = arg_get_int_def(ctx, 5, -1); + if (credit_key_len > 0 && credit_key_nr >= 0) { PrintAndLogEx(ERR, "Please specify credit key or index, not both"); + CLIParserFree(ctx); return PM3_EINVARG; } @@ -1990,6 +1955,7 @@ static int CmdHFiClassDump(const char *Cmd) { have_credit_key = true; if (credit_key_len != 8) { PrintAndLogEx(ERR, "Credit key is incorrect length"); + CLIParserFree(ctx); return PM3_EINVARG; } } @@ -2002,10 +1968,21 @@ static int CmdHFiClassDump(const char *Cmd) { PrintAndLogEx(SUCCESS, "Using AA2 (credit) key[%d] " _GREEN_("%s"), credit_key_nr, sprint_hex(iClass_Key_Table[credit_key_nr], 8)); } else { PrintAndLogEx(ERR, "Key number is invalid"); + CLIParserFree(ctx); return PM3_EINVARG; } } + bool elite = arg_get_lit(ctx, 6); + bool rawkey = arg_get_lit(ctx, 7); + bool use_replay = arg_get_lit(ctx, 8); + bool dense_output = g_session.dense_output || arg_get_lit(ctx, 9); + bool force = arg_get_lit(ctx, 10); + bool shallow_mod = arg_get_lit(ctx, 11); + bool nosave = arg_get_lit(ctx, 12); + + CLIParserFree(ctx); + if ((use_replay + rawkey + elite) > 1) { PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'"); return PM3_EINVARG; @@ -2028,6 +2005,7 @@ static int CmdHFiClassDump(const char *Cmd) { clearCommandBuffer(); PacketResponseNG resp; SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload_rdr, sizeof(iclass_card_select_t)); + if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) { PrintAndLogEx(WARNING, "command execution time out"); DropField(); @@ -2084,11 +2062,9 @@ static int CmdHFiClassDump(const char *Cmd) { PrintAndLogEx(INFO, "No keys needed, ignoring user supplied key"); } } else { - if (auth == false) { - auth = true; - memcpy(key, iClass_Key_Table[0], 8); - PrintAndLogEx(SUCCESS, "Default to AA1 (debit) " _GREEN_("%s"), sprint_hex(key, sizeof(key))); + PrintAndLogEx(FAILED, "Run command with keys"); + return PM3_ESOFT; } if (app_limit2 != 0) { @@ -2130,9 +2106,8 @@ static int CmdHFiClassDump(const char *Cmd) { return PM3_EOPABORTED; } - if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_DUMP, &resp, 2000)) break; - } } PrintAndLogEx(NORMAL, ""); @@ -2159,7 +2134,7 @@ static int CmdHFiClassDump(const char *Cmd) { uint8_t tempbuf[0x100 * 8]; // response ok - now get bigbuf content of the dump - if (GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false) == false) { + if (!GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } @@ -2224,7 +2199,7 @@ static int CmdHFiClassDump(const char *Cmd) { } // get dumped data from bigbuf - if (GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false) == false) { + if (!GetFromDevice(BIG_BUF, tempbuf, sizeof(tempbuf), startindex, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); goto write_dump; } @@ -2274,8 +2249,7 @@ write_dump: return PM3_SUCCESS; } -static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata, uint8_t *KEY, bool use_credit_key, - bool elite, bool rawkey, bool replay, bool verbose, bool use_secure_pagemode, bool shallow_mod) { +static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose, bool use_secure_pagemode, bool shallow_mod) { iclass_writeblock_req_t payload = { .req.use_raw = rawkey, @@ -2298,7 +2272,7 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == false) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == 0) { if (verbose) PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } @@ -2329,7 +2303,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { arg_lit0(NULL, "credit", "key is assumed to be the credit key"), arg_lit0(NULL, "elite", "elite computations applied to key"), arg_lit0(NULL, "raw", "no computations applied to key"), - arg_lit0(NULL, "nr", "replay of NR/MAC block write or use privilege escalation if mac is empty"), + arg_lit0(NULL, "nr", "replay of NR/MAC"), arg_lit0("v", "verbose", "verbose output"), arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"), arg_param_end @@ -2432,13 +2406,14 @@ static int CmdHFiClassCreditEpurse(const char *Cmd) { "Credit the epurse on an iCLASS tag. The provided key must be the credit key.\n" "The first two bytes of the epurse are the debit value (big endian) and may be any value except FFFF.\n" "The remaining two bytes of the epurse are the credit value and must be smaller than the previous value.", - "hf iclass creditepurse --ki 0 -d FEFFFEFF"); + "hf iclass creditepurse -d FEFFFFFF -k 001122334455667B\n" + "hf iclass creditepurse -d FEFFFFFF --ki 0"); void *argtable[] = { arg_param_begin, arg_str0("k", "key", "", "Credit key as 8 hex bytes"), arg_int0(NULL, "ki", "", "Key index to select key from memory 'hf iclass managekeys'"), - arg_str1("d", "data", "", "data to write as 4 hex bytes"), + arg_str1("d", "data", "", "data to write as 8 hex bytes"), arg_lit0(NULL, "elite", "elite computations applied to key"), arg_lit0(NULL, "raw", "no computations applied to key"), arg_lit0("v", "verbose", "verbose output"), @@ -2523,7 +2498,7 @@ static int CmdHFiClassCreditEpurse(const char *Cmd) { PacketResponseNG resp; int isok; - if (WaitForResponseTimeout(CMD_HF_ICLASS_CREDIT_EPURSE, &resp, 2000) == false) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_CREDIT_EPURSE, &resp, 2000) == 0) { if (verbose) PrintAndLogEx(WARNING, "command execution time out"); isok = PM3_ETIMEOUT; } else if (resp.status != PM3_SUCCESS) { @@ -2569,7 +2544,6 @@ static int CmdHFiClassRestore(const char *Cmd) { arg_lit0(NULL, "raw", "no computations applied to key"), arg_lit0("v", "verbose", "verbose output"), arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"), - arg_lit0(NULL, "nr", "replay of nr mac with privilege escalation"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -2620,7 +2594,6 @@ static int CmdHFiClassRestore(const char *Cmd) { bool rawkey = arg_get_lit(ctx, 8); bool verbose = arg_get_lit(ctx, 9); bool shallow_mod = arg_get_lit(ctx, 10); - bool use_replay = arg_get_lit(ctx, 11); CLIParserFree(ctx); @@ -2667,7 +2640,7 @@ static int CmdHFiClassRestore(const char *Cmd) { payload->req.use_raw = rawkey; payload->req.use_elite = elite; payload->req.use_credit_key = use_credit_key; - payload->req.use_replay = use_replay; + payload->req.use_replay = false; payload->req.blockno = startblock; payload->req.send_reply = true; payload->req.do_auth = true; @@ -2707,7 +2680,7 @@ static int CmdHFiClassRestore(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_ICLASS_RESTORE, (uint8_t *)payload, payload_size); - if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == false) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == 0) { PrintAndLogEx(WARNING, "command execution time out"); DropField(); free(payload); @@ -2839,10 +2812,10 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { int blockno = arg_get_int_def(ctx, 3, 0); - uint8_t keyType = ICLASS_DEBIT_KEYTYPE; + uint8_t keyType = 0x88; //debit key if (arg_get_lit(ctx, 4)) { PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key"); - keyType = ICLASS_CREDIT_KEYTYPE; + keyType = 0x18; //credit key } bool elite = arg_get_lit(ctx, 5); @@ -2944,68 +2917,19 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { return PM3_SUCCESS; } - -static void iclass_cmp_print(uint8_t *b1, uint8_t *b2, const char *header1, const char *header2) { - - char line1[240] = {0}; - char line2[240] = {0}; - - strcat(line1, header1); - strcat(line2, header2); - - for (uint8_t i = 0; i < PICOPASS_BLOCK_SIZE; i++) { - - int l1 = strlen(line1); - int l2 = strlen(line2); - - uint8_t hi1 = NIBBLE_HIGH(b1[i]); - uint8_t low1 = NIBBLE_LOW(b1[i]); - - uint8_t hi2 = NIBBLE_HIGH(b2[i]); - uint8_t low2 = NIBBLE_LOW(b2[i]); - - if (hi1 != hi2) { - snprintf(line1 + l1, sizeof(line1) - l1, _RED_("%1X"), hi1); - snprintf(line2 + l2, sizeof(line2) - l2, _GREEN_("%1X"), hi2); - } else { - snprintf(line1 + l1, sizeof(line1) - l1, "%1X", hi1); - snprintf(line2 + l2, sizeof(line2) - l2, "%1X", hi2); - } - - l1 = strlen(line1); - l2 = strlen(line2); - - if (low1 != low2) { - snprintf(line1 + l1, sizeof(line1) - l1, _RED_("%1X"), low1); - snprintf(line2 + l2, sizeof(line2) - l2, _GREEN_("%1X"), low2); - } else { - snprintf(line1 + l1, sizeof(line1) - l1, "%1X", low1); - snprintf(line2 + l2, sizeof(line2) - l2, "%1X", low2); - } - } - - PrintAndLogEx(INFO, "%s", line1); - PrintAndLogEx(INFO, "%s", line2); -} - static int CmdHFiClass_TearBlock(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "hf iclass tear", - "Tear off an iCLASS tag block\n" - "e-purse usually 300-500us to trigger the erase phase\n" - "also seen 1800-2100us on some cards\n" - "Make sure you know the target card credit key. Typical `--ki 1` or `--ki 3`\n", - "hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B -s 300 -e 600\n" - "hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 -s 300 -e 600\n" - "hf iclass tear --blk 2 -d fdffffffffffffff --ki 1 --credit -s 400 -e 500" - ); + CLIParserInit(&ctx, "hf iclass trbl", + "Tear off an iCLASS tag block", + "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B --tdb 100 --tde 150\n" + "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 --tdb 100 --tde 150"); void *argtable[] = { arg_param_begin, arg_str0("k", "key", "", "Access key as 8 hex bytes"), arg_int0(NULL, "ki", "", "Key index to select key from memory 'hf iclass managekeys'"), arg_int1(NULL, "blk", "", "block number"), - arg_str0("d", "data", "", "data to write as 8 hex bytes"), + arg_str1("d", "data", "", "data to write as 8 hex bytes"), arg_str0("m", "mac", "", "replay mac data (4 hex bytes)"), arg_lit0(NULL, "credit", "key is assumed to be the credit key"), arg_lit0(NULL, "elite", "elite computations applied to key"), @@ -3013,31 +2937,83 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { arg_lit0(NULL, "nr", "replay of NR/MAC"), arg_lit0("v", "verbose", "verbose output"), arg_lit0(NULL, "shallow", "use shallow (ASK) reader modulation instead of OOK"), - arg_int1("s", NULL, "", "tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3 us"), - arg_int0("i", NULL, "", "tearoff delay increment (in us) - default 10"), - arg_int0("e", NULL, "", "tearoff delay end (in us) must be a higher value than the start delay"), - arg_int0(NULL, "loop", "", "number of times to loop per tearoff time"), - arg_int0(NULL, "sleep", "", "Sleep between each tear"), - arg_lit0(NULL, "arm", "Runs the commands on device side and tries to stabilize tears"), + arg_int1(NULL, "tdb", "", "tearoff delay start in ms"), + arg_int1(NULL, "tde", "", "tearoff delay end in ms"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); int key_len = 0; uint8_t key[8] = {0}; + CLIGetHexWithReturn(ctx, 1, key, &key_len); int key_nr = arg_get_int_def(ctx, 2, -1); + + if (key_len > 0 && key_nr >= 0) { + PrintAndLogEx(ERR, "Please specify key or index, not both"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + bool auth = false; + + if (key_len > 0) { + auth = true; + if (key_len != 8) { + PrintAndLogEx(ERR, "Key is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } else if (key_nr >= 0) { + if (key_nr < ICLASS_KEYS_MAX) { + auth = true; + memcpy(key, iClass_Key_Table[key_nr], 8); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8)); + } else { + PrintAndLogEx(ERR, "Key number is invalid"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + int blockno = arg_get_int_def(ctx, 3, 0); int data_len = 0; uint8_t data[8] = {0}; CLIGetHexWithReturn(ctx, 4, data, &data_len); + if (data_len != 8) { + PrintAndLogEx(ERR, "Data must be 8 hex bytes (16 hex symbols)"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + int mac_len = 0; uint8_t mac[4] = {0}; CLIGetHexWithReturn(ctx, 5, mac, &mac_len); + if (mac_len) { + if (mac_len != 4) { + PrintAndLogEx(ERR, "MAC must be 4 hex bytes (8 hex symbols)"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + + int tearoff_start = arg_get_int_def(ctx, 12, 100); + int tearoff_end = arg_get_int_def(ctx, 13, 200); + + if (tearoff_end <= tearoff_start) { + PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay."); + return PM3_EINVARG; + } + + if (tearoff_start < 0 || tearoff_end <= 0) { + PrintAndLogEx(ERR, "Tearoff start/end delays should be bigger than 0."); + return PM3_EINVARG; + } + bool use_credit_key = arg_get_lit(ctx, 6); bool elite = arg_get_lit(ctx, 7); bool rawkey = arg_get_lit(ctx, 8); @@ -3045,492 +3021,92 @@ static int CmdHFiClass_TearBlock(const char *Cmd) { bool verbose = arg_get_lit(ctx, 10); bool shallow_mod = arg_get_lit(ctx, 11); - int tearoff_start = arg_get_int_def(ctx, 12, 100); - int tearoff_original_start = tearoff_start; // save original start value for later use - int tearoff_increment = arg_get_int_def(ctx, 13, 10); - int tearoff_end = arg_get_int_def(ctx, 14, tearoff_start + tearoff_increment + 500); - int tearoff_loop = arg_get_int_def(ctx, 15, 1); - int tearoff_sleep = arg_get_int_def(ctx, 16, 0); - bool run_on_device = arg_get_lit(ctx, 17); - CLIParserFree(ctx); - // Sanity checks - if (key_len > 0 && key_nr >= 0) { - PrintAndLogEx(ERR, "Please specify key or index, not both"); - return PM3_EINVARG; - } - - bool auth = false; - - if (key_len > 0) { - - auth = true; - if (key_len != 8) { - PrintAndLogEx(ERR, "Key is incorrect length"); - return PM3_EINVARG; - } - PrintAndLogEx(NORMAL, ""); - } - - if (key_nr >= 0) { - if (key_nr < ICLASS_KEYS_MAX) { - auth = true; - memcpy(key, iClass_Key_Table[key_nr], 8); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex_inrow(iClass_Key_Table[key_nr], 8)); - } else { - PrintAndLogEx(ERR, "Key number is invalid"); - return PM3_EINVARG; - } - } - - if (data_len && data_len != 8) { - PrintAndLogEx(ERR, "Data must be 8 hex bytes (16 hex symbols), got " _RED_("%u"), data_len); - return PM3_EINVARG; - } - - if (mac_len && mac_len != 4) { - PrintAndLogEx(ERR, "MAC must be 4 hex bytes (8 hex symbols)"); - return PM3_EINVARG; - } - - if (tearoff_end <= tearoff_start) { - PrintAndLogEx(ERR, "Tearoff end delay must be larger than the start delay"); - return PM3_EINVARG; - } - - if (tearoff_start <= 0) { - PrintAndLogEx(ERR, "Tearoff_start delays must be larger than 0"); - return PM3_EINVARG; - } - - if (tearoff_end <= 0) { - PrintAndLogEx(ERR, "Tearoff_end delays must be larger than 0"); - return PM3_EINVARG; - } - if ((use_replay + rawkey + elite) > 1) { - PrintAndLogEx(ERR, "Can not use a combo of `--elite`, `--raw`, `--nr`"); + PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'"); return PM3_EINVARG; } - - int loop_count = 0; - int isok = PM3_SUCCESS; + int isok = 0; + tearoff_params_t params; bool read_ok = false; - uint8_t keyType = ICLASS_DEBIT_KEYTYPE; - if (use_credit_key) { - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("credit") " key"); - keyType = ICLASS_CREDIT_KEYTYPE; - } + while (tearoff_start < tearoff_end && !read_ok) { + //perform read here, repeat if failed or 00s - if (data_len && auth == false) { - PrintAndLogEx(SUCCESS, "No key supplied. Trying no authentication read/writes"); - } - - if (tearoff_loop > 1) { - PrintAndLogEx(SUCCESS, _YELLOW_("%u") " attempts / tearoff", tearoff_loop); - } - - if (tearoff_sleep) { - PrintAndLogEx(SUCCESS, "Using " _YELLOW_("%u") " ms delay between attempts", tearoff_sleep); - } - - //check if the card is in secure mode or not - iclass_card_select_t payload_rdr = { - .flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE) - }; - - if (shallow_mod) { - payload_rdr.flags |= FLAG_ICLASS_READER_SHALLOW_MOD; - } - clearCommandBuffer(); - PacketResponseNG resp; - SendCommandNG(CMD_HF_ICLASS_READER, (uint8_t *)&payload_rdr, sizeof(iclass_card_select_t)); - - if (WaitForResponseTimeout(CMD_HF_ICLASS_READER, &resp, 2000) == false) { - PrintAndLogEx(WARNING, "command execution time out"); - DropField(); - return PM3_ESOFT; - } - DropField(); - - if (resp.status == PM3_ERFTRANS) { - PrintAndLogEx(FAILED, "no tag found"); - DropField(); - return PM3_ESOFT; - } - - iclass_card_select_resp_t *r = (iclass_card_select_resp_t *)resp.data.asBytes; - if (r->status == FLAG_ICLASS_NULL) { - PrintAndLogEx(FAILED, "failed to read block 0,1,2"); - return PM3_ESOFT; - } - - int fail_tolerance = 1; - if (memcmp(r->header.hdr.csn + 4, "\xFE\xFF\x12\xE0", 4) == 0) { - PrintAndLogEx(SUCCESS, "CSN................... %s ( new silicon )", sprint_hex_inrow(r->header.hdr.csn, PICOPASS_BLOCK_SIZE)); - } else { - PrintAndLogEx(SUCCESS, "CSN................... %s ( old silicon )", sprint_hex_inrow(r->header.hdr.csn, PICOPASS_BLOCK_SIZE)); - fail_tolerance = 5; - } - - picopass_hdr_t *hdr = &r->header.hdr; - uint8_t pagemap = get_pagemap(hdr); - if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - PrintAndLogEx(INFO, "Card in non-secure page mode detected"); - auth = false; - } - - if (pagemap == 0x0) { - PrintAndLogEx(WARNING, _RED_("No auth possible. Read only if RA is enabled")); - goto out; - } - - - // perform initial read here, repeat if failed or 00s - bool read_auth = auth; - uint8_t data_read_orig[8] = {0}; - uint8_t ff_data[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; - bool first_read = false; - bool reread = false; - bool erase_phase = false; - - if (blockno < 3) { - read_auth = false; - } - - int res_orig = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read_orig, false); - while (reread) { - if (res_orig == PM3_SUCCESS && !reread) { - if (memcmp(data_read_orig, zeros, 8) == 0) { - reread = true; - } else { - reread = false; - } - } else if (res_orig == PM3_SUCCESS && reread) { - reread = false; - if (blockno == 2 && memcmp(data_read_orig, zeros, 8) == 0) { - reread = true; - } - } - } - - if (blockno == 2 && data_len == 0) { - int value_index = 0; //assuming FFFFFFFF is on the right - if (memcmp(data_read_orig + 4, "\xFF\xFF\xFF\xFF", 4) != 0) { //FFFFFFFF is on the left - value_index = 4; - } - memcpy(key, iClass_Key_Table[1], PICOPASS_BLOCK_SIZE); - use_credit_key = true; - auth = true; - memcpy(data, data_read_orig, PICOPASS_BLOCK_SIZE); - //decrease the debit epurse value by 1 - if (data_read_orig[value_index] != 0x00) { - data[value_index]--; - } else { - data[value_index + 2]--; - data[value_index] = 0xFF; - } - } - - PrintAndLogEx(SUCCESS, "Original block data... " _CYAN_("%s"), sprint_hex_inrow(data_read_orig, sizeof(data_read_orig))); - PrintAndLogEx(SUCCESS, "New data to write..... " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data))); - PrintAndLogEx(SUCCESS, "Target block.......... " _YELLOW_("%u") " / " _YELLOW_("0x%02x"), blockno, blockno); - PrintAndLogEx(SUCCESS, "Using Key............. " _YELLOW_("%s"), sprint_hex_inrow(key, sizeof(key)));; - // turn off Device side debug messages - uint8_t dbg_curr = DBG_NONE; - if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) { - return PM3_EFAILED; - } - - if (setDeviceDebugLevel(DBG_NONE, false) != PM3_SUCCESS) { - return PM3_EFAILED; - } - - // clear trace log - SendCommandNG(CMD_BUFF_CLEAR, NULL, 0); - - if (run_on_device) { - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "---------------------------------------"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n"); - - iclass_tearblock_req_t payload = { - .req.use_raw = rawkey, - .req.use_elite = elite, - .req.use_credit_key = use_credit_key, - .req.use_replay = use_replay, - .req.blockno = blockno, - .req.send_reply = true, - .req.do_auth = auth, - .req.shallow_mod = shallow_mod, - .tear_start = tearoff_start, - .tear_end = tearoff_end, - .increment = tearoff_increment, - .tear_loop = tearoff_loop, - }; - memcpy(payload.req.key, key, PICOPASS_BLOCK_SIZE); - memcpy(payload.data, data, sizeof(payload.data)); - memcpy(payload.mac, mac, sizeof(payload.mac)); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_TEARBL, (uint8_t *)&payload, sizeof(payload)); - - if (WaitForResponseTimeout(CMD_HF_ICLASS_TEARBL, &resp, 1000)) { - if (resp.status == PM3_EOPABORTED) { - PrintAndLogEx(DEBUG, "Button pressed, user aborted"); - isok = resp.status; - } - } - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Done!"); - PrintAndLogEx(NORMAL, ""); - clearCommandBuffer(); - return isok; - - } else { - - PrintAndLogEx(INFO, "---------------------------------------"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n"); - // Main loop - while ((tearoff_start <= tearoff_end) && (read_ok == false)) { - - if (kbd_enter_pressed()) { - PrintAndLogEx(WARNING, "\naborted via keyboard."); - isok = PM3_EOPABORTED; - goto out; - } - - // set tear off trigger - clearCommandBuffer(); - tearoff_params_t params = { - .delay_us = (tearoff_start & 0xFFFF), - .on = true, - .off = false - }; - - int res = handle_tearoff(¶ms, verbose); - if (res != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Failed to configure tear off"); - isok = PM3_ESOFT; - goto out; - } - - if (tearoff_loop > 1) { - PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%3u")" iter", params.delay_us, (tearoff_end & 0xFFFF), loop_count + 1); - } else { - PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us", params.delay_us, (tearoff_end & 0xFFFF)); - } - - // write block - don't check the return value. As a tear-off occurred, the write failed. - // when tear off is enabled, the return code will always be PM3_ETEAROFF - iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, false, auth, shallow_mod); - - // read the data back - uint8_t data_read[8] = {0}; - first_read = false; - reread = false; - bool decrease = false; - int readcount = 0; - while (first_read == false) { - - if (kbd_enter_pressed()) { - PrintAndLogEx(WARNING, "\naborted via keyboard."); - isok = PM3_EOPABORTED; - goto out; - } - - // skip authentication for config and e-purse blocks (1,2) - if (blockno < 3) { - read_auth = false; - } - - res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read, false); - if (res == PM3_SUCCESS && !reread) { - if (memcmp(data_read, zeros, 8) == 0) { - reread = true; - } else { - first_read = true; - reread = false; - } - } else if (res == PM3_SUCCESS && reread) { + uint8_t data_read_orig[8] = {0}; + bool first_read = false; + bool reread = false; + while (!first_read) { + int res_orig = iclass_read_block_ex(key, blockno, 0x88, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read_orig, false); + if (res_orig == PM3_SUCCESS && !reread) { + if (memcmp(data_read_orig, zeros, 8) == 0) { + reread = true; + } else { first_read = true; reread = false; - } else if (res != PM3_SUCCESS) { - decrease = true; } - - readcount++; - } - - if (readcount > fail_tolerance) { - PrintAndLogEx(WARNING, "\nRead block failed "_RED_("%d") " times", readcount); - } - - // if there was an error reading repeat the tearoff with the same delay - if (decrease && (tearoff_start > tearoff_increment) && (tearoff_start >= tearoff_original_start)) { - tearoff_start -= tearoff_increment; - if (verbose) { - PrintAndLogEx(INFO, " -> Read failed, retearing with "_CYAN_("%u")" us", tearoff_start); - } - } - - bool tear_success = true; - bool expected_values = true; - - if (memcmp(data_read, data, 8) != 0) { - tear_success = false; - } - - if ((tear_success == false) && - (memcmp(data_read, zeros, 8) != 0) && - (memcmp(data_read, data_read_orig, 8) != 0)) { - - // tearoff succeeded (partially) - - expected_values = false; - - if (memcmp(data_read, ff_data, 8) == 0 && - memcmp(data_read_orig, ff_data, 8) != 0) { - - if (erase_phase == false) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, _CYAN_("Erase phase hit... ALL ONES")); - iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); - } - erase_phase = true; - } else { - - if (erase_phase) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, _MAGENTA_("Tearing! Write phase (post erase)")); - iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); - } else { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, _CYAN_("Tearing! unknown phase")); - iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: "); - } - } - - bool goto_out = false; - if (blockno == 2) { - if (memcmp(data_read, ff_data, 8) == 0 && memcmp(data_read_orig, ff_data, 8) != 0) { - PrintAndLogEx(SUCCESS, "E-purse has been teared ( %s )", _GREEN_("ok")); - PrintAndLogEx(HINT, "Hint: try `hf iclass creditepurse -d FEFFFEFF --ki 1`"); - PrintAndLogEx(HINT, "Hint: try `hf iclass wrbl -d 'FFFFFFFF FFFF FEFF' --blk 2 --ki 1 --credit`"); - isok = PM3_SUCCESS; - goto_out = true; - } - } - - if (blockno == 1) { - if (data_read[0] != data_read_orig[0]) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Application limit changed, from "_YELLOW_("%u")" to "_YELLOW_("%u"), data_read_orig[0], data_read[0]); - isok = PM3_SUCCESS; - goto_out = true; - } - - if (data_read[7] != data_read_orig[7]) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Fuse changed, from "_YELLOW_("%02x")" to "_YELLOW_("%02x"), data_read_orig[7], data_read[7]); - - const char *flag_names[8] = { - "RA", - "Fprod0", - "Fprod1", - "Crypt0 (*1)", - "Crypt1 (*0)", - "Coding0", - "Coding1", - "Fpers (*1)" - }; - PrintAndLogEx(INFO, _YELLOW_("%-10s %-10s %-10s"), "Fuse", "Original", "Changed"); - PrintAndLogEx(INFO, "---------------------------------------"); - for (int i = 7; i >= 0; --i) { - int bit1 = (data_read_orig[7] >> i) & 1; - int bit2 = (data_read[7] >> i) & 1; - PrintAndLogEx(INFO, "%-11s %-10d %-10d", flag_names[i], bit1, bit2); - } - - isok = PM3_SUCCESS; - goto_out = true; - } - - // if more OTP bits set.. - if (data_read[1] > data_read_orig[1] || - data_read[2] > data_read_orig[2]) { - PrintAndLogEx(SUCCESS, "More OTP bits got set!!!"); - - data_read[7] = 0xBC; - res = iclass_write_block(blockno, data_read, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); - if (res != PM3_SUCCESS) { - PrintAndLogEx(INFO, "Stabilize the bits ( "_RED_("failed") " )"); - } - - isok = PM3_SUCCESS; - goto_out = true; - } - } - - if (goto_out) { - goto out; - } - } - - if (tear_success) { // tearoff succeeded with expected values - - read_ok = true; - tear_success = true; - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Read: " _GREEN_("%s") " %s" - , sprint_hex_inrow(data_read, sizeof(data_read)), - (expected_values) ? _GREEN_(" -> Expected values!") : "" - ); - } - - loop_count++; - - if (loop_count == tearoff_loop) { - tearoff_start += tearoff_increment; - loop_count = 0; - } - - if (tearoff_sleep) { - msleep(tearoff_sleep); + } else if (res_orig == PM3_SUCCESS && reread) { + first_read = true; + reread = false; } } + + params.on = true; + params.delay_us = tearoff_start; + handle_tearoff(¶ms, false); + PrintAndLogEx(INFO, "Tear off delay: "_YELLOW_("%d")" ms", tearoff_start); + isok = iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod); + switch (isok) { + case PM3_SUCCESS: + PrintAndLogEx(SUCCESS, "Wrote block " _YELLOW_("%d") " / " _YELLOW_("0x%02X") " ( " _GREEN_("ok") " )", blockno, blockno); + break; + case PM3_ETEAROFF: + break; + default: + PrintAndLogEx(FAILED, "Writing failed"); + break; + } + //read the data back + uint8_t data_read[8] = {0}; + first_read = false; + reread = false; + bool decrease = false; + while (!first_read) { + int res = iclass_read_block_ex(key, blockno, 0x88, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read, false); + if (res == PM3_SUCCESS && !reread) { + if (memcmp(data_read, zeros, 8) == 0) { + reread = true; + } else { + first_read = true; + reread = false; + } + } else if (res == PM3_SUCCESS && reread) { + first_read = true; + reread = false; + } else if (res != PM3_SUCCESS) { + decrease = true; + } + } + if (decrease && tearoff_start > 0) { //if there was an error reading repeat the tearoff with the same delay + tearoff_start--; + } + bool tear_success = true; + for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { + if (data[i] != data_read[i]) { + tear_success = false; + } + } + if (tear_success) { //tearoff succeeded + read_ok = true; + PrintAndLogEx(SUCCESS, _GREEN_("Tear-off Success!")); + PrintAndLogEx(INFO, "Read: %s", sprint_hex(data_read, sizeof(data_read))); + } else { //tearoff did not succeed + PrintAndLogEx(FAILED, _RED_("Tear-off Failed!")); + tearoff_start++; + } + PrintAndLogEx(INFO, "---------------"); } - -out: - - DropField(); - - if (setDeviceDebugLevel(verbose ? MAX(dbg_curr, DBG_INFO) : DBG_NONE, false) != PM3_SUCCESS) { - return PM3_EFAILED; - } - // disable tearoff in case of keyboard abort, or it'll trigger on next operation - clearCommandBuffer(); - tearoff_params_t params = { - .delay_us = tearoff_start, - .on = false, - .off = true - }; - handle_tearoff(¶ms, false); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Done!"); - PrintAndLogEx(NORMAL, ""); - clearCommandBuffer(); return isok; } @@ -3926,6 +3502,7 @@ static int CmdHFiClassView(const char *Cmd) { } if (verbose) { + PrintAndLogEx(INFO, "File: " _YELLOW_("%s"), filename); PrintAndLogEx(INFO, "File size %zu bytes, file blocks %d (0x%x)", bytes_read, (uint16_t)(bytes_read >> 3), (uint16_t)(bytes_read >> 3)); PrintAndLogEx(INFO, "Printing blocks from: " _YELLOW_("%02d") " to: " _YELLOW_("%02d"), (startblock == 0) ? 6 : startblock, endblock); } @@ -3944,14 +3521,13 @@ static int CmdHFiClassView(const char *Cmd) { void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite) { if (elite) { uint8_t keytable[128] = {0}; - uint8_t key_index[PICOPASS_BLOCK_SIZE] = {0}; - uint8_t key_sel[PICOPASS_BLOCK_SIZE] = {0}; - uint8_t key_sel_p[PICOPASS_BLOCK_SIZE] = {0}; + uint8_t key_index[8] = {0}; + uint8_t key_sel[8] = { 0 }; + uint8_t key_sel_p[8] = { 0 }; hash2(KEY, keytable); hash1(CSN, key_index); - for (uint8_t i = 0; i < 8 ; i++) { + for (uint8_t i = 0; i < 8 ; i++) key_sel[i] = keytable[key_index[i]]; - } //Permute from iclass format to standard format permutekey_rev(key_sel, key_sel_p); @@ -3965,8 +3541,8 @@ void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite //calculate and return xor_div_key (ready for a key write command) //print all div_keys if verbose static void HFiClassCalcNewKey(uint8_t *CSN, uint8_t *OLDKEY, uint8_t *NEWKEY, uint8_t *xor_div_key, bool elite, bool oldElite, bool verbose) { - uint8_t old_div_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t new_div_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t old_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t new_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //get old div key HFiClassCalcDivKey(CSN, OLDKEY, old_div_key, oldElite); //get new div key @@ -3976,9 +3552,9 @@ static void HFiClassCalcNewKey(uint8_t *CSN, uint8_t *OLDKEY, uint8_t *NEWKEY, u xor_div_key[i] = old_div_key[i] ^ new_div_key[i]; } if (verbose) { - PrintAndLogEx(SUCCESS, "Old div key.... %s", sprint_hex_inrow(old_div_key, PICOPASS_BLOCK_SIZE)); - PrintAndLogEx(SUCCESS, "New div key.... " _MAGENTA_("%s"), sprint_hex_inrow(new_div_key, PICOPASS_BLOCK_SIZE)); - PrintAndLogEx(SUCCESS, "Xor div key.... " _YELLOW_("%s") "\n", sprint_hex_inrow(xor_div_key, PICOPASS_BLOCK_SIZE)); + PrintAndLogEx(SUCCESS, "Old div key......... %s", sprint_hex(old_div_key, 8)); + PrintAndLogEx(SUCCESS, "New div key......... %s", sprint_hex(new_div_key, 8)); + PrintAndLogEx(SUCCESS, "Xor div key......... " _YELLOW_("%s") "\n", sprint_hex(xor_div_key, 8)); } } @@ -4101,7 +3677,6 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) { uint8_t xor_div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - PrintAndLogEx(NORMAL, ""); if (givenCSN == false) { uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if (select_only(csn, CCNR, true, false) == false) { @@ -4111,8 +3686,7 @@ static int CmdHFiClassCalcNewKey(const char *Cmd) { } HFiClassCalcNewKey(csn, old_key, new_key, xor_div_key, elite, old_elite, true); - PrintAndLogEx(HINT, "Hint: Depending if card is in " _MAGENTA_("PERSONALIZATION") " or "_YELLOW_("APPLICATION") " mode"); - PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; } @@ -4281,7 +3855,7 @@ static void add_key(uint8_t *key) { static int CmdHFiClassCheckKeys(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass chk", - "Checkkeys loads a dictionary text file with 8 byte hex keys to test authenticating against a iCLASS tag", + "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag", "hf iclass chk -f iclass_default_keys.dic\n" "hf iclass chk -f iclass_elite_keys.dic --elite\n" "hf iclass chk --vb6kdf\n"); @@ -4557,10 +4131,10 @@ void picopass_elite_nextKey(uint8_t *key) { } prepared = true; } - memcpy(key, key_state, PICOPASS_BLOCK_SIZE); + memcpy(key, key_state, 8); } -static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool fast, bool short_delay, bool allnight) { +static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, uint8_t no_first_auth[8], bool debug, bool test, bool allnight) { int runs = 1; int cycle = 1; @@ -4592,8 +4166,6 @@ static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, u payload->loop = loop; payload->debug = debug; payload->test = test; - payload->fast = fast; - payload->short_delay = short_delay; memcpy(payload->nfa, no_first_auth, PICOPASS_BLOCK_SIZE); memcpy(payload->req.key, key, PICOPASS_BLOCK_SIZE); memcpy(payload->req2.key, aa2_standard_key, PICOPASS_BLOCK_SIZE); @@ -4606,15 +4178,9 @@ static int iclass_recover(uint8_t key[8], uint32_t index_start, uint32_t loop, u WaitForResponse(CMD_HF_ICLASS_RECOVER, &resp); if (resp.status == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "iCLASS Key Bits Recovery: " _GREEN_("completed!")); repeat = false; - } else if (resp.status == PM3_EOPABORTED) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(WARNING, "iCLASS Key Bits Recovery: " _YELLOW_("aborted via keyboard!")); - repeat = false; } else if (resp.status == PM3_ESOFT) { - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "iCLASS Key Bits Recovery: " _RED_("failed/errors")); repeat = false; } else if (resp.status == PM3_EINVARG) { @@ -4653,131 +4219,14 @@ void generate_key_block_inverted(const uint8_t *startingKey, uint64_t index, uin } } +static int CmdHFiClassLegRecLookUp(const char *Cmd) { -// HF iClass legbrute - Thread argument structure -typedef struct { - uint8_t startingKey[8]; - uint64_t index_start; - uint8_t CCNR1[12]; - uint8_t MAC_TAG1[4]; - uint8_t CCNR2[12]; - uint8_t MAC_TAG2[4]; - int thread_id; - int thread_count; - volatile bool *found; - pthread_mutex_t *log_lock; -} thread_args_t; - -// HF iClass legbrute - Brute-force worker thread -static void *brute_thread(void *args_void) { - - thread_args_t *args = (thread_args_t *)args_void; - uint8_t div_key[8]; - uint8_t mac[4]; - uint8_t verification_mac[4]; - uint64_t index = args->index_start; - - while (!*(args->found)) { - - generate_key_block_inverted(args->startingKey, index, div_key); - doMAC(args->CCNR1, div_key, mac); - - if (memcmp(mac, args->MAC_TAG1, 4) == 0) { - doMAC(args->CCNR2, div_key, verification_mac); - if (memcmp(verification_mac, args->MAC_TAG2, 4) == 0) { - pthread_mutex_lock(args->log_lock); - if (!*(args->found)) { - *args->found = true; - PrintAndLogEx(NORMAL, "\n"); - PrintAndLogEx(SUCCESS, "Found valid raw key " _GREEN_("%s"), sprint_hex_inrow(div_key, 8)); - PrintAndLogEx(HINT, "Hint: Run `"_YELLOW_("hf iclass unhash -k %s")"` to find the needed pre-images", sprint_hex_inrow(div_key, 8)); - PrintAndLogEx(INFO, "Done!"); - PrintAndLogEx(NORMAL, ""); - } - pthread_mutex_unlock(args->log_lock); - break; - } - } - - if (index % 1000000 == 0 && !*(args->found)) { - - if (args->thread_id == 0) { - pthread_mutex_lock(args->log_lock); - PrintAndLogEx(INPLACE, "Tested "_YELLOW_("%" PRIu64)" million keys, curr index: "_YELLOW_("%" PRIu64)", Thread[0]: %s" - , ((index / 1000000) * args->thread_count) - , (index / 1000000) - , sprint_hex_inrow(div_key, 8) - ); - pthread_mutex_unlock(args->log_lock); - } - - } - index++; - } - return NULL; -} - -// HF iClass legbrute - Multithreaded brute-force function -static int CmdHFiClassLegBrute_MT(uint8_t epurse[8], uint8_t macs[8], uint8_t macs2[8], uint8_t startingKey[8], uint64_t index, int threads) { - - int thread_count = threads; - if (thread_count < 1) { - thread_count = 1; - } - if (thread_count > 16) { - thread_count = 16; - } - PrintAndLogEx(INFO, "Bruteforcing using " _YELLOW_("%u") " threads", thread_count); - PrintAndLogEx(NORMAL, ""); - - uint8_t CCNR[12], CCNR2[12], MAC_TAG[4], MAC_TAG2[4]; - - memcpy(CCNR, epurse, 8); - memcpy(CCNR2, epurse, 8); - memcpy(CCNR + 8, macs, 4); - memcpy(CCNR2 + 8, macs2, 4); - memcpy(MAC_TAG, macs + 4, 4); - memcpy(MAC_TAG2, macs2 + 4, 4); - - pthread_t tids[thread_count]; - thread_args_t args[thread_count]; - volatile bool found = false; - pthread_mutex_t log_lock; - pthread_mutex_init(&log_lock, NULL); - - int nibble_range = 16 / thread_count; - for (int i = 0; i < thread_count; i++) { - memcpy(args[i].startingKey, startingKey, 8); - args[i].startingKey[0] = (startingKey[0] & 0x0F) | ((i * nibble_range) << 4); - args[i].index_start = index; - memcpy(args[i].CCNR1, CCNR, 12); - memcpy(args[i].MAC_TAG1, MAC_TAG, 4); - memcpy(args[i].CCNR2, CCNR2, 12); - memcpy(args[i].MAC_TAG2, MAC_TAG2, 4); - args[i].thread_id = i; - args[i].thread_count = thread_count; - args[i].found = &found; - args[i].log_lock = &log_lock; - - pthread_create(&tids[i], NULL, brute_thread, &args[i]); - } - - for (int i = 0; i < thread_count; i++) { - pthread_join(tids[i], NULL); - } - pthread_mutex_destroy(&log_lock); - - return found ? PM3_SUCCESS : ERR; -} - -// CmdHFiClassLegBrute function with CLI and multithreading support -static int CmdHFiClassLegBrute(const char *Cmd) { + //Standalone Command Start CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass legbrute", - "This command takes sniffed trace data and a partial raw key and bruteforces the remaining 40 bits of the raw key.\n" - "Complete 40 bit keyspace is 1'099'511'627'776 and command is locked down to max 16 threads currently.\n" - "A possible worst case scenario on 16 threads estimates XXX days YYY hours MMM minutes.", - "hf iclass legbrute --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225"); + "This command take sniffed trace data and partial raw key and bruteforces the remaining 40 bits of the raw key.", + "hf iclass legbrute --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225" + ); void *argtable[] = { arg_param_begin, @@ -4786,7 +4235,6 @@ static int CmdHFiClassLegBrute(const char *Cmd) { arg_str1(NULL, "macs2", "", "MACs captured from the reader, different than the first set (with the same csn and epurse value)"), arg_str1(NULL, "pk", "", "Partial Key from legrec or starting key of keyblock from legbrute"), arg_int0(NULL, "index", "", "Where to start from to retrieve the key, default 0 - value in millions e.g. 1 is 1 million"), - arg_int0(NULL, "threads", "", "Number of threads to use, by default it uses the cpu's max threads (max 16)."), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -4807,9 +4255,9 @@ static int CmdHFiClassLegBrute(const char *Cmd) { uint8_t startingKey[PICOPASS_BLOCK_SIZE] = {0}; CLIGetHexWithReturn(ctx, 4, startingKey, &startingkey_len); - uint64_t index = arg_get_int_def(ctx, 5, 0); - index *= 1000000; - int threads = arg_get_int_def(ctx, 6, num_CPUs()); + uint64_t index = arg_get_int_def(ctx, 6, 0); //has to be 64 as we're bruteforcing 40 bits + index = index * 1000000; + CLIParserFree(ctx); if (epurse_len && epurse_len != PICOPASS_BLOCK_SIZE) { @@ -4831,8 +4279,81 @@ static int CmdHFiClassLegBrute(const char *Cmd) { PrintAndLogEx(ERR, "Partial Key is incorrect length"); return PM3_EINVARG; } + //Standalone Command End - return CmdHFiClassLegBrute_MT(epurse, macs, macs2, startingKey, index, threads); + uint8_t CCNR[12]; + uint8_t MAC_TAG[4] = {0, 0, 0, 0}; + uint8_t CCNR2[12]; + uint8_t MAC_TAG2[4] = {0, 0, 0, 0}; + + // Copy CCNR and MAC_TAG + memcpy(CCNR, epurse, 8); + memcpy(CCNR2, epurse, 8); + memcpy(CCNR + 8, macs, 4); + memcpy(CCNR2 + 8, macs2, 4); + memcpy(MAC_TAG, macs + 4, 4); + memcpy(MAC_TAG2, macs2 + 4, 4); + + PrintAndLogEx(SUCCESS, " Epurse: %s", sprint_hex(epurse, 8)); + PrintAndLogEx(SUCCESS, " MACS1: %s", sprint_hex(macs, 8)); + PrintAndLogEx(SUCCESS, " MACS2: %s", sprint_hex(macs2, 8)); + PrintAndLogEx(SUCCESS, " CCNR1: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR))); + PrintAndLogEx(SUCCESS, " CCNR2: " _GREEN_("%s"), sprint_hex(CCNR2, sizeof(CCNR2))); + PrintAndLogEx(SUCCESS, "TAG MAC1: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG))); + PrintAndLogEx(SUCCESS, "TAG MAC2: %s", sprint_hex(MAC_TAG2, sizeof(MAC_TAG2))); + PrintAndLogEx(SUCCESS, "Starting Key: %s", sprint_hex(startingKey, 8)); + + bool verified = false; + uint8_t div_key[PICOPASS_BLOCK_SIZE] = {0}; + uint8_t generated_mac[4] = {0, 0, 0, 0}; + + while (!verified) { + + //generate the key block + generate_key_block_inverted(startingKey, index, div_key); + + //generate the relevant macs + + doMAC(CCNR, div_key, generated_mac); + bool mac_match = true; + for (int i = 0; i < 4; i++) { + if (MAC_TAG[i] != generated_mac[i]) { + mac_match = false; + } + } + + if (mac_match) { + //verify this against macs2 + PrintAndLogEx(WARNING, _YELLOW_("Found potentially valid RAW key ") _GREEN_("%s")_YELLOW_(" verifying it..."), sprint_hex(div_key, 8)); + //generate the macs from the key and not the other way around, so we can quickly validate it + uint8_t verification_mac[4] = {0, 0, 0, 0}; + doMAC(CCNR2, div_key, verification_mac); + PrintAndLogEx(INFO, "Usr Provided Mac2: " _GREEN_("%s"), sprint_hex(MAC_TAG2, sizeof(MAC_TAG2))); + PrintAndLogEx(INFO, "Verification Mac: " _GREEN_("%s"), sprint_hex(verification_mac, sizeof(verification_mac))); + bool check_values = true; + for (int i = 0; i < 4; i++) { + if (MAC_TAG2[i] != verification_mac[i]) { + check_values = false; + } + } + if (check_values) { + PrintAndLogEx(SUCCESS, _GREEN_("CONFIRMED VALID RAW key ") _RED_("%s"), sprint_hex(div_key, 8)); + PrintAndLogEx(INFO, "You can now run -> "_YELLOW_("hf iclass unhash -k %s")" <-to find the pre-images.", sprint_hex(div_key, 8)); + verified = true; + } else { + PrintAndLogEx(INFO, _YELLOW_("Raw Key Invalid")); + } + + } + if (index % 1000000 == 0) { + PrintAndLogEx(INFO, "Tested: " _YELLOW_("%" PRIu64)" million keys", index / 1000000); + PrintAndLogEx(INFO, "Last Generated Key Value: " _YELLOW_("%s"), sprint_hex(div_key, 8)); + } + index++; + } + + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; } static void generate_single_key_block_inverted_opt(const uint8_t *startingKey, uint32_t index, uint8_t *keyBlock) { @@ -4877,68 +4398,59 @@ static void generate_single_key_block_inverted_opt(const uint8_t *startingKey, u static int CmdHFiClassLegacyRecSim(void) { - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, _YELLOW_("This simulation assumes the card is standard keyed.")); - PrintAndLogEx(INFO, ""); + + uint8_t key[PICOPASS_BLOCK_SIZE] = {0}; + uint8_t original_key[PICOPASS_BLOCK_SIZE]; uint8_t csn[8] = {0}; + uint8_t new_div_key[8] = {0}; uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; if (select_only(csn, CCNR, true, false) == false) { DropField(); return PM3_ESOFT; } - - uint8_t new_div_key[8] = {0}; HFiClassCalcDivKey(csn, iClass_Key_Table[0], new_div_key, false); - - uint8_t key[PICOPASS_BLOCK_SIZE] = {0}; - uint8_t original_key[PICOPASS_BLOCK_SIZE] = {0}; - memcpy(key, new_div_key, PICOPASS_BLOCK_SIZE); memcpy(original_key, key, PICOPASS_BLOCK_SIZE); uint8_t zero_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t zero_key_two[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; int bits_found = -1; uint32_t index = 0; - #define MAX_UPDATES 16777216 - while (bits_found == -1 && index < MAX_UPDATES) { - - uint8_t genkeyblock[PICOPASS_BLOCK_SIZE] = {0}; + uint8_t genkeyblock[PICOPASS_BLOCK_SIZE]; + uint8_t xorkeyblock[PICOPASS_BLOCK_SIZE] = {0}; generate_single_key_block_inverted_opt(zero_key, index, genkeyblock); + memcpy(xorkeyblock, genkeyblock, PICOPASS_BLOCK_SIZE); for (int i = 0; i < 8 ; i++) { - key[i] = genkeyblock[i] ^ original_key[i]; + key[i] = xorkeyblock[i] ^ original_key[i]; + memcpy(zero_key_two, xorkeyblock, PICOPASS_BLOCK_SIZE); } // Extract the last 3 bits of the first byte uint8_t last_three_bits = key[0] & 0x07; // 0x07 is 00000111 in binary - bitmask - bool same_bits = true; // Check if the last 3 bits of all bytes are the same for (int i = 1; i < PICOPASS_BLOCK_SIZE; i++) { if ((key[i] & 0x07) != last_three_bits) { same_bits = false; - break; } } - if (same_bits) { - PrintAndLogEx(SUCCESS, "Original key... " _GREEN_("%s"), sprint_hex_inrow(original_key, sizeof(original_key))); - PrintAndLogEx(SUCCESS, "Weak key....... " _YELLOW_("%s"), sprint_hex_inrow(key, sizeof(key))); - PrintAndLogEx(SUCCESS, "Key updates required to weak key..... " _GREEN_("%d"), index); - PrintAndLogEx(SUCCESS, "Estimated time ( default mode )...... " _GREEN_("~%d")" hours", index / 17800); - PrintAndLogEx(SUCCESS, "Estimated time ( default + --sl ).... " _GREEN_("~%d")" hours", index / 19450); - PrintAndLogEx(SUCCESS, "Estimated time ( --fast mode )....... " _GREEN_("~%d")" hours", index / 26860); - PrintAndLogEx(SUCCESS, "Estimated time ( --fast + --sl )..... " _GREEN_("~%d")" hours", index / 29750); - break; + bits_found = index; + PrintAndLogEx(SUCCESS, "Original Key: " _GREEN_("%s"), sprint_hex(original_key, sizeof(original_key))); + PrintAndLogEx(SUCCESS, "Weak Key: " _GREEN_("%s"), sprint_hex(key, sizeof(key))); + PrintAndLogEx(SUCCESS, "Key Updates Required to Weak Key: " _GREEN_("%d"), index); + PrintAndLogEx(SUCCESS, "Estimated Time: ~" _GREEN_("%d")" hours", index / 6545); } index++; - } // end while + }//end while PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; @@ -4949,9 +4461,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass legrec", - "Attempts to recover the diversified key of a specific iCLASS card. This may take several days.\n" - "The card must remain be on the PM3 antenna during the whole process.\n" - _RED_(" ! Warning ! ") _WHITE_(" This process may brick the card! ") _RED_(" ! Warning ! "), + "Attempts to recover the diversified key of a specific iClass card. This may take a long time. The Card must remain be on the PM3 antenna during the whole process! This process may brick the card!", "hf iclass legrec --macs 0000000089cb984b\n" "hf iclass legrec --macs 0000000089cb984b --index 0 --loop 100 --notest" ); @@ -4959,14 +4469,12 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { void *argtable[] = { arg_param_begin, arg_str1(NULL, "macs", "", "AA1 Authentication MACs"), - arg_int0(NULL, "index", "", "Where to start from to retrieve the key (def: 0)"), - arg_int0(NULL, "loop", "", "The number of key retrieval cycles to perform, max 10000 (def 100)"), - arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1"), - arg_lit0(NULL, "notest", "Perform real writes on the card"), - arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000"), - arg_lit0(NULL, "fast", "Increases the speed (4.6->7.4 key updates/second), higher risk to brick the card"), - arg_lit0(NULL, "sl", "Lower card comms delay times, further speeds increases, may cause more errors"), - arg_lit0(NULL, "est", "Estimates the key updates based on the card's CSN assuming standard key"), + arg_int0(NULL, "index", "", "Where to start from to retrieve the key, default 0"), + arg_int0(NULL, "loop", "", "The number of key retrieval cycles to perform, max 10000, default 100"), + arg_lit0(NULL, "debug", "Re-enables tracing for debugging. Limits cycles to 1."), + arg_lit0(NULL, "notest", "Perform real writes on the card!"), + arg_lit0(NULL, "allnight", "Loops the loop for 10 times, recommended loop value of 5000."), + arg_lit0(NULL, "est", "Estimates the key updates based on the card's CSN assuming standard key."), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -4981,9 +4489,7 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { bool test = true; bool no_test = arg_get_lit(ctx, 5); bool allnight = arg_get_lit(ctx, 6); - bool fast = arg_get_lit(ctx, 7); - bool short_delay = arg_get_lit(ctx, 8); - bool sim = arg_get_lit(ctx, 9); + bool sim = arg_get_lit(ctx, 7); if (sim) { CmdHFiClassLegacyRecSim(); @@ -5000,7 +4506,6 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { return PM3_EINVARG; } else if (debug || test) { loop = 1; - fast = false; } uint8_t csn[PICOPASS_BLOCK_SIZE] = {0}; @@ -5020,14 +4525,10 @@ static int CmdHFiClassLegacyRecover(const char *Cmd) { return PM3_EINVARG; } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "---------------------------------------"); - PrintAndLogEx(INFO, "Press " _GREEN_("pm3 button") " to abort"); - PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n"); - iclass_recover(macs, index, loop, no_first_auth, debug, test, fast, short_delay, allnight); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully")); - PrintAndLogEx(HINT, "Hint: run `" _YELLOW_("hf iclass legbrute -h") "` with the partial key found"); + iclass_recover(macs, index, loop, no_first_auth, debug, test, allnight); + + PrintAndLogEx(WARNING, _YELLOW_("If the process completed successfully, you can now run 'hf iclass legbrute' with the partial key found.")); + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; @@ -5060,32 +4561,13 @@ static int CmdHFiClassUnhash(const char *Cmd) { return PM3_EINVARG; } - //check if divkey respects hash0 rules (legacy format) or if it could be AES Based - - int count_lsb0 = 0; - int count_lsb1 = 0; - - for (int i = 0; i < PICOPASS_BLOCK_SIZE; i++) { - if ((div_key[i] & 0x01) == 0) { - count_lsb0++; - } else { - count_lsb1++; - } - } - - if (count_lsb0 != 4 || count_lsb1 != 4) { - PrintAndLogEx(INFO, _RED_("Incorrect LSB Distribution, unable to unhash - the key might be AES based.")); - return PM3_SUCCESS; - } - PrintAndLogEx(INFO, "Diversified key... %s", sprint_hex_inrow(div_key, sizeof(div_key))); - PrintAndLogEx(INFO, "-----------------------------------"); + invert_hash0(div_key); - PrintAndLogEx(INFO, "-----------------------------------"); - PrintAndLogEx(INFO, "You can now retrieve the master key by cracking DES with hashcat."); - PrintAndLogEx(INFO, "Create a text file with : on each line and use it with hashcat."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(HINT, "Hint: `" _YELLOW_("hashcat.exe -a 3 -m 14000 preimage:csn -1 charsets/DES_full.hcchr --hex-charset ?1?1?1?1?1?1?1?1") "`"); + + PrintAndLogEx(SUCCESS, "You can now retrieve the master key by cracking DES with hashcat!"); + PrintAndLogEx(SUCCESS, "hashcat.exe -a 3 -m 14000 preimage:csn -1 charsets/DES_full.hcchr --hex-charset ?1?1?1?1?1?1?1?1"); + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -5112,49 +4594,56 @@ static int CmdHFiClassLookUp(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); + bool use_vb6kdf = arg_get_lit(ctx, 7); int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; + bool use_elite = arg_get_lit(ctx, 5); + bool use_raw = arg_get_lit(ctx, 6); + if (use_vb6kdf) { + use_elite = true; + } else { + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + } + int csn_len = 0; uint8_t csn[8] = {0}; CLIGetHexWithReturn(ctx, 2, csn, &csn_len); + if (csn_len > 0) { + if (csn_len != 8) { + PrintAndLogEx(ERR, "CSN is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + int epurse_len = 0; uint8_t epurse[8] = {0}; CLIGetHexWithReturn(ctx, 3, epurse, &epurse_len); + if (epurse_len > 0) { + if (epurse_len != 8) { + PrintAndLogEx(ERR, "ePurse is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } + int macs_len = 0; uint8_t macs[8] = {0}; CLIGetHexWithReturn(ctx, 4, macs, &macs_len); - bool use_elite = arg_get_lit(ctx, 5); - bool use_raw = arg_get_lit(ctx, 6); - bool use_vb6kdf = arg_get_lit(ctx, 7); - - if (use_vb6kdf == false) { - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + if (macs_len > 0) { + if (macs_len != 8) { + PrintAndLogEx(ERR, "MAC is incorrect length"); + CLIParserFree(ctx); + return PM3_EINVARG; + } } CLIParserFree(ctx); - // santity checks - - if (csn_len > 0 && csn_len != 8) { - PrintAndLogEx(ERR, "CSN is incorrect length"); - return PM3_EINVARG; - } - - if (epurse_len > 0 && epurse_len != 8) { - PrintAndLogEx(ERR, "ePurse is incorrect length"); - return PM3_EINVARG; - } - - if (macs_len > 0 && macs_len != 8) { - PrintAndLogEx(ERR, "MAC is incorrect length"); - return PM3_EINVARG; - } - - uint8_t CCNR[12]; uint8_t MAC_TAG[4] = { 0, 0, 0, 0 }; @@ -5175,7 +4664,7 @@ static int CmdHFiClassLookUp(const char *Cmd) { uint8_t *keyBlock = NULL; uint32_t keycount = 0; - if (use_vb6kdf == false) { + if (!use_vb6kdf) { // Load keys int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount); if (res != PM3_SUCCESS || keycount == 0) { @@ -5199,8 +4688,7 @@ static int CmdHFiClassLookUp(const char *Cmd) { // Iclass_prekey_t iclass_prekey_t *prekey = calloc(keycount, sizeof(iclass_prekey_t)); - if (prekey == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); + if (!prekey) { free(keyBlock); return PM3_EMALLOC; } @@ -5221,7 +4709,7 @@ static int CmdHFiClassLookUp(const char *Cmd) { // Sort mac list qsort(prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32); - PrintAndLogEx(SUCCESS, "Searching for %s key...", _YELLOW_("DEBIT")); + PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", "DEBIT"); iclass_prekey_t *item; iclass_prekey_t lookup; memcpy(lookup.mac, MAC_TAG, 4); @@ -5230,7 +4718,7 @@ static int CmdHFiClassLookUp(const char *Cmd) { item = (iclass_prekey_t *) bsearch(&lookup, prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32); if (item != NULL) { - PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s"), sprint_hex_inrow(item->key, 8)); + PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s"), sprint_hex(item->key, 8)); add_key(item->key); } @@ -5271,24 +4759,23 @@ static void *bf_generate_mac(void *thread_arg) { uint8_t *keys = targ->keys; iclass_premac_t *list = targ->list.premac; - uint8_t csn[PICOPASS_BLOCK_SIZE]; + uint8_t csn[8]; uint8_t cc_nr[12]; memcpy(csn, targ->csn, sizeof(csn)); memcpy(cc_nr, targ->cc_nr, sizeof(cc_nr)); - uint8_t key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t div_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; for (uint32_t i = idx; i < keycnt; i += iclass_tc) { - memcpy(key, keys + 8 * i, PICOPASS_BLOCK_SIZE); + memcpy(key, keys + 8 * i, 8); pthread_mutex_lock(&generator_mutex); - if (use_raw) { - memcpy(div_key, key, PICOPASS_BLOCK_SIZE); - } else { + if (use_raw) + memcpy(div_key, key, 8); + else HFiClassCalcDivKey(csn, key, div_key, use_elite); - } doMAC(cc_nr, div_key, list[i].mac); pthread_mutex_unlock(&generator_mutex); @@ -5342,23 +4829,22 @@ static void *bf_generate_mackey(void *thread_arg) { uint8_t *keys = targ->keys; iclass_prekey_t *list = targ->list.prekey; - uint8_t csn[PICOPASS_BLOCK_SIZE]; + uint8_t csn[8]; uint8_t cc_nr[12]; memcpy(csn, targ->csn, sizeof(csn)); memcpy(cc_nr, targ->cc_nr, sizeof(cc_nr)); - uint8_t div_key[PICOPASS_BLOCK_SIZE] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; for (uint32_t i = idx; i < keycnt; i += iclass_tc) { - memcpy(list[i].key, keys + 8 * i, PICOPASS_BLOCK_SIZE); + memcpy(list[i].key, keys + 8 * i, 8); pthread_mutex_lock(&generator_mutex); - if (use_raw) { - memcpy(div_key, list[i].key, PICOPASS_BLOCK_SIZE); - } else { + if (use_raw) + memcpy(div_key, list[i].key, 8); + else HFiClassCalcDivKey(csn, list[i].key, div_key, use_elite); - } doMAC(cc_nr, div_key, list[i].mac); pthread_mutex_unlock(&generator_mutex); @@ -5394,19 +4880,17 @@ void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elit } } - for (int i = 0; i < iclass_tc; i++) { + for (int i = 0; i < iclass_tc; i++) pthread_join(threads[i], NULL); - } + } // print diversified keys void PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list) { iclass_prekey_t *b = calloc(keycnt, sizeof(iclass_prekey_t)); - if (b == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); + if (!b) return; - } for (uint32_t i = 0; i < keycnt; i++) { memcpy(b[i].key, keys + 8 * i, 8); @@ -5479,27 +4963,31 @@ static void shave(uint8_t *data, uint8_t len) { } static void generate_rev(uint8_t *data, uint8_t len) { uint8_t *key = calloc(len, sizeof(uint8_t)); - PrintAndLogEx(SUCCESS, "permuted key..... %s", sprint_hex_inrow(data, len)); + PrintAndLogEx(SUCCESS, "input permuted key | %s \n", sprint_hex(data, len)); permute_rev(data, len, key); - PrintAndLogEx(SUCCESS, "unpermuted key... %s", sprint_hex_inrow(key, len)); + PrintAndLogEx(SUCCESS, " unpermuted key | %s \n", sprint_hex(key, len)); shave(key, len); - PrintAndLogEx(SUCCESS, "key.............. %s", sprint_hex_inrow(key, len)); + PrintAndLogEx(SUCCESS, " key | %s \n", sprint_hex(key, len)); free(key); } static void generate(uint8_t *data, uint8_t len) { uint8_t *key = calloc(len, sizeof(uint8_t)); uint8_t *pkey = calloc(len, sizeof(uint8_t)); - PrintAndLogEx(SUCCESS, "input key...... %s", sprint_hex_inrow(data, len)); + PrintAndLogEx(SUCCESS, " input key | %s \n", sprint_hex(data, len)); permute(data, len, pkey); - PrintAndLogEx(SUCCESS, "permuted key... %s", sprint_hex_inrow(pkey, len)); + PrintAndLogEx(SUCCESS, "permuted key | %s \n", sprint_hex(pkey, len)); simple_crc(pkey, len, key); - PrintAndLogEx(SUCCESS, "CRC'ed key..... %s", sprint_hex_inrow(key, len)); + PrintAndLogEx(SUCCESS, " CRC'ed key | %s \n", sprint_hex(key, len)); free(key); free(pkey); } static int CmdHFiClassPermuteKey(const char *Cmd) { + uint8_t key[8] = {0}; + uint8_t data[16] = {0}; + int len = 0; + CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass permutekey", "Permute function from 'heart of darkness' paper.", @@ -5513,29 +5001,22 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - bool isReverse = arg_get_lit(ctx, 1); - - int dlen = 0; - uint8_t data[16] = {0}; - CLIGetHexWithReturn(ctx, 2, data, &dlen); + CLIGetHexWithReturn(ctx, 2, data, &len); CLIParserFree(ctx); - uint8_t key[PICOPASS_BLOCK_SIZE] = {0}; - memcpy(key, data, PICOPASS_BLOCK_SIZE); + memcpy(key, data, 8); if (isReverse) { - generate_rev(data, dlen); - uint8_t key_std_format[PICOPASS_BLOCK_SIZE] = {0}; + generate_rev(data, len); + uint8_t key_std_format[8] = {0}; permutekey_rev(key, key_std_format); - PrintAndLogEx(SUCCESS, "Standard NIST format key..... " _YELLOW_("%s"), sprint_hex_inrow(key_std_format, PICOPASS_BLOCK_SIZE)); - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Standard NIST format key " _YELLOW_("%s") " \n", sprint_hex(key_std_format, 8)); } else { - generate(data, dlen); - uint8_t key_iclass_format[PICOPASS_BLOCK_SIZE] = {0}; + generate(data, len); + uint8_t key_iclass_format[8] = {0}; permutekey(key, key_iclass_format); - PrintAndLogEx(SUCCESS, "HID permuted iCLASS format... " _YELLOW_("%s"), sprint_hex_inrow(key_iclass_format, PICOPASS_BLOCK_SIZE)); - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "HID permuted iCLASS format: %s \n", sprint_hex(key_iclass_format, 8)); } return PM3_SUCCESS; } @@ -5545,12 +5026,12 @@ static int CmdHFiClassEncode(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass encode", "Encode binary wiegand to block 7,8,9\n" - "Use either --bin or --wiegand/--fc/--cn\n" - "When using emulator you have to first load a credential into emulator memory", + "Use either --bin or --wiegand/--fc/--cn", "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337 (H10301)\n" "hf iclass encode -w H10301 --fc 31 --cn 337 --ki 0 -> FC 31 CN 337 (H10301)\n" "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337 (H10301), writing w elite key\n" - "hf iclass encode -w H10301 --fc 31 --cn 337 --emu -> Writes the ecoded data to emulator memory" + "hf iclass encode -w H10301 --fc 31 --cn 337 --emu -> Writes the ecoded data to emulator memory\n" + "When using emulator you have to first load a credential into emulator memory" ); void *argtable[] = { @@ -5906,74 +5387,43 @@ static int CmdHFiClassConfigCard(const char *Cmd) { return PM3_SUCCESS; } -static bool match_with_wildcard(const uint8_t *data, const uint8_t *pattern, const bool *mask, size_t length) { - for (size_t i = 0; i < length; ++i) { - if (mask[i] && data[i] != pattern[i]) { - return false; - } - } - return true; -} - static int CmdHFiClassSAM(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf iclass sam", "Extract PACS via a HID SAM\n", "hf iclass sam\n" - "hf iclass sam -p -d a005a103800104 -> get PACS data, prevent epurse update\n" - "hf iclass sam --break -> get Nr-MAC for extracting encrypted SIO\n" + "hf iclass sam -p -d a005a103800104 -> get PACS data, but ensure that epurse will stay unchanged\n" + "hf iclass sam --break-on-nr-mac -> get Nr-MAC for extracting encrypted SIO\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("v", "verbose", "verbose output"), - arg_lit0("k", "keep", "keep the field active after command executed"), - arg_lit0("n", "nodetect", "skip selecting the card and sending card details to SAM"), + arg_lit0("v", "verbose", "verbose output"), + arg_lit0("k", "keep", "keep the field active after command executed"), + arg_lit0("n", "nodetect", "skip selecting the card and sending card details to SAM"), arg_lit0("t", "tlv", "decode TLV"), - arg_lit0(NULL, "break", "stop tag interaction on nr-mac"), - arg_lit0("p", "prevent", "fake epurse update"), - arg_lit0(NULL, "shallow", "shallow mod"), - arg_strx0("d", "data", "", "DER encoded command to send to SAM"), - arg_lit0("s", "snmp", "data is in snmp format without headers"), - arg_lit0(NULL, "info", "get SAM infos (version, serial number)"), + arg_lit0(NULL, "break-on-nr-mac", "stop tag interaction on nr-mac"), + arg_lit0("p", "prevent-epurse-update", "fake epurse update"), + arg_lit0(NULL, "shallow", "shallow mod"), + arg_strx0("d", "data", "", "DER encoded command to send to SAM"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); bool verbose = arg_get_lit(ctx, 1); - bool disconnect_after = !arg_get_lit(ctx, 2); - bool skip_detect = arg_get_lit(ctx, 3); + bool disconnectAfter = !arg_get_lit(ctx, 2); + bool skipDetect = arg_get_lit(ctx, 3); bool decodeTLV = arg_get_lit(ctx, 4); - bool break_nrmac = arg_get_lit(ctx, 5); - bool prevent = arg_get_lit(ctx, 6); + bool breakOnNrMac = arg_get_lit(ctx, 5); + bool preventEpurseUpdate = arg_get_lit(ctx, 6); bool shallow_mod = arg_get_lit(ctx, 7); - bool snmp_data = arg_get_lit(ctx, 9); - bool info = arg_get_lit(ctx, 10); uint8_t flags = 0; - if (disconnect_after) { - flags |= BITMASK(0); - } - - if (skip_detect) { - flags |= BITMASK(1); - } - - if (break_nrmac) { - flags |= BITMASK(2); - } - - if (prevent) { - flags |= BITMASK(3); - } - - if (shallow_mod) { - flags |= BITMASK(4); - } - - if (info) { - flags |= BITMASK(5); - } + if (disconnectAfter) flags |= BITMASK(0); + if (skipDetect) flags |= BITMASK(1); + if (breakOnNrMac) flags |= BITMASK(2); + if (preventEpurseUpdate) flags |= BITMASK(3); + if (shallow_mod) flags |= BITMASK(4); uint8_t data[PM3_CMD_DATA_SIZE] = {0}; data[0] = flags; @@ -5990,24 +5440,13 @@ static int CmdHFiClassSAM(const char *Cmd) { return PM3_ESOFT; } - if (snmp_data) { - uint8_t header[4] = {0xa0, cmdlen + 2, 0x94, cmdlen }; - memmove(data + 4, data, cmdlen + 1); - data[0] = flags; - memcpy(data + 1, header, 4); - cmdlen += 4; - } - clearCommandBuffer(); SendCommandNG(CMD_HF_SAM_PICOPASS, data, cmdlen + 1); PacketResponseNG resp; - WaitForResponse(CMD_HF_SAM_PICOPASS, &resp); - - bool is_snmp = false; - uint8_t snmp_pattern[] = {0xBD, 0x81, 0xFF, 0x8A, 0x81, 0xFF}; // SNMP Response header pattern, 0xFF is a wildcard value for message length - bool snmp_mask[] = {true, true, false, true, true, false}; // false means wildcard value in that position - uint8_t ok_pattern[] = {0xBD, 0xFF, 0x8A}; // Ok response header pattern, 0xFF is a wildcard value for message length - bool ok_mask[] = {true, false, true}; // false means wildcard value in that position + if (WaitForResponseTimeout(CMD_HF_SAM_PICOPASS, &resp, 4000) == false) { + PrintAndLogEx(WARNING, "SAM timeout"); + return PM3_ETIMEOUT; + } switch (resp.status) { case PM3_SUCCESS: @@ -6055,36 +5494,22 @@ static int CmdHFiClassSAM(const char *Cmd) { const uint8_t *oid = pacs + 2 + pacs_length; const uint8_t oid_length = oid[1]; const uint8_t *oid_data = oid + 2; - PrintAndLogEx(SUCCESS, "SIO OID.......... " _GREEN_("%s"), sprint_hex_inrow(oid_data, oid_length)); + PrintAndLogEx(SUCCESS, "SIO OID.......: " _GREEN_("%s"), sprint_hex_inrow(oid_data, oid_length)); const uint8_t *mediaType = oid + 2 + oid_length; const uint8_t mediaType_data = mediaType[2]; - PrintAndLogEx(SUCCESS, "SIO Media Type... " _GREEN_("%s"), getSioMediaTypeInfo(mediaType_data)); - } else if (break_nrmac && d[0] == 0x05) { - PrintAndLogEx(SUCCESS, "Nr-MAC........... " _GREEN_("%s"), sprint_hex_inrow(d + 1, 8)); + PrintAndLogEx(SUCCESS, "SIO Media Type: " _GREEN_("%s"), getSioMediaTypeInfo(mediaType_data)); + } else if (breakOnNrMac && d[0] == 0x05) { + PrintAndLogEx(SUCCESS, "Nr-MAC: " _GREEN_("%s"), sprint_hex_inrow(d + 1, 8)); if (verbose) { PrintAndLogEx(INFO, "Replay Nr-MAC to dump SIO:"); - PrintAndLogEx(SUCCESS, " hf iclass dump --nr -k %s", sprint_hex_inrow(d + 1, 8)); + PrintAndLogEx(SUCCESS, " hf iclass dump -k \"%s\" --nr", sprint_hex_inrow(d + 1, 8)); } } else { - //if it is an error decode it - if (memcmp(d, "\xBE\x07\x80\x01", 4) == 0) { //if it the string is 0xbe 0x07 0x80 0x01 the next byte will indicate the error code - PrintAndLogEx(ERR, _RED_("Sam Error Code: %02x"), d[4]); - print_hex(d, resp.length); - } else if (match_with_wildcard(d, snmp_pattern, snmp_mask, 6)) { - is_snmp = true; - PrintAndLogEx(SUCCESS, _YELLOW_("[samSNMPMessageResponse] ")"%s", sprint_hex(d + 6, resp.length - 6)); - } else if (match_with_wildcard(d, ok_pattern, ok_mask, 3)) { - PrintAndLogEx(SUCCESS, _YELLOW_("[samResponseAcknowledge] ")"%s", sprint_hex(d + 4, resp.length - 4)); - } else { - print_hex(d, resp.length); - } + print_hex(d, resp.length); } - - if (decodeTLV && is_snmp == false) { + if (decodeTLV) { asn1_print(d, d[1] + 2, " "); - } else if (decodeTLV && is_snmp) { - asn1_print(d + 6, resp.length - 6, " "); } return PM3_SUCCESS; @@ -6105,14 +5530,14 @@ static command_t CommandTable[] = { {"view", CmdHFiClassView, AlwaysAvailable, "Display content from tag dump file"}, {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "Write Picopass / iCLASS block"}, {"creditepurse", CmdHFiClassCreditEpurse, IfPm3Iclass, "Credit epurse value"}, - {"tear", CmdHFiClass_TearBlock, IfPm3Iclass, "Performs tearoff attack on iCLASS block"}, + {"trbl", CmdHFiClass_TearBlock, IfPm3Iclass, "Performs tearoff attack on iClass block"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("Recovery") " --------------------"}, // {"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "Automatic key recovery tool for iCLASS"}, {"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "Check keys"}, {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "Use loclass to perform bruteforce reader attack"}, {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "Uses authentication trace to check for key in dictionary file"}, {"legrec", CmdHFiClassLegacyRecover, IfPm3Iclass, "Recovers 24 bits of the diversified key of a legacy card provided a valid nr-mac combination"}, - {"legbrute", CmdHFiClassLegBrute, AlwaysAvailable, "Bruteforces 40 bits of a partial diversified key, provided 24 bits of the key and two valid nr-macs"}, + {"legbrute", CmdHFiClassLegRecLookUp, AlwaysAvailable, "Bruteforces 40 bits of a partial diversified key, provided 24 bits of the key and two valid nr-macs"}, {"unhash", CmdHFiClassUnhash, AlwaysAvailable, "Reverses a diversified key to retrieve hash0 pre-images after DES encryption"}, {"-----------", CmdHelp, IfPm3Iclass, "-------------------- " _CYAN_("Simulation") " -------------------"}, {"sim", CmdHFiClassSim, IfPm3Iclass, "Simulate iCLASS tag"}, @@ -6191,7 +5616,7 @@ int info_iclass(bool shallow_mod) { picopass_ns_hdr_t *ns_hdr = &r->header.ns_hdr; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " -------------------------------------"); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ----------------------------------------"); if ((r->status & FLAG_ICLASS_CSN) == FLAG_ICLASS_CSN) { PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); @@ -6209,19 +5634,19 @@ int info_iclass(bool shallow_mod) { } else { if ((r->status & FLAG_ICLASS_CC) == FLAG_ICLASS_CC) { - PrintAndLogEx(SUCCESS, "E-purse: %s card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); + PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); } if (memcmp(hdr->key_d, zeros, sizeof(zeros))) { PrintAndLogEx(SUCCESS, " Kd: " _YELLOW_("%s") " debit key", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); } else { - PrintAndLogEx(SUCCESS, " Kd: -- -- -- -- -- -- -- -- debit key ( hidden )"); + PrintAndLogEx(SUCCESS, " Kd: %s debit key ( hidden )", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); } if (memcmp(hdr->key_c, zeros, sizeof(zeros))) { PrintAndLogEx(SUCCESS, " Kc: " _YELLOW_("%s") " credit key", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); } else { - PrintAndLogEx(SUCCESS, " Kc: -- -- -- -- -- -- -- -- credit key ( hidden )"); + PrintAndLogEx(SUCCESS, " Kc: %s credit key ( hidden )", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); } @@ -6234,7 +5659,7 @@ int info_iclass(bool shallow_mod) { print_picopass_info(hdr); } - PrintAndLogEx(INFO, "----------------------- " _CYAN_("Fingerprint") " ---------------------"); + PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------"); uint8_t aia[8]; if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { @@ -6266,46 +5691,33 @@ int info_iclass(bool shallow_mod) { uint8_t cardtype = get_mem_config(hdr); PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]); - if (memcmp(hdr->csn + 4, "\xFE\xFF\x12\xE0", 4) == 0) { - PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("NEW Silicon (No 14b support)")); - } else { + if (HF14B_picopass_reader(false, false)) { PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("Old Silicon (14b support)")); + } else { + PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("NEW Silicon (No 14b support)")); } if (legacy) { int res = PM3_ESOFT; + uint8_t key_type = 0x88; // debit key + uint8_t dump[PICOPASS_BLOCK_SIZE * 8] = {0}; // we take all raw bytes from response memcpy(dump, p_response, sizeof(picopass_hdr_t)); - bool found_aa1 = false; - bool found_aa2 = false; uint8_t key[8] = {0}; for (uint8_t i = 0; i < ARRAYLEN(iClass_Key_Table); i++) { memcpy(key, iClass_Key_Table[i], sizeof(key)); - - if (found_aa1 == false) { - res = iclass_read_block_ex(key, 6, ICLASS_DEBIT_KEYTYPE, false, false, false, false, true, false, dump + (PICOPASS_BLOCK_SIZE * 6), false); - if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, " AA1 Key...... " _GREEN_("%s"), sprint_hex_inrow(key, sizeof(key))); - found_aa1 = true; - } - } - - res = iclass_read_block_ex(key, 6, ICLASS_CREDIT_KEYTYPE, false, false, false, false, true, false, dump + (PICOPASS_BLOCK_SIZE * 7), false); + res = iclass_read_block_ex(key, 6, key_type, false, false, false, false, true, false, dump + (PICOPASS_BLOCK_SIZE * 6), false); if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, " AA2 Key...... " _GREEN_("%s"), sprint_hex_inrow(key, sizeof(key))); - found_aa2 = true; - } - - if (found_aa1 && found_aa2) { + PrintAndLogEx(SUCCESS, " AA1 Key...... " _GREEN_("%s"), sprint_hex_inrow(key, sizeof(key))); break; } } - if (found_aa1) { - res = iclass_read_block_ex(key, 7, ICLASS_DEBIT_KEYTYPE, false, false, false, false, true, false, dump + (PICOPASS_BLOCK_SIZE * 7), false); + if (res == PM3_SUCCESS) { + res = iclass_read_block_ex(key, 7, key_type, false, false, false, false, true, false, dump + (PICOPASS_BLOCK_SIZE * 7), false); if (res == PM3_SUCCESS) { BLOCK79ENCRYPTION aa1_encryption = (dump[(6 * PICOPASS_BLOCK_SIZE) + 7] & 0x03); @@ -6321,6 +5733,5 @@ int info_iclass(bool shallow_mod) { } } - PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } diff --git a/client/src/cmdhfjooki.c b/client/src/cmdhfjooki.c index 81e7b3546..51f61e619 100644 --- a/client/src/cmdhfjooki.c +++ b/client/src/cmdhfjooki.c @@ -584,7 +584,7 @@ static int CmdHF14AJookiSim(const char *Cmd) { for (;;) { if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(DEBUG, "\naborted via keyboard!"); + PrintAndLogEx(DEBUG, "User aborted"); break; } diff --git a/client/src/cmdhfksx6924.c b/client/src/cmdhfksx6924.c index b6a72fe2e..7616ca766 100644 --- a/client/src/cmdhfksx6924.c +++ b/client/src/cmdhfksx6924.c @@ -358,7 +358,7 @@ end: static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"select", CmdHFKSX6924Select, IfPm3Iso14443a, "Select application, and leave field up"}, - {"info", CmdHFKSX6924Info, IfPm3Iso14443a, "Tag information"}, + {"info", CmdHFKSX6924Info, IfPm3Iso14443a, "Get info about a KS X 6924 (T-Money, Snapper+) transit card"}, {"balance", CmdHFKSX6924Balance, IfPm3Iso14443a, "Get current purse balance"}, {"init", CmdHFKSX6924Initialize, IfPm3Iso14443a, "Perform transaction initialization with Mpda"}, {"prec", CmdHFKSX6924PRec, IfPm3Iso14443a, "Send proprietary get record command (CLA=90, INS=4C)"}, diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index f47466761..0ff062532 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -560,7 +560,7 @@ static int CmdLegicSim(const char *Cmd) { for (;;) { if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(DEBUG, "Aborted via keyboard!"); + PrintAndLogEx(DEBUG, "User aborted"); break; } @@ -781,20 +781,17 @@ int legic_print_type(uint32_t tagtype, uint8_t spaces) { } int legic_get_type(legic_card_select_t *card) { - if (card == NULL) { + if (card == NULL) return PM3_EINVARG; - } clearCommandBuffer(); SendCommandNG(CMD_HF_LEGIC_INFO, NULL, 0); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_LEGIC_INFO, &resp, 1500) == false) { + if (WaitForResponseTimeout(CMD_HF_LEGIC_INFO, &resp, 1500) == false) return PM3_ETIMEOUT; - } - if (resp.status != PM3_SUCCESS) { + if (resp.status != PM3_SUCCESS) return PM3_ESOFT; - } memcpy(card, resp.data.asBytes, sizeof(legic_card_select_t)); return PM3_SUCCESS; @@ -1530,7 +1527,7 @@ int readLegicUid(bool loop, bool verbose) { PrintAndLogEx(SUCCESS, " MSN: " _GREEN_("%s"), sprint_hex(card.uid + 1, sizeof(card.uid) - 1)); legic_print_type(card.cardsize, 0); - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); return PM3_SUCCESS; } diff --git a/client/src/cmdhflto.c b/client/src/cmdhflto.c index 1eadb3d67..b56a0d34c 100644 --- a/client/src/cmdhflto.c +++ b/client/src/cmdhflto.c @@ -131,7 +131,7 @@ static int lto_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint16 SendCommandMIX(CMD_HF_ISO14443A_READER, arg0, arg1, 0, cmd, len); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); return PM3_ETIMEOUT; } @@ -438,7 +438,7 @@ int reader_lto(bool loop, bool verbose) { PrintAndLogEx(INFO, "UID......... " _GREEN_("%s"), sprint_hex_inrow(serial, sizeof(serial))); } - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); lto_switch_off_field(); return ret; diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index e35b6e18f..74899cd38 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -48,302 +48,8 @@ #include "mifare/mifarehost.h" #include "crypto/originality.h" -// Defines for Saflok parsing -#define SAFLOK_YEAR_OFFSET 1980 -#define SAFLOK_BASIC_ACCESS_BYTE_NUM 17 - -typedef struct { - uint64_t a; - uint64_t b; -} MfClassicKeyPair; - -// Structure for Saflok key levels -typedef struct { - uint8_t level_num; - const char *level_name; -} SaflokKeyLevel; - static int CmdHelp(const char *Cmd); -// Static array for Saflok key levels -static const SaflokKeyLevel saflok_key_levels[] = { - {1, "Guest Key"}, - {2, "Connectors"}, - {3, "Suite"}, - {4, "Limited Use"}, - {5, "Failsafe"}, - {6, "Inhibit"}, - {7, "Pool/Meeting Master"}, - {8, "Housekeeping"}, - {9, "Floor Key"}, - {10, "Section Key"}, - {11, "Rooms Master"}, - {12, "Grand Master"}, - {13, "Emergency"}, - {14, "Electronic Lockout"}, - {15, "Secondary Programming Key (SPK)"}, - {16, "Primary Programming Key (PPK)"}, -}; - -// Lookup table for Saflok decryption -static const uint8_t saflok_c_aDecode[256] = { - 0xEA, 0x0D, 0xD9, 0x74, 0x4E, 0x28, 0xFD, 0xBA, 0x7B, 0x98, 0x87, 0x78, 0xDD, 0x8D, 0xB5, - 0x1A, 0x0E, 0x30, 0xF3, 0x2F, 0x6A, 0x3B, 0xAC, 0x09, 0xB9, 0x20, 0x6E, 0x5B, 0x2B, 0xB6, - 0x21, 0xAA, 0x17, 0x44, 0x5A, 0x54, 0x57, 0xBE, 0x0A, 0x52, 0x67, 0xC9, 0x50, 0x35, 0xF5, - 0x41, 0xA0, 0x94, 0x60, 0xFE, 0x24, 0xA2, 0x36, 0xEF, 0x1E, 0x6B, 0xF7, 0x9C, 0x69, 0xDA, - 0x9B, 0x6F, 0xAD, 0xD8, 0xFB, 0x97, 0x62, 0x5F, 0x1F, 0x38, 0xC2, 0xD7, 0x71, 0x31, 0xF0, - 0x13, 0xEE, 0x0F, 0xA3, 0xA7, 0x1C, 0xD5, 0x11, 0x4C, 0x45, 0x2C, 0x04, 0xDB, 0xA6, 0x2E, - 0xF8, 0x64, 0x9A, 0xB8, 0x53, 0x66, 0xDC, 0x7A, 0x5D, 0x03, 0x07, 0x80, 0x37, 0xFF, 0xFC, - 0x06, 0xBC, 0x26, 0xC0, 0x95, 0x4A, 0xF1, 0x51, 0x2D, 0x22, 0x18, 0x01, 0x79, 0x5E, 0x76, - 0x1D, 0x7F, 0x14, 0xE3, 0x9E, 0x8A, 0xBB, 0x34, 0xBF, 0xF4, 0xAB, 0x48, 0x63, 0x55, 0x3E, - 0x56, 0x8C, 0xD1, 0x12, 0xED, 0xC3, 0x49, 0x8E, 0x92, 0x9D, 0xCA, 0xB1, 0xE5, 0xCE, 0x4D, - 0x3F, 0xFA, 0x73, 0x05, 0xE0, 0x4B, 0x93, 0xB2, 0xCB, 0x08, 0xE1, 0x96, 0x19, 0x3D, 0x83, - 0x39, 0x75, 0xEC, 0xD6, 0x3C, 0xD0, 0x70, 0x81, 0x16, 0x29, 0x15, 0x6C, 0xC7, 0xE7, 0xE2, - 0xF6, 0xB7, 0xE8, 0x25, 0x6D, 0x3A, 0xE6, 0xC8, 0x99, 0x46, 0xB0, 0x85, 0x02, 0x61, 0x1B, - 0x8B, 0xB3, 0x9F, 0x0B, 0x2A, 0xA8, 0x77, 0x10, 0xC1, 0x88, 0xCC, 0xA4, 0xDE, 0x43, 0x58, - 0x23, 0xB4, 0xA1, 0xA5, 0x5C, 0xAE, 0xA9, 0x7E, 0x42, 0x40, 0x90, 0xD2, 0xE9, 0x84, 0xCF, - 0xE4, 0xEB, 0x47, 0x4F, 0x82, 0xD4, 0xC5, 0x8F, 0xCD, 0xD3, 0x86, 0x00, 0x59, 0xDF, 0xF2, - 0x0C, 0x7C, 0xC6, 0xBD, 0xF9, 0x7D, 0xC4, 0x91, 0x27, 0x89, 0x32, 0x72, 0x33, 0x65, 0x68, - 0xAF -}; - -// Function to decrypt Saflok card data -static void DecryptSaflokCardData( - const uint8_t strCard[SAFLOK_BASIC_ACCESS_BYTE_NUM], - uint8_t decryptedCard[SAFLOK_BASIC_ACCESS_BYTE_NUM] -) { - int i; - int num; - int num2; - int num3; - int num4; - int b = 0; - int b2 = 0; - - for (i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM; i++) { - num = saflok_c_aDecode[strCard[i]] - (i + 1); - if (num < 0) num += 256; - decryptedCard[i] = num; - } - - b = decryptedCard[10]; - b2 = b & 1; - - for (num2 = SAFLOK_BASIC_ACCESS_BYTE_NUM; num2 > 0; num2--) { - b = decryptedCard[num2 - 1]; - for (num3 = 8; num3 > 0; num3--) { - num4 = num2 + num3; - if (num4 > SAFLOK_BASIC_ACCESS_BYTE_NUM) num4 -= SAFLOK_BASIC_ACCESS_BYTE_NUM; - int b3 = decryptedCard[num4 - 1]; - int b4 = (b3 & 0x80) >> 7; - b3 = ((b3 << 1) & 0xFF) | b2; - b2 = (b & 0x80) >> 7; - b = ((b << 1) & 0xFF) | b4; - decryptedCard[num4 - 1] = b3; - } - decryptedCard[num2 - 1] = b; - } -} - -// Function to calculate Saflok checksum -static uint8_t CalculateCheckSum(uint8_t data[SAFLOK_BASIC_ACCESS_BYTE_NUM]) { - int sum = 0; - for (int i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM - 1; i++) { - sum += data[i]; - } - sum = 255 - (sum & 0xFF); - return sum & 0xFF; -} - -// Function to parse and print Saflok data -static void ParseAndPrintSaflokData(const sector_t *sector0_info, const sector_t *sector1_info) { - (void)sector1_info; // Not directly used for payload parsing currently - - if (sector0_info == NULL) { - PrintAndLogEx(WARNING, "Saflok: Sector 0 information not available for parsing"); - return; - } - - uint8_t key_bytes_for_s0[MIFARE_KEY_SIZE]; - uint8_t key_type_for_s0; // CORRECTED: Was MifareKeyType, now uint8_t - bool s0_key_found = false; - - // Prioritize Key A for Sector 0 if available - if (sector0_info->foundKey[MF_KEY_A]) { - num_to_bytes(sector0_info->Key[MF_KEY_A], MIFARE_KEY_SIZE, key_bytes_for_s0); - key_type_for_s0 = MF_KEY_A; // MF_KEY_A is typically #define'd as 0x60 - s0_key_found = true; - PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key A for reading blocks"); - } else if (sector0_info->foundKey[MF_KEY_B]) { // Fallback to Key B for Sector 0 - num_to_bytes(sector0_info->Key[MF_KEY_B], MIFARE_KEY_SIZE, key_bytes_for_s0); - key_type_for_s0 = MF_KEY_B; // MF_KEY_B is typically #define'd as 0x61 - s0_key_found = true; - PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key B for reading blocks"); - } - - if (s0_key_found == false) { - PrintAndLogEx(WARNING, "Saflok: No known keys for Sector 0. Cannot read blocks 1 & 2 for parsing"); - return; - } - - uint8_t block1_content[MFBLOCK_SIZE]; - uint8_t block2_content[MFBLOCK_SIZE]; - - // Read absolute block 1 (data block within sector 0) - if (mf_read_block(1, key_type_for_s0, key_bytes_for_s0, block1_content) != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 1 using Sector 0 %s key", (key_type_for_s0 == MF_KEY_A) ? "A" : "B"); - return; - } - PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 1"); - - // Read absolute block 2 (data block within sector 0) - if (mf_read_block(2, key_type_for_s0, key_bytes_for_s0, block2_content) != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 2 using Sector 0 %s key", (key_type_for_s0 == MF_KEY_A) ? "A" : "B"); - return; - } - PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 2"); - - uint8_t basicAccess[SAFLOK_BASIC_ACCESS_BYTE_NUM]; - uint8_t decodedBA[SAFLOK_BASIC_ACCESS_BYTE_NUM]; - - memcpy(basicAccess, block1_content, MFBLOCK_SIZE); // 16 bytes from Block 1 - memcpy(basicAccess + MFBLOCK_SIZE, block2_content, 1); // 1 byte from Block 2 - - DecryptSaflokCardData(basicAccess, decodedBA); - - - // Byte 0: Key level, LED warning bit, and subgroup functions - uint8_t key_level = (decodedBA[0] & 0xF0) >> 4; - uint8_t led_warning = (decodedBA[0] & 0x08) >> 3; - - // Byte 1: Key ID - uint8_t key_id = decodedBA[1]; - - // Byte 2 & 3: KeyRecord, including OpeningKey flag - uint8_t opening_key = (decodedBA[2] & 0x80) >> 7; - uint16_t key_record = ((decodedBA[2] & 0x3F) << 8) | decodedBA[3]; - - // Byte 5 & 6: EncryptSequence + Combination - uint16_t sequence_combination_number = ((decodedBA[5] & 0x0F) << 8) | decodedBA[6]; - - // Byte 7: OverrideDeadbolt and Days - uint8_t override_deadbolt = (decodedBA[7] & 0x80) >> 7; - uint8_t restricted_weekday = decodedBA[7] & 0x7F; - - // Weekday names array - static const char *weekdays[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"}; - - // Buffer to store the resulting string (sufficient size for all weekdays) - char restricted_weekday_string[128] = {0}; - int restricted_count = 0; - - // Check each bit from Monday to Sunday - for (int i = 0; i < 7; i++) { - if (restricted_weekday & (0b01000000 >> i)) { - // If the bit is set, append the corresponding weekday to the buffer - if (restricted_count > 0) { - strcat(restricted_weekday_string, ", "); - } - strcat(restricted_weekday_string, weekdays[i]); - restricted_count++; - } - } - - // Determine if all weekdays are restricted - if (restricted_weekday == 0b01111100) { - strcpy(restricted_weekday_string, "weekdays"); - } - // If there are specific restricted days - else if (restricted_weekday == 0b00000011) { - strcpy(restricted_weekday_string, "weekends"); - } - // If no weekdays are restricted - else if (restricted_weekday == 0) { - strcpy(restricted_weekday_string, "none"); - } - - // Bytes 14-15: Property number and part of creation year - uint8_t creation_year_high_bits = (decodedBA[14] & 0xF0); - uint16_t property_id = ((decodedBA[14] & 0x0F) << 8) | decodedBA[15]; - - // Bytes 11-13: Creation date since SAFLOK_YEAR_OFFSET Jan 1st - uint16_t creation_year = (creation_year_high_bits | (decodedBA[11] >> 4)) + SAFLOK_YEAR_OFFSET; - uint8_t creation_month = decodedBA[11] & 0x0F; - uint8_t creation_day = (decodedBA[12] >> 3) & 0x1F; - uint8_t creation_hour = ((decodedBA[12] & 0x07) << 2) | ((decodedBA[13] & 0xC0) >> 6); - uint8_t creation_minute = decodedBA[13] & 0x3F; - - // Bytes 8-10: Expiry interval / absolute time components - uint8_t interval_year_val = (decodedBA[8] >> 4); - uint8_t interval_month_val = decodedBA[8] & 0x0F; - uint8_t interval_day_val = (decodedBA[9] >> 3) & 0x1F; - uint8_t expiry_hour = ((decodedBA[9] & 0x07) << 2) | ((decodedBA[10] & 0xC0) >> 6); - uint8_t expiry_minute = decodedBA[10] & 0x3F; - - uint16_t expire_year = creation_year + interval_year_val; - uint8_t expire_month = creation_month + interval_month_val; - uint8_t expire_day = creation_day + interval_day_val; - - // Handle month rollover for expiration - while (expire_month > 12) { - expire_month -= 12; - expire_year++; - } - - // Handle day rollover for expiration - static const uint8_t days_in_month_lookup[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 1-indexed month - if (expire_month > 0 && expire_month <= 12) { - - while (true) { - - uint8_t max_days = days_in_month_lookup[expire_month]; - if (expire_month == 2 && - (expire_year % 4 == 0 && - (expire_year % 100 != 0 || expire_year % 400 == 0))) { - max_days = 29; // Leap year - } - - if (expire_day <= max_days) { - break; - } - - if (max_days == 0) { // Should not happen with valid month - PrintAndLogEx(WARNING, "Saflok: Invalid day/month for expiration rollover calculation"); - break; - } - - expire_day -= max_days; - expire_month++; - if (expire_month > 12) { - expire_month = 1; - expire_year++; - } - } - - } else if (expire_month != 0) { // Allow 0 if it signifies no expiration or error - PrintAndLogEx(WARNING, "Saflok: Invalid expiration month (%u) before day rollover", expire_month); - } - - uint8_t checksum = decodedBA[16]; - uint8_t checksum_calculated = CalculateCheckSum(decodedBA); - bool checksum_valid = (checksum_calculated == checksum); - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Saflok details")); - PrintAndLogEx(SUCCESS, "Key Level............. %u (%s)", saflok_key_levels[key_level].level_num, saflok_key_levels[key_level].level_name); - PrintAndLogEx(SUCCESS, "LED Warning........... %s", led_warning ? "Yes" : "No"); - PrintAndLogEx(SUCCESS, "Key ID................ %u (0x%02X)", key_id, key_id); - PrintAndLogEx(SUCCESS, "Key Record............ %u (0x%04X)", key_record, key_record); - PrintAndLogEx(SUCCESS, "Opening Key........... %s", opening_key ? "Yes" : "No"); - PrintAndLogEx(SUCCESS, "Sequence & Combination: %u (0x%02X)", sequence_combination_number, sequence_combination_number); - PrintAndLogEx(SUCCESS, "Override Deadbolt..... %s", override_deadbolt ? "Yes" : "No"); - PrintAndLogEx(SUCCESS, "Restricted Weekdays... %s", restricted_weekday_string); - PrintAndLogEx(SUCCESS, "Property ID........... %u (0x%04X)", property_id, property_id); - PrintAndLogEx(SUCCESS, "Creation Date......... %04u-%02u-%02u %02u:%02u", creation_year, creation_month, creation_day, creation_hour, creation_minute); - PrintAndLogEx(SUCCESS, "Expiration Date....... %04u-%02u-%02u %02u:%02u", expire_year, expire_month, expire_day, expiry_hour, expiry_minute); - PrintAndLogEx(SUCCESS, "Checksum Valid........ ( %s )", checksum_valid ? _GREEN_("ok") : _RED_("fail")); -} - /* static int usage_hf14_keybrute(void) { PrintAndLogEx(NORMAL, "J_Run's 2nd phase of multiple sector nested authentication key recovery"); @@ -369,7 +75,7 @@ int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, in static int mf_read_uid(uint8_t *uid, int *uidlen, int *nxptype) { clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { PrintAndLogEx(DEBUG, "iso14443a card select failed"); @@ -380,63 +86,20 @@ static int mf_read_uid(uint8_t *uid, int *uidlen, int *nxptype) { iso14a_card_select_t card; memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - uint64_t select_status = resp.oldarg[0]; - - // try to request ATS even if tag claims not to support it. If yes => 4 - if (select_status == 2) { - uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, sizeof(rats)); - if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { - PrintAndLogEx(WARNING, "timeout while waiting for reply"); - return PM3_ETIMEOUT; - } - - memcpy(card.ats, resp.data.asBytes, resp.oldarg[0]); - card.ats_len = resp.oldarg[0]; // note: ats_len includes CRC Bytes - if (card.ats_len > 3) { - select_status = 4; - } - } - - uint8_t ats_hist_pos = 0; - if ((card.ats_len > 3) && (card.ats[0] > 1)) { - ats_hist_pos = 2; - ats_hist_pos += (card.ats[1] & 0x10) == 0x10; - ats_hist_pos += (card.ats[1] & 0x20) == 0x20; - ats_hist_pos += (card.ats[1] & 0x40) == 0x40; - } - - version_hw_t version_hw = {0}; - // if 4b UID or NXP, try to get version - int res = hf14a_getversion_data(&card, select_status, &version_hw); - DropField(); - - bool version_hw_available = (res == PM3_SUCCESS); - if (nxptype) { - - *nxptype = detect_nxp_card(card.sak - , ((card.atqa[1] << 8) + card.atqa[0]) - , select_status - , card.ats_len - ats_hist_pos - , card.ats + ats_hist_pos - , version_hw_available - , &version_hw - ); + uint64_t select_status = resp.oldarg[0]; + *nxptype = detect_nxp_card(card.sak, ((card.atqa[1] << 8) + card.atqa[0]), select_status); } memcpy(uid, card.uid, card.uidlen * sizeof(uint8_t)); *uidlen = card.uidlen; - return PM3_SUCCESS; } static char *GenerateFilename(const char *prefix, const char *suffix) { - if (IfPm3Iso14443a() == false) { + if (! IfPm3Iso14443a()) { return NULL; } - uint8_t uid[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int uidlen = 0; char *fptr = calloc(sizeof(char) * (strlen(prefix) + strlen(suffix)) + sizeof(uid) * 2 + 1, sizeof(uint8_t)); @@ -476,19 +139,20 @@ static int initSectorTable(sector_t **src, size_t items) { static void decode_print_st(uint16_t blockno, uint8_t *data) { if (mfIsSectorTrailer(blockno)) { PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "------------------------ " _CYAN_("Sector trailer decoder") " ------------------------"); - PrintAndLogEx(INFO, " Key A........ " _BRIGHT_GREEN_("%s"), sprint_hex_inrow(data, 6)); - PrintAndLogEx(INFO, " ACR.......... " _MAGENTA_("%s"), sprint_hex_inrow(data + 6, 3)); - PrintAndLogEx(INFO, " User / gpb... %02x", data[9]); - PrintAndLogEx(INFO, " Key B........ " _GREEN_("%s"), sprint_hex_inrow(data + 10, 6)); + PrintAndLogEx(INFO, "-------------------------- " _CYAN_("Sector trailer decoder") " --------------------------"); + PrintAndLogEx(INFO, "key A........ " _GREEN_("%s"), sprint_hex_inrow(data, 6)); + PrintAndLogEx(INFO, "acr.......... " _GREEN_("%s"), sprint_hex_inrow(data + 6, 3)); + PrintAndLogEx(INFO, "user / gpb... " _GREEN_("%02x"), data[9]); + PrintAndLogEx(INFO, "key B........ " _GREEN_("%s"), sprint_hex_inrow(data + 10, 6)); PrintAndLogEx(INFO, ""); PrintAndLogEx(INFO, " # | access rights"); - PrintAndLogEx(INFO, "----+-------------------------------------------------------------------"); + PrintAndLogEx(INFO, "----+-----------------------------------------------------------------------"); if (mfValidateAccessConditions(&data[6]) == false) { - PrintAndLogEx(WARNING, _RED_("Invalid access conditions")); + PrintAndLogEx(WARNING, _RED_("Invalid Access Conditions")); } + int bln = mfFirstBlockOfSector(mfSectorNum(blockno)); int blinc = (mfNumBlocksPerSector(mfSectorNum(blockno)) > 4) ? 5 : 1; for (int i = 0; i < 4; i++) { @@ -499,13 +163,13 @@ static void decode_print_st(uint16_t blockno, uint8_t *data) { uint8_t cond = mf_get_accesscondition(i, &data[6]); if (cond == 0 || cond == 1 || cond == 2) { PrintAndLogEx(INFO, ""); - PrintAndLogEx(INFO, "OBS!"); - PrintAndLogEx(INFO, "Key B is readable, it SHALL NOT be able to authenticate on original MFC"); + PrintAndLogEx(INFO, "OBS! Key B is readable, it SHALL NOT be able to authenticate on original MFC"); } } } - PrintAndLogEx(INFO, "------------------------------------------------------------------------"); + + PrintAndLogEx(INFO, "----------------------------------------------------------------------------"); PrintAndLogEx(NORMAL, ""); } } @@ -582,7 +246,7 @@ void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) { char ascii[24] = {0}; ascii_to_buffer((uint8_t *)ascii, d, MFBLOCK_SIZE, sizeof(ascii) - 1, 1); - PrintAndLogEx(INFO, "%3d | " _BRIGHT_GREEN_("%s") _MAGENTA_("%s") "%02X " _GREEN_("%s") "| " _YELLOW_("%s"), + PrintAndLogEx(INFO, "%3d | " _YELLOW_("%s") _MAGENTA_("%s") "%02X " _YELLOW_("%s") "| " _YELLOW_("%s"), blockno, keya, acl, @@ -601,7 +265,7 @@ void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose) { } } -static void mf_print_block(uint16_t maxblocks, uint8_t blockno, uint8_t *d, bool verbose) { +static void mf_print_block(uint8_t blockno, uint8_t *d, bool verbose) { uint8_t sectorno = mfSectorNum(blockno); char secstr[6] = " "; @@ -633,7 +297,7 @@ static void mf_print_block(uint16_t maxblocks, uint8_t blockno, uint8_t *d, bool char ascii[24] = {0}; ascii_to_buffer((uint8_t *)ascii, d, MFBLOCK_SIZE, sizeof(ascii) - 1, 1); - if (maxblocks < 18 && blockno >= MIFARE_1K_MAXBLOCK) { + if (blockno >= MIFARE_1K_MAXBLOCK) { PrintAndLogEx(INFO, _BACK_BLUE_("%s| %3d | " _YELLOW_("%s")) _BACK_BLUE_(_MAGENTA_("%s")) @@ -662,7 +326,7 @@ static void mf_print_block(uint16_t maxblocks, uint8_t blockno, uint8_t *d, bool } } else { - if (maxblocks < 18 && blockno >= MIFARE_1K_MAXBLOCK) { + if (blockno >= MIFARE_1K_MAXBLOCK) { // MFC Ev1 signature blocks. PrintAndLogEx(INFO, _BACK_BLUE_("%s| %3d | %s"), secstr, blockno, sprint_hex_ascii(d, MFBLOCK_SIZE)); } else { @@ -676,17 +340,15 @@ static void mf_print_block(uint16_t maxblocks, uint8_t blockno, uint8_t *d, bool } } -void mf_print_blocks(uint16_t n, uint8_t *d, bool verbose) { +static void mf_print_blocks(uint16_t n, uint8_t *d, bool verbose) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "-----+-----+-------------------------------------------------+-----------------"); PrintAndLogEx(INFO, " sec | blk | data | ascii"); PrintAndLogEx(INFO, "-----+-----+-------------------------------------------------+-----------------"); - for (uint16_t i = 0; i < n; i++) { - mf_print_block(n, i, d + (i * MFBLOCK_SIZE), verbose); + mf_print_block(i, d + (i * MFBLOCK_SIZE), verbose); } PrintAndLogEx(INFO, "-----+-----+-------------------------------------------------+-----------------"); - if (verbose) { PrintAndLogEx(HINT, _CYAN_("cyan") " = value block with decoded value"); PrintAndLogEx(HINT, _CYAN_("background blue") " = MFC Ev1 signature blocks"); @@ -700,7 +362,7 @@ void mf_print_blocks(uint16_t n, uint8_t *d, bool verbose) { } // assumes n is in number of blocks 0..255 -int mf_print_keys(uint16_t n, uint8_t *d) { +static int mf_print_keys(uint16_t n, uint8_t *d) { uint8_t sectors = 0; switch (n) { case MIFARE_MINI_MAXBLOCK: @@ -916,25 +578,20 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n char *fptr = NULL; if (keyfn == NULL || keyfn[0] == '\0') { fptr = GenerateFilename("hf-mf-", "-key.bin"); - if (fptr == NULL) { + if (fptr == NULL) return PM3_ESOFT; - } keyfn = fptr ; } + PrintAndLogEx(INFO, "Using... %s", keyfn); + size_t alen = 0, blen = 0; - uint8_t *keyA = NULL, *keyB = NULL; - if (loadFileBinaryKey(keyfn, "", (void **)&keyA, (void **)&keyB, &alen, &blen, true) != PM3_SUCCESS) { + uint8_t *keyA, *keyB; + if (loadFileBinaryKey(keyfn, "", (void **)&keyA, (void **)&keyB, &alen, &blen) != PM3_SUCCESS) { free(fptr); return PM3_ESOFT; } - free(fptr); - - if ((alen < (numSectors * MIFARE_KEY_SIZE)) || (blen < (numSectors * MIFARE_KEY_SIZE))) { - PrintAndLogEx(WARNING, "Key file is too small for selected card type"); - return PM3_ELENGTH; - } PrintAndLogEx(INFO, "Reading sector access bits..."); PrintAndLogEx(INFO, "." NOLF); @@ -943,17 +600,15 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n mf_readblock_t payload; uint8_t current_key; - for (uint8_t sectorNo = 0; sectorNo < numSectors; sectorNo++) { - current_key = MF_KEY_A; - for (uint8_t tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) { PrintAndLogEx(NORMAL, "." NOLF); fflush(stdout); if (kbd_enter_pressed()) { PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); + free(fptr); free(keyA); free(keyB); return PM3_EOPABORTED; @@ -998,9 +653,7 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n PrintAndLogEx(INFO, "Dumping all blocks from card..."); for (uint8_t sectorNo = 0; sectorNo < numSectors; sectorNo++) { - for (uint8_t blockNo = 0; blockNo < mfNumBlocksPerSector(sectorNo); blockNo++) { - bool received = false; current_key = MF_KEY_A; uint8_t data_area = (sectorNo < 32) ? blockNo : blockNo / 5; @@ -1021,7 +674,6 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); - } else { // data block. Check if it can be read with key A or key B if ((rights[sectorNo][data_area] == 0x03) || (rights[sectorNo][data_area] == 0x05)) { @@ -1033,7 +685,6 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); received = WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500); - } else { // key A would work payload.blockno = mfFirstBlockOfSector(sectorNo) + blockNo; @@ -1084,7 +735,7 @@ static int mfc_read_tag(iso14a_card_select_t *card, uint8_t *carddata, uint8_t n } } - + free(fptr); free(keyA); free(keyB); @@ -1128,9 +779,9 @@ static int mf_load_keys(uint8_t **pkeyBlock, uint32_t *pkeycnt, uint8_t *userkey } *pkeyBlock = p; // Copy default keys to list - for (uint32_t i = 0; i < ARRAYLEN(g_mifare_default_keys); i++) { + for (int i = 0; i < ARRAYLEN(g_mifare_default_keys); i++) { num_to_bytes(g_mifare_default_keys[i], MIFARE_KEY_SIZE, (uint8_t *)(*pkeyBlock + (*pkeycnt + i) * MIFARE_KEY_SIZE)); - PrintAndLogEx(DEBUG, _YELLOW_("%2u") " - %s", *pkeycnt + i, sprint_hex(*pkeyBlock + (*pkeycnt + i) * MIFARE_KEY_SIZE, MIFARE_KEY_SIZE)); + PrintAndLogEx(DEBUG, _YELLOW_("%2d") " - %s", *pkeycnt + i, sprint_hex(*pkeyBlock + (*pkeycnt + i) * MIFARE_KEY_SIZE, MIFARE_KEY_SIZE)); } *pkeycnt += ARRAYLEN(g_mifare_default_keys); PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%zu") " hardcoded keys", ARRAYLEN(g_mifare_default_keys)); @@ -1246,15 +897,13 @@ static int CmdHF14AMfDarkside(const char *Cmd) { uint64_t key = 0; uint64_t t1 = msclock(); - int res = mf_dark_side(blockno, key_type, &key); + int ret = mf_dark_side(blockno, key_type, &key); t1 = msclock() - t1; - if (res != PM3_SUCCESS) { - return res; - } + if (ret != PM3_SUCCESS) return ret; - PrintAndLogEx(SUCCESS, "Found valid key [ "_GREEN_("%012" PRIX64) " ]", key); - PrintAndLogEx(SUCCESS, "Time in darkside " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); + PrintAndLogEx(SUCCESS, "found valid key: " _GREEN_("%012" PRIx64), key); + PrintAndLogEx(SUCCESS, "time in darkside " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); return PM3_SUCCESS; } @@ -1484,7 +1133,7 @@ static int CmdHF14AMfRdSc(const char *Cmd) { } int keylen = 0; - uint8_t key[MIFARE_KEY_SIZE] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; CLIGetHexWithReturn(ctx, 4, key, &keylen); int s = arg_get_int_def(ctx, 5, 0); @@ -1516,13 +1165,6 @@ static int CmdHF14AMfRdSc(const char *Cmd) { uint8_t blocks = mfNumBlocksPerSector(sector); uint8_t start = mfFirstBlockOfSector(sector); - // since this was a successful read, add our known key to the output - if (keytype == MF_KEY_A) { - memcpy(data + ((blocks - 1) * MFBLOCK_SIZE), key, MIFARE_KEY_SIZE); - } else { - memcpy(data + ((blocks - 1) * MFBLOCK_SIZE) + 10, key, MIFARE_KEY_SIZE); - } - mf_print_sector_hdr(sector); for (int i = 0; i < blocks; i++) { mf_print_block_one(start + i, data + (i * MFBLOCK_SIZE), verbose); @@ -1566,7 +1208,7 @@ static int FastDumpWithEcFill(uint8_t numsectors) { } if (resp.status != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "fast dump reported back failure w KEY A. Swapping to KEY B"); + PrintAndLogEx(FAILED, "fast dump reported back failure w KEY A, swapping to KEY B"); // ecfill key B payload.keytype = MF_KEY_B; @@ -1824,10 +1466,12 @@ static int CmdHF14AMfRestore(const char *Cmd) { // size_t alen = 0, blen = 0; uint8_t *keyA, *keyB; - if (loadFileBinaryKey(keyfilename, "", (void **)&keyA, (void **)&keyB, &alen, &blen, true) != PM3_SUCCESS) { + if (loadFileBinaryKey(keyfilename, "", (void **)&keyA, (void **)&keyB, &alen, &blen) != PM3_SUCCESS) { return PM3_ESOFT; } + PrintAndLogEx(INFO, "Using key file `" _YELLOW_("%s") "`", keyfilename); + // try reading card uid and create filename if (datafnlen == 0) { char *fptr = GenerateFilename("hf-mf-", "-dump.bin"); @@ -2006,7 +1650,7 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't CLIExecWithReturn(ctx, Cmd, argtable, false); int keylen = 0; - uint8_t key[MIFARE_KEY_SIZE] = {0}; + uint8_t key[6] = {0}; CLIGetHexWithReturn(ctx, 1, key, &keylen); bool m0 = arg_get_lit(ctx, 2); @@ -2025,7 +1669,6 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't } else if (arg_get_lit(ctx, 8)) { keyType = MF_KEY_B; } - uint8_t prev_keytype = keyType; keyType = arg_get_int_def(ctx, 9, keyType); if ((arg_get_lit(ctx, 7) || arg_get_lit(ctx, 8)) && (keyType != prev_keytype)) { @@ -2045,16 +1688,13 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't } else if (arg_get_lit(ctx, 12)) { trgKeyType = MF_KEY_B; } - uint8_t prev_trgkeytype = trgKeyType; trgKeyType = arg_get_int_def(ctx, 13, trgKeyType); - if ((arg_get_lit(ctx, 11) || arg_get_lit(ctx, 12)) && (trgKeyType != prev_trgkeytype)) { CLIParserFree(ctx); PrintAndLogEx(WARNING, "Choose one single target key type"); return PM3_EINVARG; } - bool transferToEml = arg_get_lit(ctx, 14); bool createDumpFile = arg_get_lit(ctx, 15); bool singleSector = trgBlockNo > -1; @@ -2103,16 +1743,16 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't return PM3_EINVARG; } } - if (SectorsCnt == 1) { SectorsCnt = MIFARE_1K_MAXSECTOR; } - if (keylen != MIFARE_KEY_SIZE) { - PrintAndLogEx(WARNING, "Input key must include 6 HEX bytes, got %u", keylen); + if (keylen != 6) { + PrintAndLogEx(WARNING, "Input key must include 12 HEX symbols"); return PM3_EINVARG; } + sector_t *e_sector = NULL; uint8_t keyBlock[(ARRAYLEN(g_mifare_default_keys) + 1) * 6]; uint64_t key64 = 0; @@ -2126,17 +1766,15 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't // check if we can authenticate to sector if (mf_check_keys(blockNo, keyType, true, 1, key, &key64) != PM3_SUCCESS) { if (keyType < 2) { - PrintAndLogEx(WARNING, "Wrong key. Can't authenticate to block %3d key type %c", blockNo, keyType ? 'B' : 'A'); + PrintAndLogEx(WARNING, "Wrong key. Can't authenticate to block:%3d key type:%c", blockNo, keyType ? 'B' : 'A'); } else { - PrintAndLogEx(WARNING, "Wrong key. Can't authenticate to block %3d key type %02x", blockNo, MIFARE_AUTH_KEYA + keyType); + PrintAndLogEx(WARNING, "Wrong key. Can't authenticate to block:%3d key type:%02x", blockNo, MIFARE_AUTH_KEYA + keyType); } return PM3_EOPABORTED; } if (singleSector) { - - uint8_t foundkey[MIFARE_KEY_SIZE] = {0}; - int16_t isOK = mf_nested(blockNo, keyType, key, trgBlockNo, trgKeyType, foundkey, !ignore_static_encrypted); + int16_t isOK = mf_nested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, !ignore_static_encrypted); switch (isOK) { case PM3_ETIMEOUT: PrintAndLogEx(ERR, "command execution time out\n"); @@ -2151,10 +1789,10 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't PrintAndLogEx(FAILED, "No valid key found"); break; case PM3_ESTATIC_NONCE: - PrintAndLogEx(ERR, "Static encrypted nonce detected. Aborted\n"); - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("script run fm11rf08s_recovery.py") "`"); + PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); break; - case PM3_SUCCESS: { + case PM3_SUCCESS: + key64 = bytes_to_num(keyBlock, 6); // transfer key to the emulator if (transferToEml) { @@ -2165,43 +1803,32 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't } else { // 16 block sector sectortrailer = trgBlockNo | 0x0f; } + mf_eml_get_mem(keyBlock, sectortrailer, 1); - uint8_t block[MFBLOCK_SIZE] = {0}; - mf_eml_get_mem(block, sectortrailer, 1); + if (trgKeyType == MF_KEY_A) + num_to_bytes(key64, 6, keyBlock); + else + num_to_bytes(key64, 6, &keyBlock[10]); - if (trgKeyType == MF_KEY_A) { - memcpy(block, foundkey, MIFARE_KEY_SIZE); - } else { - memcpy(block + 10, foundkey, MIFARE_KEY_SIZE); - } - - mf_elm_set_mem(block, sectortrailer, 1); - PrintAndLogEx(SUCCESS, "Key transferred to emulator memory"); + mf_elm_set_mem(keyBlock, sectortrailer, 1); + PrintAndLogEx(SUCCESS, "Key transferred to emulator memory."); } return PM3_SUCCESS; - } - default : { + default : PrintAndLogEx(ERR, "Unknown error\n"); - } } return PM3_SUCCESS; } else { // ------------------------------------ multiple sectors working + uint64_t t1 = msclock(); - uint64_t t2; - - sector_t *e_sector = NULL; - if (initSectorTable(&e_sector, SectorsCnt) != PM3_SUCCESS) { - return PM3_EMALLOC; - } + e_sector = calloc(SectorsCnt, sizeof(sector_t)); + if (e_sector == NULL) return PM3_EMALLOC; // add our known key e_sector[mfSectorNum(blockNo)].foundKey[keyType] = 1; e_sector[mfSectorNum(blockNo)].Key[keyType] = key64; - PrintAndLogEx(SUCCESS, "--- " _CYAN_("Enter dictionary recovery mode") " ---------------"); - PrintAndLogEx(SUCCESS, "Sector count "_YELLOW_("%d"), SectorsCnt); - //test current key and additional standard keys first // add parameter key memcpy(keyBlock + (ARRAYLEN(g_mifare_default_keys) * 6), key, 6); @@ -2210,8 +1837,6 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6)); } - uint64_t t1 = msclock(); - PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt); int res = mf_check_keys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, use_flashmemory, false); if (res == PM3_SUCCESS) { @@ -2219,9 +1844,9 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't goto jumptoend; } - t2 = msclock() - t1; - PrintAndLogEx(SUCCESS, "Time in check keys " _YELLOW_("%.0f") " seconds\n", (float)t2 / 1000.0); - PrintAndLogEx(SUCCESS, "--- " _CYAN_("Enter nested key recovery mode") " ---------------"); + uint64_t t2 = msclock() - t1; + PrintAndLogEx(SUCCESS, "Time to check " _YELLOW_("%zu") " known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys), (float)t2 / 1000.0); + PrintAndLogEx(SUCCESS, "enter nested key recovery"); // nested sectors bool calibrate = !ignore_static_encrypted; @@ -2230,14 +1855,7 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; ++sectorNo) { for (int i = 0; i < MIFARE_SECTOR_RETRY; i++) { - while (kbd_enter_pressed()) { - PrintAndLogEx(WARNING, "\naborted via keyboard!"); - return PM3_EOPABORTED; - } - - if (e_sector[sectorNo].foundKey[trgKeyType]) { - continue; - } + if (e_sector[sectorNo].foundKey[trgKeyType]) continue; int16_t isOK = mf_nested(blockNo, keyType, key, mfFirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate); switch (isOK) { @@ -2255,13 +1873,12 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't calibrate = false; continue; case PM3_ESTATIC_NONCE: - PrintAndLogEx(ERR, "Static encrypted nonce detected. Aborted\n"); - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("script run fm11rf08s_recovery.py") "`"); + PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); break; case PM3_SUCCESS: calibrate = false; e_sector[sectorNo].foundKey[trgKeyType] = 1; - e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, MIFARE_KEY_SIZE); + e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6); mf_check_keys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false, false); continue; @@ -2275,41 +1892,37 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't } t1 = msclock() - t1; - PrintAndLogEx(SUCCESS, "Time in nested " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); + PrintAndLogEx(SUCCESS, "time in nested " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? - PrintAndLogEx(INFO, "Trying to read key B..."); + PrintAndLogEx(INFO, "trying to read key B..."); for (int i = 0; i < SectorsCnt; i++) { // KEY A but not KEY B if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) { uint8_t sectrail = (mfFirstBlockOfSector(i) + mfNumBlocksPerSector(i) - 1); - PrintAndLogEx(SUCCESS, "Reading block " _YELLOW_("%d"), sectrail); + PrintAndLogEx(SUCCESS, "reading block %d", sectrail); mf_readblock_t payload; payload.blockno = sectrail; payload.keytype = MF_KEY_A; - num_to_bytes(e_sector[i].Key[0], MIFARE_KEY_SIZE, payload.key); // KEY A + num_to_bytes(e_sector[i].Key[0], 6, payload.key); // KEY A clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) { - continue; - } + if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue; - if (resp.status != PM3_SUCCESS) { - continue; - } + if (resp.status != PM3_SUCCESS) continue; uint8_t *data = resp.data.asBytes; - key64 = bytes_to_num(data + 10, MIFARE_KEY_SIZE); + key64 = bytes_to_num(data + 10, 6); if (key64) { - PrintAndLogEx(SUCCESS, "data: %s", sprint_hex(data + 10, MIFARE_KEY_SIZE)); + PrintAndLogEx(SUCCESS, "data: %s", sprint_hex(data + 10, 6)); e_sector[i].foundKey[1] = true; e_sector[i].Key[1] = key64; } @@ -2318,6 +1931,10 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't jumptoend: + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); + + //print them printKeyTable(SectorsCnt, e_sector); // transfer them to the emulator @@ -2328,10 +1945,10 @@ jumptoend: mf_eml_get_mem(keyBlock, mfFirstBlockOfSector(i) + mfNumBlocksPerSector(i) - 1, 1); if (e_sector[i].foundKey[0]) - num_to_bytes(e_sector[i].Key[0], MIFARE_KEY_SIZE, keyBlock); + num_to_bytes(e_sector[i].Key[0], 6, keyBlock); if (e_sector[i].foundKey[1]) - num_to_bytes(e_sector[i].Key[1], MIFARE_KEY_SIZE, &keyBlock[10]); + num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]); if (i == SectorsCnt - 1) { // Disable fast mode on last packet @@ -2355,9 +1972,6 @@ jumptoend: } free(e_sector); } - - PrintAndLogEx(INFO, "Done!"); - PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -2492,8 +2106,8 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) { } uint64_t t2 = msclock() - t1; - PrintAndLogEx(SUCCESS, "Time in check keys " _YELLOW_("%.0f") " seconds\n", (float)t2 / 1000.0); - PrintAndLogEx(SUCCESS, "--- " _CYAN_("Enter static nested key recovery") " --------------"); + PrintAndLogEx(SUCCESS, "Time to check "_YELLOW_("%zu") " known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys), (float)t2 / 1000.0); + PrintAndLogEx(SUCCESS, "enter static nested key recovery"); // nested sectors for (trgKeyType = MF_KEY_A; trgKeyType <= MF_KEY_B; ++trgKeyType) { @@ -2533,7 +2147,7 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) { // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? - PrintAndLogEx(INFO, "Trying to read key B..."); + PrintAndLogEx(INFO, "trying to read key B..."); for (int i = 0; i < SectorsCnt; i++) { // KEY A but not KEY B if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) { @@ -2570,6 +2184,9 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) { jumptoend: + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); + //print them printKeyTable(SectorsCnt, e_sector); @@ -2750,15 +2367,9 @@ static int CmdHF14AMfNestedHard(const char *Cmd) { SetSIMDInstr(SIMD_NEON); #endif - if (in) { + if (in) SetSIMDInstr(SIMD_NONE); - } - // santiy checks - if ((g_session.pm3_present == false) && (tests == false)) { - PrintAndLogEx(INFO, "No device connected"); - return PM3_EFAILED; - } bool known_target_key = (trg_keylen); @@ -2814,13 +2425,13 @@ static int CmdHF14AMfNestedHard(const char *Cmd) { } } - PrintAndLogEx(INFO, "Target block no " _YELLOW_("%3d") " target key type: " _YELLOW_("%c") " known target key: " _YELLOW_("%02x%02x%02x%02x%02x%02x%s"), + PrintAndLogEx(INFO, "Target block no " _YELLOW_("%3d") ", target key type: " _YELLOW_("%c") ", known target key: " _YELLOW_("%02x%02x%02x%02x%02x%02x%s"), trg_blockno, (trg_keytype == MF_KEY_B) ? 'B' : 'A', trg_key[0], trg_key[1], trg_key[2], trg_key[3], trg_key[4], trg_key[5], known_target_key ? "" : " (not set)" ); - PrintAndLogEx(INFO, "File action: " _YELLOW_("%s") " Slow: " _YELLOW_("%s") " Tests: " _YELLOW_("%d"), + PrintAndLogEx(INFO, "File action: " _YELLOW_("%s") ", Slow: " _YELLOW_("%s") ", Tests: " _YELLOW_("%d"), nonce_file_write ? "write" : nonce_file_read ? "read" : "none", slow ? "Yes" : "No", tests); @@ -2835,8 +2446,7 @@ static int CmdHF14AMfNestedHard(const char *Cmd) { PrintAndLogEx(WARNING, "Button pressed. Aborted\n"); break; case PM3_ESTATIC_NONCE: - PrintAndLogEx(ERR, "Static encrypted nonce detected. Aborted\n"); - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("script run fm11rf08s_recovery.py") "`"); + PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); break; case PM3_EFAILED: { PrintAndLogEx(FAILED, "\nFailed to recover a key..."); @@ -3034,8 +2644,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // Settings int prng_type = PM3_EUNDEF; int isOK = 0; - - PrintAndLogEx(NORMAL, ""); + // ------------------------------ uint64_t tagT = GetHF14AMfU_Type(); if (tagT != MFU_TT_UL_ERROR) { @@ -3046,11 +2655,10 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // Select card to get UID/UIDLEN/ATQA/SAK information clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) { PrintAndLogEx(DEBUG, "iso14443a card select timeout"); - DropField(); return PM3_ETIMEOUT; } @@ -3066,64 +2674,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { iso14a_card_select_t card; memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - // try to request ATS even if tag claims not to support it. If yes => 4 - if (select_status == 2) { - uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, sizeof(rats)); - if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { - PrintAndLogEx(WARNING, "timeout while waiting for reply"); - return PM3_ETIMEOUT; - } - - memcpy(card.ats, resp.data.asBytes, resp.oldarg[0]); - card.ats_len = resp.oldarg[0]; // note: ats_len includes CRC Bytes - if (card.ats_len > 3) { - select_status = 4; - } - } - - uint8_t ats_hist_pos = 0; - if ((card.ats_len > 3) && (card.ats[0] > 1)) { - ats_hist_pos = 2; - ats_hist_pos += (card.ats[1] & 0x10) == 0x10; - ats_hist_pos += (card.ats[1] & 0x20) == 0x20; - ats_hist_pos += (card.ats[1] & 0x40) == 0x40; - } - - version_hw_t version_hw = {0}; - // if 4b UID or NXP, try to get version - int res = hf14a_getversion_data(&card, select_status, &version_hw); - DropField(); - - bool version_hw_available = (res == PM3_SUCCESS); - - int nxptype = detect_nxp_card(card.sak - , ((card.atqa[1] << 8) + card.atqa[0]) - , select_status - , card.ats_len - ats_hist_pos - , card.ats + ats_hist_pos - , version_hw_available - , &version_hw - ); - - if ((nxptype & MTDESFIRE) == MTDESFIRE) { - PrintAndLogEx(WARNING, "MIFARE DESFire card detected. Quitting..."); - return PM3_ESOFT; - } - - bool isMifareMini = ((nxptype & MTMINI) == MTMINI); - bool isMifarePlus = ((nxptype & MTPLUS) == MTPLUS); - - if (isMifarePlus) { - PrintAndLogEx(INFO, "MIFARE Plus card detected. Using limited set of attacks"); - } - - if (isMifareMini && sector_cnt != MIFARE_MINI_MAXSECTOR) { - PrintAndLogEx(WARNING, "MIFARE Mini S20 card detected. Changing sector count to %u", MIFARE_MINI_MAXSECTOR); - sector_cnt = MIFARE_MINI_MAXSECTOR; - } - bool known_key = (in_keys_len > 5); uint8_t key[MIFARE_KEY_SIZE] = {0}; if (known_key) { @@ -3163,19 +2713,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { block_cnt += 8; } - // check if we can authenticate to sector - uint8_t loopupblk = mfFirstBlockOfSector(sectorno); - if (mf_check_keys(loopupblk, keytype, true, (in_keys_len / MIFARE_KEY_SIZE), in_keys, &key64) != PM3_SUCCESS) { - if (keytype < 2) { - PrintAndLogEx(WARNING, "Known key failed. Can't authenticate to block %3d key type %c", loopupblk, keytype ? 'B' : 'A'); - } else { - PrintAndLogEx(WARNING, "Known key failed. Can't authenticate to block %3d key type %02x", loopupblk, MIFARE_AUTH_KEYA + keytype); - } - known_key = false; - } else { - num_to_bytes(key64, MIFARE_KEY_SIZE, key); - } - // create/initialize key storage structure sector_t *e_sector = NULL; size_t e_sector_cnt = (sector_cnt > sectorno) ? sector_cnt : sectorno + 1; @@ -3209,9 +2746,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // card prng type (weak=1 / hard=0 / select/card comm error = negative value) if (has_staticnonce == NONCE_NORMAL) { - prng_type = detect_classic_prng(); - if (prng_type < 0) { PrintAndLogEx(FAILED, "\nNo tag detected or other tag communication error (%i)", prng_type); free(e_sector); @@ -3219,50 +2754,47 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { return PM3_ESOFT; } - if (known_key) { - has_staticnonce = detect_classic_static_encrypted_nonce(loopupblk, keytype, key); - } else { - has_staticnonce = detect_classic_static_encrypted_nonce(0, MF_KEY_A, g_mifare_default_key); - } + // + has_staticnonce = detect_classic_static_encrypted_nonce(0, MF_KEY_A, g_mifare_default_key); } // print parameters if (verbose) { - PrintAndLogEx(INFO, "---- " _CYAN_("Command settings") " ------------------------------------------"); - PrintAndLogEx(INFO, "Card sectors... " _YELLOW_("%d"), sector_cnt); - PrintAndLogEx(INFO, "Key supplied... " _YELLOW_("%s"), known_key ? "yes" : "no"); - PrintAndLogEx(INFO, "Known sector... " _YELLOW_("%d"), sectorno); - PrintAndLogEx(INFO, "Key type....... " _YELLOW_("%c"), (keytype == MF_KEY_B) ? 'B' : 'A'); - PrintAndLogEx(INFO, "Known key...... " _YELLOW_("%s"), sprint_hex_inrow(key, sizeof(key))); + PrintAndLogEx(INFO, "======================= " _YELLOW_("SETTINGS") " ======================="); + PrintAndLogEx(INFO, " card sectors .. " _YELLOW_("%d"), sector_cnt); + PrintAndLogEx(INFO, " key supplied .. " _YELLOW_("%s"), known_key ? "True" : "False"); + PrintAndLogEx(INFO, " known sector .. " _YELLOW_("%d"), sectorno); + PrintAndLogEx(INFO, " keytype ....... " _YELLOW_("%c"), (keytype == MF_KEY_B) ? 'B' : 'A'); + PrintAndLogEx(INFO, " known key ..... " _YELLOW_("%s"), sprint_hex_inrow(key, sizeof(key))); switch (has_staticnonce) { case NONCE_STATIC: { - PrintAndLogEx(INFO, "Card PRNG ..... " _YELLOW_("STATIC")); + PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("STATIC")); break; } case NONCE_STATIC_ENC: { - PrintAndLogEx(INFO, "Card PRNG ..... " _RED_("STATIC ENCRYPTED")); + PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("STATIC ENCRYPTED")); break; } case NONCE_NORMAL: { - PrintAndLogEx(INFO, "Card PRNG ..... %s", (prng_type) ? "weak" : "hard"); + PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s"), prng_type ? "WEAK" : "HARD"); break; } default: { - PrintAndLogEx(INFO, "Card PRNG ..... " _YELLOW_("Could not determine PRNG") " ( " _RED_("read failed") " ) %i", has_staticnonce); + PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("Could not determine PRNG,") " " _RED_("read failed.")); break; } } - PrintAndLogEx(INFO, "Dictionary .... " _YELLOW_("%s"), strlen(filename) ? filename : "n/a"); - PrintAndLogEx(INFO, "Legacy mode ... %s", (legacy_mfchk) ? _YELLOW_("yes") : "no"); + PrintAndLogEx(INFO, " dictionary .... " _YELLOW_("%s"), strlen(filename) ? filename : "NONE"); + PrintAndLogEx(INFO, " legacy mode ... " _YELLOW_("%s"), legacy_mfchk ? "True" : "False"); - PrintAndLogEx(INFO, "----------------------------------------------------------------"); + PrintAndLogEx(INFO, "========================================================================"); } // check the user supplied key if (known_key == false) { - PrintAndLogEx(WARNING, "No known key was supplied, key recovery might fail"); + PrintAndLogEx(WARNING, "no known key was supplied, key recovery might fail"); } // Start the timer @@ -3273,18 +2805,17 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { if (use_flashmemory) { fnlen = 0; } - int ret = mf_load_keys(&keyBlock, &key_cnt, in_keys, in_keys_len, filename, fnlen, true); if (ret != PM3_SUCCESS) { free(e_sector); return ret; } - res = PM3_SUCCESS; + int32_t res = PM3_SUCCESS; // Use the dictionary to find sector keys on the card if (verbose) { - PrintAndLogEx(INFO, "--- " _CYAN_("Enter dictionary recovery mode") " -----------------------------"); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START DICTIONARY ATTACK") " ======================="); } if (legacy_mfchk) { @@ -3357,7 +2888,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { uint8_t num_found_keys = 0; for (int i = 0; i < sector_cnt; i++) { for (int j = MF_KEY_A; j <= MF_KEY_B; j++) { - if (e_sector[i].foundKey[j] != 1) { continue; } @@ -3373,13 +2903,13 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { known_key = true; sectorno = i; keytype = j; - PrintAndLogEx(SUCCESS, "Target sector " _GREEN_("%3u") " key type " _GREEN_("%c") " -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)", + PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ] (used for nested / hardnested attack)", i, (j == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(tmp_key, sizeof(tmp_key)) ); } else { - PrintAndLogEx(SUCCESS, "Target sector " _GREEN_("%3u") " key type " _GREEN_("%c") " -- found valid key [ " _GREEN_("%s") " ]", + PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]", i, (j == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(tmp_key, sizeof(tmp_key)) @@ -3398,7 +2928,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // Check if the darkside attack can be used if (prng_type && has_staticnonce != NONCE_STATIC) { if (verbose) { - PrintAndLogEx(INFO, "--- " _CYAN_("Enter darkside key recovery mode") " ---------------------------------"); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " ======================="); } PrintAndLogEx(NORMAL, ""); @@ -3409,13 +2939,13 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { goto noValidKeyFound; } - PrintAndLogEx(SUCCESS, "Found valid key [ " _GREEN_("%012" PRIX64) " ]\n", key64); + PrintAndLogEx(SUCCESS, "Found valid key [ " _GREEN_("%012" PRIx64) " ]\n", key64); // Store the keys num_to_bytes(key64, MIFARE_KEY_SIZE, key); e_sector[sectorno].Key[keytype] = key64; e_sector[sectorno].foundKey[keytype] = 'S'; - PrintAndLogEx(SUCCESS, "Target sector " _GREEN_("%3u") " key type "_GREEN_("%c") " -- found valid key [ " _GREEN_("%012" PRIX64) " ] (used for nested / hardnested attack)", + PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%012" PRIx64) " ] (used for nested / hardnested attack)", sectorno, (keytype == MF_KEY_B) ? 'B' : 'A', key64 @@ -3429,8 +2959,7 @@ noValidKeyFound: } if (has_staticnonce == NONCE_STATIC_ENC) { - PrintAndLogEx(ERR, "Static encrypted nonce detected. Aborted\n"); - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("script run fm11rf08s_recovery.py") "`"); + PrintAndLogEx(HINT, "Hint: Static encrypted nonce detected, run `" _YELLOW_("script run fm11rf08s_recovery.py") "`"); } DropField(); @@ -3454,9 +2983,8 @@ noValidKeyFound: // If the key is already known, just skip it if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) { - if (has_staticnonce == NONCE_STATIC) { + if (has_staticnonce == NONCE_STATIC) goto tryStaticnested; - } // Try the found keys are reused if (bytes_to_num(tmp_key, MIFARE_KEY_SIZE) != 0) { @@ -3465,15 +2993,14 @@ noValidKeyFound: for (int i = 0; i < sector_cnt; i++) { for (int j = MF_KEY_A; j <= MF_KEY_B; j++) { // Check if the sector key is already broken - if (e_sector[i].foundKey[j]) { + if (e_sector[i].foundKey[j]) continue; - } // Check if the key works if (mf_check_keys(mfFirstBlockOfSector(i), j, true, 1, tmp_key, &key64) == PM3_SUCCESS) { e_sector[i].Key[j] = bytes_to_num(tmp_key, MIFARE_KEY_SIZE); e_sector[i].foundKey[j] = 'R'; - PrintAndLogEx(SUCCESS, "Target sector " _GREEN_("%3u") " key type " _GREEN_("%c") " -- found valid key [ " _GREEN_("%s") " ]", + PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]", i, (j == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(tmp_key, sizeof(tmp_key)) @@ -3488,7 +3015,7 @@ noValidKeyFound: if (current_key_type_i == MF_KEY_B) { if (e_sector[current_sector_i].foundKey[0] && !e_sector[current_sector_i].foundKey[1]) { if (verbose) { - PrintAndLogEx(INFO, "--- " _CYAN_("Enter read B key recovery mode") " -----------------------"); + PrintAndLogEx(INFO, "======================= " _YELLOW_("START READ B KEY ATTACK") " ======================="); PrintAndLogEx(INFO, "reading B key of sector %3d with key type %c", current_sector_i, (current_key_type_i == MF_KEY_B) ? 'B' : 'A'); @@ -3504,29 +3031,24 @@ noValidKeyFound: clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); - if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) { - goto skipReadBKey; - } + if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) goto skipReadBKey; - if (resp.status != PM3_SUCCESS) { - goto skipReadBKey; - } + if (resp.status != PM3_SUCCESS) goto skipReadBKey; uint8_t *data = resp.data.asBytes; key64 = bytes_to_num(data + 10, MIFARE_KEY_SIZE); - if (key64) { e_sector[current_sector_i].foundKey[current_key_type_i] = 'A'; e_sector[current_sector_i].Key[current_key_type_i] = key64; num_to_bytes(key64, MIFARE_KEY_SIZE, tmp_key); - PrintAndLogEx(SUCCESS, "Target sector " _GREEN_("%3u") " key type " _GREEN_("%c") " -- found valid key [ " _GREEN_("%s") " ]", + PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]", current_sector_i, (current_key_type_i == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(tmp_key, sizeof(tmp_key)) ); } else { if (verbose) { - PrintAndLogEx(WARNING, "Unknown B key: sector %3d key type %c", + PrintAndLogEx(WARNING, "unknown B key: sector: %3d key type: %c", current_sector_i, (current_key_type_i == MF_KEY_B) ? 'B' : 'A' ); @@ -3542,17 +3064,14 @@ noValidKeyFound: skipReadBKey: if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) { - if (has_staticnonce == NONCE_STATIC) { + if (has_staticnonce == NONCE_STATIC) goto tryStaticnested; - } if (prng_type && (nested_failed == false)) { uint8_t retries = 0; - - PrintAndLogEx(NORMAL, ""); if (verbose) { - PrintAndLogEx(INFO, "--- " _CYAN_("Enter nested key recovery mode") " -----------------------------"); - PrintAndLogEx(INFO, "Sector " _YELLOW_("%3d") " key type " _YELLOW_("%c"), + PrintAndLogEx(INFO, "======================= " _YELLOW_("START NESTED ATTACK") " ======================="); + PrintAndLogEx(INFO, "sector no %3d, target key type %c", current_sector_i, (current_key_type_i == MF_KEY_B) ? 'B' : 'A'); } @@ -3592,12 +3111,13 @@ tryNested: break; } case PM3_ESTATIC_NONCE: { - PrintAndLogEx(ERR, "Static encrypted nonce detected. Aborted\n"); - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("script run fm11rf08s_recovery.py") "`"); + PrintAndLogEx(ERR, "Error: Static encrypted nonce detected. Aborted\n"); e_sector[current_sector_i].Key[current_key_type_i] = 0xffffffffffff; e_sector[current_sector_i].foundKey[current_key_type_i] = false; // Show the results to the user + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); printKeyTable(sector_cnt, e_sector); PrintAndLogEx(NORMAL, ""); free(e_sector); @@ -3611,7 +3131,7 @@ tryNested: break; } default: { - PrintAndLogEx(ERR, "Unknown error\n"); + PrintAndLogEx(ERR, "unknown Error.\n"); free(e_sector); free(fptr); return isOK; @@ -3620,22 +3140,9 @@ tryNested: } else { tryHardnested: // If the nested attack fails then we try the hardnested attack - - // skip this - if (isMifarePlus) { - - // Show the results to the user - printKeyTable(sector_cnt, e_sector); - PrintAndLogEx(NORMAL, ""); - free(e_sector); - free(fptr); - return PM3_ESOFT; - } - - PrintAndLogEx(NORMAL, ""); if (verbose) { - PrintAndLogEx(INFO, "--- " _CYAN_("Enter hardnested key recovery mode") " -------------------------"); - PrintAndLogEx(INFO, "Sector " _YELLOW_("%3d") " key type " _YELLOW_("%c") ", slow " _YELLOW_("%s"), + PrintAndLogEx(INFO, "======================= " _YELLOW_("START HARDNESTED ATTACK") " ======================="); + PrintAndLogEx(INFO, "sector no %3d, target key type %c, Slow %s", current_sector_i, (current_key_type_i == MF_KEY_B) ? 'B' : 'A', slow ? "Yes" : "No"); @@ -3661,6 +3168,8 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack e_sector[current_sector_i].foundKey[current_key_type_i] = false; // Show the results to the user + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); printKeyTable(sector_cnt, e_sector); PrintAndLogEx(NORMAL, ""); break; @@ -3686,10 +3195,9 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack if (has_staticnonce == NONCE_STATIC) { tryStaticnested: - PrintAndLogEx(NORMAL, ""); if (verbose) { - PrintAndLogEx(INFO, "--- " _CYAN_("Enter static nested key recovery mode") " -----------------------"); - PrintAndLogEx(INFO, "Sector " _YELLOW_("%3d") ", key type " _YELLOW_("%c"), + PrintAndLogEx(INFO, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " ======================="); + PrintAndLogEx(INFO, "sector no %3d, target key type %c", current_sector_i, (current_key_type_i == MF_KEY_B) ? 'B' : 'A'); } @@ -3722,7 +3230,7 @@ tryStaticnested: // Check if the key was found if (e_sector[current_sector_i].foundKey[current_key_type_i]) { - PrintAndLogEx(SUCCESS, "Target sector " _GREEN_("%3u") " key type " _GREEN_("%c") " -- found valid key [ " _GREEN_("%s") " ]", + PrintAndLogEx(SUCCESS, "target sector %3u key type %c -- found valid key [ " _GREEN_("%s") " ]", current_sector_i, (current_key_type_i == MF_KEY_B) ? 'B' : 'A', sprint_hex_inrow(tmp_key, sizeof(tmp_key)) @@ -3736,6 +3244,9 @@ tryStaticnested: all_found: // Show the results to the user + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); + printKeyTable(sector_cnt, e_sector); if (no_save == false) { @@ -3751,26 +3262,21 @@ all_found: clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_EML_MEMCLR, NULL, 0); - PrintAndLogEx(INFO, "Transferring keys to simulator memory " NOLF); + PrintAndLogEx(INFO, "transferring keys to simulator memory " NOLF); bool transfer_status = true; for (current_sector_i = 0; current_sector_i < sector_cnt; current_sector_i++) { - mf_eml_get_mem(block, current_sector_i, 1); - - if (e_sector[current_sector_i].foundKey[0]) { + if (e_sector[current_sector_i].foundKey[0]) num_to_bytes(e_sector[current_sector_i].Key[0], MIFARE_KEY_SIZE, block); - } - - if (e_sector[current_sector_i].foundKey[1]) { + if (e_sector[current_sector_i].foundKey[1]) num_to_bytes(e_sector[current_sector_i].Key[1], MIFARE_KEY_SIZE, block + 10); - } transfer_status |= mf_elm_set_mem(block, mfFirstBlockOfSector(current_sector_i) + mfNumBlocksPerSector(current_sector_i) - 1, 1); } PrintAndLogEx(NORMAL, "( %s )", (transfer_status) ? _GREEN_("ok") : _RED_("fail")); - PrintAndLogEx(INFO, "Dumping card content to emulator memory (Cmd Error: 04 can occur)"); + PrintAndLogEx(INFO, "dumping card content to emulator memory (Cmd Error: 04 can occur)"); // use ecfill trick FastDumpWithEcFill(sector_cnt); @@ -3806,7 +3312,6 @@ all_found: } else { snprintf(suffix, sizeof(suffix), "-dump"); } - fptr = GenerateFilename("hf-mf-", suffix); if (fptr == NULL) { free(dump); @@ -3824,7 +3329,7 @@ all_found: out: // Generate and show statistics t1 = msclock() - t1; - PrintAndLogEx(INFO, "Autopwn execution time: " _YELLOW_("%.0f") " seconds", (float)t1 / 1000.0); + PrintAndLogEx(INFO, "autopwn execution time: " _YELLOW_("%.0f") " seconds", (float)t1 / 1000.0); DropField(); free(e_sector); @@ -3935,7 +3440,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { return PM3_EMALLOC; } - uint32_t chunksize = (keycnt > (PM3_CMD_DATA_SIZE / MIFARE_KEY_SIZE)) ? (PM3_CMD_DATA_SIZE / MIFARE_KEY_SIZE) : keycnt; + uint32_t chunksize = keycnt > (PM3_CMD_DATA_SIZE / MIFARE_KEY_SIZE) ? (PM3_CMD_DATA_SIZE / MIFARE_KEY_SIZE) : keycnt; bool firstChunk = true, lastChunk = false; int i = 0; @@ -3954,26 +3459,30 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { // strategies. 1= deep first on sector 0 AB, 2= width first on all sectors for (uint8_t strategy = 1; strategy < 3; strategy++) { - PrintAndLogEx(INFO, "Running strategy " _YELLOW_("%u"), strategy); + PrintAndLogEx(INFO, "Running strategy %u", strategy); // main keychunk loop for (i = 0; i < keycnt; i += chunksize) { if (kbd_enter_pressed()) { - clearCommandBuffer(); - SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0); // field is still ON if not on last chunk PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(WARNING, "\naborted via keyboard!"); + PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); + // field is still ON if not on last chunk + clearCommandBuffer(); + SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0); + // TODO: we're missing these cleanups on arm side, not sure if it's important... + // set_tracing(false); + // BigBuf_free(); + // BigBuf_Clear_ext(false); goto out; } - + PrintAndLogEx(INPLACE, "Testing %5i/%5i %02.1f%%", i, keycnt, (float)i * 100 / keycnt); uint32_t size = ((keycnt - i) > chunksize) ? chunksize : keycnt - i; // last chunk? - if (size == keycnt - i) { + if (size == keycnt - i) lastChunk = true; - } + int res = mf_check_keys_fast_ex(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * MIFARE_KEY_SIZE), e_sector, false, false, true, singleSectorParams); if (firstChunk) firstChunk = false; @@ -3983,19 +3492,12 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { PrintAndLogEx(NORMAL, ""); goto out; } - PrintAndLogEx(INPLACE, "Testing %5i/%5i ( " _YELLOW_("%02.1f %%") " )", i, keycnt, (float)i * 100 / keycnt); } // end chunks of keys - - PrintAndLogEx(INPLACE, "Testing %5i/%5i ( " _YELLOW_("100 %%") " ) ", keycnt, keycnt); + PrintAndLogEx(INPLACE, "Testing %5i/%5i 100.00%%", keycnt, keycnt); PrintAndLogEx(NORMAL, ""); - - // reset chunks when swapping strategies firstChunk = true; lastChunk = false; - - if (blockn != -1) { - break; - } + if (blockn != -1) break; } // end strategy } out: @@ -4021,6 +3523,9 @@ out: PrintAndLogEx(WARNING, "No keys found"); } else { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); + printKeyTable(sectorsCnt, e_sector); if (use_flashmemory && found_keys == (sectorsCnt << 1)) { @@ -4239,6 +3744,9 @@ out: PrintAndLogEx(WARNING, "No keys found"); } else { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); + printKeyTable(sectorsCnt, e_sector); if (transferToEml) { @@ -4403,9 +3911,9 @@ static int CmdHF14AMfChk(const char *Cmd) { uint8_t *keyBlock = NULL; uint32_t keycnt = 0; - int res = mf_load_keys(&keyBlock, &keycnt, key, keylen, filename, fnlen, load_default); - if (res != PM3_SUCCESS) { - return res; + int ret = mf_load_keys(&keyBlock, &keycnt, key, keylen, filename, fnlen, load_default); + if (ret != PM3_SUCCESS) { + return ret; } uint64_t key64 = 0; @@ -4454,8 +3962,7 @@ static int CmdHF14AMfChk(const char *Cmd) { uint32_t size = keycnt - c > max_keys ? max_keys : keycnt - c; - res = mf_check_keys(b, trgKeyType, clearLog, size, &keyBlock[MIFARE_KEY_SIZE * c], &key64); - if (res == PM3_SUCCESS) { + if (mf_check_keys(b, trgKeyType, clearLog, size, &keyBlock[MIFARE_KEY_SIZE * c], &key64) == PM3_SUCCESS) { e_sector[i].Key[trgKeyType] = key64; e_sector[i].foundKey[trgKeyType] = true; clearLog = false; @@ -4463,21 +3970,18 @@ static int CmdHF14AMfChk(const char *Cmd) { } clearLog = false; } - - if (singleSector) { + if (singleSector) break; - } b < 127 ? (b += 4) : (b += 16); } } - t1 = msclock() - t1; - PrintAndLogEx(INFO, "\nTime in checkkeys " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); + PrintAndLogEx(INFO, "\ntime in checkkeys " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? if (keyType != MF_KEY_B) { - PrintAndLogEx(INFO, "Testing to read key B..."); + PrintAndLogEx(INFO, "testing to read key B..."); // loop sectors but block is used as to keep track of from which blocks to test int b = blockNo; @@ -4501,13 +4005,9 @@ static int CmdHF14AMfChk(const char *Cmd) { SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) { - continue; - } + if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue; - if (resp.status != PM3_SUCCESS) { - continue; - } + if (resp.status != PM3_SUCCESS) continue; uint8_t *data = resp.data.asBytes; key64 = bytes_to_num(data + 10, MIFARE_KEY_SIZE); @@ -4524,6 +4024,9 @@ static int CmdHF14AMfChk(const char *Cmd) { } out: + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, _GREEN_("found keys:")); + //print keys // if (singleSector) // printKeyTableEx(1, e_sector, mfSectorNum(blockNo)); @@ -4534,18 +4037,15 @@ out: // fast push mode g_conn.block_after_ACK = true; uint8_t block[MFBLOCK_SIZE] = {0x00}; - for (int i = 0; i < sectors_cnt; ++i) { uint8_t blockno = mfFirstBlockOfSector(i) + mfNumBlocksPerSector(i) - 1; mf_eml_get_mem(block, blockno, 1); - if (e_sector[i].foundKey[0]) { + if (e_sector[i].foundKey[0]) num_to_bytes(e_sector[i].Key[0], MIFARE_KEY_SIZE, block); - } - if (e_sector[i].foundKey[1]) { + if (e_sector[i].foundKey[1]) num_to_bytes(e_sector[i].Key[1], MIFARE_KEY_SIZE, block + 10); - } if (i == sectors_cnt - 1) { // Disable fast mode on last packet @@ -4570,7 +4070,7 @@ out: // Disable fast mode and send a dummy command to make it effective g_conn.block_after_ACK = false; SendCommandNG(CMD_PING, NULL, 0); - if (WaitForResponseTimeout(CMD_PING, NULL, 1000) == false) { + if (!WaitForResponseTimeout(CMD_PING, NULL, 1000)) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } @@ -4651,7 +4151,7 @@ static int CmdHF14AMfSim(const char *Cmd) { "hf mf sim --1k -u 11223344556677 --> MIFARE Classic 1k with 7b UID\n" "hf mf sim --1k -u 11223344 -i -x --> Perform reader attack in interactive mode\n" "hf mf sim --2k --> MIFARE 2k\n" - "hf mf sim --4k --> MIFARE 4k\n" + "hf mf sim --4k --> MIFARE 4k" "hf mf sim --1k -x -e --> Keep simulation running and populate with found reader keys\n" ); @@ -4671,7 +4171,6 @@ static int CmdHF14AMfSim(const char *Cmd) { arg_lit0("e", "emukeys", "Fill simulator keys from found keys. Requires -x or -y. Implies -i. Simulation will restart automatically."), // If access bits show that key B is Readable, any subsequent memory access should be refused. arg_lit0(NULL, "allowkeyb", "Allow key B even if readable"), - arg_lit0(NULL, "allowover", "Allow auth attempts out of range for selected MIFARE Classic type"), arg_lit0("v", "verbose", "Verbose output"), arg_lit0(NULL, "cve", "Trigger CVE 2021_0430"), arg_param_end @@ -4726,13 +4225,9 @@ static int CmdHF14AMfSim(const char *Cmd) { flags |= FLAG_MF_USE_READ_KEYB; } - if (arg_get_lit(ctx, 14)) { - flags |= FLAG_MF_ALLOW_OOB_AUTH; - } + bool verbose = arg_get_lit(ctx, 14); - bool verbose = arg_get_lit(ctx, 15); - - if (arg_get_lit(ctx, 16)) { + if (arg_get_lit(ctx, 15)) { flags |= FLAG_CVE21_0430; } CLIParserFree(ctx); @@ -4912,7 +4407,7 @@ static int CmdHF14AMfKeyBrute(const char *Cmd) { uint64_t t1 = msclock(); if (mfKeyBrute(blockNo, keytype, key, &foundkey)) - PrintAndLogEx(SUCCESS, "Found valid key [ %012" PRIX64 " ]\n", foundkey); + PrintAndLogEx(SUCCESS, "found valid key: %012" PRIx64 " \n", foundkey); else PrintAndLogEx(FAILED, "key not found"); @@ -5306,7 +4801,7 @@ int CmdHF14AMfELoad(const char *Cmd) { // update expected blocks to match converted data. block_cnt = bytes_read / MFU_BLOCK_SIZE; - PrintAndLogEx(INFO, "MIFARE Ultralight override, will use " _YELLOW_("%d") " blocks ( " _YELLOW_("%u") " bytes )", block_cnt, block_cnt * block_width); + PrintAndLogEx(INFO, "MIFARE Ultralight override, will use %d blocks ( %u bytes )", block_cnt, block_cnt * block_width); } PrintAndLogEx(INFO, "Uploading to emulator memory"); @@ -5501,7 +4996,7 @@ static int CmdHF14AMfEView(const char *Cmd) { } PrintAndLogEx(INFO, "downloading emulator memory"); - if (GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false) == false) { + if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "Fail, transfer from device time-out"); free(dump); return PM3_ETIMEOUT; @@ -5691,7 +5186,7 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) { memcpy(uid, data, sizeof(uid)); // download keys from EMUL - for (uint8_t i = 0; i < sectors_cnt; i++) { + for (int i = 0; i < sectors_cnt; i++) { if (mf_eml_get_mem(data, mfFirstBlockOfSector(i) + mfNumBlocksPerSector(i) - 1, 1) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "error get block %d", mfFirstBlockOfSector(i) + mfNumBlocksPerSector(i) - 1); @@ -6603,9 +6098,8 @@ static int CmdHf14AMfNack(const char *Cmd) { bool verbose = arg_get_lit(ctx, 1); CLIParserFree(ctx); - if (verbose) { + if (verbose) PrintAndLogEx(INFO, "Started testing card for NACK bug. Press Enter to abort"); - } detect_classic_nackbug(verbose); return PM3_SUCCESS; @@ -6682,9 +6176,7 @@ static int CmdHF14AMfice(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, NULL, 0); - if (WaitForResponseTimeout(CMD_ACK, &resp, 3000) == false) { - goto out; - } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) goto out; if (resp.oldarg[0]) goto out; uint32_t items = resp.oldarg[2]; @@ -7315,10 +6807,12 @@ int CmdHFMFNDEFFormat(const char *Cmd) { // size_t alen = 0, blen = 0; uint8_t *tmpA, *tmpB; - if (loadFileBinaryKey(keyFilename, "", (void **)&tmpA, (void **)&tmpB, &alen, &blen, true) != PM3_SUCCESS) { + if (loadFileBinaryKey(keyFilename, "", (void **)&tmpA, (void **)&tmpB, &alen, &blen) != PM3_SUCCESS) { goto skipfile; } + PrintAndLogEx(INFO, "Using `" _YELLOW_("%s") "`", keyFilename); + for (int i = 0; i < numSectors; i++) { memcpy(keyA[i], tmpA + (i * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); memcpy(keyB[i], tmpB + (i * MIFARE_KEY_SIZE), MIFARE_KEY_SIZE); @@ -9753,9 +9247,7 @@ static int CmdHF14AMfValue(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - int keylen = 0; - uint8_t key[6] = {0}; - CLIGetHexWithReturn(ctx, 1, key, &keylen); + uint8_t blockno = (uint8_t)arg_get_int_def(ctx, 13, 1); uint8_t keytype = MF_KEY_A; if (arg_get_lit(ctx, 2) && arg_get_lit(ctx, 3)) { @@ -9766,6 +9258,22 @@ static int CmdHF14AMfValue(const char *Cmd) { keytype = MF_KEY_B; } + uint8_t transferkeytype = MF_KEY_A; + if (arg_get_lit(ctx, 9) && arg_get_lit(ctx, 10)) { + CLIParserFree(ctx); + PrintAndLogEx(WARNING, "Choose one single transfer key type"); + return PM3_EINVARG; + } else if (arg_get_lit(ctx, 10)) { + transferkeytype = MF_KEY_B; + } + + int keylen = 0; + uint8_t key[6] = {0}; + CLIGetHexWithReturn(ctx, 1, key, &keylen); + + int transferkeylen = 0; + uint8_t transferkey[6] = {0}; + CLIGetHexWithReturn(ctx, 8, transferkey, &transferkeylen); /* Value /Value Value BLK /BLK BLK /BLK @@ -9780,29 +9288,11 @@ static int CmdHF14AMfValue(const char *Cmd) { int64_t decval = (int64_t)arg_get_u64_def(ctx, 5, -1); // Dec by -1 is invalid, so not set. int64_t setval = (int64_t)arg_get_u64_def(ctx, 6, 0x7FFFFFFFFFFFFFFF); // out of bounds (for int32) so not set int64_t trnval = (int64_t)arg_get_u64_def(ctx, 7, -1); // block to transfer to - - int transferkeylen = 0; - uint8_t transferkey[6] = {0}; - CLIGetHexWithReturn(ctx, 8, transferkey, &transferkeylen); - - uint8_t transferkeytype = MF_KEY_A; - if (arg_get_lit(ctx, 9) && arg_get_lit(ctx, 10)) { - CLIParserFree(ctx); - PrintAndLogEx(WARNING, "Choose one single transfer key type"); - return PM3_EINVARG; - } else if (arg_get_lit(ctx, 10)) { - transferkeytype = MF_KEY_B; - } - bool getval = arg_get_lit(ctx, 11); bool resval = arg_get_lit(ctx, 12); - - uint8_t blockno = (uint8_t)arg_get_int_def(ctx, 13, 1); - int dlen = 0; uint8_t data[16] = {0}; CLIGetHexWithReturn(ctx, 14, data, &dlen); - CLIParserFree(ctx); // sanity checks @@ -10186,16 +9676,15 @@ static int CmdHF14AMfInfo(const char *Cmd) { } if (keylen != 0 && keylen != MIFARE_KEY_SIZE) { - PrintAndLogEx(ERR, "Key length must be %u bytes, got %d", MIFARE_KEY_SIZE, keylen); + PrintAndLogEx(ERR, "Key length must be %u bytes", MIFARE_KEY_SIZE); return PM3_EINVARG; } clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { PrintAndLogEx(DEBUG, "iso14443a card select timeout"); - DropField(); return PM3_ETIMEOUT; } @@ -10210,23 +9699,6 @@ static int CmdHF14AMfInfo(const char *Cmd) { */ uint64_t select_status = resp.oldarg[0]; - // try to request ATS even if tag claims not to support it. If yes => 4 - if (select_status == 2) { - uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, sizeof(rats)); - if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { - PrintAndLogEx(WARNING, "timeout while waiting for reply"); - return PM3_ETIMEOUT; - } - - memcpy(card.ats, resp.data.asBytes, resp.oldarg[0]); - card.ats_len = resp.oldarg[0]; // note: ats_len includes CRC Bytes - if (card.ats_len > 3) { - select_status = 4; - } - } - if (select_status == 0) { PrintAndLogEx(DEBUG, "iso14443a card select failed"); return select_status; @@ -10242,74 +9714,17 @@ static int CmdHF14AMfInfo(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("ISO14443-a Information") " -----------------------------"); + PrintAndLogEx(INFO, "--- " _CYAN_("ISO14443-a Information") " ---------------------"); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]); - - uint8_t ats_hist_pos = 0; - if ((card.ats_len > 3) && (card.ats[0] > 1)) { - ats_hist_pos = 2; - ats_hist_pos += (card.ats[1] & 0x10) == 0x10; - ats_hist_pos += (card.ats[1] & 0x20) == 0x20; - ats_hist_pos += (card.ats[1] & 0x40) == 0x40; - } - - version_hw_t version_hw = {0}; - // if 4b UID or NXP, try to get version - int res = hf14a_getversion_data(&card, select_status, &version_hw); - DropField(); - bool version_hw_available = (res == PM3_SUCCESS); - - int card_type = detect_nxp_card(card.sak - , ((card.atqa[1] << 8) + card.atqa[0]) - , select_status - , card.ats_len - ats_hist_pos - , card.ats + ats_hist_pos - , version_hw_available - , &version_hw - ); - - if ((card_type & MTDESFIRE) == MTDESFIRE) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "MIFARE DESFire detected"); - PrintAndLogEx(HINT, "Hint: try `" _YELLOW_("hf mfdes info") "`"); - goto out; - } - - if ((card_type & MTULTRALIGHT) == MTULTRALIGHT) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "MIFARE Ultralight / NTAG detected"); - PrintAndLogEx(HINT, "Hint: try `" _YELLOW_("hf mfu info") "`"); - goto out; - } - - if ((card_type & MTPLUS) == MTPLUS) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "MIFARE Plus detected"); - PrintAndLogEx(HINT, "Hint: try `" _YELLOW_("hf mfp info") "`"); - } - - if ((card_type & MTEMV) == MTEMV) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "EMV detected"); - PrintAndLogEx(HINT, "Hint: try `" _YELLOW_("emv info") "`"); - } - - if ((card_type & MTFUDAN) == MTFUDAN) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "FUDAN FM11RF005 detected"); - PrintAndLogEx(HINT, "Hint: try `" _YELLOW_("hf fudan dump") "`"); - goto out; - } - if (setDeviceDebugLevel(verbose ? MAX(dbg_curr, DBG_INFO) : DBG_NONE, false) != PM3_SUCCESS) { return PM3_EFAILED; } uint8_t signature[32] = {0}; - res = read_mfc_ev1_signature(signature); + int res = read_mfc_ev1_signature(signature); if (res == PM3_SUCCESS) { mfc_ev1_print_signature(card.uid, card.uidlen, signature, sizeof(signature)); } @@ -10341,14 +9756,13 @@ static int CmdHF14AMfInfo(const char *Cmd) { uint8_t blockdata[MFBLOCK_SIZE] = {0}; res = mf_check_keys_fast(sectorsCnt, true, true, 1, keycnt, keyBlock, e_sector, false, verbose); - // Identify Backdoor keyed cards if (res == PM3_SUCCESS || res == PM3_EPARTIAL) { if (e_sector[0].foundKey[MF_KEY_A]) { PrintAndLogEx(SUCCESS, "Sector 0 key A... " _GREEN_("%012" PRIX64), e_sector[0].Key[MF_KEY_A]); num_to_bytes(e_sector[0].Key[MF_KEY_A], MIFARE_KEY_SIZE, fkey); - if (mf_read_block(0, MF_KEY_A, fkey, blockdata) == PM3_SUCCESS) { + if (mf_read_block(0, MF_KEY_A, key, blockdata) == PM3_SUCCESS) { fKeyType = MF_KEY_A; } } @@ -10358,7 +9772,7 @@ static int CmdHF14AMfInfo(const char *Cmd) { if (fKeyType == 0xFF) { num_to_bytes(e_sector[0].Key[MF_KEY_B], MIFARE_KEY_SIZE, fkey); - if (mf_read_block(0, MF_KEY_B, fkey, blockdata) == PM3_SUCCESS) { + if (mf_read_block(0, MF_KEY_B, key, blockdata) == PM3_SUCCESS) { fKeyType = MF_KEY_B; } } @@ -10367,59 +9781,33 @@ static int CmdHF14AMfInfo(const char *Cmd) { if (e_sector[1].foundKey[MF_KEY_A]) { PrintAndLogEx(SUCCESS, "Sector 1 key A... " _GREEN_("%012" PRIX64), e_sector[1].Key[MF_KEY_A]); } - - if (e_sector[1].foundKey[MF_KEY_B]) { - PrintAndLogEx(SUCCESS, "Sector 1 key B... " _GREEN_("%012" PRIX64), e_sector[1].Key[MF_KEY_B]); - } } uint8_t k08s[MIFARE_KEY_SIZE] = {0xA3, 0x96, 0xEF, 0xA4, 0xE2, 0x4F}; uint8_t k08[MIFARE_KEY_SIZE] = {0xA3, 0x16, 0x67, 0xA8, 0xCE, 0xC1}; - uint8_t k32n[MIFARE_KEY_SIZE] = {0x51, 0x8B, 0x33, 0x54, 0xE7, 0x60}; - uint8_t k32n2[MIFARE_KEY_SIZE] = {0x73, 0xB9, 0x83, 0x6C, 0xF1, 0x68}; + uint8_t k32[MIFARE_KEY_SIZE] = {0x51, 0x8B, 0x33, 0x54, 0xE7, 0x60}; if (mf_read_block(0, 4, k08s, blockdata) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08s, sizeof(k08s))); fKeyType = MF_KEY_BD; memcpy(fkey, k08s, sizeof(fkey)); + } else if (mf_read_block(0, 4, k08, blockdata) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k08, sizeof(k08))); fKeyType = MF_KEY_BD; memcpy(fkey, k08, sizeof(fkey)); - } else if (mf_read_block(0, 4, k32n, blockdata) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k32n, sizeof(k32n))); + } else if (mf_read_block(0, 4, k32, blockdata) == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k32, sizeof(k32))); fKeyType = MF_KEY_BD; - memcpy(fkey, k32n, sizeof(fkey)); - } else if (mf_read_block(0, 4, k32n2, blockdata) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Backdoor key..... " _YELLOW_("%s"), sprint_hex_inrow(k32n2, sizeof(k32n2))); - fKeyType = MF_KEY_BD; - memcpy(fkey, k32n2, sizeof(fkey)); + memcpy(fkey, k32, sizeof(fkey)); } - if ((fKeyType == MF_KEY_A) || (fKeyType == MF_KEY_B)) { - // we've a key but not a backdoor key - uint8_t blockdata2[MFBLOCK_SIZE] = {0}; - if (mf_read_block(0, fKeyType + 4, fkey, blockdata2) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Backdoor key..... " _GREEN_("same as key A/B")); - } else if (detect_classic_auth(MF_KEY_BD)) { - PrintAndLogEx(SUCCESS, "Backdoor key..... " _RED_("detected but unknown!")); - PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("hf mf nested --blk 0 -%s -k %s --tblk 0 --tc %i") "`" - , (fKeyType == MF_KEY_A) ? "a" : "b" - , sprint_hex_inrow(fkey, MIFARE_KEY_SIZE) - , fKeyType + 4 - ); - fKeyType = MF_KEY_BD; - } - } - - if (fKeyType != 0xFF) { - PrintAndLogEx(SUCCESS, "Block 0.......... %s | " NOLF, sprint_hex_inrow(blockdata, MFBLOCK_SIZE)); + PrintAndLogEx(SUCCESS, "Block 0.... %s | " NOLF, sprint_hex_inrow(blockdata, MFBLOCK_SIZE)); PrintAndLogEx(NORMAL, "%s", sprint_ascii(blockdata + 8, 8)); } PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Fingerprint")); - bool expect_static_enc_nonce = false; if (fKeyType != 0xFF) { // cards with known backdoor @@ -10428,24 +9816,16 @@ static int CmdHF14AMfInfo(const char *Cmd) { PrintAndLogEx(SUCCESS, "Fudan based card"); } else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08s, sizeof(fkey)) == 0 && card.sak == 0x08 && memcmp(blockdata + 5, "\x08\x04\x00", 3) == 0 - && (blockdata[8] == 0x03 || blockdata[8] == 0x04 || blockdata[8] == 0x05) && blockdata[15] == 0x90) { - PrintAndLogEx(SUCCESS, "Fudan FM11RF08S %02X%02X", blockdata[8], blockdata[15]); - expect_static_enc_nonce = true; - } else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08s, sizeof(fkey)) == 0 - && card.sak == 0x08 && memcmp(blockdata + 5, "\x08\x04\x00", 3) == 0 - && (blockdata[8] == 0x03 || blockdata[8] == 0x04) && blockdata[15] == 0x91) { - PrintAndLogEx(SUCCESS, "Fudan FM11RF08 %02X%02X with advanced verification method", blockdata[8], blockdata[15]); - expect_static_enc_nonce = false; + && (blockdata[8] == 0x03 || blockdata[8] == 0x04) && blockdata[15] == 0x90) { + PrintAndLogEx(SUCCESS, "Fudan FM11RF08S"); } else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08s, sizeof(fkey)) == 0 && card.sak == 0x08 && memcmp(blockdata + 5, "\x00\x03\x00\x10", 4) == 0 && blockdata[15] == 0x90) { - PrintAndLogEx(SUCCESS, "Fudan FM11RF08S-7B %02X%02X", blockdata[8], blockdata[15]); - expect_static_enc_nonce = true; + PrintAndLogEx(SUCCESS, "Fudan FM11RF08S-7B"); } else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08, sizeof(fkey)) == 0 && card.sak == 0x08 && memcmp(blockdata + 5, "\x08\x04\x00", 3) == 0 && blockdata[15] == 0x98) { - PrintAndLogEx(SUCCESS, "Fudan FM11RF08S %02X%02X", blockdata[8], blockdata[15]); - expect_static_enc_nonce = true; + PrintAndLogEx(SUCCESS, "Fudan FM11RF08S **98"); } else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08, sizeof(fkey)) == 0 && card.sak == 0x08 && memcmp(blockdata + 5, "\x08\x04\x00", 3) == 0 && (blockdata[8] >= 0x01 && blockdata[8] <= 0x03) && blockdata[15] == 0x1D) { @@ -10454,12 +9834,9 @@ static int CmdHF14AMfInfo(const char *Cmd) { && card.sak == 0x08 && memcmp(blockdata + 5, "\x00\x01\x00\x10", 4) == 0 && blockdata[15] == 0x1D) { PrintAndLogEx(SUCCESS, "Fudan FM11RF08-7B"); - } else if (fKeyType == MF_KEY_BD && memcmp(fkey, k32n, sizeof(fkey)) == 0 + } else if (fKeyType == MF_KEY_BD && memcmp(fkey, k32, sizeof(fkey)) == 0 && card.sak == 0x18 && memcmp(blockdata + 5, "\x18\x02\x00\x46\x44\x53\x37\x30\x56\x30\x31", 11) == 0) { - PrintAndLogEx(SUCCESS, "Fudan FM11RF32N"); - } else if (fKeyType == MF_KEY_BD && memcmp(fkey, k32n2, sizeof(fkey)) == 0 - && card.sak == 0x18 && memcmp(blockdata + 5, "\x18\x02\x00\x46\x44\x53\x37\x30\x56\x30\x31", 11) == 0) { - PrintAndLogEx(SUCCESS, "Fudan FM11RF32N (variant)"); + PrintAndLogEx(SUCCESS, "Fudan FM11RF32"); } else if (fKeyType == MF_KEY_BD && memcmp(fkey, k08, sizeof(fkey)) == 0 && card.sak == 0x20 && memcmp(blockdata + 8, "\x62\x63\x64\x65\x66\x67\x68\x69", 8) == 0) { PrintAndLogEx(SUCCESS, "Fudan FM11RF32 (SAK=20)"); @@ -10485,8 +9862,7 @@ static int CmdHF14AMfInfo(const char *Cmd) { && card.sak == 0x08 && memcmp(blockdata + 5, "\x88\x04\x00\x45", 4) == 0) { PrintAndLogEx(SUCCESS, "NXP MF1ICS5004"); } else if (fKeyType == MF_KEY_BD) { - PrintAndLogEx(SUCCESS, _RED_("Unknown card with backdoor")); - PrintAndLogEx(INFO, "Please report details!"); + PrintAndLogEx(SUCCESS, _RED_("Unknown card with backdoor, please report details!")); } else // other cards if (card.sak == 0x08 && memcmp(blockdata + 5, "\x88\x04\x00\x46", 4) == 0) { @@ -10500,12 +9876,11 @@ static int CmdHF14AMfInfo(const char *Cmd) { } else if (card.sak == 0x08 && memcmp(blockdata + 5, "\x88\x04\x00\xc0", 4) == 0) { PrintAndLogEx(SUCCESS, "NXP MF1ICS5035"); } else { - PrintAndLogEx(SUCCESS, "n/a"); + PrintAndLogEx(SUCCESS, "unknown"); } - if (keycnt > 1 && e_sector != NULL && e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) { + if (e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) { PrintAndLogEx(SUCCESS, "dormakaba Saflok detected"); - ParseAndPrintSaflokData(&e_sector[0], &e_sector[1]); } } else { @@ -10542,9 +9917,6 @@ static int CmdHF14AMfInfo(const char *Cmd) { PrintAndLogEx(FAILED, "Prng........ " _RED_("fail")); } - bool tested_static_nonce = false; - int result_static_nonce = 0; - // detect static encrypted nonce if (keylen == MIFARE_KEY_SIZE) { res = detect_classic_static_encrypted_nonce(blockn, keytype, key); @@ -10558,8 +9930,6 @@ static int CmdHF14AMfInfo(const char *Cmd) { PrintAndLogEx(SUCCESS, "Static enc nonce... " _RED_("yes")); fKeyType = 0xFF; // dont detect twice } - result_static_nonce = res; - tested_static_nonce = true; } if (fKeyType != 0xFF) { @@ -10571,16 +9941,6 @@ static int CmdHF14AMfInfo(const char *Cmd) { } else if (res == NONCE_STATIC_ENC) { PrintAndLogEx(SUCCESS, "Static enc nonce... " _RED_("yes")); } - result_static_nonce = res; - tested_static_nonce = true; - } - if (tested_static_nonce) { - if ((result_static_nonce == NONCE_STATIC_ENC) && (!expect_static_enc_nonce)) { - PrintAndLogEx(WARNING, "Static enc nonce detected on a card not supposed to support it, please report... "); - } - if ((result_static_nonce != NONCE_STATIC_ENC) && (expect_static_enc_nonce)) { - PrintAndLogEx(WARNING, "Static enc nonce not detected on a card supposed to support it, please report... "); - } } if (do_nack_test) { @@ -10592,7 +9952,6 @@ static int CmdHF14AMfInfo(const char *Cmd) { PrintAndLogEx(HINT, "Hint: Try `" _YELLOW_("script run fm11rf08s_recovery.py") "`"); } -out: if (setDeviceDebugLevel(dbg_curr, false) != PM3_SUCCESS) { return PM3_EFAILED; } @@ -10829,7 +10188,7 @@ static int CmdHF14AMfISEN(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("ISO14443-a Information") " -----------------------------"); + PrintAndLogEx(INFO, "--- " _CYAN_("ISO14443-a Information") " ---------------------"); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02X %02X"), card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02X [%" PRIu64 "]"), card.sak, resp.oldarg[0]); @@ -10841,11 +10200,11 @@ static int CmdHF14AMfISEN(const char *Cmd) { int res = detect_classic_static_encrypted_nonce_ex(blockn, keytype, key, blockn_nested, keytype_nested, key_nested, nr_nested, reset, hardreset, addread, addauth, incblk2, corruptnrar, corruptnrarparity, true); if (res == NONCE_STATIC) { - PrintAndLogEx(SUCCESS, "Static nonce....... " _YELLOW_("yes")); + PrintAndLogEx(SUCCESS, "Static nonce......... " _YELLOW_("yes")); } else if (res == NONCE_SUPERSTATIC) { - PrintAndLogEx(SUCCESS, "Static nonce....... " _YELLOW_("yes, even when nested")); + PrintAndLogEx(SUCCESS, "Static nonce......... " _YELLOW_("yes, even when nested")); } else if (res == NONCE_STATIC_ENC) { - PrintAndLogEx(SUCCESS, "Static enc nonce... " _RED_("yes")); + PrintAndLogEx(SUCCESS, "Static enc nonce..... " _RED_("yes")); } if (res == NONCE_STATIC_ENC) { @@ -10860,68 +10219,12 @@ static int CmdHF14AMfISEN(const char *Cmd) { return PM3_SUCCESS; } -static int CmdHF14AMfBambuKeys(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "hf mf bambukeys", - "Generate keys for a Bambu Lab filament tag", - "hf mf bambukeys -r\n" - "hf mf bambukeys -r -d\n" - "hf mf bambukeys -u 11223344\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str0("u", "uid", "", "UID (4 hex bytes)"), - arg_lit0("r", NULL, "Read UID from tag"), - arg_lit0("d", NULL, "Dump keys to file"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - int u_len = 0; - uint8_t uid[7] = {0x00}; - CLIGetHexWithReturn(ctx, 1, uid, &u_len); - bool use_tag = arg_get_lit(ctx, 2); - bool dump_keys = arg_get_lit(ctx, 3); - CLIParserFree(ctx); - - if (use_tag) { - // read uid from tag - int res = mf_read_uid(uid, &u_len, NULL); - if (res != PM3_SUCCESS) { - return res; - } - } - - if (u_len != 4) { - PrintAndLogEx(WARNING, "Key must be 4 hex bytes"); - return PM3_EINVARG; - } - - PrintAndLogEx(INFO, "-----------------------------------"); - PrintAndLogEx(INFO, " UID 4b... " _YELLOW_("%s"), sprint_hex(uid, 4)); - PrintAndLogEx(INFO, "-----------------------------------"); - - uint8_t keys[32 * 6]; - mfc_algo_bambu_all(uid, (void *)keys); - - for (int block = 0; block < 32; block++) { - PrintAndLogEx(INFO, "%d: %012" PRIX64, block, bytes_to_num(keys + (block * 6), 6)); - } - - if (dump_keys) { - char fn[FILE_PATH_SIZE] = {0}; - snprintf(fn, sizeof(fn), "hf-mf-%s-key", sprint_hex_inrow(uid, 4)); - saveFileEx(fn, ".bin", keys, 32 * 6, spDump); - } - - return PM3_SUCCESS; -} - static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdHF14AMfList, AlwaysAvailable, "List MIFARE history"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("recovery") " -----------------------"}, + {"info", CmdHF14AMfInfo, IfPm3Iso14443a, "mfc card Info"}, + {"isen", CmdHF14AMfISEN, IfPm3Iso14443a, "mfc card Info Static Encrypted Nonces"}, {"darkside", CmdHF14AMfDarkside, IfPm3Iso14443a, "Darkside attack"}, {"nested", CmdHF14AMfNested, IfPm3Iso14443a, "Nested attack"}, {"hardnested", CmdHF14AMfNestedHard, AlwaysAvailable, "Nested attack for hardened MIFARE Classic cards"}, @@ -10934,13 +10237,10 @@ static command_t CommandTable[] = { {"fchk", CmdHF14AMfChk_fast, IfPm3Iso14443a, "Check keys fast, targets all keys on card"}, {"decrypt", CmdHf14AMfDecryptBytes, AlwaysAvailable, "Decrypt Crypto1 data from sniff or trace"}, {"supercard", CmdHf14AMfSuperCard, IfPm3Iso14443a, "Extract info from a `super card`"}, - {"bambukeys", CmdHF14AMfBambuKeys, AlwaysAvailable, "Generate key table for Bambu Lab filament tag"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("operations") " -----------------------"}, {"auth4", CmdHF14AMfAuth4, IfPm3Iso14443a, "ISO14443-4 AES authentication"}, {"acl", CmdHF14AMfAcl, AlwaysAvailable, "Decode and print MIFARE Classic access rights bytes"}, {"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE Classic tag to binary file"}, - {"info", CmdHF14AMfInfo, IfPm3Iso14443a, "Tag information"}, - {"isen", CmdHF14AMfISEN, IfPm3Iso14443a, "Information Static Encrypted Nonces"}, {"mad", CmdHF14AMfMAD, AlwaysAvailable, "Checks and prints MAD"}, {"personalize", CmdHFMFPersonalize, IfPm3Iso14443a, "Personalize UID (MIFARE Classic EV1 only)"}, {"rdbl", CmdHF14AMfRdBl, IfPm3Iso14443a, "Read MIFARE Classic block"}, diff --git a/client/src/cmdhfmf.h b/client/src/cmdhfmf.h index ff1695341..f39d63ff9 100644 --- a/client/src/cmdhfmf.h +++ b/client/src/cmdhfmf.h @@ -35,13 +35,9 @@ void printKeyTable(size_t sectorscnt, sector_t *e_sector); void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector); // void printKeyTableEx(size_t sectorscnt, sector_t *e_sector, uint8_t start_sector, bool singel_sector); - bool mfc_value(const uint8_t *d, int32_t *val); void mf_print_sector_hdr(uint8_t sector); void mf_print_block_one(uint8_t blockno, uint8_t *d, bool verbose); -int mf_print_keys(uint16_t n, uint8_t *d); -void mf_print_blocks(uint16_t n, uint8_t *d, bool verbose); - int mfc_ev1_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len); #endif diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index b13989119..4e4c19a57 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -89,6 +89,15 @@ typedef struct mfdes_data { uint8_t *data; } PACKED mfdes_data_t; +typedef struct mfdes_info_res { + uint8_t isOK; + uint8_t uid[7]; + uint8_t uidlen; + uint8_t versionHW[7]; + uint8_t versionSW[7]; + uint8_t details[14]; +} PACKED mfdes_info_res_t; + typedef struct mfdes_value { uint8_t fileno; //01 uint8_t value[16]; @@ -127,6 +136,21 @@ typedef enum { MFDES_VALUE_FILE } MFDES_FILE_TYPE_T; +typedef enum { + DESFIRE_UNKNOWN = 0, + DESFIRE_MF3ICD40, + DESFIRE_EV1, + DESFIRE_EV2, + DESFIRE_EV2_XL, + DESFIRE_EV3, + DESFIRE_LIGHT, + PLUS_EV1, + PLUS_EV2, + NTAG413DNA, + NTAG424, + DUOX, +} nxp_cardtype_t; + typedef enum { DESFIRE_UNKNOWN_PROD = 0, DESFIRE_PHYSICAL, @@ -238,7 +262,7 @@ static char *getProtocolStr(uint8_t id, bool hw) { static char *getVersionStr(uint8_t type, uint8_t major, uint8_t minor) { - static char buf[60] = {0x00}; + static char buf[40] = {0x00}; char *retStr = buf; if (type == 0x01 && major == 0x00) @@ -255,8 +279,6 @@ static char *getVersionStr(uint8_t type, uint8_t major, uint8_t minor) { snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV2") " )", major, minor); else if (type == 0x01 && major == 0x33 && minor == 0x00) snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV3") " )", major, minor); - else if (type == 0x81 && major == 0x43 && minor == 0x01) - snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire EV3C implementation on P71D600") " )", major, minor); // Swisskey iShield Key else if (type == 0x01 && major == 0x30 && minor == 0x00) snprintf(retStr, sizeof(buf), "%x.%x ( " _GREEN_("DESFire Light") " )", major, minor); else if (type == 0x02 && major == 0x11 && minor == 0x00) @@ -310,7 +332,7 @@ static const char *getAidCommentStr(uint32_t aid) { return ""; } -nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) { +static nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) { // DESFire MF3ICD40 if (type == 0x01 && major == 0x00 && minor == 0x02) @@ -331,9 +353,6 @@ nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) { if (type == 0x01 && major == 0x33 && minor == 0x00) return DESFIRE_EV3; - if (type == 0x81 && major == 0x43 && minor == 0x01) - return DESFIRE_EV3; - // Duox if (type == 0x01 && major == 0xA0 && minor == 0x00) return DUOX; @@ -366,7 +385,7 @@ nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) { if (type == 0x04 && major == 0x30 && minor == 0x00) return NTAG424; - return NXP_UNKNOWN; + return DESFIRE_UNKNOWN; } // ref: https://www.nxp.com/docs/en/application-note/AN12343.pdf p7 @@ -404,7 +423,7 @@ static const char *getProductTypeStr(const uint8_t *versionhw) { return "UNKNOWN PROD"; } -int mfdes_get_info(mfdes_info_res_t *info) { +static int mfdes_get_info(mfdes_info_res_t *info) { PacketResponseNG resp; SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0); @@ -463,7 +482,7 @@ static void swap24(uint8_t *data) { // default parameters static uint8_t defaultKeyNum = 0; -static DesfireCryptoAlgorithm defaultAlgoId = T_3DES; // Real DESFire cards seem to use 2TDEA by default +static DesfireCryptoAlgorithm defaultAlgoId = T_DES; static uint8_t defaultKey[DESFIRE_MAX_KEY_SIZE] = {0}; static int defaultKdfAlgo = MFDES_KDF_ALGO_NONE; static int defaultKdfInputLen = 0; @@ -479,7 +498,6 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext_t *d uint8_t cmodeid, uint8_t ccsetid, uint8_t schannid, uint8_t appid, uint8_t appisoid, - uint8_t dfnameid, int *securechannel, DesfireCommunicationMode defcommmode, uint32_t *id, @@ -565,22 +583,6 @@ static int CmdDesGetSessionParameters(CLIParserContext *ctx, DesfireContext_t *d return PM3_ESOFT; } - // Handle dfname parameter - if (dfnameid && id) { - uint8_t dfname_data[16] = {0}; - int dfname_len = 0; - if (CLIParamHexToBuf(arg_get_str(ctx, dfnameid), dfname_data, sizeof(dfname_data), &dfname_len) == 0 && dfname_len > 0) { - if (dfname_len <= 16) { - DesfireSetDFName(dctx, dfname_data, dfname_len); - if (selectway) - *selectway = ISWDFName; - } else { - PrintAndLogEx(ERR, "DF name length must be between 1-16 bytes, got %d", dfname_len); - return PM3_EINVARG; - } - } - } - if (appid && id) { *id = 0x000000; if (CLIGetUint32Hex(ctx, appid, 0x000000, id, NULL, 3, "AID must have 3 bytes length")) @@ -634,7 +636,7 @@ static int CmdHF14ADesDefault(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; - int res = CmdDesGetSessionParameters(ctx, &dctx, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 0, &securechann, DCMNone, NULL, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 1, 2, 3, 4, 5, 6, 7, 8, 0, 0, &securechann, DCMNone, NULL, NULL); if (res) { CLIParserFree(ctx); return res; @@ -708,7 +710,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { return PM3_SUCCESS; } - if (cardtype == NXP_UNKNOWN) { + if (cardtype == DESFIRE_UNKNOWN) { PrintAndLogEx(INFO, "HW Version.. %s", sprint_hex_inrow(info.versionHW, sizeof(info.versionHW))); PrintAndLogEx(INFO, "SW Version.. %s", sprint_hex_inrow(info.versionSW, sizeof(info.versionSW))); PrintAndLogEx(INFO, "Version data identification failed. Report to Iceman!"); @@ -815,7 +817,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { if (aidbuflen > 2) { - uint8_t j = (aidbuflen / 3); + uint8_t j = aidbuflen / 3; PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "--- " _CYAN_("AID list") " ( " _YELLOW_("%u") " found )", j); @@ -824,7 +826,6 @@ static int CmdHF14ADesInfo(const char *Cmd) { uint32_t aid = DesfireAIDByteToUint(&aidbuf[i]); PrintAndLogEx(SUCCESS, _YELLOW_("%06X") ", %s", aid, getAidCommentStr(aid)); } - PrintAndLogEx(NORMAL, ""); } DesfireFillPICCInfo(&dctx, &PICCInfo, true); @@ -1049,7 +1050,7 @@ static int AuthCheckDesfire(DesfireContext_t *dctx, DesfireSetKeyNoClear(dctx, keyno, T_DES, deskeyList[curkey]); res = DesfireAuthenticate(dctx, secureChannel, false); if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "AID 0x%06X, Found DES Key %02u... " _GREEN_("%s"), curaid, keyno, sprint_hex(deskeyList[curkey], 8)); + PrintAndLogEx(SUCCESS, "AID 0x%06X, Found DES Key %02u : " _GREEN_("%s"), curaid, keyno, sprint_hex(deskeyList[curkey], 8)); foundKeys[0][keyno][0] = 0x01; *result = true; memcpy(&foundKeys[0][keyno][1], deskeyList[curkey], 8); @@ -1081,7 +1082,7 @@ static int AuthCheckDesfire(DesfireContext_t *dctx, DesfireSetKeyNoClear(dctx, keyno, T_3DES, aeskeyList[curkey]); res = DesfireAuthenticate(dctx, secureChannel, false); if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 2TDEA Key %02u... " _GREEN_("%s"), curaid, keyno, sprint_hex_inrow(aeskeyList[curkey], 16)); + PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 2TDEA Key %02u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16)); foundKeys[1][keyno][0] = 0x01; *result = true; memcpy(&foundKeys[1][keyno][1], aeskeyList[curkey], 16); @@ -1113,7 +1114,7 @@ static int AuthCheckDesfire(DesfireContext_t *dctx, DesfireSetKeyNoClear(dctx, keyno, T_AES, aeskeyList[curkey]); res = DesfireAuthenticate(dctx, secureChannel, false); if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "AID 0x%06X, Found AES Key %02u... " _GREEN_("%s"), curaid, keyno, sprint_hex_inrow(aeskeyList[curkey], 16)); + PrintAndLogEx(SUCCESS, "AID 0x%06X, Found AES Key %02u : " _GREEN_("%s"), curaid, keyno, sprint_hex(aeskeyList[curkey], 16)); foundKeys[2][keyno][0] = 0x01; *result = true; memcpy(&foundKeys[2][keyno][1], aeskeyList[curkey], 16); @@ -1145,7 +1146,7 @@ static int AuthCheckDesfire(DesfireContext_t *dctx, DesfireSetKeyNoClear(dctx, keyno, T_3K3DES, k3kkeyList[curkey]); res = DesfireAuthenticate(dctx, secureChannel, false); if (res == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3TDEA Key %02u... " _GREEN_("%s"), curaid, keyno, sprint_hex_inrow(k3kkeyList[curkey], 24)); + PrintAndLogEx(SUCCESS, "AID 0x%06X, Found 3TDEA Key %02u : " _GREEN_("%s"), curaid, keyno, sprint_hex(k3kkeyList[curkey], 24)); foundKeys[3][keyno][0] = 0x01; *result = true; memcpy(&foundKeys[3][keyno][1], k3kkeyList[curkey], 16); @@ -1185,8 +1186,8 @@ static int CmdHF14aDesChk(const char *Cmd) { CLIParserInit(&ctx, "hf mfdes chk", "Checks keys with MIFARE DESFire card.", "hf mfdes chk --aid 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456\n" - "hf mfdes chk -f mfdes_default_keys -> check keys against all existing aid on card\n" - "hf mfdes chk -f mfdes_default_keys --aid 123456 -> check keys against aid 0x123456\n" + "hf mfdes chk -d mfdes_default_keys -> check keys against all existing aid on card\n" + "hf mfdes chk -d mfdes_default_keys --aid 123456 -> check keys against aid 0x123456\n" "hf mfdes chk --aid 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to `keys.json`\n" "hf mfdes chk --aid 123456 --pattern2b --startp2b FA00 -> check all 2-byte keys pattern on aid 0x123456. Start from key FA00FA00...FA00"); @@ -1194,7 +1195,7 @@ static int CmdHF14aDesChk(const char *Cmd) { arg_param_begin, arg_str0(NULL, "aid", "", "Use specific AID (3 hex bytes, big endian)"), arg_str0("k", "key", "", "Key for checking (HEX 16 bytes)"), - arg_str0("f", "file", "", "Filename of dictionary"), + arg_str0("d", "dict", "", "Dictionary file with keys"), arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"), arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), arg_str0(NULL, "startp2b", "", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"), @@ -1207,12 +1208,12 @@ static int CmdHF14aDesChk(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); + bool APDULogging = arg_get_lit(ctx, 11); + int aidlength = 0; uint8_t aid[3] = {0}; CLIGetHexWithReturn(ctx, 1, aid, &aidlength); - swap24(aid); - uint8_t vkey[16] = {0}; int vkeylen = 0; CLIGetHexWithReturn(ctx, 2, vkey, &vkeylen); @@ -1291,26 +1292,17 @@ static int CmdHF14aDesChk(const char *Cmd) { int kdfInputLen = 0; CLIGetHexWithReturn(ctx, 10, kdfInput, &kdfInputLen); - bool APDULogging = arg_get_lit(ctx, 11); - CLIParserFree(ctx); SetAPDULogging(APDULogging); // 1-byte pattern search mode if (pattern1b) { - - for (uint32_t i = 0; i < 0x100; i++) { + for (uint32_t i = 0; i < 0x100; i++) memset(aeskeyList[i], i, 16); - } - - for (uint32_t i = 0; i < 0x100; i++) { + for (uint32_t i = 0; i < 0x100; i++) memset(deskeyList[i], i, 8); - } - - for (uint32_t i = 0; i < 0x100; i++) { + for (uint32_t i = 0; i < 0x100; i++) memset(k3kkeyList[i], i, 24); - } - aeskeyListLen = 0x100; deskeyListLen = 0x100; k3kkeyListLen = 0x100; @@ -1326,21 +1318,18 @@ static int CmdHF14aDesChk(const char *Cmd) { if (dict_filenamelen) { res = loadFileDICTIONARYEx((char *)dict_filename, deskeyList, sizeof(deskeyList), NULL, 8, &deskeyListLen, 0, &endFilePosition, true); - if (res == PM3_SUCCESS && endFilePosition) { + if (res == PM3_SUCCESS && endFilePosition) PrintAndLogEx(SUCCESS, "First part of des dictionary successfully loaded."); - } endFilePosition = 0; res = loadFileDICTIONARYEx((char *)dict_filename, aeskeyList, sizeof(aeskeyList), NULL, 16, &aeskeyListLen, 0, &endFilePosition, true); - if (res == PM3_SUCCESS && endFilePosition) { + if (res == PM3_SUCCESS && endFilePosition) PrintAndLogEx(SUCCESS, "First part of aes dictionary successfully loaded."); - } endFilePosition = 0; res = loadFileDICTIONARYEx((char *)dict_filename, k3kkeyList, sizeof(k3kkeyList), NULL, 24, &k3kkeyListLen, 0, &endFilePosition, true); - if (res == PM3_SUCCESS && endFilePosition) { + if (res == PM3_SUCCESS && endFilePosition) PrintAndLogEx(SUCCESS, "First part of k3kdes dictionary successfully loaded."); - } endFilePosition = 0; } @@ -1362,9 +1351,8 @@ static int CmdHF14aDesChk(const char *Cmd) { PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " k3kdes keys", k3kkeyListLen); } - if (verbose == false) { + if (verbose == false) PrintAndLogEx(INFO, "Search keys:"); - } bool result = false; uint8_t app_ids[78] = {0}; @@ -1519,7 +1507,7 @@ static int CmdHF14aDesDetect(const char *Cmd) { "Detect key type and tries to find one from the list.", "hf mfdes detect -> detect key 0 from PICC level\n" "hf mfdes detect --schann d40 -> detect key 0 from PICC level via secure channel D40\n" - "hf mfdes detect -f mfdes_default_keys -> detect key 0 from PICC level with help of the standard dictionary\n" + "hf mfdes detect --dict mfdes_default_keys -> detect key 0 from PICC level with help of the standard dictionary\n" "hf mfdes detect --aid 123456 -n 2 --save -> detect key 2 from app 123456 and if succeed - save params to defaults (`default` command)\n" "hf mfdes detect --isoid df01 --save -> detect key 0 and save to defaults with card in the LRP mode"); @@ -1537,8 +1525,7 @@ static int CmdHF14aDesDetect(const char *Cmd) { arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)."), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), - arg_str0("f", "file", "", "Filename of dictionary"), + arg_str0(NULL, "dict", "", "Dictionary file name with keys"), arg_lit0(NULL, "save", "Save found key and parameters to defaults"), arg_param_end }; @@ -1551,7 +1538,7 @@ static int CmdHF14aDesDetect(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -1559,13 +1546,13 @@ static int CmdHF14aDesDetect(const char *Cmd) { uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0}; int dict_filenamelen = 0; - if (CLIParamStrToBuf(arg_get_str(ctx, 14), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { + if (CLIParamStrToBuf(arg_get_str(ctx, 13), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { PrintAndLogEx(FAILED, "File name too long or invalid."); CLIParserFree(ctx); return PM3_EINVARG; } - bool save = arg_get_lit(ctx, 15); + bool save = arg_get_lit(ctx, 14); SetAPDULogging(APDULogging); CLIParserFree(ctx); @@ -1583,38 +1570,28 @@ static int CmdHF14aDesDetect(const char *Cmd) { uint8_t data[250] = {0}; size_t datalen = 0; - res = DesfireGetKeySettings(&dctx, data, &datalen); if (res == PM3_SUCCESS && datalen >= 2) { - uint8_t num_keys = data[1]; - switch (num_keys >> 6) { - case 0: { + case 0: keytypes[T_DES] = true; keytypes[T_3DES] = true; break; - } - case 1: { + case 1: keytypes[T_3K3DES] = true; break; - } - case 2: { + case 2: keytypes[T_AES] = true; break; - } - default: { + default: break; - } } - } else { // if fail - check auth commands AuthCommandsChk_t authCmdCheck = {0}; DesfireCheckAuthCommands(selectway, id, NULL, 0, &authCmdCheck); - if (authCmdCheck.checked) { - if (authCmdCheck.auth) { keytypes[T_DES] = true; keytypes[T_3DES] = true; @@ -1623,17 +1600,14 @@ static int CmdHF14aDesDetect(const char *Cmd) { keytypes[T_3K3DES] = true; } } - if (authCmdCheck.authAES || authCmdCheck.authEV2) { keytypes[T_AES] = true; } - if (authCmdCheck.authLRP) { keytypes[T_AES] = true; uselrp = true; securechann = DACLRP; } - } else { // if nothing helps - we check DES only keytypes[T_DES] = true; @@ -1648,13 +1622,10 @@ static int CmdHF14aDesDetect(const char *Cmd) { } if (verbose) { - - if (DesfireMFSelected(selectway, id)) { + if (DesfireMFSelected(selectway, id)) PrintAndLogEx(INFO, "Check PICC key num: %d (0x%02x)", dctx.keyNum, dctx.keyNum); - } else { + else PrintAndLogEx(INFO, "Check: %s key num: %d (0x%02x)", DesfireWayIDStr(selectway, id), dctx.keyNum, dctx.keyNum); - } - PrintAndLogEx(INFO, "keys: DES: %s 2TDEA: %s 3TDEA: %s AES: %s LRP: %s", keytypes[T_DES] ? _GREEN_("YES") : _RED_("NO"), keytypes[T_3DES] ? _GREEN_("YES") : _RED_("NO"), @@ -1668,61 +1639,43 @@ static int CmdHF14aDesDetect(const char *Cmd) { bool found = false; size_t errcount = 0; for (uint8_t ktype = T_DES; ktype <= T_AES; ktype++) { - - if (keytypes[ktype] == false) { + if (!keytypes[ktype]) continue; - } - dctx.keyType = ktype; - - if (verbose) { + if (verbose) PrintAndLogEx(INFO, "Scan key type: %s", CLIGetOptionListStr(DesfireAlgoOpts, dctx.keyType)); - } if (dict_filenamelen == 0) { // keys from mifaredefault.h for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { - uint8_t key[DESFIRE_MAX_KEY_SIZE] = {0}; - if (hex_to_bytes(g_mifare_plus_default_keys[i], key, 16) != 16) { + if (hex_to_bytes(g_mifare_plus_default_keys[i], key, 16) != 16) continue; - } - - if (ktype == T_3K3DES) { + if (ktype == T_3K3DES) memcpy(&key[16], key, 8); - } res = DesfireAuthCheck(&dctx, selectway, id, securechann, key); if (res == PM3_SUCCESS) { found = true; break; // all the params already in the dctx } - if (res == -10) { - - if (verbose) { + if (verbose) PrintAndLogEx(ERR, "Can't select AID. There is no connection with card."); - } found = false; break; // we can't select app after invalid 1st auth stages } - if (res == -11) { - if (errcount > 10) { - if (verbose) { + if (verbose) PrintAndLogEx(ERR, "Too much errors (%zu) from card", errcount); - } break; } errcount++; - - } else { + } else errcount = 0; - } } - } else { // keys from file uint8_t keyList[MAX_KEYS_LIST_LEN * MAX_KEY_LEN] = {0}; @@ -1730,65 +1683,49 @@ static int CmdHF14aDesDetect(const char *Cmd) { size_t keylen = desfire_get_key_length(dctx.keyType); size_t endFilePosition = 0; - while (found == false) { - + while (!found) { res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, keylen, &keyListLen, endFilePosition, &endFilePosition, verbose); - if (res != 1 && res != PM3_SUCCESS) { + if (res != 1 && res != PM3_SUCCESS) break; - } for (int i = 0; i < keyListLen; i++) { - res = DesfireAuthCheck(&dctx, selectway, id, securechann, &keyList[i * keylen]); if (res == PM3_SUCCESS) { found = true; break; // all the params already in the dctx } - if (res == -10) { - if (verbose) { + if (verbose) PrintAndLogEx(ERR, "Can't select AID. There is no connection with card."); - } found = false; break; // we can't select app after invalid 1st auth stages } - if (res == -11) { - if (errcount > 10) { - if (verbose) { + if (verbose) PrintAndLogEx(ERR, "Too much errors (%zu) from card", errcount); - } break; } errcount++; - - } else { + } else errcount = 0; - } - } - if (endFilePosition == 0) { + if (endFilePosition == 0) break; - } } } - - if (found) { + if (found) break; - } } if (found) { - - if (DesfireMFSelected(selectway, id)) { + if (DesfireMFSelected(selectway, id)) PrintAndLogEx(INFO, _GREEN_("Found") " key num: %d (0x%02x)", dctx.keyNum, dctx.keyNum); - } else { + else PrintAndLogEx(INFO, "Found key for: %s key num: %d (0x%02x)", DesfireWayIDStr(selectway, id), dctx.keyNum, dctx.keyNum); - } PrintAndLogEx(INFO, "channel " _GREEN_("%s") " key " _GREEN_("%s") " [%d]: " _GREEN_("%s"), CLIGetOptionListStr(DesfireSecureChannelOpts, securechann), @@ -1803,7 +1740,6 @@ static int CmdHF14aDesDetect(const char *Cmd) { DropField(); if (found && save) { - defaultKeyNum = dctx.keyNum; defaultAlgoId = dctx.keyType; memcpy(defaultKey, dctx.key, DESFIRE_MAX_KEY_SIZE); @@ -1814,16 +1750,17 @@ static int CmdHF14aDesDetect(const char *Cmd) { defaultCommSet = dctx.cmdSet; PrintAndLogEx(INFO, "-----------" _CYAN_("Default parameters") "---------------------------------"); - PrintAndLogEx(INFO, "Key Num....... %d", defaultKeyNum); - PrintAndLogEx(INFO, "Algo.......... %s", CLIGetOptionListStr(DesfireAlgoOpts, defaultAlgoId)); - PrintAndLogEx(INFO, "Key........... %s", sprint_hex(defaultKey, desfire_get_key_length(defaultAlgoId))); - PrintAndLogEx(INFO, "KDF algo...... %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, defaultKdfAlgo)); - PrintAndLogEx(INFO, "KDF input..... [%d] %s", defaultKdfInputLen, sprint_hex(defaultKdfInput, defaultKdfInputLen)); - PrintAndLogEx(INFO, "Secure chan... %s", CLIGetOptionListStr(DesfireSecureChannelOpts, defaultSecureChannel)); - PrintAndLogEx(INFO, "Command set... %s", CLIGetOptionListStr(DesfireCommandSetOpts, defaultCommSet)); - PrintAndLogEx(INFO, "Parameters saved to in-memory ( %s )", _GREEN_("ok")); + + PrintAndLogEx(INFO, "Key Num : %d", defaultKeyNum); + PrintAndLogEx(INFO, "Algo : %s", CLIGetOptionListStr(DesfireAlgoOpts, defaultAlgoId)); + PrintAndLogEx(INFO, "Key : %s", sprint_hex(defaultKey, desfire_get_key_length(defaultAlgoId))); + PrintAndLogEx(INFO, "KDF algo : %s", CLIGetOptionListStr(DesfireKDFAlgoOpts, defaultKdfAlgo)); + PrintAndLogEx(INFO, "KDF input : [%d] %s", defaultKdfInputLen, sprint_hex(defaultKdfInput, defaultKdfInputLen)); + PrintAndLogEx(INFO, "Secure chan : %s", CLIGetOptionListStr(DesfireSecureChannelOpts, defaultSecureChannel)); + PrintAndLogEx(INFO, "Command set : %s", CLIGetOptionListStr(DesfireCommandSetOpts, defaultCommSet)); + PrintAndLogEx(INFO, _GREEN_("Saved")); } - PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; } @@ -1866,7 +1803,7 @@ static int CmdHF14aDesMAD(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, &securechann, DCMPlain, &appid, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMPlain, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -2042,7 +1979,7 @@ static int CmdHF14ADesSelectApp(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, &securechann, DCMPlain, &appid, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMPlain, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -2164,7 +2101,7 @@ static int CmdHF14ADesBruteApps(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; - int res = CmdDesGetSessionParameters(ctx, &dctx, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &securechann, DCMNone, NULL, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &securechann, DCMNone, NULL, NULL); if (res) { CLIParserFree(ctx); return res; @@ -2196,35 +2133,25 @@ static int CmdHF14ADesBruteApps(const char *Cmd) { startAid[1] = 0x00; startAid[2] = 0x0F; } - - reverse_array(startAid, 3); - reverse_array(endAid, 3); - uint32_t idStart = DesfireAIDByteToUint(startAid); uint32_t idEnd = DesfireAIDByteToUint(endAid); - if (idStart > idEnd) { PrintAndLogEx(ERR, "Start should be lower than end. start: %06x end: %06x", idStart, idEnd); return PM3_EINVARG; } - - PrintAndLogEx(INFO, "Bruteforce from " _YELLOW_("%06x") " to " _YELLOW_("%06x"), idStart, idEnd); + PrintAndLogEx(INFO, "Bruteforce from %06x to %06x", idStart, idEnd); PrintAndLogEx(INFO, "Enumerating through all AIDs manually, this will take a while!"); - for (uint32_t id = idStart; id <= idEnd && id >= idStart; id += idIncrement) { + if (kbd_enter_pressed()) break; - if (kbd_enter_pressed()) { - break; - } - - float progress = ((id - idStart) / (idEnd - idStart)); - PrintAndLogEx(INPLACE, "Progress " _YELLOW_("%0.1f") " %% current AID: %06X", progress, id); + int progress = ((id - idStart) * 100) / ((idEnd - idStart)); + PrintAndLogEx(INPLACE, "Progress: %d %%, current AID: %06X", progress, id); res = DesfireSelectAIDHexNoFieldOn(&dctx, id); if (res == PM3_SUCCESS) { printf("\33[2K\r"); // clear current line before printing - PrintAndLogEx(SUCCESS, "Got new APPID " _GREEN_("%06X"), id); + PrintAndLogEx(SUCCESS, "Got new APPID %06X", id); } } @@ -2249,8 +2176,7 @@ static int CmdHF14ADesAuth(const char *Cmd) { "hf mfdes auth -n 0 -t des -k 0000000000000000 --kdf none -> select PICC level and authenticate with key num=0, key type=des, key=00..00 and key derivation = none\n" "hf mfdes auth -n 0 -t aes -k 00000000000000000000000000000000 -> select PICC level and authenticate with key num=0, key type=aes, key=00..00 and key derivation = none\n" "hf mfdes auth -n 0 -t des -k 0000000000000000 --save -> select PICC level and authenticate and in case of successful authentication - save channel parameters to defaults\n" - "hf mfdes auth --aid 123456 -> select application 123456 and authenticate via parameters from `default` command\n" - "hf mfdes auth --dfname D2760000850100 -n 0 -t aes -k 00000000000000000000000000000000 -> select DF by name and authenticate"); + "hf mfdes auth --aid 123456 -> select application 123456 and authenticate via parameters from `default` command"); void *argtable[] = { arg_param_begin, @@ -2266,7 +2192,6 @@ static int CmdHF14ADesAuth(const char *Cmd) { arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID of application for some parameters (3 hex bytes, big endian)"), arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)"), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_lit0(NULL, "save", "saves channels parameters to defaults if authentication succeeds"), arg_param_end }; @@ -2279,13 +2204,13 @@ static int CmdHF14ADesAuth(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, &securechann, DCMPlain, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMPlain, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } - bool save = arg_get_lit(ctx, 14); + bool save = arg_get_lit(ctx, 13); SetAPDULogging(APDULogging); CLIParserFree(ctx); @@ -2297,9 +2222,7 @@ static int CmdHF14ADesAuth(const char *Cmd) { return res; } - if (dctx.selectedDFNameLen > 0) { - PrintAndLogEx(SUCCESS, "DF selected and authenticated " _GREEN_("successfully")); - } else if (DesfireMFSelected(selectway, id)) + if (DesfireMFSelected(selectway, id)) PrintAndLogEx(SUCCESS, "PICC selected and authenticated " _GREEN_("succesfully")); else PrintAndLogEx(SUCCESS, "Application " _CYAN_("%s") " selected and authenticated " _GREEN_("succesfully"), DesfireWayIDStr(selectway, id)); @@ -2377,7 +2300,7 @@ static int CmdHF14ADesSetConfiguration(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, &securechann, DCMEncrypted, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMEncrypted, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -2492,7 +2415,7 @@ static int CmdHF14ADesChangeKey(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, &securechann, DCMEncrypted, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMEncrypted, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -2655,7 +2578,7 @@ static int CmdHF14ADesCreateApp(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 12, 0, 0, &securechann, DCMMACed, &appid, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 12, 0, &securechann, DCMMACed, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -2818,7 +2741,7 @@ static int CmdHF14ADesDeleteApp(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, &securechann, DCMMACed, &appid, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMMACed, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -2856,8 +2779,7 @@ static int CmdHF14ADesGetUID(const char *Cmd) { CLIParserInit(&ctx, "hf mfdes getuid", "Get UID from card. Get the real UID if the random UID bit is on and get the same UID as in anticollision if not. Any card's key needs to be provided. ", "hf mfdes getuid -> execute with default factory setup\n" - "hf mfdes getuid --isoid df01 -t aes --schan lrp -> for desfire lights default settings\n" - "hf mfdes getuid --dfname D2760000850100 -> select DF by name and get UID"); + "hf mfdes getuid --isoid df01 -t aes --schan lrp -> for desfire lights default settings"); void *argtable[] = { arg_param_begin, @@ -2873,7 +2795,6 @@ static int CmdHF14ADesGetUID(const char *Cmd) { arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)"), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -2885,7 +2806,7 @@ static int CmdHF14ADesGetUID(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, &securechann, DCMEncrypted, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMEncrypted, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -2963,7 +2884,7 @@ static int CmdHF14ADesFormatPICC(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, &securechann, DCMMACed, &appid, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMMACed, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -3010,7 +2931,6 @@ static int CmdHF14ADesGetFreeMem(const char *Cmd) { arg_str0("c", "ccset", "", "Communicaton command set"), arg_str0(NULL, "schann", "", "Secure channel"), arg_lit0(NULL, "no-auth", "Execute without authentication"), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -3022,9 +2942,7 @@ static int CmdHF14ADesGetFreeMem(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; - uint32_t id = 0x000000; - DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 12, &securechann, (noauth) ? DCMPlain : DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, &securechann, (noauth) ? DCMPlain : DCMMACed, NULL, NULL); if (res) { CLIParserFree(ctx); return res; @@ -3033,7 +2951,7 @@ static int CmdHF14ADesGetFreeMem(const char *Cmd) { SetAPDULogging(APDULogging); CLIParserFree(ctx); - res = DesfireSelectAndAuthenticateAppW(&dctx, securechann, selectway, id, noauth, verbose); + res = DesfireSelectAndAuthenticateEx(&dctx, securechann, 0x000000, noauth, verbose); if (res != PM3_SUCCESS) { DropField(); return res; @@ -3086,7 +3004,7 @@ static int CmdHF14ADesChKeySettings(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, &securechann, DCMEncrypted, &appid, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMEncrypted, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -3133,8 +3051,7 @@ static int CmdHF14ADesGetKeyVersions(const char *Cmd) { "--keynum parameter: App level: key number. PICC level: 00..0d - keys count, 21..23 vc keys, default 0x00.\n"\ "hf mfdes getkeyversions --keynum 00 -> get picc master key version with default key/channel setup\n"\ "hf mfdes getkeyversions --aid 123456 --keynum 0d -> get app 123456 all key versions with default key/channel setup\n" - "hf mfdes getkeyversions --aid 123456 --keynum 0d --no-auth -> get key version without authentication\n"\ - "hf mfdes getkeyversions --dfname D2760000850100 --keynum 00 -> select DF by name and get key versions"); + "hf mfdes getkeyversions --aid 123456 --keynum 0d --no-auth -> get key version without authentication"); void *argtable[] = { arg_param_begin, @@ -3150,38 +3067,36 @@ static int CmdHF14ADesGetKeyVersions(const char *Cmd) { arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)."), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_str0(NULL, "keynum", "", "Key number/count (1 hex byte). (def: 0x00)"), arg_str0(NULL, "keyset", "", "Keyset number (1 hex byte)"), arg_lit0(NULL, "no-auth", "Execute without authentication"), - arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 16); + bool noauth = arg_get_lit(ctx, 15); DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } uint32_t keynum32 = 0x00; - if (CLIGetUint32Hex(ctx, 14, 0x00, &keynum32, NULL, 1, "Key number must have 1 byte length")) { + if (CLIGetUint32Hex(ctx, 13, 0x00, &keynum32, NULL, 1, "Key number must have 1 byte length")) { CLIParserFree(ctx); return PM3_EINVARG; } uint32_t keysetnum32 = 0x00; bool keysetpresent = false; - if (CLIGetUint32Hex(ctx, 15, 0x00, &keysetnum32, &keysetpresent, 1, "Keyset number must have 1 byte length")) { + if (CLIGetUint32Hex(ctx, 14, 0x00, &keysetnum32, &keysetpresent, 1, "Keyset number must have 1 byte length")) { CLIParserFree(ctx); return PM3_EINVARG; } @@ -3238,8 +3153,7 @@ static int CmdHF14ADesGetKeySettings(const char *Cmd) { CLIParserInit(&ctx, "hf mfdes getkeysettings", "Get key settings for card level or application level.", "hf mfdes getkeysettings -> get picc key settings with default key/channel setup\n"\ - "hf mfdes getkeysettings --aid 123456 -> get app 123456 key settings with default key/channel setup\n"\ - "hf mfdes getkeysettings --dfname D2760000850100 -> select DF by name and get key settings"); + "hf mfdes getkeysettings --aid 123456 -> get app 123456 key settings with default key/channel setup"); void *argtable[] = { arg_param_begin, @@ -3254,7 +3168,6 @@ static int CmdHF14ADesGetKeySettings(const char *Cmd) { arg_str0("c", "ccset", "", "Communicaton command set"), arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -3265,8 +3178,7 @@ static int CmdHF14ADesGetKeySettings(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 12, &securechann, DCMMACed, &appid, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMMACed, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -3344,7 +3256,7 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, &securechann, DCMMACed, NULL, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, &securechann, DCMMACed, NULL, NULL); if (res) { CLIParserFree(ctx); return res; @@ -3370,15 +3282,11 @@ static int CmdHF14ADesGetAIDs(const char *Cmd) { } if (buflen >= 3) { - - uint8_t j = (buflen / 3); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "--- " _CYAN_("AID list") " ( " _YELLOW_("%u") " found )", j); + PrintAndLogEx(INFO, "---- " _CYAN_("AID list") " ----"); for (int i = 0; i < buflen; i += 3) { uint32_t aid = DesfireAIDByteToUint(&buf[i]); PrintAndLogEx(SUCCESS, _YELLOW_("%06X") " %s", aid, getAidCommentStr(aid)); } - PrintAndLogEx(NORMAL, ""); } else { PrintAndLogEx(INFO, "There is no applications on the card"); } @@ -3416,7 +3324,7 @@ static int CmdHF14ADesGetAppNames(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0, &securechann, DCMMACed, NULL, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, &securechann, DCMMACed, NULL, NULL); if (res) { CLIParserFree(ctx); return res; @@ -3463,8 +3371,7 @@ static int CmdHF14ADesGetFileIDs(const char *Cmd) { CLIParserInit(&ctx, "hf mfdes getfileids", "Get File IDs list from card. Master key needs to be provided or flag --no-auth set.", "hf mfdes getfileids --aid 123456 -> execute with defaults from `default` command\n" - "hf mfdes getfileids -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 -> execute with default factory setup\n" - "hf mfdes getfileids --dfname D2760000850100 -> select DF by name and get file IDs"); + "hf mfdes getfileids -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 -> execute with default factory setup"); void *argtable[] = { arg_param_begin, @@ -3480,7 +3387,6 @@ static int CmdHF14ADesGetFileIDs(const char *Cmd) { arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)."), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_lit0(NULL, "no-auth", "Execute without authentication"), arg_param_end }; @@ -3488,13 +3394,13 @@ static int CmdHF14ADesGetFileIDs(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 14); + bool noauth = arg_get_lit(ctx, 13); DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -3510,7 +3416,6 @@ static int CmdHF14ADesGetFileIDs(const char *Cmd) { return res; } - uint8_t buf[APDU_RES_LEN] = {0}; size_t buflen = 0; @@ -3526,7 +3431,7 @@ static int CmdHF14ADesGetFileIDs(const char *Cmd) { for (int i = 0; i < buflen; i++) PrintAndLogEx(INFO, "File ID: %02x", buf[i]); } else { - PrintAndLogEx(INFO, "There are no files in the application %06x", id); + PrintAndLogEx(INFO, "There is no files in the application %06x", id); } DropField(); @@ -3540,8 +3445,7 @@ static int CmdHF14ADesGetFileISOIDs(const char *Cmd) { "hf mfdes getfileisoids --aid 123456 -> execute with defaults from `default` command\n" "hf mfdes getfileisoids -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 -> execute with default factory setup\n" "hf mfdes getfileisoids --isoid df01 -> get iso file ids from Desfire Light with factory card settings\n" - "hf mfdes getfileisoids --isoid df01 --schann lrp -t aes -> get iso file ids from Desfire Light via lrp channel with default key authentication\n" - "hf mfdes getfileisoids --dfname D2760000850100 -> select DF by name and get file ISO IDs"); + "hf mfdes getfileisoids --isoid df01 --schann lrp -t aes -> get iso file ids from Desfire Light via lrp channel with default key authentication"); void *argtable[] = { arg_param_begin, @@ -3557,7 +3461,6 @@ static int CmdHF14ADesGetFileISOIDs(const char *Cmd) { arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)."), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_lit0(NULL, "no-auth", "Execute without authentication"), arg_param_end }; @@ -3565,13 +3468,13 @@ static int CmdHF14ADesGetFileISOIDs(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 14); + bool noauth = arg_get_lit(ctx, 13); DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -3602,7 +3505,7 @@ static int CmdHF14ADesGetFileISOIDs(const char *Cmd) { for (int i = 0; i < buflen; i += 2) PrintAndLogEx(INFO, "File ID: %04x", MemLeToUint2byte(&buf[i])); } else { - PrintAndLogEx(INFO, "There are no files in the application %06x", id); + PrintAndLogEx(INFO, "There is no files in the application %06x", id); } DropField(); @@ -3615,8 +3518,7 @@ static int CmdHF14ADesGetFileSettings(const char *Cmd) { "Get File Settings from file from application. Master key needs to be provided or flag --no-auth set (depend on cards settings).", "hf mfdes getfilesettings --aid 123456 --fid 01 -> execute with defaults from `default` command\n" "hf mfdes getfilesettings --isoid df01 --fid 00 --no-auth -> get file settings with select by iso id\n" - "hf mfdes getfilesettings -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 --fid 01 -> execute with default factory setup\n" - "hf mfdes getfilesettings --dfname D2760000850100 --fid 01 -> select DF by name and get file settings"); + "hf mfdes getfilesettings -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 --fid 01 -> execute with default factory setup"); void *argtable[] = { arg_param_begin, @@ -3632,7 +3534,6 @@ static int CmdHF14ADesGetFileSettings(const char *Cmd) { arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)"), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_str0(NULL, "fid", "", "File ID (1 hex byte). (def: 1)"), arg_lit0(NULL, "no-auth", "Execute without authentication"), arg_param_end @@ -3641,20 +3542,20 @@ static int CmdHF14ADesGetFileSettings(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 15); + bool noauth = arg_get_lit(ctx, 14); DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } uint32_t fileid = 1; - if (CLIGetUint32Hex(ctx, 14, 1, &fileid, NULL, 1, "File ID must have 1 byte length")) { + if (CLIGetUint32Hex(ctx, 13, 1, &fileid, NULL, 1, "File ID must have 1 byte length")) { CLIParserFree(ctx); return PM3_EINVARG; } @@ -3679,9 +3580,8 @@ static int CmdHF14ADesGetFileSettings(const char *Cmd) { return PM3_ESOFT; } - if (verbose) { + if (verbose) PrintAndLogEx(INFO, "%s file %02x settings[%zu]: %s", DesfireWayIDStr(selectway, id), fileid, buflen, sprint_hex(buf, buflen)); - } DesfirePrintFileSettings(buf, buflen); @@ -3824,7 +3724,7 @@ static int CmdHF14ADesChFileSettings(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, &securechann, DCMEncrypted, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMEncrypted, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -3971,7 +3871,7 @@ static int CmdHF14ADesCreateFile(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, &securechann, DCMMACed, &appid, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMMACed, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -4075,7 +3975,7 @@ static int CmdHF14ADesCreateValueFile(const char *Cmd) { arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("v", "verbose", "Verbose output"), arg_int0("n", "keyno", "", "Key number"), - arg_str0("t", "algo", "", "Crypt algo (deft: 2TDEA)"), + arg_str0("t", "algo", "", "Crypt algo"), arg_str0("k", "key", "", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0(NULL, "kdf", "", "Key Derivation Function (KDF)"), arg_str0("i", "kdfi", "", "KDF input (1-31 hex bytes)"), @@ -4108,7 +4008,7 @@ static int CmdHF14ADesCreateValueFile(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, &securechann, DCMMACed, &appid, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMMACed, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -4235,7 +4135,7 @@ static int CmdHF14ADesCreateRecordFile(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t appid = 0x000000; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, 0, &securechann, DCMMACed, &appid, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 0, &securechann, DCMMACed, &appid, NULL); if (res) { CLIParserFree(ctx); return res; @@ -4353,7 +4253,7 @@ static int CmdHF14ADesCreateTrMACFile(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, &securechann, DCMEncrypted, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMEncrypted, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -4460,7 +4360,7 @@ static int CmdHF14ADesDeleteFile(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -4515,7 +4415,7 @@ static int CmdHF14ADesValueOperations(const char *Cmd) { arg_lit0("a", "apdu", "Show APDU requests and responses"), arg_lit0("v", "verbose", "Verbose output"), arg_int0("n", "keyno", "", "Key number"), - arg_str0("t", "algo", "", "Crypt algo (deft: 2TDEA)"), + arg_str0("t", "algo", "", "Crypt algo"), arg_str0("k", "key", "", "Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)"), arg_str0(NULL, "kdf", "", "Key Derivation Function (KDF)"), arg_str0("i", "kdfi", "", "KDF input (1-31 hex bytes)"), @@ -4540,7 +4440,7 @@ static int CmdHF14ADesValueOperations(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -4710,7 +4610,7 @@ static int CmdHF14ADesClearRecordFile(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 0, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -5120,7 +5020,7 @@ static int CmdHF14ADesReadData(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 17, 0, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 17, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -5295,7 +5195,7 @@ static int CmdHF14ADesWriteData(const char *Cmd) { int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20, 0, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -5595,8 +5495,7 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { "This commands List files inside application AID / ISOID.\n" "Master key needs to be provided or flag --no-auth set (depend on cards settings).", "hf mfdes lsfiles --aid 123456 -> AID 123456, list files using `default` command creds\n" - "hf mfdes lsfiles --isoid df01 --no-auth -> list files for DESFire light\n" - "hf mfdes lsfiles --dfname D2760000850100 -> select DF by name and list files"); + "hf mfdes lsfiles --isoid df01 --no-auth -> list files for DESFire light"); void *argtable[] = { arg_param_begin, @@ -5612,7 +5511,6 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)"), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_lit0(NULL, "no-auth", "Execute without authentication"), arg_param_end }; @@ -5620,13 +5518,13 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 14); + bool noauth = arg_get_lit(ctx, 13); DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, &securechann, DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; @@ -5652,9 +5550,9 @@ static int CmdHF14ADesLsFiles(const char *Cmd) { } if (filescount == 0) { - PrintAndLogEx(INFO, "There are no files in the %s", DesfireWayIDStr(selectway, id)); + PrintAndLogEx(INFO, "There is no files in the %s", DesfireWayIDStr(selectway, id)); DropField(); - return PM3_SUCCESS; + return res; } PrintAndLogEx(INFO, "------------------------------------------ " _CYAN_("File list") " -----------------------------------------------------"); @@ -5670,8 +5568,7 @@ static int CmdHF14ADesLsApp(const char *Cmd) { CLIParserInit(&ctx, "hf mfdes lsapp", "Show application list. Master key needs to be provided or flag --no-auth set (depend on cards settings).", "hf mfdes lsapp -> show application list with defaults from `default` command\n" - "hf mfdes lsapp --files -> show application list and show each file type/settings/etc\n" - "hf mfdes lsapp --dfname D2760000850100 -> list apps after selecting DF by name"); + "hf mfdes lsapp --files -> show application list and show each file type/settings/etc"); void *argtable[] = { arg_param_begin, @@ -5688,7 +5585,6 @@ static int CmdHF14ADesLsApp(const char *Cmd) { arg_lit0(NULL, "no-auth", "Execute without authentication"), arg_lit0(NULL, "no-deep", "not to check authentication commands that avail for any application"), arg_lit0(NULL, "files", "scan files and print file settings"), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -5701,7 +5597,7 @@ static int CmdHF14ADesLsApp(const char *Cmd) { DesfireContext_t dctx; int securechann = defaultSecureChannel; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 14, &securechann, (noauth) ? DCMPlain : DCMMACed, NULL, NULL); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, &securechann, (noauth) ? DCMPlain : DCMMACed, NULL, NULL); if (res) { CLIParserFree(ctx); return res; @@ -5753,7 +5649,6 @@ static int CmdHF14ADesDump(const char *Cmd) { arg_str0(NULL, "schann", "", "Secure channel"), arg_str0(NULL, "aid", "", "Application ID (3 hex bytes, big endian)"), arg_str0(NULL, "isoid", "", "Application ISO ID (ISO DF ID) (2 hex bytes, big endian)"), - arg_str0(NULL, "dfname", "", "Application ISO DF Name (5-16 hex bytes, big endian)"), arg_str0("l", "length", "", "Maximum length for read data files (3 hex bytes, big endian)"), arg_lit0(NULL, "no-auth", "Execute without authentication"), arg_param_end @@ -5762,20 +5657,20 @@ static int CmdHF14ADesDump(const char *Cmd) { bool APDULogging = arg_get_lit(ctx, 1); bool verbose = arg_get_lit(ctx, 2); - bool noauth = arg_get_lit(ctx, 15); + bool noauth = arg_get_lit(ctx, 14); DesfireContext_t dctx; int securechann = defaultSecureChannel; uint32_t id = 0x000000; DesfireISOSelectWay selectway = ISW6bAID; - int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, &securechann, (noauth) ? DCMPlain : DCMMACed, &id, &selectway); + int res = CmdDesGetSessionParameters(ctx, &dctx, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &securechann, (noauth) ? DCMPlain : DCMMACed, &id, &selectway); if (res) { CLIParserFree(ctx); return res; } uint32_t maxlength = 0; - if (CLIGetUint32Hex(ctx, 14, 0, &maxlength, NULL, 3, "Length parameter must have 3 byte length")) { + if (CLIGetUint32Hex(ctx, 13, 0, &maxlength, NULL, 3, "Length parameter must have 3 byte length")) { CLIParserFree(ctx); return PM3_EINVARG; } @@ -5886,7 +5781,6 @@ static command_t CommandTable[] = { {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("Files") " -----------------------"}, {"getfileids", CmdHF14ADesGetFileIDs, IfPm3Iso14443a, "Get File IDs list"}, {"getfileisoids", CmdHF14ADesGetFileISOIDs, IfPm3Iso14443a, "Get File ISO IDs list"}, - {"lsfile", CmdHF14ADesLsFiles, IfPm3Iso14443a, "Show all files list"}, {"lsfiles", CmdHF14ADesLsFiles, IfPm3Iso14443a, "Show all files list"}, {"dump", CmdHF14ADesDump, IfPm3Iso14443a, "Dump all files"}, {"createfile", CmdHF14ADesCreateFile, IfPm3Iso14443a, "Create Standard/Backup File"}, diff --git a/client/src/cmdhfmfdes.h b/client/src/cmdhfmfdes.h index 0eddcf6cf..80b3e8c93 100644 --- a/client/src/cmdhfmfdes.h +++ b/client/src/cmdhfmfdes.h @@ -20,44 +20,6 @@ #include "common.h" -// Ev1 card limits -#define MAX_NUM_KEYS 0x0F -#define MAX_APPLICATION_COUNT 28 -#define MAX_FILE_COUNT 32 -#define MAX_FRAME_SIZE 60 -#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) - -// Ev2 card limits -// Ev3 card limits -// Light card limits -// Light Ev1 card limits - -#define NOT_YET_AUTHENTICATED 0xFF - -typedef enum { - NXP_UNKNOWN = 0, - DESFIRE_MF3ICD40, - DESFIRE_EV1, - DESFIRE_EV2, - DESFIRE_EV2_XL, - DESFIRE_EV3, - DESFIRE_LIGHT, - PLUS_EV1, - PLUS_EV2, - NTAG413DNA, - NTAG424, - DUOX, -} nxp_cardtype_t; - -typedef struct { - uint8_t isOK; - uint8_t uid[7]; - uint8_t uidlen; - uint8_t versionHW[7]; - uint8_t versionSW[7]; - uint8_t details[14]; -} PACKED mfdes_info_res_t; - int CmdHFMFDes(const char *Cmd); /* @@ -67,7 +29,24 @@ int getKeySettings(uint8_t *aid); */ int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, size_t signature_len); -nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor); -int mfdes_get_info(mfdes_info_res_t *info); + +// Ev1 card limits +#define MAX_NUM_KEYS 0x0F +#define MAX_APPLICATION_COUNT 28 +#define MAX_FILE_COUNT 32 +#define MAX_FRAME_SIZE 60 +#define FRAME_PAYLOAD_SIZE (MAX_FRAME_SIZE - 5) + +// Ev2 card limits + +// Ev3 card limits + +// Light card limits + +// Light Ev1 card limits + +#define NOT_YET_AUTHENTICATED 0xFF + + #endif diff --git a/client/src/cmdhfmfhard.c b/client/src/cmdhfmfhard.c index 885162437..8381a4c8d 100644 --- a/client/src/cmdhfmfhard.c +++ b/client/src/cmdhfmfhard.c @@ -127,6 +127,7 @@ static void print_progress_header(void) { get_SIMD_instruction_set(instr_set); snprintf(progress_text, sizeof(progress_text), "Start using " _YELLOW_("%d") " threads and " _YELLOW_("%s") " SIMD core", num_CPUs(), instr_set); + PrintAndLogEx(INFO, "Hardnested attack starting..."); PrintAndLogEx(INFO, "---------+---------+---------------------------------------------------------+-----------------+-------"); PrintAndLogEx(INFO, " | | | Expected to brute force"); PrintAndLogEx(INFO, " Time | #nonces | Activity | #states | time "); @@ -135,16 +136,12 @@ static void print_progress_header(void) { } void hardnested_print_progress(uint32_t nonces, const char *activity, float brute_force, uint64_t min_diff_print_time) { - static uint64_t last_print_time = 0; - if (msclock() - last_print_time >= min_diff_print_time) { - last_print_time = msclock(); uint64_t total_time = msclock() - start_time; float brute_force_time = brute_force / brute_force_per_second; char brute_force_time_string[20]; - if (brute_force_time < 90) { snprintf(brute_force_time_string, sizeof(brute_force_time_string), "%2.0fs", brute_force_time); } else if (brute_force_time < 60 * 90) { @@ -154,24 +151,7 @@ void hardnested_print_progress(uint32_t nonces, const char *activity, float brut } else { snprintf(brute_force_time_string, sizeof(brute_force_time_string), "%2.0fd", brute_force_time / (60 * 60 * 24)); } - - if (strlen(activity) > 67) { - PrintAndLogEx(INFO, " %7.0f | %7u | %-82s | %15.0f | %5s" - , (float)total_time / 1000.0 - , nonces - , activity - , brute_force - , brute_force_time_string - ); - } else { - PrintAndLogEx(INFO, " %7.0f | %7u | %-55s | %15.0f | %5s" - , (float)total_time / 1000.0 - , nonces - , activity - , brute_force - , brute_force_time_string - ); - } + PrintAndLogEx(INFO, " %7.0f | %7u | %-55s | %15.0f | %5s", (float)total_time / 1000.0, nonces, activity, brute_force, brute_force_time_string); } } @@ -506,14 +486,8 @@ static void init_bitflip_bitarrays(void) { effective_bitflip[odd_even][num_effective_bitflips[odd_even]] = 0x400; // EndOfList marker } { - char progress_text[100]; - memset(progress_text, 0, sizeof(progress_text)); - snprintf(progress_text, sizeof(progress_text), "Loaded " _YELLOW_("%u") " RAW / " _YELLOW_("%u") " LZ4 / " _YELLOW_("%u") " BZ2 in %4"PRIu64" ms" - , nraw - , nlz4 - , nbz2 - , msclock() - init_bitflip_bitarrays_starttime - ); + char progress_text[80]; + snprintf(progress_text, sizeof(progress_text), "Loaded %u RAW / %u LZ4 / %u BZ2 in %"PRIu64" ms", nraw, nlz4, nbz2, msclock() - init_bitflip_bitarrays_starttime); hardnested_print_progress(0, progress_text, (float)(1LL << 47), 0); } uint16_t i = 0; @@ -2507,10 +2481,8 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc free_candidates_memory(candidates); candidates = NULL; } else { - pre_XOR_nonces(); prepare_bf_test_nonces(nonces, best_first_bytes[0]); - for (uint8_t j = 0; j < NUM_SUMS && !key_found; j++) { float expected_brute_force = nonces[best_first_bytes[0]].expected_num_brute_force; snprintf(progress_text, sizeof(progress_text), "(%d. guess: Sum(a8) = %" PRIu16 ")", j + 1, sums[nonces[best_first_bytes[0]].sum_a8_guess[j].sum_a8_idx]); @@ -2572,9 +2544,7 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc int res; if (nonce_file_read) { // use pre-acquired data from file nonces.bin - res = read_nonce_file(filename); - if (res != PM3_SUCCESS) { free_bitflip_bitarrays(); free_nonces_memory(); @@ -2584,16 +2554,12 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc free_part_sum_bitarrays(); return res; } - hardnested_stage = CHECK_1ST_BYTES | CHECK_2ND_BYTES; update_nonce_data(false); float brute_force_depth; shrink_key_space(&brute_force_depth); - } else { // acquire nonces. - res = acquire_nonces(blockNo, keyType, key, trgBlockNo, trgKeyType, nonce_file_write, slow, filename); - if (res != PM3_SUCCESS) { free_bitflip_bitarrays(); free_nonces_memory(); diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index 6433bcf2e..8437d72da 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -17,7 +17,6 @@ //----------------------------------------------------------------------------- #include "cmdhfmfp.h" -#include "cmdhfmfdes.h" #include #include "cmdparser.h" // command_t #include "commonutil.h" // ARRAYLEN @@ -42,7 +41,6 @@ static const uint8_t mfp_default_key[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, static uint16_t mfp_card_adresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0x9006, 0x9007, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; #define MFP_KEY_FILE_SIZE 14 + (2 * 64 * (AES_KEY_LEN + 1)) -#define MFP_CHK_KEY_TRIES (2) static int CmdHelp(const char *Cmd); @@ -143,6 +141,54 @@ static char *getTypeStr(uint8_t type) { return buf; } +static nxp_cardtype_t getCardType(uint8_t type, uint8_t major, uint8_t minor) { + + // DESFire MF3ICD40 + if (type == 0x01 && major == 0x00 && minor == 0x02) + return DESFIRE_MF3ICD40; + + // DESFire EV1 + if (type == 0x01 && major == 0x01 && minor == 0x00) + return DESFIRE_EV1; + + // DESFire EV2 + if (type == 0x01 && major == 0x12 && minor == 0x00) + return DESFIRE_EV2; + + if (type == 0x01 && major == 0x22 && minor == 0x00) + return DESFIRE_EV2_XL; + + // DESFire EV3 + if (type == 0x01 && major == 0x33 && minor == 0x00) + return DESFIRE_EV3; + + // DESFire Light + if (type == 0x08 && major == 0x30 && minor == 0x00) + return DESFIRE_LIGHT; + + // combo card DESFire / EMV + if (type == 0x81 && major == 0x42 && minor == 0x00) + return DESFIRE_EV2; + + // Plus EV1 + if (type == 0x02 && major == 0x11 && minor == 0x00) + return PLUS_EV1; + + // Plus Ev2 + if (type == 0x02 && major == 0x22 && minor == 0x00) + return PLUS_EV2; + + // NTAG 413 DNA + if (type == 0x04 && major == 0x10 && minor == 0x00) + return NTAG413DNA; + + // NTAG 424 + if (type == 0x04 && major == 0x30 && minor == 0x00) + return NTAG424; + + return MFP_UNKNOWN; +} + // --- GET SIGNATURE static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, int signature_len) { int index = originality_check_verify(uid, uidlen, signature, signature_len, PK_MFP); @@ -213,153 +259,6 @@ static int get_plus_version(uint8_t *version, int *version_len) { return retval; } -static int mfp_read_card_id(iso14a_card_select_t *card, int *nxptype) { - - if (card == NULL) { - return PM3_EINVARG; - } - - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { - PrintAndLogEx(DEBUG, "iso14443a card select failed"); - DropField(); - return PM3_ERFTRANS; - } - - memcpy(card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - - if (nxptype) { - uint64_t select_status = resp.oldarg[0]; - - uint8_t ats_hist_pos = 0; - if ((card->ats_len > 3) && (card->ats[0] > 1)) { - ats_hist_pos = 2; - ats_hist_pos += (card->ats[1] & 0x10) == 0x10; - ats_hist_pos += (card->ats[1] & 0x20) == 0x20; - ats_hist_pos += (card->ats[1] & 0x40) == 0x40; - } - - version_hw_t version_hw = {0}; - // if 4b UID or NXP, try to get version - int res = hf14a_getversion_data(card, select_status, &version_hw); - DropField(); - - bool version_hw_available = (res == PM3_SUCCESS); - - *nxptype = detect_nxp_card(card->sak - , ((card->atqa[1] << 8) + card->atqa[0]) - , select_status - , card->ats_len - ats_hist_pos - , card->ats + ats_hist_pos - , version_hw_available - , &version_hw - ); - } - return PM3_SUCCESS; -} - -static int mfp_load_keygen_keys(uint8_t **pkeyBlock, uint32_t *pkeycnt, uint8_t *uid) { - - // Handle dymanica keys - - return PM3_SUCCESS; -} - -static int mfp_load_keys(uint8_t **pkeyBlock, uint32_t *pkeycnt, uint8_t *userkey, int userkeylen, const char *filename, int fnlen, uint8_t *uid, bool load_default) { - // Handle Keys - *pkeycnt = 0; - *pkeyBlock = NULL; - uint8_t *p; - - // Handle KDF uid based keys - if (uid) { - mfp_load_keygen_keys(pkeyBlock, pkeycnt, uid); - } - - // Handle user supplied key - // (it considers *pkeycnt and *pkeyBlock as possibly non-null so logic can be easily reordered) - if (userkeylen >= AES_KEY_LEN) { - int numKeys = userkeylen / AES_KEY_LEN; - p = realloc(*pkeyBlock, (*pkeycnt + numKeys) * AES_KEY_LEN); - if (p == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); - free(*pkeyBlock); - return PM3_EMALLOC; - } - *pkeyBlock = p; - - memcpy(*pkeyBlock, userkey, numKeys * AES_KEY_LEN); - - for (int i = 0; i < numKeys; i++) { - PrintAndLogEx(DEBUG, _YELLOW_("%2d") " - %s", i, sprint_hex_inrow(*pkeyBlock + i * AES_KEY_LEN, AES_KEY_LEN)); - } - *pkeycnt += numKeys; - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%d") " user keys", numKeys); - } - - if (load_default) { - // Handle default keys - p = realloc(*pkeyBlock, (*pkeycnt + g_mifare_plus_default_keys_len) * AES_KEY_LEN); - if (p == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); - free(*pkeyBlock); - return PM3_EMALLOC; - } - *pkeyBlock = p; - - // Copy default keys to list - size_t cnt = 0; - for (cnt = 0; cnt < g_mifare_plus_default_keys_len; cnt++) { - - int len = hex_to_bytes(g_mifare_plus_default_keys[cnt], (uint8_t *)(*pkeyBlock + (*pkeycnt + cnt) * AES_KEY_LEN), AES_KEY_LEN); - - PrintAndLogEx(DEBUG, _YELLOW_("%2u") " - %s", *pkeycnt + cnt, sprint_hex_inrow(*pkeyBlock + (*pkeycnt + cnt) * AES_KEY_LEN, AES_KEY_LEN)); - if (len != AES_KEY_LEN) { - break; - } - } - *pkeycnt += cnt; - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%zu") " hardcoded keys", cnt); - } - - // Handle user supplied dictionary file - if (fnlen > 0) { - - uint32_t loaded_numKeys = 0; - uint8_t *dict_keys = NULL; - - int res = loadFileDICTIONARY_safe(filename, (void **) &dict_keys, AES_KEY_LEN, &loaded_numKeys); - - if (res != PM3_SUCCESS || loaded_numKeys == 0 || dict_keys == NULL) { - PrintAndLogEx(FAILED, "An error occurred while loading the dictionary!"); - free(dict_keys); - free(*pkeyBlock); - return PM3_EFILE; - - } else { - - p = realloc(*pkeyBlock, (*pkeycnt + loaded_numKeys) * AES_KEY_LEN); - if (p == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); - free(dict_keys); - free(*pkeyBlock); - return PM3_EMALLOC; - } - *pkeyBlock = p; - - memcpy(*pkeyBlock + *pkeycnt * AES_KEY_LEN, dict_keys, loaded_numKeys * AES_KEY_LEN); - - *pkeycnt += loaded_numKeys; - - free(dict_keys); - } - } - return PM3_SUCCESS; -} - - static int CmdHFMFPInfo(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfp info", @@ -676,8 +575,7 @@ static int CmdHFMFPInitPerso(const char *Cmd) { CLIParserInit(&ctx, "hf mfp initp", "Executes Write Perso command for all card's keys. Can be used in SL0 mode only.", "hf mfp initp --key 000102030405060708090a0b0c0d0e0f -> fill all the keys with key (00..0f)\n" - "hf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange" - ); + "hf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange"); void *argtable[] = { arg_param_begin, @@ -802,14 +700,13 @@ static int CmdHFMFPAuth(const char *Cmd) { CLIParserInit(&ctx, "hf mfp auth", "Executes AES authentication command for MIFARE Plus card", "hf mfp auth --ki 4000 --key 000102030405060708090a0b0c0d0e0f -> executes authentication\n" - "hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data" - ); + "hf mfp auth --ki 9003 --key FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data"); void *argtable[] = { arg_param_begin, arg_lit0("v", "verbose", "Verbose output"), arg_str1(NULL, "ki", "", "Key number, 2 hex bytes"), - arg_str1("k", "key", "", "Key, 16 hex bytes"), + arg_str1(NULL, "key", "", "Key, 16 hex bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -831,54 +728,35 @@ static int CmdHFMFPAuth(const char *Cmd) { return MifareAuth4(NULL, keyn, key, true, false, true, verbose, false); } - -int mfp_data_crypt(mf4Session_t *mf4session, uint8_t *dati, uint8_t *dato, bool rev) { - uint8_t kenc[MFBLOCK_SIZE]; - memcpy(kenc, mf4session->Kenc, MFBLOCK_SIZE); - +static int data_crypt(mf4Session_t *mf4session, uint8_t *dati, uint8_t *dato, bool rev) { + uint8_t kenc[16]; + memcpy(kenc, mf4session->Kenc, 16); uint8_t ti[4]; memcpy(ti, mf4session->TI, 4); - uint8_t ctr[1]; - uint8_t IV[MFBLOCK_SIZE] = { 0 }; - + uint8_t IV[16] = {0, 0, 0x00, 0x00, 0x00, 0, 0x00, 0x00, 0x00, 0}; if (rev) { - - ctr[0] = (uint8_t)(mf4session->R_Ctr & 0xFF); - - for (int i = 0; i < 9; i += 4) { - memcpy(&IV[i], ctr, 1); - } - + ctr[0] = (uint8_t)(mf4session->R_Ctr & 0xff); + for (int i = 0; i < 9; i += 4) {memcpy(&IV[i], ctr, 1);} memcpy(&IV[12], ti, 4); // For reads TI is LS - } else { - - ctr[0] = (uint8_t)(mf4session->W_Ctr & 0xFF); - - for (int i = 3; i < MFBLOCK_SIZE; i += 4) { - memcpy(&IV[i], ctr, 1); - } - + ctr[0] = (uint8_t)(mf4session->W_Ctr & 0xff); + for (int i = 3; i < 16; i += 4) {memcpy(&IV[i], ctr, 1);} memcpy(&IV[0], ti, 4); // For writes TI is MS } - if (rev) { - aes_decode(IV, kenc, dati, dato, MFBLOCK_SIZE); + aes_decode(IV, kenc, dati, dato, 16); } else { - aes_encode(IV, kenc, dati, dato, MFBLOCK_SIZE); + aes_encode(IV, kenc, dati, dato, 16); } - - return PM3_SUCCESS; + return 0; } - static int CmdHFMFPRdbl(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfp rdbl", "Reads blocks from MIFARE Plus card", "hf mfp rdbl --blk 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n" - "hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF" - ); + "hf mfp rdbl --blk 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF"); void *argtable[] = { arg_param_begin, @@ -910,7 +788,7 @@ static int CmdHFMFPRdbl(const char *Cmd) { mfpSetVerboseMode(verbose); - if (keylen == 0) { + if (!keylen) { memmove(key, mfp_default_key, 16); keylen = 16; } @@ -939,9 +817,8 @@ static int CmdHFMFPRdbl(const char *Cmd) { uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0); keyn[0] = uKeyNum >> 8; keyn[1] = uKeyNum & 0xff; - if (verbose) { + if (verbose) PrintAndLogEx(INFO, "--block:%d sector[%u]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); - } mf4Session_t mf4session; int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); @@ -969,10 +846,7 @@ static int CmdHFMFPRdbl(const char *Cmd) { return PM3_ESOFT; } - if (plain == false) { - mfp_data_crypt(&mf4session, &data[1], &data[1], true); - } - + if (!plain) data_crypt(&mf4session, &data[1], &data[1], true); uint8_t sector = mfSectorNum(blockn); mf_print_sector_hdr(sector); @@ -1000,8 +874,7 @@ static int CmdHFMFPRdsc(const char *Cmd) { CLIParserInit(&ctx, "hf mfp rdsc", "Reads one sector from MIFARE Plus card", "hf mfp rdsc -s 0 --key 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data\n" - "hf mfp rdsc -s 1 -v -> executes authentication and shows sector 1 data with default key" - ); + "hf mfp rdsc -s 1 -v -> executes authentication and shows sector 1 data with default key"); void *argtable[] = { arg_param_begin, @@ -1030,7 +903,7 @@ static int CmdHFMFPRdsc(const char *Cmd) { mfpSetVerboseMode(verbose); - if (keylen == 0) { + if (!keylen) { memmove(key, mfp_default_key, 16); keylen = 16; } @@ -1048,9 +921,8 @@ static int CmdHFMFPRdsc(const char *Cmd) { uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0); keyn[0] = uKeyNum >> 8; keyn[1] = uKeyNum & 0xff; - if (verbose) { + if (verbose) PrintAndLogEx(INFO, "--sector[%u]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); - } mf4Session_t mf4session; int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); @@ -1085,11 +957,7 @@ static int CmdHFMFPRdsc(const char *Cmd) { DropField(); return PM3_ESOFT; } - - if (plain == false) { - mfp_data_crypt(&mf4session, &data[1], &data[1], true); - } - + if (!plain) data_crypt(&mf4session, &data[1], &data[1], true); mf_print_block_one(blockno, data + 1, verbose); if (memcmp(&data[1 + 16], mac, 8) && !nomacres) { @@ -1171,9 +1039,8 @@ static int CmdHFMFPWrbl(const char *Cmd) { uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0); keyn[0] = uKeyNum >> 8; keyn[1] = uKeyNum & 0xff; - if (verbose) { + if (verbose) PrintAndLogEx(INFO, "--block:%d sector[%u]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); - } mf4Session_t mf4session; int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); @@ -1181,11 +1048,7 @@ static int CmdHFMFPWrbl(const char *Cmd) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; } - - if (plain == false) { - mfp_data_crypt(&mf4session, &datain[0], &datain[0], false); - } - + if (!plain) data_crypt(&mf4session, &datain[0], &datain[0], false); uint8_t data[250] = {0}; int datalen = 0; uint8_t mac[8] = {0}; @@ -1279,35 +1142,24 @@ static int CmdHFMFPChKey(const char *Cmd) { PrintAndLogEx(ERR, " must be 16 bytes. Got %d", datainlen); return PM3_EINVARG; } - mf4Session_t mf4session; - keyn[0] = ki[0]; - if (ki[0] == 0x40) { // Only if we are working with sector keys - if (usekeyb) { keyn[1] = (ki[1] % 2 == 0) ? ki[1] + 1 : ki[1]; // If we change using key B, check if KI is key A } else { keyn[1] = (ki[1] % 2 == 0) ? ki[1] : ki[1] - 1; // If we change using key A, check if KI is key A } - - } else { - keyn[1] = ki[1]; - } - + } else {keyn[1] = ki[1];} if (verbose) { PrintAndLogEx(INFO, "--key index:", sprint_hex(keyn, 2)); } - int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; } - - mfp_data_crypt(&mf4session, &datain[0], &datain[0], false); - + data_crypt(&mf4session, &datain[0], &datain[0], false); uint8_t data[250] = {0}; int datalen = 0; uint8_t mac[8] = {0}; @@ -1335,9 +1187,8 @@ static int CmdHFMFPChKey(const char *Cmd) { PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[1], 8)); PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8)); } else if (!nomacres) { - if (verbose) { + if (verbose) PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[1], 8)); - } } DropField(); @@ -1390,7 +1241,7 @@ static int CmdHFMFPChConf(const char *Cmd) { mfpSetVerboseMode(verbose); - if (keylen == 0) { + if (!keylen) { memmove(key, mfp_default_key, 16); keylen = 16; } @@ -1409,23 +1260,18 @@ static int CmdHFMFPChConf(const char *Cmd) { PrintAndLogEx(ERR, " must be in range [0..3]. Got %d", blockNum); return PM3_EINVARG; } - mf4Session_t mf4session; keyn[0] = 0x90; keyn[1] = usecck ? 0x01 : 0x00; - if (verbose) { PrintAndLogEx(INFO, "--key index:", sprint_hex(keyn, 2)); } - int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; } - - mfp_data_crypt(&mf4session, &datain[0], &datain[0], false); - + data_crypt(&mf4session, &datain[0], &datain[0], false); uint8_t data[250] = {0}; int datalen = 0; uint8_t mac[8] = {0}; @@ -1452,10 +1298,9 @@ static int CmdHFMFPChConf(const char *Cmd) { PrintAndLogEx(WARNING, "WARNING: mac not equal..."); PrintAndLogEx(WARNING, "MAC card: %s", sprint_hex(&data[1], 8)); PrintAndLogEx(WARNING, "MAC reader: %s", sprint_hex(mac, 8)); - } else if (nomacres == false) { - if (verbose) { + } else if (!nomacres) { + if (verbose) PrintAndLogEx(INFO, "MAC: %s", sprint_hex(&data[1], 8)); - } } DropField(); @@ -1463,33 +1308,19 @@ static int CmdHFMFPChConf(const char *Cmd) { return PM3_SUCCESS; } -static int plus_key_check(uint8_t start_sector, uint8_t end_sector, uint8_t startKeyAB, uint8_t endKeyAB, - uint8_t *keys, size_t keycount, uint8_t foundKeys[2][64][AES_KEY_LEN + 1], - bool verbose, bool newline) { - - if (newline) { - PrintAndLogEx(INFO, "." NOLF); - } +static int plus_key_check(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, + uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1], + bool verbose) { + int res; + bool selectCard = true; + uint8_t keyn[2] = {0}; // sector number from 0 - for (uint8_t sector = start_sector; sector <= end_sector; sector++) { - + for (uint8_t sector = startSector; sector <= endSector; sector++) { // 0-keyA 1-keyB for (uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { - - // skip already found keys - if (foundKeys[keyAB][sector][0]) { - continue; - } - - int res; - bool selectCard = true; - - // reset current key pointer after each loop - uint8_t *currkey = keys; - // main cycle with key check - for (int i = 0; i < keycount; i++) { + for (int i = 0; i < keyListLen; i++) { // allow client abort every iteration if (kbd_enter_pressed()) { @@ -1505,21 +1336,18 @@ static int plus_key_check(uint8_t start_sector, uint8_t end_sector, uint8_t star } uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; - uint8_t keyn[2] = { uKeyNum >> 8, uKeyNum & 0xff}; + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; - // authentication loop with retries - for (int retry = 0; retry < MFP_CHK_KEY_TRIES; retry++) { - - res = MifareAuth4(NULL, keyn, currkey, selectCard, true, false, false, true); - if (res == PM3_SUCCESS || res == PM3_EWRONGANSWER) { + for (int retry = 0; retry < 4; retry++) { + res = MifareAuth4(NULL, keyn, keyList[i], selectCard, true, false, false, true); + if (res == PM3_SUCCESS || res == PM3_EWRONGANSWER) break; - } - if (verbose) { + if (verbose) PrintAndLogEx(WARNING, "\nretried[%d]...", retry); - } else { + else PrintAndLogEx(NORMAL, "R" NOLF); - } DropField(); selectCard = true; @@ -1528,52 +1356,38 @@ static int plus_key_check(uint8_t start_sector, uint8_t end_sector, uint8_t star // key for [sector,keyAB] found if (res == PM3_SUCCESS) { - - if (verbose) { - PrintAndLogEx(INFO, "Found key for sector " _YELLOW_("%d") " key "_YELLOW_("%s") " [ " _GREEN_("%s") " ]", sector, (keyAB == 0) ? "A" : "B", sprint_hex_inrow(currkey, AES_KEY_LEN)); - } else { - PrintAndLogEx(NORMAL, _GREEN_("+") NOLF); - } + if (verbose) + PrintAndLogEx(INFO, "\nFound key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); + else + PrintAndLogEx(NORMAL, "+" NOLF); foundKeys[keyAB][sector][0] = 0x01; - memcpy(&foundKeys[keyAB][sector][1], currkey, AES_KEY_LEN); - + memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN); DropField(); selectCard = true; -// msleep(50); - - // recursive test of a successful key - if (keycount > 1) { - plus_key_check(start_sector, end_sector, startKeyAB, endKeyAB, currkey, 1, foundKeys, verbose, false); - } + msleep(50); // break out from keylist check loop, break; } - if (verbose) { - PrintAndLogEx(WARNING, "\nsector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(currkey, AES_KEY_LEN), res); - } + if (verbose) + PrintAndLogEx(WARNING, "\nsector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); // RES can be: // PM3_ERFTRANS -7 // PM3_EWRONGANSWER -16 if (res == PM3_ERFTRANS) { - - if (verbose) { + if (verbose) PrintAndLogEx(ERR, "\nExchange error. Aborted."); - } else { + else PrintAndLogEx(NORMAL, "E" NOLF); - } DropField(); return PM3_ECARDEXCHANGE; } selectCard = false; - - // set pointer to next key - currkey += AES_KEY_LEN; } } } @@ -1582,31 +1396,18 @@ static int plus_key_check(uint8_t start_sector, uint8_t end_sector, uint8_t star return PM3_SUCCESS; } -static void Fill2bPattern(uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *n, uint32_t *startPattern) { - - uint32_t cnt = 0; +static void Fill2bPattern(uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN], uint32_t *keyListLen, uint32_t *startPattern) { for (uint32_t pt = *startPattern; pt < 0x10000; pt++) { - - for (uint8_t i = 0; i < AES_KEY_LEN; i += 2) { - keyList[*n][i] = (pt >> 8) & 0xff; - keyList[*n][i + 1] = pt & 0xff; - } - - PrintAndLogEx(DEBUG, _YELLOW_("%4d") " - %s", *n, sprint_hex_inrow(keyList[*n], AES_KEY_LEN)); - - // increase number of keys - (*n)++; - cnt++; - + keyList[*keyListLen][0] = (pt >> 8) & 0xff; + keyList[*keyListLen][1] = pt & 0xff; + memcpy(&keyList[*keyListLen][2], &keyList[*keyListLen][0], 2); + memcpy(&keyList[*keyListLen][4], &keyList[*keyListLen][0], 4); + memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8); + (*keyListLen)++; *startPattern = pt; - - if (*n == MAX_AES_KEYS_LIST_LEN) { + if (*keyListLen == MAX_AES_KEYS_LIST_LEN) break; - } } - - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%d") " pattern2 keys", cnt); - (*startPattern)++; } @@ -1617,10 +1418,9 @@ static int CmdHFMFPChk(const char *Cmd) { "Checks keys on MIFARE Plus card", "hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" "hf mfp chk -s 2 -a -> check default key list on sector 2, only key A\n" - "hf mfp chk -f mfp_default_keys -s 0 -e 6 -> check keys from dictionary against sectors 0-6\n" + "hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n" "hf mfp chk --pattern1b --dump -> check all 1-byte keys pattern and save found keys to file\n" - "hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00" - ); + "hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00"); void *argtable[] = { arg_param_begin, @@ -1629,12 +1429,11 @@ static int CmdHFMFPChk(const char *Cmd) { arg_int0("s", "startsec", "<0..255>", "Start sector number"), arg_int0("e", "endsec", "<0..255>", "End sector number"), arg_str0("k", "key", "", "Key for checking (HEX 16 bytes)"), - arg_str0("f", "file", "", "Dictionary file with default keys"), + arg_str0("d", "dict", "", "Dictionary file with keys"), arg_lit0(NULL, "pattern1b", "Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"), arg_lit0(NULL, "pattern2b", "Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), arg_str0(NULL, "startp2b", "", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"), arg_lit0(NULL, "dump", "Dump found keys to JSON file"), - arg_lit0(NULL, "no-default", "Skip check default keys"), arg_lit0("v", "verbose", "Verbose output"), arg_param_end }; @@ -1642,117 +1441,88 @@ static int CmdHFMFPChk(const char *Cmd) { bool keyA = arg_get_lit(ctx, 1); bool keyB = arg_get_lit(ctx, 2); - uint8_t startSector = arg_get_int_def(ctx, 3, 0); uint8_t endSector = arg_get_int_def(ctx, 4, 0); - uint32_t keyListLen = 0; uint8_t keyList[MAX_AES_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; + uint32_t keyListLen = 0; uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}}; + uint8_t vkey[16] = {0}; int vkeylen = 0; - uint8_t vkey[AES_KEY_LEN] = {0}; CLIGetHexWithReturn(ctx, 5, vkey, &vkeylen); + if (vkeylen > 0) { + if (vkeylen == 16) { + memcpy(&keyList[keyListLen], vkey, 16); + keyListLen++; + } else { + PrintAndLogEx(ERR, "Specified key must have 16 bytes. Got %d", vkeylen); + CLIParserFree(ctx); + return PM3_EINVARG; + } + } - int fnlen = 0; - char filename[FILE_PATH_SIZE] = {0}; - CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0}; + int dict_filenamelen = 0; + if (CLIParamStrToBuf(arg_get_str(ctx, 6), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { + PrintAndLogEx(FAILED, "File name too long or invalid."); + CLIParserFree(ctx); + return PM3_EINVARG; + } bool pattern1b = arg_get_lit(ctx, 7); bool pattern2b = arg_get_lit(ctx, 8); - int vpatternlen = 0; + if (pattern1b && pattern2b) { + PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + if (dict_filenamelen && (pattern1b || pattern2b)) { + PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command."); + CLIParserFree(ctx); + return PM3_EINVARG; + } + + uint32_t startPattern = 0x0000; uint8_t vpattern[2]; + int vpatternlen = 0; CLIGetHexWithReturn(ctx, 9, vpattern, &vpatternlen); + if (vpatternlen > 0) { + if (vpatternlen <= 2) { + startPattern = (vpattern[0] << 8) + vpattern[1]; + } else { + PrintAndLogEx(ERR, "Pattern must be 2-bytes. Got %d", vpatternlen); + CLIParserFree(ctx); + return PM3_EINVARG; + } + if (!pattern2b) + PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search."); + } bool create_dumpfile = arg_get_lit(ctx, 10); - bool load_default = ! arg_get_lit(ctx, 11); - bool verbose = arg_get_lit(ctx, 12); - + bool verbose = arg_get_lit(ctx, 11); CLIParserFree(ctx); - // sanity checks - if (vkeylen && (vkeylen != AES_KEY_LEN)) { - PrintAndLogEx(ERR, "Specified key must have 16 bytes. Got %d", vkeylen); - return PM3_EINVARG; - } - - if (pattern1b && pattern2b) { - PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only"); - return PM3_EINVARG; - } - - if (fnlen && (pattern1b || pattern2b)) { - PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command"); - return PM3_EINVARG; - } - - if (vpatternlen && pattern2b == false) { - PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search"); - return PM3_EINVARG; - } - - if (vpatternlen > 2) { - PrintAndLogEx(ERR, "Pattern must be 2-bytes. Got %d", vpatternlen); - return PM3_EINVARG; - } - - uint32_t startPattern = (vpattern[0] << 8) + vpattern[1]; - - // read card UID - iso14a_card_select_t card; - int nxptype = MTNONE; - int res = mfp_read_card_id(&card, &nxptype); - if (res != PM3_SUCCESS) { - return res; - } - uint8_t startKeyAB = 0; uint8_t endKeyAB = 1; - if (keyA && (keyB == false)) { + if (keyA && (keyB == false)) endKeyAB = 0; - } - if ((keyA == false) && keyB) { + if ((keyA == false) && keyB) startKeyAB = 1; - } - if (endSector < startSector) { + if (endSector < startSector) endSector = startSector; - } - // Print generic information - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Check keys") " ----------"); - PrintAndLogEx(INFO, "Start sector... %u", startSector); - PrintAndLogEx(INFO, "End sector..... %u", endSector); - - char keytypestr[6] = {0}; - if (keyA == false && keyB == false) { - strcat(keytypestr, "AB"); - } - if (keyA) { - strcat(keytypestr, "A"); - } - if (keyB) { - strcat(keytypestr, "B"); - } - PrintAndLogEx(INFO, "Key type....... " _YELLOW_("%s"), keytypestr); - PrintAndLogEx(NORMAL, ""); - - // - // Key creation section - // // 1-byte pattern search mode if (pattern1b) { - for (int i = 0; i < 0x100; i++) { memset(keyList[i], i, 16); - PrintAndLogEx(DEBUG, _YELLOW_("%3d") " - %s", i, sprint_hex_inrow(keyList[i], AES_KEY_LEN)); } keyListLen = 0x100; - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%d") " pattern1b keys", 0x100); } // 2-byte pattern search mode @@ -1760,58 +1530,87 @@ static int CmdHFMFPChk(const char *Cmd) { Fill2bPattern(keyList, &keyListLen, &startPattern); } + int res = PM3_SUCCESS; + // dictionary mode - uint8_t *key_block = NULL; - uint32_t keycnt = 0; + size_t endFilePosition = 0; + if (dict_filenamelen) { + uint32_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, 0, &endFilePosition, true); - int ret = mfp_load_keys(&key_block, &keycnt, vkey, vkeylen, filename, fnlen, card.uid, load_default); - if (ret != PM3_SUCCESS) { - return ret; + if (res == PM3_SUCCESS && endFilePosition) { + keyListLen = keycnt; + PrintAndLogEx(SUCCESS, "First part of dictionary successfully loaded."); + } } - PrintAndLogEx(INFO, "Start check for keys..."); + if (keyListLen == 0) { + for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { + if (hex_to_bytes(g_mifare_plus_default_keys[i], keyList[keyListLen], 16) != 16) { + break; + } - // time - uint64_t t1 = msclock(); - - res = plus_key_check(startSector, endSector, startKeyAB, endKeyAB, key_block, keycnt, foundKeys, verbose, true); - if (res == PM3_EOPABORTED) { - t1 = msclock() - t1; - PrintAndLogEx(INFO, "\ntime in checkkeys " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); - return res; + keyListLen++; + } } - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Start check for pattern based keys..."); - while (keyListLen) { + if (keyListLen == 0) { + PrintAndLogEx(ERR, "Key list is empty. Nothing to check."); + return PM3_EINVARG; + } else { + PrintAndLogEx(INFO, "Loaded " _YELLOW_("%"PRIu32) " keys", keyListLen); + } - res = plus_key_check(startSector, endSector, startKeyAB, endKeyAB, (uint8_t *)keyList, keyListLen, foundKeys, verbose, true); + if (verbose == false) { + PrintAndLogEx(INFO, "Search keys"); + } + + while (true) { + res = plus_key_check(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); if (res == PM3_EOPABORTED) { break; } if (pattern2b && startPattern < 0x10000) { + if (verbose == false) { + PrintAndLogEx(NORMAL, "p" NOLF); + } + keyListLen = 0; - PrintAndLogEx(NORMAL, ""); Fill2bPattern(keyList, &keyListLen, &startPattern); continue; } + + if (dict_filenamelen && endFilePosition) { + if (verbose == false) + PrintAndLogEx(NORMAL, "d" NOLF); + + uint32_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); + if (res == PM3_SUCCESS && endFilePosition) { + keyListLen = keycnt; + } + + continue; + } break; } - t1 = msclock() - t1; - PrintAndLogEx(INFO, "\ntime in checkkeys " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0); + if (verbose == false) { + PrintAndLogEx(NORMAL, ""); + } // print result char strA[46 + 1] = {0}; char strB[46 + 1] = {0}; + uint8_t ndef_key[] = {0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7, 0xD3, 0xF7}; bool has_ndef_key = false; bool printedHeader = false; for (uint8_t s = startSector; s <= endSector; s++) { - if ((memcmp(&foundKeys[0][s][1], g_mifarep_ndef_key, AES_KEY_LEN) == 0) || - (memcmp(&foundKeys[1][s][1], g_mifarep_ndef_key, AES_KEY_LEN) == 0)) { + if ((memcmp(&foundKeys[0][s][1], ndef_key, AES_KEY_LEN) == 0) || + (memcmp(&foundKeys[1][s][1], ndef_key, AES_KEY_LEN) == 0)) { has_ndef_key = true; } @@ -1838,12 +1637,10 @@ static int CmdHFMFPChk(const char *Cmd) { PrintAndLogEx(INFO, " " _YELLOW_("%03d") " | %s | %s", s, strA, strB); } - if (printedHeader == false) { - PrintAndLogEx(INFO, "No keys found"); - } else { - PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------"); - } - PrintAndLogEx(NORMAL, ""); + if (printedHeader == false) + PrintAndLogEx(INFO, "No keys found("); + else + PrintAndLogEx(INFO, "-----+----------------------------------+----------------------------------\n"); // save keys to json if (create_dumpfile && printedHeader) { @@ -1853,12 +1650,29 @@ static int CmdHFMFPChk(const char *Cmd) { uint8_t data[10 + 1 + 2 + 1 + 256 + keys_len]; memset(data, 0, sizeof(data)); - memcpy(data, card.uid, card.uidlen); - data[10] = card.sak; - data[11] = card.atqa[1]; - data[12] = card.atqa[0]; - data[13] = card.ats_len; - memcpy(&data[14], card.ats, card.ats_len); + // Mifare Plus info + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + + PacketResponseNG resp; + if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { + PrintAndLogEx(WARNING, "timeout while waiting for reply"); + return PM3_ETIMEOUT; + } + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + uint8_t atslen = 0; + if (select_status == 1 || select_status == 2) { + memcpy(data, card.uid, card.uidlen); + data[10] = card.sak; + data[11] = card.atqa[1]; + data[12] = card.atqa[0]; + atslen = card.ats_len; + data[13] = atslen; + memcpy(&data[14], card.ats, atslen); + } char *fptr = calloc(sizeof(char) * (strlen("hf-mfp-") + strlen("-key")) + card.uidlen * 2 + 1, sizeof(uint8_t)); if (fptr == NULL) { @@ -1870,14 +1684,14 @@ static int CmdHFMFPChk(const char *Cmd) { FillFileNameByUID(fptr, card.uid, "-key", card.uidlen); // length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1] - memcpy(&data[14 + card.ats_len], foundKeys, keys_len); + memcpy(&data[14 + atslen], foundKeys, keys_len); // 64 here is for how many "rows" there is in the data array. A bit confusing saveFileJSON(fptr, jsfMfPlusKeys, data, 64, NULL); free(fptr); } // MAD detection - if ((memcmp(&foundKeys[0][0][1], g_mifarep_mad_key, AES_KEY_LEN) == 0)) { + if ((memcmp(&foundKeys[0][0][1], "\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7", AES_KEY_LEN) == 0)) { PrintAndLogEx(HINT, "Hint: MAD key detected. Try " _YELLOW_("`hf mfp mad`") " for more details"); } @@ -1970,8 +1784,7 @@ static int CmdHFMFPMAD(const char *Cmd) { CLIParserInit(&ctx, "hf mfp mad", "Checks and prints MIFARE Application Directory (MAD)", "hf mfp mad\n" - "hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid" - ); + "hf mfp mad --aid e103 -k d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 -> read and print NDEF data from MAD aid"); void *argtable[] = { arg_param_begin, @@ -2326,7 +2139,7 @@ static command_t CommandTable[] = { {"auth", CmdHFMFPAuth, IfPm3Iso14443a, "Authentication"}, {"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"}, {"dump", CmdHFMFPDump, IfPm3Iso14443a, "Dump MIFARE Plus tag to binary file"}, - {"info", CmdHFMFPInfo, IfPm3Iso14443a, "Tag information"}, + {"info", CmdHFMFPInfo, IfPm3Iso14443a, "Info about MIFARE Plus tag"}, {"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Check and print MAD"}, {"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks from card"}, {"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors from card"}, diff --git a/client/src/cmdhfmfp.h b/client/src/cmdhfmfp.h index 377525c03..f6189fadf 100644 --- a/client/src/cmdhfmfp.h +++ b/client/src/cmdhfmfp.h @@ -19,7 +19,20 @@ #define CMDHFMFP_H__ #include "common.h" -#include "mifare/mifare4.h" + +typedef enum { + MFP_UNKNOWN = 0, + DESFIRE_MF3ICD40, + DESFIRE_EV1, + DESFIRE_EV2, + DESFIRE_EV2_XL, + DESFIRE_EV3, + DESFIRE_LIGHT, + PLUS_EV1, + PLUS_EV2, + NTAG413DNA, + NTAG424 +} nxp_cardtype_t; typedef struct mfp_key_item { uint8_t a[16]; @@ -33,5 +46,5 @@ typedef struct mfp_keys { int CmdHFMFP(const char *Cmd); int CmdHFMFPNDEFRead(const char *Cmd); -int mfp_data_crypt(mf4Session_t *mf4session, uint8_t *dati, uint8_t *dato, bool rev); + #endif diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 1815705de..b98d6faa1 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -59,13 +59,11 @@ static int CmdHelp(const char *Cmd); -static const char *key_type[] = { "DataProtKey", "UIDRetrKey", "OriginalityKey" }; - static uint8_t default_aes_keys[][16] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // all zeroes { 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key - { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }, // NFC-key { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, // 0x00-0x0F + { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }, // NFC-key { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // all ones { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // all FF { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }, // 11 22 33 @@ -76,8 +74,8 @@ static uint8_t default_aes_keys[][16] = { static uint8_t default_3des_keys[][16] = { { 0x42, 0x52, 0x45, 0x41, 0x4b, 0x4d, 0x45, 0x49, 0x46, 0x59, 0x4f, 0x55, 0x43, 0x41, 0x4e, 0x21 }, // 3des std key { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // all zeroes - { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }, // NFC-key { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }, // 0x00-0x0F + { 0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, 0x46 }, // NFC-key { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, // all ones { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, // all FF { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }, // 11 22 33 @@ -301,7 +299,7 @@ static const char *getUlev1CardSizeStr(uint8_t fsize) { // is LSB set? if (fsize & 1) - snprintf(buf, sizeof(buf), "%02X, (%u - %u bytes)", fsize, usize, lsize); + snprintf(buf, sizeof(buf), "%02X, (%u <-> %u bytes)", fsize, usize, lsize); else snprintf(buf, sizeof(buf), "%02X, (%u bytes)", fsize, lsize); return buf; @@ -453,7 +451,7 @@ static int ul_comp_write(uint8_t page, const uint8_t *data, uint8_t datalen) { uint8_t response[1] = {0xFF}; ul_send_cmd_raw(cmd, 2 + datalen, response, sizeof(response)); // ACK - if (response[0] == CARD_ACK) { + if (response[0] == 0x0a) { return PM3_SUCCESS; } // NACK @@ -466,31 +464,13 @@ static int ulc_requestAuthentication(uint8_t *nonce, uint16_t nonceLength) { return ul_send_cmd_raw(cmd, sizeof(cmd), nonce, nonceLength); } -int mfuc_test_authentication_support(void) { - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { - PrintAndLogEx(DEBUG, "iso14443a card select timeout"); - DropField(); - return PM3_ETIMEOUT; - } - uint8_t nonce1[11] = {0x00}; - int resplen = ulc_requestAuthentication(nonce1, sizeof(nonce1)); - DropField(); - if (resplen == 11) { // ULC nonce - return PM3_SUCCESS; - } - return PM3_ESOFT; -} - static int ulev1_requestAuthentication(const uint8_t *pwd, uint8_t *pack, uint16_t packLength) { uint8_t cmd[] = {MIFARE_ULEV1_AUTH, pwd[0], pwd[1], pwd[2], pwd[3]}; int len = ul_send_cmd_raw(cmd, sizeof(cmd), pack, packLength); // NACK tables different tags, but between 0-9 is a NEGATIVE response. // ACK == 0xA - // should only give you PACK (4 byytes) - if (len == 1) { + if (len == 1 && pack[0] <= 0x09) { return PM3_EWRONGANSWER; } return len; @@ -518,7 +498,10 @@ static int ulaes_requestAuthentication(const uint8_t *key, uint8_t keyno, bool s if (WaitForResponseTimeout(CMD_HF_MIFAREULAES_AUTH, &resp, 1500) == false) { return PM3_ETIMEOUT; } - return resp.status; + if (resp.status != PM3_SUCCESS) { + return resp.status; + } + return PM3_SUCCESS; } static int ulc_authentication(const uint8_t *key, bool switch_off_field) { @@ -1630,7 +1613,6 @@ static int mfu_dump_tag(uint16_t pages, void **pdata, uint16_t *len) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { PrintAndLogEx(WARNING, "command execution time out"); free(*pdata); - *pdata = NULL; res = PM3_ETIMEOUT; goto out; } @@ -1638,7 +1620,6 @@ static int mfu_dump_tag(uint16_t pages, void **pdata, uint16_t *len) { if (resp.oldarg[0] != 1) { PrintAndLogEx(WARNING, "Failed reading card"); free(*pdata); - *pdata = NULL; res = PM3_ESOFT; goto out; } @@ -1654,7 +1635,6 @@ static int mfu_dump_tag(uint16_t pages, void **pdata, uint16_t *len) { if (GetFromDevice(BIG_BUF, *pdata, buffer_size, startindex, NULL, 0, NULL, 2500, false) == false) { PrintAndLogEx(WARNING, "command execution time out"); free(*pdata); - *pdata = NULL; res = PM3_ETIMEOUT; goto out; } @@ -1686,7 +1666,7 @@ typedef struct { } mfu_otp_identify_t; static mfu_otp_identify_t mfu_otp_ident_table[] = { - { "SALTO Systems card", 12, 4, "534C544F", ul_c_otpgenA, "report to iceman!" }, + { "SALTO Systems card", 12, 4, "534C544F", ul_c_otpgenA, NULL }, { NULL, 0, 0, NULL, NULL, NULL } }; @@ -1852,7 +1832,7 @@ static uint8_t mfu_max_len(void) { return n; } -int mfu_get_version_uid(uint8_t *version, uint8_t *uid) { +static int mfu_get_version_uid(uint8_t *version, uint8_t *uid) { iso14a_card_select_t card; if (ul_select(&card) == false) { return PM3_ESOFT; @@ -1965,7 +1945,7 @@ static int mfu_fingerprint(uint64_t tagtype, bool hasAuthKey, const uint8_t *aut // OTP checks mfu_otp_identify_t *item = mfu_match_otp_fingerprint(uid, data); if (item) { - PrintAndLogEx(SUCCESS, _BACK_GREEN_(" %s "), item->desc); + PrintAndLogEx(SUCCESS, _GREEN_("%s"), item->desc); res = PM3_SUCCESS; if (item->hint) { @@ -2038,12 +2018,12 @@ uint64_t GetHF14AMfU_Type(void) { return MFU_TT_UL_ERROR; // Ultralight - ATQA / SAK - if (card.atqa[1] != 0x00 || card.sak != 0x00) { + if (card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00) { //PrintAndLogEx(NORMAL, "Tag is not Ultralight | NTAG | MY-D |ST25TN [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak); DropField(); return MFU_TT_UL_ERROR; } - if ((card.uid[0] == 0x02) && (card.atqa[0] == 0x44)) { + if (card.uid[0] == 0x02) { // ST25TN // read SYSBLOCK uint8_t data[4] = {0x00}; @@ -2065,7 +2045,7 @@ uint64_t GetHF14AMfU_Type(void) { } } - } else if ((card.uid[0] == 0x05) && (card.atqa[0] == 0x44)) { + } else if (card.uid[0] == 0x05) { // Infineon MY-D tests Exam high nibble DropField(); uint8_t nib = (card.uid[1] & 0xf0) >> 4; @@ -2086,7 +2066,7 @@ uint64_t GetHF14AMfU_Type(void) { } } else { - // Note that SAK might be 0x44 but also e.g. 0x04 for cards in Random ID mode + uint8_t version[10] = {0x00}; int len = ulev1_getVersion(version, sizeof(version)); DropField(); @@ -2337,8 +2317,8 @@ static int CmdHF14AMfUInfo(const char *Cmd) { uint8_t ulc_conf[16] = {0x00}; status = ul_read(0x28, ulc_conf, sizeof(ulc_conf)); if (status <= 0) { - PrintAndLogEx(ERR, "Error: tag didn't answer to page 40 read command"); - PrintAndLogEx(HINT, "Hint: tag config may be set to read-protect those pages, try dumping"); + PrintAndLogEx(ERR, "Error: tag didn't answer to READ UL-C"); + PrintAndLogEx(HINT, "Hint: Tag is most likely fully read protected"); DropField(); return PM3_ESOFT; } @@ -2727,9 +2707,8 @@ static int CmdHF14AMfUWrBl(const char *Cmd) { // starting with getting tagtype uint64_t tagtype = GetHF14AMfU_Type(); - if (tagtype == MFU_TT_UL_ERROR) { + if (tagtype == MFU_TT_UL_ERROR) return PM3_ESOFT; - } uint8_t maxblockno = 0; for (uint8_t idx = 1; idx < ARRAYLEN(UL_TYPES_ARRAY); idx++) { @@ -3838,21 +3817,18 @@ static int CmdHF14AMfUSim(const char *Cmd) { "ISO/IEC 14443 type A tag with 4,7 or 10 byte UID\n" "from emulator memory. See `hf mfu eload` first. \n" "The UID from emulator memory will be used if not specified.\n" - "See `hf 14a sim -h` to see available types. You want 2, 7 or 13 usually.", + "See `hf 14a sim -h` to see available types. You want 2 or 7 usually.", "hf mfu sim -t 2 --uid 11223344556677 -> MIFARE Ultralight\n" "hf mfu sim -t 7 --uid 11223344556677 -n 5 -> MFU EV1 / NTAG 215 Amiibo\n" - "hf mfu sim -t 7 -> MFU EV1 / NTAG 215 Amiibo\n" - "hf mfu sim -t 13 -> MIFARE Ultralight-C\n" + "hf mfu sim -t 7 -> MFU EV1 / NTAG 215 Amiibo" ); void *argtable[] = { arg_param_begin, - arg_int1("t", "type", "<1..13> ", "Simulation type to use"), + arg_int1("t", "type", "<1..12> ", "Simulation type to use"), arg_str0("u", "uid", "", "<4|7|10> hex bytes UID"), arg_int0("n", "num", "", "Exit simulation after blocks. 0 = infinite"), arg_lit0("v", "verbose", "Verbose output"), - arg_lit0(NULL, "c1", "UL-C Auth - all zero handshake part 1"), - arg_lit0(NULL, "c2", "UL-C Auth - all zero handshake part 2"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -3869,17 +3845,17 @@ static int CmdHF14AMfUSim(const char *Cmd) { static int CmdHF14AMfUCAuth(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf mfu cauth", - "Tests 3DES key on Mifare Ultralight-C tag.\n" - "If key is not specified, a set of known defaults will be tried.", + "Tests 3DES password on Mifare Ultralight-C tag.\n" + "If password is not specified, a set of known defaults will be tested.", "hf mfu cauth\n" "hf mfu cauth --key 000102030405060708090a0b0c0d0e0f" ); void *argtable[] = { arg_param_begin, - arg_str0(NULL, "key", "", "Authentication key (16 bytes in hex)"), + arg_str0(NULL, "key", "", "Authentication key (UL-C 16 hex bytes)"), arg_lit0("l", NULL, "Swap entered key's endianness"), - arg_lit0("k", NULL, "Keep field on (only if a key is provided)"), + arg_lit0("k", NULL, "Keep field on (only if a password is provided)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); @@ -3931,24 +3907,24 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) { CLIParserInit(&ctx, "hf mfu aesauth", "Tests AES key on Mifare Ultralight AES tags.\n" "If no key is specified, null key will be tried.\n" - " Key index 0... DataProtKey (default)\n" - " Key index 1... UIDRetrKey\n" - " Key index 2... OriginalityKey\n", + "Key index 0: DataProtKey (default)\n" + "Key index 1: UIDRetrKey\n" + "Key index 2: OriginalityKey\n", "hf mfu aesauth\n" - "hf mfu aesauth --key <16 hex bytes> --idx <0..2>" + "hf mfu aesauth --key <32 bytes> --index <0..2>" ); void *argtable[] = { arg_param_begin, - arg_str0(NULL, "key", "", "AES key (16 hex bytes)"), - arg_int0("i", "idx", "<0..2>", "Key index (def: 0)"), + arg_str0(NULL, "key", "", "AES key (32 hex bytes)"), + arg_int0("i", "index", "<0..2>", "Key index, default: 0"), arg_lit0("k", NULL, "Keep field on (only if a key is provided)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); int ak_len = 0; - uint8_t authentication_key[16] = {0}; + uint8_t authentication_key[32] = {0}; uint8_t *authKeyPtr = authentication_key; CLIGetHexWithReturn(ctx, 1, authentication_key, &ak_len); int key_index = arg_get_int_def(ctx, 2, 0); @@ -3958,9 +3934,9 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) { if (ak_len == 0) { // default to null key - ak_len = 16; + ak_len = 32; } - if (ak_len != 16) { + if (ak_len != 32) { PrintAndLogEx(WARNING, "Invalid key length"); return PM3_EINVARG; } @@ -3971,13 +3947,14 @@ static int CmdHF14AMfUAESAuth(const char *Cmd) { } int result = ulaes_requestAuthentication(authKeyPtr, key_index, !keep_field_on); + + const char *key_type[] = { "DataProtKey", "UIDRetrKey", "OriginalityKey" }; if (result == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "Authentication with " _YELLOW_("%s") " " _GREEN_("%s") " ( " _GREEN_("ok")" )" - , key_type[key_index] - , sprint_hex_inrow(authKeyPtr, ak_len) - ); + PrintAndLogEx(SUCCESS, "Authentication with " _YELLOW_("%s") " " _GREEN_("%s") " ( " _GREEN_("ok")" )", + key_type[key_index], sprint_hex_inrow(authKeyPtr, ak_len)); } else { - PrintAndLogEx(WARNING, "Authentication with " _YELLOW_("%s") " ( " _RED_("fail") " )", key_type[key_index]); + PrintAndLogEx(WARNING, "Authentication with " _YELLOW_("%s") " ( " _RED_("fail") " )", + key_type[key_index]); } return result; } @@ -4170,17 +4147,17 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { // Enforce bad BCC handling temporarily as BCC will be wrong between // block 1 write and block2 write - hf14a_config_t config; + hf14a_config config; SendCommandNG(CMD_HF_ISO14443A_GET_CONFIG, NULL, 0); if (WaitForResponseTimeout(CMD_HF_ISO14443A_GET_CONFIG, &resp, 2000) == false) { PrintAndLogEx(WARNING, "command execute timeout"); return PM3_ETIMEOUT; } - memcpy(&config, resp.data.asBytes, sizeof(hf14a_config_t)); + memcpy(&config, resp.data.asBytes, sizeof(hf14a_config)); int8_t oldconfig_bcc = config.forcebcc; if (oldconfig_bcc != 2) { config.forcebcc = 2; - SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)&config, sizeof(hf14a_config_t)); + SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)&config, sizeof(hf14a_config)); } // block 0. @@ -4223,7 +4200,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { // restore BCC config if (oldconfig_bcc != 2) { config.forcebcc = oldconfig_bcc; - SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)&config, sizeof(hf14a_config_t)); + SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)&config, sizeof(hf14a_config)); } return PM3_SUCCESS; } @@ -4632,7 +4609,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { // we be getting ACK that we are silently ignoring here.. - if (WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000) == false) { + if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000)) { PrintAndLogEx(WARNING, "Failed"); return PM3_ESOFT; } @@ -4653,13 +4630,11 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) { got_post = true; } } - - if (!got_post) { + if (! got_post) { PrintAndLogEx(FAILED, "Failed to read block BEFORE"); error_retries++; continue; // try again } - error_retries = 0; char prestr[20] = {0}; snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre))); @@ -4942,7 +4917,7 @@ static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) { clearCommandBuffer(); PacketResponseNG resp; SendCommandNG(CMD_HF_MFU_COUNTER_TEAROFF, (uint8_t*)&payload, sizeof(payload)); - if (WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000) == false) { + if (!WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000)) { PrintAndLogEx(WARNING, "\ntear off command failed"); continue; } @@ -5923,6 +5898,12 @@ static int CmdHF14AMfUIncr(const char *Cmd) { increment_cmd[i + 2] = (value >> (8 * i)) & 0xff; } + iso14a_card_select_t card; + if (ul_select(&card) == false) { + PrintAndLogEx(FAILED, "failed to select card, exiting..."); + return PM3_ESOFT; + } + uint64_t tagtype = GetHF14AMfU_Type(); uint64_t tags_with_counter_ul = MFU_TT_UL_EV1_48 | MFU_TT_UL_EV1_128 | MFU_TT_UL_EV1; uint64_t tags_with_counter_ntag = MFU_TT_NTAG_213 | MFU_TT_NTAG_213_F | MFU_TT_NTAG_213_C | MFU_TT_NTAG_213_TT | MFU_TT_NTAG_215 | MFU_TT_NTAG_216; @@ -5948,12 +5929,6 @@ static int CmdHF14AMfUIncr(const char *Cmd) { } } - iso14a_card_select_t card; - if (ul_select(&card) == false) { - PrintAndLogEx(FAILED, "failed to select card, exiting..."); - return PM3_ESOFT; - } - uint8_t current_counter[3] = { 0, 0, 0 }; int len = ulev1_readCounter(counter, current_counter, sizeof(current_counter)); if (len != sizeof(current_counter)) { diff --git a/client/src/cmdhfmfu.h b/client/src/cmdhfmfu.h index ea1c67340..a365e76d3 100644 --- a/client/src/cmdhfmfu.h +++ b/client/src/cmdhfmfu.h @@ -53,8 +53,6 @@ int ul_print_type(uint64_t tagtype, uint8_t spaces); void mfu_print_dump(mfu_dump_t *card, uint16_t pages, uint8_t startpage, bool dense_output); int ul_read_uid(uint8_t *uid); int trace_mfuc_try_default_3des_keys(uint8_t **correct_key, int state, uint8_t (*authdata)[16]); -int mfu_get_version_uid(uint8_t *version, uint8_t *uid); -int mfuc_test_authentication_support(void); int CmdHFMFUltra(const char *Cmd); int CmdHF14MfuNDEFRead(const char *Cmd); diff --git a/client/src/cmdhfntag424.c b/client/src/cmdhfntag424.c index 188b4eec5..81926f103 100644 --- a/client/src/cmdhfntag424.c +++ b/client/src/cmdhfntag424.c @@ -34,8 +34,8 @@ #include "crc32.h" #include "cmdhfmfdes.h" -#define NTAG424_MAX_BYTES 412 -#define NTAG424_RESPONSE_LENGTH 2 +#define NTAG424_MAX_BYTES 412 + // NTAG424 commands currently implemented // icenam: should be able to use 14a / msdes to annotate NTAG424 communications @@ -542,17 +542,19 @@ static void ntag424_print_file_settings(uint8_t fileno, const ntag424_file_setti // NTAG424 only have one static application, so we select it here static int ntag424_select_application(void) { + const size_t RESPONSE_LENGTH = 2; uint8_t cmd[] = {0x00, 0xA4, 0x04, 0x0C, 0x07, 0xD2, 0x76, 0x00, 0x00, 0x85, 0x01, 0x01, 0x00 }; - uint8_t resp[NTAG424_RESPONSE_LENGTH]; + uint8_t resp[RESPONSE_LENGTH]; int outlen = 0; + int res; - int res = ExchangeAPDU14a(cmd, sizeof(cmd), false, true, resp, NTAG424_RESPONSE_LENGTH, &outlen); + res = ExchangeAPDU14a(cmd, sizeof(cmd), false, true, resp, RESPONSE_LENGTH, &outlen); if (res != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to send apdu"); return res; } - if (outlen != NTAG424_RESPONSE_LENGTH || resp[NTAG424_RESPONSE_LENGTH - 2] != 0x90 || resp[NTAG424_RESPONSE_LENGTH - 1] != 0x00) { + if (outlen != RESPONSE_LENGTH || resp[RESPONSE_LENGTH - 2] != 0x90 || resp[RESPONSE_LENGTH - 1] != 0x00) { PrintAndLogEx(ERR, "Failed to select application"); return PM3_ESOFT; } @@ -760,7 +762,7 @@ static int ntag424_write_data(uint8_t fileno, uint32_t offset, uint32_t num_byte static int ntag424_read_data(uint8_t fileno, uint16_t offset, uint16_t num_bytes, uint8_t *out, ntag424_communication_mode_t comm_mode, ntag424_session_keys_t *session_keys) { uint8_t cmd_header[] = { fileno, - (uint8_t)offset, (uint8_t)(offset >> 8), (uint8_t)(offset >> 16), // offset + (uint8_t)offset, (uint8_t)(offset << 8), (uint8_t)(offset << 16), // offset (uint8_t)num_bytes, (uint8_t)(num_bytes >> 8), 0x00 }; diff --git a/client/src/cmdhfseos.c b/client/src/cmdhfseos.c index 69b789d42..6956f2f2c 100644 --- a/client/src/cmdhfseos.c +++ b/client/src/cmdhfseos.c @@ -562,7 +562,7 @@ static int select_DF_verify(uint8_t *response, uint8_t response_length, uint8_t } // ----------------- MAC Key Generation ----------------- - uint8_t cmac[16]; + uint8_t cmac[8]; uint8_t MAC_key[24] = {0x00}; memcpy(MAC_key, keys[key_index].privMacKey, 16); create_cmac(MAC_key, input, cmac, sizeof(input), encryption_algorithm); @@ -1351,7 +1351,7 @@ static int CmdHfSeosGDF(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, true); - int key_index = arg_get_int_def(ctx, 1, 0); + int key_index = arg_get_int_def(ctx, 1, -1); CLIParserFree(ctx); return seos_global_df(key_index); diff --git a/client/src/cmdhftesla.c b/client/src/cmdhftesla.c index bf42f84cb..e1687a170 100644 --- a/client/src/cmdhftesla.c +++ b/client/src/cmdhftesla.c @@ -24,7 +24,6 @@ #include "cmdtrace.h" #include "cliparser.h" #include "cmdhf14a.h" -#include "crypto/asn1utils.h" // ASN1 decode / print #include "protocols.h" // definitions of ISO14A/7816 protocol #include "iso7816/apduinfo.h" // GetAPDUCodeDescription #include "commonutil.h" // get_sw @@ -33,7 +32,6 @@ #include "cmdhf14a.h" // apdu chaining #define TIMEOUT 2000 -#define MAX_CERT_SIZE 768 static int CmdHelp(const char *Cmd); @@ -53,22 +51,17 @@ static int CmdHelp(const char *Cmd); */ // TESLA -static int info_hf_tesla(bool parse_certs) { +static int info_hf_tesla(void) { bool activate_field = true; bool keep_field_on = true; - uint8_t response[MAX_CERT_SIZE]; // Some cards have pretty large certificates + uint8_t response[PM3_CMD_DATA_SIZE]; int resplen = 0; - - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); - PrintAndLogEx(NORMAL, ""); - // --------------- Select TESLA application ---------------- uint8_t aSELECT_AID[80]; int aSELECT_AID_n = 0; - param_gethex_to_eol("00a404000a7465736c614c6f67696300", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); + param_gethex_to_eol("00a404000a7465736c614c6f676963", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res != PM3_SUCCESS) { DropField(); @@ -80,7 +73,7 @@ static int info_hf_tesla(bool parse_certs) { if ((resplen < 2) || (sw != ISO7816_OK)) { - param_gethex_to_eol("00a404000af465736c614c6f67696300", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); + param_gethex_to_eol("00a404000af465736c614c6f676963", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n); res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res != PM3_SUCCESS) { DropField(); @@ -99,9 +92,9 @@ static int info_hf_tesla(bool parse_certs) { // --------------- ECDH public key file reading ---------------- - uint8_t pk[4][65] = {{0}}; + uint8_t pk[3][65] = {{0}}; - for (uint8_t i = 0; i < 4; i++) { + for (uint8_t i = 0; i < 3; i++) { uint8_t aSELECT_PK[5] = {0x80, 0x04, i, 0x00, 0x00}; res = ExchangeAPDU14a(aSELECT_PK, sizeof(aSELECT_PK), activate_field, keep_field_on, response, sizeof(response), &resplen); @@ -117,7 +110,7 @@ static int info_hf_tesla(bool parse_certs) { uint8_t aREAD_FORM_FACTOR[30]; int aREAD_FORM_FACTOR_n = 0; - param_gethex_to_eol("8014000000", 0, aREAD_FORM_FACTOR, sizeof(aREAD_FORM_FACTOR), &aREAD_FORM_FACTOR_n); + param_gethex_to_eol("80140000", 0, aREAD_FORM_FACTOR, sizeof(aREAD_FORM_FACTOR), &aREAD_FORM_FACTOR_n); res = ExchangeAPDU14a(aREAD_FORM_FACTOR, aREAD_FORM_FACTOR_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res != PM3_SUCCESS) { DropField(); @@ -156,58 +149,23 @@ static int info_hf_tesla(bool parse_certs) { Set_apdu_in_framing(true); for (uint8_t i = 0; i < 5; i++) { - // First, read the certificate length - uint8_t aSELECT_CERT[PM3_CMD_DATA_SIZE] = {0x80, 0x06, i, 0x00, 0x04}; - int aSELECT_CERT_n = 5; + uint8_t aSELECT_CERT[PM3_CMD_DATA_SIZE] = {0x80, 0x06, i, 0x00, 0x00, 0x00, 0xFF}; + int aSELECT_CERT_n = 7; - res = ExchangeAPDU14a(aSELECT_CERT, aSELECT_CERT_n, activate_field, keep_field_on, response, sizeof(response), &resplen); + res = ExchangeAPDU14a(aSELECT_CERT, aSELECT_CERT_n, activate_field, keep_field_on, response, PM3_CMD_DATA_SIZE, &resplen); if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Could not read certificate %i length", i); continue; } sw = get_sw(response, resplen); - bool cert_len_present = false; - if (sw == ISO7816_OK && resplen > 3) { - uint16_t cert_len = response[0] << 8 | response[1]; + if (sw == ISO7816_OK) { + // save CERT for later + uint8_t cert[515] = {0}; + memcpy(cert, response, resplen - 2); + PrintAndLogEx(INFO, "CERT # %i", i); - if (cert_len == 0x3082) { - cert_len = (response[2] << 8 | response[3]) + 4; - PrintAndLogEx(INFO, "Length (calculated from ASN.1): %i", cert_len); - } else { - PrintAndLogEx(INFO, "Length (included at start of cert slot): %i", cert_len); - cert_len_present = true; - } - cert_len += 2; // Add 2 bytes for the 9000 at the end - // Read the entire cert (extended length APDU) - aSELECT_CERT[4] = 0x00; - aSELECT_CERT[5] = (cert_len >> 8) & 0xff; - aSELECT_CERT[6] = cert_len & 0xff; - aSELECT_CERT_n = 7; - - res = ExchangeAPDU14a(aSELECT_CERT, aSELECT_CERT_n, activate_field, keep_field_on, response, sizeof(response), &resplen); - if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Could not read certificate %i (return code %i)", i, res); - continue; - } - - sw = get_sw(response, resplen); - if (sw == ISO7816_OK) { - // save CERT for later - uint8_t cert[MAX_CERT_SIZE] = {0}; - memcpy(cert, response, resplen - 2); - - PrintAndLogEx(INFO, "%s", sprint_hex_inrow(cert + (cert_len_present ? 2 : 0), resplen - 2)); - if (parse_certs) { - asn1_print(cert + (cert_len_present ? 2 : 0), cert_len - 2, " "); - } - } - } else if (sw == 0x6f17) { - PrintAndLogEx(INFO, "CERT # %i", i); - PrintAndLogEx(INFO, "No certificate in slot %i", i); - } else { - PrintAndLogEx(ERR, "Could not read certificate %i", i); + PrintAndLogEx(INFO, "%s", sprint_hex_inrow(cert, resplen - 2)); } } Set_apdu_in_framing(false); @@ -217,28 +175,30 @@ static int info_hf_tesla(bool parse_certs) { // vehicle public key , 16 byte CHALLENGE // 00112233445566778899AABBCCDDEEFF // 0x51 = 81 dec - // param_gethex_to_eol("8011000051 046F08AE62526ABB5690643458152AC963CF5D7C113949F3C2453D1DDC6E4385B430523524045A22F5747BF236F1B5F60F0EA32DC2B8276D75ACDE9813EF77C330 00112233445566778899AABBCCDDEEFF", 0, aAUTH, sizeof(aAUTH), &aAUTH_n); - param_gethex_to_eol("8011000051046F08AE62526ABB5690643458152AC963CF5D7C113949F3C2453D1DDC6E4385B430523524045A22F5747BF236F1B5F60F0EA32DC2B8276D75ACDE9813EF77C33000112233445566778899AABBCCDDEEFF00", 0, aAUTH, sizeof(aAUTH), &aAUTH_n); +// param_gethex_to_eol("8011000051 046F08AE62526ABB5690643458152AC963CF5D7C113949F3C2453D1DDC6E4385B430523524045A22F5747BF236F1B5F60F0EA32DC2B8276D75ACDE9813EF77C330 00112233445566778899AABBCCDDEEFF", 0, aAUTH, sizeof(aAUTH), &aAUTH_n); + param_gethex_to_eol("8011000051046F08AE62526ABB5690643458152AC963CF5D7C113949F3C2453D1DDC6E4385B430523524045A22F5747BF236F1B5F60F0EA32DC2B8276D75ACDE9813EF77C33000112233445566778899AABBCCDDEEFF", 0, aAUTH, sizeof(aAUTH), &aAUTH_n); res = ExchangeAPDU14a(aAUTH, aAUTH_n, activate_field, keep_field_on, response, sizeof(response), &resplen); if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Could not exchange authentication challenge"); - } else { + DropField(); + return res; + } - uint8_t auth[resplen - 2]; + uint8_t auth[resplen - 2]; - sw = get_sw(response, resplen); - if (sw == ISO7816_OK) { - // store CHALLENGE for later - memcpy(auth, response, sizeof(auth)); - } - PrintAndLogEx(INFO, "CHALL......... %s", sprint_hex_inrow(auth, sizeof(auth))); + sw = get_sw(response, resplen); + if (sw == ISO7816_OK) { + // store CHALLENGE for later + memcpy(auth, response, sizeof(auth)); } keep_field_on = false; - DropField(); // No further interaction with the card is needed + DropField(); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "PUBLIC KEY"); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < 3; i++) { PrintAndLogEx(INFO, "%d - %s", i, sprint_hex_inrow(pk[i], 65)); } PrintAndLogEx(INFO, "Form factor... %s " NOLF, sprint_hex_inrow(form_factor, sizeof(form_factor))); @@ -247,33 +207,16 @@ static int info_hf_tesla(bool parse_certs) { switch (form_factor_value) { case 0x0001: - PrintAndLogEx(NORMAL, "(NXP P60 card)"); - break; - case 0x0002: - PrintAndLogEx(NORMAL, "(NXP P71 card)"); - break; - case 0x0021: - PrintAndLogEx(NORMAL, "(Model 3 fob without passive entry)"); + PrintAndLogEx(NORMAL, "( card )"); break; case 0x0022: - PrintAndLogEx(NORMAL, "(Model 3 fob with passive entry)"); - break; - case 0x0023: - case 0x0025: - case 0x0026: - PrintAndLogEx(NORMAL, "(Model S fob)"); - break; - case 0x0024: - PrintAndLogEx(NORMAL, "(Model X fob)"); + PrintAndLogEx(NORMAL, "( fob )"); break; case 0x0031: - PrintAndLogEx(NORMAL, "(Android phone app with NFC)"); - break; - case 0x0032: - PrintAndLogEx(NORMAL, "(iOS phone app with NFC)"); + PrintAndLogEx(NORMAL, "( phone app )"); break; default: - PrintAndLogEx(NORMAL, "(Unknown)"); + PrintAndLogEx(NORMAL, "( unknown )"); break; } @@ -281,6 +224,8 @@ static int info_hf_tesla(bool parse_certs) { PrintAndLogEx(INFO, "Version....... %s", sprint_hex_inrow(version, sizeof(version))); } + PrintAndLogEx(INFO, "CHALL......... %s", sprint_hex_inrow(auth, sizeof(auth))); + PrintAndLogEx(INFO, "Fingerprint"); if ((memcmp(pk[0], pk[1], 65) == 0)) { PrintAndLogEx(INFO, " GaussKey detected"); @@ -299,14 +244,11 @@ static int CmdHFTeslaInfo(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_lit0("p", "parse", "Parse the certificates as ASN.1"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - - bool parse_certs = arg_get_lit(ctx, 1); CLIParserFree(ctx); - return info_hf_tesla(parse_certs); + return info_hf_tesla(); } static int CmdHFTeslaList(const char *Cmd) { diff --git a/client/src/cmdhftexkom.c b/client/src/cmdhftexkom.c index 8a6cee6f2..b033050ba 100644 --- a/client/src/cmdhftexkom.c +++ b/client/src/cmdhftexkom.c @@ -623,7 +623,7 @@ int read_texkom_uid(bool loop, bool verbose) { } } - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); return PM3_SUCCESS; } @@ -664,7 +664,7 @@ static int CmdHFTexkomReader(const char *Cmd) { SendCommandNG(CMD_HF_ACQ_RAW_ADC, (uint8_t *)&samplesCount, sizeof(uint32_t)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500) == false) { + if (!WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500)) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } diff --git a/client/src/cmdhfthinfilm.c b/client/src/cmdhfthinfilm.c index fa7921dc6..4e3bafdb9 100644 --- a/client/src/cmdhfthinfilm.c +++ b/client/src/cmdhfthinfilm.c @@ -187,7 +187,7 @@ int CmdHfThinFilmSim(const char *Cmd) { int ret; while (!(ret = kbd_enter_pressed())) { - if (WaitForResponseTimeout(CMD_HF_THINFILM_SIMULATE, &resp, 500) == false) { + if (WaitForResponseTimeout(CMD_HF_THINFILM_SIMULATE, &resp, 500) == 0) { continue; } diff --git a/client/src/cmdhftopaz.c b/client/src/cmdhftopaz.c index ca3efdaa3..05069a35b 100644 --- a/client/src/cmdhftopaz.c +++ b/client/src/cmdhftopaz.c @@ -109,7 +109,7 @@ static int topaz_select(uint8_t *atqa, uint8_t atqa_len, uint8_t *rid_response, } // read all of the static memory of a selected Topaz tag. -static int topaz_rall(const uint8_t *uid, uint8_t *response) { +static int topaz_rall(uint8_t *uid, uint8_t *response) { uint16_t resp_len = 124; uint8_t rall_cmd[] = {TOPAZ_RALL, 0, 0, 0, 0, 0, 0, 0, 0}; @@ -1180,7 +1180,7 @@ int readTopazUid(bool loop, bool verbose) { topaz_tag.HR01[0] = rid_response[0]; topaz_tag.HR01[1] = rid_response[1]; - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); topaz_switch_off_field(); return res; diff --git a/client/src/cmdhfxerox.c b/client/src/cmdhfxerox.c index 713b7f616..ad13a0dca 100644 --- a/client/src/cmdhfxerox.c +++ b/client/src/cmdhfxerox.c @@ -593,7 +593,7 @@ int read_xerox_uid(bool loop, bool verbose) { return PM3_ESOFT; } - } while (loop && (kbd_enter_pressed() == false)); + } while (loop && kbd_enter_pressed() == false); return PM3_SUCCESS; } @@ -1013,8 +1013,8 @@ static int CmdHFXeroxRdBl(const char *Cmd) { static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdHFXeroxList, AlwaysAvailable, "List ISO-14443B history"}, - {"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("Operations") " -----------------------"}, - {"info", CmdHFXeroxInfo, IfPm3Iso14443b, "Tag information"}, + {"--------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("General") " -----------------------"}, + {"info", CmdHFXeroxInfo, IfPm3Iso14443b, "Short info on Fuji/Xerox tag"}, {"dump", CmdHFXeroxDump, IfPm3Iso14443b, "Read all memory pages of an Fuji/Xerox tag, save to file"}, {"reader", CmdHFXeroxReader, IfPm3Iso14443b, "Act like a Fuji/Xerox reader"}, {"view", CmdHFXeroxView, AlwaysAvailable, "Display content from tag dump file"}, diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 047cf387f..7dd2cee2f 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -928,19 +928,15 @@ static int CmdTune(const char *Cmd) { SendCommandNG(CMD_MEASURE_ANTENNA_TUNING, NULL, 0); PacketResponseNG resp; PrintAndLogEx(INPLACE, "% 3i", timeout_max - timeout); - - while (WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING, &resp, 500) == false) { - + while (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING, &resp, 500)) { fflush(stdout); if (timeout >= timeout_max) { PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); return PM3_ETIMEOUT; } - timeout++; PrintAndLogEx(INPLACE, "% 3i", timeout_max - timeout); } - PrintAndLogEx(NORMAL, ""); if (resp.status != PM3_SUCCESS) { @@ -1596,7 +1592,7 @@ void pm3_version_short(void) { PrintAndLogEx(NORMAL, " Client.... %s", temp); bool armsrc_mismatch = false; - char *ptr = strstr(payload->versionstr, "OS......... "); + char *ptr = strstr(payload->versionstr, " os: "); if (ptr != NULL) { ptr = strstr(ptr, "\n"); if ((ptr != NULL) && (strlen(g_version_information.armsrc) == 9)) { @@ -1611,7 +1607,7 @@ void pm3_version_short(void) { if (ptr != NULL) { char *ptr_end = strstr(ptr, "\n"); if (ptr_end != NULL) { - uint8_t len = ptr_end - 12 - ptr; + uint8_t len = ptr_end - 19 - ptr; PrintAndLogEx(NORMAL, " Bootrom... %.*s", len, ptr + 12); } } @@ -1621,7 +1617,7 @@ void pm3_version_short(void) { if (ptr != NULL) { char *ptr_end = strstr(ptr, "\n"); if (ptr_end != NULL) { - uint8_t len = ptr_end - 12 - ptr; + uint8_t len = ptr_end - 14 - ptr; PrintAndLogEx(NORMAL, " OS........ %.*s", len, ptr + 12); } } diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index b36c1c97b..5a2278859 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -83,7 +83,7 @@ int lfsim_wait_check(uint32_t cmd) { for (;;) { if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(DEBUG, "\naborted via keyboard!"); + PrintAndLogEx(DEBUG, "User aborted"); break; } @@ -435,17 +435,15 @@ int CmdLFCommandRead(const char *Cmd) { i = 10; // 20sec wait loop - while (WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) == false && i != 0) { + while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) { if (verbose) { PrintAndLogEx(NORMAL, "." NOLF); } i--; } - if (verbose) { PrintAndLogEx(NORMAL, ""); } - if (resp.status != PM3_SUCCESS) { PrintAndLogEx(WARNING, "command failed."); return PM3_ESOFT; @@ -462,7 +460,7 @@ int CmdLFCommandRead(const char *Cmd) { return PM3_ETIMEOUT; } - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && kbd_enter_pressed() == false); return ret; } @@ -597,7 +595,7 @@ int lf_getconfig(sample_config *config) { SendCommandNG(CMD_LF_SAMPLING_GET_CONFIG, NULL, 0); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_LF_SAMPLING_GET_CONFIG, &resp, 2000) == false) { + if (!WaitForResponseTimeout(CMD_LF_SAMPLING_GET_CONFIG, &resp, 2000)) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } @@ -799,12 +797,10 @@ static int lf_read_internal(bool realtime, bool verbose, uint64_t samples) { payload.samples = (samples > MAX_LF_SAMPLES) ? MAX_LF_SAMPLES : samples; SendCommandNG(CMD_LF_ACQ_RAW_ADC, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (is_trigger_threshold_set) { WaitForResponse(CMD_LF_ACQ_RAW_ADC, &resp); } else { - - if (WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500) == false) { + if (!WaitForResponseTimeout(CMD_LF_ACQ_RAW_ADC, &resp, 2500)) { PrintAndLogEx(WARNING, "(lf_read) command execution time out"); return PM3_ETIMEOUT; } @@ -859,7 +855,7 @@ int CmdLFRead(const char *Cmd) { int ret = PM3_SUCCESS; do { ret = lf_read_internal(realtime, verbose, samples); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && kbd_enter_pressed() == false); if (ret == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "Got " _YELLOW_("%zu") " samples", g_GraphTraceLen); @@ -985,7 +981,7 @@ int CmdLFSniff(const char *Cmd) { int ret = PM3_SUCCESS; do { ret = lf_sniff(realtime, verbose, samples); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && kbd_enter_pressed() == false); return ret; } diff --git a/client/src/cmdlfawid.c b/client/src/cmdlfawid.c index 0f28d823d..9e330844a 100644 --- a/client/src/cmdlfawid.c +++ b/client/src/cmdlfawid.c @@ -349,7 +349,7 @@ static int CmdAWIDReader(const char *Cmd) { do { lf_read(false, 12000); demodAWID(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfdestron.c b/client/src/cmdlfdestron.c index a9c6b1bd2..c8cd6c596 100644 --- a/client/src/cmdlfdestron.c +++ b/client/src/cmdlfdestron.c @@ -129,7 +129,7 @@ static int CmdDestronReader(const char *Cmd) { do { lf_read(false, 16000); demodDestron(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfem410x.c b/client/src/cmdlfem410x.c index c178eb440..1b4f31d95 100644 --- a/client/src/cmdlfem410x.c +++ b/client/src/cmdlfem410x.c @@ -445,7 +445,7 @@ static int CmdEM410xReader(const char *Cmd) { if (break_first && gs_em410xid != 0) { break; } - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfem4x05.c b/client/src/cmdlfem4x05.c index 11589d881..709322e3a 100644 --- a/client/src/cmdlfem4x05.c +++ b/client/src/cmdlfem4x05.c @@ -2013,7 +2013,7 @@ int CmdEM4x05Unlock(const char *Cmd) { PrintAndLogEx(INFO, "----------------------------------------------------------------------------\n"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); + PrintAndLogEx(INFO, "Press " _GREEN_("'") " to exit"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------------\n"); diff --git a/client/src/cmdlfem4x50.c b/client/src/cmdlfem4x50.c index a8b199700..61cf2db22 100644 --- a/client/src/cmdlfem4x50.c +++ b/client/src/cmdlfem4x50.c @@ -639,8 +639,10 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out) { return PM3_ESOFT; } + em4x50_read_data_response_t *o = (em4x50_read_data_response_t *)resp.data.asBytes; + em4x50_word_t words[EM4X50_NO_WORDS] = {0}; - em4x50_prepare_result(resp.data.asBytes, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words); + em4x50_prepare_result((uint8_t *)o->words, etd->addresses & 0xFF, (etd->addresses >> 8) & 0xFF, words); if (out != NULL) { memcpy(out, &words, sizeof(em4x50_word_t) * EM4X50_NO_WORDS); diff --git a/client/src/cmdlfem4x70.c b/client/src/cmdlfem4x70.c index 8fd80e3d7..27672f9f4 100644 --- a/client/src/cmdlfem4x70.c +++ b/client/src/cmdlfem4x70.c @@ -86,12 +86,18 @@ typedef struct _em4x70_tag_info_t { uint8_t Raw[32]; } em4x70_tag_info_t; +typedef struct _em4x70_cmd_input_info_t { + uint8_t use_parity; +} em4x70_cmd_input_info_t; + typedef struct _em4x70_cmd_input_writeblock_t { + uint8_t use_parity; uint8_t block; uint8_t value[2]; } em4x70_cmd_input_writeblock_t; typedef struct _em4x70_cmd_input_brute_t { + uint8_t use_parity; ID48LIB_NONCE rn; ID48LIB_FRN frn; uint8_t block; @@ -115,10 +121,12 @@ typedef struct _em4x70_cmd_output_brute_t { } em4x70_cmd_output_brute_t; typedef struct _em4x70_cmd_input_unlock_t { + uint8_t use_parity; uint8_t pin[4]; } em4x70_cmd_input_unlock_t; typedef struct _em4x70_cmd_input_auth_t { + uint8_t use_parity; ID48LIB_NONCE rn; ID48LIB_FRN frn; } em4x70_cmd_input_auth_t; @@ -128,10 +136,12 @@ typedef struct _em4x70_cmd_output_auth_t { } em4x70_cmd_output_auth_t; typedef struct _em4x70_cmd_input_setpin_t { + uint8_t use_parity; uint8_t pin[4]; } em4x70_cmd_input_setpin_t; typedef struct _em4x70_cmd_input_setkey_t { + uint8_t use_parity; ID48LIB_KEY key; } em4x70_cmd_input_setkey_t; @@ -141,6 +151,7 @@ typedef struct _em4x70_cmd_input_recover_t { ID48LIB_NONCE nonce; ID48LIB_FRN frn; ID48LIB_GRN grn; + bool parity; // if true, add parity bit to commands sent to tag bool verify; // if true, tag must be present } em4x70_cmd_input_recover_t; @@ -153,6 +164,7 @@ typedef struct _em4x70_cmd_output_recover_t { } em4x70_cmd_output_recover_t; typedef struct _em4x70_cmd_input_verify_auth_t { + uint8_t use_parity; ID48LIB_NONCE rn; ID48LIB_FRN frn; ID48LIB_GRN grn; @@ -216,12 +228,12 @@ static void em4x70_print_info_result(const em4x70_tag_info_t *data) { PrintAndLogEx(NORMAL, ""); } -static int get_em4x70_info(em4x70_tag_info_t *data_out) { +static int get_em4x70_info(const em4x70_cmd_input_info_t *opts, em4x70_tag_info_t *data_out) { memset(data_out, 0, sizeof(em4x70_tag_info_t)); // TODO: change firmware to use per-cmd structures - em4x70_data_t edata = {0}; + em4x70_data_t edata = { .parity = opts->use_parity }; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X70_INFO, (uint8_t *)&edata, sizeof(em4x70_data_t)); PacketResponseNG resp; @@ -239,10 +251,10 @@ static int writeblock_em4x70(const em4x70_cmd_input_writeblock_t *opts, em4x70_t memset(data_out, 0, sizeof(em4x70_tag_info_t)); // TODO: change firmware to use per-cmd structures - em4x70_data_t etd = { - .address = opts->block, - .word = BYTES2UINT16(opts->value), - }; + em4x70_data_t etd = {0}; + etd.address = opts->block; + etd.word = BYTES2UINT16(opts->value); + etd.parity = opts->use_parity; clearCommandBuffer(); SendCommandNG(CMD_LF_EM4X70_WRITE, (uint8_t *)&etd, sizeof(etd)); @@ -261,6 +273,7 @@ static int auth_em4x70(const em4x70_cmd_input_auth_t *opts, em4x70_cmd_output_au // TODO: change firmware to use per-cmd structures em4x70_data_t etd = {0}; + etd.parity = opts->use_parity; memcpy(&etd.rnd[0], &opts->rn.rn[0], 7); memcpy(&etd.frnd[0], &opts->frn.frn[0], 4); @@ -285,6 +298,7 @@ static int setkey_em4x70(const em4x70_cmd_input_setkey_t *opts) { // TODO: change firmware to use per-cmd structures em4x70_data_t etd = {0}; + etd.parity = opts->use_parity; memcpy(&etd.crypt_key[0], &opts->key.k[0], 12); clearCommandBuffer(); @@ -301,6 +315,7 @@ static int brute_em4x70(const em4x70_cmd_input_brute_t *opts, em4x70_cmd_output_ // TODO: change firmware to use per-cmd structures em4x70_data_t etd = {0}; + etd.parity = opts->use_parity; etd.address = opts->block; memcpy(&etd.rnd[0], &opts->rn.rn[0], 7); memcpy(&etd.frnd[0], &opts->frn.frn[0], 4); @@ -351,6 +366,7 @@ static int unlock_em4x70(const em4x70_cmd_input_unlock_t *opts, em4x70_tag_info_ // TODO: change firmware to use per-cmd structures em4x70_data_t etd = {0}; + etd.parity = opts->use_parity; etd.pin = BYTES2UINT32(opts->pin); clearCommandBuffer(); @@ -370,6 +386,7 @@ static int setpin_em4x70(const em4x70_cmd_input_setpin_t *opts, em4x70_tag_info_ // TODO: change firmware to use per-cmd structures em4x70_data_t etd = {0}; + etd.parity = opts->use_parity; etd.pin = BYTES2UINT32(opts->pin); clearCommandBuffer(); @@ -412,6 +429,7 @@ static int recover_em4x70(const em4x70_cmd_input_recover_t *opts, em4x70_cmd_out static int verify_auth_em4x70(const em4x70_cmd_input_verify_auth_t *opts) { em4x70_cmd_input_auth_t opts_auth = { + .use_parity = opts->use_parity, .rn = opts->rn, .frn = opts->frn, }; @@ -440,19 +458,24 @@ static int CmdEM4x70Info(const char *Cmd) { " ID48 does not use command parity (default).\n" " V4070 and EM4170 do require parity bit.", "lf em 4x70 info\n" + "lf em 4x70 info --par -> adds parity bit to command\n" ); void *argtable[] = { arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + em4x70_cmd_input_info_t opts = { + .use_parity = arg_get_lit(ctx, 0), + }; CLIParserFree(ctx); // Client command line parsing and validation complete ... now use the helper function em4x70_tag_info_t info; - int result = get_em4x70_info(&info); + int result = get_em4x70_info(&opts, &info); if (result == PM3_ETIMEOUT) { PrintAndLogEx(WARNING, "timeout while waiting for reply"); @@ -471,10 +494,12 @@ static int CmdEM4x70Write(const char *Cmd) { CLIParserInit(&ctx, "lf em 4x70 write", "Write EM4x70\n", "lf em 4x70 write -b 15 -d c0de -> write 'c0de' to block 15\n" + "lf em 4x70 write -b 15 -d c0de --par -> adds parity bit to commands\n" ); void *argtable[] = { arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_int1("b", "block", "", "block/word address, dec"), arg_str1("d", "data", "", "data, 2 bytes"), arg_param_end @@ -483,12 +508,12 @@ static int CmdEM4x70Write(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); em4x70_cmd_input_writeblock_t opts = { - .block = arg_get_int_def(ctx, 1, 1), + .use_parity = arg_get_lit(ctx, 1), + .block = arg_get_int_def(ctx, 2, 1), .value = {0}, // hex value macro exits function, so cannot be initialized here }; - int value_len = 0; - CLIGetHexWithReturn(ctx, 2, opts.value, &value_len); + CLIGetHexWithReturn(ctx, 3, opts.value, &value_len); CLIParserFree(ctx); if (opts.block >= EM4X70_NUM_BLOCKS) { @@ -530,6 +555,7 @@ static int CmdEM4x70Brute(const char *Cmd) { ); void *argtable[] = { arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_int1("b", "block", "", "block/word address, dec"), arg_str1(NULL, "rnd", "", "Random 56-bit"), arg_str1(NULL, "frn", "", "F(RN) 28-bit as 4 hex bytes"), @@ -539,7 +565,8 @@ static int CmdEM4x70Brute(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); em4x70_cmd_input_brute_t opts = { - .block = arg_get_int_def(ctx, 1, 0), + .use_parity = arg_get_lit(ctx, 1), + .block = arg_get_int_def(ctx, 2, 0), .rn = {{0}}, // hex value macro exits function, so cannot be initialized here .frn = {{0}}, // hex value macro exits function, so cannot be initialized here .partial_key_start = {0}, // hex value macro exits function, so cannot be initialized here @@ -552,15 +579,15 @@ static int CmdEM4x70Brute(const char *Cmd) { } int rnd_len = 7; - CLIGetHexWithReturn(ctx, 2, opts.rn.rn, &rnd_len); + CLIGetHexWithReturn(ctx, 3, opts.rn.rn, &rnd_len); int frnd_len = 4; - CLIGetHexWithReturn(ctx, 3, opts.frn.frn, &frnd_len); + CLIGetHexWithReturn(ctx, 4, opts.frn.frn, &frnd_len); // would prefer to use above CLIGetHexWithReturn(), but it does not // appear to support optional arguments. uint32_t start_key = 0; - int res = arg_get_u32_hexstr_def_nlen(ctx, 4, 0, &start_key, 2, true); // this stores in NATIVE ENDIAN + int res = arg_get_u32_hexstr_def_nlen(ctx, 5, 0, &start_key, 2, true); // this stores in NATIVE ENDIAN if (res == 2) { PrintAndLogEx(WARNING, "start key parameter must be in range [0, FFFF]"); CLIParserFree(ctx); @@ -587,7 +614,7 @@ static int CmdEM4x70Brute(const char *Cmd) { em4x70_cmd_output_brute_t data; int result = brute_em4x70(&opts, &data); if (result == PM3_EOPABORTED) { - PrintAndLogEx(DEBUG, "\naborted via keyboard!"); + PrintAndLogEx(DEBUG, "User aborted"); } else if (result == PM3_ETIMEOUT) { PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); } else if (result == PM3_SUCCESS) { @@ -608,9 +635,11 @@ static int CmdEM4x70Unlock(const char *Cmd) { " AAAAAAAA\n" " 00000000\n", "lf em 4x70 unlock -p 11223344 -> Unlock with PIN\n" + "lf em 4x70 unlock -p 11223344 --par -> Unlock with PIN using parity commands\n" ); void *argtable[] = { arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_str1("p", "pin", "", "pin, 4 bytes"), arg_param_end }; @@ -618,10 +647,11 @@ static int CmdEM4x70Unlock(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); em4x70_cmd_input_unlock_t opts = { + .use_parity = arg_get_lit(ctx, 1), .pin = {0}, // hex value macro exits function, so cannot be initialized here }; int pin_len = 0; - CLIGetHexWithReturn(ctx, 1, opts.pin, &pin_len); + CLIGetHexWithReturn(ctx, 2, opts.pin, &pin_len); CLIParserFree(ctx); if (pin_len != 4) { @@ -661,6 +691,7 @@ static int CmdEM4x70Auth(const char *Cmd) { void *argtable[] = { arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_str1(NULL, "rnd", "", "Random 56-bit"), arg_str1(NULL, "frn", "", "F(RN) 28-bit as 4 hex bytes"), arg_param_end @@ -669,14 +700,15 @@ static int CmdEM4x70Auth(const char *Cmd) { CLIExecWithReturn(ctx, Cmd, argtable, true); em4x70_cmd_input_auth_t opts = { + .use_parity = arg_get_lit(ctx, 1), .rn = {{0}}, // hex value macro exits function, so cannot be initialized here .frn = {{0}}, // hex value macro exits function, so cannot be initialized here }; int rn_len = 7; - CLIGetHexWithReturn(ctx, 1, opts.rn.rn, &rn_len); + CLIGetHexWithReturn(ctx, 2, opts.rn.rn, &rn_len); int frn_len = 4; - CLIGetHexWithReturn(ctx, 2, opts.frn.frn, &frn_len); + CLIGetHexWithReturn(ctx, 3, opts.frn.frn, &frn_len); CLIParserFree(ctx); if (rn_len != 7) { PrintAndLogEx(FAILED, "Random number length must be 7 bytes, got %d", rn_len); @@ -706,19 +738,23 @@ static int CmdEM4x70SetPIN(const char *Cmd) { CLIParserInit(&ctx, "lf em 4x70 setpin", "Write new PIN\n", "lf em 4x70 setpin -p 11223344 -> Write new PIN\n" + "lf em 4x70 setpin -p 11223344 --par -> Write new PIN using parity commands\n" ); void *argtable[] = { arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_str1("p", "pin", "", "pin, 4 bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + em4x70_cmd_input_setpin_t opts = { + .use_parity = arg_get_lit(ctx, 1), .pin = {0}, // hex value macro exits function, so cannot be initialized here }; int pin_len = 0; - CLIGetHexWithReturn(ctx, 1, opts.pin, &pin_len); + CLIGetHexWithReturn(ctx, 2, opts.pin, &pin_len); CLIParserFree(ctx); if (pin_len != 4) { @@ -753,16 +789,19 @@ static int CmdEM4x70SetKey(const char *Cmd) { void *argtable[] = { arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_str1("k", "key", "", "Key as 12 hex bytes"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); + em4x70_cmd_input_setkey_t opts = { + .use_parity = arg_get_lit(ctx, 1), .key = {{0}}, // hex value macro exits function, so cannot be initialized here }; int key_len = 12; - CLIGetHexWithReturn(ctx, 1, opts.key.k, &key_len); + CLIGetHexWithReturn(ctx, 2, opts.key.k, &key_len); CLIParserFree(ctx); if (key_len != 12) { PrintAndLogEx(FAILED, "Key length must be 12 bytes, got %d", key_len); @@ -784,6 +823,7 @@ static int CmdEM4x70SetKey(const char *Cmd) { // Now verify authentication using the new key, to ensure it was correctly written em4x70_cmd_input_verify_auth_t opts_v = { + .use_parity = opts.use_parity, //.rn = opts_auth.rn, //.frn = opts_auth.frn, //.grn = {{0}}, @@ -869,6 +909,7 @@ static int CmdEM4x70Recover_ParseArgs(const char *Cmd, em4x70_cmd_input_recover_ void *argtable[] = { arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_str1("k", "key", "", "Key as 6 hex bytes"), arg_str1(NULL, "rnd", "", "Random 56-bit"), arg_str1(NULL, "frn", "", "F(RN) 28-bit as 4 hex bytes"), @@ -890,16 +931,17 @@ static int CmdEM4x70Recover_ParseArgs(const char *Cmd, em4x70_cmd_input_recover_ // if all OK so far, convert to internal data structure if (PM3_SUCCESS == result) { // magic number == index in argtable above. Fragile technique! - if (CLIParamHexToBuf(arg_get_str(ctx, 1), &(out_results->key.k[0]), 12, &key_len)) { + out_results->parity = arg_get_lit(ctx, 1); + if (CLIParamHexToBuf(arg_get_str(ctx, 2), &(out_results->key.k[0]), 12, &key_len)) { result = PM3_ESOFT; } - if (CLIParamHexToBuf(arg_get_str(ctx, 2), &(out_results->nonce.rn[0]), 7, &rnd_len)) { + if (CLIParamHexToBuf(arg_get_str(ctx, 3), &(out_results->nonce.rn[0]), 7, &rnd_len)) { result = PM3_ESOFT; } - if (CLIParamHexToBuf(arg_get_str(ctx, 3), &(out_results->frn.frn[0]), 4, &frn_len)) { + if (CLIParamHexToBuf(arg_get_str(ctx, 4), &(out_results->frn.frn[0]), 4, &frn_len)) { result = PM3_ESOFT; } - if (CLIParamHexToBuf(arg_get_str(ctx, 4), &(out_results->grn.grn[0]), 3, &grn_len)) { + if (CLIParamHexToBuf(arg_get_str(ctx, 5), &(out_results->grn.grn[0]), 3, &grn_len)) { result = PM3_ESOFT; } //out_results->verify = arg_get_lit(ctx, 6); @@ -1070,6 +1112,7 @@ static int CmdEM4x70AutoRecover_ParseArgs(const char *Cmd, em4x70_cmd_input_reco void *argtable[] = { arg_param_begin, + arg_lit0(NULL, "par", "Add parity bit when sending commands"), arg_str1(NULL, "rnd", "", "Random 56-bit from known-good authentication"), arg_str1(NULL, "frn", "", "F(RN) 28-bit as 4 hex bytes from known-good authentication"), arg_str1(NULL, "grn", "", "G(RN) 20-bit as 3 hex bytes from known-good authentication"), @@ -1082,9 +1125,10 @@ static int CmdEM4x70AutoRecover_ParseArgs(const char *Cmd, em4x70_cmd_input_reco int rnd_len = 0; // must be 7 bytes hex data int frn_len = 0; // must be 4 bytes hex data int grn_len = 0; // must be 3 bytes hex data - CLIGetHexWithReturn(ctx, 1, out_results->nonce.rn, &rnd_len); - CLIGetHexWithReturn(ctx, 2, out_results->frn.frn, &frn_len); - CLIGetHexWithReturn(ctx, 3, out_results->grn.grn, &grn_len); + out_results->parity = arg_get_lit(ctx, 1); + CLIGetHexWithReturn(ctx, 2, out_results->nonce.rn, &rnd_len); + CLIGetHexWithReturn(ctx, 3, out_results->frn.frn, &frn_len); + CLIGetHexWithReturn(ctx, 4, out_results->grn.grn, &grn_len); CLIParserFree(ctx); if (rnd_len != 7) { @@ -1146,6 +1190,7 @@ static int CmdEM4x70AutoRecover(const char *Cmd) { PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 auth --rnd %s --frn %s"), rnd_string, frn_string); em4x70_cmd_input_auth_t opts_auth = { + .use_parity = opts.parity, .rn = opts.nonce, .frn = opts.frn, }; @@ -1189,6 +1234,7 @@ static int CmdEM4x70AutoRecover(const char *Cmd) { PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 write -b %d -d 0000"), block); em4x70_cmd_input_writeblock_t opt_write_zeros = { + .use_parity = opts.parity, .block = block, .value = {0x00, 0x00}, }; @@ -1209,6 +1255,7 @@ static int CmdEM4x70AutoRecover(const char *Cmd) { PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 brute -b %d --rnd %s --frn %s"), block, rnd_string, frn_string); em4x70_cmd_input_brute_t opts_brute = { + .use_parity = opts.parity, .block = block, .rn = opts.nonce, .frn = opts.frn, @@ -1247,6 +1294,7 @@ static int CmdEM4x70AutoRecover(const char *Cmd) { PrintAndLogEx(HINT, "Hint: " _YELLOW_("lf em 4x70 write -b %d -d %02X%02X"), block, brute.partial_key[0], brute.partial_key[1]); em4x70_cmd_input_writeblock_t opt_write_zeros2 = { + .use_parity = opts.parity, .block = block, .value = {brute.partial_key[0], brute.partial_key[1]}, }; @@ -1306,6 +1354,7 @@ static int CmdEM4x70AutoRecover(const char *Cmd) { PrintAndLogEx(INFO, "Step 6. Verify which potential key is actually on the tag"); em4x70_cmd_input_verify_auth_t opts_v = { + .use_parity = opts.parity, //.rn = {{0}}, //.frn = {{0}}, //.grn = {{0}}, @@ -1472,7 +1521,7 @@ static int CmdHelp(const char *Cmd); static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"brute", CmdEM4x70Brute, IfPm3EM4x70, "Bruteforce EM4X70 to find partial key"}, - {"info", CmdEM4x70Info, IfPm3EM4x70, "Tag information"}, + {"info", CmdEM4x70Info, IfPm3EM4x70, "Tag information EM4x70"}, {"write", CmdEM4x70Write, IfPm3EM4x70, "Write EM4x70"}, {"unlock", CmdEM4x70Unlock, IfPm3EM4x70, "Unlock EM4x70 for writing"}, {"auth", CmdEM4x70Auth, IfPm3EM4x70, "Authenticate EM4x70"}, @@ -1505,8 +1554,9 @@ int CmdLFEM4X70(const char *Cmd) { // Use helper function `get_em4x70_info()` if wanting to limit / avoid output. bool detect_4x70_block(void) { em4x70_tag_info_t info; + em4x70_cmd_input_info_t opts = { 0 }; - int result = get_em4x70_info(&info); + int result = get_em4x70_info(&opts, &info); if (result == PM3_ETIMEOUT) { // consider removing this output? PrintAndLogEx(WARNING, "timeout while waiting for reply"); diff --git a/client/src/cmdlffdxb.c b/client/src/cmdlffdxb.c index 853c10dde..c3034f98f 100644 --- a/client/src/cmdlffdxb.c +++ b/client/src/cmdlffdxb.c @@ -692,7 +692,7 @@ static int CmdFdxBReader(const char *Cmd) { lf_read(false, 10000); ret = demodFDXB(!cm); // be verbose only if not in continuous mode - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); if (old_div != curr_div) { diff --git a/client/src/cmdlfgallagher.c b/client/src/cmdlfgallagher.c index 98e6bf524..b4955290d 100644 --- a/client/src/cmdlfgallagher.c +++ b/client/src/cmdlfgallagher.c @@ -132,7 +132,7 @@ static int CmdGallagherReader(const char *Cmd) { do { lf_read(false, 4096 * 2 + 20); demodGallagher(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfguard.c b/client/src/cmdlfguard.c index 8ff8c13d1..9275a5e32 100644 --- a/client/src/cmdlfguard.c +++ b/client/src/cmdlfguard.c @@ -243,7 +243,7 @@ static int CmdGuardReader(const char *Cmd) { do { lf_read(false, 10000); demodGuard(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfhid.c b/client/src/cmdlfhid.c index 0e932fccb..1db507df4 100644 --- a/client/src/cmdlfhid.c +++ b/client/src/cmdlfhid.c @@ -215,7 +215,7 @@ static int CmdHIDReader(const char *Cmd) { do { lf_read(false, 16000); demodHID(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfhitag.c b/client/src/cmdlfhitag.c index dddad1bab..8e3a0b808 100644 --- a/client/src/cmdlfhitag.c +++ b/client/src/cmdlfhitag.c @@ -498,7 +498,7 @@ static int ht2_check_dictionary(uint32_t key_count, uint8_t *keys, uint8_t keyl if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(WARNING, "\naborted via keyboard!"); + PrintAndLogEx(INFO, "User aborted"); break; } @@ -912,7 +912,7 @@ static int CmdLFHitagReader(const char *Cmd) { if (ht2_get_uid(&uid)) { PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%08X"), uid); } - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && kbd_enter_pressed() == false); return PM3_SUCCESS; } @@ -2428,8 +2428,8 @@ int ht2_read_uid(void) { return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "UID....... " _GREEN_("%08X"), uid); - PrintAndLogEx(SUCCESS, "TYPE...... " _GREEN_("%s"), getHitagTypeStr(uid)); + PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%08X"), uid); + PrintAndLogEx(SUCCESS, "TYPE... " _GREEN_("%s"), getHitagTypeStr(uid)); return PM3_SUCCESS; } @@ -2468,7 +2468,7 @@ static command_t CommandTable[] = { {"hts", CmdLFHitagS, AlwaysAvailable, "{ Hitag S/8211 operations }"}, {"htu", CmdLFHitagU, AlwaysAvailable, "{ Hitag µ/8265 operations }"}, {"-----------", CmdHelp, IfPm3Hitag, "------------------------ " _CYAN_("General") " ------------------------"}, - {"info", CmdLFHitagInfo, IfPm3Hitag, "Tag information"}, + {"info", CmdLFHitagInfo, IfPm3Hitag, "Hitag 2 tag information"}, {"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag 2 reader"}, {"test", CmdLFHitag2Selftest, AlwaysAvailable, "Perform self tests"}, {"-----------", CmdHelp, IfPm3Hitag, "----------------------- " _CYAN_("Operations") " -----------------------"}, diff --git a/client/src/cmdlfhitaghts.c b/client/src/cmdlfhitaghts.c index de6efcae3..f474e1bd1 100644 --- a/client/src/cmdlfhitaghts.c +++ b/client/src/cmdlfhitaghts.c @@ -182,8 +182,8 @@ int read_hts_uid(void) { return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "UID....... " _GREEN_("%08X"), uid); - PrintAndLogEx(SUCCESS, "TYPE...... " _GREEN_("%s"), hts_get_type_str(uid)); + PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%08X"), uid); + PrintAndLogEx(SUCCESS, "TYPE... " _GREEN_("%s"), hts_get_type_str(uid)); return PM3_SUCCESS; } @@ -968,7 +968,7 @@ static int CmdLFHitagSReader(const char *Cmd) { if (hts_get_uid(&uid)) { PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%08X"), uid); } - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && kbd_enter_pressed() == false); return PM3_SUCCESS; } diff --git a/client/src/cmdlfhitagu.c b/client/src/cmdlfhitagu.c index 59e72aebe..9a561651c 100644 --- a/client/src/cmdlfhitagu.c +++ b/client/src/cmdlfhitagu.c @@ -197,8 +197,8 @@ int read_htu_uid(void) { return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "UID....... " _GREEN_("%012llX"), uid); - // PrintAndLogEx(SUCCESS, "TYPE...... " _GREEN_("%s"), htu_get_type_str(uid)); + PrintAndLogEx(SUCCESS, "UID.... " _GREEN_("%012llX"), uid); + // PrintAndLogEx(SUCCESS, "TYPE... " _GREEN_("%s"), htu_get_type_str(uid)); return PM3_SUCCESS; } diff --git a/client/src/cmdlfidteck.c b/client/src/cmdlfidteck.c index b6976fe4d..fa498ea74 100644 --- a/client/src/cmdlfidteck.c +++ b/client/src/cmdlfidteck.c @@ -315,7 +315,7 @@ static int CmdIdteckReader(const char *Cmd) { do { lf_read(false, 5000); demodIdteck(NULL, !cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfindala.c b/client/src/cmdlfindala.c index 4efdd3531..87ad4d833 100644 --- a/client/src/cmdlfindala.c +++ b/client/src/cmdlfindala.c @@ -632,7 +632,7 @@ static int CmdIndalaReader(const char *Cmd) { do { lf_read(false, 30000); demodIndalaEx(clk, invert, max_err, !cm); - } while (cm & (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } @@ -1163,12 +1163,12 @@ int getIndalaBits(uint8_t fc, uint16_t cn, uint8_t *bits) { chk += ((cn >> 2) & 1); //y14 == 89 - 30 = 59 chk += (cn & 1); //y16 == 71 - 30 = 41 - if ((chk & 1) == 0) { // If the sum is even, checksum is '10' (binary) = 2. - bits[62] = 1; - bits[63] = 0; - } else { // If the sum is odd, checksum is '01' (binary) = 1. + if ((chk & 1) == 0) { bits[62] = 0; bits[63] = 1; + } else { + bits[62] = 1; + bits[63] = 0; } // add parity diff --git a/client/src/cmdlfio.c b/client/src/cmdlfio.c index a56b6b3a0..865b2b74a 100644 --- a/client/src/cmdlfio.c +++ b/client/src/cmdlfio.c @@ -202,7 +202,7 @@ static int CmdIOProxReader(const char *Cmd) { do { lf_read(false, 12000); demodIOProx(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfjablotron.c b/client/src/cmdlfjablotron.c index d0f9305d8..290181ae7 100644 --- a/client/src/cmdlfjablotron.c +++ b/client/src/cmdlfjablotron.c @@ -152,7 +152,7 @@ static int CmdJablotronReader(const char *Cmd) { do { lf_read(false, 16000); demodJablotron(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfkeri.c b/client/src/cmdlfkeri.c index 4fc5cac72..fc599a646 100644 --- a/client/src/cmdlfkeri.c +++ b/client/src/cmdlfkeri.c @@ -221,7 +221,7 @@ static int CmdKeriReader(const char *Cmd) { do { lf_read(false, 10000); demodKeri(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfmotorola.c b/client/src/cmdlfmotorola.c index 04cf7fe20..99caaa7a3 100644 --- a/client/src/cmdlfmotorola.c +++ b/client/src/cmdlfmotorola.c @@ -179,7 +179,7 @@ static int CmdMotorolaReader(const char *Cmd) { // 64 * 32 * 2 * n-ish lf_read(false, 5000); res = demodMotorola(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); // reset back to 125 kHz sc.divisor = LF_DIVISOR_125; diff --git a/client/src/cmdlfnedap.c b/client/src/cmdlfnedap.c index ac50d4851..ac6bea204 100644 --- a/client/src/cmdlfnedap.c +++ b/client/src/cmdlfnedap.c @@ -296,7 +296,7 @@ static int CmdLFNedapReader(const char *Cmd) { do { lf_read(false, 16000); demodNedap(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfnexwatch.c b/client/src/cmdlfnexwatch.c index 505ca6d7e..b1a162817 100644 --- a/client/src/cmdlfnexwatch.c +++ b/client/src/cmdlfnexwatch.c @@ -287,7 +287,7 @@ static int CmdNexWatchReader(const char *Cmd) { do { lf_read(false, 20000); demodNexWatch(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfnoralsy.c b/client/src/cmdlfnoralsy.c index b10ee7f97..2a0fbd2b2 100644 --- a/client/src/cmdlfnoralsy.c +++ b/client/src/cmdlfnoralsy.c @@ -150,7 +150,7 @@ static int CmdNoralsyReader(const char *Cmd) { do { lf_read(false, 8000); demodNoralsy(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfpac.c b/client/src/cmdlfpac.c index 8d00c40df..757fd9051 100644 --- a/client/src/cmdlfpac.c +++ b/client/src/cmdlfpac.c @@ -35,9 +35,6 @@ #include "cmdlfem4x05.h" // #include "cliparser.h" -// 8 bytes + null terminator -#define PAC_ID_LEN (8 + 1) - static int CmdHelp(const char *Cmd); // PAC_8byte format: preamble (8 mark/idle bits), ascii STX (02), ascii '2' (32), ascii '0' (30), ascii bytes 0..7 (cardid), then xor checksum of cardid bytes @@ -163,13 +160,12 @@ int demodPac(bool verbose) { uint32_t raw3 = bytebits_to_byte(g_DemodBuffer + 64, 32); uint32_t raw4 = bytebits_to_byte(g_DemodBuffer + 96, 32); - // 8 bytes + null terminator - uint8_t cardid[PAC_ID_LEN]; + const size_t idLen = 9; // 8 bytes + null terminator + uint8_t cardid[idLen]; int retval = pac_buf_to_cardid(g_DemodBuffer, g_DemodBufferLen, cardid, sizeof(cardid)); - if (retval == PM3_SUCCESS) { + if (retval == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "PAC/Stanley - Card: " _GREEN_("%s") ", Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4); - } return retval; } @@ -214,7 +210,7 @@ static int CmdPacReader(const char *Cmd) { do { lf_read(false, 4096 * 2 + 20); demodPac(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfparadox.c b/client/src/cmdlfparadox.c index 71aa19ebe..dae518311 100644 --- a/client/src/cmdlfparadox.c +++ b/client/src/cmdlfparadox.c @@ -285,7 +285,7 @@ static int CmdParadoxReader(const char *Cmd) { do { lf_read(false, 10000); demodParadox(!cm, old); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfpcf7931.c b/client/src/cmdlfpcf7931.c index df18617dc..ae19b174f 100644 --- a/client/src/cmdlfpcf7931.c +++ b/client/src/cmdlfpcf7931.c @@ -84,7 +84,7 @@ static int CmdLFPCF7931Reader(const char *Cmd) { PrintAndLogEx(WARNING, "command execution time out"); return PM3_ETIMEOUT; } - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfpresco.c b/client/src/cmdlfpresco.c index 969a054ce..a3f1c89e2 100644 --- a/client/src/cmdlfpresco.c +++ b/client/src/cmdlfpresco.c @@ -160,7 +160,7 @@ static int CmdPrescoReader(const char *Cmd) { do { lf_read(false, 12000); demodPresco(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfpyramid.c b/client/src/cmdlfpyramid.c index e29453263..9e24c319b 100644 --- a/client/src/cmdlfpyramid.c +++ b/client/src/cmdlfpyramid.c @@ -231,7 +231,7 @@ static int CmdPyramidReader(const char *Cmd) { do { lf_read(false, 15000); demodPyramid(true); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } @@ -498,28 +498,25 @@ int getPyramidBits(uint32_t fc, uint32_t cn, uint8_t *pyramidBits) { // FSK Demod then try to locate a Farpointe Data (pyramid) ID int detectPyramid(uint8_t *dest, size_t *size, int *waveStartIdx) { - // make sure buffer has data + //make sure buffer has data if (*size < 128 * 50) return -1; - // test samples are not just noise + //test samples are not just noise if (getSignalProperties()->isnoise) return -2; // FSK demodulator RF/50 FSK 10,8 *size = fskdemod(dest, *size, 50, 1, 10, 8, waveStartIdx); // pyramid fsk2 - // did we get a good demod? + //did we get a good demod? if (*size < 128) return -3; size_t startIdx = 0; uint8_t preamble[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1}; - if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) { - return -4; // preamble not found - } + if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) + return -4; //preamble not found // wrong size? (between to preambles) - if (*size < 128) { - return -5; - } + if (*size < 128) return -5; return (int)startIdx; } diff --git a/client/src/cmdlfsecurakey.c b/client/src/cmdlfsecurakey.c index 30e997421..f4e381e42 100644 --- a/client/src/cmdlfsecurakey.c +++ b/client/src/cmdlfsecurakey.c @@ -161,7 +161,7 @@ static int CmdSecurakeyReader(const char *Cmd) { do { lf_read(false, 8000); demodSecurakey(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 49e50902f..7da9967f2 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -466,7 +466,7 @@ int clone_t55xx_tag(uint32_t *blockdata, uint8_t numblocks) { ng.flags = 0; SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng)); - if (WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, T55XX_WRITE_TIMEOUT) == false) { + if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, T55XX_WRITE_TIMEOUT)) { PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation."); return PM3_ETIMEOUT; } @@ -664,7 +664,7 @@ int t55xxWrite(uint8_t block, bool page1, bool usepwd, bool testMode, uint32_t p PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_T55XX_WRITEBL, (uint8_t *)&ng, sizeof(ng)); - if (WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, 2000) == false) { + if (!WaitForResponseTimeout(CMD_LF_T55XX_WRITEBL, &resp, 2000)) { PrintAndLogEx(ERR, "Error occurred, device did not ACK write operation."); return PM3_ETIMEOUT; } @@ -1992,7 +1992,7 @@ static int CmdT55xxDangerousRaw(const char *Cmd) { PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_LF_T55XX_DANGERRAW, (uint8_t *)&ng, sizeof(ng)); - if (WaitForResponseTimeout(CMD_LF_T55XX_DANGERRAW, &resp, 2000) == false) { + if (!WaitForResponseTimeout(CMD_LF_T55XX_DANGERRAW, &resp, 2000)) { PrintAndLogEx(ERR, "Error occurred, device did not ACK write operation."); return PM3_ETIMEOUT; } @@ -2840,7 +2840,7 @@ bool AcquireData(uint8_t page, uint8_t block, bool pwdmode, uint32_t password, u clearCommandBuffer(); SendCommandNG(CMD_LF_T55XX_READBL, (uint8_t *)&payload, sizeof(payload)); - if (WaitForResponseTimeout(CMD_LF_T55XX_READBL, NULL, 2500) == false) { + if (!WaitForResponseTimeout(CMD_LF_T55XX_READBL, NULL, 2500)) { PrintAndLogEx(WARNING, "command execution time out"); return false; } @@ -3435,7 +3435,7 @@ static int CmdT55xxChkPwds(const char *Cmd) { PacketResponseNG resp; uint8_t timeout = 0; - while (WaitForResponseTimeout(CMD_LF_T55XX_CHK_PWDS, &resp, 2000) == false) { + while (!WaitForResponseTimeout(CMD_LF_T55XX_CHK_PWDS, &resp, 2000)) { timeout++; PrintAndLogEx(NORMAL, "." NOLF); if (timeout > 180) { @@ -4694,74 +4694,6 @@ static int CmdT55xxSniff(const char *Cmd) { return PM3_SUCCESS; } -static int CmdT55xxView(const char *Cmd) { - - CLIParserContext *ctx; - CLIParserInit(&ctx, "lf t55xx view", - "Print a T55xx dump file (bin/eml/json)\n", - "lf t55xx view -f lf-t55xx-00000000-11111111-22222222-33333333-dump.bin" - ); - void *argtable[] = { - arg_param_begin, - arg_str1("f", "file", "", "Specify a filename for dump file"), - arg_lit0("v", "verbose", "verbose output"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, false); - int fnlen = 0; - char filename[FILE_PATH_SIZE]; - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); - // bool verbose = arg_get_lit(ctx, 2); - CLIParserFree(ctx); - - if (fnlen == 0) { - PrintAndLogEx(ERR, "Must specify a filename"); - return PM3_EINVARG; - } - - // read dump file - uint32_t *dump = NULL; - size_t bytes_read = 0; - int res = pm3_load_dump(filename, (void **)&dump, &bytes_read, (T55x7_BLOCK_COUNT * 4)); - if (res != PM3_SUCCESS) { - return res; - } - - if (bytes_read != (T55x7_BLOCK_COUNT * 4)) { - free(dump); - PrintAndLogEx(FAILED, "wrong length of dump file. Expected 48 bytes, got %zu", bytes_read); - return PM3_EFILE; - } - - - PrintAndLogEx(INFO, ""); - PrintAndLogEx(SUCCESS, " " _CYAN_("Page 0")); - PrintAndLogEx(SUCCESS, "----+----------+-------"); - PrintAndLogEx(SUCCESS, "blk | hex data | ascii"); - PrintAndLogEx(SUCCESS, "----+----------+-------"); - - uint32_t *pd = dump; - uint8_t tmp[4] = {0}; - for (uint8_t i = 0; i < 8; ++i) { - Uint4byteToMemLe(tmp, *pd); - PrintAndLogEx(SUCCESS, " %02d | %s | %s", i, sprint_hex_inrow(tmp, sizeof(tmp)), sprint_ascii(tmp, 4)); - pd++; - } - PrintAndLogEx(INFO, ""); - PrintAndLogEx(SUCCESS, " " _CYAN_("Page 1")); - PrintAndLogEx(SUCCESS, "----+----------+-------"); - PrintAndLogEx(SUCCESS, "blk | hex data | ascii"); - PrintAndLogEx(SUCCESS, "----+----------+-------"); - for (uint8_t i = 0; i < 4; i++) { - Uint4byteToMemLe(tmp, *pd); - PrintAndLogEx(SUCCESS, " %02d | %s | %s", i, sprint_hex_inrow(tmp, sizeof(tmp)), sprint_ascii(tmp, 4)); - pd++; - } - PrintAndLogEx(NORMAL, ""); - free(dump); - return PM3_SUCCESS; -} - static command_t CommandTable[] = { {"-----------", CmdHelp, AlwaysAvailable, "---------------------------- " _CYAN_("notice") " -----------------------------"}, {"", CmdHelp, AlwaysAvailable, "Remember to run `" _YELLOW_("lf t55xx detect") "` first whenever a new card"}, @@ -4782,7 +4714,6 @@ static command_t CommandTable[] = { {"restore", CmdT55xxRestore, IfPm3Lf, "Restore T55xx card Page 0 / Page 1 blocks"}, {"trace", CmdT55xxReadTrace, AlwaysAvailable, "Show T55x7 traceability data (page 1/ blk 0-1)"}, {"wakeup", CmdT55xxWakeUp, IfPm3Lf, "Send AOR wakeup command"}, - {"view", CmdT55xxView, AlwaysAvailable, "Display content from tag dump file"}, {"write", CmdT55xxWriteBlock, IfPm3Lf, "Write T55xx block data"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"}, {"bruteforce", CmdT55xxBruteForce, IfPm3Lf, "Simple bruteforce attack to find password"}, diff --git a/client/src/cmdlfti.c b/client/src/cmdlfti.c index 17d843a7c..4664a344d 100644 --- a/client/src/cmdlfti.c +++ b/client/src/cmdlfti.c @@ -325,7 +325,7 @@ static int CmdTIReader(const char *Cmd) { do { clearCommandBuffer(); SendCommandNG(CMD_LF_TI_READ, NULL, 0); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfviking.c b/client/src/cmdlfviking.c index 7c206af4b..83f34862a 100644 --- a/client/src/cmdlfviking.c +++ b/client/src/cmdlfviking.c @@ -102,7 +102,7 @@ static int CmdVikingReader(const char *Cmd) { do { lf_read(false, 10000); demodViking(true); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } @@ -172,7 +172,7 @@ static int CmdVikingClone(const char *Cmd) { SendCommandNG(CMD_LF_VIKING_CLONE, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_LF_VIKING_CLONE, &resp, T55XX_WRITE_TIMEOUT) == false) { + if (!WaitForResponseTimeout(CMD_LF_VIKING_CLONE, &resp, T55XX_WRITE_TIMEOUT)) { PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation."); return PM3_ETIMEOUT; } diff --git a/client/src/cmdlfvisa2000.c b/client/src/cmdlfvisa2000.c index 092f38e30..7de1e9334 100644 --- a/client/src/cmdlfvisa2000.c +++ b/client/src/cmdlfvisa2000.c @@ -185,7 +185,7 @@ static int CmdVisa2kReader(const char *Cmd) { do { lf_read(false, 20000); demodVisa2k(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdlfzx8211.c b/client/src/cmdlfzx8211.c index 793cc3d54..03fcd6053 100644 --- a/client/src/cmdlfzx8211.c +++ b/client/src/cmdlfzx8211.c @@ -138,7 +138,7 @@ static int CmdzxReader(const char *Cmd) { do { lf_Zx_read(); demodzx(!cm); - } while (cm && (kbd_enter_pressed() == false)); + } while (cm && !kbd_enter_pressed()); return PM3_SUCCESS; } diff --git a/client/src/cmdmain.c b/client/src/cmdmain.c index 9ab88324b..25bf6cce8 100644 --- a/client/src/cmdmain.c +++ b/client/src/cmdmain.c @@ -48,7 +48,6 @@ #include "commonutil.h" // ARRAYLEN #include "preferences.h" #include "cliparser.h" -#include "cmdmqtt.h" static int CmdHelp(const char *Cmd); @@ -339,7 +338,6 @@ static command_t CommandTable[] = { {"hw", CmdHW, AlwaysAvailable, "{ Hardware commands... }"}, {"lf", CmdLF, AlwaysAvailable, "{ Low frequency commands... }"}, {"mem", CmdFlashMem, IfPm3Flash, "{ Flash memory manipulation... }"}, - {"mqtt", CmdMqtt, AlwaysAvailable, "{ MQTT commmands... }"}, {"nfc", CmdNFC, AlwaysAvailable, "{ NFC commands... }"}, {"piv", CmdPIV, AlwaysAvailable, "{ PIV commands... }"}, {"reveng", CmdRev, AlwaysAvailable, "{ CRC calculations from RevEng software... }"}, diff --git a/client/src/cmdmqtt.c b/client/src/cmdmqtt.c deleted file mode 100644 index 1a0ea15ae..000000000 --- a/client/src/cmdmqtt.c +++ /dev/null @@ -1,422 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// See LICENSE.txt for the text of the license. -//----------------------------------------------------------------------------- -// MQTT commands -//----------------------------------------------------------------------------- -#include "cmdmqtt.h" - -#include "cmdparser.h" -#include "cliparser.h" -#include "mqtt.h" // MQTT support -//#include "mbedtls_sockets.h" // MQTT networkings examples - -#ifndef _WIN32 -#include "posix_sockets.h" // MQTT networkings examples -#else -#include "win32_sockets.h" // MQTT networkings examples -#endif -#include "util_posix.h" // time -#include "fileutils.h" - -#define MQTT_BUFFER_SIZE ( 1 << 16 ) - -static int CmdHelp(const char *Cmd); - -static void mqtt_publish_callback(void **unused, struct mqtt_response_publish *published) { - - if (published == NULL) { - return; - } - - - // note that published->topic_name is NOT null-terminated (here we'll change it to a c-string) - char *topic_name = (char *) calloc(published->topic_name_size + 1, 1); - memcpy(topic_name, published->topic_name, published->topic_name_size); - - const char *msg = published->application_message; - - char *ps = strstr(msg, "Created\": \"proxmark3"); - if (ps) { - int res = saveFileTXT("ice_mqtt", ".json", msg, published->application_message_size, spDefault); - if (res == PM3_SUCCESS) { - PrintAndLogEx(INFO, "Got a json file ( %s )", _GREEN_("ok")); - } - } else { - PrintAndLogEx(SUCCESS, _GREEN_("%s") " - ( %zu ) " _YELLOW_("%s"), topic_name, published->application_message_size, msg); - } - free(topic_name); -} - -static volatile int mqtt_client_should_exit = 0; - -static void *mqtt_client_refresher(void *client) { - while (!mqtt_client_should_exit) { - mqtt_sync((struct mqtt_client *) client); - msleep(100); - } - return NULL; -} -static int mqtt_exit(int status, mqtt_pal_socket_handle sockfd, pthread_t *client_daemon) { - close_nb_socket(sockfd); - if (client_daemon != NULL) { - mqtt_client_should_exit = 1; - pthread_join(*client_daemon, NULL); // Wait for the thread to finish - mqtt_client_should_exit = 0; - } - return status; -} - -/* -static void mqtt_reconnect_client(struct mqtt_client* client, void **reconnect_state_vptr) { - - struct reconnect_state_t *rs = *((struct reconnect_state_t**) reconnect_state_vptr); - - // Close the clients socket if this isn't the initial reconnect call - if (client->error != MQTT_ERROR_INITIAL_RECONNECT) { - close_nb_socket(client->socketfd); - } - - if (client->error != MQTT_ERROR_INITIAL_RECONNECT) { - PrintAndLogEx(INFO, "reconnect_client: called while client was in error state `%s`", mqtt_error_str(client->error)); - } - - int sockfd = open_nb_socket(rs->hostname, rs->port); - if (sockfd == -1) { - PrintAndLogEx(FAILED, "Failed to open socket"); - mqtt_exit(PM3_EFAILED, sockfd, NULL); - } - - // Reinitialize the client. - mqtt_reinit(client, sockfd, rs->sendbuf, rs->sendbufsz, rs->recvbuf, rs->recvbufsz); - - const char* client_id = NULL; - - uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION; - - mqtt_connect(client, client_id, NULL, NULL, 0, NULL, NULL, connect_flags, 400); - - mqtt_subscribe(client, rs->topic, 0); -} -*/ - -static int mqtt_receive(const char *addr, const char *port, const char *topic, const char *fn) { - // open the non-blocking TCP socket (connecting to the broker) - mqtt_pal_socket_handle sockfd = open_nb_socket(addr, port); - if (sockfd == -1) { - PrintAndLogEx(FAILED, "Failed to open socket"); - return mqtt_exit(PM3_EFAILED, sockfd, NULL); - } - - uint8_t sendbuf[MQTT_BUFFER_SIZE]; // 64kb sendbuf should be large enough to hold multiple whole mqtt messages - uint8_t recvbuf[MQTT_BUFFER_SIZE]; // 64kb recvbuf should be large enough any whole mqtt message expected to be received - - struct mqtt_client client; - - /* - struct reconnect_state_t rs; - rs.hostname = addr; - rs.port = port; - rs.topic = topic; - rs.sendbuf = sendbuf; - rs.sendbufsz = sizeof(sendbuf); - rs.recvbuf = recvbuf; - rs.recvbufsz = sizeof(recvbuf); - mqtt_init_reconnect(&client, mqtt_reconnect_client, &rs, mqtt_publish_callback); - */ - - mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), mqtt_publish_callback); - - char cid[20] = "pm3_"; - sprintf(cid + strlen(cid), "%02x%02x%02x%02x" - , rand() % 0xFF - , rand() % 0xFF - , rand() % 0xFF - , rand() % 0xFF - ); - - // Ensure we have a clean session - uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION; - // Send connection request to the broker - mqtt_connect(&client, cid, NULL, NULL, 0, NULL, NULL, connect_flags, 400); - - // check that we don't have any errors - if (client.error != MQTT_OK) { - PrintAndLogEx(FAILED, "error: %s", mqtt_error_str(client.error)); - return mqtt_exit(PM3_ESOFT, sockfd, NULL); - } - - // start a thread to refresh the client (handle egress and ingree client traffic) - pthread_t client_daemon; - if (pthread_create(&client_daemon, NULL, mqtt_client_refresher, &client)) { - PrintAndLogEx(FAILED, "Failed to start client daemon"); - return mqtt_exit(PM3_ESOFT, sockfd, NULL); - } - - // subscribe to a topic with a max QoS level of 0 - mqtt_subscribe(&client, topic, 0); - - PrintAndLogEx(INFO, _CYAN_("%s") " listening at " _CYAN_("%s:%s/%s"), cid, addr, port, topic); - PrintAndLogEx(INFO, "Press " _GREEN_("") " to exit"); - - while (kbd_enter_pressed() == false) { - msleep(2000); - }; - - PrintAndLogEx(INFO, _CYAN_("%s") " disconnecting from " _CYAN_("%s"), cid, addr); - return mqtt_exit(PM3_SUCCESS, sockfd, &client_daemon); -} - -static int mqtt_send(const char *addr, const char *port, const char *topic, char *msg, const char *fn) { - - uint8_t *data; - size_t bytes_read = 0; - if (fn != NULL) { - int res = loadFile_TXTsafe(fn, "", (void **)&data, &bytes_read, true); - if (res != PM3_SUCCESS) { - return res; - } - } - - // open the non-blocking TCP socket (connecting to the broker) - int sockfd = open_nb_socket(addr, port); - - if (sockfd == -1) { - PrintAndLogEx(FAILED, "Failed to open socket"); - return mqtt_exit(PM3_EFAILED, sockfd, NULL); - } - - struct mqtt_client client; - uint8_t sendbuf[MQTT_BUFFER_SIZE]; - uint8_t recvbuf[MQTT_BUFFER_SIZE]; - mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), mqtt_publish_callback); - - char cid[20] = "pm3_"; - sprintf(cid + strlen(cid), "%02x%02x%02x%02x" - , rand() % 0xFF - , rand() % 0xFF - , rand() % 0xFF - , rand() % 0xFF - ); - - // Ensure we have a clean session - uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION; - // Send connection request to the broker - mqtt_connect(&client, cid, NULL, NULL, 0, NULL, NULL, connect_flags, 400); - - // check that we don't have any errors - if (client.error != MQTT_OK) { - PrintAndLogEx(FAILED, "error: %s", mqtt_error_str(client.error)); - mqtt_exit(PM3_EFAILED, sockfd, NULL); - } - - // start a thread to refresh the client (handle egress and ingree client traffic) - pthread_t client_daemon; - if (pthread_create(&client_daemon, NULL, mqtt_client_refresher, &client)) { - PrintAndLogEx(FAILED, "Failed to start client daemon"); - mqtt_exit(PM3_EFAILED, sockfd, NULL); - - } - - PrintAndLogEx(INFO, _CYAN_("%s") " is ready", cid); - - if (fn != NULL) { - PrintAndLogEx(INFO, "Publishing file..."); - mqtt_publish(&client, topic, data, bytes_read, MQTT_PUBLISH_QOS_0); - } else { - PrintAndLogEx(INFO, "Publishing message..."); - mqtt_publish(&client, topic, msg, strlen(msg) + 1, MQTT_PUBLISH_QOS_0); - } - - if (client.error != MQTT_OK) { - PrintAndLogEx(INFO, "error: %s", mqtt_error_str(client.error)); - mqtt_exit(PM3_ESOFT, sockfd, &client_daemon); - } - - msleep(4000); - - PrintAndLogEx(INFO, _CYAN_("%s") " disconnecting from " _CYAN_("%s"), cid, addr); - return mqtt_exit(PM3_SUCCESS, sockfd, &client_daemon); -} - -static int CmdMqttSend(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "mqtt send", - "This command send MQTT messages. You can send JSON file\n" - "Default server: proxdump.com:1883 topic: proxdump\n", - "mqtt send --msg \"Hello from Pm3\" --> sending msg to default server/port/topic\n" - "mqtt send -f myfile.json --> sending file to default server/port/topic\n" - "mqtt send --addr test.mosquitto.org -p 1883 --topic pm3 --msg \"custom mqtt server \"\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str0(NULL, "addr", "", "MQTT server address"), - arg_str0("p", "port", "", "MQTT server port"), - arg_str0(NULL, "topic", "", "MQTT topic"), - arg_str0(NULL, "msg", "", "Message to send over MQTT"), - arg_str0("f", "file", "", "file to send"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, false); - - int alen = 0; - char addr[256] = {0x00}; - int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)addr, sizeof(addr), &alen); - - int plen = 0; - char port[10 + 1] = {0x00}; - res = CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)port, sizeof(port), &plen); - - int tlen = 0; - char topic[128] = {0x00}; - res = CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)topic, sizeof(topic), &tlen); - - int mlen = 0; - char msg[128] = {0x00}; - res = CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)msg, sizeof(msg), &mlen); - - int fnlen = 0; - char filename[FILE_PATH_SIZE] = {0}; - CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); - - CLIParserFree(ctx); - - // Error message if... an error occured. - if (res) { - PrintAndLogEx(FAILED, "Error parsing input strings"); - return PM3_EINVARG; - } - - if (alen == 0) { - if (strlen(g_session.mqtt_server)) { - strcpy(addr, g_session.mqtt_server); - } else { - strcpy(addr, "proxdump.com"); - } - } - - if (plen == 0) { - if (strlen(g_session.mqtt_port)) { - strcpy(port, g_session.mqtt_port); - } else { - strcpy(port, "1883"); - } - } - - if (tlen == 0) { - if (strlen(g_session.mqtt_topic)) { - strcpy(topic, g_session.mqtt_topic); - } else { - strcpy(topic, "proxdump"); - } - } - - if (fnlen) { - return mqtt_send(addr, port, topic, NULL, filename); - } - - if (mlen) { - return mqtt_send(addr, port, topic, msg, NULL); - } - return PM3_SUCCESS; -} - -static int CmdMqttReceive(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "mqtt receive", - "This command receives MQTT messages. JSON text will be saved to file if detected\n" - "Default server: proxdump.com:1883 topic: proxdump\n", - "mqtt receive --> listening to default server/port/topic\n" - "mqtt receive --addr test.mosquitto.org -p 1883 --topic pm3\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str0(NULL, "addr", "", "MQTT server address"), - arg_str0("p", "port", "", "MQTT server port"), - arg_str0(NULL, "topic", "", "MQTT topic"), - arg_str0("f", "file", "", "file name to use for received files"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - - int alen = 0; - char addr[256] = {0x00}; - int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)addr, sizeof(addr), &alen); - - int plen = 0; - char port[10 + 1] = {0x00}; - res = CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)port, sizeof(port), &plen); - - int tlen = 0; - char topic[128] = {0x00}; - res = CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)topic, sizeof(topic), &tlen); - - int fnlen = 0; - char filename[FILE_PATH_SIZE] = {0}; - CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); - - CLIParserFree(ctx); - - // Error message if... an error occured. - if (res) { - PrintAndLogEx(FAILED, "Error parsing input strings"); - return PM3_EINVARG; - } - - if (alen == 0) { - if (strlen(g_session.mqtt_server)) { - strcpy(addr, g_session.mqtt_server); - } else { - strcpy(addr, "proxdump.com"); - } - } - - if (plen == 0) { - if (strlen(g_session.mqtt_port)) { - strcpy(port, g_session.mqtt_port); - } else { - strcpy(port, "1883"); - } - } - - if (tlen == 0) { - if (strlen(g_session.mqtt_topic)) { - strcpy(topic, g_session.mqtt_topic); - } else { - strcpy(topic, "proxdump"); - } - } - - return mqtt_receive(addr, port, topic, filename); -} - -static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"send", CmdMqttSend, AlwaysAvailable, "Send messages or json file over MQTT"}, - {"receive", CmdMqttReceive, AlwaysAvailable, "Receive message or json file over MQTT"}, - {NULL, NULL, NULL, NULL} -}; - -static int CmdHelp(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdsHelp(CommandTable); - return 0; -} - -int CmdMqtt(const char *Cmd) { - clearCommandBuffer(); - return CmdsParse(CommandTable, Cmd); -} diff --git a/client/src/cmdmqtt.h b/client/src/cmdmqtt.h deleted file mode 100644 index fad58ff8f..000000000 --- a/client/src/cmdmqtt.h +++ /dev/null @@ -1,26 +0,0 @@ -//----------------------------------------------------------------------------- -// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// See LICENSE.txt for the text of the license. -//----------------------------------------------------------------------------- -// MQTT commands -//----------------------------------------------------------------------------- - -#ifndef CMDMQTT_H__ -#define CMDMQTT_H__ - -#include "common.h" - -int CmdMqtt(const char *Cmd); - -#endif diff --git a/client/src/cmdparser.c b/client/src/cmdparser.c index fc628b947..7421b3f58 100644 --- a/client/src/cmdparser.c +++ b/client/src/cmdparser.c @@ -20,15 +20,11 @@ #include #include -#include // spinlock -#include // system + #include "ui.h" #include "comms.h" #include "util_posix.h" // msleep -#if defined(__MACH__) && defined(__APPLE__) -# include "pthread_spin_lock_shim.h" // spinlock shim for OSX .. -#endif #define MAX_PM3_INPUT_ARGS_LENGTH 4096 @@ -223,30 +219,6 @@ void CmdsHelp(const command_t Commands[]) { PrintAndLogEx(NORMAL, ""); } -static int execute_system_command(const char *command) { - - pthread_spinlock_t sycmd_spinlock; - pthread_spin_init(&sycmd_spinlock, 0); - pthread_spin_lock(&sycmd_spinlock); - - int ret; - -#if defined(_WIN32) - char wrapped_command[255]; - strncat(wrapped_command, "cmd /C \"", 9); - strncat(wrapped_command, command, strlen(command)); - strncat(wrapped_command, "\"", 2); - - ret = system(wrapped_command); -#else - ret = system(command); -#endif - pthread_spin_unlock(&sycmd_spinlock); - pthread_spin_destroy(&sycmd_spinlock); - return ret; -} - - int CmdsParse(const command_t Commands[], const char *Cmd) { if (g_session.client_exe_delay != 0) { @@ -295,9 +267,6 @@ int CmdsParse(const command_t Commands[], const char *Cmd) { return PM3_SUCCESS; } - if (Cmd[0] == '!') { - return execute_system_command(Cmd + 1); - } char cmd_name[128] = {0}; memset(cmd_name, 0, sizeof(cmd_name)); @@ -318,9 +287,8 @@ int CmdsParse(const command_t Commands[], const char *Cmd) { } // Comment - if (cmd_name[0] == '#') { + if (cmd_name[0] == '#') return PM3_SUCCESS; - } // find args, check for -h / --help int tmplen = len; diff --git a/client/src/cmdsmartcard.c b/client/src/cmdsmartcard.c index 6e1c67ba5..ed515a04a 100644 --- a/client/src/cmdsmartcard.c +++ b/client/src/cmdsmartcard.c @@ -663,7 +663,7 @@ static int CmdSmartUpgrade(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_SMART_UPLOAD, (uint8_t *)&upload, sizeof(upload)); - if (WaitForResponseTimeout(CMD_SMART_UPLOAD, &resp, 2000) == false) { + if (!WaitForResponseTimeout(CMD_SMART_UPLOAD, &resp, 2000)) { PrintAndLogEx(WARNING, "timeout while waiting for reply"); free(firmware); return PM3_ETIMEOUT; @@ -695,7 +695,7 @@ static int CmdSmartUpgrade(const char *Cmd) { free(firmware); SendCommandNG(CMD_SMART_UPGRADE, (uint8_t *)&payload, sizeof(payload)); - if (WaitForResponseTimeout(CMD_SMART_UPGRADE, &resp, 2500) == false) { + if (!WaitForResponseTimeout(CMD_SMART_UPGRADE, &resp, 2500)) { PrintAndLogEx(WARNING, "timeout while waiting for reply"); return PM3_ETIMEOUT; } @@ -876,7 +876,7 @@ static int CmdSmartSetClock(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_SMART_SETCLOCK, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_SMART_SETCLOCK, &resp, 2500) == false) { + if (!WaitForResponseTimeout(CMD_SMART_SETCLOCK, &resp, 2500)) { PrintAndLogEx(WARNING, "smart card select failed"); return PM3_ETIMEOUT; } @@ -1469,7 +1469,7 @@ static int CmdPCSC(const char *Cmd) { msleep(300); } - } while (kbd_enter_pressed() == false); + } while (!kbd_enter_pressed()); mbedtls_net_close(&netCtx); mbedtls_net_free(&netCtx); diff --git a/client/src/cmdtrace.c b/client/src/cmdtrace.c index 0f3242345..0e83bf128 100644 --- a/client/src/cmdtrace.c +++ b/client/src/cmdtrace.c @@ -181,7 +181,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t } */ - // extract UL-C KEY when written. + // extract MFU-C KEY when written. switch (frame[0]) { case MIFARE_ULC_AUTH_1: { diff --git a/client/src/cmdusart.c b/client/src/cmdusart.c index b3e2bdc5d..357d20c32 100644 --- a/client/src/cmdusart.c +++ b/client/src/cmdusart.c @@ -35,7 +35,7 @@ static int usart_tx(uint8_t *data, size_t len) { clearCommandBuffer(); SendCommandNG(CMD_USART_TX, data, len); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_USART_TX, &resp, 1000) == false) { + if (!WaitForResponseTimeout(CMD_USART_TX, &resp, 1000)) { return PM3_ETIMEOUT; } return resp.status; @@ -49,7 +49,7 @@ static int usart_rx(uint8_t *data, size_t *len, uint32_t waittime) { payload.waittime = waittime; SendCommandNG(CMD_USART_RX, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_USART_RX, &resp, waittime + 500) == false) { + if (!WaitForResponseTimeout(CMD_USART_RX, &resp, waittime + 500)) { return PM3_ETIMEOUT; } if (resp.status == PM3_SUCCESS) { @@ -99,7 +99,7 @@ static int set_usart_config(uint32_t baudrate, uint8_t parity) { payload.parity = parity; SendCommandNG(CMD_USART_CONFIG, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_USART_CONFIG, &resp, 1000) == false) { + if (!WaitForResponseTimeout(CMD_USART_CONFIG, &resp, 1000)) { return PM3_ETIMEOUT; } return resp.status; diff --git a/client/src/cmdwiegand.c b/client/src/cmdwiegand.c index c2d6bb3b1..d29521d53 100644 --- a/client/src/cmdwiegand.c +++ b/client/src/cmdwiegand.c @@ -201,7 +201,7 @@ int CmdWiegandDecode(const char *Cmd) { PrintAndLogEx(ERR, "Binary string contains none <0|1> chars"); return PM3_EINVARG; } - PrintAndLogEx(INFO, "#bits... %d", blen); + PrintAndLogEx(INFO, "Input bin len... %d", blen); } else if (plen) { diff --git a/client/src/comms.c b/client/src/comms.c index 2ded55ebc..e2684100f 100644 --- a/client/src/comms.c +++ b/client/src/comms.c @@ -871,7 +871,7 @@ int TestProxmark(pm3_device_t *dev) { #endif PacketResponseNG resp; - if (WaitForResponseTimeoutW(CMD_PING, &resp, timeout, false) == false) { + if (WaitForResponseTimeoutW(CMD_PING, &resp, timeout, false) == 0) { return PM3_ETIMEOUT; } @@ -881,7 +881,7 @@ int TestProxmark(pm3_device_t *dev) { } SendCommandNG(CMD_CAPABILITIES, NULL, 0); - if (WaitForResponseTimeoutW(CMD_CAPABILITIES, &resp, 1000, false) == false) { + if (WaitForResponseTimeoutW(CMD_CAPABILITIES, &resp, 1000, false) == 0) { return PM3_ETIMEOUT; } diff --git a/client/src/crypto/libpcrypto.c b/client/src/crypto/libpcrypto.c index 9d506d8a8..031005ce0 100644 --- a/client/src/crypto/libpcrypto.c +++ b/client/src/crypto/libpcrypto.c @@ -55,15 +55,13 @@ void des_decrypt(void *out, const void *in, const void *key) { } void des_encrypt_ecb(void *out, const void *in, const int length, const void *key) { - for (int i = 0; i < length; i += 8) { + for (int i = 0; i < length; i += 8) des_encrypt((uint8_t *)out + i, (uint8_t *)in + i, key); - } } void des_decrypt_ecb(void *out, const void *in, const int length, const void *key) { - for (int i = 0; i < length; i += 8) { + for (int i = 0; i < length; i += 8) des_decrypt((uint8_t *)out + i, (uint8_t *)in + i, key); - } } void des_encrypt_cbc(void *out, const void *in, const int length, const void *key, uint8_t *iv) { @@ -163,45 +161,6 @@ int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int l return PM3_SUCCESS; } -// NIST Special Publication 800-38A — Recommendation for block cipher modes of operation: methods and techniques, 2001. -int aes256_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) { - uint8_t iiv[16] = {0}; - if (iv) { - memcpy(iiv, iv, sizeof(iiv)); - } - - mbedtls_aes_context aes; - mbedtls_aes_init(&aes); - if (mbedtls_aes_setkey_enc(&aes, key, 256)) { - return 1; - } - if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_ENCRYPT, length, iiv, input, output)) { - return 2; - } - mbedtls_aes_free(&aes); - return PM3_SUCCESS; -} - - -int aes256_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length) { - uint8_t iiv[16] = {0}; - if (iv) { - memcpy(iiv, iv, 16); - } - - mbedtls_aes_context aes; - mbedtls_aes_init(&aes); - if (mbedtls_aes_setkey_dec(&aes, key, 256)) { - return 1; - } - if (mbedtls_aes_crypt_cbc(&aes, MBEDTLS_AES_DECRYPT, length, iiv, input, output)) { - return 2; - } - mbedtls_aes_free(&aes); - return PM3_SUCCESS; -} - - // NIST Special Publication 800-38B — Recommendation for block cipher modes of operation: The CMAC mode for authentication. // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/AES_CMAC.pdf int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length) { diff --git a/client/src/crypto/libpcrypto.h b/client/src/crypto/libpcrypto.h index 7b086bf33..5d10b10ee 100644 --- a/client/src/crypto/libpcrypto.h +++ b/client/src/crypto/libpcrypto.h @@ -38,10 +38,6 @@ void des3_decrypt(void *out, const void *in, const void *key, uint8_t keycount); int aes_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); int aes_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); - -int aes256_encode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); -int aes256_decode(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *output, int length); - int aes_cmac(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); int aes_cmac8(uint8_t *iv, uint8_t *key, uint8_t *input, uint8_t *mac, int length); diff --git a/client/src/crypto/originality.c b/client/src/crypto/originality.c index e0dfe1f9c..6b6e687a0 100644 --- a/client/src/crypto/originality.c +++ b/client/src/crypto/originality.c @@ -59,12 +59,6 @@ const ecdsa_publickey_ng_t manufacturer_public_keys[] = { "04DC34DAA903F2726A6225B11C692AF6AB4396575CA12810CBBCE3F781A097B3833B50AB364A70D9C2B641A728A599AE74" }, - // ref: AN12998 NTAG 22x DNA (StatusDetect) - Features and hints - { - PK_MFUL, MBEDTLS_ECP_DP_SECP192R1, 49, "NXP NTAG 22x DNA", - "0485D5B9353B4FAA77581BA2AE96630C5876D6E8603308ABE9A81A0B506F52D02D04FEE6F2D365B3DEE7B9FAD9133E2976" - }, - { PK_MFP, MBEDTLS_ECP_DP_SECP224R1, 57, "MIFARE Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E" diff --git a/client/src/emv/emvcore.c b/client/src/emv/emvcore.c index b663af706..b2aa524ac 100644 --- a/client/src/emv/emvcore.c +++ b/client/src/emv/emvcore.c @@ -484,7 +484,7 @@ int EMVSearch(Iso7816CommandChannel channel, bool ActivateField, bool LeaveField for (int i = 0; i < ARRAYLEN(AIDlist); i ++) { if (kbd_enter_pressed()) { - PrintAndLogEx(WARNING, "\naborted via keyboard!"); + PrintAndLogEx(INFO, "user aborted..."); break; } diff --git a/client/src/fileutils.c b/client/src/fileutils.c index 1cbe50fba..128826c10 100644 --- a/client/src/fileutils.c +++ b/client/src/fileutils.c @@ -72,7 +72,9 @@ DumpFileType_t get_filetype(const char *filename) { size_t len = strlen(filename); if (len > 4) { // check if valid file extension and attempt to load data - char *s = str_dup(filename); + char s[FILE_PATH_SIZE]; + memset(s, 0, sizeof(s)); + memcpy(s, filename, len); str_lower(s); if (str_endswith(s, "bin")) { @@ -89,16 +91,12 @@ DumpFileType_t get_filetype(const char *filename) { o = FLIPPER; } else if (str_endswith(s, "picopass")) { o = FLIPPER; - } else if (str_endswith(s, "xml")) { - o = TAGINFO; } else { // mfd, trc, trace is binary o = BIN; // log is text // .pm3 is text values of signal data } - - free(s); } return o; } @@ -167,7 +165,6 @@ static char *filenamemcopy(const char *preferredName, const char *suffix) { char *fileName = (char *) calloc(strlen(preferredName) + strlen(suffix) + 1, sizeof(uint8_t)); if (fileName == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); return NULL; } @@ -280,7 +277,7 @@ int saveFileEx(const char *preferredName, const char *suffix, const void *data, // Opening file for writing in binary mode FILE *f = fopen(fileName, "wb"); - if (f == NULL) { + if (!f) { PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName); free(fileName); return PM3_EFILE; @@ -293,33 +290,6 @@ int saveFileEx(const char *preferredName, const char *suffix, const void *data, return PM3_SUCCESS; } -int saveFileTXT(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path) { - if (data == NULL || datalen == 0) { - return PM3_EINVARG; - } - - char *fileName = newfilenamemcopyEx(preferredName, suffix, e_save_path); - if (fileName == NULL) { - return PM3_EMALLOC; - } - - // We should have a valid filename now, e.g. dumpdata-3.txt - - // Opening file for writing in text mode - FILE *f = fopen(fileName, "w"); - if (f == NULL) { - PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", fileName); - free(fileName); - return PM3_EFILE; - } - fwrite(data, 1, datalen, f); - fflush(f); - fclose(f); - PrintAndLogEx(SUCCESS, "Saved " _YELLOW_("%zu") " bytes to text file `" _YELLOW_("%s") "`", datalen, fileName); - free(fileName); - return PM3_SUCCESS; -} - int prepareJSON(json_t *root, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *)) { if (ftype != jsfCustom) { if (data == NULL || datalen == 0) { @@ -823,9 +793,8 @@ int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool v } int saveFileJSONrootEx(const char *preferredName, const void *root, size_t flags, bool verbose, bool overwrite, savePaths_t e_save_path) { - if (root == NULL) { + if (root == NULL) return PM3_EINVARG; - } char *filename = NULL; if (overwrite) @@ -977,7 +946,7 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, const sector } for (int i = 0; i < sectorsCnt; i++) { - if (e_sector[i].foundKey[1]) + if (e_sector[i].foundKey[0]) num_to_bytes(e_sector[i].Key[1], sizeof(tmp), tmp); else memcpy(tmp, empty, sizeof(tmp)); @@ -1005,7 +974,7 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, } FILE *f = fopen(path, "rb"); - if (f == NULL) { + if (!f) { PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); free(path); return PM3_EFILE; @@ -1024,8 +993,8 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, } *pdata = calloc(fsize, sizeof(uint8_t)); - if (*pdata == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); + if (!*pdata) { + PrintAndLogEx(FAILED, "error, cannot allocate memory"); fclose(f); return PM3_EMALLOC; } @@ -1048,58 +1017,6 @@ int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, return PM3_SUCCESS; } -int loadFile_TXTsafe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose) { - - char *path; - int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, suffix, false); - if (res != PM3_SUCCESS) { - return PM3_EFILE; - } - - FILE *f = fopen(path, "r"); - if (f == NULL) { - PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); - free(path); - return PM3_EFILE; - } - free(path); - - // get filesize in order to malloc memory - fseek(f, 0, SEEK_END); - long fsize = ftell(f); - fseek(f, 0, SEEK_SET); - - if (fsize <= 0) { - PrintAndLogEx(FAILED, "error, when getting filesize"); - fclose(f); - return PM3_EFILE; - } - - *pdata = calloc(fsize, sizeof(uint8_t)); - if (*pdata == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); - fclose(f); - return PM3_EMALLOC; - } - - size_t bytes_read = fread(*pdata, 1, fsize, f); - - fclose(f); - - if (bytes_read != fsize) { - PrintAndLogEx(FAILED, "error, bytes read mismatch file size"); - free(*pdata); - return PM3_EFILE; - } - - *datalen = bytes_read; - - if (verbose) { - PrintAndLogEx(SUCCESS, "Loaded " _YELLOW_("%zu") " bytes from text file `" _YELLOW_("%s") "`", bytes_read, preferredName); - } - return PM3_SUCCESS; -} - int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { char *path; int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, "", false); @@ -1127,8 +1044,8 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { } *pdata = calloc(fsize, sizeof(uint8_t)); - if (*pdata == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); + if (!*pdata) { + PrintAndLogEx(FAILED, "error, cannot allocate memory"); fclose(f); return PM3_EMALLOC; } @@ -1174,7 +1091,6 @@ int loadFileEML_safe(const char *preferredName, void **pdata, size_t *datalen) { uint8_t *newdump = realloc(*pdata, counter); if (newdump == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); free(*pdata); return PM3_EMALLOC; } else { @@ -1203,7 +1119,7 @@ int loadFileNFC_safe(const char *preferredName, void *data, size_t maxdatalen, s } FILE *f = fopen(path, "r"); - if (f == NULL) { + if (!f) { PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); free(path); return PM3_EFILE; @@ -1450,8 +1366,8 @@ int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) { } *pdata = calloc(fsize, sizeof(uint8_t)); - if (*pdata == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); + if (!*pdata) { + PrintAndLogEx(FAILED, "error, cannot allocate memory"); fclose(f); return PM3_EMALLOC; } @@ -1498,7 +1414,6 @@ int loadFileMCT_safe(const char *preferredName, void **pdata, size_t *datalen) { uint8_t *newdump = realloc(*pdata, counter); if (newdump == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); free(*pdata); return PM3_EMALLOC; } else { @@ -1528,9 +1443,7 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ } int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, bool verbose, void (*callback)(json_t *)) { - if (data == NULL) { - return PM3_EINVARG; - } + if (data == NULL) return PM3_EINVARG; *datalen = 0; int retval = PM3_SUCCESS; @@ -2305,8 +2218,6 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL, true); } -// this function handles exceptional large dictionaries, -// using start position and end position parameters. int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint32_t *keycnt, size_t startFilePosition, size_t *endFilePosition, bool verbose) { @@ -2332,17 +2243,17 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale int retval = PM3_SUCCESS; FILE *f = fopen(path, "r"); - if (f == NULL) { + if (!f) { PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); - free(path); - return PM3_EFILE; + retval = PM3_EFILE; + goto out; } if (startFilePosition) { if (fseek(f, startFilePosition, SEEK_SET) < 0) { fclose(f); - free(path); - return PM3_EFILE; + retval = PM3_EFILE; + goto out; } } @@ -2350,7 +2261,6 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale // read file while (!feof(f)) { - long filepos = ftell(f); if (!fgets(line, sizeof(line), f)) { @@ -2408,7 +2318,7 @@ int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatale if (keycnt) { *keycnt = vkeycnt; } - +out: free(path); return retval; } @@ -2433,11 +2343,12 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo // mf desfire == 3des3k 24 bytes // iclass == 8 bytes // default to 6 bytes. - if (keylen != 4 && keylen != 5 && keylen != 6 && keylen != 8 && keylen != 12 && keylen != 16 && keylen != 24) { + if (keylen != 4 && keylen != 5 && keylen != 6 && keylen != 8 && keylen != 16 && keylen != 24) { keylen = 6; } - size_t block_size = 1000 * keylen; + size_t mem_size; + size_t block_size = 10 * keylen; // double up since its chars keylen <<= 1; @@ -2447,14 +2358,13 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo // allocate some space for the dictionary *pdata = calloc(block_size, sizeof(uint8_t)); if (*pdata == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); free(path); return PM3_EFILE; } - size_t mem_size = block_size; + mem_size = block_size; FILE *f = fopen(path, "r"); - if (f == NULL) { + if (!f) { PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); retval = PM3_EFILE; goto out; @@ -2467,10 +2377,9 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo if ((*keycnt * (keylen >> 1)) >= mem_size) { mem_size += block_size; - *pdata = realloc(*pdata, mem_size); + if (*pdata == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); retval = PM3_EFILE; fclose(f); goto out; @@ -2486,7 +2395,6 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo // remove newline/linefeed str_cleanrn(line, strlen(line)); - str_trim(line); // smaller keys than expected is skipped if (strlen(line) < keylen) { @@ -2504,7 +2412,6 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo // larger keys than expected is skipped if (strlen(line) > keylen) { - PrintAndLogEx(INFO, "too long line (%zu) ... %s", strlen(line), line); continue; } @@ -2512,9 +2419,10 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo continue; } - int ret = hex_to_bytes(line, (uint8_t *)*pdata + (*keycnt * (keylen >> 1)), keylen >> 1); - if (ret != (keylen >> 1)) { - PrintAndLogEx(INFO, "hex to bytes wrong %i", ret); + if (hex_to_bytes( + line, + (uint8_t *)*pdata + (*keycnt * (keylen >> 1)), + keylen >> 1) != (keylen >> 1)) { continue; } @@ -2533,16 +2441,16 @@ out: return retval; } -int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen, bool verbose) { +int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen) { char *path; int res = searchFile(&path, RESOURCES_SUBDIR, preferredName, suffix, false); if (res != PM3_SUCCESS) { - return PM3_ENOFILE; + return PM3_EFILE; } FILE *f = fopen(path, "rb"); - if (f == NULL) { + if (!f) { PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); free(path); return PM3_EFILE; @@ -2565,7 +2473,7 @@ int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya *keya = calloc(fsize, sizeof(uint8_t)); if (*keya == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); + PrintAndLogEx(FAILED, "error, cannot allocate memory"); fclose(f); free(path); return PM3_EMALLOC; @@ -2575,7 +2483,7 @@ int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya *keyb = calloc(fsize, sizeof(uint8_t)); if (*keyb == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); + PrintAndLogEx(FAILED, "error, cannot allocate memory"); fclose(f); free(*keya); free(path); @@ -2585,9 +2493,7 @@ int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya *blen = fread(*keyb, 1, fsize, f); fclose(f); - if (verbose) { - PrintAndLogEx(SUCCESS, "Loaded binary key file `" _YELLOW_("%s") "`", path); - } + PrintAndLogEx(SUCCESS, "Loaded binary key file `" _YELLOW_("%s") "`", path); free(path); return PM3_SUCCESS; } @@ -2662,7 +2568,7 @@ int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool } FILE *f = fopen(path, "r"); - if (f == NULL) { + if (!f) { PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); free(path); return PM3_EFILE; @@ -2713,10 +2619,6 @@ int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool *dump_type = NFC_DF_14_4A; break; } - if (str_startswith(line, "device type: iso15693")) { - *dump_type = NFC_DF_15; - break; - } if (str_startswith(line, "filetype: flipper picopass device")) { *dump_type = NFC_DF_PICOPASS; break; @@ -2749,8 +2651,6 @@ int detect_nfc_dump_format(const char *preferredName, nfc_df_e *dump_type, bool case NFC_DF_PICOPASS: PrintAndLogEx(INFO, "Detected PICOPASS based dump format"); break; - case NFC_DF_15: - PrintAndLogEx(INFO, "Detected ISO15693 based dump format"); case NFC_DF_UNKNOWN: PrintAndLogEx(WARNING, "Failed to detected dump format"); break; @@ -2763,7 +2663,6 @@ static int convert_plain_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose) mfu_dump_t *mfu = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t)); if (mfu == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); return PM3_EMALLOC; } @@ -2801,7 +2700,6 @@ static int convert_old_mfu_dump(uint8_t **dump, size_t *dumplen, bool verbose) { mfu_dump_t *mfu_dump = (mfu_dump_t *) calloc(sizeof(mfu_dump_t), sizeof(uint8_t)); if (mfu_dump == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); return PM3_EMALLOC; } @@ -2948,7 +2846,6 @@ static int searchFinalFile(char **foundpath, const char *pm3dir, const char *sea // explicit absolute (/) or relative path (./) => try only to match it directly char *filename = calloc(strlen(searchname) + 1, sizeof(char)); if (filename == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); return PM3_EMALLOC; } @@ -3134,22 +3031,18 @@ out: int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix, bool silent) { - if (foundpath == NULL) { + if (foundpath == NULL) return PM3_EINVARG; - } - if (searchname == NULL || strlen(searchname) == 0) { + if (searchname == NULL || strlen(searchname) == 0) return PM3_EINVARG; - } - if (is_directory(searchname)) { + if (is_directory(searchname)) return PM3_EINVARG; - } char *filename = filenamemcopy(searchname, suffix); - if (filename == NULL) { + if (filename == NULL) return PM3_EMALLOC; - } if (strlen(filename) == 0) { free(filename); @@ -3166,82 +3059,6 @@ int searchFile(char **foundpath, const char *pm3dir, const char *searchname, con return res; } -/** - * Inserts a line into a text file only if it does not already exist. - * Returns PM3_SUCCES or, PM3_EFILE; - * - * @param filepath Path to the file. - * @param line Line to insert (should not contain a trailing newline). - */ -int insert_line_if_not_exists(const char *preferredName, const char *keystr) { - - char *path; - int res = searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false); - if (res != PM3_SUCCESS) { - return PM3_EFILE; - } - - FILE *f = fopen(path, "r"); - if (f == NULL) { - PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); - free(path); - return PM3_EFILE; - } - - // Maximum line length we assume (adjust as necessary for your use case) - char line[255]; - bool key_exists = false; - - char *keystrdup = str_dup(keystr); - str_upper(keystrdup); - - // First pass: check if the line exists - while (fgets(line, sizeof(line), f)) { - - // The line start with # is comment, skip - if (line[0] == '#') { - continue; - } - - // Remove trailing newline for comparison - line[strcspn(line, "\n")] = '\0'; - - // UPPER CASE - str_upper(line); - - key_exists = str_startswith(line, keystrdup); - if (key_exists) { - fclose(f); - free(path); - PrintAndLogEx(INFO, "already in there..."); - return PM3_SUCCESS; - } - } - - fclose(f); - - - // Reopen for appending if line doesn't exist - f = fopen(path, "a"); - if (f == NULL) { - PrintAndLogEx(WARNING, "file not found or locked `" _YELLOW_("%s") "`", path); - free(path); - return PM3_EFILE; - } - - free(path); - - // Append the line with a newline - if (fprintf(f, "%s\n", keystrdup) < 0) { - PrintAndLogEx(WARNING, "error writing to file"); - fclose(f); - return PM3_EFILE; - } - - fclose(f); - return PM3_SUCCESS; -} - int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumplen) { int res = PM3_SUCCESS; @@ -3264,7 +3081,7 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl case JSON: { *pdump = calloc(maxdumplen, sizeof(uint8_t)); if (*pdump == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); + PrintAndLogEx(WARNING, "fail, cannot allocate memory"); return PM3_EMALLOC; } @@ -3300,11 +3117,11 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl break; } - if (dumptype == NFC_DF_MFC || dumptype == NFC_DF_MFU || dumptype == NFC_DF_PICOPASS || dumptype == NFC_DF_15) { + if (dumptype == NFC_DF_MFC || dumptype == NFC_DF_MFU || dumptype == NFC_DF_PICOPASS) { *pdump = calloc(maxdumplen, sizeof(uint8_t)); if (*pdump == NULL) { - PrintAndLogEx(WARNING, "Failed to allocate memory"); + PrintAndLogEx(WARNING, "Fail, cannot allocate memory"); return PM3_EMALLOC; } res = loadFileNFC_safe(fn, *pdump, maxdumplen, dumplen, dumptype); @@ -3325,10 +3142,6 @@ int pm3_load_dump(const char *fn, void **pdump, size_t *dumplen, size_t maxdumpl } break; } - case TAGINFO: { - //res = loadFileXML_safe(fn, ".xml", pdump, dumplen); - break; - } } return res; } @@ -3341,7 +3154,6 @@ int pm3_save_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft) { PrintAndLogEx(INFO, "No data to save, skipping..."); return PM3_EINVARG; } - saveFile(fn, ".bin", d, n); saveFileJSON(fn, jsft, d, n, NULL); return PM3_SUCCESS; diff --git a/client/src/fileutils.h b/client/src/fileutils.h index a2d31c196..6fc450dd1 100644 --- a/client/src/fileutils.h +++ b/client/src/fileutils.h @@ -83,7 +83,6 @@ typedef enum { DICTIONARY, MCT, FLIPPER, - TAGINFO, } DumpFileType_t; typedef enum { @@ -101,16 +100,9 @@ typedef enum { NFC_DF_14_3A, NFC_DF_14_3B, NFC_DF_14_4A, - NFC_DF_15, NFC_DF_PICOPASS, } nfc_df_e; -typedef enum { - ISO15_DF_UNKNOWN, - ISO15_DF_V4_BIN, - ISO15_DF_V5_BIN -} iso15_df_e; - int fileExists(const char *filename); // set a path in the path list g_session.defaultPaths @@ -124,7 +116,7 @@ void truncate_filename(char *fn, uint16_t maxlen); /** * @brief Utility function to save data to a binary file. This method takes a preferred name, but if that * file already exists, it tries with another name until it finds something suitable. - * E.g. dumpdata-15.bin + * E.g. dumpdata-15.txt * * @param preferredName * @param suffix the file suffix. Including the ".". @@ -135,19 +127,6 @@ void truncate_filename(char *fn, uint16_t maxlen); int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen); int saveFileEx(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path); -/** - * @brief Utility function to save data to a text file. This method takes a preferred name, but if that - * file already exists, it tries with another name until it finds something suitable. - * E.g. dumpdata-15.txt - * - * @param preferredName - * @param suffix the file suffix. Including the ".". - * @param data The binary data to write to the file - * @param datalen the length of the data - * @return 0 for ok, 1 for failz - */ -int saveFileTXT(const char *preferredName, const char *suffix, const void *data, size_t datalen, savePaths_t e_save_path); - /** STUB * @brief Utility function to save JSON data to a file. This method takes a preferred name, but if that * file already exists, it tries with another name until it finds something suitable. @@ -211,19 +190,6 @@ int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, const sector */ int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen); int loadFile_safeEx(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose); - -/** - * @brief Utility function to load a text file. This method takes a preferred name. - * E.g. dumpdata-15.json, tries to search for it, and allocated memory. - * - * @param preferredName - * @param suffix the file suffix. Including the ".". - * @param data The data array to store the loaded bytes from file - * @param datalen the number of bytes loaded from file - * @return PM3_SUCCESS for ok, PM3_E* for failz -*/ -int loadFile_TXTsafe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen, bool verbose); - /** * @brief Utility function to load data from a textfile (EML). This method takes a preferred name. * E.g. dumpdata-15.txt @@ -341,7 +307,7 @@ int loadFileDICTIONARY_safe_ex(const char *preferredName, const char *suffix, vo */ int loadFileXML_safe(const char *preferredName, const char *suffix, void **pdata, size_t *datalen); -int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen, bool verbose); +int loadFileBinaryKey(const char *preferredName, const char *suffix, void **keya, void **keyb, size_t *alen, size_t *blen); /** * @brief Utility function to check and convert plain mfu dump format to new mfu binary format. @@ -419,15 +385,4 @@ int pm3_save_mf_dump(const char *fn, uint8_t *d, size_t n, JSONFileType jsft); * @return PM3_SUCCESS if OK */ int pm3_save_fm11rf08s_nonces(const char *fn, iso14a_fm11rf08s_nonces_with_data_t *d, bool with_data); - - -/** - * Inserts a line into a text file only if it does not already exist. - * Returns PM3_SUCCES or, PM3_EFILE; - * - * @param filepath Path to the file. - * @param line Line to insert (should not contain a trailing newline). - */ -int insert_line_if_not_exists(const char *preferredName, const char *line); - #endif // FILEUTILS_H diff --git a/client/src/flash.c b/client/src/flash.c index 25edb7c0f..ff14309a0 100644 --- a/client/src/flash.c +++ b/client/src/flash.c @@ -30,7 +30,6 @@ #include "util_posix.h" #include "comms.h" #include "commonutil.h" -#include "fileutils.h" #define FLASH_START 0x100000 @@ -267,7 +266,7 @@ int flash_load(flash_file_t *ctx, bool force) { int res = PM3_EUNDEF; fd = fopen(ctx->filename, "rb"); - if (fd == NULL) { + if (!fd) { PrintAndLogEx(ERR, _RED_("Could not open file") " %s >>> ", ctx->filename); res = PM3_EFILE; goto fail; @@ -653,41 +652,17 @@ static const char ice[] = " !!: :!! !!: !!: !!: !!: !!! !!: !!!\n : :: :: : : :: ::: : : : : : :: : \n" _RED_(" . .. .. . . .. ... . . . . . .. . "); - -#define ICEMAN_LOGO_FN "iceman.txt" -#define ICEMAN_LOGO_SIZE (5000) // Write a file's segments to Flash int flash_write(flash_file_t *ctx) { - - char ice2[ICEMAN_LOGO_SIZE] = {0}; - char ice3[ICEMAN_LOGO_SIZE] = {0}; - - bool is_loaded = false; - if (g_session.supports_colors) { - - uint8_t *iraw = NULL; - size_t irawlen = 0; - int res = loadFile_safeEx(ICEMAN_LOGO_FN, "", (void **)&iraw, &irawlen, false); - if (res == PM3_SUCCESS && irawlen > ICEMAN_LOGO_SIZE) { - irawlen = ICEMAN_LOGO_SIZE; - } - if (res == PM3_SUCCESS) { - memcpy(ice3, iraw, irawlen); - free(iraw); - is_loaded = true; - } - } - - if (is_loaded == false) { - memcpy_filter_ansi(ice2, ice, sizeof(ice), !g_session.supports_colors); - memcpy_filter_emoji(ice3, ice2, sizeof(ice2), g_session.emoji_mode); - } - - size_t ice3len = strlen(ice3); + int len = 0; PrintAndLogEx(SUCCESS, "Writing segments for file: %s", ctx->filename); - int len = 0; + char ice2[sizeof(ice)] = {0}; + char ice3[sizeof(ice)] = {0}; + memcpy_filter_ansi(ice2, ice, sizeof(ice), !g_session.supports_colors); + memcpy_filter_emoji(ice3, ice2, sizeof(ice2), g_session.emoji_mode); + size_t ice3len = strlen(ice3); for (int i = 0; i < ctx->num_segs; i++) { flash_seg_t *seg = &ctx->segments[i]; @@ -697,14 +672,6 @@ int flash_write(flash_file_t *ctx) { uint32_t end = seg->start + length; PrintAndLogEx(SUCCESS, " 0x%08x..0x%08x [0x%x / %u blocks]", seg->start, end - 1, length, blocks); - if (is_loaded) { - if (blocks < 50) { - PrintAndLogEx(SUCCESS, "" NOLF); - } else { - fprintf(stdout, "\n\n"); - } - } - fflush(stdout); int block = 0; uint8_t *data = seg->data; @@ -726,45 +693,15 @@ int flash_write(flash_file_t *ctx) { length -= block_size; block++; - // small files, like bootrom - if (blocks < 50) { + if (len < ice3len) { + fprintf(stdout, "%c", ice3[len++]); + } else { + + if ((len - ice3len) % 67 == 0) { + fprintf(stdout, "\n"); + } fprintf(stdout, "."); len++; - fflush(stdout); - continue; - } - - // large fullimage write - if (is_loaded) { - if (len < ice3len) { - fprintf(stdout, "%c", ice3[len++]); - fprintf(stdout, "%c", ice3[len++]); - fprintf(stdout, "%c", ice3[len++]); - fprintf(stdout, "%c", ice3[len++]); - fprintf(stdout, "%c", ice3[len++]); - fprintf(stdout, "%c", ice3[len++]); - fprintf(stdout, "%c", ice3[len++]); - fprintf(stdout, "%c", ice3[len++]); - } else { - - if ((len - ice3len - 1) % 61 == 0) { - fprintf(stdout, "\n"); - } - fprintf(stdout, "."); - len++; - } - - } else { - if (len < ice3len) { - fprintf(stdout, "%c", ice3[len++]); - } else { - - if ((len - ice3len) % 67 == 0) { - fprintf(stdout, "\n"); - } - fprintf(stdout, "."); - len++; - } } fflush(stdout); } diff --git a/client/src/loclass/cipherutils.c b/client/src/loclass/cipherutils.c index 2ff42274d..83b23c698 100644 --- a/client/src/loclass/cipherutils.c +++ b/client/src/loclass/cipherutils.c @@ -126,67 +126,47 @@ uint64_t x_bytes_to_num(uint8_t *src, size_t len) { } void printarr(const char *name, uint8_t *arr, int len) { - - if (name == NULL || arr == NULL) { - return; - } + if (name == NULL || arr == NULL) return; int cx, i; size_t outsize = 40 + strlen(name) + len * 5; - char *output = calloc(outsize, sizeof(char)); if (output == NULL) { PrintAndLogEx(WARNING, "Failed to allocate memory"); return; } - cx = snprintf(output, outsize, "uint8_t %s[] = {", name); for (i = 0; i < len; i++) { - if (cx < outsize) { + if (cx < outsize) cx += snprintf(output + cx, outsize - cx, "0x%02x,", *(arr + i)); //5 bytes per byte - } } - - if (cx < outsize) { + if (cx < outsize) snprintf(output + cx, outsize - cx, "};"); - } - PrintAndLogEx(INFO, output); free(output); } void printarr_human_readable(const char *title, uint8_t *arr, int len) { - if (arr == NULL) { - return; - } + if (arr == NULL) return; int cx = 0, i; size_t outsize = 100 + strlen(title) + (len * 4); char *output = calloc(outsize, sizeof(char)); PrintAndLogEx(INFO, "%s", title); - for (i = 0; i < len; i++) { - if (i % 16 == 0) { if (i == 0) { - - if (cx < outsize) { + if (cx < outsize) cx += snprintf(output + cx, outsize - cx, "%02x| ", i); - } - } else { - - if (cx < outsize) { + if (cx < outsize) cx += snprintf(output + cx, outsize - cx, "\n%02x| ", i); - } } } - - if (cx < outsize) { + if (cx < outsize) cx += snprintf(output + cx, outsize - cx, "%02x ", *(arr + i)); - } } PrintAndLogEx(INFO, output); free(output); @@ -253,14 +233,11 @@ static int testReversedBitstream(void) { } int testCipherUtils(void) { + PrintAndLogEx(INFO, "Testing some internals..."); + int retval = testBitStream(); + if (retval == PM3_SUCCESS) + retval = testReversedBitstream(); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "---------------- " _CYAN_("Loclass selftests") " ----------------"); - - int res = testBitStream(); - if (res == PM3_SUCCESS) { - res = testReversedBitstream(); - } - return res; + return retval; } #endif diff --git a/client/src/loclass/elite_crack.c b/client/src/loclass/elite_crack.c index ad7beb249..01ffe7b29 100644 --- a/client/src/loclass/elite_crack.c +++ b/client/src/loclass/elite_crack.c @@ -248,12 +248,10 @@ void hash2(uint8_t *key64, uint8_t *outp_keytable) { } if (outp_keytable != NULL) { - for (uint8_t i = 0 ; i < 8 ; i++) { memcpy(outp_keytable + i * 16, y[i], 8); memcpy(outp_keytable + 8 + i * 16, z[i], 8); } - } else { printarr_human_readable("hash2", outp_keytable, 128); } @@ -331,9 +329,7 @@ static void *bf_thread(void *thread_arg) { int found = __atomic_load_n(&loclass_found, __ATOMIC_SEQ_CST); - if (found != 0xFF) { - return NULL; - } + if (found != 0xFF) return NULL; //Update the keytable with the brute-values for (uint8_t i = 0; i < numbytes_to_recover; i++) { @@ -387,22 +383,15 @@ static void *bf_thread(void *thread_arg) { #define _CLR_ "\x1b[0K" if (numbytes_to_recover == 3) { - if ((brute > 0) && ((brute & 0xFFFF) == 0)) { PrintAndLogEx(INPLACE, "[ %02x %02x %02x ] %8u / %u", bytes_to_recover[0], bytes_to_recover[1], bytes_to_recover[2], brute, 0xFFFFFF); } - } else if (numbytes_to_recover == 2) { - - if ((brute > 0) && ((brute & 0x3F) == 0)) { + if ((brute > 0) && ((brute & 0x3F) == 0)) PrintAndLogEx(INPLACE, "[ %02x %02x ] %5u / %u" _CLR_, bytes_to_recover[0], bytes_to_recover[1], brute, 0xFFFF); - } - } else { - - if ((brute > 0) && ((brute & 0x1F) == 0)) { + if ((brute > 0) && ((brute & 0x1F) == 0)) PrintAndLogEx(INPLACE, "[ %02x ] %3u / %u" _CLR_, bytes_to_recover[0], brute, 0xFF); - } } } pthread_exit(NULL); @@ -435,19 +424,15 @@ int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) { uint8_t bytes_to_recover[3] = {0}; uint8_t numbytes_to_recover = 0; for (uint8_t i = 0; i < 8; i++) { - - if (keytable[key_index[i]] & (LOCLASS_CRACKED | LOCLASS_BEING_CRACKED)) { - continue; - } + if (keytable[key_index[i]] & (LOCLASS_CRACKED | LOCLASS_BEING_CRACKED)) continue; bytes_to_recover[numbytes_to_recover++] = key_index[i]; - keytable[key_index[i]] |= LOCLASS_BEING_CRACKED; if (numbytes_to_recover > 3) { PrintAndLogEx(FAILED, "The CSN requires > 3 byte bruteforce, not supported"); - PrintAndLogEx(INFO, "CSN..... %s", sprint_hex_inrow(item.csn, 8)); - PrintAndLogEx(INFO, "HASH1... %s", sprint_hex_inrow(key_index, 8)); + PrintAndLogEx(INFO, "CSN %s", sprint_hex(item.csn, 8)); + PrintAndLogEx(INFO, "HASH1 %s", sprint_hex(key_index, 8)); PrintAndLogEx(NORMAL, ""); //Before we exit, reset the 'BEING_CRACKED' to zero keytable[bytes_to_recover[0]] &= ~LOCLASS_BEING_CRACKED; @@ -458,7 +443,6 @@ int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) { } if (numbytes_to_recover == 0) { - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "No bytes to recover, exiting"); return PM3_ESOFT; } @@ -488,9 +472,8 @@ int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) { } // wait for threads to terminate: void *ptrs[loclass_tc]; - for (size_t i = 0; i < loclass_tc; i++) { + for (size_t i = 0; i < loclass_tc; i++) pthread_join(threads[i], &ptrs[i]); - } // was it a success? int res = PM3_SUCCESS; @@ -678,6 +661,7 @@ int bruteforceItem(loclass_dumpdata_t item, uint16_t keytable[]) { * @return 0 for ok, 1 for failz */ int calculateMasterKey(uint8_t first16bytes[], uint8_t kcus[]) { + mbedtls_des_context ctx_e; uint8_t z_0[8] = {0}; uint8_t y_0[8] = {0}; @@ -696,9 +680,8 @@ int calculateMasterKey(uint8_t first16bytes[], uint8_t kcus[]) { permutekey_rev(z_0, z_0_rev); // ~K_cus = DESenc(z[0], y[0]) - mbedtls_des_context ctx; - mbedtls_des_setkey_enc(&ctx, z_0_rev); - mbedtls_des_crypt_ecb(&ctx, y_0, key64_negated); + mbedtls_des_setkey_enc(&ctx_e, z_0_rev); + mbedtls_des_crypt_ecb(&ctx_e, y_0, key64_negated); key64[0] = ~key64_negated[0]; key64[1] = ~key64_negated[1]; @@ -714,24 +697,20 @@ int calculateMasterKey(uint8_t first16bytes[], uint8_t kcus[]) { uint8_t key64_stdformat[8] = {0}; permutekey_rev(key64, key64_stdformat); - mbedtls_des_setkey_enc(&ctx, key64_stdformat); - mbedtls_des_crypt_ecb(&ctx, key64_negated, result); - mbedtls_des_free(&ctx); + mbedtls_des_setkey_enc(&ctx_e, key64_stdformat); + mbedtls_des_crypt_ecb(&ctx_e, key64_negated, result); - // copy key to out array - if (kcus != NULL) { + if (kcus != NULL) memcpy(kcus, key64, 8); - } if (memcmp(z_0, result, 4) != 0) { - PrintAndLogEx(WARNING, "Calculated master key, k_cus ( %s )", _RED_("fail")); - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(WARNING, _RED_("Failed to verify") " calculated master key (k_cus)! Something is wrong."); return PM3_ESOFT; } - PrintAndLogEx(SUCCESS, "--- " _CYAN_("High security custom key (Kcus)") " ---"); - PrintAndLogEx(SUCCESS, "Standard format... %s", sprint_hex_inrow(key64_stdformat, sizeof(key64_stdformat))); - PrintAndLogEx(SUCCESS, "iCLASS format..... " _GREEN_("%s"), sprint_hex_inrow(key64, sizeof(key64))); + PrintAndLogEx(SUCCESS, "----- " _CYAN_("High security custom key (Kcus)") " -----"); + PrintAndLogEx(SUCCESS, "Standard format %s", sprint_hex(key64_stdformat, 8)); + PrintAndLogEx(SUCCESS, "iCLASS format " _GREEN_("%s"), sprint_hex(key64, 8)); PrintAndLogEx(SUCCESS, "Key verified ( " _GREEN_("ok") " )"); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; @@ -744,7 +723,7 @@ int calculateMasterKey(uint8_t first16bytes[], uint8_t kcus[]) { * @return */ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) { - + uint8_t i; size_t itemsize = sizeof(loclass_dumpdata_t); loclass_dumpdata_t *attack = (loclass_dumpdata_t *) calloc(itemsize, sizeof(uint8_t)); if (attack == NULL) { @@ -758,28 +737,19 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) { int res = 0; uint64_t t1 = msclock(); - for (uint16_t i = 0 ; i * itemsize < dumpsize ; i++) { - + for (i = 0 ; i * itemsize < dumpsize ; i++) { memcpy(attack, dump + i * itemsize, itemsize); - res = bruteforceItem(*attack, keytable); - if (res != PM3_SUCCESS) { + if (res != PM3_SUCCESS) break; - } } - free(attack); - t1 = msclock() - t1; - if (res == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, ""); - } + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "time " _YELLOW_("%" PRIu64) " seconds", t1 / 1000); if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "loclass key recovery( %s )", _RED_("fail")); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass sim -t 2") "` again and collect new data"); - PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(ERR, "loclass exiting. Try run " _YELLOW_("`hf iclass sim -t 2`") " again and collect new data"); return PM3_ESOFT; } @@ -788,12 +758,11 @@ int bruteforceDump(uint8_t dump[], size_t dumpsize, uint16_t keytable[]) { // indicate crack-status. Those must be discarded for the // master key calculation uint8_t first16bytes[16] = {0}; - for (uint8_t i = 0 ; i < 16 ; i++) { + for (i = 0 ; i < 16 ; i++) { first16bytes[i] = keytable[i] & 0xFF; if ((keytable[i] & LOCLASS_CRACKED) != LOCLASS_CRACKED) { PrintAndLogEx(WARNING, "Warning: we are missing byte " _RED_("%d") " , custom key calculation will fail...", i); - PrintAndLogEx(NORMAL, ""); return PM3_ESOFT; } } @@ -904,7 +873,7 @@ static int _testHash1(void) { } int testElite(bool slowtests) { - PrintAndLogEx(INFO, "Testing iClass Elite functionality..."); + PrintAndLogEx(INFO, "Testing iClass Elite functionality"); PrintAndLogEx(INFO, "Testing hash2..."); uint8_t k_cus[8] = {0x5B, 0x7C, 0x62, 0xC4, 0x91, 0xC1, 0x1B, 0x39}; @@ -925,23 +894,22 @@ int testElite(bool slowtests) { */ uint8_t keytable[128] = {0}; hash2(k_cus, keytable); - printarr_human_readable("--------------------- " _CYAN_("Hash2") " -----------------------", keytable, sizeof(keytable)); + printarr_human_readable("---------------------- Hash2 ----------------------", keytable, sizeof(keytable)); if (keytable[3] == 0xA1 && keytable[0x30] == 0xA3 && keytable[0x6F] == 0x95) { - PrintAndLogEx(SUCCESS, " Hash2 ( %s )", _GREEN_("ok")); + PrintAndLogEx(SUCCESS, " hash2 ( %s )", _GREEN_("ok")); } int res = PM3_SUCCESS; PrintAndLogEx(INFO, "Testing hash1..."); res += _testHash1(); - PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " Hash1 ( %s )", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail")); + PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " hash1 ( %s )", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail")); PrintAndLogEx(INFO, "Testing key diversification..."); res += _test_iclass_key_permutation(); - PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " Key diversification ( %s )", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail")); + PrintAndLogEx((res == PM3_SUCCESS) ? SUCCESS : WARNING, " key diversification ( %s )", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail")); - if (slowtests) { + if (slowtests) res += _testBruteforce(); - } return res; } diff --git a/client/src/loclass/ikeys.c b/client/src/loclass/ikeys.c index b50699e9e..9e9c4c5c4 100644 --- a/client/src/loclass/ikeys.c +++ b/client/src/loclass/ikeys.c @@ -657,7 +657,7 @@ void invert_hash0(uint8_t k[8]) { x_num_to_bytes(original_z, sizeof(original_z), des_pre_image); if (image_match) { - PrintAndLogEx(INFO, "Pre-image......... " _YELLOW_("%s") " ( "_GREEN_("ok") " )", sprint_hex_inrow(des_pre_image, sizeof(des_pre_image))); + PrintAndLogEx(INFO, "Pre-image......... " _YELLOW_("%s") " ( "_GREEN_("valid") " )", sprint_hex_inrow(des_pre_image, sizeof(des_pre_image))); } else { if (g_debugMode > 0) { @@ -803,17 +803,17 @@ static bool des_getParityBitFromKey(uint8_t key) { } static void des_checkParity(uint8_t *key) { + int i; int fails = 0; - for (uint8_t i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { bool parity = des_getParityBitFromKey(key[i]); if (parity != (key[i] & 0x1)) { fails++; PrintAndLogEx(FAILED, "parity1 fail, byte %d [%02x] was %d, should be %d", i, key[i], (key[i] & 0x1), parity); } } - if (fails) { - PrintAndLogEx(FAILED, "parity fails... " _RED_("%d"), fails); + PrintAndLogEx(FAILED, "parity fails: %d", fails); } else { PrintAndLogEx(SUCCESS, " Key syntax is with parity bits inside each byte (%s)", _GREEN_("ok")); } @@ -894,17 +894,15 @@ static int testKeyDiversificationWithMasterkeyTestcases(uint8_t *key) { int i, error = 0; uint8_t empty[8] = {0}; - PrintAndLogEx(INFO, "Testing encryption/decryption..."); + PrintAndLogEx(INFO, "Testing encryption/decryption"); - for (i = 0; memcmp(testcases + i, empty, 8); i++) { + for (i = 0; memcmp(testcases + i, empty, 8); i++) error += testDES(key, testcases[i]); - } - if (error) { - PrintAndLogEx(FAILED, "%d errors occurred, %d testcases ( %s )", error, i, _RED_("fail")); - } else { - PrintAndLogEx(SUCCESS, " Hashing seems to work, " _YELLOW_("%d") " testcases ( %s )", i, _GREEN_("ok")); - } + if (error) + PrintAndLogEx(FAILED, "%d errors occurred (%d testcases)", error, i); + else + PrintAndLogEx(SUCCESS, "Hashing seems to work (%d testcases)", i); return error; } @@ -944,9 +942,8 @@ static int testDES2(uint8_t *key, uint64_t csn, uint64_t expected) { PrintAndLogEx(DEBUG, " {csn} %"PRIx64, crypt_csn); PrintAndLogEx(DEBUG, " expected %"PRIx64 " (%s)", expected, (expected == crypt_csn) ? _GREEN_("ok") : _RED_("fail")); - if (expected != crypt_csn) { + if (expected != crypt_csn) return PM3_ESOFT; - } return PM3_SUCCESS; } @@ -957,12 +954,12 @@ static int testDES2(uint8_t *key, uint64_t csn, uint64_t expected) { */ static int doTestsWithKnownInputs(void) { // KSel from http://www.proxmark.org/forum/viewtopic.php?pid=10977#p10977 - PrintAndLogEx(INFO, "Testing DES encryption... "); + PrintAndLogEx(INFO, "Testing DES encryption"); uint8_t key[8] = {0x6c, 0x8d, 0x44, 0xf9, 0x2a, 0x2d, 0x01, 0xbf}; testDES2(key, 0xbbbbaaaabbbbeeee, 0xd6ad3ca619659e6b); - PrintAndLogEx(INFO, "Testing hashing algorithm... "); + PrintAndLogEx(INFO, "Testing hashing algorithm"); int res = PM3_SUCCESS; res += testCryptedCSN(0x0102030405060708, 0x0bdd6512073c460a); @@ -976,29 +973,57 @@ static int doTestsWithKnownInputs(void) { res += testCryptedCSN(0x14e2adfc5bb7e134, 0x6ac90c6508bd9ea3); if (res != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "%d res occurred " _YELLOW_("9") " testcases ( %s )", res, _RED_("fail")); + PrintAndLogEx(FAILED, "%d res occurred (9 testcases)", res); res = PM3_ESOFT; } else { - PrintAndLogEx(SUCCESS, " Hashing seems to work " _YELLOW_("9") " testcases ( %s )", _GREEN_("ok")); + PrintAndLogEx(SUCCESS, "Hashing seems to work (9 testcases)"); res = PM3_SUCCESS; } return res; } +static bool readKeyFile(uint8_t *key, size_t keylen) { + + bool retval = false; + size_t len = 0; + uint8_t *keyptr = NULL; + if (loadFile_safe("iclass_key.bin", "", (void **)&keyptr, &len) != PM3_SUCCESS) { + return retval; + } + if (keylen == len) { + memcpy(key, keyptr, keylen); + retval = true; + } + free(keyptr); + return retval; +} + int doKeyTests(void) { - uint8_t key[8] = { 0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78 }; - uint8_t parity[8] = {0x00, 0x01, 0x01, 0x01, 0x00, 0x01, 0x00, 0x01}; + PrintAndLogEx(INFO, "Checking if the master key is present (iclass_key.bin)..."); + uint8_t key[8] = {0}; + if (readKeyFile(key, sizeof(key)) == false) { + PrintAndLogEx(FAILED, "Master key not present, will not be able to do all testcases"); + } else { - for (int i = 0; i < 8; i++) { - key[i] += parity[i]; + //Test if it's the right key... + uint8_t i; + uint8_t j = 0; + for (i = 0; i < ARRAYLEN(key); i++) + j += key[i]; + + if (j != 185) { + PrintAndLogEx(INFO, "A key was loaded, but it does not seem to be the correct one. Aborting these tests"); + } else { + PrintAndLogEx(SUCCESS, "Key present"); + PrintAndLogEx(SUCCESS, "Checking key parity..."); + des_checkParity(key); + + // Test hashing functions + PrintAndLogEx(SUCCESS, "The following tests require the correct 8-byte master key"); + testKeyDiversificationWithMasterkeyTestcases(key); + } } - - PrintAndLogEx(SUCCESS, "Checking key parity..."); - des_checkParity(key); - - // Test hashing functions - testKeyDiversificationWithMasterkeyTestcases(key); PrintAndLogEx(INFO, "Testing key diversification with non-sensitive keys..."); return doTestsWithKnownInputs(); } diff --git a/client/src/mifare/desfirecore.c b/client/src/mifare/desfirecore.c index 9d6fc5084..9adfcdefd 100644 --- a/client/src/mifare/desfirecore.c +++ b/client/src/mifare/desfirecore.c @@ -575,11 +575,10 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uin size_t sentdatalen = 0; while (cdatalen >= sentdatalen) { - if ((cdatalen - sentdatalen) > DESFIRE_TX_FRAME_MAX_LEN) { + if ((cdatalen - sentdatalen) > DESFIRE_TX_FRAME_MAX_LEN) len = DESFIRE_TX_FRAME_MAX_LEN; - } else { + else len = cdatalen - sentdatalen; - } size_t sendindx = sentdatalen; size_t sendlen = len; @@ -658,9 +657,8 @@ static int DesfireExchangeNative(bool activate_field, DesfireContext_t *ctx, uin } pos += buflen; - if (rcode != MFDES_ADDITIONAL_FRAME) { + if (rcode != MFDES_ADDITIONAL_FRAME) break; - } } if (resplen) { @@ -971,14 +969,12 @@ int DesfireSelectAIDHexNoFieldOn(DesfireContext_t *ctx, uint32_t aid) { ctx->secureChannel = DACNone; int res = DesfireExchangeEx(false, ctx, MFDES_SELECT_APPLICATION, data, 3, &respcode, resp, &resplen, true, 0); if (res == PM3_SUCCESS) { - if (resplen != 0) { + if (resplen != 0) return PM3_ECARDEXCHANGE; - } // select operation fail - if (respcode != MFDES_S_OPERATION_OK) { + if (respcode != MFDES_S_OPERATION_OK) return PM3_EAPDU_FAIL; - } DesfireClearSession(ctx); ctx->appSelected = (aid != 0x000000); @@ -1100,57 +1096,7 @@ int DesfireSelectAndAuthenticateW(DesfireContext_t *dctx, DesfireSecureChannel s DesfirePrintContext(dctx); int res = 0; - - // Handle DF Name selection if it's present in the context - if (dctx->selectedDFNameLen > 0) { - // Select DF by name using ISO7816 SELECT - uint8_t resp[250] = {0}; - size_t resplen = 0; - res = DesfireISOSelect(dctx, ISSDFName, dctx->selectedDFName, dctx->selectedDFNameLen, resp, &resplen); - if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Desfire DF name select " _RED_("error")); - return 200; - } - if (verbose) { - PrintAndLogEx(INFO, "DF %s is " _GREEN_("selected"), sprint_hex(dctx->selectedDFName, dctx->selectedDFNameLen)); - } - - // If both dfname and aid are specified, now also select by AID - if (way == ISW6bAID && id != 0x000000) { - if (dctx->cmdSet == DCCISO) { - dctx->cmdSet = DCCNativeISO; - if (verbose) - PrintAndLogEx(INFO, "Select via " _CYAN_("native iso wrapping") " interface"); - - res = DesfireSelectAIDHex(dctx, id, false, 0); - if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Desfire select " _RED_("error")); - return 200; - } - if (verbose) - PrintAndLogEx(INFO, "App %06x via native iso channel is " _GREEN_("selected"), id); - - dctx->cmdSet = DCCISO; - } else { - res = DesfireSelectEx(dctx, false, way, id, NULL); - if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Desfire %s select " _RED_("error"), DesfireSelectWayToStr(way)); - return 202; - } - if (verbose) - PrintAndLogEx(INFO, "%s is " _GREEN_("selected"), DesfireWayIDStr(way, id)); - } - } else if (way == ISWIsoID && id != 0x0000) { - // Also select by ISO ID if specified - res = DesfireSelectEx(dctx, false, way, id, NULL); - if (res != PM3_SUCCESS) { - PrintAndLogEx(ERR, "Desfire %s select " _RED_("error"), DesfireSelectWayToStr(way)); - return 202; - } - if (verbose) - PrintAndLogEx(INFO, "%s is " _GREEN_("selected"), DesfireWayIDStr(way, id)); - } - } else if (way == ISW6bAID && dctx->cmdSet == DCCISO) { + if (way == ISW6bAID && dctx->cmdSet == DCCISO) { dctx->cmdSet = DCCNativeISO; if (verbose) PrintAndLogEx(INFO, "Select via " _CYAN_("native iso wrapping") " interface"); @@ -2290,20 +2236,6 @@ int DesfireValueFileOperations(DesfireContext_t *dctx, uint8_t fid, uint8_t oper int res = DesfireCommand(dctx, operation, data, datalen, resp, &resplen, -1); - // Auto-detection fallback: if MAC mode fails with length error, retry with plain mode - if ((res == 0x7E || res == -20) && dctx->commMode == DCMMACed) { - PrintAndLogEx(INFO, "MAC mode failed with length error, retrying with plain mode"); - DesfireCommunicationMode original_mode = dctx->commMode; - dctx->commMode = DCMPlain; - - memset(resp, 0, sizeof(resp)); - resplen = 0; - res = DesfireCommand(dctx, operation, data, datalen, resp, &resplen, -1); - - // Restore original mode for future commands - dctx->commMode = original_mode; - } - if (resplen == 4 && value) { *value = MemLeToUint4byte(resp); } @@ -2342,10 +2274,10 @@ int DesfireUpdateRecord(DesfireContext_t *dctx, uint8_t fnum, uint32_t recnum, u static void PrintKeySettingsPICC(uint8_t keysettings, uint8_t numkeys, bool print2ndbyte) { PrintAndLogEx(SUCCESS, "PICC level rights"); - PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)")); - PrintAndLogEx(SUCCESS, "[.%c..] CMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : _RED_("YES")); - PrintAndLogEx(SUCCESS, "[..%c.] CMK required for AID list / GetKeySettings : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : _RED_("YES")); - PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)")); + PrintAndLogEx(SUCCESS, "[%c...] CMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)")); + PrintAndLogEx(SUCCESS, "[.%c..] CMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with CMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, "[...%c] CMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)")); PrintAndLogEx(SUCCESS, ""); if (print2ndbyte) { @@ -2382,10 +2314,10 @@ static void PrintKeySettingsApp(uint8_t keysettings, uint8_t numkeys, bool print } } - PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)")); - PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : _RED_("YES")); - PrintAndLogEx(SUCCESS, "[..%c.] AMK required for FID list / GetKeySettings : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : _RED_("YES")); - PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)")); + PrintAndLogEx(SUCCESS, "[%c...] AMK Configuration changeable : %s", (keysettings & (1 << 3)) ? '1' : '0', (keysettings & (1 << 3)) ? _GREEN_("YES") : _RED_("NO (frozen)")); + PrintAndLogEx(SUCCESS, "[.%c..] AMK required for create/delete : %s", (keysettings & (1 << 2)) ? '1' : '0', (keysettings & (1 << 2)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, "[..%c.] Directory list access with AMK : %s", (keysettings & (1 << 1)) ? '1' : '0', (keysettings & (1 << 1)) ? _GREEN_("NO") : "YES"); + PrintAndLogEx(SUCCESS, "[...%c] AMK is changeable : %s", (keysettings & (1 << 0)) ? '1' : '0', (keysettings & (1 << 0)) ? _GREEN_("YES") : _RED_("NO (frozen)")); PrintAndLogEx(SUCCESS, ""); if (print2ndbyte) { diff --git a/client/src/mifare/desfirecrypto.c b/client/src/mifare/desfirecrypto.c index b0097aab7..bf61472e2 100644 --- a/client/src/mifare/desfirecrypto.c +++ b/client/src/mifare/desfirecrypto.c @@ -101,24 +101,11 @@ void DesfireSetCommMode(DesfireContext_t *ctx, DesfireCommunicationMode commMode void DesfireSetKdf(DesfireContext_t *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint8_t kdfInputLen) { ctx->kdfAlgo = kdfAlgo; ctx->kdfInputLen = kdfInputLen; - if (kdfInputLen) + if (kdfInputLen) { memcpy(ctx->kdfInput, kdfInput, kdfInputLen); -} - -void DesfireSetDFName(DesfireContext_t *ctx, uint8_t *dfname, uint8_t dfnameLen) { - ctx->selectedDFNameLen = 0; - memset(ctx->selectedDFName, 0, sizeof(ctx->selectedDFName)); - - if (dfname && dfnameLen > 0 && dfnameLen <= 16) { - ctx->selectedDFNameLen = dfnameLen; - memcpy(ctx->selectedDFName, dfname, dfnameLen); } } -void DesfireSetSecureChannel(DesfireContext_t *ctx, DesfireSecureChannel schann) { - ctx->secureChannel = schann; -} - bool DesfireIsAuthenticated(DesfireContext_t *dctx) { return dctx->secureChannel != DACNone; } diff --git a/client/src/mifare/desfirecrypto.h b/client/src/mifare/desfirecrypto.h index 363cef461..43f9cd386 100644 --- a/client/src/mifare/desfirecrypto.h +++ b/client/src/mifare/desfirecrypto.h @@ -75,9 +75,6 @@ typedef struct { bool appSelected; // for iso auth uint32_t selectedAID; - uint8_t selectedDFName[16]; - uint8_t selectedDFNameLen; - uint8_t uid[10]; uint8_t uidlen; @@ -98,9 +95,7 @@ void DesfireSetKey(DesfireContext_t *ctx, uint8_t keyNum, DesfireCryptoAlgorithm void DesfireSetKeyNoClear(DesfireContext_t *ctx, uint8_t keyNum, DesfireCryptoAlgorithm keyType, uint8_t *key); void DesfireSetCommandSet(DesfireContext_t *ctx, DesfireCommandSet cmdSet); void DesfireSetCommMode(DesfireContext_t *ctx, DesfireCommunicationMode commMode); -void DesfireSetSecureChannel(DesfireContext_t *ctx, DesfireSecureChannel schann); void DesfireSetKdf(DesfireContext_t *ctx, uint8_t kdfAlgo, uint8_t *kdfInput, uint8_t kdfInputLen); -void DesfireSetDFName(DesfireContext_t *ctx, uint8_t *dfname, uint8_t dfnameLen); bool DesfireIsAuthenticated(DesfireContext_t *dctx); size_t DesfireGetMACLength(DesfireContext_t *ctx); diff --git a/client/src/mifare/desfiresecurechan.c b/client/src/mifare/desfiresecurechan.c index d9506d48b..2b439b1b4 100644 --- a/client/src/mifare/desfiresecurechan.c +++ b/client/src/mifare/desfiresecurechan.c @@ -219,6 +219,9 @@ static uint8_t DesfireGetCmdHeaderLen(uint8_t cmd) { static const uint8_t EV1D40TransmitMAC[] = { MFDES_WRITE_DATA, + MFDES_CREDIT, + MFDES_LIMITED_CREDIT, + MFDES_DEBIT, MFDES_WRITE_RECORD, MFDES_UPDATE_RECORD, MFDES_COMMIT_READER_ID, diff --git a/client/src/mifare/mad.c b/client/src/mifare/mad.c index eae149a4c..b5ab07897 100644 --- a/client/src/mifare/mad.c +++ b/client/src/mifare/mad.c @@ -317,6 +317,7 @@ static int MADInfoByteDecode(const uint8_t *sector, bool swapmad, int mad_ver, b void MADPrintHeader(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("MIFARE App Directory Information") " ----------------"); + PrintAndLogEx(INFO, "-----------------------------------------------------"); } int MAD1DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose, bool *haveMAD2) { @@ -407,14 +408,14 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) { uint16_t aid = madGetAID(sector, swapmad, 2, i); if (aid < 6) { PrintAndLogEx(INFO, - (ibs == i + 16) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s", + (ibs == i) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s", i + 16, aid, aid_admin[aid] ); } else if (prev_aid == aid) { PrintAndLogEx(INFO, - (ibs == i + 16) ? _MAGENTA_(" %02d [%04X] continuation") : " %02d [" _YELLOW_("%04X") "] continuation", + (ibs == i) ? _MAGENTA_(" %02d [%04X] continuation") : " %02d [" _YELLOW_("%04X") "] continuation", i + 16, aid ); @@ -422,7 +423,7 @@ int MAD2DecodeAndPrint(uint8_t *sector, bool swapmad, bool verbose) { char fmt[80]; snprintf(fmt , sizeof(fmt) - , (ibs == i + 16) ? + , (ibs == i) ? _MAGENTA_(" %02d [%04X] %s") : " %02d [" _GREEN_("%04X") "] %s" , i + 16 @@ -449,9 +450,8 @@ int MADDFDecodeAndPrint(uint32_t short_aid, bool verbose) { } bool HasMADKey(uint8_t *d) { - if (d == NULL) { + if (d == NULL) return false; - } return (memcmp(d + (3 * MFBLOCK_SIZE), g_mifare_mad_key, sizeof(g_mifare_mad_key)) == 0); } diff --git a/client/src/mifare/mifare4.c b/client/src/mifare/mifare4.c index ea7986441..85af35820 100644 --- a/client/src/mifare/mifare4.c +++ b/client/src/mifare/mifare4.c @@ -210,18 +210,15 @@ int MifareAuth4(mf4Session_t *mf4session, const uint8_t *keyn, uint8_t *key, boo uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; uint8_t RndB[17] = {0}; - if (silentMode) { + if (silentMode) verbose = false; - } - if (mf4session) { + if (mf4session) mf4session->Authenticated = false; - } uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00}; int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen, silentMode); if (res != PM3_SUCCESS) { - if (silentMode == false) { PrintAndLogEx(ERR, "Exchange raw error: %d", res); } @@ -237,35 +234,20 @@ int MifareAuth4(mf4Session_t *mf4session, const uint8_t *keyn, uint8_t *key, boo } if (datalen < 1) { - if (silentMode == false) { - PrintAndLogEx(ERR, "Card response wrong length: %d", datalen); - } - - if (dropFieldIfError) { - DropField(); - } + if (!silentMode) PrintAndLogEx(ERR, "Card response wrong length: %d", datalen); + if (dropFieldIfError) DropField(); return PM3_EWRONGANSWER; } if (data[0] != 0x90) { - if (silentMode == false) { - PrintAndLogEx(ERR, "Card response error: %02x %s", data[0], mfpGetErrorDescription(data[0])); - } - - if (dropFieldIfError) { - DropField(); - } + if (!silentMode) PrintAndLogEx(ERR, "Card response error: %02x %s", data[0], mfpGetErrorDescription(data[0])); + if (dropFieldIfError) DropField(); return PM3_EWRONGANSWER; } if (datalen != 19) { // code 1b + 16b + crc 2b - if (silentMode == false) { - PrintAndLogEx(ERR, "Card response must be 19 bytes long instead of: %d", datalen); - } - - if (dropFieldIfError) { - DropField(); - } + if (!silentMode) PrintAndLogEx(ERR, "Card response must be 19 bytes long instead of: %d", datalen); + if (dropFieldIfError) DropField(); return PM3_EWRONGANSWER; } @@ -286,13 +268,11 @@ int MifareAuth4(mf4Session_t *mf4session, const uint8_t *keyn, uint8_t *key, boo if (verbose) { PrintAndLogEx(INFO, ">phase2: %s", sprint_hex(cmd2, 33)); } - res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen, silentMode); if (res != PM3_SUCCESS) { if (silentMode == false) { PrintAndLogEx(ERR, "Exchange raw error: %d", res); } - if (dropFieldIfError) { DropField(); } @@ -311,18 +291,12 @@ int MifareAuth4(mf4Session_t *mf4session, const uint8_t *keyn, uint8_t *key, boo } if (memcmp(&raw[4], &RndA[1], 16)) { - if (silentMode == false) { - PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd is not equal"); - } - + if (!silentMode) PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd is not equal"); if (verbose) { PrintAndLogEx(ERR, "RndA reader: %s", sprint_hex(&RndA[1], 16)); PrintAndLogEx(ERR, "RndA card: %s", sprint_hex(&raw[4], 16)); } - - if (dropFieldIfError) { - DropField(); - } + if (dropFieldIfError) DropField(); return PM3_EWRONGANSWER; } @@ -335,7 +309,6 @@ int MifareAuth4(mf4Session_t *mf4session, const uint8_t *keyn, uint8_t *key, boo uint8_t kenc[16] = {0}; memcpy(&kenc[0], &RndA[11], 5); memcpy(&kenc[5], &RndB[11], 5); - for (int i = 0; i < 5; i++) { kenc[10 + i] = RndA[4 + i] ^ RndB[4 + i]; } @@ -349,7 +322,6 @@ int MifareAuth4(mf4Session_t *mf4session, const uint8_t *keyn, uint8_t *key, boo uint8_t kmac[16] = {0}; memcpy(&kmac[0], &RndA[7], 5); memcpy(&kmac[5], &RndB[7], 5); - for (int i = 0; i < 5; i++) { kmac[10 + i] = RndA[0 + i] ^ RndB[0 + i]; } @@ -615,8 +587,6 @@ uint8_t mfFirstBlockOfSector(uint8_t sectorNo) { } } -// returns the sectortrailer block number in the range of all block no. -// ie: sector 1 has its sector trailer at block number 7 uint8_t mfSectorTrailerOfSector(uint8_t sectorNo) { if (sectorNo < 32) { return (sectorNo * 4) | 0x03; diff --git a/client/src/mifare/mifaredefault.h b/client/src/mifare/mifaredefault.h index e43c42a4b..bcdc4a84b 100644 --- a/client/src/mifare/mifaredefault.h +++ b/client/src/mifare/mifaredefault.h @@ -121,24 +121,20 @@ static const uint64_t g_mifare_default_keys[] = { 0x96a301bce267, }; -static const uint8_t g_mifare_default_key[MIFARE_KEY_SIZE] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -static const uint8_t g_mifare_mad_key[MIFARE_KEY_SIZE] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}; -static const uint8_t g_mifare_mad_key_b[MIFARE_KEY_SIZE] = {0x89, 0xEC, 0xA9, 0x7F, 0x8C, 0x2A}; +static const uint8_t g_mifare_default_key[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +static const uint8_t g_mifare_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5}; +static const uint8_t g_mifare_mad_key_b[] = {0x89, 0xEC, 0xA9, 0x7F, 0x8C, 0x2A}; // 16 key B D01AFEEB890A -static const uint8_t g_mifare_signature_key_a[MIFARE_KEY_SIZE] = {0x5C, 0x8F, 0xF9, 0x99, 0x0D, 0xA2}; -static const uint8_t g_mifare_signature_key_b[MIFARE_KEY_SIZE] = {0x4b, 0x79, 0x1b, 0xea, 0x7b, 0xcc}; +static const uint8_t g_mifare_signature_key_a[] = {0x5C, 0x8F, 0xF9, 0x99, 0x0D, 0xA2}; +static const uint8_t g_mifare_signature_key_b[] = {0x4b, 0x79, 0x1b, 0xea, 0x7b, 0xcc}; // Manufacture MFC / QL88 (S17 / B) -static const uint8_t g_mifare_ql88_signature_key_b[MIFARE_KEY_SIZE] = {0x70, 0x7B, 0x11, 0xFC, 0x14, 0x81}; +static const uint8_t g_mifare_ql88_signature_key_b[] = {0x70, 0x7B, 0x11, 0xFC, 0x14, 0x81}; -static const uint8_t g_mifare_ndef_key[MIFARE_KEY_SIZE] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; +static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7}; static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; -static const uint8_t g_mifare_k08s[MIFARE_KEY_SIZE] = {0xA3, 0x96, 0xEF, 0xA4, 0xE2, 0x4F}; -static const uint8_t g_mifare_k08[MIFARE_KEY_SIZE] = {0xA3, 0x16, 0x67, 0xA8, 0xCE, 0xC1}; -static const uint8_t g_mifare_k32n[MIFARE_KEY_SIZE] = {0x51, 0x8B, 0x33, 0x54, 0xE7, 0x60}; -static const uint8_t g_mifare_k32n2[MIFARE_KEY_SIZE] = {0x73, 0xB9, 0x83, 0x6C, 0xF1, 0x68}; extern const char *g_mifare_plus_default_keys[]; extern size_t g_mifare_plus_default_keys_len; diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index d8f3a04ed..2a2aed593 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -43,8 +43,6 @@ #include "cmdhf14a.h" #include "gen4.h" #include "parity.h" -#include "pmflash.h" -#include "preferences.h" // setDeviceDebugLevel int mf_dark_side(uint8_t blockno, uint8_t key_type, uint64_t *key) { uint32_t uid = 0; @@ -64,7 +62,7 @@ int mf_dark_side(uint8_t blockno, uint8_t key_type, uint64_t *key) { //flush queue while (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(WARNING, "aborted via keyboard"); + PrintAndLogEx(WARNING, "Aborted via keyboard"); return PM3_EOPABORTED; } @@ -90,7 +88,7 @@ int mf_dark_side(uint8_t blockno, uint8_t key_type, uint64_t *key) { //TODO: Not really stopping the command in time. if (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(WARNING, "\naborted via keyboard"); + PrintAndLogEx(WARNING, "\nAborted via keyboard"); return PM3_EOPABORTED; } @@ -277,7 +275,7 @@ int mf_check_keys_fast_ex(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastCh while (kbd_enter_pressed()) { SendCommandNG(CMD_BREAK_LOOP, NULL, 0); - PrintAndLogEx(INFO, "aborted via keyboard!"); + PrintAndLogEx(NORMAL, ""); return PM3_EOPABORTED; } @@ -307,11 +305,12 @@ int mf_check_keys_fast_ex(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastCh uint8_t curr_keys = resp.oldarg[0]; if ((singleSectorParams >> 15) & 1) { - if (curr_keys) { - + // uint64_t foo = bytes_to_num(resp.data.asBytes, 6); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "\nTarget block " _GREEN_("%4u") " key type " _GREEN_("%c") " -- found valid key [ " _GREEN_("%s") " ]", +// PrintAndLogEx(SUCCESS, "found Key %s for block %2i found: " _GREEN_("%012" PRIx64), (singleSectorParams >> 8) & 1 ? "B" : "A", singleSectorParams & 0xFF, foo); + + PrintAndLogEx(SUCCESS, "\nTarget block %4u key type %c -- found valid key [ " _GREEN_("%s") " ]", singleSectorParams & 0xFF, ((singleSectorParams >> 8) & 1) ? 'B' : 'A', sprint_hex_inrow(resp.data.asBytes, MIFARE_KEY_SIZE) @@ -562,9 +561,8 @@ int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo struct p *package = (struct p *)resp.data.asBytes; // error during nested on device side - if (package->isOK != PM3_SUCCESS) { + if (package->isOK != PM3_SUCCESS) return package->isOK; - } memcpy(&uid, package->cuid, sizeof(package->cuid)); @@ -584,14 +582,12 @@ int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo pthread_t thread_id[2]; // create and run worker threads - for (uint8_t i = 0; i < 2; i++) { + for (uint8_t i = 0; i < 2; i++) pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]); - } // wait for threads to terminate: - for (uint8_t i = 0; i < 2; i++) { + for (uint8_t i = 0; i < 2; i++) pthread_join(thread_id[i], (void *)&statelists[i].head.slhead); - } // the first 16 Bits of the cryptostate already contain part of our key. // Create the intersection of the two lists based on these 16 Bits and @@ -600,11 +596,9 @@ int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo p2 = p4 = statelists[1].head.slhead; while (p1 <= statelists[0].tail.sltail && p2 <= statelists[1].tail.sltail) { - if (Compare16Bits(p1, p2) == 0) { struct Crypto1State savestate; - savestate = *p1; while (Compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) { *p3 = *p1; @@ -612,7 +606,6 @@ int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo p3++; p1++; } - savestate = *p2; while (Compare16Bits(p2, &savestate) == 0 && p2 <= statelists[1].tail.sltail) { *p4 = *p2; @@ -620,7 +613,6 @@ int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo p4++; p2++; } - } else { while (Compare16Bits(p1, p2) == -1) p1++; while (Compare16Bits(p1, p2) == 1) p2++; @@ -643,15 +635,13 @@ int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo // Create the intersection statelists[0].len = intersection(statelists[0].head.keyhead, statelists[1].head.keyhead); - bool looped = false; - //statelists[0].tail.keytail = --p7; uint32_t keycnt = statelists[0].len; if (keycnt == 0) { goto out; } - PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") " key candidate%c", keycnt, (keycnt > 1) ? 's' : ' '); + PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") " key candidates", keycnt); memset(resultKey, 0, MIFARE_KEY_SIZE); uint64_t key64 = -1; @@ -669,53 +659,44 @@ int mf_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo register uint8_t j; for (j = 0; j < size; j++) { crypto1_get_lfsr(statelists[0].head.slhead + i, &key64); - num_to_bytes(key64, MIFARE_KEY_SIZE, keyBlock + j * MIFARE_KEY_SIZE); + num_to_bytes(key64, 6, keyBlock + j * MIFARE_KEY_SIZE); } if (mf_check_keys(statelists[0].blockNo, statelists[0].keyType, false, size, keyBlock, &key64) == PM3_SUCCESS) { - - if (looped) { - PrintAndLogEx(NORMAL, ""); - } - free(statelists[0].head.slhead); free(statelists[1].head.slhead); - num_to_bytes(key64, MIFARE_KEY_SIZE, resultKey); + num_to_bytes(key64, 6, resultKey); if (package->keytype < 2) { - PrintAndLogEx(SUCCESS, "Target block " _GREEN_("%4u") " key type " _GREEN_("%c") " -- found valid key [ " _GREEN_("%s") " ]", + PrintAndLogEx(SUCCESS, "\nTarget block %4u key type %c -- found valid key [ " _GREEN_("%s") " ]", package->block, package->keytype ? 'B' : 'A', sprint_hex_inrow(resultKey, MIFARE_KEY_SIZE) ); } else { - PrintAndLogEx(SUCCESS, "Target block " _GREEN_("%4u") " key type " _GREEN_("%02x") " -- found valid key [ " _GREEN_("%s") " ]", + PrintAndLogEx(SUCCESS, "\nTarget block %4u key type %02x -- found valid key [ " _GREEN_("%s") " ]", package->block, MIFARE_AUTH_KEYA + package->keytype, sprint_hex_inrow(resultKey, MIFARE_KEY_SIZE) ); } + + return PM3_SUCCESS; } float bruteforce_per_second = (float)(i + max_keys) / ((msclock() - start_time) / 1000.0); PrintAndLogEx(INPLACE, "%6d/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt - i) / bruteforce_per_second); - looped = true; } out: - - if (looped) { - PrintAndLogEx(NORMAL, ""); - } - if (package->keytype < 2) { - PrintAndLogEx(SUCCESS, "Target block " _YELLOW_("%4u") " key type " _YELLOW_("%c"), + PrintAndLogEx(SUCCESS, "\nTarget block %4u key type %c", package->block, package->keytype ? 'B' : 'A' ); } else { - PrintAndLogEx(SUCCESS, "Target block " _YELLOW_("%4u") " key type " _YELLOW_("%02x"), + PrintAndLogEx(SUCCESS, "\nTarget block %4u key type %02x", package->block, MIFARE_AUTH_KEYA + package->keytype ); @@ -930,11 +911,10 @@ int mf_static_nested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trg num_to_bytes(key64, MIFARE_KEY_SIZE, resultKey); - if (IfPm3Flash() && keycnt > 70) { + if (IfPm3Flash() && keycnt > 70) PrintAndLogEx(NORMAL, ""); - } - PrintAndLogEx(SUCCESS, "target block " _GREEN_("%4u") " key type " _GREEN_("%c") " -- found valid key [ " _GREEN_("%s") " ]", + PrintAndLogEx(SUCCESS, "target block %4u key type %c -- found valid key [ " _GREEN_("%s") " ]", package->block, package->keytype ? 'B' : 'A', sprint_hex_inrow(resultKey, MIFARE_KEY_SIZE) @@ -1011,7 +991,7 @@ int mf_read_block(uint8_t blockNo, uint8_t keyType, const uint8_t *key, uint8_t return PM3_SUCCESS; } -int mf_write_block(uint8_t blockno, uint8_t keyType, const uint8_t *key, const uint8_t *block) { +int mf_write_block(uint8_t blockno, uint8_t keyType, const uint8_t *key, uint8_t *block) { uint8_t data[26]; memcpy(data, key, MIFARE_KEY_SIZE); @@ -1328,28 +1308,6 @@ int mf_chinese_gen_3_freeze(void) { return resp.status; } -// GDM Gen4 write block -int mf_chinese_gen_4_set_block(uint8_t blockNo, uint8_t *block, uint8_t *key) { - struct p { - uint8_t blockno; - uint8_t key[6]; - uint8_t data[MFBLOCK_SIZE]; // data to be written - } PACKED payload; - - payload.blockno = blockNo; - memcpy(payload.key, key, sizeof(payload.key)); - memcpy(payload.data, block, sizeof(payload.data)); - - clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_G4_GDM_WRBL, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_MIFARE_G4_GDM_WRBL, &resp, 1500) == false) { - PrintAndLogEx(WARNING, "command execution time out"); - return PM3_ETIMEOUT; - } - return resp.status; -} - void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted) { if (len != 1) { for (int i = 0; i < len; i++) { @@ -1418,41 +1376,6 @@ int detect_classic_prng(void) { uint32_t nonce = bytes_to_num(respA.data.asBytes, respA.oldarg[0]); return validate_prng_nonce(nonce); } - - -/* Detect supported Auth, -* function performs a partial AUTH, where it tries to authenticate against block0, but only collects tag nonce. -* @returns -* TRUE if tag replies with a nonce -* FALSE is tag does not reply with a nonce -*/ -int detect_classic_auth(uint8_t key_type) { - - PacketResponseNG resp, respA; - uint8_t cmd[] = {MIFARE_AUTH_KEYA + key_type, 0x00}; - uint32_t flags = ISO14A_CONNECT | ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_RATS; - - clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_READER, flags, sizeof(cmd), 0, cmd, sizeof(cmd)); - if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { - PrintAndLogEx(WARNING, "timeout while waiting for reply"); - return PM3_ETIMEOUT; - } - - // if select tag failed. - if (resp.oldarg[0] == 0) { - PrintAndLogEx(ERR, "error: selecting tag failed, can't detect nonce\n"); - return PM3_ERFTRANS; - } - if (WaitForResponseTimeout(CMD_ACK, &respA, 2500) == false) { - PrintAndLogEx(WARNING, "timeout while waiting for reply"); - return PM3_ETIMEOUT; - } - - // check respA for a nonce - return respA.oldarg[0] == 4; -} - /* Detect Mifare Classic NACK bug returns: @@ -1516,19 +1439,19 @@ int detect_classic_nackbug(bool verbose) { return PM3_SUCCESS; } case 2: { - PrintAndLogEx(SUCCESS, "NACK test... " _GREEN_("always leak NACK")); + PrintAndLogEx(SUCCESS, "NACK test: " _GREEN_("always leak NACK")); return PM3_SUCCESS; } case 1: { - PrintAndLogEx(SUCCESS, "NACK test... " _GREEN_("detected")); + PrintAndLogEx(SUCCESS, "NACK test: " _GREEN_("detected")); return PM3_SUCCESS; } case 0: { - PrintAndLogEx(SUCCESS, "NACK test... " _GREEN_("no bug")); + PrintAndLogEx(SUCCESS, "NACK test: " _GREEN_("no bug")); return PM3_SUCCESS; } default: { - PrintAndLogEx(ERR, "errorcode from device (" _RED_("%u") " )", ok); + PrintAndLogEx(ERR, "errorcode from device " _RED_("[%i]"), ok); return PM3_EUNDEF; } } @@ -1590,21 +1513,10 @@ int detect_classic_static_encrypted_nonce_ex(uint8_t block_no, uint8_t key_type, cdata[21] = corruptnrar; cdata[22] = corruptnrarparity; - uint8_t dbg_curr = DBG_NONE; - if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) { - return PM3_EFAILED; - } - - if (setDeviceDebugLevel(verbose ? MAX(dbg_curr, DBG_INFO) : DBG_NONE, false) != PM3_SUCCESS) { - return PM3_EFAILED; - } - clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE, cdata, sizeof(cdata)); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE, &resp, 1500)) { - - setDeviceDebugLevel(dbg_curr, false); + if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE, &resp, 1000)) { if (resp.status == PM3_ESOFT) { return NONCE_FAIL; @@ -1670,8 +1582,6 @@ int detect_classic_static_encrypted_nonce_ex(uint8_t block_no, uint8_t key_type, } return resp.data.asBytes[0]; } - - setDeviceDebugLevel(dbg_curr, false); return NONCE_FAIL; } diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index 02c0422f0..fd065bfbc 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -26,7 +26,7 @@ #include "mifaredefault.h" // consts #include "protocol_vigik.h" -#define MIFARE_SECTOR_RETRY 6 +#define MIFARE_SECTOR_RETRY 10 // mifare tracer flags #define TRACE_IDLE 0x00 @@ -88,7 +88,7 @@ int mf_key_brute(uint8_t blockNo, uint8_t keyType, const uint8_t *key, uint64_t int mf_read_sector(uint8_t sectorNo, uint8_t keyType, const uint8_t *key, uint8_t *data); int mf_read_block(uint8_t blockNo, uint8_t keyType, const uint8_t *key, uint8_t *data); -int mf_write_block(uint8_t blockno, uint8_t keyType, const uint8_t *key, const uint8_t *block); +int mf_write_block(uint8_t blockno, uint8_t keyType, const uint8_t *key, uint8_t *block); int mf_write_sector(uint8_t sectorNo, uint8_t keyType, const uint8_t *key, uint8_t *sector); int mf_eml_get_mem(uint8_t *data, int blockNum, int blocksCount); @@ -105,12 +105,9 @@ int mf_chinese_gen_3_uid(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid); int mf_chinese_gen_3_block(uint8_t *block, int blockLen, uint8_t *newBlock); int mf_chinese_gen_3_freeze(void); -int mf_chinese_gen_4_set_block(uint8_t blockNo, uint8_t *block, uint8_t *key); - int try_decrypt_word(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len); int detect_classic_prng(void); -int detect_classic_auth(uint8_t key_type); int detect_classic_nackbug(bool verbose); uint16_t detect_mf_magic(bool is_mfc, uint8_t key_type, uint64_t key); int detect_classic_static_nonce(void); diff --git a/client/src/pm3line_vocabulary.h b/client/src/pm3line_vocabulary.h index 8c106751f..bfe823459 100644 --- a/client/src/pm3line_vocabulary.h +++ b/client/src/pm3line_vocabulary.h @@ -51,7 +51,6 @@ const static vocabulary_t vocabulary[] = { { 1, "prefs get hints" }, { 1, "prefs get output" }, { 1, "prefs get plotsliders" }, - { 1, "prefs get mqtt" }, { 1, "prefs set help" }, { 1, "prefs set barmode" }, { 1, "prefs set client.debug" }, @@ -63,7 +62,6 @@ const static vocabulary_t vocabulary[] = { { 1, "prefs set savepaths" }, { 1, "prefs set output" }, { 1, "prefs set plotsliders" }, - { 1, "prefs set mqtt" }, { 1, "analyse help" }, { 1, "analyse lrc" }, { 1, "analyse crc" }, @@ -242,7 +240,6 @@ const static vocabulary_t vocabulary[] = { { 0, "hf felica reader" }, { 0, "hf felica sniff" }, { 0, "hf felica wrbl" }, - { 0, "hf felica dump" }, { 0, "hf felica rqservice" }, { 0, "hf felica rqresponse" }, { 0, "hf felica scsvcode" }, @@ -252,7 +249,6 @@ const static vocabulary_t vocabulary[] = { { 0, "hf felica rqspecver" }, { 0, "hf felica resetmode" }, { 0, "hf felica litesim" }, - { 0, "hf felica liteauth" }, { 0, "hf felica litedump" }, { 1, "hf fido help" }, { 1, "hf fido list" }, @@ -285,7 +281,7 @@ const static vocabulary_t vocabulary[] = { { 1, "hf iclass view" }, { 0, "hf iclass wrbl" }, { 0, "hf iclass creditepurse" }, - { 0, "hf iclass tear" }, + { 0, "hf iclass trbl" }, { 0, "hf iclass chk" }, { 1, "hf iclass loclass" }, { 1, "hf iclass lookup" }, @@ -347,6 +343,8 @@ const static vocabulary_t vocabulary[] = { { 0, "hf lto wrbl" }, { 1, "hf mf help" }, { 1, "hf mf list" }, + { 0, "hf mf info" }, + { 0, "hf mf isen" }, { 0, "hf mf darkside" }, { 0, "hf mf nested" }, { 1, "hf mf hardnested" }, @@ -358,12 +356,9 @@ const static vocabulary_t vocabulary[] = { { 0, "hf mf fchk" }, { 1, "hf mf decrypt" }, { 0, "hf mf supercard" }, - { 1, "hf mf bambukeys" }, { 0, "hf mf auth4" }, { 1, "hf mf acl" }, { 0, "hf mf dump" }, - { 0, "hf mf info" }, - { 0, "hf mf isen" }, { 1, "hf mf mad" }, { 0, "hf mf personalize" }, { 0, "hf mf rdbl" }, @@ -477,7 +472,6 @@ const static vocabulary_t vocabulary[] = { { 0, "hf mfdes getkeyversions" }, { 0, "hf mfdes getfileids" }, { 0, "hf mfdes getfileisoids" }, - { 0, "hf mfdes lsfile" }, { 0, "hf mfdes lsfiles" }, { 0, "hf mfdes dump" }, { 0, "hf mfdes createfile" }, @@ -799,7 +793,6 @@ const static vocabulary_t vocabulary[] = { { 0, "lf t55xx restore" }, { 1, "lf t55xx trace" }, { 0, "lf t55xx wakeup" }, - { 1, "lf t55xx view" }, { 0, "lf t55xx write" }, { 0, "lf t55xx bruteforce" }, { 0, "lf t55xx chk" }, @@ -838,9 +831,6 @@ const static vocabulary_t vocabulary[] = { { 0, "mem spiffs upload" }, { 0, "mem spiffs view" }, { 0, "mem spiffs wipe" }, - { 1, "mqtt help" }, - { 1, "mqtt send" }, - { 1, "mqtt receive" }, { 1, "nfc help" }, { 1, "nfc decode" }, { 0, "nfc type1 read" }, diff --git a/client/src/preferences.c b/client/src/preferences.c index f654a8533..37941ed65 100644 --- a/client/src/preferences.c +++ b/client/src/preferences.c @@ -48,54 +48,6 @@ static char *prefGetFilename(void) { return str_dup(preferencesFilename); } -static bool setDefaultMqttServer(const char *srv) { - - if ((srv == NULL) && (g_session.mqtt_server != NULL)) { - free(g_session.mqtt_server); - g_session.mqtt_server = NULL; - } - - if (srv == NULL) { - return false; - } - - g_session.mqtt_server = (char *)realloc(g_session.mqtt_server, strlen(srv) + 1); - strcpy(g_session.mqtt_server, srv); - return true; -} - -static bool setDefaultMqttPort(const char *port) { - - if ((port == NULL) && (g_session.mqtt_port != NULL)) { - free(g_session.mqtt_port); - g_session.mqtt_port = NULL; - } - - if (port == NULL) { - return false; - } - - g_session.mqtt_port = (char *)realloc(g_session.mqtt_port, strlen(port) + 1); - strcpy(g_session.mqtt_port, port); - return true; -} - -static bool setDefaultMqttTopic(const char *topic) { - - if ((topic == NULL) && (g_session.mqtt_topic != NULL)) { - free(g_session.mqtt_topic); - g_session.mqtt_topic = NULL; - } - - if (topic == NULL) { - return false; - } - - g_session.mqtt_topic = (char *)realloc(g_session.mqtt_topic, strlen(topic) + 1); - strcpy(g_session.mqtt_topic, topic); - return true; -} - int preferences_load(void) { // Set all defaults @@ -121,10 +73,6 @@ int preferences_load(void) { setDefaultPath(spDump, ""); setDefaultPath(spTrace, ""); - setDefaultMqttServer(""); - setDefaultMqttPort(""); - setDefaultMqttTopic(""); - // default save path if (get_my_user_directory() != NULL) { // should return path to .proxmark3 folder setDefaultPath(spDefault, get_my_user_directory()); @@ -329,13 +277,7 @@ void preferences_save_callback(json_t *root) { */ JsonSaveInt(root, "client.exe.delay", g_session.client_exe_delay); JsonSaveInt(root, "client.timeout", g_session.timeout); - - // MQTT - JsonSaveStr(root, "mqtt.server", g_session.mqtt_server); - JsonSaveStr(root, "mqtt.port", g_session.mqtt_port); - JsonSaveStr(root, "mqtt.topic", g_session.mqtt_topic); } - void preferences_load_callback(json_t *root) { json_error_t up_error = {0}; int b1; @@ -439,17 +381,6 @@ void preferences_load_callback(json_t *root) { // client command timeout if (json_unpack_ex(root, &up_error, 0, "{s:i}", "client.timeout", &i1) == 0) g_session.timeout = i1; - - // MQTT server - if (json_unpack_ex(root, &up_error, 0, "{s:s}", "mqtt.server", &s1) == 0) - setDefaultMqttServer(s1); - - if (json_unpack_ex(root, &up_error, 0, "{s:s}", "mqtt.port", &s1) == 0) - setDefaultMqttPort(s1); - - if (json_unpack_ex(root, &up_error, 0, "{s:s}", "mqtt.topic", &s1) == 0) - setDefaultMqttTopic(s1); - } // Help Functions @@ -469,6 +400,7 @@ static const char *pref_show_status_msg(prefShowOpt_t opt) { case prefShowUnknown: default: return ""; + } } @@ -588,7 +520,6 @@ static void showSavePathState(savePaths_t path_index, prefShowOpt_t opt) { case spItemCount: default: strcpy(s, _RED_("unknown")" save path......."); - break; } if (path_index < spItemCount) { @@ -671,30 +602,6 @@ static void showClientTimeoutState(void) { PrintAndLogEx(INFO, " communication timeout... " _GREEN_("%u") " ms", g_session.timeout); } -static void showMqttServer(prefShowOpt_t opt) { - if ((g_session.mqtt_server == NULL) || (strcmp(g_session.mqtt_server, "") == 0)) { - PrintAndLogEx(INFO, " MQTT server.............%s "_WHITE_("not set"), pref_show_status_msg(opt)); - } else { - PrintAndLogEx(INFO, " MQTT server.............%s "_GREEN_("%s"), pref_show_status_msg(opt), g_session.mqtt_server); - } -} - -static void showMqttPort(prefShowOpt_t opt) { - if ((g_session.mqtt_port == NULL) || (strcmp(g_session.mqtt_port, "") == 0)) { - PrintAndLogEx(INFO, " MQTT port...............%s "_WHITE_("not set"), pref_show_status_msg(opt)); - } else { - PrintAndLogEx(INFO, " MQTT port...............%s "_GREEN_("%s"), pref_show_status_msg(opt), g_session.mqtt_port); - } -} - -static void showMqttTopic(prefShowOpt_t opt) { - if ((g_session.mqtt_topic == NULL) || (strcmp(g_session.mqtt_topic, "") == 0)) { - PrintAndLogEx(INFO, " MQTT topic..............%s "_WHITE_("not set"), pref_show_status_msg(opt)); - } else { - PrintAndLogEx(INFO, " MQTT topic..............%s "_GREEN_("%s"), pref_show_status_msg(opt), g_session.mqtt_topic); - } -} - static int setCmdEmoji(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "prefs set emoji ", @@ -1030,7 +937,7 @@ static int setCmdExeDelay(const char *Cmd) { return PM3_SUCCESS; } -static int setCmdClientTimeout(const char *Cmd) { +static int setClientTimeout(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "prefs set client.timeout", "Set persistent preference of client communication timeout", @@ -1281,80 +1188,6 @@ static int setCmdBarMode(const char *Cmd) { return PM3_SUCCESS; } -static int setCmdMqtt(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "prefs set mqtt", - "Set persistent preference MQTT Server in the client", - "prefs set mqtt -s test.mosquito.com\n" - "prefs set mqtt -s test.mosquito.com -p 1883 -t proxdump\n" - ); - - void *argtable[] = { - arg_param_begin, - arg_str0("s", "srv", "", "default MQTT Server"), - arg_str0("p", "port", "", "default MQTT Port"), - arg_str0("t", "topic", "", "default MQTT Topic"), - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - int deflen = 0; - char def_server[128] = {0}; - memset(def_server, 0, sizeof(def_server)); - int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)def_server, sizeof(def_server), &deflen); - - int plen = 0; - char def_port[10] = {0}; - memset(def_port, 0, sizeof(def_port)); - res |= CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)def_port, sizeof(def_port), &plen); - - int tlen = 0; - char def_topic[10] = {0}; - memset(def_topic, 0, sizeof(def_topic)); - res |= CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)def_topic, sizeof(def_topic), &tlen); - CLIParserFree(ctx); - - // sanity checks - if (res) { - PrintAndLogEx(FAILED, "Error parsing input strings"); - return PM3_EINVARG; - } - - if (deflen) { - if (strcmp(def_server, g_session.mqtt_server) != 0) { - showMqttServer(prefShowOLD); - setDefaultMqttServer(def_server); - showMqttServer(prefShowNEW); - preferences_save(); - } else { - showMqttServer(prefShowNone); - } - } - - if (plen) { - if (strcmp(def_port, g_session.mqtt_port) != 0) { - showMqttPort(prefShowOLD); - setDefaultMqttPort(def_port); - showMqttPort(prefShowNEW); - preferences_save(); - } else { - showMqttPort(prefShowNone); - } - } - - if (tlen) { - if (strcmp(def_topic, g_session.mqtt_topic) != 0) { - showMqttTopic(prefShowOLD); - setDefaultMqttTopic(def_topic); - showMqttTopic(prefShowNEW); - preferences_save(); - } else { - showMqttTopic(prefShowNone); - } - } - - return PM3_SUCCESS; -} - static int getCmdEmoji(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "prefs get emoji", @@ -1501,7 +1334,7 @@ static int getCmdExeDelay(const char *Cmd) { return PM3_SUCCESS; } -static int getCmdClientTimeout(const char *Cmd) { +static int getClientTimeout(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "prefs get client.timeout", "Get preference of delay time before execution of a command in the client", @@ -1517,29 +1350,11 @@ static int getCmdClientTimeout(const char *Cmd) { return PM3_SUCCESS; } -static int getCmdMqtt(const char *Cmd) { - CLIParserContext *ctx; - CLIParserInit(&ctx, "prefs get mqtt", - "Get preference of MQTT settings in the client", - "prefs get mqtt" - ); - void *argtable[] = { - arg_param_begin, - arg_param_end - }; - CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIParserFree(ctx); - showMqttServer(prefShowNone); - showMqttPort(prefShowNone); - showMqttTopic(prefShowNone); - return PM3_SUCCESS; -} - static command_t CommandTableGet[] = { {"barmode", getCmdBarMode, AlwaysAvailable, "Get bar mode preference"}, {"client.debug", getCmdDebug, AlwaysAvailable, "Get client debug level preference"}, {"client.delay", getCmdExeDelay, AlwaysAvailable, "Get client execution delay preference"}, - {"client.timeout", getCmdClientTimeout, AlwaysAvailable, "Get client execution delay preference"}, + {"client.timeout", getClientTimeout, AlwaysAvailable, "Get client execution delay preference"}, {"color", getCmdColor, AlwaysAvailable, "Get color support preference"}, {"savepaths", getCmdSavePaths, AlwaysAvailable, "Get file folder "}, // {"devicedebug", getCmdDeviceDebug, AlwaysAvailable, "Get device debug level"}, @@ -1547,7 +1362,6 @@ static command_t CommandTableGet[] = { {"hints", getCmdHint, AlwaysAvailable, "Get hint display preference"}, {"output", getCmdOutput, AlwaysAvailable, "Get dump output style preference"}, {"plotsliders", getCmdPlotSlider, AlwaysAvailable, "Get plot slider display preference"}, - {"mqtt", getCmdMqtt, AlwaysAvailable, "Get MQTT preference"}, {NULL, NULL, NULL, NULL} }; @@ -1556,7 +1370,7 @@ static command_t CommandTableSet[] = { {"barmode", setCmdBarMode, AlwaysAvailable, "Set bar mode"}, {"client.debug", setCmdDebug, AlwaysAvailable, "Set client debug level"}, {"client.delay", setCmdExeDelay, AlwaysAvailable, "Set client execution delay"}, - {"client.timeout", setCmdClientTimeout, AlwaysAvailable, "Set client communication timeout"}, + {"client.timeout", setClientTimeout, AlwaysAvailable, "Set client communication timeout"}, {"color", setCmdColor, AlwaysAvailable, "Set color support"}, {"emoji", setCmdEmoji, AlwaysAvailable, "Set emoji display"}, @@ -1565,7 +1379,6 @@ static command_t CommandTableSet[] = { // {"devicedebug", setCmdDeviceDebug, AlwaysAvailable, "Set device debug level"}, {"output", setCmdOutput, AlwaysAvailable, "Set dump output style"}, {"plotsliders", setCmdPlotSliders, AlwaysAvailable, "Set plot slider display"}, - {"mqtt", setCmdMqtt, AlwaysAvailable, "Set MQTT default values"}, {NULL, NULL, NULL, NULL} }; @@ -1630,9 +1443,6 @@ static int CmdPrefShow(const char *Cmd) { showClientExeDelayState(); showOutputState(prefShowNone); showClientTimeoutState(); - showMqttServer(prefShowNone); - showMqttPort(prefShowNone); - showMqttTopic(prefShowNone); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index 2904aaab8..de668a0c0 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -17,12 +17,14 @@ //----------------------------------------------------------------------------- #include "proxmark3.h" + #include #include #include #include #include // basename #include + #include "pm3line.h" #include "usart_defs.h" #include "util_posix.h" @@ -41,12 +43,13 @@ #include #endif + static int mainret = PM3_SUCCESS; #ifndef LIBPM3 #define BANNERMSG1 "" #define BANNERMSG2 "" -#define BANNERMSG3 "" +#define BANNERMSG3 "Release v4.20142 - Blue Ice" typedef enum LogoMode { UTF8, ANSI, ASCII } LogoMode; @@ -72,9 +75,8 @@ static void showBanner_logo(LogoMode mode) { sq, sq, tl, hl, hl, hl, br, __, sq, sq, vl, bl, sq, sq, tl, br, sq, sq, vl, __, bl, hl, hl, sq, sq, tr); PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")" " BANNERMSG1, sq, sq, vl, __, __, __, __, __, sq, sq, vl, __, bl, hl, br, __, sq, sq, vl, sq, sq, sq, sq, sq, tl, br); - PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"), + PrintAndLogEx(NORMAL, " " _BLUE_("%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s")" " BANNERMSG2, bl, hl, br, __, __, __, __, __, bl, hl, br, __, __, __, __, __, bl, hl, br, bl, hl, hl, hl, hl, br, __); - PrintAndLogEx(NORMAL, " " BANNERMSG2); break; } case ANSI: { @@ -85,8 +87,7 @@ static void showBanner_logo(LogoMode mode) { PrintAndLogEx(NORMAL, " " _CYAN_("8888888P\" 888 Y888P 888 \"Y8b. ")); PrintAndLogEx(NORMAL, " " _CYAN_("888 888 Y8P 888 888 888 ")); PrintAndLogEx(NORMAL, " " _CYAN_("888 888 \" 888 Y88b d88P") " " BANNERMSG1); - PrintAndLogEx(NORMAL, " " _CYAN_("888 888 888 \"Y8888P\"")); - PrintAndLogEx(NORMAL, " " BANNERMSG2); + PrintAndLogEx(NORMAL, " " _CYAN_("888 888 888 \"Y8888P\"") " " BANNERMSG2); break; } case ASCII: { @@ -97,11 +98,11 @@ static void showBanner_logo(LogoMode mode) { PrintAndLogEx(NORMAL, " 8888888P\" 888 Y888P 888 \"Y8b. "); PrintAndLogEx(NORMAL, " 888 888 Y8P 888 888 888 "); PrintAndLogEx(NORMAL, " 888 888 \" 888 Y88b d88P " BANNERMSG1); - PrintAndLogEx(NORMAL, " 888 888 888 \"Y8888P\""); - PrintAndLogEx(NORMAL, " " BANNERMSG2); + PrintAndLogEx(NORMAL, " 888 888 888 \"Y8888P\" " BANNERMSG2); break; } } + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, BANNERMSG3); } @@ -124,18 +125,17 @@ static uint8_t detect_current_lang(void) { static const char *get_quote(void) { const char *quotes_en[] = { - "too many secrets", - "It's not that simple", - "I have received a coded signal", - "I await your instructions", - "And so I watch, I wait", - "Listen to the Domain", - "ghost.713", - "Local node X.XX.713", - "Beggar after knowledge", - "343 Gulity Spark: offline", - "I serve the Builders!", - "This is rather distressing" + "E Pluribus Unum", + "Carpe Diem", + "Ad astra per aspera", + "Fortes fortuna adiuvat", + "Non ducor, duco", + "Veni, vidi, vici", + "Audentes fortuna iuvat", + "Virtus in actione consistit", + "Dum spiro, spero", + "Non scholae, sed vitae discimus", + "Faber est suae quisque fortunae" }; const char *quotes_fr[] = { @@ -206,6 +206,7 @@ static void showBanner(void) { PrintAndLogEx(NORMAL, " [ " _YELLOW_("%s!")" :coffee: ]", get_quote()); // PrintAndLogEx(NORMAL, " [ https://patreon.com/iceman1001/ ]"); +// PrintAndLogEx(NORMAL, ""); // PrintAndLogEx(NORMAL, " Monero"); // PrintAndLogEx(NORMAL, " 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP"); PrintAndLogEx(NORMAL, ""); @@ -304,18 +305,16 @@ static bool DetectWindowsAnsiSupport(void) { #endif // disable colors if stdin or stdout are redirected - if ((! g_session.stdinOnTTY) || (! g_session.stdoutOnTTY)) { + if ((! g_session.stdinOnTTY) || (! g_session.stdoutOnTTY)) return false; - } HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); DWORD dwMode = 0; GetConsoleMode(hOut, &dwMode); //ENABLE_VIRTUAL_TERMINAL_PROCESSING is already set - if ((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { + if ((dwMode & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) return true; - } dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; @@ -335,13 +334,11 @@ int push_cmdscriptfile(char *path, bool stayafter) { } FILE *f = fopen(path, "r"); - if (f == NULL) { + if (f == NULL) return PM3_EFILE; - } - if (cmdscriptfile_idx == 0) { + if (cmdscriptfile_idx == 0) cmdscriptfile_stayafter = stayafter; - } cmdscriptfile[++cmdscriptfile_idx] = f; return PM3_SUCCESS; @@ -373,32 +370,28 @@ main_loop(const char *script_cmds_file, char *script_cmd, bool stayInCommandLoop bool execCommand = (script_cmd != NULL); bool fromInteractive = false; uint16_t script_cmd_len = 0; - if (execCommand) { script_cmd_len = strlen(script_cmd); str_creplace(script_cmd, script_cmd_len, ';', '\0'); } - bool stdinOnPipe = !isatty(STDIN_FILENO); char script_cmd_buf[256] = {0x00}; // iceman, needs lua script the same file_path_buffer as the rest // cache Version information now: - if (execCommand || script_cmds_file || stdinOnPipe) { + if (execCommand || script_cmds_file || stdinOnPipe) pm3_version(false, false); - } else { + else pm3_version_short(); - } if (script_cmds_file) { char *path; int res = searchFile(&path, CMD_SCRIPTS_SUBDIR, script_cmds_file, ".cmd", false); if (res == PM3_SUCCESS) { - if (push_cmdscriptfile(path, stayInCommandLoop) == PM3_SUCCESS) { + if (push_cmdscriptfile(path, stayInCommandLoop) == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "executing commands from file: %s\n", path); - } else { + else PrintAndLogEx(ERR, "could not open " _YELLOW_("%s") "...", path); - } free(path); } } @@ -455,23 +448,20 @@ check_script: prompt_ctx = stdinOnPipe ? PROXPROMPT_CTX_STDIN : PROXPROMPT_CTX_SCRIPTCMD; cmd = str_dup(script_cmd); - if ((cmd != NULL) && (! fromInteractive)) { + if ((cmd != NULL) && (! fromInteractive)) printprompt = true; - } uint16_t len = strlen(script_cmd) + 1; script_cmd += len; - if (script_cmd_len == len - 1) { + if (script_cmd_len == len - 1) execCommand = false; - } script_cmd_len -= len; } else { // exit after exec command - if (script_cmd && !stayInCommandLoop) { + if (script_cmd && !stayInCommandLoop) break; - } // if there is a pipe from stdin if (stdinOnPipe) { @@ -561,27 +551,22 @@ check_script: mainret = CommandReceived(cmd); // exit or quit - if (mainret == PM3_EFATAL) { + if (mainret == PM3_EFATAL) break; - } - if (mainret == PM3_SQUIT) { // Normal quit, map to 0 mainret = PM3_SUCCESS; break; } } - free(cmd); cmd = NULL; - } else { PrintAndLogEx(NORMAL, "\n"); - if (script_cmds_file && stayInCommandLoop) { + if (script_cmds_file && stayInCommandLoop) stayInCommandLoop = false; - } else { + else break; - } } } // end while @@ -630,9 +615,8 @@ const char *get_my_executable_directory(void) { static void set_my_executable_path(void) { int path_length = wai_getExecutablePath(NULL, 0, NULL); - if (path_length == -1) { + if (path_length == -1) return; - } my_executable_path = (char *)calloc(path_length + 1, sizeof(uint8_t)); int dirname_length = 0; @@ -857,13 +841,12 @@ finish2: CloseProxmark(g_session.current_device); finish: - if (ret == PM3_SUCCESS) { + if (ret == PM3_SUCCESS) PrintAndLogEx(SUCCESS, _CYAN_("All done")); - } else if (ret == PM3_EOPABORTED) { + else if (ret == PM3_EOPABORTED) PrintAndLogEx(FAILED, "Aborted by user"); - } else { + else PrintAndLogEx(ERR, "Aborted on error %u", ret); - } return ret; } @@ -922,9 +905,8 @@ static int flash_pm3(char *serial_port_name, uint8_t num_files, const char *file goto finish; } - if (num_files == 0) { + if (num_files == 0) goto finish; - } for (int i = 0 ; i < num_files; ++i) { ret = flash_prepare(&files[i], can_write_bl, max_allowed * ONE_KB); @@ -945,26 +927,20 @@ static int flash_pm3(char *serial_port_name, uint8_t num_files, const char *file } finish: - if (ret != PM3_SUCCESS) { + if (ret != PM3_SUCCESS) PrintAndLogEx(WARNING, "The flashing procedure failed, follow the suggested steps!"); - } - ret = flash_stop_flashing(); CloseProxmark(g_session.current_device); - finish2: for (int i = 0 ; i < num_files; ++i) { flash_free(&files[i]); } - - if (ret == PM3_SUCCESS) { + if (ret == PM3_SUCCESS) PrintAndLogEx(SUCCESS, _CYAN_("All done")); - } else if (ret == PM3_EOPABORTED) { + else if (ret == PM3_EOPABORTED) PrintAndLogEx(FAILED, "Aborted by user"); - } else { + else PrintAndLogEx(ERR, "Aborted on error"); - } - PrintAndLogEx(INFO, "\nHave a nice day!"); return ret; } @@ -1000,6 +976,7 @@ void pm3_init(void) { // set global variables soon enough to get the log path set_my_executable_path(); set_my_user_directory(); + } #ifndef LIBPM3 @@ -1074,7 +1051,6 @@ int main(int argc, char *argv[]) { show_help(false, exec_name); return 1; } - if (port != NULL) { // We got already one PrintAndLogEx(ERR, _RED_("ERROR:") " cannot parse command line. We got " _YELLOW_("%s") " as port and now we got also: " _YELLOW_("%s") "\n", port, argv[i + 1]); @@ -1336,22 +1312,21 @@ int main(int argc, char *argv[]) { // This will allow the command line to override the settings.json values preferences_load(); // quick patch for debug level - if (debug_mode_forced == false) { + if (! debug_mode_forced) { g_debugMode = g_session.client_debug_level; } // settings_save (); // End Settings // even if prefs, we disable colors if stdin or stdout is not a TTY - if ((g_session.stdinOnTTY == false) || (g_session.stdoutOnTTY == false)) { + if ((! g_session.stdinOnTTY) || (! g_session.stdoutOnTTY)) { g_session.supports_colors = false; g_session.emoji_mode = EMO_ALTTEXT; } // Let's take a baudrate ok for real UART, USB-CDC & BT don't use that info anyway - if (speed == 0) { + if (speed == 0) speed = USART_BAUD_RATE; - } if (dumpmem_mode) { dumpmem_pm3(port, dumpmem_filename, dumpmem_addr, dumpmem_len, dumpmem_raw); @@ -1369,9 +1344,8 @@ int main(int argc, char *argv[]) { } if (script_cmd) { - while (script_cmd[strlen(script_cmd) - 1] == ' ') { + while (script_cmd[strlen(script_cmd) - 1] == ' ') script_cmd[strlen(script_cmd) - 1] = 0x00; - } if (strlen(script_cmd) == 0) { script_cmd = NULL; @@ -1404,23 +1378,23 @@ int main(int argc, char *argv[]) { CloseProxmark(g_session.current_device); } - if ((port != NULL) && (g_session.pm3_present == false)) { + if ((port != NULL) && (!g_session.pm3_present)) { exit(EXIT_FAILURE); } - if (g_session.pm3_present == false) { + if (!g_session.pm3_present) { PrintAndLogEx(INFO, _YELLOW_("OFFLINE") " mode. Check " _YELLOW_("\"%s -h\"") " if it's not what you want.\n", exec_name); } // ascii art only in interactive client - if (!script_cmds_file && !script_cmd && g_session.stdinOnTTY && g_session.stdoutOnTTY && (dumpmem_mode == false) && (flash_mode == false) && (reboot_bootloader_mode == false)) { + if (!script_cmds_file && !script_cmd && g_session.stdinOnTTY && g_session.stdoutOnTTY && !dumpmem_mode && !flash_mode && !reboot_bootloader_mode) { showBanner(); } // Save settings if not loaded from settings json file. // Doing this here will ensure other checks and updates are saved to over rule default // e.g. Linux color use check - if ((g_session.preferences_loaded == false) && (g_session.incognito == false)) { + if ((!g_session.preferences_loaded) && (!g_session.incognito)) { PrintAndLogEx(INFO, "Creating initial preferences file"); // json save reports file name, so just info msg here preferences_save(); // Save defaults g_session.preferences_loaded = true; @@ -1440,7 +1414,7 @@ int main(int argc, char *argv[]) { #ifdef HAVE_GUI -# if defined(_WIN32) || (defined(__MACH__) && defined(__APPLE__)) +# if defined(_WIN32) InitGraphics(argc, argv, script_cmds_file, script_cmd, stayInCommandLoop); MainGraphics(); # else diff --git a/client/src/pthread_spin_lock_shim.h b/client/src/pthread_spin_lock_shim.h deleted file mode 100644 index 243771a6c..000000000 --- a/client/src/pthread_spin_lock_shim.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - -Required imports: -#include - -*/ - -#ifndef PTHREAD_SPIN_LOCK_SHIM -#define PTHREAD_SPIN_LOCK_SHIM - -typedef int pthread_spinlock_t; - -#ifndef PTHREAD_PROCESS_SHARED -# define PTHREAD_PROCESS_SHARED 1 -#endif -#ifndef PTHREAD_PROCESS_PRIVATE -# define PTHREAD_PROCESS_PRIVATE 2 -#endif - -static inline int pthread_spin_init(pthread_spinlock_t *lock, int pshared) { - __asm__ __volatile__("" ::: "memory"); - *lock = 0; - return 0; -} - -static inline int pthread_spin_destroy(pthread_spinlock_t *lock) { - return 0; -} - -static inline int pthread_spin_lock(pthread_spinlock_t *lock) { - while (1) { - int i; - for (i = 0; i < 10000; i++) { - if (__sync_bool_compare_and_swap(lock, 0, 1)) { - return 0; - } - } - sched_yield(); - } -} - -static inline int pthread_spin_trylock(pthread_spinlock_t *lock) { - if (__sync_bool_compare_and_swap(lock, 0, 1)) { - return 0; - } - return 16; // EBUSY; -} - -static inline int pthread_spin_unlock(pthread_spinlock_t *lock) { - __asm__ __volatile__("" ::: "memory"); - *lock = 0; - return 0; -} - -#endif diff --git a/client/src/scripting.c b/client/src/scripting.c index 1cd1ed1a0..251a0d915 100644 --- a/client/src/scripting.c +++ b/client/src/scripting.c @@ -303,7 +303,7 @@ static int l_GetFromFlashMemSpiffs(lua_State *L) { // get size from spiffs itself ! SendCommandNG(CMD_SPIFFS_STAT, (uint8_t *)destfilename, 32); PacketResponseNG resp; - if (WaitForResponseTimeout(CMD_SPIFFS_STAT, &resp, 2000) == false) + if (!WaitForResponseTimeout(CMD_SPIFFS_STAT, &resp, 2000)) return returnToLuaWithError(L, "No response from the device"); len = resp.data.asDwords[0]; diff --git a/client/src/uart/uart_common.c b/client/src/uart/uart_common.c index f797d763c..e10897326 100644 --- a/client/src/uart/uart_common.c +++ b/client/src/uart/uart_common.c @@ -39,36 +39,31 @@ #endif bool uart_bind(void *socket, const char *bindAddrStr, const char *bindPortStr, bool isBindingIPv6) { - if (bindAddrStr == NULL && bindPortStr == NULL) { + if (bindAddrStr == NULL && bindPortStr == NULL) return true; // no need to bind - } struct sockaddr_storage bindSockaddr; memset(&bindSockaddr, 0, sizeof(bindSockaddr)); int bindPort = 0; // 0: port unspecified - if (bindPortStr != NULL) { + if (bindPortStr != NULL) bindPort = atoi(bindPortStr); - } - if (isBindingIPv6 == false) { + if (!isBindingIPv6) { struct sockaddr_in *bindSockaddr4 = (struct sockaddr_in *)&bindSockaddr; bindSockaddr4->sin_family = AF_INET; bindSockaddr4->sin_port = htons(bindPort); - if (bindAddrStr == NULL) { + if (bindAddrStr == NULL) bindSockaddr4->sin_addr.s_addr = INADDR_ANY; - } else { + else bindSockaddr4->sin_addr.s_addr = inet_addr(bindAddrStr); - } - } else { struct sockaddr_in6 *bindSockaddr6 = (struct sockaddr_in6 *)&bindSockaddr; bindSockaddr6->sin6_family = AF_INET6; bindSockaddr6->sin6_port = htons(bindPort); - if (bindAddrStr == NULL) { + if (bindAddrStr == NULL) bindSockaddr6->sin6_addr = in6addr_any; - } else { + else inet_pton(AF_INET6, bindAddrStr, &(bindSockaddr6->sin6_addr)); - } } #ifdef _WIN32 int res = bind(*(SOCKET *)socket, (struct sockaddr *)&bindSockaddr, sizeof(bindSockaddr)); diff --git a/client/src/ui.c b/client/src/ui.c index 1901ac9ef..4aed59a45 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -424,13 +424,18 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) { #ifdef RL_STATE_READCMD // We are using GNU readline. libedit (OSX) doesn't support this flag. int need_hack = (rl_readline_state & RL_STATE_READCMD) > 0; - char *saved_line = NULL; + char *saved_line; + int saved_point; if (need_hack) { + saved_point = rl_point; saved_line = rl_copy_text(0, rl_end); - rl_clear_visible_line(); + rl_save_prompt(); + rl_replace_line("", 0); + rl_redisplay(); } #endif + va_start(argptr, fmt); vsnprintf(buffer, sizeof(buffer), fmt, argptr); va_end(argptr); @@ -448,13 +453,14 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) { if (linefeed) { fprintf(stream, "\n"); } - fflush(stream); } #ifdef RL_STATE_READCMD + // We are using GNU readline. libedit (OSX) doesn't support this flag. if (need_hack) { - rl_on_new_line(); + rl_restore_prompt(); rl_replace_line(saved_line, 0); + rl_point = saved_point; rl_redisplay(); free(saved_line); } diff --git a/client/src/ui.h b/client/src/ui.h index b79798862..95ed70390 100644 --- a/client/src/ui.h +++ b/client/src/ui.h @@ -63,9 +63,6 @@ typedef struct { char *history_path; pm3_device_t *current_device; uint32_t timeout; - char *mqtt_server; - char *mqtt_port; - char *mqtt_topic; } session_arg_t; extern session_arg_t g_session; diff --git a/client/src/util.c b/client/src/util.c index 133f639ee..6a54387d2 100644 --- a/client/src/util.c +++ b/client/src/util.c @@ -73,7 +73,6 @@ int kbd_enter_pressed(void) { c = getchar(); ret |= c == '\n'; } while (c != EOF); - //blocking flags &= ~O_NONBLOCK; if (fcntl(STDIN_FILENO, F_SETFL, flags) < 0) { @@ -1213,29 +1212,6 @@ void binstr_2_bytes(uint8_t *target, size_t *targetlen, const char *src) { } } -void binstr_2_u8(char *src, uint8_t n, uint8_t *dest) { - - uint8_t b = 0; - // Process binary string - for (uint8_t i = 0; i < n; ++i) { - b = (b << 1) | (src[i] == '1'); - } - if (dest) { - *dest = b; - } -} - -void binstr_2_u16(char *src, uint8_t n, uint16_t *dest) { - uint16_t b = 0; - // Process binary string - for (uint8_t i = 0; i < n; ++i) { - b = (b << 1) | (src[i] == '1'); - } - if (dest) { - *dest = b; - } -} - void hex_xor(uint8_t *d, const uint8_t *x, int n) { while (n--) { d[n] ^= x[n]; @@ -1433,20 +1409,6 @@ void str_inverse_bin(char *buf, size_t len) { } } -void str_trim(char *s) { - if (s == NULL) { - return; - } - - // handle empty string - if (!*s) { - return; - } - - char *ptr; - for (ptr = s + strlen(s) - 1; (ptr >= s) && isspace(*ptr); --ptr); - ptr[1] = '\0'; -} /** * Converts a hex string to component "hi2", "hi" and "lo" 32-bit integers @@ -1630,40 +1592,3 @@ uint8_t get_highest_frequency(const uint8_t *d, uint8_t n) { PrintAndLogEx(DEBUG, "highest occurance... %u xor byte... 0x%02X", highest, v); return v; } - -size_t unduplicate(uint8_t *d, size_t n, const uint8_t item_n) { - if (n == 0) { - return 0; - } - if (n == 1) { - return 1; - } - - int write_index = 0; - - for (int read_index = 0; read_index < n; ++read_index) { - uint8_t *current = d + read_index * item_n; - - bool is_duplicate = false; - - // Check against all previous unique elements - for (int i = 0; i < write_index; ++i) { - uint8_t *unique = d + i * item_n; - if (memcmp(current, unique, item_n) == 0) { - is_duplicate = 1; - break; - } - } - - // If not duplicate, move to the write_index position - if (is_duplicate == false) { - uint8_t *dest = d + write_index * item_n; - if (dest != current) { - memcpy(dest, current, item_n); - } - write_index++; - } - } - - return write_index; -} diff --git a/client/src/util.h b/client/src/util.h index 186f2e2a7..d4c34eb46 100644 --- a/client/src/util.h +++ b/client/src/util.h @@ -141,9 +141,6 @@ int binstr_2_binarray(uint8_t *target, char *source, int length); void bytes_2_binstr(char *target, const uint8_t *source, size_t sourcelen); void binstr_2_bytes(uint8_t *target, size_t *targetlen, const char *src); -void binstr_2_u8(char *src, uint8_t n, uint8_t *dest); -void binstr_2_u16(char *src, uint8_t n, uint16_t *dest); - void hex_xor(uint8_t *d, const uint8_t *x, int n); void hex_xor_token(uint8_t *d, const uint8_t *x, int dn, int xn); @@ -171,12 +168,10 @@ void str_creplace(char *buf, size_t len, char from, char to); void str_reverse(char *buf, size_t len); void str_inverse_hex(char *buf, size_t len); void str_inverse_bin(char *buf, size_t len); -void str_trim(char *s); char *str_dup(const char *src); char *str_ndup(const char *src, size_t len); size_t str_nlen(const char *src, size_t maxlen); - int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str); int binstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str); int binarray_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const uint8_t *arr, int arrlen); @@ -197,7 +192,4 @@ struct smartbuf { void sb_append_char(smartbuf *sb, unsigned char c); uint8_t get_highest_frequency(const uint8_t *d, uint8_t n); - -size_t unduplicate(uint8_t *d, size_t n, const uint8_t item_n); - #endif diff --git a/client/src/wiegand_formats.c b/client/src/wiegand_formats.c index fa1d68eb1..03b0f5501 100644 --- a/client/src/wiegand_formats.c +++ b/client/src/wiegand_formats.c @@ -733,7 +733,7 @@ static bool Unpack_Sie36(wiegand_message_t *packed, wiegand_card_t *card) { card->CardNumber = get_linear_field(packed, 19, 16); card->ParityValid = (get_bit_by_position(packed, 0) == oddparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 3, 4, 6, 7, 9, 10, 12, 13, 15, 16, 18, 19, 21, 22, 24, 25, 27, 28, 30, 31, 33, 34}))) && - (get_bit_by_position(packed, 35) == evenparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34}))); + (get_bit_by_position(packed, 35) == oddparity32(get_nonlinear_field(packed, 23, (uint8_t[]) {1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34}))); return true; } @@ -1477,7 +1477,7 @@ static const cardformat_t FormatTable[] = { {"BQT34", Pack_bqt34, Unpack_bqt34, "BQT 34-bit", 34, {1, 1, 0, 0, 1, 0xFF, 0xFFFFFF, 0, 0}}, // from cardinfo.barkweb.com.au {"C1k35s", Pack_C1k35s, Unpack_C1k35s, "HID Corporate 1000 35-bit std", 35, {1, 1, 0, 0, 1, 0xFFF, 0xFFFFF, 0, 0}}, // imported from old pack/unpack {"C15001", Pack_C15001, Unpack_C15001, "HID KeyScan 36-bit", 36, {1, 1, 0, 1, 1, 0xFF, 0xFFFF, 0, 0x3FF}}, // from Proxmark forums - {"S12906", Pack_S12906, Unpack_S12906, "HID Simplex 36-bit", 36, {1, 1, 1, 0, 1, 0xFF, 0xFFFFFF, 0x3, 0}}, // from cardinfo.barkweb.com.au + {"S12906", Pack_S12906, Unpack_S12906, "HID Simplex 36-bit", 36, {1, 1, 1, 0, 1, 0xFF, 0x3, 0xFFFFFF, 0}}, // from cardinfo.barkweb.com.au {"Sie36", Pack_Sie36, Unpack_Sie36, "HID 36-bit Siemens", 36, {1, 1, 0, 0, 1, 0x3FFFF, 0xFFFF, 0, 0}}, // from cardinfo.barkweb.com.au {"H10320", Pack_H10320, Unpack_H10320, "HID H10320 37-bit BCD", 37, {1, 0, 0, 0, 1, 0, 99999999, 0, 0}}, // from Proxmark forums {"H10302", Pack_H10302, Unpack_H10302, "HID H10302 37-bit huge ID", 37, {1, 0, 0, 0, 1, 0, 0x7FFFFFFFF, 0, 0}}, // from Proxmark forums diff --git a/common/commonutil.c b/common/commonutil.c index ff0782514..48ce64bfa 100644 --- a/common/commonutil.c +++ b/common/commonutil.c @@ -450,43 +450,6 @@ void lslx(uint8_t *d, size_t n, uint8_t shifts) { } } -// right shift an array of length one bit -void rsl(uint8_t *d, size_t n) { - - uint8_t carry = 0; - - for (size_t i = 0; i < n; i++) { - - // Save the LSB before shifting - uint8_t new_carry = d[i] & 0x1; - - // Shift current byte right and incorporate previous carry - d[i] = (d[i] >> 1) | (carry ? 0x80 : 0); - - // Update carry for next byte - carry = new_carry; - } -} - -void rslx(uint8_t *d, size_t n, uint8_t shifts) { - - uint8_t carry = 0; - for (uint8_t j = 0; j < shifts; j++) { - - for (size_t i = 0; i < n; i++) { - - // Save the LSB before shifting - uint8_t new_carry = d[i] & 0x1; - - // Shift current byte right and incorporate previous carry - d[i] = (d[i] >> 1) | (carry ? 0x80 : 0); - - // Update carry for next byte - carry = new_carry; - } - } -} - // BSWAP24 of array[3] uint32_t le24toh(const uint8_t data[3]) { diff --git a/common/commonutil.h b/common/commonutil.h index bb4697ffa..f963805bb 100644 --- a/common/commonutil.h +++ b/common/commonutil.h @@ -75,7 +75,6 @@ typedef struct { int calculate_hours_between_dates(const Date_t s, Date_t *e); -void add_minutes(Date_t *d, int minutes_to_add); void add_hours(Date_t *d, int hours_to_add); void add_days(Date_t *d, int days_to_add); uint8_t days_in_month(int year, int month); @@ -136,9 +135,6 @@ void xor(uint8_t *dest, const uint8_t *src, size_t n); void lsl(uint8_t *d, size_t n); void lslx(uint8_t *d, size_t n, uint8_t shifts); -void rsl(uint8_t *d, size_t n); -void rslx(uint8_t *d, size_t n, uint8_t shifts); - uint32_t le24toh(const uint8_t data[3]); void htole24(uint32_t val, uint8_t data[3]); diff --git a/common/crapto1/crypto1.c b/common/crapto1/crypto1.c index 8ffe04fdb..78d42cec4 100644 --- a/common/crapto1/crypto1.c +++ b/common/crapto1/crypto1.c @@ -35,9 +35,8 @@ int filter(uint32_t const x) { (x = (x >> 8 & 0xff00ff) | (x & 0xff00ff) << 8, x = x >> 16 | x << 16) void crypto1_init(struct Crypto1State *state, uint64_t key) { - if (state == NULL) { + if (state == NULL) return; - } state->odd = 0; state->even = 0; for (int i = 47; i > 0; i -= 2) { @@ -54,9 +53,7 @@ void crypto1_deinit(struct Crypto1State *state) { #if !defined(__arm__) || defined(__linux__) || defined(_WIN32) || defined(__APPLE__) // bare metal ARM Proxmark lacks calloc()/free() struct Crypto1State *crypto1_create(uint64_t key) { struct Crypto1State *state = calloc(sizeof(*state), sizeof(uint8_t)); - if (state == NULL) { - return NULL; - } + if (!state) return NULL; crypto1_init(state, key); return state; } @@ -148,8 +145,8 @@ uint32_t crypto1_word(struct Crypto1State *s, uint32_t in, int is_encrypted) { */ uint32_t prng_successor(uint32_t x, uint32_t n) { SWAPENDIAN(x); - while (n--) { + while (n--) x = x >> 1 | (x >> 16 ^ x >> 18 ^ x >> 19 ^ x >> 21) << 31; - } + return SWAPENDIAN(x); } diff --git a/common/crc16.c b/common/crc16.c index ecf8c1ed7..e55b20bdc 100644 --- a/common/crc16.c +++ b/common/crc16.c @@ -27,14 +27,12 @@ static CrcType_t current_crc_type = CRC_NONE; void init_table(CrcType_t crctype) { // same crc algo, and initialised already - if (crctype == current_crc_type && crc_table_init) { + if (crctype == current_crc_type && crc_table_init) return; - } // not the same crc algo. reset table. - if (crctype != current_crc_type) { + if (crctype != current_crc_type) reset_table(); - } current_crc_type = crctype; @@ -70,29 +68,23 @@ void init_table(CrcType_t crctype) { void generate_table(uint16_t polynomial, bool refin) { for (uint16_t i = 0; i < 256; i++) { - uint16_t c, crc = 0; - - if (refin) { + if (refin) c = reflect8(i) << 8; - } else { + else c = i << 8; - } for (uint16_t j = 0; j < 8; j++) { - if ((crc ^ c) & 0x8000) { + if ((crc ^ c) & 0x8000) crc = (crc << 1) ^ polynomial; - } else { + else crc = crc << 1; - } c = c << 1; } - - if (refin) { + if (refin) crc = reflect16(crc); - } crc_table[i] = crc; } @@ -110,25 +102,21 @@ uint16_t crc16_fast(uint8_t const *d, size_t n, uint16_t initval, bool refin, bo // fast lookup table algorithm without augmented zero bytes, e.g. used in pkzip. // only usable with polynom orders of 8, 16, 24 or 32. - if (n == 0) { + if (n == 0) return (~initval); - } uint16_t crc = initval; - if (refin) { + if (refin) crc = reflect16(crc); - } - if (refin == false) { + if (!refin) while (n--) crc = (crc << 8) ^ crc_table[((crc >> 8) ^ *d++) & 0xFF ]; - } else { + else while (n--) crc = (crc >> 8) ^ crc_table[(crc & 0xFF) ^ *d++]; - } - if (refout ^ refin) { + if (refout ^ refin) crc = reflect16(crc); - } return crc; } @@ -155,9 +143,8 @@ uint16_t update_crc16(uint16_t crc, uint8_t c) { // two ways. msb or lsb loop. uint16_t Crc16(uint8_t const *d, size_t bitlength, uint16_t remainder, uint16_t polynomial, bool refin, bool refout) { - if (bitlength == 0) { + if (bitlength == 0) return (~remainder); - } uint8_t offset = 8 - (bitlength % 8); // front padding with 0s won't change the CRC result @@ -166,9 +153,7 @@ uint16_t Crc16(uint8_t const *d, size_t bitlength, uint16_t remainder, uint16_t uint8_t c = prebits | d[i] >> offset; prebits = d[i] << (8 - offset); - if (refin) { - c = reflect8(c); - } + if (refin) c = reflect8(c); // xor in at msb remainder ^= (c << 8); @@ -182,10 +167,8 @@ uint16_t Crc16(uint8_t const *d, size_t bitlength, uint16_t remainder, uint16_t } } } - - if (refout) { + if (refout) remainder = reflect16(remainder); - } return remainder; } diff --git a/common/crc16.h b/common/crc16.h index 5e0686fca..c8aecaf21 100644 --- a/common/crc16.h +++ b/common/crc16.h @@ -20,7 +20,6 @@ #include "common.h" -#define CRC16_SIZE 2 #define CRC16_POLY_CCITT 0x1021 #define CRC16_POLY_KERMIT 0x8408 #define CRC16_POLY_LEGIC 0xc6c6 //0x6363 diff --git a/common/default_version_pm3.c b/common/default_version_pm3.c index d93a7ef15..084eb2b63 100644 --- a/common/default_version_pm3.c +++ b/common/default_version_pm3.c @@ -1,20 +1,5 @@ -//----------------------------------------------------------------------------- -// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// See LICENSE.txt for the text of the license. -//----------------------------------------------------------------------------- #include "common.h" -/* This is the default version_pm3.c file that Makefile.common falls back to if sh is not available */ +/* Generated file, do not edit */ #ifndef ON_DEVICE #define SECTVERSINFO #else @@ -23,10 +8,10 @@ const struct version_information_t SECTVERSINFO g_version_information = { VERSION_INFORMATION_MAGIC, - 1, /* version 1 */ - 0, /* version information not present */ - 2, /* cleanliness couldn't be determined */ - "Iceman/master/unknown", - "1970-01-01 00:00:00", - "no sha256" + 1, + 1, + 2, + "Iceman/master/v4.20142", + "2025-03-25 16:18:49", + "4c1a288da" }; diff --git a/common/hitag2/hitag2_crypto.h b/common/hitag2/hitag2_crypto.h index f5d4e7102..1dae77353 100644 --- a/common/hitag2/hitag2_crypto.h +++ b/common/hitag2/hitag2_crypto.h @@ -29,7 +29,7 @@ typedef struct { enum { TAG_STATE_RESET = 0x01, // Just powered up, awaiting GetSnr TAG_STATE_ACTIVATING = 0x02, // In activation phase (password mode), sent UID, awaiting reader password -// TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands + TAG_STATE_ACTIVATED = 0x03, // Activation complete, awaiting read/write commands TAG_STATE_WRITING = 0x04, // In write command, awaiting sector contents to be written } state; uint16_t active_sector; diff --git a/common_arm/Makefile.common b/common_arm/Makefile.common index e8e574112..a845963b2 100644 --- a/common_arm/Makefile.common +++ b/common_arm/Makefile.common @@ -49,7 +49,7 @@ VPATH = . ../common_arm ../common ../common/crapto1 ../common/mbedtls ../common/ INCLUDES = ../include/proxmark3_arm.h ../include/at91sam7s512.h ../include/config_gpio.h ../include/pm3_cmd.h ARMCFLAGS = -mthumb-interwork -fno-builtin -DEFCFLAGS = -Wall -Werror -Os -pedantic -fstrict-aliasing -pipe +DEFCFLAGS = -Wall -Os -pedantic -fstrict-aliasing -pipe # Some more warnings we want as errors: DEFCFLAGS += -Wbad-function-cast -Wchar-subscripts -Wundef -Wunused -Wuninitialized -Wpointer-arith -Wformat -Wformat-security -Winit-self -Wmissing-include-dirs -Wnested-externs -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wtype-limits diff --git a/common_arm/Makefile.hal b/common_arm/Makefile.hal index 568c245ba..f9bb9065e 100644 --- a/common_arm/Makefile.hal +++ b/common_arm/Makefile.hal @@ -29,17 +29,15 @@ define KNOWN_PLATFORM_DEFINITIONS Known definitions: -+==================================================+ ++============================================+ | PLATFORM | DESCRIPTION | -+==================================================+ ++============================================+ | PM3RDV4 (def) | Proxmark3 RDV4 | -+--------------------------------------------------+ ++--------------------------------------------+ | PM3GENERIC | Proxmark3 generic target | -+--------------------------------------------------+ ++--------------------------------------------+ | PM3ICOPYX | iCopy-X with XC3S100E | -+--------------------------------------------------+ -| PM3ULTIMATE | Proxmark3 Ultimate with XC2S50 | -+--------------------------------------------------+ ++--------------------------------------------+ +============================================+ | PLATFORM_EXTRAS | DESCRIPTION | @@ -155,21 +153,7 @@ else ifeq ($(PLATFORM),PM3ICOPYX) PLATFORM_DEFS = -DWITH_FLASH -DICOPYX -DXC3 PLTNAME = iCopy-X with XC3S100E PLATFORM_FPGA = xc3s100e -else ifeq ($(PLATFORM),PM3ULTIMATE) - # FPGA bitstream files, the order doesn't matter anymore - only hf has a bitstream - FPGA_BITSTREAMS = fpga_pm3_ult_hf.bit - ifneq ($(SKIP_LF),1) - FPGA_BITSTREAMS += fpga_pm3_ult_lf.bit - endif - ifneq ($(SKIP_FELICA),1) - FPGA_BITSTREAMS += fpga_pm3_ult_felica.bit - endif - ifneq ($(SKIP_ISO15693),1) - FPGA_BITSTREAMS += fpga_pm3_ult_hf_15.bit - endif - PLATFORM_DEFS = -DWITH_FLASH -DXC2S50 - PLTNAME = Proxmark3 Ultimate with XC2S50 - PLATFORM_FPGA = xc2s50 + else $(error Invalid or empty PLATFORM: $(PLATFORM). $(KNOWN_DEFINITIONS)) endif @@ -268,10 +252,6 @@ endif # WITH_FPC_USART_* needs WITH_FPC_USART : ifneq (,$(findstring WITH_FPC_USART_,$(PLATFORM_DEFS))) PLATFORM_DEFS += -DWITH_FPC_USART - ifeq ($(USART_BAUD_RATE),) - USART_BAUD_RATE=115200 - endif - PLATFORM_DEFS += -DUSART_BAUD_RATE=$(USART_BAUD_RATE) endif PLATFORM_DEFS_INFO = $(strip $(filter-out STANDALONE%, $(subst -DWITH_,,$(PLATFORM_DEFS)))) diff --git a/common_arm/ticks.c b/common_arm/ticks.c index 73182a11c..4abda2689 100644 --- a/common_arm/ticks.c +++ b/common_arm/ticks.c @@ -116,9 +116,8 @@ uint32_t RAMFUNC GetTickCount(void) { uint32_t RAMFUNC GetTickCountDelta(uint32_t start_ticks) { uint32_t stop_ticks = AT91C_BASE_RTTC->RTTC_RTVR; - if (stop_ticks >= start_ticks) { + if (stop_ticks >= start_ticks) return stop_ticks - start_ticks; - } return (UINT32_MAX - start_ticks) + stop_ticks; } diff --git a/common_fpga/fpga.h b/common_fpga/fpga.h index 1b009cd62..c383d2d44 100644 --- a/common_fpga/fpga.h +++ b/common_fpga/fpga.h @@ -25,9 +25,6 @@ #if defined XC3 #define FPGA_TYPE "3s100evq100" #define FPGA_CONFIG_SIZE 72864L // FPGA .bit file rounded up to next multiple of FPGA_INTERLEAVE_SIZE -#elif defined XC2S50 -#define FPGA_TYPE "2s50vq144" -#define FPGA_CONFIG_SIZE 69984L // FPGA .bit file rounded up to next multiple of FPGA_INTERLEAVE_SIZE #else #define FPGA_TYPE "2s30vq100" #define FPGA_CONFIG_SIZE 42336L // FPGA .bit file rounded up to next multiple of FPGA_INTERLEAVE_SIZE diff --git a/doc/commands.json b/doc/commands.json index 564f068d7..2012b339e 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -278,8 +278,9 @@ }, "data crypto": { "command": "data crypto", - "description": "This command lets you encrypt or decrypt data using DES/3DES/AES. Supply data, key, IV (needed for des MAC or aes), and cryptography action.", + "description": "Encrypt data, right here, right now. Or decrypt.", "notes": [ + "Supply data, key, IV (needed for des MAC or aes), and cryptography action.", "To calculate a MAC for FMCOS, supply challenge as IV, data as data, and session/line protection key as key.", "To calculate a MAC for FeliCa, supply first RC as IV, BLE+data as data and session key as key.", "data crypto -d 04D6850E06AABB80 -k FFFFFFFFFFFFFFFF --iv 9EA0401A00000000 --des -> Calculate a MAC for FMCOS chip. The result should be ED3A0133" @@ -1135,7 +1136,7 @@ }, "help": { "command": "help", - "description": "help Use ` help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } mqtt { MQTT commmands... } nfc { NFC commands... } piv { PIV commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program --------------------------------------------------------------------------------------- auto available offline: no Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE", + "description": "help Use ` help` for details of a command prefs { Edit client/device preferences... } -------- ----------------------- Technology ----------------------- analyse { Analyse utils... } data { Plot window / data buffer manipulation... } emv { EMV ISO-14443 / ISO-7816... } hf { High frequency commands... } hw { Hardware commands... } lf { Low frequency commands... } nfc { NFC commands... } piv { PIV commands... } reveng { CRC calculations from RevEng software... } smart { Smart card ISO-7816 commands... } script { Scripting commands... } trace { Trace manipulation... } wiegand { Wiegand format manipulation... } -------- ----------------------- General ----------------------- clear Clear screen hints Turn hints on / off msleep Add a pause in milliseconds rem Add a text line in log file quit exit Exit program --------------------------------------------------------------------------------------- auto available offline: no Run LF SEARCH / HF SEARCH / DATA PLOT / DATA SAVE", "notes": [ "auto" ], @@ -1323,6 +1324,7 @@ "notes": [ "hf 14a raw -sc 3000 -> select, crc, where 3000 == 'read block 00'", "hf 14a raw -ak -b 7 40 -> send 7 bit byte 0x40", + "hf 14a raw --ecp -s -> send ECP before select", "Crypto1 session example, with special auth shortcut 6xxx:", "hf 14a raw --crypto1 -skc 6000FFFFFFFFFFFF", "hf 14a raw --crypto1 -kc 3000", @@ -1341,18 +1343,22 @@ "-t, --timeout Timeout in milliseconds", "-b Number of bits to send. Useful for send partial byte", "-v, --verbose Verbose output", + "--ecp Use enhanced contactless polling", + "--mag Use Apple magsafe polling", "--topaz Use Topaz protocol to send command", "--crypto1 Use crypto1 session", " Raw bytes to send" ], - "usage": "hf 14a raw [-hack3rsv] [-t ] [-b ] [--topaz] [--crypto1] []..." + "usage": "hf 14a raw [-hack3rsv] [-t ] [-b ] [--ecp] [--mag] [--topaz] [--crypto1] []..." }, "hf 14a reader": { "command": "hf 14a reader", "description": "Act as a ISO-14443a reader to identify tag. Look for ISO-14443a tags until Enter or the pm3 button is pressed", "notes": [ "hf 14a reader", - "hf 14a reader -@ -> Continuous mode" + "hf 14a reader -@ -> Continuous mode", + "hf 14a reader --ecp -> trigger apple enhanced contactless polling", + "hf 14a reader --mag -> trigger apple magsafe polling" ], "offline": false, "options": [ @@ -1361,10 +1367,12 @@ "-s, --silent silent (no messages)", "--drop just drop the signal field", "--skip ISO14443-3 select only (skip RATS)", + "--ecp Use enhanced contactless polling", + "--mag Use Apple magsafe polling", "-@ continuous reader mode", "-w, --wait wait for card" ], - "usage": "hf 14a reader [-hks@w] [--drop] [--skip]" + "usage": "hf 14a reader [-hks@w] [--drop] [--skip] [--ecp] [--mag]" }, "hf 14a sim": { "command": "hf 14a sim", @@ -1381,8 +1389,7 @@ "hf 14a sim -t 9 -> FM11RF005SH Shanghai Metro", "hf 14a sim -t 10 -> ST25TA IKEA Rothult", "hf 14a sim -t 11 -> Javacard (JCOP)", - "hf 14a sim -t 12 -> 4K Seos card", - "hf 14a sim -t 13 -> MIFARE Ultralight C" + "hf 14a sim -t 12 -> 4K Seos card" ], "offline": false, "options": [ @@ -1392,11 +1399,9 @@ "-n, --num Exit simulation after blocks have been read by reader. 0 = infinite", "-x Performs the 'reader attack', nr/ar attack against a reader", "--sk Fill simulator keys from found keys", - "-v, --verbose verbose output", - "--c1 UL-C Auth - all zero handshake part 1", - "--c2 UL-C Auth - all zero handshake part 2" + "-v, --verbose verbose output" ], - "usage": "hf 14a sim [-hxv] -t <1-12> [-u ] [-n ] [--sk] [--c1] [--c2]" + "usage": "hf 14a sim [-hxv] -t <1-12> [-u ] [-n ] [--sk]" }, "hf 14a simaid": { "command": "hf 14a simaid", @@ -2514,7 +2519,7 @@ }, "hf emrtd help": { "command": "hf emrtd help", - "description": "help This help info Tag information list List ISO 14443A/7816 history --------------------------------------------------------------------------------------- hf emrtd dump available offline: no Dump all files on an eMRTD", + "description": "help This help info Display info about an eMRTD list List ISO 14443A/7816 history --------------------------------------------------------------------------------------- hf emrtd dump available offline: no Dump all files on an eMRTD", "notes": [ "hf emrtd dump", "hf emrtd dump --dir ../dump", @@ -2659,19 +2664,6 @@ ], "usage": "hf felica auth2 [-hv] [-i ] [-c ] [-k ]" }, - "hf felica dump": { - "command": "hf felica dump", - "description": "Dump all existing Area Code and Service Code. Only works on services that do not require authentication yet.", - "notes": [ - "hf felica dump" - ], - "offline": false, - "options": [ - "-h, --help This help", - "--no-auth read public services" - ], - "usage": "hf felica dump [-h] [--no-auth]" - }, "hf felica help": { "command": "hf felica help", "description": "----------- ----------------------- General ----------------------- help This help list List ISO 18092/FeliCa history ----------- ----------------------- Operations ----------------------- ----------- ----------------------- FeliCa Standard ----------------------- ----------- ----------------------- FeliCa Light ----------------------- --------------------------------------------------------------------------------------- hf felica list available offline: yes Alias of `trace list -t felica` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", @@ -2705,25 +2697,6 @@ ], "usage": "hf felica info [-h]" }, - "hf felica liteauth": { - "command": "hf felica liteauth", - "description": "Authenticate", - "notes": [ - "hf felica liteauth -i 11100910C11BC407", - "hf felica liteauth --key 46656c69436130313233343536616263", - "hf felica liteauth --key 46656c69436130313233343536616263 -k", - "hf felica liteauth -c 701185c59f8d30afeab8e4b3a61f5cc4 --key 46656c69436130313233343536616263" - ], - "offline": false, - "options": [ - "-h, --help This help", - "--key set card key, 16 bytes", - "-c, set random challenge, 16 bytes", - "-i, set custom IDm", - "-k, keep signal field ON after receive" - ], - "usage": "hf felica liteauth [-hk] [--key ] [-c ] [-i ]" - }, "hf felica litedump": { "command": "hf felica litedump", "description": "Dump ISO/18092 FeliCa Lite tag. It will timeout after 200sec", @@ -2732,11 +2705,9 @@ ], "offline": false, "options": [ - "-h, --help This help", - "-i, set custom IDm", - "--key set card key, 16 bytes" + "-h, --help This help" ], - "usage": "hf felica litedump [-h] [-i ] [--key ]" + "usage": "hf felica litedump [-h]" }, "hf felica litesim": { "command": "hf felica litesim", @@ -2888,7 +2859,7 @@ }, "hf felica scsvcode": { "command": "hf felica scsvcode", - "description": "Dump all existing Area Code and Service Code.", + "description": "Feature not implemented yet. Feel free to contribute!", "notes": [ "hf felica scsvcode" ], @@ -3237,7 +3208,7 @@ }, "hf help": { "command": "hf help", - "description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } iclass { ICLASS RFIDs... } ict { ICT MFC/DESfire RFIDs... } jooki { Jooki RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } vas { Apple Value Added Service... } waveshare { Waveshare NFC ePaper... } xerox { Fuji/Xerox cartridge RFIDs... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags --------------------------------------------------------------------------------------- hf list available offline: yes Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "description": "-------- ----------------------- High Frequency ----------------------- 14a { ISO14443A RFIDs... } 14b { ISO14443B RFIDs... } 15 { ISO15693 RFIDs... } cipurse { Cipurse transport Cards... } epa { German Identification Card... } emrtd { Machine Readable Travel Document... } felica { ISO18092 / FeliCa RFIDs... } fido { FIDO and FIDO2 authenticators... } fudan { Fudan RFIDs... } gallagher { Gallagher DESFire RFIDs... } iclass { ICLASS RFIDs... } ict { ICT MFC/DESfire RFIDs... } jooki { Jooki RFIDs... } ksx6924 { KS X 6924 (T-Money, Snapper+) RFIDs } legic { LEGIC RFIDs... } lto { LTO Cartridge Memory RFIDs... } mf { MIFARE RFIDs... } mfp { MIFARE Plus RFIDs... } mfu { MIFARE Ultralight RFIDs... } mfdes { MIFARE Desfire RFIDs... } ntag424 { NXP NTAG 4242 DNA RFIDs... } seos { SEOS RFIDs... } st25ta { ST25TA RFIDs... } tesla { TESLA Cards... } texkom { Texkom RFIDs... } thinfilm { Thinfilm RFIDs... } topaz { TOPAZ (NFC Type 1) RFIDs... } vas { Apple Value Added Service } waveshare { Waveshare NFC ePaper... } xerox { Fuji/Xerox cartridge RFIDs... } ----------- --------------------- General --------------------- help This help list List protocol data in trace buffer search Search for known HF tags --------------------------------------------------------------------------------------- hf list available offline: yes Alias of `trace list -t raw` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf list --frame -> show frame delay times", "hf list -1 -> use trace buffer" @@ -3280,7 +3251,7 @@ }, "hf iclass chk": { "command": "hf iclass chk", - "description": "Checkkeys loads a dictionary text file with 8 byte hex keys to test authenticating against a iCLASS tag", + "description": "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag", "notes": [ "hf iclass chk -f iclass_default_keys.dic", "hf iclass chk -f iclass_elite_keys.dic --elite", @@ -3321,14 +3292,15 @@ "command": "hf iclass creditepurse", "description": "Credit the epurse on an iCLASS tag. The provided key must be the credit key. The first two bytes of the epurse are the debit value (big endian) and may be any value except FFFF. The remaining two bytes of the epurse are the credit value and must be smaller than the previous value.", "notes": [ - "hf iclass creditepurse --ki 0 -d FEFFFEFF" + "hf iclass creditepurse -d FEFFFFFF -k 001122334455667B", + "hf iclass creditepurse -d FEFFFFFF --ki 0" ], "offline": false, "options": [ "-h, --help This help", "-k, --key Credit key as 8 hex bytes", "--ki Key index to select key from memory 'hf iclass managekeys'", - "-d, --data data to write as 4 hex bytes", + "-d, --data data to write as 8 hex bytes", "--elite elite computations applied to key", "--raw no computations applied to key", "-v, --verbose verbose output", @@ -3403,12 +3375,13 @@ }, "hf iclass encode": { "command": "hf iclass encode", - "description": "Encode binary wiegand to block 7,8,9 Use either --bin or --wiegand/--fc/--cn When using emulator you have to first load a credential into emulator memory", + "description": "Encode binary wiegand to block 7,8,9 Use either --bin or --wiegand/--fc/--cn", "notes": [ "hf iclass encode --bin 10001111100000001010100011 --ki 0 -> FC 31 CN 337 (H10301)", "hf iclass encode -w H10301 --fc 31 --cn 337 --ki 0 -> FC 31 CN 337 (H10301)", "hf iclass encode --bin 10001111100000001010100011 --ki 0 --elite -> FC 31 CN 337 (H10301), writing w elite key", - "hf iclass encode -w H10301 --fc 31 --cn 337 --emu -> Writes the ecoded data to emulator memory" + "hf iclass encode -w H10301 --fc 31 --cn 337 --emu -> Writes the ecoded data to emulator memory", + "When using emulator you have to first load a credential into emulator memory" ], "offline": true, "options": [ @@ -3528,7 +3501,7 @@ }, "hf iclass legbrute": { "command": "hf iclass legbrute", - "description": "This command takes sniffed trace data and a partial raw key and bruteforces the remaining 40 bits of the raw key. Complete 40 bit keyspace is 1'099'511'627'776 and command is locked down to max 16 threads currently. A possible worst case scenario on 16 threads estimates XXX days YYY hours MMM minutes.", + "description": "This command take sniffed trace data and partial raw key and bruteforces the remaining 40 bits of the raw key.", "notes": [ "hf iclass legbrute --epurse feffffffffffffff --macs1 1306cad9b6c24466 --macs2 f0bf905e35f97923 --pk B4F12AADC5301225" ], @@ -3539,14 +3512,13 @@ "--macs1 MACs captured from the reader", "--macs2 MACs captured from the reader, different than the first set (with the same csn and epurse value)", "--pk Partial Key from legrec or starting key of keyblock from legbrute", - "--index Where to start from to retrieve the key, default 0 - value in millions e.g. 1 is 1 million", - "--threads Number of threads to use, by default it uses the cpu's max threads (max 16)." + "--index Where to start from to retrieve the key, default 0 - value in millions e.g. 1 is 1 million" ], - "usage": "hf iclass legbrute [-h] --epurse --macs1 --macs2 --pk [--index ] [--threads ]" + "usage": "hf iclass legbrute [-h] --epurse --macs1 --macs2 --pk [--index ]" }, "hf iclass legrec": { "command": "hf iclass legrec", - "description": "Attempts to recover the diversified key of a specific iCLASS card. This may take several days. The card must remain be on the PM3 antenna during the whole process. ! Warning ! This process may brick the card! ! Warning !", + "description": "Attempts to recover the diversified key of a specific iClass card. This may take a long time. The Card must remain be on the PM3 antenna during the whole process! This process may brick the card!", "notes": [ "hf iclass legrec --macs 0000000089cb984b", "hf iclass legrec --macs 0000000089cb984b --index 0 --loop 100 --notest" @@ -3555,16 +3527,14 @@ "options": [ "-h, --help This help", "--macs AA1 Authentication MACs", - "--index Where to start from to retrieve the key (def: 0)", - "--loop The number of key retrieval cycles to perform, max 10000 (def 100)", - "--debug Re-enables tracing for debugging. Limits cycles to 1", - "--notest Perform real writes on the card", - "--allnight Loops the loop for 10 times, recommended loop value of 5000", - "--fast Increases the speed (4.6->7.4 key updates/second), higher risk to brick the card", - "--sl Lower card comms delay times, further speeds increases, may cause more errors", - "--est Estimates the key updates based on the card's CSN assuming standard key" + "--index Where to start from to retrieve the key, default 0", + "--loop The number of key retrieval cycles to perform, max 10000, default 100", + "--debug Re-enables tracing for debugging. Limits cycles to 1.", + "--notest Perform real writes on the card!", + "--allnight Loops the loop for 10 times, recommended loop value of 5000.", + "--est Estimates the key updates based on the card's CSN assuming standard key." ], - "usage": "hf iclass legrec [-h] --macs [--index ] [--loop ] [--debug] [--notest] [--allnight] [--fast] [--sl] [--est]" + "usage": "hf iclass legrec [-h] --macs [--index ] [--loop ] [--debug] [--notest] [--allnight] [--est]" }, "hf iclass loclass": { "command": "hf iclass loclass", @@ -3696,18 +3666,17 @@ "--elite elite computations applied to key", "--raw no computations applied to key", "-v, --verbose verbose output", - "--shallow use shallow (ASK) reader modulation instead of OOK", - "--nr replay of nr mac with privilege escalation" + "--shallow use shallow (ASK) reader modulation instead of OOK" ], - "usage": "hf iclass restore [-hv] -f [-k ] [--ki ] --first --last [--credit] [--elite] [--raw] [--shallow] [--nr]" + "usage": "hf iclass restore [-hv] -f [-k ] [--ki ] --first --last [--credit] [--elite] [--raw] [--shallow]" }, "hf iclass sam": { "command": "hf iclass sam", "description": "Extract PACS via a HID SAM", "notes": [ "hf iclass sam", - "hf iclass sam -p -d a005a103800104 -> get PACS data, prevent epurse update", - "hf iclass sam --break -> get Nr-MAC for extracting encrypted SIO" + "hf iclass sam -p -d a005a103800104 -> get PACS data, but ensure that epurse will stay unchanged", + "hf iclass sam --break-on-nr-mac -> get Nr-MAC for extracting encrypted SIO" ], "offline": false, "options": [ @@ -3716,14 +3685,12 @@ "-k, --keep keep the field active after command executed", "-n, --nodetect skip selecting the card and sending card details to SAM", "-t, --tlv decode TLV", - "--break stop tag interaction on nr-mac", - "-p, --prevent fake epurse update", + "--break-on-nr-mac stop tag interaction on nr-mac", + "-p, --prevent-epurse-update fake epurse update", "--shallow shallow mod", - "-d, --data DER encoded command to send to SAM", - "-s, --snmp data is in snmp format without headers", - "--info get SAM infos (version, serial number)" + "-d, --data DER encoded command to send to SAM" ], - "usage": "hf iclass sam [-hvkntps] [--break] [--shallow] [-d ]... [--info]" + "usage": "hf iclass sam [-hvkntp] [--break-on-nr-mac] [--shallow] [-d ]..." }, "hf iclass sim": { "command": "hf iclass sim", @@ -3733,9 +3700,7 @@ "hf iclass sim -t 1 -> simulate with default CSN", "hf iclass sim -t 2 -> execute loclass attack online part", "hf iclass sim -t 3 -> simulate full iCLASS 2k tag", - "hf iclass sim -t 4 -> Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key", - "hf iclass sim -t 6 -> simulate full iCLASS 2k tag that doesn't respond to r/w requests to the last SIO block", - "hf iclass sim -t 7 -> simulate full iCLASS 2k tag that doesn't XOR or respond to r/w requests on block 3" + "hf iclass sim -t 4 -> Reader-attack, adapted for KeyRoll mode, gather reader responses to extract elite key" ], "offline": false, "options": [ @@ -3759,13 +3724,12 @@ ], "usage": "hf iclass sniff [-hj]" }, - "hf iclass tear": { - "command": "hf iclass tear", - "description": "Tear off an iCLASS tag block e-purse usually 300-500us to trigger the erase phase also seen 1800-2100us on some cards Make sure you know the target card credit key. Typical `--ki 1` or `--ki 3`", + "hf iclass trbl": { + "command": "hf iclass trbl", + "description": "Tear off an iCLASS tag block", "notes": [ - "hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B -s 300 -e 600", - "hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 -s 300 -e 600", - "hf iclass tear --blk 2 -d fdffffffffffffff --ki 1 --credit -s 400 -e 500" + "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B --tdb 100 --tde 150", + "hf iclass trbl --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 --tdb 100 --tde 150" ], "offline": false, "options": [ @@ -3781,14 +3745,10 @@ "--nr replay of NR/MAC", "-v, --verbose verbose output", "--shallow use shallow (ASK) reader modulation instead of OOK", - "-s tearoff delay start (in us) must be between 1 and 43000 (43ms). Precision is about 1/3 us", - "-i tearoff delay increment (in us) - default 10", - "-e tearoff delay end (in us) must be a higher value than the start delay", - "--loop number of times to loop per tearoff time", - "--sleep Sleep between each tear", - "--arm Runs the commands on device side and tries to stabilize tears" + "--tdb tearoff delay start in ms", + "--tde tearoff delay end in ms" ], - "usage": "hf iclass tear [-hv] [-k ] [--ki ] --blk [-d ] [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] -s [-i ] [-e ] [--loop ] [--sleep ] [--arm]" + "usage": "hf iclass trbl [-hv] [-k ] [--ki ] --blk -d [-m ] [--credit] [--elite] [--raw] [--nr] [--shallow] --tdb --tde " }, "hf iclass unhash": { "command": "hf iclass unhash", @@ -3843,7 +3803,7 @@ "--credit key is assumed to be the credit key", "--elite elite computations applied to key", "--raw no computations applied to key", - "--nr replay of NR/MAC block write or use privilege escalation if mac is empty", + "--nr replay of NR/MAC", "-v, --verbose verbose output", "--shallow use shallow (ASK) reader modulation instead of OOK" ], @@ -4455,23 +4415,6 @@ ], "usage": "hf mf autopwn [-hablv] [-k ]... [-s ] [-f ] [--suffix ] [--slow] [--mem] [--ns] [--mini] [--1k] [--2k] [--4k] [--in] [--im] [--is] [--ia] [--i2] [--i5]" }, - "hf mf bambukeys": { - "command": "hf mf bambukeys", - "description": "Generate keys for a Bambu Lab filament tag", - "notes": [ - "hf mf bambukeys -r", - "hf mf bambukeys -r -d", - "hf mf bambukeys -u 11223344" - ], - "offline": true, - "options": [ - "-h, --help This help", - "-u, --uid UID (4 hex bytes)", - "-r Read UID from tag", - "-d Dump keys to file" - ], - "usage": "hf mf bambukeys [-hrd] [-u ]" - }, "hf mf brute": { "command": "hf mf brute", "description": "This is a smart bruteforce, exploiting common patterns, bugs and bad designs in key generators.", @@ -5206,7 +5149,7 @@ }, "hf mf help": { "command": "hf mf help", - "description": "help This help list List MIFARE history hardnested Nested attack for hardened MIFARE Classic cards decrypt Decrypt Crypto1 data from sniff or trace bambukeys Generate key table for Bambu Lab filament tag acl Decode and print MIFARE Classic access rights bytes mad Checks and prints MAD value Value blocks view Display content from tag dump file ginfo Info about configuration of the card gdmparsecfg Parse config block to card --------------------------------------------------------------------------------------- hf mf list available offline: yes Alias of `trace list -t mf -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "description": "help This help list List MIFARE history hardnested Nested attack for hardened MIFARE Classic cards decrypt Decrypt Crypto1 data from sniff or trace acl Decode and print MIFARE Classic access rights bytes mad Checks and prints MAD value Value blocks view Display content from tag dump file ginfo Info about configuration of the card gdmparsecfg Parse config block to card --------------------------------------------------------------------------------------- hf mf list available offline: yes Alias of `trace list -t mf -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf mf list --frame -> show frame delay times", "hf mf list -1 -> use trace buffer" @@ -5524,8 +5467,7 @@ "hf mf sim --1k -u 11223344556677 -> MIFARE Classic 1k with 7b UID", "hf mf sim --1k -u 11223344 -i -x -> Perform reader attack in interactive mode", "hf mf sim --2k -> MIFARE 2k", - "hf mf sim --4k -> MIFARE 4k", - "hf mf sim --1k -x -e -> Keep simulation running and populate with found reader keys" + "hf mf sim --4k -> MIFARE 4khf mf sim --1k -x -e --> Keep simulation running and populate with found reader keys" ], "offline": false, "options": [ @@ -5543,11 +5485,10 @@ "-y Performs the nested 'reader attack'. This requires preloading nt & nt_enc in emulator memory. Implies -x.", "-e, --emukeys Fill simulator keys from found keys. Requires -x or -y. Implies -i. Simulation will restart automatically.", "--allowkeyb Allow key B even if readable", - "--allowover Allow auth attempts out of range for selected MIFARE Classic type", "-v, --verbose Verbose output", "--cve Trigger CVE 2021_0430" ], - "usage": "hf mf sim [-hixyev] [-u ] [--mini] [--1k] [--2k] [--4k] [--atqa ] [--sak ] [-n ] [--allowkeyb] [--allowover] [--cve]" + "usage": "hf mf sim [-hixyev] [-u ] [--mini] [--1k] [--2k] [--4k] [--atqa ] [--sak ] [-n ] [--allowkeyb] [--cve]" }, "hf mf staticnested": { "command": "hf mf staticnested", @@ -5680,8 +5621,7 @@ "hf mfdes auth -n 0 -t des -k 0000000000000000 --kdf none -> select PICC level and authenticate with key num=0, key type=des, key=00..00 and key derivation = none", "hf mfdes auth -n 0 -t aes -k 00000000000000000000000000000000 -> select PICC level and authenticate with key num=0, key type=aes, key=00..00 and key derivation = none", "hf mfdes auth -n 0 -t des -k 0000000000000000 --save -> select PICC level and authenticate and in case of successful authentication - save channel parameters to defaults", - "hf mfdes auth --aid 123456 -> select application 123456 and authenticate via parameters from `default` command", - "hf mfdes auth --dfname D2760000850100 -n 0 -t aes -k 00000000000000000000000000000000 -> select DF by name and authenticate" + "hf mfdes auth --aid 123456 -> select application 123456 and authenticate via parameters from `default` command" ], "offline": false, "options": [ @@ -5698,10 +5638,9 @@ "--schann Secure channel", "--aid Application ID of application for some parameters (3 hex bytes, big endian)", "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian)", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)", "--save saves channels parameters to defaults if authentication succeeds" ], - "usage": "hf mfdes auth [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ] [--save]" + "usage": "hf mfdes auth [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--save]" }, "hf mfdes bruteaid": { "command": "hf mfdes bruteaid", @@ -5798,8 +5737,8 @@ "description": "Checks keys with MIFARE DESFire card.", "notes": [ "hf mfdes chk --aid 123456 -k 000102030405060708090a0b0c0d0e0f -> check key on aid 0x123456", - "hf mfdes chk -f mfdes_default_keys -> check keys against all existing aid on card", - "hf mfdes chk -f mfdes_default_keys --aid 123456 -> check keys against aid 0x123456", + "hf mfdes chk -d mfdes_default_keys -> check keys against all existing aid on card", + "hf mfdes chk -d mfdes_default_keys --aid 123456 -> check keys against aid 0x123456", "hf mfdes chk --aid 123456 --pattern1b -j keys -> check all 1-byte keys pattern on aid 0x123456 and save found keys to `keys.json`", "hf mfdes chk --aid 123456 --pattern2b --startp2b FA00 -> check all 2-byte keys pattern on aid 0x123456. Start from key FA00FA00...FA00" ], @@ -5808,7 +5747,7 @@ "-h, --help This help", "--aid Use specific AID (3 hex bytes, big endian)", "-k, --key Key for checking (HEX 16 bytes)", - "-f, --file Filename of dictionary", + "-d, --dict Dictionary file with keys", "--pattern1b Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)", "--pattern2b Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)", "--startp2b Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)", @@ -5818,7 +5757,7 @@ "-i, --kdfi KDF input (1-31 hex bytes)", "-a, --apdu Show APDU requests and responses" ], - "usage": "hf mfdes chk [-hva] [--aid ] [-k ] [-f ] [--pattern1b] [--pattern2b] [--startp2b ] [-j ] [--kdf <0|1|2>] [-i ]" + "usage": "hf mfdes chk [-hva] [--aid ] [-k ] [-d ] [--pattern1b] [--pattern2b] [--startp2b ] [-j ] [--kdf <0|1|2>] [-i ]" }, "hf mfdes chkeysettings": { "command": "hf mfdes chkeysettings", @@ -6074,7 +6013,7 @@ "-a, --apdu Show APDU requests and responses", "-v, --verbose Verbose output", "-n, --keyno Key number", - "-t, --algo Crypt algo (deft: 2TDEA)", + "-t, --algo Crypt algo", "-k, --key Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)", "--kdf Key Derivation Function (KDF)", "-i, --kdfi KDF input (1-31 hex bytes)", @@ -6173,7 +6112,7 @@ "notes": [ "hf mfdes detect -> detect key 0 from PICC level", "hf mfdes detect --schann d40 -> detect key 0 from PICC level via secure channel D40", - "hf mfdes detect -f mfdes_default_keys -> detect key 0 from PICC level with help of the standard dictionary", + "hf mfdes detect --dict mfdes_default_keys -> detect key 0 from PICC level with help of the standard dictionary", "hf mfdes detect --aid 123456 -n 2 --save -> detect key 2 from app 123456 and if succeed - save params to defaults (`default` command)", "hf mfdes detect --isoid df01 --save -> detect key 0 and save to defaults with card in the LRP mode" ], @@ -6192,11 +6131,10 @@ "--schann Secure channel", "--aid Application ID (3 hex bytes, big endian)", "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian).", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)", - "-f, --file Filename of dictionary", + "--dict Dictionary file name with keys", "--save Save found key and parameters to defaults" ], - "usage": "hf mfdes detect [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ] [-f ] [--save]" + "usage": "hf mfdes detect [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dict ] [--save]" }, "hf mfdes dump": { "command": "hf mfdes dump", @@ -6219,11 +6157,10 @@ "--schann Secure channel", "--aid Application ID (3 hex bytes, big endian)", "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian)", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)", "-l, --length Maximum length for read data files (3 hex bytes, big endian)", "--no-auth Execute without authentication" ], - "usage": "hf mfdes dump [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ] [-l ] [--no-auth]" + "usage": "hf mfdes dump [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [-l ] [--no-auth]" }, "hf mfdes formatpicc": { "command": "hf mfdes formatpicc", @@ -6267,10 +6204,9 @@ "-m, --cmode Communicaton mode", "-c, --ccset Communicaton command set", "--schann Secure channel", - "--no-auth Execute without authentication", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)" + "--no-auth Execute without authentication" ], - "usage": "hf mfdes getfreemem [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--no-auth] [--dfname ]" + "usage": "hf mfdes getfreemem [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--no-auth]" }, "hf mfdes getaids": { "command": "hf mfdes getaids", @@ -6323,8 +6259,7 @@ "description": "Get File IDs list from card. Master key needs to be provided or flag --no-auth set.", "notes": [ "hf mfdes getfileids --aid 123456 -> execute with defaults from `default` command", - "hf mfdes getfileids -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 -> execute with default factory setup", - "hf mfdes getfileids --dfname D2760000850100 -> select DF by name and get file IDs" + "hf mfdes getfileids -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 -> execute with default factory setup" ], "offline": false, "options": [ @@ -6341,10 +6276,9 @@ "--schann Secure channel", "--aid Application ID (3 hex bytes, big endian)", "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian).", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)", "--no-auth Execute without authentication" ], - "usage": "hf mfdes getfileids [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ] [--no-auth]" + "usage": "hf mfdes getfileids [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--no-auth]" }, "hf mfdes getfileisoids": { "command": "hf mfdes getfileisoids", @@ -6353,8 +6287,7 @@ "hf mfdes getfileisoids --aid 123456 -> execute with defaults from `default` command", "hf mfdes getfileisoids -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 -> execute with default factory setup", "hf mfdes getfileisoids --isoid df01 -> get iso file ids from Desfire Light with factory card settings", - "hf mfdes getfileisoids --isoid df01 --schann lrp -t aes -> get iso file ids from Desfire Light via lrp channel with default key authentication", - "hf mfdes getfileisoids --dfname D2760000850100 -> select DF by name and get file ISO IDs" + "hf mfdes getfileisoids --isoid df01 --schann lrp -t aes -> get iso file ids from Desfire Light via lrp channel with default key authentication" ], "offline": false, "options": [ @@ -6371,10 +6304,9 @@ "--schann Secure channel", "--aid Application ID (3 hex bytes, big endian)", "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian).", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)", "--no-auth Execute without authentication" ], - "usage": "hf mfdes getfileisoids [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ] [--no-auth]" + "usage": "hf mfdes getfileisoids [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--no-auth]" }, "hf mfdes getfilesettings": { "command": "hf mfdes getfilesettings", @@ -6382,8 +6314,7 @@ "notes": [ "hf mfdes getfilesettings --aid 123456 --fid 01 -> execute with defaults from `default` command", "hf mfdes getfilesettings --isoid df01 --fid 00 --no-auth -> get file settings with select by iso id", - "hf mfdes getfilesettings -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 --fid 01 -> execute with default factory setup", - "hf mfdes getfilesettings --dfname D2760000850100 --fid 01 -> select DF by name and get file settings" + "hf mfdes getfilesettings -n 0 -t des -k 0000000000000000 --kdf none --aid 123456 --fid 01 -> execute with default factory setup" ], "offline": false, "options": [ @@ -6400,19 +6331,17 @@ "--schann Secure channel", "--aid Application ID (3 hex bytes, big endian)", "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian)", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)", "--fid File ID (1 hex byte). (def: 1)", "--no-auth Execute without authentication" ], - "usage": "hf mfdes getfilesettings [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ] [--fid ] [--no-auth]" + "usage": "hf mfdes getfilesettings [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--fid ] [--no-auth]" }, "hf mfdes getkeysettings": { "command": "hf mfdes getkeysettings", "description": "Get key settings for card level or application level.", "notes": [ "hf mfdes getkeysettings -> get picc key settings with default key/channel setup", - "hf mfdes getkeysettings --aid 123456 -> get app 123456 key settings with default key/channel setup", - "hf mfdes getkeysettings --dfname D2760000850100 -> select DF by name and get key settings" + "hf mfdes getkeysettings --aid 123456 -> get app 123456 key settings with default key/channel setup" ], "offline": false, "options": [ @@ -6427,10 +6356,9 @@ "-m, --cmode Communicaton mode", "-c, --ccset Communicaton command set", "--schann Secure channel", - "--aid Application ID (3 hex bytes, big endian)", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)" + "--aid Application ID (3 hex bytes, big endian)" ], - "usage": "hf mfdes getkeysettings [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--dfname ]" + "usage": "hf mfdes getkeysettings [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ]" }, "hf mfdes getkeyversions": { "command": "hf mfdes getkeyversions", @@ -6439,8 +6367,7 @@ "--keynum parameter: App level: key number. PICC level: 00..0d - keys count, 21..23 vc keys, default 0x00.", "hf mfdes getkeyversions --keynum 00 -> get picc master key version with default key/channel setup", "hf mfdes getkeyversions --aid 123456 --keynum 0d -> get app 123456 all key versions with default key/channel setup", - "hf mfdes getkeyversions --aid 123456 --keynum 0d --no-auth -> get key version without authentication", - "hf mfdes getkeyversions --dfname D2760000850100 --keynum 00 -> select DF by name and get key versions" + "hf mfdes getkeyversions --aid 123456 --keynum 0d --no-auth -> get key version without authentication" ], "offline": false, "options": [ @@ -6457,20 +6384,18 @@ "--schann Secure channel", "--aid Application ID (3 hex bytes, big endian)", "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian).", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)", "--keynum Key number/count (1 hex byte). (def: 0x00)", "--keyset Keyset number (1 hex byte)", "--no-auth Execute without authentication" ], - "usage": "hf mfdes getkeyversions [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ] [--keynum ] [--keyset ] [--no-auth]" + "usage": "hf mfdes getkeyversions [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--keynum ] [--keyset ] [--no-auth]" }, "hf mfdes getuid": { "command": "hf mfdes getuid", "description": "Get UID from card. Get the real UID if the random UID bit is on and get the same UID as in anticollision if not. Any card's key needs to be provided.", "notes": [ "hf mfdes getuid -> execute with default factory setup", - "hf mfdes getuid --isoid df01 -t aes --schan lrp -> for desfire lights default settings", - "hf mfdes getuid --dfname D2760000850100 -> select DF by name and get UID" + "hf mfdes getuid --isoid df01 -t aes --schan lrp -> for desfire lights default settings" ], "offline": false, "options": [ @@ -6486,10 +6411,9 @@ "-c, --ccset Communicaton command set", "--schann Secure channel", "--aid Application ID (3 hex bytes, big endian)", - "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian)", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)" + "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian)" ], - "usage": "hf mfdes getuid [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ]" + "usage": "hf mfdes getuid [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ]" }, "hf mfdes help": { "command": "hf mfdes help", @@ -6529,8 +6453,7 @@ "description": "Show application list. Master key needs to be provided or flag --no-auth set (depend on cards settings).", "notes": [ "hf mfdes lsapp -> show application list with defaults from `default` command", - "hf mfdes lsapp --files -> show application list and show each file type/settings/etc", - "hf mfdes lsapp --dfname D2760000850100 -> list apps after selecting DF by name" + "hf mfdes lsapp --files -> show application list and show each file type/settings/etc" ], "offline": false, "options": [ @@ -6547,46 +6470,16 @@ "--schann Secure channel", "--no-auth Execute without authentication", "--no-deep not to check authentication commands that avail for any application", - "--files scan files and print file settings", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)" + "--files scan files and print file settings" ], - "usage": "hf mfdes lsapp [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--no-auth] [--no-deep] [--files] [--dfname ]" - }, - "hf mfdes lsfile": { - "command": "hf mfdes lsfile", - "description": "This commands List files inside application AID / ISOID. Master key needs to be provided or flag --no-auth set (depend on cards settings).", - "notes": [ - "hf mfdes lsfiles --aid 123456 -> AID 123456, list files using `default` command creds", - "hf mfdes lsfiles --isoid df01 --no-auth -> list files for DESFire light", - "hf mfdes lsfiles --dfname D2760000850100 -> select DF by name and list files" - ], - "offline": false, - "options": [ - "-h, --help This help", - "-a, --apdu Show APDU requests and responses", - "-v, --verbose Verbose output", - "-n, --keyno Key number", - "-t, --algo Crypt algo", - "-k, --key Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)", - "--kdf Key Derivation Function (KDF)", - "-i, --kdfi KDF input (1-31 hex bytes)", - "-m, --cmode Communicaton mode", - "-c, --ccset Communicaton command set", - "--schann Secure channel", - "--aid Application ID (3 hex bytes, big endian)", - "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian)", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)", - "--no-auth Execute without authentication" - ], - "usage": "hf mfdes lsfiles [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ] [--no-auth]" + "usage": "hf mfdes lsapp [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--no-auth] [--no-deep] [--files]" }, "hf mfdes lsfiles": { "command": "hf mfdes lsfiles", "description": "This commands List files inside application AID / ISOID. Master key needs to be provided or flag --no-auth set (depend on cards settings).", "notes": [ "hf mfdes lsfiles --aid 123456 -> AID 123456, list files using `default` command creds", - "hf mfdes lsfiles --isoid df01 --no-auth -> list files for DESFire light", - "hf mfdes lsfiles --dfname D2760000850100 -> select DF by name and list files" + "hf mfdes lsfiles --isoid df01 --no-auth -> list files for DESFire light" ], "offline": false, "options": [ @@ -6603,10 +6496,9 @@ "--schann Secure channel", "--aid Application ID (3 hex bytes, big endian)", "--isoid Application ISO ID (ISO DF ID) (2 hex bytes, big endian)", - "--dfname Application ISO DF Name (5-16 hex bytes, big endian)", "--no-auth Execute without authentication" ], - "usage": "hf mfdes lsfiles [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--dfname ] [--no-auth]" + "usage": "hf mfdes lsfiles [-hav] [-n ] [-t ] [-k ] [--kdf ] [-i ] [-m ] [-c ] [--schann ] [--aid ] [--isoid ] [--no-auth]" }, "hf mfdes mad": { "command": "hf mfdes mad", @@ -6783,7 +6675,7 @@ "-a, --apdu Show APDU requests and responses", "-v, --verbose Verbose output", "-n, --keyno Key number", - "-t, --algo Crypt algo (deft: 2TDEA)", + "-t, --algo Crypt algo", "-k, --key Key for authenticate (HEX 8(DES), 16(2TDEA or AES) or 24(3TDEA) bytes)", "--kdf Key Derivation Function (KDF)", "-i, --kdfi KDF input (1-31 hex bytes)", @@ -6860,9 +6752,9 @@ "-h, --help This help", "-v, --verbose Verbose output", "--ki Key number, 2 hex bytes", - "-k, --key Key, 16 hex bytes" + "--key Key, 16 hex bytes" ], - "usage": "hf mfp auth [-hv] --ki -k " + "usage": "hf mfp auth [-hv] --ki --key " }, "hf mfp chconf": { "command": "hf mfp chconf", @@ -6896,7 +6788,7 @@ "notes": [ "hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B", "hf mfp chk -s 2 -a -> check default key list on sector 2, only key A", - "hf mfp chk -f mfp_default_keys -s 0 -e 6 -> check keys from dictionary against sectors 0-6", + "hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6", "hf mfp chk --pattern1b --dump -> check all 1-byte keys pattern and save found keys to file", "hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00" ], @@ -6908,15 +6800,14 @@ "-s, --startsec <0..255> Start sector number", "-e, --endsec <0..255> End sector number", "-k, --key Key for checking (HEX 16 bytes)", - "-f, --file Dictionary file with default keys", + "-d, --dict Dictionary file with keys", "--pattern1b Check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)", "--pattern2b Check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)", "--startp2b Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)", "--dump Dump found keys to JSON file", - "--no-default Skip check default keys", "-v, --verbose Verbose output" ], - "usage": "hf mfp chk [-habv] [-s <0..255>] [-e <0..255>] [-k ] [-f ] [--pattern1b] [--pattern2b] [--startp2b ] [--dump] [--no-default]" + "usage": "hf mfp chk [-habv] [-s <0..255>] [-e <0..255>] [-k ] [-d ] [--pattern1b] [--pattern2b] [--startp2b ] [--dump]" }, "hf mfp chkey": { "command": "hf mfp chkey", @@ -7174,16 +7065,16 @@ }, "hf mfu aesauth": { "command": "hf mfu aesauth", - "description": "Tests AES key on Mifare Ultralight AES tags. If no key is specified, null key will be tried. Key index 0... DataProtKey (default) Key index 1... UIDRetrKey Key index 2... OriginalityKey", + "description": "Tests AES key on Mifare Ultralight AES tags. If no key is specified, null key will be tried. Key index 0: DataProtKey (default) Key index 1: UIDRetrKey Key index 2: OriginalityKey", "notes": [ "hf mfu aesauth", - "hf mfu aesauth --key <16 hex bytes> --idx <0..2>" + "hf mfu aesauth --key <32 bytes> --index <0..2>" ], "offline": false, "options": [ "-h, --help This help", - "--key AES key (16 hex bytes)", - "-i, --idx <0..2> Key index (def: 0)", + "--key AES key (32 hex bytes)", + "-i, --index <0..2> Key index, default: 0", "-k Keep field on (only if a key is provided)" ], "usage": "hf mfu aesauth [-hk] [--key ] [-i <0..2>]" @@ -7208,7 +7099,7 @@ }, "hf mfu cauth": { "command": "hf mfu cauth", - "description": "Tests 3DES key on Mifare Ultralight-C tag. If key is not specified, a set of known defaults will be tried.", + "description": "Tests 3DES password on Mifare Ultralight-C tag. If password is not specified, a set of known defaults will be tested.", "notes": [ "hf mfu cauth", "hf mfu cauth --key 000102030405060708090a0b0c0d0e0f" @@ -7216,9 +7107,9 @@ "offline": false, "options": [ "-h, --help This help", - "--key Authentication key (16 bytes in hex)", + "--key Authentication key (UL-C 16 hex bytes)", "-l Swap entered key's endianness", - "-k Keep field on (only if a key is provided)" + "-k Keep field on (only if a password is provided)" ], "usage": "hf mfu cauth [-hlk] [--key ]" }, @@ -7487,24 +7378,21 @@ }, "hf mfu sim": { "command": "hf mfu sim", - "description": "Simulate MIFARE Ultralight family type based upon ISO/IEC 14443 type A tag with 4,7 or 10 byte UID from emulator memory. See `hf mfu eload` first. The UID from emulator memory will be used if not specified. See `hf 14a sim -h` to see available types. You want 2, 7 or 13 usually.", + "description": "Simulate MIFARE Ultralight family type based upon ISO/IEC 14443 type A tag with 4,7 or 10 byte UID from emulator memory. See `hf mfu eload` first. The UID from emulator memory will be used if not specified. See `hf 14a sim -h` to see available types. You want 2 or 7 usually.", "notes": [ "hf mfu sim -t 2 --uid 11223344556677 -> MIFARE Ultralight", "hf mfu sim -t 7 --uid 11223344556677 -n 5 -> MFU EV1 / NTAG 215 Amiibo", - "hf mfu sim -t 7 -> MFU EV1 / NTAG 215 Amiibo", - "hf mfu sim -t 13 -> MIFARE Ultralight-C" + "hf mfu sim -t 7 -> MFU EV1 / NTAG 215 Amiibo" ], "offline": false, "options": [ "-h, --help This help", - "-t, --type <1..13> Simulation type to use", + "-t, --type <1..12> Simulation type to use", "-u, --uid <4|7|10> hex bytes UID", "-n, --num Exit simulation after blocks. 0 = infinite", - "-v, --verbose Verbose output", - "--c1 UL-C Auth - all zero handshake part 1", - "--c2 UL-C Auth - all zero handshake part 2" + "-v, --verbose Verbose output" ], - "usage": "hf mfu sim [-hv] -t <1..13> [-u ] [-n ] [--c1] [--c2]" + "usage": "hf mfu sim [-hv] -t <1..12> [-u ] [-n ]" }, "hf mfu tamper": { "command": "hf mfu tamper", @@ -7985,10 +7873,9 @@ ], "offline": true, "options": [ - "-h, --help This help", - "-p, --parse Parse the certificates as ASN.1" + "-h, --help This help" ], - "usage": "hf telsa info [-hp]" + "usage": "hf telsa info [-h]" }, "hf tesla list": { "command": "hf tesla list", @@ -8328,7 +8215,7 @@ }, "hf xerox help": { "command": "hf xerox help", - "description": "help This help list List ISO-14443B history -------- ----------------------- Operations ----------------------- view Display content from tag dump file --------------------------------------------------------------------------------------- hf xerox list available offline: yes Alias of `trace list -t 14b -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", + "description": "help This help list List ISO-14443B history -------- ----------------------- General ----------------------- view Display content from tag dump file --------------------------------------------------------------------------------------- hf xerox list available offline: yes Alias of `trace list -t 14b -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol", "notes": [ "hf 14b list --frame -> show frame delay times", "hf 14b list -1 -> use trace buffer" @@ -9490,10 +9377,11 @@ "offline": false, "options": [ "-h, --help This help", + "--par Add parity bit when sending commands", "--rnd Random 56-bit", "--frn F(RN) 28-bit as 4 hex bytes" ], - "usage": "lf em 4x70 auth [-h] --rnd --frn " + "usage": "lf em 4x70 auth [-h] [--par] --rnd --frn " }, "lf em 4x70 autorecover": { "command": "lf em 4x70 autorecover", @@ -9506,11 +9394,12 @@ "offline": false, "options": [ "-h, --help This help", + "--par Add parity bit when sending commands", "--rnd Random 56-bit from known-good authentication", "--frn F(RN) 28-bit as 4 hex bytes from known-good authentication", "--grn G(RN) 20-bit as 3 hex bytes from known-good authentication" ], - "usage": "lf em 4x70 autorecover [-h] --rnd --frn --grn " + "usage": "lf em 4x70 autorecover [-h] [--par] --rnd --frn --grn " }, "lf em 4x70 calc": { "command": "lf em 4x70 calc", @@ -9539,24 +9428,27 @@ "offline": true, "options": [ "-h, --help This help", + "--par Add parity bit when sending commands", "-b, --block block/word address, dec", "--rnd Random 56-bit", "--frn F(RN) 28-bit as 4 hex bytes", "-s, --start Start bruteforce enumeration from this key value" ], - "usage": "lf em 4x70 brute [-h] -b --rnd --frn [-s ]" + "usage": "lf em 4x70 brute [-h] [--par] -b --rnd --frn [-s ]" }, "lf em 4x70 info": { "command": "lf em 4x70 info", "description": "Tag Information EM4x70 Tag variants include ID48 automotive transponder. ID48 does not use command parity (default). V4070 and EM4170 do require parity bit.", "notes": [ - "lf em 4x70 info" + "lf em 4x70 info", + "lf em 4x70 info --par -> adds parity bit to command" ], "offline": false, "options": [ - "-h, --help This help" + "-h, --help This help", + "--par Add parity bit when sending commands" ], - "usage": "lf em 4x70 info [-h]" + "usage": "lf em 4x70 info [-h] [--par]" }, "lf em 4x70 recover": { "command": "lf em 4x70 recover", @@ -9569,12 +9461,13 @@ "offline": true, "options": [ "-h, --help This help", + "--par Add parity bit when sending commands", "-k, --key Key as 6 hex bytes", "--rnd Random 56-bit", "--frn F(RN) 28-bit as 4 hex bytes", "--grn G(RN) 20-bit as 3 hex bytes" ], - "usage": "lf em 4x70 recover [-h] -k --rnd --frn --grn " + "usage": "lf em 4x70 recover [-h] [--par] -k --rnd --frn --grn " }, "lf em 4x70 setkey": { "command": "lf em 4x70 setkey", @@ -9587,49 +9480,56 @@ "offline": false, "options": [ "-h, --help This help", + "--par Add parity bit when sending commands", "-k, --key Key as 12 hex bytes" ], - "usage": "lf em 4x70 setkey [-h] -k " + "usage": "lf em 4x70 setkey [-h] [--par] -k " }, "lf em 4x70 setpin": { "command": "lf em 4x70 setpin", "description": "Write new PIN", "notes": [ - "lf em 4x70 setpin -p 11223344 -> Write new PIN" + "lf em 4x70 setpin -p 11223344 -> Write new PIN", + "lf em 4x70 setpin -p 11223344 --par -> Write new PIN using parity commands" ], "offline": false, "options": [ "-h, --help This help", + "--par Add parity bit when sending commands", "-p, --pin pin, 4 bytes" ], - "usage": "lf em 4x70 setpin [-h] -p " + "usage": "lf em 4x70 setpin [-h] [--par] -p " }, "lf em 4x70 unlock": { "command": "lf em 4x70 unlock", "description": "Unlock EM4x70 by sending PIN Default pin may be: AAAAAAAA 00000000", "notes": [ - "lf em 4x70 unlock -p 11223344 -> Unlock with PIN" + "lf em 4x70 unlock -p 11223344 -> Unlock with PIN", + "lf em 4x70 unlock -p 11223344 --par -> Unlock with PIN using parity commands" ], "offline": false, "options": [ "-h, --help This help", + "--par Add parity bit when sending commands", "-p, --pin pin, 4 bytes" ], - "usage": "lf em 4x70 unlock [-h] -p " + "usage": "lf em 4x70 unlock [-h] [--par] -p " }, "lf em 4x70 write": { "command": "lf em 4x70 write", "description": "Write EM4x70", "notes": [ - "lf em 4x70 write -b 15 -d c0de -> write 'c0de' to block 15" + "lf em 4x70 write -b 15 -d c0de -> write 'c0de' to block 15", + "lf em 4x70 write -b 15 -d c0de --par -> adds parity bit to commands" ], "offline": false, "options": [ "-h, --help This help", + "--par Add parity bit when sending commands", "-b, --block block/word address, dec", "-d, --data data, 2 bytes" ], - "usage": "lf em 4x70 write [-h] -b -d " + "usage": "lf em 4x70 write [-h] [--par] -b -d " }, "lf em help": { "command": "lf em help", @@ -11731,7 +11631,7 @@ }, "lf t55xx help": { "command": "lf t55xx help", - "description": "----------- ---------------------------- notice ----------------------------- Remember to run `lf t55xx detect` first whenever a new card is placed on the Proxmark3 or the config block changed. help This help ----------- --------------------- operations --------------------- config Set/Get T55XX configuration (modulation, inverted, offset, rate) detect Try detecting the tag modulation from reading the configuration block info Show T55x7 configuration data (page 0/ blk 0) trace Show T55x7 traceability data (page 1/ blk 0-1) view Display content from tag dump file ----------- --------------------- recovery --------------------- sniff Attempt to recover T55xx commands from sample buffer --------------------------------------------------------------------------------------- lf t55xx clonehelp available offline: no Display a list of available commands for cloning specific techs on T5xx tags", + "description": "----------- ---------------------------- notice ----------------------------- Remember to run `lf t55xx detect` first whenever a new card is placed on the Proxmark3 or the config block changed. help This help ----------- --------------------- operations --------------------- config Set/Get T55XX configuration (modulation, inverted, offset, rate) detect Try detecting the tag modulation from reading the configuration block info Show T55x7 configuration data (page 0/ blk 0) trace Show T55x7 traceability data (page 1/ blk 0-1) ----------- --------------------- recovery --------------------- sniff Attempt to recover T55xx commands from sample buffer --------------------------------------------------------------------------------------- lf t55xx clonehelp available offline: no Display a list of available commands for cloning specific techs on T5xx tags", "notes": [ "lf t55xx clonehelp" ], @@ -11926,20 +11826,6 @@ ], "usage": "lf t55xx trace [-h1] [--r0] [--r1] [--r2] [--r3]" }, - "lf t55xx view": { - "command": "lf t55xx view", - "description": "Print a T55xx dump file (bin/eml/json)", - "notes": [ - "lf t55xx view -f lf-t55xx-00000000-11111111-22222222-33333333-dump.bin" - ], - "offline": true, - "options": [ - "-h, --help This help", - "-f, --file Specify a filename for dump file", - "-v, --verbose verbose output" - ], - "usage": "lf t55xx view [-hv] -f " - }, "lf t55xx wakeup": { "command": "lf t55xx wakeup", "description": "This commands sends the Answer-On-Request command and leaves the readerfield ON afterwards", @@ -12223,27 +12109,24 @@ }, "mem load": { "command": "mem load", - "description": "Loads binary file into flash memory on device Warning! - mem area to be written must have been wiped first OBS! - dictionaries are serviced as files in spiffs so no wipe is needed", + "description": "Loads binary file into flash memory on device Warning: mem area to be written must have been wiped first ( dictionaries are serviced as files in spiffs so no wipe is needed )", "notes": [ "mem load -f myfile -> upload file myfile values at default offset 0", "mem load -f myfile -o 1024 -> upload file myfile values at offset 1024", - "mem load -f mfc_default_keys -m -> upload MIFARE Classic keys", + "mem load -f mfc_default_keys -m -> upload MFC keys", "mem load -f t55xx_default_pwds -t -> upload T55XX passwords", - "mem load -f iclass_default_keys -i -> upload iCLASS keys", - "mem load -f mfulc_default_keys --ulc -> upload MIFARE UL-C keys" + "mem load -f iclass_default_keys -i -> upload iCLASS keys" ], "offline": false, "options": [ "-h, --help This help", "-o, --offset offset in memory", - "-m, --mfc upload 6 bytes keys (MIFARE Classic dictionary)", - "-i, --iclass upload 8 bytes keys (iClass dictionary)", - "-t, --t55xx upload 4 bytes keys (T55xx dictionary)", - "--ulc upload 16 bytes keys (MIFARE UL-C dictionary)", - "--aes upload 16 bytes keys (MIFARE UL-AES dictionary)", + "-m, --mifare, --mfc upload 6 bytes keys (mifare key dictionary)", + "-i, --iclass upload 8 bytes keys (iClass key dictionary)", + "-t, --t55xx upload 4 bytes keys (password dictionary)", "-f, --file file name" ], - "usage": "mem load [-hmit] [-o ] [--ulc] [--aes] -f " + "usage": "mem load [-hmit] [-o ] -f " }, "mem spiffs check": { "command": "mem spiffs check", @@ -12428,42 +12311,6 @@ ], "usage": "mem wipe [-h] [-p ]" }, - "mqtt help": { - "command": "mqtt help", - "description": "help This help send Send messages or json file over MQTT receive Receive message or json file over MQTT --------------------------------------------------------------------------------------- mqtt send available offline: yes This command send MQTT messages. You can send JSON file Default server: proxdump.com:1883 topic: proxdump", - "notes": [ - "mqtt send --msg \"Hello from Pm3\" -> sending msg to default server/port/topic", - "mqtt send -f myfile.json -> sending file to default server/port/topic", - "mqtt send --addr test.mosquitto.org -p 1883 --topic pm3 --msg \"custom mqtt server \"" - ], - "offline": true, - "options": [ - "-h, --help This help", - "--addr MQTT server address", - "-p, --port MQTT server port", - "--topic MQTT topic", - "--msg Message to send over MQTT", - "-f, --file file to send" - ], - "usage": "mqtt send [-h] [--addr ] [-p ] [--topic ] [--msg ] [-f ]" - }, - "mqtt receive": { - "command": "mqtt receive", - "description": "This command receives MQTT messages. JSON text will be saved to file if detected Default server: proxdump.com:1883 topic: proxdump", - "notes": [ - "mqtt receive -> listening to default server/port/topic", - "mqtt receive --addr test.mosquitto.org -p 1883 --topic pm3" - ], - "offline": true, - "options": [ - "-h, --help This help", - "--addr MQTT server address", - "-p, --port MQTT server port", - "--topic MQTT topic", - "-f, --file file name to use for received files" - ], - "usage": "mqtt receive [-h] [--addr ] [-p ] [--topic ] [-f ]" - }, "msleep": { "command": "msleep", "description": "Sleep for given amount of milliseconds", @@ -12894,18 +12741,6 @@ ], "usage": "prefs get hints [-h]" }, - "prefs get mqtt": { - "command": "prefs get mqtt", - "description": "Get preference of MQTT settings in the client", - "notes": [ - "prefs get mqtt" - ], - "offline": true, - "options": [ - "-h, --help This help" - ], - "usage": "prefs get mqtt [-h]" - }, "prefs get output": { "command": "prefs get output", "description": "Get preference of dump output style", @@ -13031,7 +12866,7 @@ }, "prefs set help": { "command": "prefs set help", - "description": "help This help barmode Set bar mode client.debug Set client debug level client.delay Set client execution delay client.timeout Set client communication timeout color Set color support emoji Set emoji display hints Set hint display savepaths ... to be adjusted next ... output Set dump output style plotsliders Set plot slider display mqtt Set MQTT default values --------------------------------------------------------------------------------------- prefs set barmode available offline: yes Set persistent preference of HF/LF tune command styled output in the client", + "description": "help This help barmode Set bar mode client.debug Set client debug level client.delay Set client execution delay client.timeout Set client communication timeout color Set color support emoji Set emoji display hints Set hint display savepaths ... to be adjusted next ... output Set dump output style plotsliders Set plot slider display --------------------------------------------------------------------------------------- prefs set barmode available offline: yes Set persistent preference of HF/LF tune command styled output in the client", "notes": [ "prefs set barmode --mix" ], @@ -13058,22 +12893,6 @@ ], "usage": "prefs set hints [-h] [--off] [--on]" }, - "prefs set mqtt": { - "command": "prefs set mqtt", - "description": "Set persistent preference MQTT Server in the client", - "notes": [ - "prefs set mqtt -s test.mosquito.com", - "prefs set mqtt -s test.mosquito.com -p 1883 -t proxdump" - ], - "offline": true, - "options": [ - "-h, --help This help", - "-s, --srv default MQTT Server", - "-p, --port default MQTT Port", - "-t, --topic default MQTT Topic" - ], - "usage": "prefs set mqtt [-h] [-s ] [-p ] [-t ]" - }, "prefs set output": { "command": "prefs set output", "description": "Set dump output style to condense consecutive repeated data", @@ -13536,8 +13355,8 @@ } }, "metadata": { - "commands_extracted": 780, + "commands_extracted": 767, "extracted_by": "PM3Help2JSON v1.00", - "extracted_on": "2025-08-20T08:39:30" + "extracted_on": "2025-03-24T22:47:29" } } diff --git a/doc/commands.md b/doc/commands.md index fbae0a050..12312b7fc 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -46,7 +46,6 @@ Check column "offline" for their availability. |`prefs get hints `|Y |`Get hint display preference` |`prefs get output `|Y |`Get dump output style preference` |`prefs get plotsliders `|Y |`Get plot slider display preference` -|`prefs get mqtt `|Y |`Get MQTT preference` ### prefs set @@ -66,7 +65,6 @@ Check column "offline" for their availability. |`prefs set savepaths `|Y |`... to be adjusted next ... ` |`prefs set output `|Y |`Set dump output style` |`prefs set plotsliders `|Y |`Set plot slider display` -|`prefs set mqtt `|Y |`Set MQTT default values` ### analyse @@ -279,7 +277,7 @@ Check column "offline" for their availability. |command |offline |description |------- |------- |----------- |`hf cipurse help `|Y |`This help.` -|`hf cipurse info `|N |`Tag information` +|`hf cipurse info `|N |`Get info about CIPURSE tag` |`hf cipurse select `|N |`Select CIPURSE application or file` |`hf cipurse auth `|N |`Authenticate CIPURSE tag` |`hf cipurse read `|N |`Read binary file` @@ -315,7 +313,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`hf emrtd help `|Y |`This help` |`hf emrtd dump `|N |`Dump eMRTD files to binary files` -|`hf emrtd info `|Y |`Tag information` +|`hf emrtd info `|Y |`Display info about an eMRTD` |`hf emrtd list `|Y |`List ISO 14443A/7816 history` @@ -333,7 +331,6 @@ Check column "offline" for their availability. |`hf felica reader `|N |`Act like an ISO18092/FeliCa reader` |`hf felica sniff `|N |`Sniff ISO 18092/FeliCa traffic` |`hf felica wrbl `|N |`write block data to an authentication-not-required Service.` -|`hf felica dump `|N |`Wait for and try dumping FeliCa` |`hf felica rqservice `|N |`verify the existence of Area and Service, and to acquire Key Version.` |`hf felica rqresponse `|N |`verify the existence of a card and its Mode.` |`hf felica scsvcode `|N |`acquire Area Code and Service Code.` @@ -343,7 +340,6 @@ Check column "offline" for their availability. |`hf felica rqspecver `|N |`acquire the version of card OS.` |`hf felica resetmode `|N |`reset Mode to Mode 0.` |`hf felica litesim `|N |`Emulating ISO/18092 FeliCa Lite tag` -|`hf felica liteauth `|N |`authenticate a card.` |`hf felica litedump `|N |`Wait for and try dumping FelicaLite` @@ -355,7 +351,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`hf fido help `|Y |`This help.` |`hf fido list `|Y |`List ISO 14443A history` -|`hf fido info `|N |`Tag information` +|`hf fido info `|N |`Info about FIDO tag.` |`hf fido reg `|N |`FIDO U2F Registration Message.` |`hf fido auth `|N |`FIDO U2F Authentication Message.` |`hf fido make `|N |`FIDO2 MakeCredential command.` @@ -408,7 +404,7 @@ Check column "offline" for their availability. |`hf iclass view `|Y |`Display content from tag dump file` |`hf iclass wrbl `|N |`Write Picopass / iCLASS block` |`hf iclass creditepurse `|N |`Credit epurse value` -|`hf iclass tear `|N |`Performs tearoff attack on iCLASS block` +|`hf iclass trbl `|N |`Performs tearoff attack on iClass block` |`hf iclass chk `|N |`Check keys` |`hf iclass loclass `|Y |`Use loclass to perform bruteforce reader attack` |`hf iclass lookup `|Y |`Uses authentication trace to check for key in dictionary file` @@ -464,7 +460,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`hf ksx6924 help `|Y |`This help` |`hf ksx6924 select `|N |`Select application, and leave field up` -|`hf ksx6924 info `|N |`Tag information` +|`hf ksx6924 info `|N |`Get info about a KS X 6924 (T-Money, Snapper+) transit card` |`hf ksx6924 balance `|N |`Get current purse balance` |`hf ksx6924 init `|N |`Perform transaction initialization with Mpda` |`hf ksx6924 prec `|N |`Send proprietary get record command (CLA=90, INS=4C)` @@ -518,6 +514,8 @@ Check column "offline" for their availability. |------- |------- |----------- |`hf mf help `|Y |`This help` |`hf mf list `|Y |`List MIFARE history` +|`hf mf info `|N |`mfc card Info` +|`hf mf isen `|N |`mfc card Info Static Encrypted Nonces` |`hf mf darkside `|N |`Darkside attack` |`hf mf nested `|N |`Nested attack` |`hf mf hardnested `|Y |`Nested attack for hardened MIFARE Classic cards` @@ -529,12 +527,9 @@ Check column "offline" for their availability. |`hf mf fchk `|N |`Check keys fast, targets all keys on card` |`hf mf decrypt `|Y |`Decrypt Crypto1 data from sniff or trace` |`hf mf supercard `|N |`Extract info from a `super card`` -|`hf mf bambukeys `|Y |`Generate key table for Bambu Lab filament tag` |`hf mf auth4 `|N |`ISO14443-4 AES authentication` |`hf mf acl `|Y |`Decode and print MIFARE Classic access rights bytes` |`hf mf dump `|N |`Dump MIFARE Classic tag to binary file` -|`hf mf info `|N |`Tag information` -|`hf mf isen `|N |`Information Static Encrypted Nonces` |`hf mf mad `|Y |`Checks and prints MAD` |`hf mf personalize `|N |`Personalize UID (MIFARE Classic EV1 only)` |`hf mf rdbl `|N |`Read MIFARE Classic block` @@ -594,7 +589,7 @@ Check column "offline" for their availability. |`hf mfp auth `|N |`Authentication` |`hf mfp chk `|N |`Check keys` |`hf mfp dump `|N |`Dump MIFARE Plus tag to binary file` -|`hf mfp info `|N |`Tag information` +|`hf mfp info `|N |`Info about MIFARE Plus tag` |`hf mfp mad `|N |`Check and print MAD` |`hf mfp rdbl `|N |`Read blocks from card` |`hf mfp rdsc `|N |`Read sectors from card` @@ -672,7 +667,6 @@ Check column "offline" for their availability. |`hf mfdes getkeyversions`|N |`Get Key Versions` |`hf mfdes getfileids `|N |`Get File IDs list` |`hf mfdes getfileisoids `|N |`Get File ISO IDs list` -|`hf mfdes lsfile `|N |`Show all files list` |`hf mfdes lsfiles `|N |`Show all files list` |`hf mfdes dump `|N |`Dump all files` |`hf mfdes createfile `|N |`Create Standard/Backup File` @@ -792,7 +786,7 @@ Check column "offline" for their availability. ### hf vas - { Apple Value Added Service... } + { Apple Value Added Service } |command |offline |description |------- |------- |----------- @@ -819,7 +813,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`hf xerox help `|Y |`This help` |`hf xerox list `|Y |`List ISO-14443B history` -|`hf xerox info `|N |`Tag information` +|`hf xerox info `|N |`Short info on Fuji/Xerox tag` |`hf xerox dump `|N |`Read all memory pages of an Fuji/Xerox tag, save to file` |`hf xerox reader `|N |`Act like a Fuji/Xerox reader` |`hf xerox view `|Y |`Display content from tag dump file` @@ -996,7 +990,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf em 4x70 help `|Y |`This help` |`lf em 4x70 brute `|N |`Bruteforce EM4X70 to find partial key` -|`lf em 4x70 info `|N |`Tag information` +|`lf em 4x70 info `|N |`Tag information EM4x70` |`lf em 4x70 write `|N |`Write EM4x70` |`lf em 4x70 unlock `|N |`Unlock EM4x70 for writing` |`lf em 4x70 auth `|N |`Authenticate EM4x70` @@ -1069,7 +1063,7 @@ Check column "offline" for their availability. |------- |------- |----------- |`lf hitag help `|Y |`This help` |`lf hitag list `|Y |`List Hitag trace history` -|`lf hitag info `|N |`Tag information` +|`lf hitag info `|N |`Hitag 2 tag information` |`lf hitag reader `|N |`Act like a Hitag 2 reader` |`lf hitag test `|Y |`Perform self tests` |`lf hitag dump `|N |`Dump Hitag 2 tag` @@ -1347,7 +1341,6 @@ Check column "offline" for their availability. |`lf t55xx restore `|N |`Restore T55xx card Page 0 / Page 1 blocks` |`lf t55xx trace `|Y |`Show T55x7 traceability data (page 1/ blk 0-1)` |`lf t55xx wakeup `|N |`Send AOR wakeup command` -|`lf t55xx view `|Y |`Display content from tag dump file` |`lf t55xx write `|N |`Write T55xx block data` |`lf t55xx bruteforce `|N |`Simple bruteforce attack to find password` |`lf t55xx chk `|N |`Check passwords` @@ -1408,7 +1401,7 @@ Check column "offline" for their availability. |`mem spiffs copy `|N |`Copy a file to another (destructively) in SPIFFS file system` |`mem spiffs check `|N |`Check/try to defrag faulty/fragmented file system` |`mem spiffs dump `|N |`Dump a file from SPIFFS file system` -|`mem spiffs info `|N |`File system information and usage statistics` +|`mem spiffs info `|N |`Print file system info and usage statistics` |`mem spiffs mount `|N |`Mount the SPIFFS file system if not already mounted` |`mem spiffs remove `|N |`Remove a file from SPIFFS file system` |`mem spiffs rename `|N |`Rename/move a file in SPIFFS file system` @@ -1420,17 +1413,6 @@ Check column "offline" for their availability. |`mem spiffs wipe `|N |`Wipe all files from SPIFFS file system * dangerous *` -### mqtt - - { MQTT commmands... } - -|command |offline |description -|------- |------- |----------- -|`mqtt help `|Y |`This help` -|`mqtt send `|Y |`Send messages or json file over MQTT` -|`mqtt receive `|Y |`Receive message or json file over MQTT` - - ### nfc { NFC commands... } diff --git a/doc/desfire.md b/doc/desfire.md index 65f1af748..50bddc9d5 100644 --- a/doc/desfire.md +++ b/doc/desfire.md @@ -23,7 +23,6 @@ - [How to create files](#how-to-create-files) - [How to delete files](#how-to-delete-files) - [How to read/write files](#how-to-readwrite-files) - - [How to work with value files](#how-to-work-with-value-files) - [How to work with transaction mac](#how-to-work-with-transaction-mac) - [How to switch DESFire Light to LRP mode](#how-to-switch-desfire-light-to-lrp-mode) @@ -255,7 +254,7 @@ Create standard file with mac access mode and specified access settings. access `hf mfdes createfile --aid 123456 --fid 01 --isofid 0001 --size 000010 --amode mac --rrights free --wrights free --rwrights free --chrights key0` -`hf mfdes createvaluefile --aid 123456 --fid 01 --isofid 0001 --lower 00000010 --upper 00010000 --value 00000100` - create value file (see [How to work with value files](#how-to-work-with-value-files) for detailed examples) +`hf mfdes createvaluefile --aid 123456 --fid 01 --isofid 0001 --lower 00000010 --upper 00010000 --value 00000100` - create value file `hf mfdes createrecordfile --aid 123456 --fid 01 --isofid 0001 --size 000010 --maxrecord 000010` - create linear record file @@ -295,11 +294,9 @@ Here it is needed to specify the type of the file because there is no `hf mfdes `hf mfdes write --aid 123456 --fid 01 --type data -d 01020304 --commit` - write backup data file and commit -`hf mfdes write --aid 123456 --fid 01 --type value -d 00000001` increment value file (deprecated, use `hf mfdes value` command) +`hf mfdes write --aid 123456 --fid 01 --type value -d 00000001` increment value file -`hf mfdes write --aid 123456 --fid 01 --type value -d 00000001 --debit` decrement value file (deprecated, use `hf mfdes value` command) - -For modern value file operations, see [How to work with value files](#how-to-work-with-value-files) +`hf mfdes write --aid 123456 --fid 01 --type value -d 00000001 --debit` decrement value file `hf mfdes write --aid 123456 --fid 01 --type record -d 01020304` write data to a record file @@ -317,188 +314,6 @@ For more detailed samples look at the next howto. `hf mfdes write --aid 123456 --fid 01 -d 01020304 --readerid 010203` write data to the file with CommitReaderID command before and CommitTransaction after write -### How to work with value files -^[Top](#top) - -Value files are specialized files designed for storing and manipulating monetary values or counters. They provide atomic operations for incrementing (credit) and decrementing (debit) values with built-in limits and security features. - -**Key Features:** -- 32-bit value storage (represented internally as unsigned) -- Lower and upper limits to prevent underflow/overflow -- Atomic operations with automatic transaction commit -- Transaction logging support -- Secure communication modes (plain, MAC, encrypted) - -**Value File Structure:** -- Current value: 32-bit value -- Lower limit: minimum allowed value (prevents underflow) -- Upper limit: maximum allowed value (prevents overflow) - -**Access Rights:** -Value files use four access right categories: -- **Read**: Required to get the current value (`hf mfdes value --op get`) -- **Write**: Required for debit operations (`hf mfdes value --op debit`) -- **Read/Write**: Required for credit operations (`hf mfdes value --op credit`) -- **Change**: Required to modify file settings or delete the file - -Access rights can be set to: -- `key0` through `keyE`: Requires authentication with the specified key -- `free`: No authentication required -- `deny`: Operation is forbidden - -*Create value file:* - -Creating a Bitcoin wallet on your DESFire card: -``` -pm3 --> hf mfdes createapp --aid 425443 --ks1 0B --ks2 0E -[+] Desfire application 425443 successfully created - -pm3 --> hf mfdes createvaluefile --aid 425443 --fid 01 --lower 00000000 --upper 01406F40 --value 00000032 -[=] ---- Create file settings ---- -[+] File type : Value -[+] File number : 0x01 (1) -[+] File comm mode : Plain -[+] Additional access: No -[+] Access rights : EEEE -[+] read......... free -[+] write........ free -[+] read/write... free -[+] change....... free -[=] Lower limit... 0 / 0x00000000 -[=] Upper limit... 21000000 / 0x01406F40 -[=] Value............ 50 / 0x00000032 -[=] Limited credit... 0 - disabled -[=] GetValue access... Not Free -[+] Value file 01 in the app 425443 created successfully -``` -This creates a DESFire Bitcoin wallet with: -- Application ID 0x425443 (ASCII "BTC") -- File ID 0x01 for the wallet -- Lower limit: 0 BTC (no overdrafts in crypto) -- Upper limit: 21,000,000 BTC (respecting Satoshi's vision) -- Initial value: 50 BTC (the original block reward) - -Creating the infamous Pizza Day wallet: -``` -pm3 --> hf mfdes createvaluefile --aid 425443 --fid 02 --lower 00000000 --upper 01406F40 --value 00002710 -[=] ---- Create file settings ---- -[+] File type : Value -[+] File number : 0x02 (2) -[+] File comm mode : Plain -[+] Additional access: No -[+] Access rights : EEEE -[+] read......... free -[+] write........ free -[+] read/write... free -[+] change....... free -[=] Lower limit... 0 / 0x00000000 -[=] Upper limit... 21000000 / 0x01406F40 -[=] Value............ 10000 / 0x00002710 -[=] Limited credit... 0 - disabled -[=] GetValue access... Not Free -[+] Value file 02 in the app 425443 created successfully -``` -This creates a wallet pre-loaded with 10,000 BTC (historical exchange rate: 2 pizzas) - -*Value file operations:* - -Check your Bitcoin balance: -``` -pm3 --> hf mfdes value --aid 425443 --fid 01 --op get -[+] Value: 50 (0x00000032) - -pm3 --> hf mfdes value --aid 425443 --fid 01 --op get -m mac -[+] Value: 50 (0x00000032) -``` - -Loading Bitcoin IOUs onto your card: -``` -pm3 --> hf mfdes value --aid 425443 --fid 01 --op credit -d 00000019 -[+] Value changed successfully - -pm3 --> hf mfdes value --aid 425443 --fid 01 --op get -[+] Value: 75 (0x0000004b) -``` -Card now holds 75 BTC in IOUs ($9,000,000 in debt obligations) - -Buying coffee with Bitcoin IOUs: -``` -pm3 --> hf mfdes value --aid 425443 --fid 01 --op debit -d 00000001 -[+] Value changed successfully # You now owe the coffee shop $120,000 - -pm3 --> hf mfdes value --aid 425443 --fid 01 --op get -[+] Value: 74 (0x0000004a) # Remaining debt capacity -``` - -The legendary Pizza Day recreation: -``` -pm3 --> hf mfdes value --aid 425443 --fid 02 --op debit -d 00002710 -[+] Value changed successfully # You now owe Papa John's $1.2 billion - -pm3 --> hf mfdes value --aid 425443 --fid 02 --op get -[+] Value: 0 (0x00000000) # Card empty, bankruptcy imminent -``` - -*Communication modes:* - -Value files support different communication modes for security: - -Plain mode (no encryption): -``` -pm3 --> hf mfdes value --aid 123456 --fid 02 --op get -m plain -[+] Value: 125 (0x0000007d) -``` - -MAC mode (message authentication): -``` -pm3 --> hf mfdes value --aid 123456 --fid 02 --op credit -d 00000032 -m mac -[+] Value changed successfully -``` - -Encrypted mode (full encryption): -``` -pm3 --> hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m encrypted -[+] Value changed successfully -``` - -*Error handling and compatibility:* - -The Proxmark3 implementation includes automatic fallback for compatibility: -- If MAC mode fails with a length error (-20), it automatically retries in plain mode -- This ensures compatibility across different DESFire card generations -- Original communication mode is restored after fallback - -*Transaction behavior:* - -Value operations are atomic with automatic commit: -- The `hf mfdes value` command automatically issues CommitTransaction after credit/debit operations -- Get operations do not require a commit -- Operations either complete fully (including commit) or fail completely -- No manual transaction management required when using the `hf mfdes value` command -- Transaction MAC files can log all value operations for audit trails - -*Practical examples:* - -Daily Bitcoin IOU catastrophes: -``` -# Check morning IOU balance -pm3 --> hf mfdes value --aid 425443 --fid 01 --op get -[+] Value: 50 (0x00000032) # $6 million in IOUs - -# Friend sends you more IOUs via NFC bump -pm3 --> hf mfdes value --aid 425443 --fid 01 --op credit -d 000000C8 -[+] Value changed successfully # +200 BTC IOUs ($24M more debt) - -# Buy a Tesla (tap payment) -pm3 --> hf mfdes value --aid 425443 --fid 01 --op debit -d 00000001 -[+] Value changed successfully - -# Check remaining IOU capacity -pm3 --> hf mfdes value --aid 425443 --fid 01 --op get -[+] Value: 273 (0x00000111) # $32.76M in transferable debt -``` - - ### How to work with transaction mac ^[Top](#top) diff --git a/doc/fpga_arm_notes.md b/doc/fpga_arm_notes.md index 21eba6818..4cc47b88a 100644 --- a/doc/fpga_arm_notes.md +++ b/doc/fpga_arm_notes.md @@ -73,9 +73,9 @@ There is a docker image with webpack installed which has been built which you ca ``` docker pull nhutton/prox-container:webp_image_complete -docker run -v /proxmark3:/tmp/proxmark3 --rm -it nhutton/prox-container:1.0 bash -$ cd /tmp/proxmark3/fpga -$ make all -j +docker run -v /proxmark3:/tmp --rm -it nhutton/prox-container:webp_image_complete bash +$ cd /tmp/proxmark/fpga +$ make all ``` In order to save space, these fpga images are LZ4 compressed and included in the fullimage.elf file when compiling the ARM SRC. `make armsrc` diff --git a/doc/hid_downgrade.md b/doc/hid_downgrade.md index 3cc23beea..c5a85f0ab 100644 --- a/doc/hid_downgrade.md +++ b/doc/hid_downgrade.md @@ -24,7 +24,6 @@ This document targets both Proxmark3 and Flipper Zero devices. - [Simulate a standard keyed iCLASS legacy credential](#simulate-a-standard-keyed-iclass-legacy-credential) - [Write a downgraded iCLASS legacy credential](#write-a-downgraded-iclass-legacy-credential) - [Using Omnikey Reader 5427CK Gen2 and Proxmark3](#using-omnikey-reader-5427ck-gen2-and-proxmark3) - - [Using Elatec TWN4 or TWN4 mini (USB front reader)](#using-elatec-twn4-or-twn4-mini-usb-front-reader) - [Using Flipper Zero with NARD](#using-flipper-zero-with-nard) - [Using Weaponized HID Reader](#using-weaponized-hid-reader) - [Write ProxII credential to a T5577](#write-proxii-credential-to-a-t5577) @@ -83,7 +82,7 @@ Unfortantely not all readers will have iCLASS legacy enabled and your **downgrad For the next steps, you will need a `Proxmark3` or `Flipper Zero` device. -## Verify reader has iCLASS legacy enabled +## Verfiy reader has iCLASS legacy enabled ^[Top](#top) Present a standard keyed iCLASS legacy credential at the reader and see if it beeps. @@ -192,20 +191,6 @@ drop iclass-flipper.picopass file here and simulate on Flipper 7. Launch PM3 client, place iCLASS/Picopass card on HF antenna and read your original card on the Omnikey reader 8. Press enter -## Using Elatec TWN4 or TWN4 mini (USB front reader) -^[Top](#top) - -OBS! -The reader must have the `PI` designation on the label for it to have a embedded HID SAM. If you have a reader with a different configuration as per the label, an HID SAM will have to be installed in the SAM slot. - -1. Plug in Elatec reader -2. Launch [appblaster.exe](../tools/twn/AppBlaster.exe) -3. Click on "program firmware image" -4. Select [encoder.bix](../tools/twn/encoder.bix) as the reader firmware -5. Click program image -6. Launch PM3 client, place iCLASS/Picopass card on HF antenna and read your original card on the Elatec reader -8. Press enter - ## Using Flipper Zero with NARD ^[Top](#top) @@ -237,7 +222,7 @@ Prequisite, you will need the following bill of materials (BOM): * Some 20-24 AWG wire or ethernet cable * Your preferred power source (5-9v) -The easiest way is to buy a [ESPKEY](https://www.aliexpress.com/w/wholesale-esp-rfid-tool.html)) +The easiest way is to buy a [ESPKEY](https://www.aliexpress.com/item/32850151497.html) Follow these steps: diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index 1b43873e5..a1d4e7350 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -27,6 +27,7 @@ Useful docs: * [MIFARE Classic block0](#mifare-classic-block0) * [MIFARE Classic Gen1A aka UID](#mifare-classic-gen1a-aka-uid) * [MIFARE Classic Gen1B](#mifare-classic-gen1b) + * [Mifare Classic Direct Write OTP](#mifare-classic-direct-write-otp) * [MIFARE Classic OTP 2.0](#mifare-classic-otp-20) * [MIFARE Classic MF4](#mifare-classic-mf4) * [MIFARE Classic DirectWrite aka Gen2 aka CUID](#mifare-classic-directwrite-aka-gen2-aka-cuid) @@ -46,15 +47,12 @@ Useful docs: * [MIFARE Ultralight EV1 DirectWrite](#mifare-ultralight-ev1-directwrite) * [MIFARE Ultralight C Gen1A](#mifare-ultralight-c-gen1a) * [MIFARE Ultralight C DirectWrite](#mifare-ultralight-c-directwrite) - * [MIFARE Ultralight USCUID-UL](#mifare-ultralight-uscuid-ul) - * [UL-2](#ul-2) - * [UL-2 (20 blocks)](#ul-2-20-blocks) - * [UL-2 (41 blocks)](#ul-2-41-blocks) - * [UL-2 (44 blocks)](#ul-2-44-blocks) + * [UL series (RU)](#ul-series-ru) * [UL-Y](#ul-y) - * [Ultra](#ultra-ru) + * [ULtra](#ultra) * [UL-5](#ul-5) * [UL, other chips](#ul-other-chips) + * [MIFARE Ultralight USCUID-UL](#mifare-ultralight-uscuid-ul) * [NTAG](#ntag) * [NTAG213 DirectWrite](#ntag213-directwrite) * [NTAG21x](#ntag21x) @@ -620,7 +618,7 @@ hf mf info ^[Top](#top) Similar to Gen1A, but after first block 0 edit, tag no longer replies to 0x40 command. -Were manufactured by iKey LLC as a replacement for [OTP](#fuid) +Were manufactured by iKey LLC as a replacement for [OTP](#mifare-classic-direct-write-otp) ### Characteristics @@ -745,9 +743,9 @@ Here is how the IC can be configured: * Other names: * MF-8 (RU) - * MF-3 (RU) - not susceptible to "field reset bug", a way to detect [OTP](#fuid) chips. - * MF-3.2 (RU) - static nonce `01200145`, potentially fixed chip which can bypass Iron Logic's filters. -` + * MF-3 (RU) - not susceptible to "field reset bug", a way to detect [OTP](#mifare-classic-direct-write-otp) chips. + * MF-3.2 (RU) - static nonce `01200145`, helps avoid magic detection. + ### Identify ^[Top](#top) @@ -1148,26 +1146,13 @@ Well-known variations are described below. ^[Top](#top) -* Other names: - * OTP (RU) +Known as "write only once", which is only partially true. Please note that some newer FUIDs have had ton configration blocks locked down and are truly a write-once tag. -Known as "write only once", which is only partially true, because old revisions had backdoor commands enabled, so you could manipulate the tag, using them. -Newer FUIDs are based on new implementation of chip and have backdoor commands disabled by default. +Allows direct write to block 0 only when UID is default `AA55C396`. If your tag responds to a gen4 magic wakeup, the UID could always be rewritten multiple times with backdoors commands. -Allows direct write to block 0 only when UID is default `AA55C396`. If your tag responds to a `20(7)`, `23` magic wakeup, the UID could always be rewritten multiple times with backdoors commands, but that makes that tag detecteable. +Backdoor commands are available even after the personalization and makes that tag detectable. -### Market Usage - -In ex-USSR countries were widely used as a replacement for UID tags. Especially for protected Iron Logic readers.Later filter `OTP` was created in those readers. -The idea of the filter is that old version's chip had an issue in the protocol implementation. - -The reader could interrupt radiofield for 2-3 microseconds (standard pause in the bit period of ISO14443-2). -After the response to first `26 (7)` command, but before the following `93 70` command. In that case original M1 card will stop the flow, but OTP will continue it. - -That issue led to the development of the filters against that card and discontinuation of the production. -As a successor, [OTP 2.0](#mifare-classic-otp-20) was created for that market. - -Newer FUID tags (with backdoor command disabled) has protocol fixed and works fine on Iron Logic readers with firmware older than 7.28, but are filtered by latest filters on mentioned firmware. +That's a key difference from [OTP](#mifare-classic-direct-write-otp)/[OTP 2.0](#mifare-classic-otp-20) tags. ### Characteristics @@ -1192,7 +1177,7 @@ hf mf info ``` -Or locked down tag type: +or locked down tag type: ``` hf mf info @@ -1358,22 +1343,16 @@ All commands are available before sealing. ^[Top](#top) -That tag is a UID tag, built on USCUID chip. It is not sold separately, but could be found on marketplaces under the guise of a UID tag. +That tag is a UID tag, built on USCUID chip. It doesn't sold separately, but could be found on marketplaces under the guise of a UID tag. ### Characteristics ^[Top](#top) -* Default configuration block value: `7AFF0000000000000000000000000008` +* Configuration block value: `7AFF0000000000000000000000000008` +* No direct write to block 0 * Responds to magic wakeup `40(7)`, `43` commands -* Does not have hidden blocks, and only acknowledges the following bytes marked with carats. As such, Gen 1a mode cannot be disabled. All acknowledged bytes follow the standard USCUID format. - -``` -7AFF0000000000000000000000000008 - ^^ >> Block use of Key B if readable by ACL - ^^ >> CUID mode - ^^ >> SAK*** -``` +* Acknowledge only the first (except wakeup command) and last config byte(s), so doesn't have the hidden block ### Identify @@ -1383,10 +1362,13 @@ That tag is a UID tag, built on USCUID chip. It is not sold separately, but coul hf mf info ... [+] Magic capabilities... Gen 1a -[+] Magic capabilities... Gen 4 GDM / USCUID ( ZUID Gen1 Magic Wakeup ) +[+] Magic capabilities... Gen 4 GDM / USCUID ( Gen1 Magic Wakeup ) ``` +Currently Proxmark3 doesn't identify it as a separate tag. +Could be detected from the config block value. + ### Parsed configuration ^[Top](#top) @@ -1416,6 +1398,8 @@ hf mf info * Magic wakeup: `40(7)`, `43` * Backdoor read main block: `30xx+crc` * Backdoor write main block: `A0xx+crc`, `[16 bytes data]+crc` + * Read hidden block: `38xx+crc` + * Write hidden block: `A8xx+crc`, `[16 bytes data]+crc` * Read configuration: `E000+crc` * Write configuration: `E100+crc` @@ -2036,6 +2020,121 @@ Anticol shortcut (CL1/3000): fails script run hf_mfu_magicwrite -h ``` +## UL series (RU) + +^[Top](#top) + +Custom chips, manufactured by iKey LLC for cloning Ultralight tags used in Visit intercoms. That leads to the non-standard for Ultralight chips tag version. + +### UL-Y + +^[Top](#top) + +Ultralight magic, 16 pages. Recommended for Vizit RF3.1 with markings "3.1" or "4.1". +Behavior: allows writes to page 0-2. + +#### Identify + +^[Top](#top) + +``` +hf mfu rdbl --force -b 16 +hf 14a raw -sct 250 60 +``` + +If tag replies with +`Cmd Error: 00` +`00 00 00 00 00 00 00 00` +then it is UL-Y. + +### ULtra + +^[Top](#top) + +Ultralight EV1 magic; 41 page. Recommended for Vizit RF3.1 with 41 page. +Behavior: allows writes to page 0-2. + +#### Identify + +^[Top](#top) + +``` +hf mfu info +... +[=] TAG IC Signature: 0000000000000000000000000000000000000000000000000000000000000000 +[=] --- Tag Version +[=] Raw bytes: 00 34 21 01 01 00 0E 03 +[=] Vendor ID: 34, Mikron JSC Russia +[=] Product type: 21, unknown +``` + +#### ULtra flavour 1 + +^[Top](#top) + +Could be identified by indirect evidence before writing + +* Initial UID: `34 D7 08 11 AD D7 D0` +* `hf mfu dump --ns` + + ``` + [=] 3/0x03 | CF 39 A1 C8 | 1 | .9.. + [=] 4/0x04 | B6 69 26 0D | 1 | .i&. + [=] 5/0x05 | EC A1 73 C4 | 1 | ..s. + [=] 6/0x06 | 81 3D 29 B8 | 1 | .=). + [=] 16/0x10 | 6A F0 2D FF | 0 | j.-. + [=] 20/0x14 | 6A F0 2D FF | 0 | j.-. + [=] 24/0x18 | 6A F0 2D FF | 0 | j.-. + [=] 38/0x26 | 00 E2 00 00 | 0 | .... <- E2, Virtual Card Type Identifier is not default + + ``` + +#### ULtra flavour 2 + +^[Top](#top) + +Could be identified by indirect evidence before writing + +* Initial UID: `04 15 4A 23 36 2F 81` +* Values in pages `3, 4, 5, 6, 16, 20, 24, 38` are default for that tag flavour + +### UL-5 + +^[Top](#top) + +Ultralight EV1 magic; 41 page. Recommended for Vizit RF3.1 with 41 page. +Created as a response to filters that try to overwrite page 0 (as a detection for [ULtra](#mifare-ultra) tags). + +Behavior: similar to Ultra, but after editing page 0 become locked and tag becomes the original Mifare Ultralight EV1 (except the tag version, which remains specific). + +**WARNING!** When using UL-5 to clone, write UID pages in inverse (from 2 to 0) and do NOT make mistakes! This tag does not allow reversing one-way actions (OTP page, lock bits). + +#### Identify + +^[Top](#top) + +``` +hf mfu info +... +TAG IC Signature: 0000000000000000000000000000000000000000000000000000000000000000 +[=] --- Tag Version +[=] Raw bytes: 00 34 21 01 01 00 0E 03 +[=] Vendor ID: 34, Mikron JSC Russia +``` + +After personalization it is not possible to identify UL-5. + +The manufacturer confirmed unpersonalized tags could be identified by first 3 bytes of UID: + +* `AA 55 39...` +* `AA 55 C3...` + +### UL, other chips + +**TODO** + +UL-X, UL-Z - ? + ## MIFARE Ultralight USCUID-UL ^[Top](#top) @@ -2206,9 +2305,7 @@ No implemented commands at time of writing No implemented commands at time of writing ### Variations - ^[Top](#top) - | Factory configuration | Name | | --- | --- | | 850000A0 00000AC3 00040301 01000B03 | UL-11 | @@ -2218,237 +2315,6 @@ No implemented commands at time of writing | 850000A0 00000A5A 00040402 01001103 | NTAG215 | | 850000A0 00000AAA 00040402 01001303 | NTAG216 | -Variations of USCUID-UL, that were distributed in ex-USSR countries are known as UL-family. -Different variarions were targeted for copying different original tags + for bypassing of different filters. - -## UL-2 - -^[Top](#top) - -Sold on Russian market in variations with 20, 41 and 44 blocks. -All variations support direct write to block 0-2. - -### UL-2 (20 blocks) - -#### Characteristics - -^[Top](#top) - -* Configuration block value: `850000A000000AC30034210101000B03`. -* EV1 Version: `0034210101000B03`. - -#### Identify - -^[Top](#top) - -``` -[usb] pm3 --> hf 14a info -... -[+] ATS: 85 00 00 A0 00 00 0A C3 00 34 21 01 01 00 0B 03 [ 84 00 ] -``` - -### UL-2 (41 blocks) - -Default configuration for USCUID-UL with 41 blocks. Can be found in China by names UL-21 or Ultra (targeting Russian market). - -In China exists in versions with opened and locked configuration. -Could be used for intercoms Grazhda (UA) and Vizit (RU) with non-Micron chips (original chips have EV1 Version `0004030101000E03`). - -* Other names: - * Ultra (China) - * UL-21 (China) - -#### Characteristics - -^[Top](#top) - -* Configuration block value: `850000A000000A3C0004030101000E03`. -* EV1 Version: `0004030101000E03`. - -#### Identify - -^[Top](#top) - -``` -[usb] pm3 --> hf 14a info -... -[+] ATS: 85 00 00 A0 00 00 0A 3C 00 04 03 01 01 00 0E 03 [ C8 1D ] -``` - -### UL-2 (44 blocks) - -#### Characteristics - -^[Top](#top) - -* Configuration block value: `850000A000000A5A0034210101000E03`. -* EV1 Version: `0034210101000E03`. - -#### Identify - -^[Top](#top) - -``` -[usb] pm3 --> hf 14a info -... -[+] ATS: 85 00 00 A0 00 00 0A 5A 00 34 21 01 01 00 0E 03 [ F1 F3 ] -``` - -## UL-Y - -^[Top](#top) - -Variation based on NTAG215 config. -Created for copying 16-blocks Vizit tags. -Now there are well-known 2 variations, which differs only with EV1 Version. -Newer has *Micron Russia* version. - -### Characteristics - -^[Top](#top) - -* Configuration block value: `850000A0AA000A5A0000000000000000` or `850000A0AA000A5A0034210100000000`. -* EV1 Version: `0000000000000000` or `0034210100000000`. -* Has 16 blocks readable. -* Allows write to pages 0-2. -* Has next NTAG215-related configuration: - -``` -[=] 130/0x82 | 00 00 00 BD | 0 | ...� -[=] 131/0x83 | 04 00 00 10 | 0 | .... -[=] 132/0x84 | C0 05 00 00 | 0 | �... -[=] 133/0x85 | FF FF FF FF | 0 | .... // Password, will not be readable in normal conditions -``` - -### Identify - -^[Top](#top) - -``` -[usb] pm3 --> hf 14a info -... -[+] ATS: 85 00 00 A0 AA 00 0A 5A 00 00 00 00 00 00 00 00 [ D5 F9 ] -``` - -## Ultra (RU) - -^[Top](#top) - -Modification of [UL-2 (41 blocks)](#ul-2-41-blocks) for Vizit (RU) intercoms. -Suitable for tags with EV1 Version `0034210101000E03`. - -After communication to iKey LLC (importer of those tags to Russian market), new revisions, imported to Russia have closed config. - -### Characteristics - -^[Top](#top) - -* Configuration block value: `850000A000000A3C0034210101000E03`. -* EV1 Version: `0034210101000E03`. - -### Identify - -^[Top](#top) - -``` -[usb] pm3 --> hf 14a info -... -[+] ATS: 85 00 00 A0 00 00 0A 3C 00 04 03 01 01 00 0E 03 [ C8 1D ] -``` - -### Magic commands - -^[Top](#top) - -Use the script `hf_mfu_ultra.lua` to restore (write) dump to tag or clear previously written tag. - -Usage: -1. Restore dump to tag: - ``` - script run hf_mfu_ultra -f -k -r - ``` -2. Wipe tag (use it to prepare tag for restoring another dump): - ``` - script run hf_mfu_ultra -k -w - ``` -3. Show help: - ``` - script run hf_mfu_ultra -h - ``` - -Examples: -1. Restore dump to tag: - ``` - script run hf_mfu_ultra -f hf-mfu-3476FF1514D866-dump.bin -k ffffffff -r - ``` -2. Wipe tag: - ``` - script run hf_mfu_ultra -k 1d237f76 -w - ``` - -## UL-5 - -^[Top](#top) - -Variation of [Ultra](#ultra-ru) tag, which allows to change UID only once. - -After editing page 0 become locked and tag becomes the original Mifare Ultralight EV1 (except the tag version, which remains specific). - -Created as a response to Vizit (RU) filters that try to overwrite page 0 (as a detection for Ultra (RU) tags). - -**WARNING!** When using UL-5 to clone, write UID pages in inverse (from 2 to 0) and do NOT make mistakes! This tag does not allow reversing one-way actions (OTP page, lock bits). - -It was confirmed from importers to Russian and Ukrainian market (independently) that UL-5 is a variation of USCUID-UL. But so far it's unknown how to achieve that behaviors, because by default UL-5 has it's config locked. - -### Identify - -^[Top](#top) - -``` -hf mfu info -... -TAG IC Signature: 0000000000000000000000000000000000000000000000000000000000000000 -[=] --- Tag Version -[=] Raw bytes: 00 34 21 01 01 00 0E 03 -[=] Vendor ID: 34, Mikron JSC Russia -``` - -After personalization it is not possible to identify UL-5. - -The manufacturer confirmed unpersonalized tags could be identified by first 2 bytes of UID: - -* `AA 55...` - -### Magic commands - -^[Top](#top) - -Use the script `hf_mfu_ultra.lua` to restore (write) dump to tag. - -Usage: -1. Restore dump to tag: - ``` - script run hf_mfu_ultra -f -k -r - ``` -3. Show help: - ``` - script run hf_mfu_ultra -h - ``` - -Examples: -1. Restore dump to tag: - ``` - script run hf_mfu_ultra -f hf-mfu-3476FF1514D866-dump.bin -k ffffffff -r - ``` - -## UL, other chips - -** TODO ** - -* UL -* UL-X -* UL-Z - # DESFire ^[Top](#top) diff --git a/doc/md/Development/Makefile-vs-CMake.md b/doc/md/Development/Makefile-vs-CMake.md index b561ef2d2..2d1094970 100644 --- a/doc/md/Development/Makefile-vs-CMake.md +++ b/doc/md/Development/Makefile-vs-CMake.md @@ -112,7 +112,7 @@ At the moment both are maintained because they don't perfectly overlap yet. | Feature | Makefile | Remarks | |-----|---|---| -| Platform choice | `PLATFORM=` | values: `PM3RDV4`, `PM3GENERIC`, `PM3ICOPYX`, `PM3ULTIMATE` | +| Platform choice | `PLATFORM=` | values: `PM3RDV4`, `PM3GENERIC`, `PM3ICOPYX` | | Platform size | `PLATFORM_SIZE=` | values: `256`, `512` | | Platform extras | `PLATFORM_EXTRAS=` | values: `BTADDON`, `FPC_USART_DEV` | | Skip LF/HF techs in the firmware | `SKIP_`*`=1` | see `common_arm/Makefile.hal` for a list | diff --git a/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md b/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md index 2a6611659..5c9149826 100644 --- a/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md +++ b/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md @@ -47,21 +47,12 @@ On Archlinux: sudo pacman -R modemmanager ``` -# Solution 2: mask ModemManager +# Solution 2: disable ModemManager ^[Top](#top) ```sh sudo systemctl stop ModemManager sudo systemctl disable ModemManager -sudo systemctl mask ModemManager -``` -After doing this check if it has been masked with: -`systemctl status ModemManager` -If you'll get something like this, you've masked ModemManager and you will be ready to install and setup your pm3. -``` -○ ModemManager.service - Loaded: masked (Reason: Unit ModemManager.service is masked.) - Active: inactive (dead) ``` # Solution 3: use filtering udev rules diff --git a/doc/md/Installation_Instructions/Windows-WSL2-Installation-Instructions.md b/doc/md/Installation_Instructions/Windows-WSL2-Installation-Instructions.md index ab25bbcde..cfc6cd01b 100644 --- a/doc/md/Installation_Instructions/Windows-WSL2-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Windows-WSL2-Installation-Instructions.md @@ -467,7 +467,7 @@ You must have Windows Terminal installed to use this script. 3. Make sure your Proxmark3 is plugged in, and it is detected in the Device Manager as a COM port. 4. Run **pm3_quick_startup_wsl2.bat** and accept the UAC prompt. The script auto detects and asks for admin privileges, so you don't have to right-click and select Run As Administrator. 5. It will open up 2 windows. The first one is Command Prompt where initializing commands will run, and you need to keep this window open. The second one is Windows Terminal, where your pm3 client will run. -6. On some systems, you will occasionally see this error popping up: `usbipd: error: WSL kernel is not USBIP capable`. Use command `service udev restart` to suppress that error. + ```batch @echo off @@ -514,9 +514,6 @@ REM -- Replace the following hardware IDs with your actual Proxmark3 ID. You can usbipd bind --hardware-id 9ac4:4b8f usbipd attach --auto-attach --hardware-id 9ac4:4b8f --wsl -REM -- Activate below line by removing the "REM --" prefix if you encounter this error: "usbipd: error: WSL kernel is not USBIP capable" -REM -- wsl -u root "modprobe vhci_hcd" - wsl -u root "service udev restart" wsl -u root "udevadm trigger --action=change" diff --git a/doc/md/Installation_Instructions/macOS-Homebrew-Installation-Instructions.md b/doc/md/Installation_Instructions/macOS-Homebrew-Installation-Instructions.md index f44fa6851..9102de117 100644 --- a/doc/md/Installation_Instructions/macOS-Homebrew-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/macOS-Homebrew-Installation-Instructions.md @@ -175,7 +175,7 @@ These instructions will show how to setup the environment on OSX to the point wh 2. Install dependencies: ``` -brew install readline qt5 gd pkgconfig coreutils openssl +brew install readline qt5 gd pkgconfig coreutils brew install RfidResearchGroup/proxmark3/arm-none-eabi-gcc ``` 3. (optional) Install makefile dependencies: diff --git a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md index 55ca51687..e79863faa 100644 --- a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md +++ b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md @@ -61,12 +61,11 @@ For an up-to-date exhaustive list of options, you can run `make PLATFORM=`. Here are the supported values you can assign to `PLATFORM` in `Makefile.platform`: -| PLATFORM | DESCRIPTION | -|-----------------|-------------------------------| -| PM3RDV4 (def) | Proxmark3 RDV4 | -| PM3GENERIC | Proxmark3 generic target | -| PM3ICOPYX | iCopy-X with XC3S100E | -| PM3ULTIMATE | Proxmark3 Ultimate with XC2S50 | +| PLATFORM | DESCRIPTION | +|-----------------|--------------------------| +| PM3RDV4 (def) | Proxmark3 RDV4 | +| PM3GENERIC | Proxmark3 generic target | +| PM3ICOPYX | iCopy-X with XC3S100E | By default `PLATFORM=PM3RDV4`. @@ -141,7 +140,6 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo | HF_MFCSIM | Simulate Mifare Classic 1k card storing in flashmem - Ray Lee | HF_MSDSAL | EMV Read and emulation - Salvador Mendoza | HF_REBLAY | 14A relay over BT - Salvador Mendoza -| HF_ST25_TEAROFF | Store/restore ST25TB tags with tear-off for counters - SecLabz | HF_TCPRST | IKEA Rothult ST25TA, Standalone Master Key Dump/Emulation - Nick Draffen | HF_TMUDFORD | Read and emulate ISO15693 card UID - Tim Mudford | HF_UNISNIFF | Combined 14a/14b/15 sniffer with runtime selection & extra save options diff --git a/doc/unofficial_desfire_bible.md b/doc/unofficial_desfire_bible.md deleted file mode 100644 index 104f64fcc..000000000 --- a/doc/unofficial_desfire_bible.md +++ /dev/null @@ -1,1008 +0,0 @@ -# The Unofficial DESFire Bible -## A Comprehensive Technical Reference with Citations - -### Table of Contents -1. [Introduction](#introduction) -2. [DESFire Evolution Timeline](#desfire-evolution-timeline) -3. [Version Comparison Table](#version-comparison-table) -4. [Memory Architecture](#memory-architecture) -5. [Security Features by Version](#security-features-by-version) -6. [Complete Command Reference](#complete-command-reference) -7. [Authentication Deep Dive](#authentication-deep-dive) -8. [File Types and Operations](#file-types-and-operations) -9. [Cryptographic Implementation](#cryptographic-implementation) -10. [Communication Modes](#communication-modes) -11. [Error Codes Reference](#error-codes-reference) -12. [Implementation Examples](#implementation-examples) -13. [Bibliography](#bibliography) - ---- - -## Introduction - -MIFARE DESFire is a family of contactless smart card ICs (Integrated Circuits) compliant with ISO/IEC 14443-4 Type A. This comprehensive reference documents all DESFire versions from Classic (D40) through EV3, including the cost-optimized Light variant. Every technical detail includes inline citations to ensure accuracy and traceability. - -### Document Scope -This bible covers: -- All DESFire versions: Classic/EV0, EV1, EV2, EV3, and Light -- Complete command sets with hex codes and parameters -- Authentication protocols and cryptographic implementations -- Memory organization and file structures -- Security features and attack mitigations -- Real-world implementation examples - ---- - -## DESFire Evolution Timeline - -### DESFire Classic/EV0 (D40) - Original Release -- **Release**: Early 2000s -- **Memory**: Fixed 4KB EEPROM [Source: MF3D_H_X3_SDS.pdf] -- **Applications**: Maximum 28 applications [Source: MF3D_H_X3_SDS.pdf] -- **Files per App**: Up to 16 files [Source: AN11004.pdf] -- **Encryption**: DES and 3DES only [Source: MF3D_H_X3_SDS.pdf] -- **Communication Speed**: 106 kbps [Source: AN11004.pdf] -- **Key Features**: - - Basic file types: Standard, Backup, Value, Cyclic Record - - Simple authentication protocol - - No advanced security features - -### DESFire EV1 - First Evolution (2006) -- **Memory Options**: 2KB, 4KB, 8KB EEPROM [Source: AN11004.pdf] -- **Applications**: Still limited to 28 [Source: MF3D_H_X3_SDS.pdf] -- **Files per App**: Increased to 32 [Source: AN11004.pdf] -- **New Cryptography**: Added AES-128 support [Source: AN11004.pdf] -- **Communication Speed**: Up to 848 kbps [Source: AN11004.pdf] -- **New Features** [Source: AN11004.pdf]: - - ISO/IEC 7816-4 APDU wrapping support - - Random UID option for privacy - - GetCardUID command - - ISO file identifiers (2 bytes) - - Transaction backup mechanism - - Improved key management - -### DESFire EV2 - Second Generation (2016) -- **Memory Options**: 2KB, 4KB, 8KB EEPROM [Source: AN12696.pdf] -- **Applications**: Unlimited (removed 28 app limit) [Source: MF3D_H_X3_SDS.pdf] -- **Communication Improvements**: 128-byte frame size (2x EV1) [Source: AN12696.pdf] -- **Major New Features**: - - **Virtual Card Architecture (VCA)** [Source: AN12696.pdf]: Privacy-preserving multiple card emulation - - **Transaction MAC (TMAC)** [Source: AN12696.pdf]: Offline transaction verification - - **Proximity Check** [Source: AN12696.pdf]: Protection against relay attacks - - **Delegated Application Management (DAM)** [Source: AN12696.pdf]: Secure cloud provisioning - - **Multiple Key Sets** [Source: AN12696.pdf]: Key rolling mechanism - - **Originality Check** [Source: AN12696.pdf]: Verify genuine NXP silicon - -### DESFire EV3 - Latest Generation (2020) -- **Memory Options**: 2KB, 4KB, 8KB, 16KB EEPROM [Source: MF3D_H_X3_SDS.pdf] -- **Performance**: 1.6x faster than EV1 [Source: AN12753.pdf] -- **Communication**: 256-byte frame size (2x EV2) [Source: AN12753.pdf] -- **Security Certification**: Common Criteria EAL5+ [Source: plt-05618-a.0-mifare-desfire-ev3-application-note.pdf] -- **New Features**: - - **Transaction Timer** [Source: AN12753.pdf]: Prevents delayed attack scenarios - - **Secure Dynamic Messaging (SDM)** [Source: AN12753.pdf]: Dynamic URL generation - - **Secure Unique NFC (SUN)** [Source: AN12753.pdf]: Unique tap verification - - **Pre-configured DAM Keys** [Source: AN12753.pdf]: Simplified cloud setup - - **Improved MACing** [Source: AN12753.pdf]: Enhanced integrity protection - -### DESFire Light - Cost-Optimized Variant -- **Memory Options**: 0.5KB (640B) or 2KB [Source: [0011955][v1.0] st_pegasus_desfire_lite_v10.pdf] -- **Applications**: Single application only [Source: [0011955][v1.0] st_pegasus_desfire_lite_v10.pdf] -- **Files**: Up to 32 files [Source: [0011955][v1.0] st_pegasus_desfire_lite_v10.pdf] -- **Cryptography**: AES-128 only (no DES/3DES) [Source: [0011955][v1.0] st_pegasus_desfire_lite_v10.pdf] -- **Limitations**: - - No backup files support - - Simplified command set - - No multi-application features - - Reduced security options - ---- - -## Version Comparison Table - -| Feature | Classic/EV0 | EV1 | EV2 | EV3 | Light | -|---------|-------------|-----|-----|-----|-------| -| **Memory Options** | 4KB | 2/4/8KB | 2/4/8KB | 2/4/8/16KB | 0.5/2KB | -| **Max Applications** | 28 [^1] | 28 [^1] | Unlimited [^2] | Unlimited [^2] | 1 [^3] | -| **Files per App** | 16 [^4] | 32 [^4] | 32 [^5] | 32 [^5] | 32 [^3] | -| **Frame Size** | 64B | 64B | 128B [^5] | 256B [^6] | 64B | -| **DES/3DES** | ✓ | ✓ | ✓ | ✓ | ✗ | -| **AES-128** | ✗ | ✓ [^4] | ✓ | ✓ | ✓ [^3] | -| **Random UID** | ✗ | ✓ [^4] | ✓ | ✓ | ✗ | -| **VCA** | ✗ | ✗ | ✓ [^5] | ✓ | ✗ | -| **Proximity Check** | ✗ | ✗ | ✓ [^5] | ✓ | ✗ | -| **Transaction MAC** | ✗ | ✗ | ✓ [^5] | ✓ | Limited | -| **Transaction Timer** | ✗ | ✗ | ✗ | ✓ [^6] | ✗ | -| **SDM/SUN** | ✗ | ✗ | ✗ | ✓ [^6] | ✗ | -| **Speed** | 106 kbps | 848 kbps [^4] | 848 kbps | 1.6x EV1 [^6] | 106 kbps | -| **CC Certification** | ✗ | EAL4+ | EAL5+ | EAL5+ [^7] | EAL4+ | - -[^1]: [Source: MF3D_H_X3_SDS.pdf] -[^2]: [Source: MF3D_H_X3_SDS.pdf] -[^3]: [Source: [0011955][v1.0] st_pegasus_desfire_lite_v10.pdf] -[^4]: [Source: AN11004.pdf] -[^5]: [Source: AN12696.pdf] -[^6]: [Source: AN12753.pdf] -[^7]: [Source: plt-05618-a.0-mifare-desfire-ev3-application-note.pdf] - ---- - -## Memory Architecture - -### Memory Layout Structure - -All DESFire cards follow a hierarchical structure: - -``` -PICC (Card) Level -├── Master Application (AID 0x000000) -│ ├── PICC Master Key -│ └── Card Configuration -└── Applications (AID 0x000001 - 0xFFFFFF) - ├── Application Master Key - ├── Application Keys (0-13) - └── Files (0-31) - ├── Standard Data Files - ├── Backup Files - ├── Value Files - ├── Linear Record Files - └── Cyclic Record Files -``` - -### Application Identifier (AID) -- **Size**: 3 bytes (24 bits) [Source: AN11004.pdf] -- **Range**: 0x000000 to 0xFFFFFF -- **Reserved**: 0x000000 (Master Application) -- **User Range**: 0x000001 to 0xFFFFFF - -### File Types and Structures - -#### 1. Standard Data File -- **Purpose**: Store raw data [Source: AN11004.pdf] -- **Size**: 1 to 8191 bytes (EV1), 1 to 32 bytes (Light) [Source: various] -- **Operations**: Read, Write -- **Structure**: Simple byte array - -#### 2. Backup File -- **Purpose**: Transactional data with commit/abort [Source: AN11004.pdf] -- **Size**: Same as Standard File -- **Operations**: Read, Write, Commit, Abort -- **Note**: Not supported on DESFire Light [Source: [0011955][v1.0] st_pegasus_desfire_lite_v10.pdf] - -#### 3. Value File -- **Purpose**: Store 32-bit signed integer [Source: AN11004.pdf] -- **Operations**: Read, Credit, Debit, Limited Credit -- **Limits**: Configurable lower and upper bounds -- **Structure**: - ``` - Value: 4 bytes (signed int32) - ``` - -#### 4. Linear Record File -- **Purpose**: Append-only records [Source: AN11004.pdf] -- **Record Size**: 1 to 8191 bytes -- **Max Records**: Configurable -- **Operations**: Read, Write (append), Clear - -#### 5. Cyclic Record File -- **Purpose**: Circular buffer of records [Source: AN11004.pdf] -- **Behavior**: Oldest record overwritten when full -- **Operations**: Read, Write (newest), Clear - -### Memory Access Rights - -Each file has configurable access rights [Source: AN11004.pdf]: -- **Read Access**: Key 0-13, 0xE (free), 0xF (deny) -- **Write Access**: Key 0-13, 0xE (free), 0xF (deny) -- **Read&Write Access**: Key 0-13, 0xE (free), 0xF (deny) -- **Change Access Rights**: Key 0-13, 0xF (deny) - -Communication settings per file: -- **0x00**: Plain communication -- **0x01**: MACed communication -- **0x03**: Fully enciphered communication - ---- - -## Security Features by Version - -### DESFire Classic/EV0 Security -- **Encryption**: DES/3DES only [Source: MF3D_H_X3_SDS.pdf] -- **Authentication**: Simple challenge-response -- **Protection**: Basic anti-collision, no advanced features - -### DESFire EV1 Security Enhancements -- **AES-128 Support**: Added alongside DES/3DES [Source: AN11004.pdf] -- **Random UID**: Configurable for privacy [Source: AN11004.pdf] -- **Diversified Keys**: Support for key derivation -- **Anti-tearing**: Transaction backup mechanism - -### DESFire EV2 Security Additions -- **Proximity Check** [Source: AN12696.pdf]: - - Prevents relay attacks - - Time-based distance bounding - - Configurable timing parameters - -- **Virtual Card Architecture (VCA)** [Source: AN12696.pdf]: - - Multiple virtual cards in one - - Install/Select/Delete virtual cards - - Privacy through UID randomization - -- **Transaction MAC (TMAC)** [Source: AN12696.pdf, MF2DLHX0.pdf]: - - Offline transaction verification - - Reader-specific MACs with CommitReaderID command (0xC8) - - Counter-based freshness (TMC - Transaction MAC Counter) - - Special file type 0x05 with unique access rights: - - Read: Normal access control - - Write: Always 0xF (disabled) - - ReadWrite: CommitReaderID key (0x0-0xE enabled, 0xF disabled) - - Change: Normal access control - - TMV (Transaction MAC Value) calculated on CommitTransaction - -- **Secure Messaging v2** [Source: AN12696.pdf]: - - Improved IV generation - - Command counter protection - - Enhanced session key derivation - -### DESFire EV3 Security Features -- **Transaction Timer** [Source: AN12753.pdf]: - - Maximum time window for operations - - Prevents delayed attack scenarios - - Configurable per application - -- **Secure Dynamic Messaging (SDM)** [Source: AN12753.pdf]: - - Dynamic NDEF message generation - - Encrypted file data in URLs - - PICCData and MACed responses - -- **Common Criteria EAL5+** [Source: plt-05618-a.0-mifare-desfire-ev3-application-note.pdf]: - - Highest security certification - - Formally verified implementation - - Hardware security evaluation - ---- - -## Complete Command Reference - -### Authentication Commands - -#### 0x0A - Authenticate (Legacy DES/3DES) -- **Parameters**: KeyNo (1 byte) [Source: protocols.h, line 334] -- **Response**: Encrypted RndB (8 bytes) + status -- **Versions**: All except Light -- **Flow**: See Authentication Deep Dive section - -#### 0x1A - Authenticate ISO (3DES) -- **Parameters**: KeyNo (1 byte) [Source: protocols.h, line 335] -- **Response**: Encrypted RndB (8 bytes) + status -- **Versions**: EV1, EV2, EV3 -- **Note**: ISO/IEC 7816-4 compliant - -#### 0xAA - Authenticate AES -- **Parameters**: KeyNo (1 byte) [Source: protocols.h, line 336] -- **Response**: Encrypted RndB (16 bytes) + status -- **Versions**: EV1, EV2, EV3, Light -- **Note**: Uses AES-128 in CBC mode - -#### 0x71 - AuthenticateEV2First -- **Parameters**: KeyNo (1 byte) + Capabilities [Source: protocols.h, line 337] -- **Response**: Transaction identifier + encrypted data -- **Versions**: EV2, EV3 -- **Purpose**: Initial EV2 authentication with capability exchange - -#### 0x77 - AuthenticateEV2NonFirst -- **Parameters**: KeyNo (1 byte) [Source: protocols.h, line 338] -- **Response**: Encrypted authentication data -- **Versions**: EV2, EV3 -- **Purpose**: Subsequent EV2 authentication - -#### 0x70 - FreeMem -- **Parameters**: None [Source: protocols.h, line 339] -- **Response**: Free memory (3 bytes) -- **Versions**: All -- **Authentication**: Not required - -### Application Management Commands - -#### 0xCA - CreateApplication -- **Parameters**: [Source: protocols.h, line 344] - - AID (3 bytes) - - KeySettings (1 byte) - - NumOfKeys (1 byte): Lower nibble = key count, Upper nibble = crypto method -- **Versions**: All -- **Example**: `CA 01 00 00 0F 81` creates AID 0x000001 with 1 AES key - -#### 0xDA - DeleteApplication -- **Parameters**: AID (3 bytes) [Source: protocols.h, line 345] -- **Versions**: All -- **Authentication**: PICC Master Key required - -#### 0x5A - SelectApplication -- **Parameters**: AID (3 bytes) [Source: protocols.h, line 347] -- **Versions**: All -- **Note**: AID 0x000000 selects master application - -#### 0x6A - GetApplicationIDs -- **Parameters**: None [Source: protocols.h, line 346] -- **Response**: List of AIDs (3 bytes each) -- **Versions**: All - -#### 0x45 - GetKeySettings -- **Parameters**: None [Source: protocols.h, line 350] -- **Response**: KeySettings (1 byte) + NumOfKeys (1 byte) -- **Versions**: All - -#### 0x64 - GetKeyVersion -- **Parameters**: KeyNo (1 byte) [Source: protocols.h, line 355] -- **Response**: Key version (1 byte) -- **Versions**: All - -### File Management Commands - -#### 0xCD - CreateStdDataFile -- **Parameters**: [Source: protocols.h, line 357] - - FileNo (1 byte) - - FileOption/CommSettings (1 byte) - - AccessRights (2 bytes) - - FileSize (3 bytes, LSB first) -- **Versions**: All - -#### 0xCB - CreateBackupFile -- **Parameters**: Same as CreateStdDataFile [Source: protocols.h, line 358] -- **Versions**: All except Light -- **Note**: Supports transaction mechanism - -#### 0xCC - CreateValueFile -- **Parameters**: [Source: protocols.h, line 359] - - FileNo (1 byte) - - CommSettings (1 byte) - - AccessRights (2 bytes) - - LowerLimit (4 bytes) - - UpperLimit (4 bytes) - - Value (4 bytes) - - LimitedCreditEnable (1 byte) -- **Versions**: All - -#### 0xC1 - CreateLinearRecordFile -- **Parameters**: [Source: protocols.h, line 360] - - FileNo (1 byte) - - CommSettings (1 byte) - - AccessRights (2 bytes) - - RecordSize (3 bytes) - - MaxNumberOfRecords (3 bytes) -- **Versions**: All - -#### 0xC0 - CreateCyclicRecordFile -- **Parameters**: Same as CreateLinearRecordFile [Source: protocols.h, line 361] -- **Versions**: All - -#### 0xDF - DeleteFile -- **Parameters**: FileNo (1 byte) [Source: protocols.h, line 362] -- **Versions**: All - -#### 0x6F - GetFileIDs -- **Parameters**: None [Source: protocols.h, line 363] -- **Response**: List of FileIDs (1 byte each) -- **Versions**: All - -#### 0xF5 - GetFileSettings -- **Parameters**: FileNo (1 byte) [Source: protocols.h, line 364] -- **Response**: File type + settings structure -- **Versions**: All - -### Data Manipulation Commands - -#### 0xBD - ReadData -- **Parameters**: [Source: protocols.h, line 367] - - FileNo (1 byte) - - Offset (3 bytes, LSB first) - - Length (3 bytes, LSB first) -- **Response**: Data + status -- **Versions**: All - -#### 0x3D - WriteData -- **Parameters**: [Source: protocols.h, line 368] - - FileNo (1 byte) - - Offset (3 bytes) - - Length (3 bytes) - - Data (variable) -- **Versions**: All - -#### 0x6C - GetValue -- **Parameters**: FileNo (1 byte) [Source: protocols.h, line 369] -- **Response**: Value (4 bytes) -- **Versions**: All - -#### 0x0C - Credit -- **Parameters**: [Source: protocols.h, line 370] - - FileNo (1 byte) - - Amount (4 bytes) -- **Versions**: All - -#### 0xDC - Debit -- **Parameters**: Same as Credit [Source: protocols.h, line 371] -- **Versions**: All - -#### 0x1C - LimitedCredit -- **Parameters**: Same as Credit [Source: protocols.h, line 372] -- **Versions**: All -- **Note**: Only if LimitedCreditEnabled - -#### 0x3B - WriteRecord -- **Parameters**: [Source: protocols.h, line 373] - - FileNo (1 byte) - - Offset (3 bytes) - - Length (3 bytes) - - Data (variable) -- **Versions**: All - -#### 0xBB - ReadRecords -- **Parameters**: [Source: protocols.h, line 374] - - FileNo (1 byte) - - Offset (3 bytes): Record number - - Length (3 bytes): Number of records -- **Versions**: All - -#### 0xEB - ClearRecordFile -- **Parameters**: FileNo (1 byte) [Source: protocols.h, line 375] -- **Versions**: All - -#### 0xC7 - CommitTransaction -- **Parameters**: Option byte (optional, 1 byte) [Source: MF2DLHX0.pdf, AN12343.pdf] -- **Versions**: All -- **Purpose**: Commit all pending changes -- **Note**: With option 0x01, returns TMC and TMV for TMAC verification - -#### 0xC8 - CommitReaderID -- **Parameters**: ReaderID (16 bytes) [Source: MF2DLHX0.pdf, Section 10.3] -- **Versions**: EV2, EV3, Light -- **Purpose**: Set reader-specific identifier for Transaction MAC generation -- **Authentication**: Depends on TMAC file ReadWrite access rights: - - 0x0-0x4: Authentication with specified key required - - 0xE: Free access allowed - - 0xF: CommitReaderID disabled -- **Communication**: Requires MACed or Encrypted mode -- **Response**: - - When authenticated: EncTMRI (16 bytes) = E_TM(SesTMENCKey, TMRIPrev) - - When not authenticated: No data, only status code -- **Notes**: - - EncTMRI uses AES CBC with zero IV for encryption - - TMRIPrev tracks previous transaction's ReaderID for chain verification - - TMRIPrev only updated on CommitTransaction if authenticated - - Used with TMAC file type (0x05) for offline transaction verification - -#### 0xA7 - AbortTransaction -- **Parameters**: None [Source: protocols.h, line 377] -- **Versions**: All -- **Purpose**: Rollback pending changes - -### Configuration Commands - -#### 0x5F - ChangeFileSettings -- **Parameters**: [Source: protocols.h, line 365] - - FileNo (1 byte) - - CommSettings (1 byte) - - AccessRights (2 bytes) -- **Versions**: All - -#### 0x54 - ChangeKeySettings -- **Parameters**: KeySettings (1 byte) [Source: protocols.h, line 351] -- **Versions**: All - -#### 0xC4 - ChangeKey -- **Parameters**: [Source: protocols.h, line 352] - - KeyNo (1 byte) - - New key data (encrypted) -- **Versions**: All - -### Information Commands - -#### 0x60 - GetVersion -- **Parameters**: None [Source: protocols.h, line 349] -- **Response**: Version info structure (28 bytes) -- **Versions**: All - -#### 0x51 - GetCardUID -- **Parameters**: None [Source: protocols.h, line 389] -- **Response**: UID (7 bytes) -- **Versions**: EV1+ -- **Authentication**: Required - -#### 0x61 - GetFileCounters -- **Parameters**: FileNo (1 byte) [Source: protocols.h, line 390] -- **Response**: Counters for SDM -- **Versions**: EV2+ - -#### 0x6E - GetFreeMemory -- **Parameters**: None [Source: AN11004.pdf] -- **Response**: Free memory (3 bytes) -- **Versions**: All - -### ISO Wrapped Commands - -#### 0xAD - ISOReadBinary -- **Parameters**: ISO 7816-4 wrapped ReadData [Source: protocols.h, line 378] -- **Versions**: EV1+ - -#### 0xAB - ISOAppendRecord -- **Parameters**: ISO 7816-4 wrapped WriteRecord [Source: protocols.h, line 380] -- **Versions**: EV1+ - -#### 0xA2 - ISOReadRecords -- **Parameters**: ISO 7816-4 wrapped ReadRecords [Source: protocols.h, line 379] -- **Versions**: EV1+ - -#### 0xA0 - ISOSelectFile -- **Parameters**: ISO 7816-4 file selection [Source: protocols.h, line 382] -- **Versions**: EV1+ - -#### 0x3A - ISOUpdateBinary -- **Parameters**: ISO 7816-4 wrapped WriteData [Source: protocols.h, line 383] -- **Versions**: EV1+ - -### Special Commands - -#### 0xAF - Additional Frame -- **Purpose**: Continue previous command [Source: protocols.h, line 342] -- **Parameters**: Additional data -- **Versions**: All - -#### 0x00 - ISO Wrapping -- **Purpose**: ISO 7816-4 command wrapping [Source: protocols.h, line 341] -- **Versions**: EV1+ - -### Transaction/Security Commands (EV2/EV3) - -#### 0xC9 - InitializeKeySet -- **Parameters**: KeySetNo + KeySetSettings [Source: protocols.h, line 385] -- **Versions**: EV2+ - -#### 0xCE - FinalizeKeySet -- **Parameters**: KeySetNo + KeyVersion [Source: protocols.h, line 386] -- **Versions**: EV2+ - -#### 0xCF - RollKeySet -- **Parameters**: KeySetNo [Source: protocols.h, line 387] -- **Versions**: EV2+ - -#### 0xF6 - GetDelegatedInfo -- **Parameters**: DAMSlotNo [Source: protocols.h, line 391] -- **Versions**: EV2+ - -#### 0xFA - TransactionMAC -- **Parameters**: Transaction data [Source: various sources] -- **Versions**: EV2+ -- **Purpose**: Generate offline verification MAC - -### Status Codes - -#### Success Codes -- **0x00**: OPERATION_OK [Source: protocols.h, line 393] -- **0x0C**: NO_CHANGES [Source: protocols.h, line 394] - -#### Error Codes -- **0x0E**: OUT_OF_MEMORY [Source: protocols.h, line 395] -- **0x1C**: ILLEGAL_COMMAND_CODE [Source: protocols.h, line 396] -- **0x1E**: INTEGRITY_ERROR [Source: protocols.h, line 397] -- **0x40**: NO_SUCH_KEY [Source: protocols.h, line 398] -- **0x7E**: LENGTH_ERROR [Source: protocols.h, line 399] -- **0x9D**: PERMISSION_DENIED [Source: protocols.h, line 400] -- **0x9E**: PARAMETER_ERROR [Source: protocols.h, line 401] -- **0xA0**: APPLICATION_NOT_FOUND [Source: protocols.h, line 402] -- **0xA1**: APPL_INTEGRITY_ERROR [Source: protocols.h, line 403] -- **0xAE**: AUTHENTICATION_ERROR [Source: protocols.h, line 404] -- **0xAF**: ADDITIONAL_FRAME [Source: protocols.h, line 405] -- **0xBE**: BOUNDARY_ERROR [Source: protocols.h, line 406] -- **0xC1**: COMMAND_ABORTED [Source: protocols.h, line 408] -- **0xCA**: PICC_INTEGRITY_ERROR [Source: protocols.h, line 407] -- **0xCD**: PICC_DISABLED_ERROR [Source: protocols.h, line 409] -- **0xCE**: COUNT_ERROR [Source: protocols.h, line 410] -- **0xDE**: DUPLICATE_ERROR [Source: protocols.h, line 411] -- **0xEE**: EEPROM_ERROR [Source: protocols.h, line 412] -- **0xF0**: FILE_NOT_FOUND [Source: protocols.h, line 413] -- **0xF1**: FILE_INTEGRITY_ERROR [Source: protocols.h, line 414] - ---- - -## Authentication Deep Dive - -### DES/3DES Authentication Protocol - -#### Phase 1: Initial Authentication Request -``` -PCD → PICC: 90 0A 00 00 01 [KeyNo] 00 - └─ Authenticate command (0x0A) -``` -[Source: DESFire DES authentication D40-DES authentification.pdf, line 7] - -#### Phase 2: PICC Responds with Encrypted RndB -``` -PICC → PCD: [Ek(RndB)] 91 AF - └─ 8 bytes encrypted RndB -``` -[Source: DESFire DES authentication D40-DES authentification.pdf, line 9] - -#### Phase 3: PCD Prepares Response -1. Decrypt RndB using key -2. Generate RndA (8 bytes) -3. Rotate RndB left by 1 byte -4. Concatenate: RndA || RndB_rotated -5. Encrypt with CBC mode, IV from previous response - -[Source: DESFire DES authentication D40-DES authentification.pdf, lines 23-39] - -#### Phase 4: Send Encrypted Challenge -``` -PCD → PICC: 90 AF 00 00 10 [Ek(RndA || RndB_rot)] 00 -``` -[Source: DESFire DES authentication D40-DES authentification.pdf, line 41] - -#### Phase 5: Verify PICC Response -``` -PICC → PCD: [Ek(RndA_rot)] 91 00 -``` -PCD decrypts and verifies rotated RndA matches -[Source: DESFire DES authentication D40-DES authentification.pdf, lines 43-56] - -### AES Authentication Protocol - -Similar flow but with 16-byte blocks: -1. Uses command 0xAA instead of 0x0A -2. RndA and RndB are 16 bytes each -3. AES-128 in CBC mode -4. Session key derivation differs - -[Source: DESFire.py, lines 79-144] - -### EV2 Authentication Protocol - -#### EV2First Authentication -1. **Capability Exchange**: - ``` - PCD → PICC: 71 [KeyNo] [Len] [PCDcap2] - PICC → PCD: [TI] [PDcap2] [PCDcap2] AF - ``` - [Source: desfire_ev3_authentication.pdf, lines 18-25] - -2. **Complete Authentication**: - - Similar challenge-response - - Generates Transaction Identifier (TI) - - Establishes secure channel - -#### EV2NonFirst Authentication -``` -PCD → PICC: 77 [KeyNo] -``` -Requires previous EV2First in same session -[Source: desfire_ev3_authentication.pdf, lines 27-30] - -### Session Key Generation - -#### DES Session Key (8 bytes) -``` -SessionKey = RndA[0:4] || RndB[0:4] -``` -[Source: DESFire DES authentication D40-DES authentification.pdf, lines 66-71] - -#### 2K3DES Session Key (16 bytes) -``` -SessionKey = RndA[0:4] || RndB[0:4] || RndA[4:8] || RndB[4:8] -``` -[Source: DESFire.py, lines 135-136] - -#### 3K3DES Session Key (24 bytes) -``` -SessionKey = RndA[0:4] || RndB[0:4] || - RndA[6:10] || RndB[6:10] || - RndA[12:16] || RndB[12:16] -``` -[Source: DESFire.py, lines 138-141] - -#### AES Session Key (16 bytes) -``` -SessionKey = RndA[0:4] || RndB[0:4] || RndA[12:16] || RndB[12:16] -``` -[Source: DESFire.py, lines 143-144] - -### CMAC Calculation - -#### Subkey Generation -```python -# Generate L by encrypting zero block -L = AES_Encrypt(Key, 0x00000000000000000000000000000000) - -# Generate K1 -K1 = L << 1 -if MSB(L) == 1: - K1 = K1 XOR Rb # Rb = 0x87 for AES - -# Generate K2 -K2 = K1 << 1 -if MSB(K1) == 1: - K2 = K2 XOR Rb -``` -[Source: mifare_desfire_crypto.c, lines 95-123] - -#### CMAC Calculation -1. Pad message if needed (0x80 0x00...) -2. XOR last block with K1 (complete) or K2 (incomplete) -3. CBC encrypt all blocks -4. Final block is CMAC - -[Source: mifare_desfire_crypto.c, lines 126-151] - ---- - -## File Types and Operations - -### Standard Data File Operations - -#### CreateStdDataFile -``` -Command: CD [FileNo] [CommSettings] [AccessRights] [FileSize] -Example: CD 01 00 00 00 00 10 00 00 // File 01, plain, free access, 16 bytes -``` -[Source: protocols.h, line 357] - -#### ReadData -``` -Command: BD [FileNo] [Offset-3B] [Length-3B] -Example: BD 01 00 00 00 10 00 00 // Read 16 bytes from offset 0 -``` -[Source: protocols.h, line 367] - -#### WriteData -``` -Command: 3D [FileNo] [Offset-3B] [Length-3B] [Data] -Example: 3D 01 00 00 00 04 00 00 DE AD BE EF // Write 4 bytes -``` -[Source: protocols.h, line 368] - -### Value File Operations - -#### CreateValueFile -``` -Command: CC [FileNo] [CommSettings] [AccessRights] [LowerLimit-4B] [UpperLimit-4B] [Value-4B] [LimitedCreditEnable] -Example: CC 02 00 00 00 00 00 00 00 E8 03 00 00 00 00 00 00 01 - // Value file 02, limits 0-1000, initial 0, limited credit enabled -``` -[Source: protocols.h, line 359] - -#### Credit Operation -``` -Command: 0C [FileNo] [Amount-4B] -Example: 0C 02 64 00 00 00 // Credit 100 to file 02 -``` -[Source: protocols.h, line 370] - -#### Debit Operation -``` -Command: DC [FileNo] [Amount-4B] -Example: DC 02 0A 00 00 00 // Debit 10 from file 02 -``` -[Source: protocols.h, line 371] - -### Record File Operations - -#### CreateLinearRecordFile -``` -Command: C1 [FileNo] [CommSettings] [AccessRights] [RecordSize-3B] [MaxRecords-3B] -Example: C1 03 00 00 00 20 00 00 0A 00 00 - // Linear record file 03, 32-byte records, max 10 records -``` -[Source: protocols.h, line 360] - -#### WriteRecord -``` -Command: 3B [FileNo] [Offset-3B] [Length-3B] [Data] -Example: 3B 03 00 00 00 20 00 00 [32 bytes of data] -``` -[Source: protocols.h, line 373] - -#### ReadRecords -``` -Command: BB [FileNo] [RecordNo-3B] [NumRecords-3B] -Example: BB 03 00 00 00 05 00 00 // Read 5 records starting from record 0 -``` -[Source: protocols.h, line 374] - -### Transaction Mechanism - -For Backup and Value files: -1. Perform operations (Write, Credit, Debit) -2. Changes are pending until: - - **CommitTransaction (0xC7)**: Apply changes - - **AbortTransaction (0xA7)**: Discard changes - -[Source: protocols.h, lines 376-377] - ---- - -## Cryptographic Implementation - -### Key Diversification (AN10922) - -#### Algorithm Steps -1. **Prepare Diversification Input**: - ``` - M = [Constant] || [UID] || [AID] || [SystemIdentifier] - ``` - Constants: - - 0x01: AES-128 - - 0x21: 2K3DES - - 0x31: 3K3DES - [Source: mifare_key_deriver.c, lines 10-17] - -2. **Calculate Diversified Key**: - ``` - DiversifiedKey = CMAC(MasterKey, M) - ``` - [Source: mifare_key_deriver.c, lines 101-177] - -### Secure Messaging - -#### MACed Communication Mode (0x01) -- Commands sent in plain -- Response includes 8-byte CMAC -- CMAC covers: Response Data + Status Code -[Source: various implementation files] - -#### Full Enciphered Mode (0x03) -- Command data encrypted after authentication -- Response data encrypted -- Both include CMAC for integrity -- Uses session keys and IVs - -### IV Generation - -#### EV1 IV Handling -- Initial IV: All zeros -- Subsequent: Last block of previous crypto operation - -#### EV2/EV3 IV Generation -``` -IV = EncryptedFlag || TI || .pdfCtr || ZeroPadding -``` -- TI: Transaction Identifier (4 bytes) -- .pdfCtr: Command Counter (2 bytes) -[Source: hf_desfire.c and crypto implementations] - ---- - -## Communication Modes - -### Plain Communication (0x00) -- No encryption or MACing -- Suitable for public data -- Fastest performance -- No authentication required for read - -### MACed Communication (0x01) -- Data transmitted in plain -- 8-byte CMAC appended to responses -- Integrity protection -- Requires authentication - -### Fully Enciphered Communication (0x03) -- All data encrypted -- CMAC for integrity -- Maximum security -- Requires authentication -- Performance impact - ---- - -## Error Codes Reference - -### Common Error Scenarios - -#### 0x9D - PERMISSION_DENIED -- Attempting operation without required authentication -- Wrong key authenticated for operation -- Access rights don't permit operation - -#### 0xAE - AUTHENTICATION_ERROR -- Authentication protocol failure -- Wrong key or key version -- Corrupted authentication data - -#### 0x7E - LENGTH_ERROR -- Command parameters wrong length -- Data exceeds file size -- Frame size exceeded - -#### 0xA0 - APPLICATION_NOT_FOUND -- Invalid AID selected -- Application was deleted -- Card not properly initialized - ---- - -## Implementation Examples - -### Example 1: Creating an Application with AES Keys -```python -# Create application 0x000001 with 5 AES keys -aid = [0x01, 0x00, 0x00] -key_settings = 0x0F # All keys changeable, free directory -num_keys = 0x85 # 5 keys, AES encryption (bit 7 set) - -command = [0xCA] + aid + [key_settings, num_keys] -response = send_command(command) -``` - -### Example 2: Secure File Write with MACing -```python -# Authenticate first -authenticate_aes(key_no=0x01, key=master_key) - -# Create MACed file -create_std_file(file_no=0x01, - comm_settings=0x01, # MACed - access_rights=0x0000, # Free access - file_size=32) - -# Write data (will be MACed automatically) -write_data(file_no=0x01, offset=0, data=b"Secure data here") -``` - -### Example 3: Value File Transaction -```python -# Create value file with limits -create_value_file(file_no=0x02, - lower_limit=0, - upper_limit=10000, - initial_value=1000, - limited_credit=True) - -# Perform operations -credit(file_no=0x02, amount=500) # Balance: 1500 -debit(file_no=0x02, amount=200) # Balance: 1300 - -# Commit all changes -commit_transaction() -``` - ---- - -## Bibliography - -### Primary Sources (Datasheets) -1. **AN11004**: MIFARE DESFire EV1 Features and Hints -2. **AN12696**: MIFARE DESFire EV2 Features and Hints -3. **AN12753**: MIFARE DESFire EV3 Features and Hints -4. **MF3D_H_X3_SDS**: MIFARE DESFire EV3 Secure Data Sheet -5. **PLT-05618**: MIFARE DESFire EV3 Application Note -6. **[0011955][v1.0]**: ST Pegasus DESFire Light v1.0 Specification -7. **AN-315**: Understanding Protege MIFARE DESFire Credentials - -### Implementation Sources -1. **protocols.h**: Proxmark3 DESFire protocol definitions -2. **hf_desfire.c**: Proxmark3 DESFire implementation -3. **DESFire.py**: Python DESFire implementation -4. **DESFire_DEF.py**: Python DESFire constants -5. **mifare_desfire.c**: libfreefare C implementation -6. **mifare_desfire_crypto.c**: libfreefare crypto implementation -7. **DesfireEv3.java**: Android DESFire EV3 implementation - -### Documentation Sources -1. **desfire_ev3_authentication.pdf**: EV3 authentication details -2. **desfire_ev3_file_operations.pdf**: EV3 file operation examples -3. **DESFire DES authentication D40-DES authentification.pdf**: Legacy auth flow -4. **DESFire TDES decryption SEND mode.pdf**: TDES implementation details -5. **auth1d_d40.pdf**: D40 authentication documentation - -### Additional References -1. ISO/IEC 14443-4: Proximity cards protocol -2. ISO/IEC 7816-4: Smart card APDU specification -3. Common Criteria EAL5+ certification documents -4. NIST SP 800-38B: CMAC specification -5. AN10922: NXP Key Diversification - ---- - -*End of The Unofficial DESFire Bible* - -*Compiled from official documentation and implementation sources* -*All information includes inline citations for verification* -*Last updated: Based on DESFire EV3 specifications* \ No newline at end of file diff --git a/docker/archlinux/docker_conf.inc b/docker/archlinux/docker_conf.inc deleted file mode 100644 index 0f069bf63..000000000 --- a/docker/archlinux/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-arch:1.0 diff --git a/docker/ubuntu-24.10/Dockerfile b/docker/debian-11-bullseye/Dockerfile similarity index 75% rename from docker/ubuntu-24.10/Dockerfile rename to docker/debian-11-bullseye/Dockerfile index 89abd2516..c32710dda 100644 --- a/docker/ubuntu-24.10/Dockerfile +++ b/docker/debian-11-bullseye/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:24.10 +FROM debian:bullseye-slim ENV LANG=C ENV DEBIAN_FRONTEND=noninteractive @@ -9,15 +9,15 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends git ca-certificates build-essential cmake pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev libssl-dev libgd-dev sudo && \ apt-get clean -RUN apt-get install -y --no-install-recommends python3-minimal python3-pip python3-venv && \ - apt-get clean +RUN apt-get install -y python3-minimal && \ + apt-get install -y python3-pip && \ + apt-get clean && \ + python3 -m pip install ansicolors sslcrypto RUN apt-get install -y opencl-dev && \ apt-get clean -# Create rrg user => there is already a ubuntu user = 1000 that we need to move away -RUN usermod -u 999 ubuntu -RUN groupmod -g 999 ubuntu +# Create rrg user RUN useradd -ms /bin/bash rrg RUN passwd -d rrg ARG UART_GID diff --git a/docker/debian-11-bullseye/README.md b/docker/debian-11-bullseye/README.md new file mode 100644 index 000000000..3a7775b7c --- /dev/null +++ b/docker/debian-11-bullseye/README.md @@ -0,0 +1,21 @@ +# Notes on run_tests.sh script +This script runs a bunch of different builds with make and cmake together +with the different combos of RDV4, GENERIC, BTADDON combos. + +If all tests OK, the script will finish with PASS. + + +# Notes to run tests +The script is to be run in proxmark root folder inside the docker env. + +``` +docker/debian-11-bullseye/run_tests.sh; +``` + +Or if you want to run single test, + +``` +sudo apt update +make clean; make -j +tools/pm3_tests.sh --long +``` diff --git a/docker/debian-11-bullseye/run_tests.sh b/docker/debian-11-bullseye/run_tests.sh new file mode 100755 index 000000000..9c7128942 --- /dev/null +++ b/docker/debian-11-bullseye/run_tests.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Iceman 2022 +# +# This script is to be run from proxmark root folder inside the docker env +# docker/debian-11-bullseye/run_tests.sh; + +sudo apt update && sudo apt upgrade -y +tools/release_tests.sh diff --git a/docker/debian-12-bookworm-arm64/docker_conf.inc b/docker/debian-12-bookworm-arm64/docker_conf.inc deleted file mode 100644 index 753d89ff3..000000000 --- a/docker/debian-12-bookworm-arm64/docker_conf.inc +++ /dev/null @@ -1,2 +0,0 @@ -DOCKER_IMAGE=pm3-debian-bookworm-arm64:1.0 -DOCKER_PLATFORM="--platform linux/arm64" diff --git a/docker/debian-12-bookworm-armhf/docker_conf.inc b/docker/debian-12-bookworm-armhf/docker_conf.inc deleted file mode 100644 index 3c9160afc..000000000 --- a/docker/debian-12-bookworm-armhf/docker_conf.inc +++ /dev/null @@ -1,2 +0,0 @@ -DOCKER_IMAGE=pm3-debian-bookworm-armhf:1.0 -DOCKER_PLATFORM="--platform linux/arm/v7" diff --git a/docker/debian-12-bookworm/docker_conf.inc b/docker/debian-12-bookworm/docker_conf.inc deleted file mode 100644 index 6d979b6cc..000000000 --- a/docker/debian-12-bookworm/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-debian-bookworm:1.0 diff --git a/docker/debian-13-trixie/docker_conf.inc b/docker/debian-13-trixie/docker_conf.inc deleted file mode 100644 index 481a94e9f..000000000 --- a/docker/debian-13-trixie/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-debian-trixie:1.0 diff --git a/docker/fedora-41/Dockerfile b/docker/fedora-36/Dockerfile similarity index 98% rename from docker/fedora-41/Dockerfile rename to docker/fedora-36/Dockerfile index 959922831..1041b799a 100644 --- a/docker/fedora-41/Dockerfile +++ b/docker/fedora-36/Dockerfile @@ -1,4 +1,4 @@ -FROM fedora:41 +FROM fedora:36 ENV LANG=C # qt5-qtbase-devel skipped diff --git a/docker/fedora-43/README.md b/docker/fedora-36/README.md similarity index 84% rename from docker/fedora-43/README.md rename to docker/fedora-36/README.md index b88fb1457..6648fb28d 100644 --- a/docker/fedora-43/README.md +++ b/docker/fedora-36/README.md @@ -4,14 +4,15 @@ with the different combos of RDV4, GENERIC, BTADDON combos. If all tests OK, the script will finish with PASS. + # Notes to run tests The script is to be run in proxmark root folder inside the docker env. ``` -docker/fedora-43/run_tests.sh; -``` +docker/fedora-36/run_tests.sh; +``` -Or if you want to run single test, +Or if you want to run single test, ``` sudo yum -y update diff --git a/docker/fedora-41/run_tests.sh b/docker/fedora-36/run_tests.sh similarity index 82% rename from docker/fedora-41/run_tests.sh rename to docker/fedora-36/run_tests.sh index b97b86afe..05cdb7da8 100755 --- a/docker/fedora-41/run_tests.sh +++ b/docker/fedora-36/run_tests.sh @@ -2,7 +2,7 @@ # Iceman 2022 # # This script is to be run from proxmark root folder inside the docker env -# docker/fedora-41/run_tests.sh; +# docker/fedora-36/run_tests.sh; sudo yum -y update tools/release_tests.sh diff --git a/docker/fedora-42/Dockerfile b/docker/fedora-37/Dockerfile similarity index 98% rename from docker/fedora-42/Dockerfile rename to docker/fedora-37/Dockerfile index 181ac02a3..bb3118fd2 100644 --- a/docker/fedora-42/Dockerfile +++ b/docker/fedora-37/Dockerfile @@ -1,4 +1,4 @@ -FROM fedora:42 +FROM fedora:37 ENV LANG=C # qt5-qtbase-devel skipped diff --git a/docker/fedora-42/README.md b/docker/fedora-37/README.md similarity index 93% rename from docker/fedora-42/README.md rename to docker/fedora-37/README.md index 25e0264e3..79c88e040 100644 --- a/docker/fedora-42/README.md +++ b/docker/fedora-37/README.md @@ -8,7 +8,7 @@ If all tests OK, the script will finish with PASS. The script is to be run in proxmark root folder inside the docker env. ``` -docker/fedora-42/run_tests.sh; +docker/fedora-37/run_tests.sh; ``` Or if you want to run single test, diff --git a/docker/fedora-37/run_tests.sh b/docker/fedora-37/run_tests.sh new file mode 100755 index 000000000..05cdb7da8 --- /dev/null +++ b/docker/fedora-37/run_tests.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Iceman 2022 +# +# This script is to be run from proxmark root folder inside the docker env +# docker/fedora-36/run_tests.sh; + +sudo yum -y update +tools/release_tests.sh diff --git a/docker/fedora-41/README.md b/docker/fedora-41/README.md deleted file mode 100644 index 2c1d28040..000000000 --- a/docker/fedora-41/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# Notes on run_tests.sh script -This script runs a bunch of different builds with make and cmake together -with the different combos of RDV4, GENERIC, BTADDON combos. - -If all tests OK, the script will finish with PASS. - -# Notes to run tests -The script is to be run in proxmark root folder inside the docker env. - -``` -docker/fedora-41/run_tests.sh; -``` - -Or if you want to run single test, - -``` -sudo yum -y update -make clean; make -j -tools/pm3_tests.sh --long -``` diff --git a/docker/fedora-41/docker_conf.inc b/docker/fedora-41/docker_conf.inc deleted file mode 100644 index eb8968f1c..000000000 --- a/docker/fedora-41/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-fedora-41:1.0 diff --git a/docker/fedora-42/docker_conf.inc b/docker/fedora-42/docker_conf.inc deleted file mode 100644 index 002e2ec26..000000000 --- a/docker/fedora-42/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-fedora-42:1.0 diff --git a/docker/fedora-42/run_tests.sh b/docker/fedora-42/run_tests.sh deleted file mode 100755 index f94642645..000000000 --- a/docker/fedora-42/run_tests.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -# Iceman 2022 -# -# This script is to be run from proxmark root folder inside the docker env -# docker/fedora-42/run_tests.sh; - -sudo yum -y update -python3 -m venv /tmp/venv -source /tmp/venv/bin/activate -python3 -m pip install --use-pep517 pyaes -python3 -m pip install ansicolors sslcrypto -tools/release_tests.sh -deactivate diff --git a/docker/fedora-43/Dockerfile b/docker/fedora-43/Dockerfile deleted file mode 100644 index 1c8affc51..000000000 --- a/docker/fedora-43/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM fedora:rawhide - -ENV LANG=C -# qt5-qtbase-devel skipped -RUN dnf install -y passwd sudo git make gcc gcc-c++ arm-none-eabi-gcc-cs arm-none-eabi-newlib readline-devel bzip2-devel lz4-devel bluez-libs-devel python3-devel openssl-devel gd-devel libatomic findutils - -RUN yum -y update -RUN yum -y install cmake python-pip -RUN python3 -m pip install ansicolors sslcrypto - -RUN yum -y install mesa-libOpenCL ocl-icd-devel - -# Create rrg user -RUN useradd -ms /bin/bash rrg -RUN passwd -d rrg -ARG UART_GID -# dialout group may already exist on another numeric ID than on host -RUN if [ -n "${UART_GID}" ]; then \ - groupadd -g ${UART_GID} mydialout || true; \ - usermod -aG ${UART_GID} rrg; \ - fi -RUN printf 'rrg ALL=(ALL) ALL\n' | tee -a /etc/sudoers - -USER rrg -WORKDIR "/home/rrg" - -CMD ["/bin/bash"] diff --git a/docker/fedora-43/docker_conf.inc b/docker/fedora-43/docker_conf.inc deleted file mode 100644 index 9f1c4c08c..000000000 --- a/docker/fedora-43/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-fedora-43:1.0 diff --git a/docker/fedora-43/run_tests.sh b/docker/fedora-43/run_tests.sh deleted file mode 100755 index f73e5fb62..000000000 --- a/docker/fedora-43/run_tests.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -# Iceman 2022 -# -# This script is to be run from proxmark root folder inside the docker env -# docker/fedora-43/run_tests.sh; - -sudo yum -y update -python3 -m venv /tmp/venv -source /tmp/venv/bin/activate -python3 -m pip install --use-pep517 pyaes -python3 -m pip install ansicolors sslcrypto -tools/release_tests.sh -deactivate diff --git a/docker/homebrew/docker_conf.inc b/docker/homebrew/docker_conf.inc deleted file mode 100644 index b53f34184..000000000 --- a/docker/homebrew/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-brew:1.0 diff --git a/docker/kali/docker_conf.inc b/docker/kali/docker_conf.inc deleted file mode 100644 index 62f57876b..000000000 --- a/docker/kali/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-kali:1.0 diff --git a/docker/opensuse-leap/docker_conf.inc b/docker/opensuse-leap/docker_conf.inc deleted file mode 100644 index ac8d995f5..000000000 --- a/docker/opensuse-leap/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-suse-leap:1.0 diff --git a/docker/opensuse-tumbleweed/Dockerfile b/docker/opensuse-tumbleweed/Dockerfile index 7bc086b29..a0faf50c2 100644 --- a/docker/opensuse-tumbleweed/Dockerfile +++ b/docker/opensuse-tumbleweed/Dockerfile @@ -2,7 +2,7 @@ FROM opensuse/tumbleweed ENV LANG=C # libqt5-qtbase-devel skipped -RUN zypper --non-interactive install --no-recommends shadow sudo git patterns-devel-base-devel_basis gcc-c++ readline-devel libbz2-devel liblz4-devel bluez-devel python3-devel libopenssl-devel cross-arm-none-gcc14 cross-arm-none-newlib-devel gd-devel +RUN zypper --non-interactive install --no-recommends shadow sudo git patterns-devel-base-devel_basis gcc-c++ readline-devel libbz2-devel liblz4-devel bluez-devel python3-devel libopenssl-devel cross-arm-none-gcc12 cross-arm-none-newlib-devel gd-devel #RUN zypper addrepo https://download.opensuse.org/repositories/home:wkazubski/openSUSE_Tumbleweed/home:wkazubski.repo && \ # zypper --gpg-auto-import-keys refresh && \ diff --git a/docker/opensuse-tumbleweed/docker_conf.inc b/docker/opensuse-tumbleweed/docker_conf.inc deleted file mode 100644 index e6cc65b22..000000000 --- a/docker/opensuse-tumbleweed/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-suse-tumbleweed:1.0 diff --git a/docker/parrot-core-latest/docker_conf.inc b/docker/parrot-core-latest/docker_conf.inc deleted file mode 100644 index 6410849ad..000000000 --- a/docker/parrot-core-latest/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-parrotsec-core-latest:1.0 diff --git a/docker/ubuntu-18.04/Dockerfile b/docker/ubuntu-18.04/Dockerfile new file mode 100644 index 000000000..f287c344e --- /dev/null +++ b/docker/ubuntu-18.04/Dockerfile @@ -0,0 +1,35 @@ +FROM ubuntu:18.04 + +ENV LANG=C +ENV DEBIAN_FRONTEND=noninteractive +# qtbase5-dev skipped +# python3 skipped, not yet searchable with pkg-config python3 +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends git ca-certificates build-essential cmake pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev liblz4-dev libbluetooth-dev libssl-dev libgd-dev sudo && \ + apt-get clean + +RUN apt-get install -y python3-minimal && \ + apt-get install -y python3-pip && \ + apt-get clean && \ + python3 -m pip install ansicolors sslcrypto + +RUN apt-get install -y opencl-dev && \ + apt-get clean + +# Create rrg user +RUN useradd -ms /bin/bash rrg +RUN passwd -d rrg +ARG UART_GID +# dialout group may already exist on another numeric ID than on host +RUN if [ -n "${UART_GID}" ]; then \ + groupadd -g ${UART_GID} mydialout || true; \ + usermod -aG ${UART_GID} rrg; \ + fi +RUN printf 'rrg ALL=(ALL) ALL\n' | tee -a /etc/sudoers + +USER rrg +WORKDIR "/home/rrg" + +CMD ["/bin/bash"] diff --git a/docker/ubuntu-24.04/README.md b/docker/ubuntu-18.04/README.md similarity index 92% rename from docker/ubuntu-24.04/README.md rename to docker/ubuntu-18.04/README.md index 24a2605a1..6cc3b9ef2 100644 --- a/docker/ubuntu-24.04/README.md +++ b/docker/ubuntu-18.04/README.md @@ -9,10 +9,11 @@ If all tests OK, the script will finish with PASS. The script is to be run in proxmark root folder inside the docker env. ``` -docker/ubuntu-24.04/run_tests.sh; +docker/ubuntu-18.04/run_tests.sh; ``` Or if you want to run single test, + ``` sudo apt update make clean; make -j diff --git a/docker/ubuntu-18.04/run_tests.sh b/docker/ubuntu-18.04/run_tests.sh new file mode 100755 index 000000000..1efdbc060 --- /dev/null +++ b/docker/ubuntu-18.04/run_tests.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Iceman 2022 +# +# This script is to be run from proxmark root folder inside the docker env +# docker/ubuntu-18.04/run_tests.sh; + +sudo apt update && sudo apt upgrade -y +tools/release_tests.sh diff --git a/docker/ubuntu-24.04/Dockerfile b/docker/ubuntu-20.04/Dockerfile similarity index 75% rename from docker/ubuntu-24.04/Dockerfile rename to docker/ubuntu-20.04/Dockerfile index 0932f8e4f..c02544234 100644 --- a/docker/ubuntu-24.04/Dockerfile +++ b/docker/ubuntu-20.04/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:24.04 +FROM ubuntu:20.04 ENV LANG=C ENV DEBIAN_FRONTEND=noninteractive @@ -9,15 +9,15 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends git ca-certificates build-essential cmake pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev libssl-dev libgd-dev sudo && \ apt-get clean -RUN apt-get install -y --no-install-recommends python3-minimal python3-pip python3-venv && \ - apt-get clean +RUN apt-get install -y python3-minimal && \ + apt-get install -y python3-pip && \ + apt-get clean && \ + python3 -m pip install ansicolors sslcrypto RUN apt-get install -y opencl-dev && \ apt-get clean -# Create rrg user => there is already a ubuntu user = 1000 that we need to move away -RUN usermod -u 999 ubuntu -RUN groupmod -g 999 ubuntu +# Create rrg user RUN useradd -ms /bin/bash rrg RUN passwd -d rrg ARG UART_GID diff --git a/docker/ubuntu-25.04/README.md b/docker/ubuntu-20.04/README.md similarity index 92% rename from docker/ubuntu-25.04/README.md rename to docker/ubuntu-20.04/README.md index ae44d231a..4c432eff1 100644 --- a/docker/ubuntu-25.04/README.md +++ b/docker/ubuntu-20.04/README.md @@ -9,10 +9,11 @@ If all tests OK, the script will finish with PASS. The script is to be run in proxmark root folder inside the docker env. ``` -docker/ubuntu-25.04/run_tests.sh; +docker/ubuntu-20.04/run_tests.sh; ``` Or if you want to run single test, + ``` sudo apt update make clean; make -j diff --git a/docker/ubuntu-20.04/run_tests.sh b/docker/ubuntu-20.04/run_tests.sh new file mode 100755 index 000000000..aa98bc327 --- /dev/null +++ b/docker/ubuntu-20.04/run_tests.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Iceman 2022 +# +# This script is to be run from proxmark root folder inside the docker env +# docker/ubuntu-20.04/run_tests.sh; + +sudo apt update && sudo apt upgrade -y +tools/release_tests.sh diff --git a/docker/ubuntu-25.04/Dockerfile b/docker/ubuntu-22.04/Dockerfile similarity index 75% rename from docker/ubuntu-25.04/Dockerfile rename to docker/ubuntu-22.04/Dockerfile index 245d7343a..d182d893e 100644 --- a/docker/ubuntu-25.04/Dockerfile +++ b/docker/ubuntu-22.04/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:25.04 +FROM ubuntu:22.04 ENV LANG=C ENV DEBIAN_FRONTEND=noninteractive @@ -9,15 +9,15 @@ RUN apt-get update && \ apt-get install -y --no-install-recommends git ca-certificates build-essential cmake pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev libssl-dev libgd-dev sudo && \ apt-get clean -RUN apt-get install -y --no-install-recommends python3-minimal python3-pip python3-venv && \ - apt-get clean +RUN apt-get install -y python3-minimal && \ + apt-get install -y python3-pip && \ + apt-get clean && \ + python3 -m pip install ansicolors sslcrypto RUN apt-get install -y opencl-dev && \ apt-get clean -# Create rrg user => there is already a ubuntu user = 1000 that we need to move away -RUN usermod -u 999 ubuntu -RUN groupmod -g 999 ubuntu +# Create rrg user RUN useradd -ms /bin/bash rrg RUN passwd -d rrg ARG UART_GID diff --git a/docker/ubuntu-24.10/README.md b/docker/ubuntu-22.04/README.md similarity index 92% rename from docker/ubuntu-24.10/README.md rename to docker/ubuntu-22.04/README.md index 53a3a2107..93d4462ad 100644 --- a/docker/ubuntu-24.10/README.md +++ b/docker/ubuntu-22.04/README.md @@ -9,7 +9,7 @@ If all tests OK, the script will finish with PASS. The script is to be run in proxmark root folder inside the docker env. ``` -docker/ubuntu-24.10/run_tests.sh; +docker/ubuntu-22.04/run_tests.sh; ``` Or if you want to run single test, diff --git a/docker/ubuntu-22.04/run_tests.sh b/docker/ubuntu-22.04/run_tests.sh new file mode 100755 index 000000000..4f8ce55ea --- /dev/null +++ b/docker/ubuntu-22.04/run_tests.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +# Iceman 2022 +# +# This script is to be run from proxmark root folder inside the docker env +# docker/ubuntu-22.04/run_tests.sh; + +sudo apt update && sudo apt upgrade -y +tools/release_tests.sh diff --git a/docker/ubuntu-24.04/docker_conf.inc b/docker/ubuntu-24.04/docker_conf.inc deleted file mode 100644 index 38c37aff7..000000000 --- a/docker/ubuntu-24.04/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-ubuntu-24.04:1.0 diff --git a/docker/ubuntu-24.04/run_tests.sh b/docker/ubuntu-24.04/run_tests.sh deleted file mode 100755 index f77f54baf..000000000 --- a/docker/ubuntu-24.04/run_tests.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -# Iceman 2022 -# -# This script is to be run from proxmark root folder inside the docker env -# docker/ubuntu-24.04/run_tests.sh; - -sudo apt update && sudo apt upgrade -y -python3 -m venv /tmp/venv -source /tmp/venv/bin/activate -python3 -m pip install --use-pep517 pyaes -python3 -m pip install ansicolors sslcrypto -tools/release_tests.sh -deactivate diff --git a/docker/ubuntu-24.10/docker_conf.inc b/docker/ubuntu-24.10/docker_conf.inc deleted file mode 100644 index a6c548152..000000000 --- a/docker/ubuntu-24.10/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-ubuntu-24.10:1.0 diff --git a/docker/ubuntu-24.10/run_tests.sh b/docker/ubuntu-24.10/run_tests.sh deleted file mode 100755 index 3dbfac71d..000000000 --- a/docker/ubuntu-24.10/run_tests.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -# Iceman 2022 -# -# This script is to be run from proxmark root folder inside the docker env -# docker/ubuntu-24.10/run_tests.sh; - -sudo apt update && sudo apt upgrade -y -python3 -m venv /tmp/venv -source /tmp/venv/bin/activate -python3 -m pip install --use-pep517 pyaes -python3 -m pip install ansicolors sslcrypto -tools/release_tests.sh -deactivate diff --git a/docker/ubuntu-25.04/docker_conf.inc b/docker/ubuntu-25.04/docker_conf.inc deleted file mode 100644 index 3b0c2e0e3..000000000 --- a/docker/ubuntu-25.04/docker_conf.inc +++ /dev/null @@ -1 +0,0 @@ -DOCKER_IMAGE=pm3-ubuntu-25.04:1.0 diff --git a/docker/ubuntu-25.04/run_tests.sh b/docker/ubuntu-25.04/run_tests.sh deleted file mode 100755 index d65d78809..000000000 --- a/docker/ubuntu-25.04/run_tests.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/env bash -# Iceman 2022 -# -# This script is to be run from proxmark root folder inside the docker env -# docker/ubuntu-25.04/run_tests.sh; - -sudo apt update && sudo apt upgrade -y -python3 -m venv /tmp/venv -source /tmp/venv/bin/activate -python3 -m pip install --use-pep517 pyaes -python3 -m pip install ansicolors sslcrypto -tools/release_tests.sh -deactivate diff --git a/fpga/Makefile b/fpga/Makefile index 2411ab7e8..769185260 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -45,7 +45,7 @@ XST_OPTS_AREA += -fsm_style bram XST_OPTS_AREA += -fsm_encoding compact # par specific option (set determistic seed) -PAR_OPTIONS = -t 2 +PAR_OPTIONS = -t 1 # Types of selective module compilation: # WITH_LF Enables selection of LF modules (and disables all HF) @@ -74,11 +74,7 @@ TARGET3_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF3 WITH_HF5 WITH_HF_15 WITH_ # RDV40/Generic - Enable all HF modules except ISO14443 TARGET4_OPTIONS = -define \{WITH_HF0 WITH_HF1 WITH_HF3 WITH_HF4 WITH_HF5\} # ICOPYX -TARGET5_OPTIONS = $(TARGET1_OPTIONS) -TARGET6_OPTIONS = $(TARGET1_OPTIONS) -TARGET7_OPTIONS = $(TARGET1_OPTIONS) -TARGET8_OPTIONS = $(TARGET1_OPTIONS) -TARGET9_OPTIONS = $(TARGET1_OPTIONS) +TARGET5_OPTIONS = -define {PM3ICOPYX} -rtlview Yes # Here we list the target names TARGET1_NAME = fpga_pm3_lf @@ -86,10 +82,6 @@ TARGET2_NAME = fpga_pm3_hf TARGET3_NAME = fpga_pm3_hf_15 TARGET4_NAME = fpga_pm3_felica TARGET5_NAME = fpga_icopyx_hf -TARGET6_NAME = fpga_pm3_ult_lf -TARGET7_NAME = fpga_pm3_ult_hf -TARGET8_NAME = fpga_pm3_ult_hf_15 -TARGET9_NAME = fpga_pm3_ult_felica # Targets can be compiled for different FPGA flavours TARGET1_FPGA = xc2s30-5-vq100 @@ -97,10 +89,6 @@ TARGET2_FPGA = $(TARGET1_FPGA) TARGET3_FPGA = $(TARGET1_FPGA) TARGET4_FPGA = $(TARGET1_FPGA) TARGET5_FPGA = xc3s100e-4-vq100 -TARGET6_FPGA = xc2s50-5-tq144 -TARGET7_FPGA = $(TARGET6_FPGA) -TARGET8_FPGA = $(TARGET6_FPGA) -TARGET9_FPGA = $(TARGET6_FPGA) # Assemble the final XST options for each target TARGET1_XST_OPTS = $(XST_OPTS_BASE) $(XST_OPTS_AREA) -p $(TARGET1_FPGA) -ofn $(TARGET1_NAME) $(TARGET1_OPTIONS) @@ -108,10 +96,6 @@ TARGET2_XST_OPTS = $(XST_OPTS_BASE) $(XST_OPTS_AREA) -p $(TARGET2_FPGA) -ofn $( TARGET3_XST_OPTS = $(XST_OPTS_BASE) $(XST_OPTS_AREA) -p $(TARGET3_FPGA) -ofn $(TARGET3_NAME) $(TARGET3_OPTIONS) TARGET4_XST_OPTS = $(XST_OPTS_BASE) $(XST_OPTS_AREA) -p $(TARGET4_FPGA) -ofn $(TARGET4_NAME) $(TARGET4_OPTIONS) TARGET5_XST_OPTS = $(XST_OPTS_BASE) $(XST_OPTS_SPEED) -p $(TARGET5_FPGA) -ofn $(TARGET5_NAME) $(TARGET5_OPTIONS) -TARGET6_XST_OPTS = $(XST_OPTS_BASE) $(XST_OPTS_SPEED) -p $(TARGET6_FPGA) -ofn $(TARGET6_NAME) $(TARGET6_OPTIONS) -TARGET7_XST_OPTS = $(XST_OPTS_BASE) $(XST_OPTS_SPEED) -p $(TARGET7_FPGA) -ofn $(TARGET7_NAME) $(TARGET7_OPTIONS) -TARGET8_XST_OPTS = $(XST_OPTS_BASE) $(XST_OPTS_SPEED) -p $(TARGET8_FPGA) -ofn $(TARGET8_NAME) $(TARGET8_OPTIONS) -TARGET9_XST_OPTS = $(XST_OPTS_BASE) $(XST_OPTS_SPEED) -p $(TARGET9_FPGA) -ofn $(TARGET9_NAME) $(TARGET9_OPTIONS) # these files are common for all targets TARGET_COMMON_FILES = define.v @@ -137,18 +121,14 @@ TARGET2_FILES = $(TARGET1_FILES) TARGET3_FILES = $(TARGET1_FILES) TARGET4_FILES = $(TARGET1_FILES) TARGET5_FILES = $(TARGET_COMMON_FILES) mux2_onein.v mux2_oneout.v fpga_icopyx_hf.v fpga_icopyx_lf.v fpga_icopyx_top.v -TARGET6_FILES = $(TARGET1_FILES) -TARGET7_FILES = $(TARGET1_FILES) -TARGET8_FILES = $(TARGET1_FILES) -TARGET9_FILES = $(TARGET1_FILES) # List of all valid target FPGA images to build -TARGETS = $(TARGET1_NAME) $(TARGET2_NAME) $(TARGET3_NAME) $(TARGET4_NAME) $(TARGET5_NAME) $(TARGET6_NAME) $(TARGET7_NAME) $(TARGET8_NAME) $(TARGET9_NAME) +TARGETS = $(TARGET1_NAME) $(TARGET2_NAME) $(TARGET3_NAME) $(TARGET4_NAME) $(TARGET5_NAME) # Verbosity type for ISE tools ise|xflow|silent VERBOSITY = -intstyle silent # Echo (Q=) or not echo (Q=@) build commands to the terminal -Q= +Q=@ # Pass the custom variables to the lower make rules $(TARGET1_NAME).bit: TARGET_FPGA = $(TARGET1_FPGA) @@ -171,22 +151,6 @@ $(TARGET5_NAME).bit: TARGET_FPGA = $(TARGET5_FPGA) $(TARGET5_NAME).bit: TARGET_FILES = $(TARGET5_FILES) $(TARGET5_NAME).bit: TARGET_XST_OPTS = $(TARGET5_XST_OPTS) -$(TARGET6_NAME).bit: TARGET_FPGA = $(TARGET6_FPGA) -$(TARGET6_NAME).bit: TARGET_FILES = $(TARGET6_FILES) -$(TARGET6_NAME).bit: TARGET_XST_OPTS = $(TARGET6_XST_OPTS) - -$(TARGET7_NAME).bit: TARGET_FPGA = $(TARGET7_FPGA) -$(TARGET7_NAME).bit: TARGET_FILES = $(TARGET7_FILES) -$(TARGET7_NAME).bit: TARGET_XST_OPTS = $(TARGET7_XST_OPTS) - -$(TARGET8_NAME).bit: TARGET_FPGA = $(TARGET8_FPGA) -$(TARGET8_NAME).bit: TARGET_FILES = $(TARGET8_FILES) -$(TARGET8_NAME).bit: TARGET_XST_OPTS = $(TARGET8_XST_OPTS) - -$(TARGET9_NAME).bit: TARGET_FPGA = $(TARGET9_FPGA) -$(TARGET9_NAME).bit: TARGET_FILES = $(TARGET9_FILES) -$(TARGET9_NAME).bit: TARGET_XST_OPTS = $(TARGET9_XST_OPTS) - $(TARGETS): $(Q)$(MKDIR) $(PREFIX)build_$@ $(Q)$(MAKE) -C $(PREFIX)build_$@ -f ../Makefile $(notdir $@).bit @@ -224,7 +188,7 @@ work: $(Q)$(RM) $@ $*.drc $*.rbt $(info [=] BITGEN $@) $(Q)$(XILINX_TOOLS_PREFIX)bitgen $(VERBOSITY) -w $* $@ - $(Q)python3 ../strip_date_time_from_binary.py $@ || true + python3 ../strip_date_time_from_binary.py $@ || true $(Q)$(CP) $@ .. # Build all targets diff --git a/fpga/fpga_icopyx_hf.bit b/fpga/fpga_icopyx_hf.bit index 6198fa35f..a7824dd74 100644 Binary files a/fpga/fpga_icopyx_hf.bit and b/fpga/fpga_icopyx_hf.bit differ diff --git a/fpga/fpga_pm3_felica.bit b/fpga/fpga_pm3_felica.bit index cbc31b0e3..386638478 100644 Binary files a/fpga/fpga_pm3_felica.bit and b/fpga/fpga_pm3_felica.bit differ diff --git a/fpga/fpga_pm3_hf.bit b/fpga/fpga_pm3_hf.bit index 9713f7406..1c159a612 100644 Binary files a/fpga/fpga_pm3_hf.bit and b/fpga/fpga_pm3_hf.bit differ diff --git a/fpga/fpga_pm3_hf_15.bit b/fpga/fpga_pm3_hf_15.bit index b532b622a..055615e71 100644 Binary files a/fpga/fpga_pm3_hf_15.bit and b/fpga/fpga_pm3_hf_15.bit differ diff --git a/fpga/fpga_pm3_lf.bit b/fpga/fpga_pm3_lf.bit index 50c8c6c1f..79485cac1 100644 Binary files a/fpga/fpga_pm3_lf.bit and b/fpga/fpga_pm3_lf.bit differ diff --git a/fpga/fpga_pm3_top.v b/fpga/fpga_pm3_top.v index a183d34d2..a36cd3e6d 100644 --- a/fpga/fpga_pm3_top.v +++ b/fpga/fpga_pm3_top.v @@ -28,8 +28,6 @@ //`define PM3GENERIC // iCopy-X with XC3S100E //`define PM3ICOPYX -// Proxmark3 Ultimate with XC2S50 -//`define PM3ULTIMATE // Pass desired defines to compiler to enable required modules // WITH_LF enables Low Frequency mode when defined else HF is enabled diff --git a/fpga/fpga_pm3_ult_felica.bit b/fpga/fpga_pm3_ult_felica.bit deleted file mode 100644 index 31bff7c05..000000000 Binary files a/fpga/fpga_pm3_ult_felica.bit and /dev/null differ diff --git a/fpga/fpga_pm3_ult_hf.bit b/fpga/fpga_pm3_ult_hf.bit deleted file mode 100644 index 4effbe83a..000000000 Binary files a/fpga/fpga_pm3_ult_hf.bit and /dev/null differ diff --git a/fpga/fpga_pm3_ult_hf_15.bit b/fpga/fpga_pm3_ult_hf_15.bit deleted file mode 100644 index deff00d73..000000000 Binary files a/fpga/fpga_pm3_ult_hf_15.bit and /dev/null differ diff --git a/fpga/fpga_pm3_ult_lf.bit b/fpga/fpga_pm3_ult_lf.bit deleted file mode 100644 index 74fbb661b..000000000 Binary files a/fpga/fpga_pm3_ult_lf.bit and /dev/null differ diff --git a/include/ansi.h b/include/ansi.h index b791741f5..20815bc03 100644 --- a/include/ansi.h +++ b/include/ansi.h @@ -21,12 +21,6 @@ #define AEND "\x1b[0m" -#define _CLEAR_ "\x1b[2J" -#define _CLEAR_SCROLLBACK_ "\x1b[3J" -#define _TOP_ "\x1b[1;1f" - -#define _CLR_ "\x1b[0K" - #define _BLACK_(s) "\x1b[30m" s AEND #define _RED_(s) "\x1b[31m" s AEND #define _GREEN_(s) "\x1b[32m" s AEND @@ -63,6 +57,10 @@ #define _BACK_BRIGHT_CYAN_(s) "\x1b[46;1m" s AEND #define _BACK_BRIGHT_WHITE_(s) "\x1b[47;1m" s AEND +#define _CLEAR_ "\x1b[2J" +#define _CLEAR_SCROLLBACK_ "\x1b[3J" +#define _TOP_ "\x1b[1;1f" + #if defined(HAVE_READLINE) // https://wiki.hackzine.org/development/misc/readline-color-prompt.html // Applications may indicate that the prompt contains diff --git a/include/em4x70.h b/include/em4x70.h index 23cb2d8ef..597dbfe26 100644 --- a/include/em4x70.h +++ b/include/em4x70.h @@ -38,7 +38,7 @@ /// The only requirement is that this structure remain /// smaller than the NG buffer size (256 bytes). typedef struct { - bool _ignored__was_use_parity; // BUGBUG: Ignored, but kept for structure size / offset compatibility + bool parity; // Used for writing address uint8_t address; diff --git a/include/iclass_cmd.h b/include/iclass_cmd.h index 259c8cc2f..e4761584f 100644 --- a/include/iclass_cmd.h +++ b/include/iclass_cmd.h @@ -24,8 +24,7 @@ //----------------------------------------------------------------------------- // iCLASS / PICOPASS //----------------------------------------------------------------------------- -#define PICOPASS_BLOCK_SIZE ( 8 ) -#define PICOPASS_MAX_BYTES ( 4096 ) // # 32k bits = 4096 bytes +#define PICOPASS_BLOCK_SIZE 8 // iCLASS reader flags #define FLAG_ICLASS_READER_INIT 0x01 @@ -49,8 +48,7 @@ #define ICLASS_SIM_MODE_FULL 3 #define ICLASS_SIM_MODE_READER_ATTACK_KEYROLL 4 #define ICLASS_SIM_MODE_EXIT_AFTER_MAC 5 // note: device internal only -#define ICLASS_SIM_MODE_FULL_GLITCH 6 -#define ICLASS_SIM_MODE_FULL_GLITCH_KEY 7 +#define ICLASS_SIM_MODE_CONFIG_CARD 6 // iCLASS auth request data structure @@ -89,17 +87,6 @@ typedef struct { uint8_t mac[4]; } PACKED iclass_writeblock_req_t; -// iCLASS tearoff block request data structure -typedef struct { - iclass_auth_req_t req; - uint8_t data[8]; - uint8_t mac[4]; - int tear_start; - int tear_end; - int increment; - int tear_loop; -} PACKED iclass_tearblock_req_t; - // iCLASS write block request data structure typedef struct { iclass_auth_req_t req; @@ -126,8 +113,6 @@ typedef struct { uint8_t nfa[8]; bool debug; bool test; - bool fast; - bool short_delay; } PACKED iclass_recover_req_t; typedef struct iclass_premac { @@ -198,12 +183,5 @@ typedef struct { } header; } PACKED iclass_card_select_resp_t; -typedef struct { - union { - picopass_hdr_t hdr; - picopass_ns_hdr_t ns_hdr; - } header; - uint8_t data[PICOPASS_MAX_BYTES]; -} PACKED iclass_tag_t; #endif // _ICLASS_H_ diff --git a/include/iso15.h b/include/iso15.h index 9c39db3a3..0d19c1756 100644 --- a/include/iso15.h +++ b/include/iso15.h @@ -20,14 +20,10 @@ #define _ISO15_H_ #include "common.h" - -#define ISO15693_UID_LENGTH 8 -#define ISO15693_ATQB_LENGTH 7 - typedef struct { - uint8_t uid[ISO15693_UID_LENGTH]; + uint8_t uid[8]; uint8_t uidlen; - uint8_t atqb[ISO15693_ATQB_LENGTH]; + uint8_t atqb[7]; uint8_t chipid; uint8_t cid; } PACKED iso15_card_select_t; diff --git a/include/iso18.h b/include/iso18.h index da37819da..377f864d0 100644 --- a/include/iso18.h +++ b/include/iso18.h @@ -124,31 +124,4 @@ typedef struct { uint8_t PMi[8]; } PACKED felica_auth2_response_t; -typedef struct { - felica_frame_response_t frame_response; - uint8_t payload[4]; -} PACKED felica_service_dump_response_t; - -typedef struct { - uint8_t command_code[1]; - uint8_t IDm[8]; - uint8_t number_of_service[1]; - uint8_t service_code_list[2]; - uint8_t number_of_block[1]; -} PACKED felica_write_request_haeder_t; - -typedef struct { - uint8_t command_code[1]; - uint8_t IDm[8]; - uint8_t number_of_service[1]; - uint8_t service_code_list[2]; - uint8_t number_of_block[1]; -} PACKED felica_read_request_haeder_t; - - -typedef struct { - uint8_t random_challenge[16]; - uint8_t session_key[16]; -} PACKED felica_auth_context_t; - #endif // _ISO18_H_ diff --git a/include/mifare.h b/include/mifare.h index 4754a6f20..69665cdc8 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -108,6 +108,23 @@ typedef enum ISO14A_COMMAND { ISO14A_CRYPTO1MODE = (1 << 14) } iso14a_command_t; +// Defines a frame that will be used in a polling sequence +// ECP Frames are up to (7 + 16) bytes long, 24 bytes should cover future and other cases +typedef struct { + uint8_t frame[24]; + uint8_t frame_length; + uint8_t last_byte_bits; + uint16_t extra_delay; +} PACKED iso14a_polling_frame_t; + +// Defines polling sequence configuration +// 6 would be enough for 4 magsafe, 1 wupa, 1 ecp, +typedef struct { + iso14a_polling_frame_t frames[6]; + uint8_t frame_count; + uint16_t extra_timeout; +} PACKED iso14a_polling_parameters_t; + typedef struct { uint8_t *response; uint8_t *modulation; diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index e5d8d2474..89600e8e4 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -131,27 +131,6 @@ typedef struct { bool verbose; } PACKED sample_config; - -// Defines a frame that will be used in a polling sequence -// Polling loop annotations are up to 20 bytes long, 24 bytes should cover future and other cases -typedef struct { - uint8_t frame[24]; - // negative values can be used to carry special info - int8_t frame_length; - uint8_t last_byte_bits; - uint16_t extra_delay; -} PACKED iso14a_polling_frame_t; - - -// Defines polling sequence configuration -typedef struct { - // 6 would be enough for 4 magsafe, 1 wupa, 1 pla, - iso14a_polling_frame_t frames[6]; - int8_t frame_count; - uint16_t extra_timeout; -} PACKED iso14a_polling_parameters_t; - - // A struct used to send hf14a-configs over USB typedef struct { int8_t forceanticol; // 0:auto 1:force executing anticol 2:force skipping anticol @@ -159,9 +138,7 @@ typedef struct { int8_t forcecl2; // 0:auto 1:force executing CL2 2:force skipping CL2 int8_t forcecl3; // 0:auto 1:force executing CL3 2:force skipping CL3 int8_t forcerats; // 0:auto 1:force executing RATS 2:force skipping RATS - int8_t magsafe; // 0:disabled 1:enabled - iso14a_polling_frame_t polling_loop_annotation; // Polling loop annotation -} PACKED hf14a_config_t; +} PACKED hf14a_config; // Tracelog Header struct typedef struct { @@ -349,12 +326,6 @@ typedef struct { uint8_t key[6]; } PACKED mfc_eload_t; -typedef struct { - bool use_flashmem; - uint16_t keycount; - uint8_t keys[]; -} PACKED mfulc_keys_t; - typedef struct { uint8_t status; uint8_t CSN[8]; @@ -674,7 +645,6 @@ typedef struct { #define CMD_HF_ICLASS_RESTORE 0x039B #define CMD_HF_ICLASS_CREDIT_EPURSE 0x039C #define CMD_HF_ICLASS_RECOVER 0x039D -#define CMD_HF_ICLASS_TEARBL 0x039E // For ISO1092 / FeliCa @@ -872,7 +842,7 @@ typedef struct { #define FLAG_NR_AR_ATTACK 0x0400 // support nested authentication attack #define FLAG_NESTED_AUTH_ATTACK 0x0800 -#define FLAG_MF_ALLOW_OOB_AUTH 0x1000 + #define MODE_SIM_CSN 0 #define MODE_EXIT_AFTER_MAC 1 @@ -964,8 +934,6 @@ typedef struct { // Cryptographic error client/pm3: cryptographic operation failed #define PM3_ECRYPTO -29 -// File error client: error related to file does not exist in search paths -#define PM3_ENOFILE -30 // No data client/pm3: no data available, no host frame available (not really an error) #define PM3_ENODATA -98 // Quit program client: reserved, order to quit the program diff --git a/include/pmflash.h b/include/pmflash.h index 7e601c2bc..7820ad4e2 100644 --- a/include/pmflash.h +++ b/include/pmflash.h @@ -79,13 +79,6 @@ #define MF_KEYS_FILE "dict_mf.bin" #define MF_KEY_LENGTH 6 -// MIFARE Ultralight-C keys stored in spiffs -#define MFULC_KEYS_FILE "dict_mfulc.bin" -#define MFULC_KEY_LENGTH (16) - -// MIFARE Ultralight-AES keys stored in spiffs -#define MFULAES_KEYS_FILE "dict_mfulaes.bin" -#define MFULAES_KEY_LENGTH (16) // RDV40, validation structure to help identifying that client/firmware is talking with RDV40 typedef struct { uint8_t magic[4]; diff --git a/include/usart_defs.h b/include/usart_defs.h index 84d6ff17c..501f66464 100644 --- a/include/usart_defs.h +++ b/include/usart_defs.h @@ -16,9 +16,8 @@ #ifndef __USART_DEFS_H #define __USART_DEFS_H -#ifndef USART_BAUD_RATE +//#define USART_BAUD_RATE 9600 #define USART_BAUD_RATE 115200 -#endif // BT HC-06 physical layer runs at 128kbps // so it's possible to gain a little bit by using 230400 // with some risk to overflow its internal buffers: diff --git a/pm3 b/pm3 index 5122fe536..80aad83d8 100755 --- a/pm3 +++ b/pm3 @@ -136,15 +136,11 @@ function get_pm3_list_Windows { PM3LIST=() # Normal SERIAL PORTS (COM) - for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.PNPDeviceID -like '*VID_9AC4&PID_4B8F*' -or \$_.PNPDeviceID -like '*VID_2D2D&PID_504D*'} | Select -expandproperty DeviceID" 2>/dev/null); do - - _comport=$DEV - + for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_9AC4&PID_4B8F%' Or PNPDeviceID LIKE '%VID_2D2D&PID_504D%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do + DEV=${DEV/ */} #prevent soft bricking when using pm3-flash-all on an outdated bootloader if [ $(basename -- "$0") = "pm3-flash-all" ]; then - - line=$($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object {\$_.DeviceID -eq '$_comport'} | Select -expandproperty PNPDeviceID" 2>/dev/null); - + line=$(wmic /locale:ms_409 path Win32_SerialPort Where "DeviceID='$DEV'" Get PNPDeviceID 2>/dev/null | awk -b '/^USB/{print $1}'); if [[ ! $line =~ ^"USB\VID_9AC4&PID_4B8F\ICEMAN" ]]; then echo -e "\033[0;31m[!] Using pm3-flash-all on an oudated bootloader, use pm3-flash-bootrom first!" exit 1 @@ -158,8 +154,8 @@ function get_pm3_list_Windows { #BT direct SERIAL PORTS (COM) if $FINDBTRFCOMM; then - - for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_PnPEntity | Where-Object Caption -like 'Standard Serial over Bluetooth link (COM*' | Select Name" 2>/dev/null); do + for DEV in $(wmic /locale:ms_409 path Win32_PnPEntity Where "Caption LIKE '%Bluetooth%(COM%'" Get Name 2> /dev/null | awk -b 'match($0,/(COM[0-9]+)/,m){print m[1]}'); do + DEV=${DEV/ */} PM3LIST+=("$DEV") if [ ${#PM3LIST[*]} -ge "$N" ]; then return @@ -169,8 +165,8 @@ function get_pm3_list_Windows { #white BT dongle SERIAL PORTS (COM) if $FINDBTDONGLE; then - - for DEV in $($PSHEXE -command "Get-CimInstance -ClassName Win32_serialport | Where-Object PNPDeviceID -like '*VID_10C4&PID_EA60*' | Select -expandproperty DeviceID" 2>/dev/null); do + for DEV in $(wmic /locale:ms_409 path Win32_SerialPort Where "PNPDeviceID LIKE '%VID_10C4&PID_EA60%'" Get DeviceID 2>/dev/null | awk -b '/^COM/{print $1}'); do + DEV=${DEV/ */} PM3LIST+=("$DEV") if [ ${#PM3LIST[*]} -ge "$N" ]; then return @@ -501,21 +497,6 @@ if [ "$HOSTOS" = "LINUX" ]; then elif [ "$HOSTOS" = "DARWIN" ]; then GETPM3LIST=get_pm3_list_macOS elif [[ "$HOSTOS" =~ MINGW(32|64)_NT* ]]; then - - # First try finding it using the PATH environment variable - PSHEXE=$(command -v powershell.exe 2>/dev/null) - - # If it fails (such as if WSLENV is not set), try using the default installation path - if [ -z "$PSHEXE" ]; then - PSHEXE=/cygdrive/c/WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe - fi - - # Finally test if PowerShell is working - if ! "$PSHEXE" exit >/dev/null 2>&1; then - echo >&2 "[!!] Cannot run powershell.exe in your MINGW environment" - exit 1 - fi - GETPM3LIST=get_pm3_list_Windows else echo >&2 "[!!] Host OS not recognized, abort: $HOSTOS" diff --git a/tools/build_all_firmwares.sh b/tools/build_all_firmwares.sh index 3023fe741..2740d7150 100755 --- a/tools/build_all_firmwares.sh +++ b/tools/build_all_firmwares.sh @@ -32,11 +32,11 @@ mv bootrom/obj/bootrom.elf "$DEST/PM3BOOTROM.elf" # cf armsrc/Standalone/Makefile.hal STANDALONE_MODES=(LF_SKELETON) STANDALONE_MODES+=(LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE) -STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_ST25_TEAROFF HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG) +STANDALONE_MODES+=(HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_15SIM HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG) STANDALONE_MODES+=(DANKARMULTI) STANDALONE_MODES_REQ_BT=(HF_CARDHOPPER HF_REBLAY) STANDALONE_MODES_REQ_SMARTCARD=() -STANDALONE_MODES_REQ_FLASH=(LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_LEGICSIM HF_MFCSIM HF_ST25_TEAROFF) +STANDALONE_MODES_REQ_FLASH=(LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_LEGICSIM HF_MFCSIM) # PM3GENERIC 256kb, no flash, need to skip some parts to reduce size diff --git a/tools/cryptorf/sma.cpp b/tools/cryptorf/sma.cpp index 9a019114e..4b7b2d15a 100644 --- a/tools/cryptorf/sma.cpp +++ b/tools/cryptorf/sma.cpp @@ -706,10 +706,6 @@ void combine_valid_left_right_states(vector *plcstates, vector *prcs printf("but only " _GREEN_("%zu")" were valid!\n", pgc_candidates->size()); } -#if defined(__cplusplus) -} -#endif - int main(int argc, const char *argv[]) { size_t pos; crypto_state_t ostate; @@ -859,3 +855,7 @@ int main(int argc, const char *argv[]) { } return 0; } + +#if defined(__cplusplus) +} +#endif diff --git a/tools/cryptorf/sma_multi.cpp b/tools/cryptorf/sma_multi.cpp index 10a15e7b1..9bd95e1fa 100644 --- a/tools/cryptorf/sma_multi.cpp +++ b/tools/cryptorf/sma_multi.cpp @@ -802,10 +802,6 @@ static void ice_compare( return; } -#if defined(__cplusplus) -} -#endif - int main(int argc, const char *argv[]) { size_t pos; crypto_state_t ostate; @@ -973,3 +969,7 @@ int main(int argc, const char *argv[]) { } return 0; } + +#if defined(__cplusplus) +} +#endif diff --git a/tools/fpga_compress/Makefile b/tools/fpga_compress/Makefile index 3e34619e8..324860995 100644 --- a/tools/fpga_compress/Makefile +++ b/tools/fpga_compress/Makefile @@ -1,8 +1,6 @@ ifeq ($(PLTNAME),) -include ../../Makefile.platform -include ../../.Makefile.options.cache -# Default platform if no platform specified - PLATFORM?=PM3RDV4 ifneq ($(PLATFORM), $(CACHED_PLATFORM)) $(error platform definitions have been changed, please "make clean" at the root of the project) endif @@ -13,8 +11,6 @@ MYINCLUDES = -I../../common_fpga MYCFLAGS = -std=c99 -D_ISOC99_SOURCE ifeq ($(PLATFORM),PM3ICOPYX) MYDEFS = -DXC3 -else ifeq ($(PLATFORM),PM3ULTIMATE) - MYDEFS = -DXC2S50 else MYDEFS = endif diff --git a/tools/mfc/card_only/staticnested_0nt.c b/tools/mfc/card_only/staticnested_0nt.c index 088b4aadc..44bfaaf11 100644 --- a/tools/mfc/card_only/staticnested_0nt.c +++ b/tools/mfc/card_only/staticnested_0nt.c @@ -272,9 +272,7 @@ static uint64_t **unpredictable_nested(NtpKs1List *pNKL, uint32_t keyCounts[]) { pthread_cond_wait(&status_cond, &status_mutex); activeThreads = 0; for (int i = 0; i < NUM_THREADS; i++) { - if (thread_status[i]) { - activeThreads++; - } + if (thread_status[i]) activeThreads++; } } diff --git a/tools/mfc/card_only/staticnested_2nt.c b/tools/mfc/card_only/staticnested_2nt.c index a013a0d97..4409d94e2 100644 --- a/tools/mfc/card_only/staticnested_2nt.c +++ b/tools/mfc/card_only/staticnested_2nt.c @@ -175,19 +175,19 @@ static void pm3_staticnested(uint32_t uid, uint32_t nt1, uint32_t ks1, uint32_t } } -static int usage(const char *prog) { +static int usage(void) { printf("\n"); printf("\nProgram tries to recover keys from static encrypted nested MFC cards\n"); printf("using two different implementations, Chameleon Ultra (CU) and Proxmark3.\n"); printf("It uses the nonce, keystream sent from pm3 device to client.\n"); printf("ie: NOT the CU data which is data in the trace.\n"); printf("\n"); - printf("syntax: %s \n\n", prog); + printf("syntax: staticnested \n\n"); printf("samples:\n"); printf("\n"); - printf(" %s 461dce03 7eef3586 ffb02eda 322bc14d ffc875ca\n", prog); - printf(" %s 461dce03 7eef3586 1fb6b496 322bc14d 1f4eebdd\n", prog); - printf(" %s 461dce03 7eef3586 7fa28c7e 322bc14d 7f62b3d6\n", prog); + printf(" ./staticnested 461dce03 7eef3586 ffb02eda 322bc14d ffc875ca\n"); + printf(" ./staticnested 461dce03 7eef3586 1fb6b496 322bc14d 1f4eebdd\n"); + printf(" ./staticnested 461dce03 7eef3586 7fa28c7e 322bc14d 7f62b3d6\n"); printf("\n"); return 1; } @@ -196,7 +196,7 @@ int main(int argc, char *const argv[]) { printf("\nMIFARE Classic static nested key recovery\n\n"); - if (argc < 5) return usage(argv[0]); + if (argc < 5) return usage(); printf("Init...\n"); NtpKs1 *pNK = calloc(2, sizeof(NtpKs1)); diff --git a/tools/mfc/card_only/staticnested_2x1nt_rf08s.c b/tools/mfc/card_only/staticnested_2x1nt_rf08s.c index 0a83c10fd..10f31875d 100644 --- a/tools/mfc/card_only/staticnested_2x1nt_rf08s.c +++ b/tools/mfc/card_only/staticnested_2x1nt_rf08s.c @@ -31,23 +31,11 @@ static void init_lfsr16_table(void) { } // static uint16_t next_lfsr16(uint16_t nonce) { -// uint16_t i = i_lfsr16[nonce]; -// if (i == 0xffff) { -// i = 1; -// } else { -// i++; -// } -// return s_lfsr16[i]; +// return s_lfsr16[(i_lfsr16[nonce]+1) % 65535]; // } static uint16_t prev_lfsr16(uint16_t nonce) { - uint16_t i = i_lfsr16[nonce]; - if (i == 1) { - i = 0xffff; - } else { - i--; - } - return s_lfsr16[i]; + return s_lfsr16[(i_lfsr16[nonce] - 1) % 65535]; } static uint16_t compute_seednt16_nt32(uint32_t nt32, uint64_t key) { diff --git a/tools/mfc/card_only/staticnested_2x1nt_rf08s_1key.c b/tools/mfc/card_only/staticnested_2x1nt_rf08s_1key.c index 87b2f330d..66f0cecab 100644 --- a/tools/mfc/card_only/staticnested_2x1nt_rf08s_1key.c +++ b/tools/mfc/card_only/staticnested_2x1nt_rf08s_1key.c @@ -5,7 +5,7 @@ // * keyA and keyB are different for the targeted sector // // Strategy: -// * Use staticnested_2x1nt_rf08s to crack keyA +// * Use f08s_nested_known_collision to crack keyA // * If keyB not readable, find keyB in its dictionary based on the obscure relationship between keyA, keyB and their nT // // Doegox, 2024, cf https://eprint.iacr.org/2024/1275 for more info @@ -33,23 +33,11 @@ static void init_lfsr16_table(void) { } // static uint16_t next_lfsr16(uint16_t nonce) { -// uint16_t i = i_lfsr16[nonce]; -// if (i == 0xffff) { -// i = 1; -// } else { -// i++; -// } -// return s_lfsr16[i]; +// return s_lfsr16[(i_lfsr16[nonce]+1) % 65535]; // } static uint16_t prev_lfsr16(uint16_t nonce) { - uint16_t i = i_lfsr16[nonce]; - if (i == 1) { - i = 0xffff; - } else { - i--; - } - return s_lfsr16[i]; + return s_lfsr16[(i_lfsr16[nonce] - 1) % 65535]; } static uint16_t compute_seednt16_nt32(uint32_t nt32, uint64_t key) { @@ -89,7 +77,7 @@ int main(int argc, char *const argv[]) { if (argc != 4) { printf("Usage:\n %s keys___.dic\n" - " where dict file is produced by staticnested_1nt *for the same UID and same sector* as provided nt and key\n", + " where dict file is produced by rf08s_nested_known *for the same UID and same sector* as provided nt and key\n", argv[0]); return 1; } diff --git a/tools/mfd_aes_brute/Makefile b/tools/mfd_aes_brute/Makefile index 07330e077..6f8fa44a9 100644 --- a/tools/mfd_aes_brute/Makefile +++ b/tools/mfd_aes_brute/Makefile @@ -34,8 +34,8 @@ endif # OS X needs linking to openssl ifeq ($(USE_BREW),1) - MYCFLAGS += -I$(BREW_PREFIX)/opt/openssl@3/include -I$(BREW_PREFIX)/opt/openssl@3.5/include - MYLDFLAGS += -L$(BREW_PREFIX)/opt/openssl@3/lib -L$(BREW_PREFIX)/opt/openssl@3.5/lib + MYCFLAGS += -I$(BREW_PREFIX)/opt/openssl@3/include -I$(BREW_PREFIX)/opt/openssl@1.1/include + MYLDFLAGS += -L$(BREW_PREFIX)/opt/openssl@3/lib -L$(BREW_PREFIX)/opt/openssl@1.1/lib endif ifeq ($(USE_MACPORTS),1) diff --git a/tools/pm3_online_tests.sh b/tools/pm3_online_tests.sh deleted file mode 100755 index 998122f62..000000000 --- a/tools/pm3_online_tests.sh +++ /dev/null @@ -1,148 +0,0 @@ -#!/usr/bin/env bash - -# Online tests that require actual PM3 device connection -# This is used to make sure that the language for the functions is english instead of the system default language. -LANG=C - -PM3PATH="$(dirname "$0")/.." -cd "$PM3PATH" || exit 1 - -TESTALL=false -TESTDESFIREVALUE=false - -# https://medium.com/@Drew_Stokes/bash-argument-parsing-54f3b81a6a8f -PARAMS="" -while (( "$#" )); do - case "$1" in - -h|--help) - echo """ -Usage: $0 [--pm3bin /path/to/pm3] [desfire_value] - --pm3bin ...: Specify path to pm3 binary to test - desfire_value: Test DESFire value operations with card - You must specify a test target - no default 'all' for online tests -""" - exit 0 - ;; - --pm3bin) - if [ -n "$2" ] && [ ${2:0:1} != "-" ]; then - PM3BIN=$2 - shift 2 - else - echo "Error: Argument for $1 is missing" >&2 - exit 1 - fi - ;; - desfire_value) - TESTALL=false - TESTDESFIREVALUE=true - shift - ;; - -*|--*=) # unsupported flags - echo "Error: Unsupported flag $1" >&2 - exit 1 - ;; - *) # preserve positional arguments - PARAMS="$PARAMS $1" - shift - ;; - esac -done -# set positional arguments in their proper place -eval set -- "$PARAMS" - -C_RED='\033[0;31m' -C_GREEN='\033[0;32m' -C_YELLOW='\033[0;33m' -C_BLUE='\033[0;34m' -C_NC='\033[0m' # No Color -C_OK='\xe2\x9c\x94\xef\xb8\x8f' -C_FAIL='\xe2\x9d\x8c' - -# Check if file exists -function CheckFileExist() { - printf "%-40s" "$1 " - if [ -f "$2" ]; then - echo -e "[ ${C_GREEN}OK${C_NC} ] ${C_OK}" - return 0 - fi - if ls "$2" 1> /dev/null 2>&1; then - echo -e "[ ${C_GREEN}OK${C_NC} ] ${C_OK}" - return 0 - fi - echo -e "[ ${C_RED}FAIL${C_NC} ] ${C_FAIL}" - return 1 -} - -# Execute command and check result -function CheckExecute() { - printf "%-40s" "$1 " - - start=$(date +%s) - TIMEINFO="" - RES=$(eval "$2") - end=$(date +%s) - delta=$(expr $end - $start) - if [ $delta -gt 2 ]; then - TIMEINFO=" ($delta s)" - fi - if echo "$RES" | grep -E -q "$3"; then - echo -e "[ ${C_GREEN}OK${C_NC} ] ${C_OK} $TIMEINFO" - return 0 - fi - echo -e "[ ${C_RED}FAIL${C_NC} ] ${C_FAIL} $TIMEINFO" - echo "Execution trace:" - echo "$RES" - return 1 -} - -echo -e "${C_BLUE}Iceman Proxmark3 online test tool${C_NC}" -echo "" -echo "work directory: $(pwd)" - -if command -v git >/dev/null && git rev-parse --is-inside-work-tree >/dev/null 2>&1; then - echo -n "git branch: " - git describe --all - echo -n "git sha: " - git rev-parse HEAD - echo "" -fi - -# Check that user specified a test -if [ "$TESTDESFIREVALUE" = false ]; then - echo "Error: You must specify a test target. Use -h for help." - exit 1 -fi - -while true; do - # DESFire value tests - if $TESTDESFIREVALUE; then - echo -e "\n${C_BLUE}Testing DESFire card value operations${C_NC} ${PM3BIN:=./pm3}" - echo " PLACE A FACTORY DESFIRE CARD ON THE READER NOW" - if ! CheckFileExist "pm3 exists" "$PM3BIN"; then break; fi - - echo " Formatting card to clean state..." - if ! CheckExecute "format card" "$PM3BIN -c 'hf mfdes formatpicc'" "done"; then break; fi - - echo " Running value operation tests..." - if ! CheckExecute "card auth test" "$PM3BIN -c 'hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none'" "authenticated.*succes"; then break; fi - if ! CheckExecute "card app creation" "$PM3BIN -c 'hf mfdes createapp --aid 123456 --ks1 0F --ks2 0E --numkeys 1'" "successfully created"; then break; fi - if ! CheckExecute "card value file creation" "$PM3BIN -c 'hf mfdes createvaluefile --aid 123456 --fid 02 --lower 00000000 --upper 000003E8 --value 00000064'" "created successfully"; then break; fi - if ! CheckExecute "card value get plain" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m plain'" "Value.*100"; then break; fi - if ! CheckExecute "card value get mac" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m mac'" "Value.*100"; then break; fi - if ! CheckExecute "card value credit plain" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op credit -d 00000032 -m plain'" "Value.*changed"; then break; fi - if ! CheckExecute "card value get after credit" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m plain'" "Value.*150"; then break; fi - if ! CheckExecute "card value credit mac" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op credit -d 0000000A -m mac'" "Value.*changed"; then break; fi - if ! CheckExecute "card value debit plain" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m plain'" "Value.*changed"; then break; fi - if ! CheckExecute "card value debit mac" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op debit -d 00000014 -m mac'" "Value.*changed"; then break; fi - if ! CheckExecute "card value final check" "$PM3BIN -c 'hf mfdes value --aid 123456 --fid 02 --op get -m mac'" "Value.*120"; then break; fi - if ! CheckExecute "card cleanup" "$PM3BIN -c 'hf mfdes selectapp --aid 000000; hf mfdes auth -n 0 -t 2tdea -k 00000000000000000000000000000000 --kdf none; hf mfdes deleteapp --aid 123456'" "application.*deleted"; then break; fi - echo " card value operation tests completed successfully!" - fi - - echo -e "\n------------------------------------------------------------" - echo -e "Tests [ ${C_GREEN}OK${C_NC} ] ${C_OK}\n" - exit 0 -done -echo -e "\n------------------------------------------------------------" -echo -e "\nTests [ ${C_RED}FAIL${C_NC} ] ${C_FAIL}\n" -exit 1 \ No newline at end of file diff --git a/tools/pm3_tests.sh b/tools/pm3_tests.sh index f8e2dba2b..96a6376f7 100755 --- a/tools/pm3_tests.sh +++ b/tools/pm3_tests.sh @@ -1,8 +1,5 @@ #!/usr/bin/env bash -# This is used to make sure that the language for the functions is english instead of the system default language. -LANG=C - PM3PATH="$(dirname "$0")/.." cd "$PM3PATH" || exit 1 @@ -573,8 +570,8 @@ while true; do if ! CheckExecute slow "hf iclass loclass long test" "$CLIENTBIN -c 'hf iclass loclass --long'" "verified \( ok \)"; then break; fi if ! CheckExecute slow "emv long test" "$CLIENTBIN -c 'emv test -l'" "Tests \( ok"; then break; fi if ! CheckExecute "hf iclass lookup test" "$CLIENTBIN -c 'hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f $DICPATH/iclass_default_keys.dic'" \ - "valid key AEA684A6DAB23278"; then break; fi - if ! CheckExecute "hf iclass loclass test" "$CLIENTBIN -c 'hf iclass loclass --test'" "Key diversification \( ok \)"; then break; fi + "valid key AE A6 84 A6 DA B2 32 78"; then break; fi + if ! CheckExecute "hf iclass loclass test" "$CLIENTBIN -c 'hf iclass loclass --test'" "key diversification \( ok \)"; then break; fi if ! CheckExecute "emv test" "$CLIENTBIN -c 'emv test'" "Tests \( ok"; then break; fi if ! CheckExecute "hf cipurse test" "$CLIENTBIN -c 'hf cipurse test'" "Tests \( ok"; then break; fi if ! CheckExecute "hf mfdes test" "$CLIENTBIN -c 'hf mfdes test'" "Tests \( ok"; then break; fi diff --git a/tools/recover_pk.py b/tools/recover_pk.py index 7795604d8..1e6bc33f7 100755 --- a/tools/recover_pk.py +++ b/tools/recover_pk.py @@ -173,22 +173,16 @@ def selftests(): 'samples': ["045E4CC2451390", "C9BBDA1B99EB6634CDFD8E3251AC5C4742EA5FA507B8A8A8B39B19AB7340D173331589C54C56C49F0CCA6DDBAC1E492A", # noqa: E501 "043F88C2451390", "5C2055A7373F119C3FDD9843020B06AA0E6DE18C16496C425C4AD971A50F05FA1A67B9E39CA60C355EEEEBF8214A84A5"], # noqa: E501 'pk': "0453BF8C49B7BD9FE3207A91513B9C1D238ECAB07186B772104AB535F7D3AE63CF7C7F3DD0D169DA3E99E43C6399621A86"}, # noqa: E501 - {'name': "MIFARE Ultralight AES (Vingcard alt key)", + {'name': "MIFARE Ultralight AES (alt key)", # uses prime192v1, None, - 'samples': ["04A31232241C90", "057595DCC601CA7E21341F1F978FA134F0204D87A33749C56DDB4ABD6F1F26194341DB10093B34C42F524A30DCC5CE54", # noqa: E501 - "041BC1D2F31B90", "FB5CF8F1B3CC39984BCA54A50FCF47ACFDC8C969010C1F4599554AF9A8E4F2B8371524855E45AD7EE71179A660D27667"], # noqa: E501 + # TODO more samples + 'samples': ["04A31232241C90", "057595DCC601CA7E21341F1F978FA134F0204D87A33749C56DDB4ABD6F1F26194341DB10093B34C42F524A30DCC5CE54"], # noqa: E501 'pk': "04DC34DAA903F2726A6225B11C692AF6AB4396575CA12810CBBCE3F781A097B3833B50AB364A70D9C2B641A728A599AE74"}, # noqa: E501 {'name': "MIFARE Classic / QL88", 'samples': ["30933C61", "AEA4DD0B800FAC63D4DE08EE91F4650ED825FD6B4D7DEEE98DBC9BAE10BE003E", "20593261", "F762CDD59EEDC075F4DDBA7ECD529FEEE5135C65A84D12EF0A250A321B2012F5"], 'pk': "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"}, - {'name': "NTAG223DNA, NTAG224DNA", - # uses prime192v1, None, - # TODO more samples - 'samples': ["043302218D3D00", "6A5D5E034F4FC823CACAB56C1A77A409B8DB345F89BD3FD59ED1F9C0093518609BE62D0A20764D2011E47EFA187F29AA"], # noqa: E501 - 'pk': "0485D5B9353B4FAA77581BA2AE96630C5876D6E8603308ABE9A81A0B506F52D02D04FEE6F2D365B3DEE7B9FAD9133E2976"}, # noqa: E501 - # TruST25 (ST25TA) - KeyID 0x01? # curve=secp128r1, hash=sha256 - from block 224 in ST25TA NDEF file {'name': "ST25TA02KB TruST25 (ST) / KeyID 0x01?", @@ -215,7 +209,7 @@ def selftests(): succeeded = True for t in tests: - print("Testing %-41s" % (t['name']+":"), end="") + print("Testing %-40s" % (t['name']+":"), end="") curvenames = guess_curvename(t['samples'][1]) recovered = set() @@ -229,16 +223,16 @@ def selftests(): c, h, pk = recovered.pop() pk = binascii.hexlify(pk).decode('utf8') if pk.lower() == t['pk'].lower(): - print("%14s/%-8s ( %s )" % (c, h, color('ok', fg='green'))) + print("%15s/%-8s ( %s )" % (c, h, color('ok', fg='green'))) else: succeeded = False - print("%14s/%-8s ( %s ) got %s" % (c, h, color('fail', fg='red'), pk.lower())) + print("%15s/%-8s ( %s ) got %s" % (c, h, color('fail', fg='red'), pk.lower())) elif len(t['samples'])//2 == 1: recovereds = [(c, h) for c, h, pk in list(recovered) if t['pk'].lower() == binascii.hexlify(pk).decode('utf8').lower()] if len(recovereds) == 1: c, h = recovereds[0] - print("%14s/%-8s ( %s ) partial" % (c, h, color('ok', fg='green'))) + print("%15s/%-8s ( %s ) partial" % (c, h, color('ok', fg='green'))) else: succeeded = False print(" ( %s ), got" % color('fail', fg='red')) diff --git a/tools/twn/AppBlaster.exe b/tools/twn/AppBlaster.exe deleted file mode 100644 index 6fdfae2fc..000000000 Binary files a/tools/twn/AppBlaster.exe and /dev/null differ diff --git a/tools/twn/decoder.bix b/tools/twn/decoder.bix deleted file mode 100644 index daf694630..000000000 Binary files a/tools/twn/decoder.bix and /dev/null differ diff --git a/tools/twn/encoder.bix b/tools/twn/encoder.bix deleted file mode 100644 index 1f472028d..000000000 Binary files a/tools/twn/encoder.bix and /dev/null differ diff --git a/tools/twn/pcsc.bix b/tools/twn/pcsc.bix deleted file mode 100644 index 304500be1..000000000 Binary files a/tools/twn/pcsc.bix and /dev/null differ