diff --git a/.gitignore b/.gitignore index 349ef5efb..1b352bcfe 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ .profile *.log *.eml +*.html *.o *.a *.d diff --git a/.travis.yml b/.travis.yml index 1cb60f8e9..5aee2a918 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,16 @@ addons: - qt5 - RfidResearchGroup/proxmark3/arm-none-eabi-gcc taps: RfidResearchGroup/proxmark3 +# update trick to fix https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296/14 + update: true + +before_install: + # bug? + # homebrew update replaced python2.7 by python3.7 but + # python3 link failed while python@2 still present, so let's do it again: + if [ "$TRAVIS_OS_NAME" == "osx" ]; then + brew link --overwrite python; + fi install: if ! arm-none-eabi-gcc -v; then diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a36b58da..95d7ce2e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,51 @@ 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] + - Change `hf search` - now continue to search in case of dual tech cards (@iceman1001) Thanks to @ikarus23 for the suggestion! + - Added `hf topas info` - old reader command, now also prints NDEF (@iceman1001) + - Change `hf topaz reader` - now only prints lighter info, like UID. (@iceman1001) + - Change `hf iclass readtagfile` - improved param handling (@iceman1001) + - Change `hf mfu ndef` - text record now correctly decode language code and test (@iceman1001) Thanks to @bettse! + - Updated the helptexts for `hf iclass` commands (@iceman1001) + - Fix NDEF TLV lock / memory parsed correct (@merlokk) + - Change `mem spiffs` commands now parse h param correct (@iceman1001) + - Add colour to `hf mf chk` and `hf mf fchk` (@dunderhay) + - Change - updated public keys info (@bkerler) + - Change - mfc default keys removed dublicates (@iceman1001) + . Change - mfc default keys got new entries found on TagInfo app (@bkerler) + - Added `hf mfu ndef` - read and decode NDEF Type2 messages (@iceman1001) + - Added `data ndef` - decode NDEF messages (@iceman1001) + - Change - usb write's now waits for shiftregisters (@pwpiwi) + - Change - NDEF supports more signatures now (@iceman1001) + - OSX Makefile now supports `make style` and `make checks` (@Pizza_4u) + - Added `HF_LEGIC` standalone mode to read and simulate a Legic prime tag (@Pizza_4u) + - Added keri MS decode/encode and update 'lf keri clone' to support MS fc/cid cloning. (@mwalker33) + - Fix 'hf mfdes enum' - now actually manages to enumerate files under all AID's. :smiley: (@iceman1001) + - Fix 'hf mfdes info' - now detects DESFire light and work properly Wrapped commands :+1: (@iceman1001) + - :smiling_imp: support (@doegox) + - Additional colour changes as recommended by @iceman (@dunderhay) + - Change type colour for `hf 14a` card types (@dunderhay) + - Add colour to `hf mfdes` command (@dunderhay) + - Add 'HINTS' command. Will turn off / on hint messages. Default mode is OFF. (@iceman1001) + - Add colour to `hf 14a` and `hf mfu` commands (@dunderhay) + - Add colour to `lf hid` commands (@dunderhay) + - Change `script run hf_bruteforce -s start_id -e end_id -t timeout -x mifare_card_type` - The hf_bruteforce card script now requires Mifare type (mfc or mfu) (@dunderhay) + - Updated `hf_bruteforce.lua` script - added support for brute forcing Mifare Ultralight EV1 cards (@dunderhay) + - Added `hf mf personlize` - personalize the UID of a Mifare Classic EV1 card (@pwpiwi) + - Change - hint texts added to all lf clone commands (@iceman1001) + - Change `lf keri demod` - adjusted the internal id. (@mwalker33) + - Added seamless integration with cryptohelper (@iceman1001) + - Change `lf hid brute` - new params for direction (UP/DOWN); textual and main loop actually exit. (@capnkrunchy and @iceman1001) + - Fix `lf hid brute` - made it work again (@capnkrunchy) + - Fix standalone mode HF_MATTYRUN - correct logic when all keys found in printing. partial fix (@iceman1001) + - Change static nonce detection got tighter (@iceman1001) + - Improved termux notes (@msoose) + - Fix `hf mf autopwn` - works on debian 10 *nix. Bad exit commands in hardnested (@iceman1001) + - Fix `hf mf hardnested` - bad mutex strategies (@msoose) + - Change `lf hitag` - now obeys `lf config` (@iceman1001) + - Ported all python 2 scripts to python 3 (@doegox and @sigwinch28) + - Removed undefined exit behaviour from `analyzesize` tool: it now exits with code 2 when called with wrong args (@sigwinch28) + - Replaced shebangs in scripts with more portable versions which use `/usr/bin/env` (@sigwinch28) - Added `hf lto restore` - restore LTO cartridge memory from dump file [.bin|.eml] (@Kevin-Nakamoto) - Added `LF_ICEHID` standalone mode which searches for lf HID credentials and store to RDV4 flashmem (@iceman1001) - Added `HF_14ASNIFF` standalone mode with storing trace to RDV4 flashmem (@micolous) @@ -12,7 +57,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fix compilation under openSUSE (@hsanjuan) - Added `lf nexwatch sim` - use raw hex to simulate (@iceman1001) - Fix `lf indala read` - long id 224bits preamble identification less strict (@iceman1001) - - Added `hf mf staticnested` - useful when targeting the strange cards with a static nonce. (@iceman100) Thanks to @xtigmh @uzlonewolf for their solutions. + - Added `hf mf staticnested` - useful when targeting the strange cards with a static nonce. (@iceman1001) Thanks to @xtigmh @uzlonewolf for their solutions. - Added `hf plot` (@pwpiwi) - Fix `lf config` - when called with no params, it no longer mess up all device lf config settings. (@iceman1001) - Change `lf indala clone` - new option `--Q5` writes to q5/T5555 tags. (@iceman1001) @@ -21,7 +66,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `commands.md` - document with all proxmark client commands. Generated with XX_internal_command_dump_markdown_XX. (@iceman1001) - Change `lf pac clone` - new option `c ` to allow cloning PAC/Stanley tag from card ID (@danshuk) - Change `lf pac read` - decoded PAC/Stanley card ID (@danshuk) - - Change mifare classic keytable output refactored and uses colors (@iceman1001) + - Change mifare classic keytable output refactored and uses colors (@iceman1001) - Fix `hf mf nested` - now writes the correct blockno (@iceman1001) - Change `lf t55xx dump` - now supports saving to JSON (@iceman1001) - Change `hf mf chk | fchk` faster authentication by lower timeout limit. (@pwpiwi) @@ -417,6 +462,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk) - Added `script run luxeodump` (@0xdrrb) - Fix `lf hitag reader 02` - print all bytes (@bosb) + - Fix hitag S simulation (still not working), write, add example HITAG S 256 (@bosb) ### Fixed @@ -591,8 +637,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Updated the Reveng 1.31 sourcecode to 1.40 from Reveng project homepage (@iceman1001) - Added possibility to write direct to a Legic Prime Tag (MIM256/1024) without using values from the `BigBuffer` -> `hf legic writeRaw ` (@icsom) - Added possibility to decrease DCF values at address 0x05 & 0x06 on a Legic Prime Tag - DCF-value will be pulled from the BigBuffer (address 0x05 & 0x06) so you have to - load the data into the BigBuffer before with `hf legic load ` & then + DCF-value will be pulled from the BigBuffer (address 0x05 & 0x06) so you have to + load the data into the BigBuffer before with `hf legic load ` & then write the DCF-Values (both at once) with `hf legic write 0x05 0x02` (@icsom) - Added script `legic.lua` for display and edit Data of Legic-Prime Tags (@icsom) - Added the experimental HITAG_S support (@spenneb) diff --git a/Makefile b/Makefile index 783b5fa27..5c7947fc5 100644 --- a/Makefile +++ b/Makefile @@ -210,13 +210,20 @@ style: # Detecting weird codepages and tabs. checks: + # Make sure recode is installed + @which recode >/dev/null || ( echo "Please install 'recode' package first" ; exit 1 ) @echo "Files with suspicious chars:" @find . \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \ -exec sh -c "cat {} |recode utf8.. >/dev/null || echo {}" \; @echo "Files with tabs:" # to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq' +ifeq ($(platform),Darwin) + @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \ + -exec egrep -l '\t' {} \; +else @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \ -exec grep -lP '\t' {} \; +endif # @echo "Files with printf \\\\t:" # @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \ # -exec grep -lP '\\t' {} \; diff --git a/README.md b/README.md index 96a8d2693..d183309b4 100644 --- a/README.md +++ b/README.md @@ -11,16 +11,16 @@ | FAQ's & Updates | Installation | Use of the Proxmark | | ------------------- |:-------------------:| -------------------:| -|[What has changed?](#what-has-changed) | [Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)| -|[Development](#development) | [Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md) | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) | -|[Why didn't you base it on official Proxmark3 Master?](#why-didnt-you-base-it-on-official-proxmark3-master)| [Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md) | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)| -|[Proxmark3 GUI](#proxmark3-gui)|[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)| +|[What has changed?](#what-has-changed) | **[Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md)** | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)| +|[Development](#development) | **[Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md)** | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) | +|[Why didn't you base it on official Proxmark3 Master?](#why-didnt-you-base-it-on-official-proxmark3-master)| **[Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md)** | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)| +|[Proxmark3 GUI](#proxmark3-gui)|**[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)**|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)| |[Issues](#issues)|[Blue shark manual](/doc/bt_manual_v10.md) |[Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)| |[Notes on UART](/doc/uart_notes.md)|[Maintainers](/doc/md/Development/Maintainers.md)|[Command Cheat sheet](/doc/cheatsheet.md)| |[Notes on frame format](/doc/new_frame_format.md)||[More cheat sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)| |[Notes on external flash](/doc/ext_flash_notes.md)||[EMV](/doc/emv_notes.md)| |[Notes on Termux / Android](/doc/termux_notes.md)||[Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md)| -|[Notes on wireshark / tracedata](/doc/trace_wireshark_notes.md)||[JTAG](/doc/jtag_notes.md)| +|[Notes on tracedata / wireshark](/doc/trace_notes.md)||[JTAG](/doc/jtag_notes.md)| |[Notes on loclass](/doc/loclass_notes.md)||[Complete client command set](/doc/commands.md)| |[Notes on paths](/doc/path_notes.md)||| |[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) || @@ -47,9 +47,9 @@ On the software side: quite a lot, see the [Changelog file](CHANGELOG.md). > ⚠ **Note**: This is a bleeding edge repository. The maintainers actively is working out of this repository and will be periodically re-structuring the code to make it easier to comprehend, navigate, build, test, and contribute to, so **DO expect significant changes to code layout on a regular basis**. This repo compiles nicely on - - Proxspace v3.2 + - Proxspace v3.x - Windows/mingw environment with Qt5.6.1 & GCC 4.8 - - Ubuntu 1404, 1510, 1604, 1804, 1904 + - Ubuntu 1604, 1804, 1904 - Mac OS X / Homebrew - ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora - WSL, WSL2 (Windows subsystem linux) on Windows 10 @@ -67,7 +67,7 @@ We usually merge your contributions fast since we do like the idea of getting a - notes on [external flash](/doc/ext_flash_notes.md) - notes on [standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) - notes on [Termux / Android](/doc/termux_notes.md) -- notes on [Wireshark / tracedata](/doc/trace_wireshark_notes.md) +- notes on [tracedata / Wireshark](/doc/trace_notes.md) - notes on [loclass](/doc/loclass_notes.md) - notes on [EMV](/doc/emv_notes.md) - notes on [Paths](/doc/path_notes.md) diff --git a/appveyor.yml b/appveyor.yml index b2ab84fb4..230bb44bf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,7 +24,7 @@ init: Add-AppveyorMessage -Message "[$env:APPVEYOR_REPO_COMMIT_SHORT]$env:appveyor_repo_name($env:APPVEYOR_REPO_BRANCH)" -Category Information -Details "repository: $env:appveyor_repo_name branch: $env:APPVEYOR_REPO_BRANCH release: $releasename" - iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) + # iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) clone_script: - ps: >- Write-Host "Removing ProxSpace..." -NoNewLine @@ -409,4 +409,4 @@ on_success: on_failure: - ps: Write-Host "Build error." -ForegroundColor Red on_finish: -- ps: $blockRdp = $false; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +- ps: # $blockRdp = $false; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/armsrc/LCD_disabled.c b/armsrc/LCD_disabled.c index 32a917928..97bf6da71 100644 --- a/armsrc/LCD_disabled.c +++ b/armsrc/LCD_disabled.c @@ -5,7 +5,7 @@ //----------------------------------------------------------------------------- // LCD code //----------------------------------------------------------------------------- -#include "LCD.h" +#include "LCD_disabled.h" void LCDSend(unsigned int data) { // 9th bit set for data, clear for command diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index 2dec4cfde..e3ad8accb 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -41,10 +41,19 @@ define KNOWN_STANDALONE_DEFINITIONS | LF_ICEHID | LF HID collector to flashmem | | (RDV4 only) | | +----------------------------------------------------------+ +| LF_EM4100EMUL | Simulate predefined em4100 tags only | +| | | ++----------------------------------------------------------+ +| LF_EM4100RWC | Read/simulate em4100 tags & clone it | +| | to T555x tags | ++----------------------------------------------------------+ +| HF_LEGIC | Read/simulate Legic Prime tags | +| | storing in flashmem | ++----------------------------------------------------------+ endef -STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE LF_ICEHID -STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG HF_14ASNIFF +STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE LF_ICEHID LF_EM4100EMUL LF_EM4100RWC +STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG HF_14ASNIFF HF_LEGIC STANDALONE_MODES_REQ_SMARTCARD := STANDALONE_MODES_REQ_FLASH := HF_COLIN HF_BOG HF_14ASNIFF LF_ICEHID ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),) diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index d4de0411e..4b480ad3a 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -40,4 +40,16 @@ endif # WITH_STANDALONE_LF_ICEHID ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS))) SRC_STANDALONE = lf_icehid.c -endif \ No newline at end of file +endif +# WITH_STANDALONE_LF_EM4100EMUL +ifneq (,$(findstring WITH_STANDALONE_LF_EM4100EMUL,$(APP_CFLAGS))) + SRC_STANDALONE = lf_em4100emul.c +endif +# WITH_STANDALONE_LF_EM4100RWC +ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RWC,$(APP_CFLAGS))) + SRC_STANDALONE = lf_em4100rwc.c +endif +# WITH_STANDALONE_HF_LEGIC +ifneq (,$(findstring WITH_STANDALONE_HF_LEGIC,$(APP_CFLAGS))) + SRC_STANDALONE = hf_legic.c +endif diff --git a/armsrc/Standalone/hf_14asniff.c b/armsrc/Standalone/hf_14asniff.c index d8bf6ab82..706a41b8b 100644 --- a/armsrc/Standalone/hf_14asniff.c +++ b/armsrc/Standalone/hf_14asniff.c @@ -45,7 +45,7 @@ * This module emits debug strings during normal operation -- so try it out in * the lab connected to PM3 client before taking it into the field. * - * To delete the trace data from flash: + * To delete the trace data from flash: * * Caveats / notes: * - Trace buffer will be cleared on starting stand-alone mode. Data in flash @@ -97,7 +97,7 @@ void RunMod() { if (trace_len > 0) { Dbprintf("[!] Trace length (bytes) = %u", trace_len); - uint8_t* trace_buffer = BigBuf_get_addr(); + uint8_t *trace_buffer = BigBuf_get_addr(); if (!exists_in_spiffs(HF_14ASNIFF_LOGFILE)) { rdv40_spiffs_write( HF_14ASNIFF_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE); @@ -117,7 +117,7 @@ void RunMod() { SpinErr(LED_A, 200, 5); SpinDelay(100); - + LEDsoff(); SpinDelay(300); DownloadTraceInstructions(); diff --git a/armsrc/Standalone/hf_legic.c b/armsrc/Standalone/hf_legic.c new file mode 100644 index 000000000..2b826528f --- /dev/null +++ b/armsrc/Standalone/hf_legic.c @@ -0,0 +1,173 @@ +//----------------------------------------------------------------------------- +// (c) Stefanie Hofmann, 2020 +// (c) Uli Heilmeier, 2020 +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// main code for Legic Prime read/sim +//----------------------------------------------------------------------------- + +#include "standalone.h" +#include "proxmark3_arm.h" +#include "BigBuf.h" +#include "appmain.h" +#include "fpgaloader.h" +#include "util.h" +#include "dbprint.h" +#include "ticks.h" +#include "legicrf.h" +#include "legicrfsim.h" +#include "legic.h" // legic_card_select_t struct +#include "spiffs.h" // flashmem + + +/* + * To list all dump files from flash: + * + * 1. mem spiffs tree + * + * + * To retrieve dump files from flash: + * + * 1. mem spiffs dump o hf-legic-XXYYZZWW-dump.bin f hf-legic-XXYYZZWW-dump.bin + * Copies log file from flash to your client. + * + * + * This module emits debug strings during normal operation -- so try it out in + * the lab connected to PM3 client before taking it into the field. + * + * To delete a dump file from flash: + * + * 1. mem spiffs remove hf-legic-XXYYZZWW-dump.bin + * +*/ + +void DownloadLogInstructions() { + Dbprintf(""); + Dbprintf("[=] List all dumps from flash:"); + Dbprintf("[=] " _YELLOW_("-") "mem spiffs tree"); + Dbprintf(""); + Dbprintf("[=] To save a dump file from flash to client:"); + Dbprintf("[=] " _YELLOW_("-") "mem spiffs dump o hf-legic-UID-dump.bin f hf-legic-UID-dump.bin"); +} + +void save_dump_to_file(legic_card_select_t *p_card) { + +#ifdef WITH_FLASH + + // legic functions puts it memory in Emulator reserved memory. + uint8_t *mem = BigBuf_get_EM_addr(); + + char *preferredName = (char*)BigBuf_malloc(30); + if (preferredName == NULL) { + goto OUT; + } + + sprintf(preferredName, "hf-legic-%02X%02X%02X%02X-dump", p_card->uid[0], p_card->uid[1], p_card->uid[2], p_card->uid[3]); + uint16_t preferredNameLen = strlen(preferredName); + + char *filename = (char*)BigBuf_malloc(preferredNameLen + 4 + 1 + 10); + if (filename == NULL) { + goto OUT; + } + + sprintf(filename, "%.*s%s", preferredNameLen, preferredName, ".bin"); + uint16_t num = 1; + while (exists_in_spiffs(filename)) { + sprintf(filename, "%.*s-%d%s", preferredNameLen, preferredName, num, ".bin"); + num++; + } + + rdv40_spiffs_write(filename, mem, p_card->cardsize, RDV40_SPIFFS_SAFETY_SAFE); + + Dbprintf("[=] saved card dump to flashmem::" _YELLOW_("%s"), filename); +OUT: + BigBuf_free_keep_EM(); +#endif + +} + +void ModInfo(void) { + DbpString(" HF Legic Prime standalone"); +} + +// Searching for Legic card until found and read. +// Simulating recorded Legic Prime card. +// C = Searching +// A, B, C = Reading +// A, D = Simulating + +void RunMod() { + StandAloneMode(); + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + Dbprintf("[=] >> HF Legic Prime Read/Simulate Started <<"); + DbpString("[=] press and HOLD button to exit standalone mode"); + for (;;) { + WDT_HIT(); + + //exit from hf_legic, send usbcommand + if (data_available()) break; + + //Was our button held down or pressed? + int button_pressed = BUTTON_HELD(280); + if (button_pressed == BUTTON_HOLD) { + break; + } + + LEDsoff(); + LED_C_ON(); + + DbpString("[=] looking for tags"); + int read_success = PM3_ESOFT; + + //search for legic card until reading successfull or button pressed + do { + LED_C_ON(); + SpinDelay(500); + // We don't care if we read a MIM256, MIM512 or MIM1024 + // we just read 1024 bytes + read_success = LegicRfReaderEx(0, 1024, 0x55); + + } while (read_success == PM3_ESOFT && !BUTTON_PRESS()); + + LEDsoff(); + + //simulate if read successfully + if (read_success != PM3_ESOFT) { + + legic_card_select_t *p_card; + p_card = getLegicCardInfo(); + if (p_card->cardsize == 0) + continue; + + save_dump_to_file(p_card); + + LED_D_ON(); + uint8_t ct; + switch(p_card->tagtype) { + case 0x0D: + ct = 0; + break; + case 0x1D: + ct = 1; + break; + case 0x3D: + ct = 2; + break; + default: + continue; + } + + // The read data is migrated to a MIM1024 card + LegicRfSimulate(ct); + } + } + + LEDsoff(); +#ifdef WITH_FLASH + DownloadLogInstructions(); +#endif + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +} diff --git a/armsrc/Standalone/hf_mattyrun.c b/armsrc/Standalone/hf_mattyrun.c index 3e53fffe9..60619e657 100644 --- a/armsrc/Standalone/hf_mattyrun.c +++ b/armsrc/Standalone/hf_mattyrun.c @@ -323,7 +323,7 @@ void RunMod() { Dbprintf("\tCurrent sector:%3d, block:%3d, key type: %c, key count: %i ", sec, block, type ? 'B' : 'A', mfKeysCnt); int key = saMifareChkKeys(block, type, true, size, &keyBlock[0], &key64); if (key == -1) { - LED(LED_RED, 50); //red + LED(LED_RED, 50); Dbprintf("\t✕ Key not found for this sector!"); allKeysFound = false; // break; @@ -348,21 +348,24 @@ void RunMod() { TODO: - Get UID from tag and set accordingly in emulator memory and call mifaresim with right flags (iceman) */ - if (!allKeysFound && keyFound) { - Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!"); - LED_C_ON(); //red - LED_A_ON(); //yellow - // no room to run nested attack on device (iceman) - // Do nested attack, set allKeysFound = true; - // allKeysFound = true; + if (allKeysFound) { + Dbprintf("\t✓ All keys found"); } else { - Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!"); - LED_C_ON(); //red + if (keyFound) { + Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!"); + LED_C_ON(); //red + LED_A_ON(); //yellow + // no room to run nested attack on device (iceman) + // Do nested attack, set allKeysFound = true; + // allKeysFound = true; + } else { + Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!"); + LED_C_ON(); //red + } } - /* - If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned. - */ + // If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned. + if ((transferToEml) && (allKeysFound)) { emlClearMem(); diff --git a/armsrc/Standalone/lf_em4100emul.c b/armsrc/Standalone/lf_em4100emul.c new file mode 100644 index 000000000..7b38133bc --- /dev/null +++ b/armsrc/Standalone/lf_em4100emul.c @@ -0,0 +1,100 @@ +//----------------------------------------------------------------------------- +// Artyom Gnatyuk, 2020 +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// LF emul - Very simple mode. Simulate only predefined in low[] IDs +// Short click - select next slot and start simulation +//----------------------------------------------------------------------------- +#include "standalone.h" +#include "proxmark3_arm.h" +#include "appmain.h" +#include "fpgaloader.h" +#include "lfops.h" +#include "util.h" +#include "dbprint.h" +#include "ticks.h" +#include "string.h" +#include "BigBuf.h" + +#define MAX_IND 16 // 4 LEDs - 2^4 combinations +#define CLOCK 64 //for 125kHz + +// low & high - array for storage IDs. Its length must be equal. +// Predefined IDs must be stored in low[]. +// In high[] must be nulls +uint64_t low[] = {0x565A1140BE, 0x365A398149, 0x5555555555, 0xFFFFFFFFFF}; +uint32_t high[] = {0, 0, 0, 0}; +uint8_t *bba, slots_count; +int buflen; + +void ModInfo(void) { + DbpString(" LF EM4100 simulator standalone mode"); +} + +uint64_t ReversQuads(uint64_t bits) { + uint64_t result = 0; + for (int i = 0; i < 16; i++) { + result += ((bits >> (60 - 4 * i)) & 0xf) << (4 * i); + } + return result >> 24; +} + +void FillBuff(uint8_t bit) { + memset(bba + buflen, bit, CLOCK / 2); + buflen += (CLOCK / 2); + memset(bba + buflen, bit ^ 1, CLOCK / 2); + buflen += (CLOCK / 2); +} + +void ConstructEM410xEmulBuf(uint64_t id) { + + int i, j, binary[4], parity[4]; + buflen = 0; + for (i = 0; i < 9; i++) + FillBuff(1); + parity[0] = parity[1] = parity[2] = parity[3] = 0; + for (i = 0; i < 10; i++) { + for (j = 3; j >= 0; j--, id /= 2) + binary[j] = id % 2; + for (j = 0; j < 4; j++) + FillBuff(binary[j]); + FillBuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]); + for (j = 0; j < 4; j++) + parity[j] ^= binary[j]; + } + for (j = 0; j < 4; j++) + FillBuff(parity[j]); + FillBuff(0); +} + +void LED_Slot(int i) { + LEDsoff(); + if (slots_count > 4) { + LED(i % MAX_IND, 0); //binary indication for slots_count > 4 + } else { + LED(1 << i, 0); //simple indication for slots_count <=4 + } +} + +void RunMod() { + StandAloneMode(); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + Dbprintf("[=] >> LF EM4100 simulator started <<"); + + int selected = 0; //selected slot after start + slots_count = sizeof(low) / sizeof(low[0]); + bba = BigBuf_get_addr(); + for (;;) { + WDT_HIT(); + if (data_available()) break; + SpinDelay(100); + SpinUp(100); + LED_Slot(selected); + ConstructEM410xEmulBuf(ReversQuads(low[selected])); + SimulateTagLowFrequency(buflen, 0, true); + selected = (selected + 1) % slots_count; + } +} diff --git a/armsrc/Standalone/lf_em4100rwc.c b/armsrc/Standalone/lf_em4100rwc.c new file mode 100644 index 000000000..02366d0a6 --- /dev/null +++ b/armsrc/Standalone/lf_em4100rwc.c @@ -0,0 +1,204 @@ +//----------------------------------------------------------------------------- +// Artyom Gnatyuk, 2020 +// +// This code is licensed to you under the terms of the GNU GPL, version 2 or, +// at your option, any later version. See the LICENSE.txt file for the text of +// the license. +//----------------------------------------------------------------------------- +// LF rwc - This mode can simulate ID from selected slot, read ID to +// selected slot, write from selected slot to T5555 tag and store +// readed ID to flash (only RDV4). Also you can set predefined IDs +// in any slot. +// To recall stored ID from flash execute: +// mem spifss dump o emdump p +// or: +// mem spifss dump o emdump f emdump +// then from shell: +// hexdump emdump -e '5/1 "%02X" /0 "\n"' +//----------------------------------------------------------------------------- +#include "standalone.h" +#include "proxmark3_arm.h" +#include "appmain.h" +#include "fpgaloader.h" +#include "lfops.h" +#include "util.h" +#include "dbprint.h" +#include "ticks.h" +#include "string.h" +#include "BigBuf.h" +#include "spiffs.h" + +#ifdef WITH_FLASH +#include "flashmem.h" +#endif + +#define MAX_IND 16 // 4 LEDs - 2^4 combinations +#define CLOCK 64 //for 125kHz + +// low & high - array for storage IDs. Its length must be equal. +// Predefined IDs must be stored in low[]. +// In high[] must be nulls +uint64_t low[] = {0x565AF781C7, 0x540053E4E2, 0x1234567890, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +uint32_t high[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +uint8_t *bba, slots_count; +int buflen; + +void ModInfo(void) { + DbpString(" LF EM4100 read/write/clone mode"); +} + +uint64_t ReversQuads(uint64_t bits) { + uint64_t result = 0; + for (int i = 0; i < 16; i++) { + result += ((bits >> (60 - 4 * i)) & 0xf) << (4 * i); + } + return result >> 24; +} + +void FillBuff(uint8_t bit) { + memset(bba + buflen, bit, CLOCK / 2); + buflen += (CLOCK / 2); + memset(bba + buflen, bit ^ 1, CLOCK / 2); + buflen += (CLOCK / 2); +} + +void ConstructEM410xEmulBuf(uint64_t id) { + + int i, j, binary[4], parity[4]; + buflen = 0; + for (i = 0; i < 9; i++) + FillBuff(1); + parity[0] = parity[1] = parity[2] = parity[3] = 0; + for (i = 0; i < 10; i++) { + for (j = 3; j >= 0; j--, id /= 2) + binary[j] = id % 2; + for (j = 0; j < 4; j++) + FillBuff(binary[j]); + FillBuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]); + for (j = 0; j < 4; j++) + parity[j] ^= binary[j]; + } + for (j = 0; j < 4; j++) + FillBuff(parity[j]); + FillBuff(0); +} + +void LED_Slot(int i) { + LEDsoff(); + if (slots_count > 4) { + LED(i % MAX_IND, 0); //binary indication, usefully for slots_count > 4 + } else { + LED(1 << i, 0); //simple indication for slots_count <=4 + } +} + +void FlashLEDs(uint32_t speed, uint8_t times) { + for (int i = 0; i < times * 2; i++) { + LED_A_INV(); + LED_B_INV(); + LED_C_INV(); + LED_D_INV(); + SpinDelay(speed); + } +} + +#ifdef WITH_FLASH +void SaveIDtoFlash(int addr, uint64_t id) { + uint8_t bt[5]; + char *filename = "emdump"; + rdv40_spiffs_mount(); + for (int i = 0; i < 5; i++) { + bt[4 - i] = (uint8_t)(id >> 8 * i & 0xff); + } + if (exists_in_spiffs(filename) == false) { + rdv40_spiffs_write(filename, &bt[0], 5, RDV40_SPIFFS_SAFETY_NORMAL); + } else { + rdv40_spiffs_append(filename, &bt[0], 5, RDV40_SPIFFS_SAFETY_NORMAL); + } +} +#endif + +void RunMod() { + StandAloneMode(); + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + Dbprintf("[=] >> LF EM4100 read/write/clone started <<"); + + int selected = 0; + //state 0 - select slot + // 1 - read tag to selected slot, + // 2 - simulate tag from selected slot + // 3 - write to T5555 tag + uint8_t state = 0; + slots_count = sizeof(low) / sizeof(low[0]); + bba = BigBuf_get_addr(); + LED_Slot(selected); + for (;;) { + WDT_HIT(); + if (data_available()) break; + int button_pressed = BUTTON_HELD(1000); + SpinDelay(300); + switch (state) { + case 0: + // Select mode + if (button_pressed == 1) { + // Long press - switch to simulate mode + SpinUp(100); + LED_Slot(selected); + state = 2; + } else if (button_pressed < 0) { + // Click - switch to next slot + selected = (selected + 1) % slots_count; + LED_Slot(selected); + } + break; + case 1: + // Read mode. + if (button_pressed > 0) { + // Long press - switch to read mode + SpinUp(100); + LED_Slot(selected); + state = 3; + } else if (button_pressed < 0) { + // Click - exit to select mode + CmdEM410xdemod(1, &high[selected], &low[selected], 0); + FlashLEDs(100, 5); +#ifdef WITH_FLASH + SaveIDtoFlash(selected, low[selected]); +#endif + state = 0; + } + break; + case 2: + // Simulate mode + if (button_pressed > 0) { + // Long press - switch to read mode + SpinDown(100); + LED_Slot(selected); + state = 1; + } else if (button_pressed < 0) { + // Click - start simulating. Click again to exit from simulate mode + LED_Slot(selected); + ConstructEM410xEmulBuf(ReversQuads(low[selected])); + FlashLEDs(100, 5); + SimulateTagLowFrequency(buflen, 0, 1); + LED_Slot(selected); + state = 0; // Switch to select mode + } + break; + case 3: + // Write tag mode + if (button_pressed > 0) { + // Long press - switch to select mode + SpinDown(100); + LED_Slot(selected); + state = 0; + } else if (button_pressed < 0) { + // Click - write ID to tag + WriteEM410x(0, (uint32_t)(low[selected] >> 32), (uint32_t)(low[selected] & 0xffffffff)); + LED_Slot(selected); + state = 0; // Switch to select mode + } + break; + } + } +} diff --git a/armsrc/Standalone/lf_icehid.c b/armsrc/Standalone/lf_icehid.c index 77f04024e..33d4ed764 100644 --- a/armsrc/Standalone/lf_icehid.c +++ b/armsrc/Standalone/lf_icehid.c @@ -7,6 +7,7 @@ //----------------------------------------------------------------------------- // main code for HID collector aka IceHID by Iceman //----------------------------------------------------------------------------- +#include #include "standalone.h" // standalone definitions #include "proxmark3_arm.h" #include "appmain.h" @@ -36,7 +37,7 @@ * To retrieve log file from flash: * * 1. mem spiffs dump o lf_hidcollect.log f lf_hidcollect.log - * Copies log file from flash to your PC. + * Copies log file from flash to your client. * * 2. exit the Proxmark3 client * @@ -63,7 +64,7 @@ void DownloadLogInstructions() { bool log_exists; -void append(uint8_t* entry, size_t entry_len) { +void append(uint8_t *entry, size_t entry_len) { LED_B_ON(); if (log_exists == false) { @@ -105,23 +106,23 @@ uint32_t IceEM410xdemod() { memset(entry, 0, sizeof(entry)); if (size == 128) { - sprintf((char *)entry, "EM XL TAG ID: %06lx%08lx%08lx - (%05ld_%03ld_%08ld)\n", - hi, - (uint32_t)(lo >> 32), - (uint32_t)lo, - (uint32_t)(lo & 0xFFFF), - (uint32_t)((lo >> 16LL) & 0xFF), - (uint32_t)(lo & 0xFFFFFF)); + sprintf((char *)entry, "EM XL TAG ID: %06"PRIx32"%08"PRIx32"%08"PRIx32" - (%05"PRIu32"_%03"PRIu32"_%08"PRIu32")\n", + hi, + (uint32_t)(lo >> 32), + (uint32_t)lo, + (uint32_t)(lo & 0xFFFF), + (uint32_t)((lo >> 16LL) & 0xFF), + (uint32_t)(lo & 0xFFFFFF)); } else { - sprintf((char *)entry, "EM TAG ID: %02lx%08lx - (%05ld_%03ld_%08ld)\n", - (uint32_t)(lo >> 32), - (uint32_t)lo, - (uint32_t)(lo & 0xFFFF), - (uint32_t)((lo >> 16LL) & 0xFF), - (uint32_t)(lo & 0xFFFFFF)); + sprintf((char *)entry, "EM TAG ID: %02"PRIx32"%08"PRIx32" - (%05"PRIu32"_%03"PRIu32"_%08"PRIu32")\n", + (uint32_t)(lo >> 32), + (uint32_t)lo, + (uint32_t)(lo & 0xFFFF), + (uint32_t)((lo >> 16LL) & 0xFF), + (uint32_t)(lo & 0xFFFFFF)); } - append(entry, strlen((char*)entry)); + append(entry, strlen((char *)entry)); Dbprintf("%s", entry); BigBuf_free(); return PM3_SUCCESS; @@ -160,20 +161,20 @@ uint32_t IceAWIDdemod() { uint8_t fac = bytebits_to_byte(dest + 9, 8); uint32_t cardnum = bytebits_to_byte(dest + 17, 16); uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen); - sprintf((char *)entry, "AWID bit len: %d, FC: %d, Card: %ld - Wiegand: %lx, Raw: %08lx%08lx%08lx\n", fmtLen, fac, cardnum, code1, rawHi2, rawHi, rawLo); + sprintf((char *)entry, "AWID bit len: %d, FC: %d, Card: %"PRIu32" - Wiegand: %"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, fac, cardnum, code1, rawHi2, rawHi, rawLo); } else { uint32_t cardnum = bytebits_to_byte(dest + 8 + (fmtLen - 17), 16); if (fmtLen > 32) { uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen - 32); uint32_t code2 = bytebits_to_byte(dest + 8 + (fmtLen - 32), 32); - sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %ld - Wiegand: %lx%08lx, Raw: %08lx%08lx%08lx\n", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); + sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %"PRIu32" - Wiegand: %"PRIx32"%08"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo); } else { uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen); - sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %ld - Wiegand: %lx, Raw: %08lx%08lx%08lx\n", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo); + sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %"PRIu32" - Wiegand: %"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo); } } - append(entry, strlen((char*)entry)); + append(entry, strlen((char *)entry)); Dbprintf("%s", entry); BigBuf_free(); return PM3_SUCCESS; @@ -209,15 +210,15 @@ uint32_t IceIOdemod() { uint8_t entry[64]; memset(entry, 0, sizeof(entry)); - sprintf((char *)entry, "IO Prox XSF(%02d)%02x:%05d (%08lx%08lx)\n" - , version - , facilitycode - , number - , hi - , lo - ); + sprintf((char *)entry, "IO Prox XSF(%02u)%02x:%05u (%08"PRIx32"%08"PRIx32")\n" + , version + , facilitycode + , number + , hi + , lo + ); - append(entry, strlen((char*)entry)); + append(entry, strlen((char *)entry)); Dbprintf("%s", entry); BigBuf_free(); return PM3_SUCCESS; @@ -249,14 +250,14 @@ uint32_t IceHIDDemod() { // go over previously decoded manchester data and decode into usable tag ID if (hi2 != 0) { //extra large HID tags 88/192 bits - sprintf((char *)entry, "HID large: %lx%08lx%08lx (%ld)\n", - hi2, - hi, - lo, - (lo >> 1) & 0xFFFF - ); + sprintf((char *)entry, "HID large: %"PRIx32"%08"PRIx32"%08"PRIx32" (%"PRIu32")\n", + hi2, + hi, + lo, + (lo >> 1) & 0xFFFF + ); - append(entry, strlen((char*)entry)); + append(entry, strlen((char *)entry)); } else { //standard HID tags 44/96 bits uint8_t bitlen = 0; @@ -296,16 +297,16 @@ uint32_t IceHIDDemod() { fac = ((hi & 0xF) << 12) | (lo >> 20); } - sprintf((char *)entry, "HID: %lx%08lx (%ld) Format: %d bit FC: %ld Card: %ld\n", - hi, - lo, - (lo >> 1) & 0xFFFF, - bitlen, - fac, - cardnum - ); + sprintf((char *)entry, "HID: %"PRIx32"%08"PRIx32" (%"PRIu32") Format: %d bit FC: %"PRIu32" Card: %"PRIu32"\n", + hi, + lo, + (lo >> 1) & 0xFFFF, + bitlen, + fac, + cardnum + ); - append(entry, strlen((char*)entry)); + append(entry, strlen((char *)entry)); } Dbprintf("%s", entry); @@ -349,7 +350,7 @@ void RunMod() { uint32_t res; - // since we steal 12800 from bigbuffer, no need to sample it. + // since we steal 12800 from bigbuffer, no need to sample it. DoAcquisition_config(false, 28000); res = IceHIDDemod(); if (res == PM3_SUCCESS) { diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 15d939a35..5bec32364 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -42,6 +42,7 @@ #include "Standalone/standalone.h" #include "util.h" #include "ticks.h" +#include "commonutil.h" #ifdef WITH_LCD #include "LCD.h" @@ -548,7 +549,7 @@ void ListenReaderField(uint8_t limit) { // iceman, useless, since we are measuring readerfield, not our field. My tests shows a max of 20v from a reader. hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40); #else - hf_av = hf_max = AvgAdc(ADC_CHAN_HF); + hf_av = hf_max = AvgAdc(ADC_CHAN_HF); #endif Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10); hf_baseline = hf_av; @@ -721,12 +722,20 @@ static void PacketReceived(PacketCommandNG *packet) { setT55xxConfig(packet->oldarg[0], (t55xx_configurations_t *) packet->data.asBytes); break; } - case CMD_LF_SAMPLING_GET_CONFIG: { + case CMD_LF_SAMPLING_PRINT_CONFIG: { printConfig(); break; } + case CMD_LF_SAMPLING_GET_CONFIG: { + sample_config *config = getSamplingConfig(); + reply_ng(CMD_LF_SAMPLING_GET_CONFIG, PM3_SUCCESS, (uint8_t *)config, sizeof(sample_config)); + break; + } case CMD_LF_SAMPLING_SET_CONFIG: { - setSamplingConfig((sample_config *) packet->data.asBytes); + sample_config c; + memcpy(&c, packet->data.asBytes, sizeof(sample_config)); + setSamplingConfig(&c); +// setSamplingConfig((sample_config *) packet->data.asBytes); break; } case CMD_LF_ACQ_RAW_ADC: { @@ -1239,6 +1248,17 @@ static void PacketReceived(PacketCommandNG *packet) { // SniffMifare(packet->oldarg[0]); // break; // } + case CMD_HF_MIFARE_PERSONALIZE_UID: { + struct p { + uint8_t keytype; + uint8_t pers_option; + uint8_t key[6]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + uint64_t authkey = bytes_to_num(payload->key, 6); + MifarePersonalizeUID(payload->keytype, payload->pers_option, authkey); + break; + } case CMD_HF_MIFARE_SETMOD: { MifareSetMod(packet->data.asBytes); break; diff --git a/armsrc/buzzer_disabled.c b/armsrc/buzzer_disabled.c index 708b7d3f7..579ffaa4e 100644 --- a/armsrc/buzzer_disabled.c +++ b/armsrc/buzzer_disabled.c @@ -1,4 +1,4 @@ -#include "buzzer.h" +#include "buzzer_disabled.h" void Ring_BEE_ONCE(uint16_t music_note) { BEE_ON(); diff --git a/armsrc/desfire_crypto_disabled.c b/armsrc/desfire_crypto_disabled.c index d835a55d4..02896afa8 100644 --- a/armsrc/desfire_crypto_disabled.c +++ b/armsrc/desfire_crypto_disabled.c @@ -26,9 +26,7 @@ * May 2005 */ #include - -#include "desfire_crypto.h" - +#include "desfire_crypto_disabled.h" #include "crc32.h" #include "printf.h" #include "desfire.h" diff --git a/armsrc/fonts_disabled.c b/armsrc/fonts_disabled.c index 97079f48a..45a85e679 100644 --- a/armsrc/fonts_disabled.c +++ b/armsrc/fonts_disabled.c @@ -6,7 +6,7 @@ // Fonts for the LCD //----------------------------------------------------------------------------- -#include "fonts.h" +#include "fonts_disabled.h" const char FONT6x8[97][8] = { {0x06, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}, // columns, rows, bytes per char diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 8a0d4934a..7e4c7ca14 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -20,6 +20,8 @@ // Anon, 2019 // Doegox, 2020 +#define DBG if (DBGLEVEL >= DBG_EXTENDED) + #include "hitag2.h" #include "hitag2_crypto.h" #include "string.h" @@ -92,7 +94,7 @@ uint8_t nonce[4]; bool key_no; static uint64_t cipher_state; -size_t blocknr; +int16_t blocknr; size_t flipped_bit = 0; uint32_t byte_value = 0; @@ -305,6 +307,9 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ break; } + // LogTrace(rx, nbytes(rxlen), 0, 0, NULL, false); + // LogTrace(tx, nbytes(txlen), 0, 0, NULL, true); + if (tag.crypto_active) { hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen / 8, *txlen % 8); } @@ -337,12 +342,12 @@ static uint32_t hitag_reader_send_bit(int bit) { lf_wait_periods(HITAG_T_1 - HITAG_T_LOW); // wait for 26-32 times the carrier period wait += HITAG_T_1 - HITAG_T_LOW; } - /*lf_wait_periods(10);*/ + LED_A_OFF(); return wait; } -// reader/writer +// reader / writer commands static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) { uint32_t wait = 0; @@ -403,7 +408,7 @@ void fix_ac_decoding(uint8_t *input, size_t len) { */ -// looks at number of received bits. +// looks at number of received bits. // 0 = collision? // 32 = good response bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) { @@ -539,7 +544,7 @@ bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *t // will receive 32-bit configuration page } else if (bSelecting) { // Initiate auth - tx[0] = 0xa0 | key_no >> 4; // WRCPAGE + tx[0] = 0xa0 | (key_no); // WRCPAGE tx[1] = blocknr << 4; crc = hitag_crc(tx, 12); tx[1] |= crc >> 4; @@ -577,14 +582,15 @@ bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *t Dbhexdump(4, logdata_1, false); bSuccessful = true; return false; - - // read next page of card until done - tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE - tx[1] = blocknr << 4; - crc = hitag_crc(tx, 12); - tx[1] |= crc >> 4; - tx[2] = crc << 4; - *txlen = 20; + /* + // read next page of card until done + tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE + tx[1] = blocknr << 4; + crc = hitag_crc(tx, 12); + tx[1] |= crc >> 4; + tx[2] = crc << 4; + *txlen = 20; + */ } } break; @@ -953,17 +959,18 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t memcpy(tag.sectors[blocknr], rx, 4); blocknr++; - Dbhexdump(4, rx, false); + DBG Dbhexdump(4, rx, false); } if (blocknr > 0) { + DBG DbpString("Read successful!"); bSuccessful = true; - return false; + return true; } } break; // Unexpected response default: { - Dbprintf("Unknown frame length: %d", rxlen); + DBG Dbprintf("Unknown frame length: %d", rxlen); return false; } break; @@ -1017,7 +1024,7 @@ void SniffHitag2(void) { // Receive frame, watch for at most T0*EOF periods - lf_reset_counter(); +// lf_reset_counter(); // Wait "infinite" for reader modulation periods = lf_detect_gap(20000); @@ -1071,8 +1078,6 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) { DbpString("Starting Hitag2 simulation"); - LED_D_ON(); - // hitag2 state machine? hitag2_init(); @@ -1086,7 +1091,7 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) { uint32_t block = 0; for (size_t i = 0; i < 12; i++) { - // num2bytes? + // num2bytes? for (size_t j = 0; j < 4; j++) { block <<= 8; block |= tag.sectors[i][j]; @@ -1094,31 +1099,36 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) { Dbprintf("| %d | %08x |", i, block); } - uint8_t tag_modulation; + uint8_t reader_modulation; size_t max_nrzs = 8 * HITAG_FRAME_LEN + 5; uint8_t nrz_samples[max_nrzs]; size_t nrzs = 0, periods = 0; // uint32_t command_start = 0, command_duration = 0; + // int16_t checked = 0; - int16_t checked = 0; +// SIMULATE while (!BUTTON_PRESS()) { -loop1: + LED_D_ON(); + +// lf_reset_counter(); LED_A_OFF(); WDT_HIT(); - // only every 1000th times, in order to save time when collecting samples. - if (checked == 100) { - if (data_available()) { - checked = -1; - break; - } else { - checked = 0; - } - } - ++checked; + /* + // only every 1000th times, in order to save time when collecting samples. + if (checked == 100) { + if (data_available()) { + checked = -1; + break; + } else { + checked = 0; + } + } + ++checked; + */ rxlen = 0; @@ -1126,10 +1136,10 @@ loop1: bool waiting_for_first_edge = true; // Did we detected any modulaiton at all - bool detected_tag_modulation = false; + bool detected_modulation = false; // Use the current modulation state as starting point - tag_modulation = lf_get_tag_modulation(); + reader_modulation = lf_get_reader_modulation(); // Receive frame, watch for at most max_nrzs periods // Reset the number of NRZ samples and use edge detection to detect them @@ -1141,7 +1151,7 @@ loop1: // Just break out of loop after an initial time-out (tag is probably not available) // The function lf_count_edge_periods() returns 0 when a time-out occurs if (periods == 0) { - goto loop1; //break; + break; } LED_A_ON(); @@ -1159,32 +1169,36 @@ loop1: periods = 16; // We have received more than 0 periods, so we have detected a tag response - detected_tag_modulation = true; + detected_modulation = true; } // Evaluate the number of periods before the next edge if (periods > 24 && periods <= 64) { // Detected two sequential equal bits and a modulation switch // NRZ modulation: (11 => --|) or (11 __|) - nrz_samples[nrzs++] = tag_modulation; - nrz_samples[nrzs++] = tag_modulation; + nrz_samples[nrzs++] = reader_modulation; + nrz_samples[nrzs++] = reader_modulation; // Invert tag modulation state - tag_modulation ^= 1; + reader_modulation ^= 1; } else if (periods > 0 && periods <= 24) { // Detected one bit and a modulation switch // NRZ modulation: (1 => -|) or (0 _|) - nrz_samples[nrzs++] = tag_modulation; - tag_modulation ^= 1; + nrz_samples[nrzs++] = reader_modulation; + reader_modulation ^= 1; } else { - tag_modulation ^= 1; + reader_modulation ^= 1; // The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods Dbprintf("Detected unexpected period count: %d", periods); break; } } + LED_D_OFF(); + // If there is no response, just repeat the loop - if (!detected_tag_modulation) continue; + if (!detected_modulation) continue; + + LED_A_OFF(); // Make sure we always have an even number of samples. This fixes the problem // of ending the manchester decoding with a zero. See the example below where @@ -1194,7 +1208,7 @@ loop1: // The last modulation change of a zero is not detected, but we should take // the half period in account, otherwise the demodulator will fail. if ((nrzs % 2) != 0) { - nrz_samples[nrzs++] = tag_modulation; + nrz_samples[nrzs++] = reader_modulation; } LED_B_ON(); @@ -1206,8 +1220,8 @@ loop1: if (nrzs < 5) { Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs); continue; - } else { - for (size_t i = 0; i < 5; i++){ + } else { + for (size_t i = 0; i < 5; i++) { if (nrz_samples[i] != 1) { Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one", i); } @@ -1215,7 +1229,7 @@ loop1: } // Pack the response into a byte array - for (size_t i = 5; i < 37; i++){ + for (size_t i = 5; i < 37; i++) { uint8_t bit = nrz_samples[i]; rx[rxlen / 8] |= bit << (7 - (rxlen % 8)); rxlen++; @@ -1233,8 +1247,8 @@ loop1: // not that since the clock counts since the rising edge, but T_Wait1 is // with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low) // periods. The gap time T_Low varies (4..10). All timer values are in - // terms of T0 units - lf_wait_periods(200); + // terms of T0 units (HITAG_T_WAIT_1_MIN - HITAG_T_LOW ) + lf_wait_periods(HITAG_T_WAIT_1_MIN); // Send and store the tag answer (if there is any) if (txlen) { @@ -1266,19 +1280,19 @@ loop1: void ReaderHitag(hitag_function htf, hitag_data *htd) { - uint32_t command_start = 0; - uint32_t command_duration = 0; - uint32_t response_start = 0; - uint32_t response_duration = 0; + uint32_t command_start = 0, command_duration = 0; + uint32_t response_start = 0, response_duration = 0; + uint8_t rx[HITAG_FRAME_LEN]; size_t rxlen = 0; uint8_t txbuf[HITAG_FRAME_LEN]; uint8_t *tx = txbuf; size_t txlen = 0; - int t_wait_1; + + int t_wait_1 = 204; int t_wait_1_guard = 8; - int t_wait_2; - size_t tag_size; + int t_wait_2 = 128; + size_t tag_size = 48; bool bStop = false; // Raw demodulation/decoding by sampling edge periods @@ -1292,19 +1306,17 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { set_tracing(true); clear_trace(); - DbpString("Starting Hitag reader family"); - // Check configuration switch (htf) { case RHT1F_PLAIN: { - Dbprintf("Read public blocks in plain mode"); + DBG Dbprintf("Read public blocks in plain mode"); // this part will be unreadable memset(tag.sectors + 2, 0x0, 30); blocknr = 0; break; } case RHT1F_AUTHENTICATE: { - Dbprintf("Read all blocks in authed mode"); + DBG Dbprintf("Read all blocks in authed mode"); memcpy(nonce, htd->ht1auth.nonce, 4); memcpy(key, htd->ht1auth.key, 4); memcpy(logdata_0, htd->ht1auth.logdata_0, 4); @@ -1314,19 +1326,19 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { memset(logdata_1, 0x00, 4); byte_value = 0; key_no = htd->ht1auth.key_no; - Dbprintf("Authenticating using key #%d:", key_no); - Dbhexdump(4, key, false); - DbpString("Nonce:"); - Dbhexdump(4, nonce, false); - DbpString("Logdata_0:"); - Dbhexdump(4, logdata_0, false); - DbpString("Logdata_1:"); - Dbhexdump(4, logdata_1, false); + DBG Dbprintf("Authenticating using key #%d:", key_no); + DBG Dbhexdump(4, key, false); + DBG DbpString("Nonce:"); + DBG Dbhexdump(4, nonce, false); + DBG DbpString("Logdata_0:"); + DBG Dbhexdump(4, logdata_0, false); + DBG DbpString("Logdata_1:"); + DBG Dbhexdump(4, logdata_1, false); blocknr = 0; break; } case RHT2F_PASSWORD: { - Dbprintf("List identifier in password mode"); + DBG Dbprintf("List identifier in password mode"); if (memcmp(htd->pwd.password, "\x00\x00\x00\x00", 4) == 0) memcpy(password, tag.sectors[1], sizeof(password)); else @@ -1338,19 +1350,19 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { break; } case RHT2F_AUTHENTICATE: { - DbpString("Authenticating using nr,ar pair:"); + DBG DbpString("Authenticating using nr,ar pair:"); memcpy(NrAr, htd->auth.NrAr, 8); - Dbhexdump(8, NrAr, false); + DBG Dbhexdump(8, NrAr, false); bCrypto = false; bAuthenticating = false; break; } case RHT2F_CRYPTO: { - DbpString("Authenticating using key:"); + DBG DbpString("Authenticating using key:"); memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code. - Dbhexdump(6, key, false); - DbpString("Nonce:"); - Dbhexdump(4, nonce, false); + DBG Dbhexdump(6, key, false); + DBG DbpString("Nonce:"); + DBG Dbhexdump(4, nonce, false); memcpy(nonce, htd->crypto.data, 4); blocknr = 0; bCrypto = false; @@ -1358,7 +1370,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { break; } case RHT2F_TEST_AUTH_ATTEMPTS: { - Dbprintf("Testing %d authentication attempts", (auth_table_len / 8)); + DBG Dbprintf("Testing %d authentication attempts", (auth_table_len / 8)); auth_table_pos = 0; memcpy(NrAr, auth_table, 8); bCrypto = false; @@ -1371,7 +1383,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { break; } default: { - Dbprintf("Error, unknown function: %d", htf); + DBG Dbprintf("Error, unknown function: %d", htf); set_tracing(false); return; } @@ -1382,9 +1394,6 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { // hitag2 state machine? hitag2_init(); - // init as reader - lf_init(true, false); - uint8_t attempt_count = 0; // Tag specific configuration settings (sof, timings, etc.) @@ -1392,41 +1401,40 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { // hitagS settings t_wait_1 = 204; t_wait_2 = 128; - /*tag_size = 256;*/ flipped_bit = 0; tag_size = 8; - DbpString("Configured for hitagS reader"); + DBG DbpString("Configured for hitagS reader"); } else if (htf < 20) { // hitag1 settings t_wait_1 = 204; t_wait_2 = 128; tag_size = 256; flipped_bit = 0; - DbpString("Configured for hitag1 reader"); + DBG DbpString("Configured for hitag1 reader"); } else if (htf < 30) { // hitag2 settings t_wait_1 = HITAG_T_WAIT_1_MIN; t_wait_2 = HITAG_T_WAIT_2_MIN; tag_size = 48; - DbpString("Configured for hitag2 reader"); - } else { - Dbprintf("Error, unknown hitag reader type: %d", htf); - return; + DBG DbpString("Configured for hitag2 reader"); } + // init as reader + lf_init(true, false); + uint8_t tag_modulation; size_t max_nrzs = (8 * HITAG_FRAME_LEN + 5) * 2; // up to 2 nrzs per bit uint8_t nrz_samples[max_nrzs]; size_t nrzs = 0; int16_t checked = 0; - while (!bStop) { + while (!bStop && !BUTTON_PRESS()) { WDT_HIT(); // only every 1000th times, in order to save time when collecting samples. if (checked == 1000) { - if (BUTTON_PRESS() || data_available()) { + if (data_available()) { checked = -1; break; } else { @@ -1471,7 +1479,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { break; } default: { - Dbprintf("Error, unknown function: %d", htf); + DBG Dbprintf("Error, unknown function: %d", htf); goto out; } } @@ -1531,7 +1539,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { } else { // The function lf_count_edge_periods() returns 0 when a time-out occurs if (periods == 0) { - //Dbprintf("Detected timeout after [%d] nrz samples", nrzs); + DBG Dbprintf("Detected timeout after [%d] nrz samples", nrzs); break; } } @@ -1552,7 +1560,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { tag_modulation ^= 1; } else { // The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods - //Dbprintf("Detected unexpected period count: %d", periods); + DBG Dbprintf("Detected unexpected period count: %d", periods); break; } } @@ -1591,13 +1599,13 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { // Verify if the header consists of five consecutive ones if (nrzs < 5) { - Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs); + DBG Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs); break; } else { size_t i; for (i = 0; i < 5; i++) { if (nrz_samples[i] != 1) { - Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one, abort", i); + DBG Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one, abort", i); break; } } @@ -1608,7 +1616,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { for (size_t i = 5; i < nrzs; i++) { uint8_t bit = nrz_samples[i]; if (bit > 1) { // When Manchester detects impossible symbol it writes "7" - Dbprintf("Error in Manchester decoding, abort"); + DBG Dbprintf("Error in Manchester decoding, abort"); break; } rx[rxlen / 8] |= bit << (7 - (rxlen % 8)); @@ -1648,16 +1656,18 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { uint32_t command_start = 0; uint32_t command_duration = 0; uint32_t response_start = 0; - uint32_t response_duration = 0; + uint32_t response_duration = 0; uint8_t rx[HITAG_FRAME_LEN]; size_t rxlen = 0; uint8_t txbuf[HITAG_FRAME_LEN]; uint8_t *tx = txbuf; size_t txlen = 0; - int t_wait_1; + + int t_wait_1 = 204; int t_wait_1_guard = 8; - int t_wait_2; - size_t tag_size; + int t_wait_2 = 128; + size_t tag_size = 48; + bool bStop = false; // Raw demodulation/decoding by sampling edge periods @@ -1671,8 +1681,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { set_tracing(true); clear_trace(); - DbpString("Starting Hitag writer family"); - + // Check configuration switch (htf) { case WHT2F_CRYPTO: { @@ -1710,7 +1719,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { // init as reader lf_init(true, false); - + // Tag specific configuration settings (sof, timings, etc.) if (htf < 10) { // hitagS settings @@ -1721,21 +1730,18 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { tag_size = 8; DbpString("Configured for hitagS writer"); } else if (htf < 20) { - // hitag1 settings + // hitag1 settings t_wait_1 = 204; t_wait_2 = 128; tag_size = 256; flipped_bit = 0; DbpString("Configured for hitag1 writer"); } else if (htf < 30) { - // hitag2 settings + // hitag2 settings t_wait_1 = HITAG_T_WAIT_1_MIN; t_wait_2 = HITAG_T_WAIT_2_MIN; tag_size = 48; DbpString("Configured for hitag2 writer"); - } else { - Dbprintf("Error, unknown hitag writer type: %d", htf); - return; } uint8_t tag_modulation; @@ -1744,11 +1750,11 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { size_t nrzs = 0; int16_t checked = 0; - while (!bStop) { + while (!bStop && !BUTTON_PRESS()) { // only every 1000th times, in order to save time when collecting samples. if (checked == 1000) { - if (BUTTON_PRESS() || data_available()) { + if (data_available()) { checked = -1; break; } else { @@ -1776,7 +1782,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { } } - // Wait for t_wait_2 carrier periods after the last tag bit before transmitting, + // Wait for t_wait_2 carrier periods after the last tag bit before transmitting, lf_wait_periods(t_wait_2); command_start += t_wait_2; diff --git a/armsrc/hitag2crack.c b/armsrc/hitag2crack.c index c6b61b019..34d35ada6 100644 --- a/armsrc/hitag2crack.c +++ b/armsrc/hitag2crack.c @@ -11,7 +11,7 @@ // hitag2 attack functions //----------------------------------------------------------------------------- -#include "hitagcrypto.h" +#include "hitag2_crypto.h" #include "hitag2crack.h" #define READP0CMD "1100000111" @@ -38,70 +38,60 @@ bool hitag2_crack(uint8_t *response, uint8_t *nrarhex) { uint8_t temp[20]; int i; uint8_t *spaceptr = NULL; - + // get uid as hexstring - if(!hitag2_get_uid(uidhex)) - { + if (!hitag2_get_uid(uidhex)) { UserMessage("Cannot get UID\r\n"); return false; } // convert uid hexstring to binarray hextobinarray(uid, uidhex); - + // convert nR and aR hexstrings to binarray spaceptr = strchr(nrarhex, ' '); - if (!spaceptr) - { + if (!spaceptr) { UserMessage("Please supply a valid nR aR pair\r\n"); return false; } *spaceptr = 0x00; - - if (hextobinarray(nrar, nrarhex) != 32) - { + + if (hextobinarray(nrar, nrarhex) != 32) { UserMessage("nR is not 32 bits long\r\n"); return false; } - - if (hextobinarray(nrar + 32, spaceptr + 1) != 32) - { + + if (hextobinarray(nrar + 32, spaceptr + 1) != 32) { UserMessage("aR is not 32 bits long\r\n"); return false; } // find a valid encrypted command - if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) - { + if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) { UserMessage("Cannot find a valid encrypted command\r\n"); return false; } - + // find the 'read page 0' command and recover key stream - if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) - { + if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) { UserMessage("Cannot find encrypted 'read page0' command\r\n"); return false; } - + // empty the response string response[0] = 0x00; - + // read all pages using key stream - for (i=0; i<8; i++) - { - if (hitag2crack_read_page(pagehex, i, nrar, keybits)) - { + for (i = 0; i < 8; i++) { + if (hitag2crack_read_page(pagehex, i, nrar, keybits)) { sprintf(temp, "%1d: %s\r\n", i, pagehex); - } - else - { + } else { sprintf(temp, "%1d:\r\n", i); } // add page string to response strcat(response, temp); } - + return true; } @@ -113,16 +103,16 @@ bool hitag2_crack(uint8_t *response, uint8_t *nrarhex) { bool hitag2crack_find_valid_e_cmd(uint8_t e_cmd[], uint8_t nrar[]) { uint8_t guess[10]; uint8_t responsestr[9]; - + // UserMessage("Finding valid encrypted command:"); // we're going to hold bits 5, 7, 8 and 9 and brute force the rest // e.g. x x x x x 0 x 0 0 0 - for (uint8_t a=0; a<2; a++) { - for (uint8_t b=0; b<2; b++) { - for (uint8_t c=0; c<2; c++) { - for (uint8_t d=0; d<2; d++) { - for (uint8_t e=0; e<2; e++) { - for (uint8_t g=0; g<2; g++) { + for (uint8_t a = 0; a < 2; a++) { + for (uint8_t b = 0; b < 2; b++) { + for (uint8_t c = 0; c < 2; c++) { + for (uint8_t d = 0; d < 2; d++) { + for (uint8_t e = 0; e < 2; e++) { + for (uint8_t g = 0; g < 2; g++) { // build binarray guess[0] = a; guess[1] = b; @@ -175,65 +165,50 @@ bool hitag2crack_find_e_page0_cmd(uint8_t keybits[], uint8_t e_firstcmd[], uint8 UserMessage("Finding 'read page 0' command:"); // we're going to brute the missing 4 bits of the valid encrypted command - for (a=0; a<2; a++) - { - for (b=0; b<2; b++) - { - for (c=0; c<2; c++) - { - for (d=0; d<2; d++) - { + for (a = 0; a < 2; a++) { + for (b = 0; b < 2; b++) { + for (c = 0; c < 2; c++) { + for (d = 0; d < 2; d++) { // create our guess by bit flipping the pattern of bits // representing the inverted bit and the 3 page bits // in both the non-inverted and inverted parts of the // encrypted command. memcpy(guess, e_firstcmd, 10); - if (a) - { + if (a) { guess[5] = !guess[5]; guess[0] = !guess[0]; } - if (b) - { + if (b) { guess[7] = !guess[7]; guess[2] = !guess[2]; } - if (c) - { + if (c) { guess[8] = !guess[8]; guess[3] = !guess[3]; } - if (d) - { + if (d) { guess[9] = !guess[9]; guess[4] = !guess[4]; } - + // try the guess - if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10)) - { + if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10)) { // check if it was valid - if (strcmp(responsestr, ERROR_RESPONSE) != 0) - { + if (strcmp(responsestr, ERROR_RESPONSE) != 0) { // convert response to binarray hextobinarray(e_uid, responsestr); // test if the guess was 'read page 0' command - if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid)) - { - + if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid)) { + return true; } - } - else - { + } else { #ifdef RFIDLER_DEBUG UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n"); #endif } - } - else - { - #ifdef RFIDLER_DEBUG + } else { +#ifdef RFIDLER_DEBUG UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd failed\r\n"); #endif } @@ -262,56 +237,51 @@ bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, u uint8_t e_ext_cmd[40]; uint8_t responsestr[9]; int i; - + // copy encrypted cmd to cipherbits memcpy(cipherbits, e_cmd, 10); - + // copy encrypted uid to cipherbits memcpy(cipherbits + 10, e_uid, 32); - + // copy cmd to plainbits binstringtobinarray(plainbits, READP0CMD); - + // copy uid to plainbits memcpy(plainbits + 10, uid, 32); // xor the plainbits with the cipherbits to get keybits hitag2crack_xor(keybits, plainbits, cipherbits, 42); - + // create extended cmd -> 4 * READP0CMD = 40 bits - for (i=0; i<4; i++) - { + for (i = 0; i < 4; i++) { binstringtobinarray(ext_cmd + (i * 10), READP0CMD); } - + // xor extended cmd with keybits hitag2crack_xor(e_ext_cmd, ext_cmd, keybits, 40); - + // send extended encrypted cmd - if (hitag2crack_send_e_cmd(responsestr, nrar, e_ext_cmd, 40)) - { + if (hitag2crack_send_e_cmd(responsestr, nrar, e_ext_cmd, 40)) { // test if it was valid - if (strcmp(responsestr, ERROR_RESPONSE) != 0) - { + if (strcmp(responsestr, ERROR_RESPONSE) != 0) { return true; } - } - else - { + } else { #ifdef RFIDLER_DEBUG UserMessage("hitag2crack_test_e_p0cmd:\r\n hitag2crack_send_e_cmd failed\r\n"); #endif } - + return false; - + } // hitag2crack_xor XORs the source with the pad to produce the target. // source, target and pad are binarrays of length len. void hitag2crack_xor(uint8_t *target, uint8_t *source, uint8_t *pad, unsigned int len) { - for (int i=0; i 7)) - { + + if (pagenum > 7) { UserMessage("hitag2crack_read_page:\r\n invalid pagenum\r\n"); return false; } - + // create cmd binstringtobinarray(cmd, READP0CMD); - if (pagenum & 0x1) - { + if (pagenum & 0x1) { cmd[9] = !cmd[9]; cmd[4] = !cmd[4]; } - if (pagenum & 0x2) - { + if (pagenum & 0x2) { cmd[8] = !cmd[8]; cmd[3] = !cmd[3]; } - if (pagenum & 0x4) - { + if (pagenum & 0x4) { cmd[7] = !cmd[7]; cmd[2] = !cmd[2]; } - + // encrypt command hitag2crack_xor(e_cmd, cmd, keybits, 10); - + // send encrypted command - if (hitag2crack_send_e_cmd(e_responsestr, nrar, e_cmd, 10)) - { + if (hitag2crack_send_e_cmd(e_responsestr, nrar, e_cmd, 10)) { // check if it is valid - if (strcmp(e_responsestr, ERROR_RESPONSE) != 0) - { + if (strcmp(e_responsestr, ERROR_RESPONSE) != 0) { // convert to binarray hextobinarray(e_response, e_responsestr); // decrypt response @@ -370,17 +334,13 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar, // convert to hexstring binarraytohex(responsestr, response, 32); return true; - } - else - { + } else { UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n"); } - } - else - { + } else { UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd failed\r\n"); } - + return false; } @@ -391,14 +351,13 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar, // cmd is the binarray of the encrypted command to send; // len is the length of the encrypted command. bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, int len) { - uint8_t tmp[37]; +// uint8_t tmp[37]; uint8_t uid[9]; uint8_t e_page3str[9]; int ret = 0; // get the UID - if(!hitag2_get_uid(uid)) - { + if (!hitag2_get_uid(uid)) { UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID\r\n"); return false; } @@ -407,22 +366,19 @@ bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, i CryptoActive = false; // get the UID again - if(!hitag2_get_uid(uid)) - { + if (!hitag2_get_uid(uid)) { UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID (2nd time)\r\n"); return false; } - + // send nrar and receive (useless) encrypted page 3 value - if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) - { + if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) { UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx nrar failed\r\n"); return false; } - + // send encrypted command - if (!hitag2crack_tx_rx(responsestr, cmd, len, RWD_STATE_WAKING, false)) - { + if (!hitag2crack_tx_rx(responsestr, cmd, len, RWD_STATE_WAKING, false)) { #ifdef RFIDLER_DEBUG UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx cmd failed\r\n"); #endif @@ -442,34 +398,29 @@ bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, b int ret = 0; // START_AUTH kills active crypto session - CryptoActive= false; - - if(!rwd_send(msg, len, reset, BLOCK, state, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX)) - { + CryptoActive = false; + + if (!rwd_send(msg, len, reset, BLOCK, state, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX)) { UserMessage("hitag2crack_tx_rx: rwd_send failed\r\n"); return false; } - + // skip 1/2 bit to synchronise manchester HW_Skip_Bits = 1; ret = read_ask_data(RFIDlerConfig.FrameClock, RFIDlerConfig.DataRate, tmp, 37, RFIDlerConfig.Sync, RFIDlerConfig.SyncBits, RFIDlerConfig.Timeout, ONESHOT_READ, BINARY); // check if response was a valid length (5 sync bits + 32 bits response) - if (ret == 37) - { + if (ret == 37) { // check sync bits - if (memcmp(tmp, Hitag2Sync, 5) != 0) - { + if (memcmp(tmp, Hitag2Sync, 5) != 0) { UserMessage("hitag2crack_tx_rx: no sync\r\n"); return false; } - + // convert response to hexstring binarraytohex(responsestr, tmp + 5, 32); return true; - } - else - { + } else { #ifdef RFIDLER_DEBUG UserMessage("hitag2crack_tx_rx: wrong rx len\r\n"); #endif @@ -485,58 +436,53 @@ bool hitag2crack_rng_init(uint8_t *response, uint8_t *input) { uint32_t initvector; uint8_t *spaceptr; uint8_t *dataptr; - + // extract vals from input dataptr = input; spaceptr = strchr(dataptr, ' '); - if (!spaceptr) - { + if (!spaceptr) { UserMessage("/r/nformat is 'sharedkey UID nR' in hex\r\n"); return false; } - + *spaceptr = 0x00; - - if (strlen(dataptr) != 12) - { + + if (strlen(dataptr) != 12) { UserMessage("/r/nsharedkey should be 48 bits long (12 hexchars)\r\n"); return false; } sharedkey = rev64(hexreversetoulonglong(dataptr)); - - dataptr = spaceptr+1; + + dataptr = spaceptr + 1; spaceptr = strchr(dataptr, ' '); - if (!spaceptr) - { + if (!spaceptr) { UserMessage("/r/nno UID\r\n"); return false; } - + *spaceptr = 0x00; - if (strlen(dataptr) != 8) - { + if (strlen(dataptr) != 8) { UserMessage("/r/nUID should be 32 bits long (8 hexchars)\r\n"); return false; } - + serialnum = rev32(hexreversetoulong(dataptr)); - - dataptr = spaceptr+1; - - if (strlen(dataptr) != 8) - { + + dataptr = spaceptr + 1; + + if (strlen(dataptr) != 8) { UserMessage("/r/nnR should be 32 bits long (8 hexchars)\r\n"); return false; } - + initvector = rev32(hexreversetoulong(dataptr)); - + // start up crypto engine hitag2_init(&Hitag_Crypto_State, sharedkey, serialnum, initvector); - + strcpy(response, "Success\r\n"); - + return true; } @@ -545,21 +491,20 @@ bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex) { uint8_t binhex[9]; uint8_t binstr[33]; uint32_t binulong; - - if (strlen(hex) != 8) - { + + if (strlen(hex) != 8) { UserMessage("/r/nhex must be 32bits (8 hex chars)\r\n"); return false; } - + binulong = hextoulong(hex); - + ulongtobinarray(bin, hitag2_crypt(binulong, 32), 32); binarraytobinstring(binstr, bin, 32); binarraytohex(binhex, bin, 32); // UserMessage("ar = %s\r\n", binstr); // UserMessage("arhex = %s\r\n", binhex); - + strcpy(response, binhex); return true; } @@ -570,17 +515,16 @@ bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *e_binstr) { uint8_t binstr[33]; uint32_t binulong; int len; - + len = strlen(e_binstr); - if (len > 32) - { + if (len > 32) { UserMessage("\r\nbinary string must be <= 32 bits\r\n"); return false; } - + binstringtobinarray(e_bin, e_binstr); binulong = binarraytoulong(e_bin, len); - + ulongtobinarray(bin, hitag2_crypt(binulong, len), len); binarraytobinstring(binstr, bin, len); strcpy(response, binstr); @@ -595,7 +539,7 @@ bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex) { bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *e_binstr) { return hitag2crack_decrypt_bin(response, e_binstr); } - + // hitag2_keystream uses the first crack algorithm described in the paper, // Gone In 360 Seconds by Verdult, Garcia and Balasch, to retrieve 2048 bits // of keystream. @@ -607,113 +551,101 @@ bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex) { uint8_t uid[32]; uint8_t nrar[64]; uint8_t e_firstcmd[10]; - uint8_t e_page0cmd[10]; +// uint8_t e_page0cmd[10]; // uint8_t keybits[2080]; uint8_t *keybits = DataBuff; uint8_t keybitshex[67]; int kslen; int ksoffset; - uint8_t pagehex[9]; - uint8_t temp[20]; +// uint8_t pagehex[9]; +// uint8_t temp[20]; int i; uint8_t *spaceptr = NULL; -/* - keybits = malloc(2080); - if (!keybits) { - UserMessage("cannot malloc keybits\r\n"); - return false; - } -*/ - + /* + keybits = malloc(2080); + if (!keybits) { + UserMessage("cannot malloc keybits\r\n"); + return false; + } + */ + // get uid as hexstring - if(!hitag2_get_uid(uidhex)) - { + if (!hitag2_get_uid(uidhex)) { UserMessage("Cannot get UID\r\n"); return false; } // convert uid hexstring to binarray hextobinarray(uid, uidhex); - + // convert nR and aR hexstrings to binarray spaceptr = strchr(nrarhex, ' '); - if (!spaceptr) - { + if (!spaceptr) { UserMessage("Please supply a valid nR aR pair\r\n"); return false; } *spaceptr = 0x00; - - if (hextobinarray(nrar, nrarhex) != 32) - { + + if (hextobinarray(nrar, nrarhex) != 32) { UserMessage("nR is not 32 bits long\r\n"); return false; } - - if (hextobinarray(nrar + 32, spaceptr + 1) != 32) - { + + if (hextobinarray(nrar + 32, spaceptr + 1) != 32) { UserMessage("aR is not 32 bits long\r\n"); return false; } // find a valid encrypted command - if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) - { + if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) { UserMessage("Cannot find a valid encrypted command\r\n"); return false; } - + // find the 'read page 0' command and recover key stream - if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) - { + if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) { UserMessage("Cannot find encrypted 'read page0' command\r\n"); return false; } - + // using the 40 bits of keystream in keybits, sending commands with ever // increasing lengths to acquire 2048 bits of key stream. kslen = 40; - - while (kslen < 2048) - { + + while (kslen < 2048) { ksoffset = 0; - if (!hitag2crack_send_auth(nrar)) - { + if (!hitag2crack_send_auth(nrar)) { UserMessage("hitag2crack_send_auth failed\r\n"); return false; } // while we have at least 52 bits of keystream, consume it with // extended read page 0 commands. 52 = 10 (min command len) + // 32 (response) + 10 (min command len we'll send) - while ((kslen - ksoffset) >= 52) - { + while ((kslen - ksoffset) >= 52) { // consume the keystream, updating ksoffset as we go - if (!hitag2crack_consume_keystream(keybits, kslen, &ksoffset, nrar)) - { + if (!hitag2crack_consume_keystream(keybits, kslen, &ksoffset, nrar)) { UserMessage("hitag2crack_consume_keystream failed\r\n"); return false; } } // send an extended command to retrieve more keystream, updating kslen // as we go - if (!hitag2crack_extend_keystream(keybits, &kslen, ksoffset, nrar, uid)) - { + if (!hitag2crack_extend_keystream(keybits, &kslen, ksoffset, nrar, uid)) { UserMessage("hitag2crack_extend_keystream failed\r\n"); return false; } UserMessage("Recovered %d bits of keystream\r\n", kslen); } - - for (i=0; i<2048; i+=256) - { + + for (i = 0; i < 2048; i += 256) { binarraytohex(keybitshex, keybits + i, 256); UserMessage("%s\r\n", keybitshex); } response[0] = 0x00; - + return true; } @@ -724,8 +656,7 @@ bool hitag2crack_send_auth(uint8_t *nrar) { uint8_t e_page3str[9]; // get the UID - if(!hitag2_get_uid(uid)) - { + if (!hitag2_get_uid(uid)) { UserMessage("hitag2crack_send_auth:\r\n cannot get UID\r\n"); return false; } @@ -734,15 +665,13 @@ bool hitag2crack_send_auth(uint8_t *nrar) { CryptoActive = false; // get the UID again - if(!hitag2_get_uid(uid)) - { + if (!hitag2_get_uid(uid)) { UserMessage("hitag2crack_send_auth:\r\n cannot get UID (2nd time)\r\n"); return false; } - + // send nrar and receive (useless) encrypted page 3 value - if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) - { + if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) { UserMessage("hitag2crack_send_auth:\r\n tx/rx nrar failed\r\n"); return false; } @@ -767,46 +696,41 @@ bool hitag2crack_consume_keystream(uint8_t *keybits, int kslen, int *ksoffset, u // 42 = 32 bit response + 10 bit command reserved for next command. conlen // cannot be longer than 510 bits to fit into the small RWD buffer. conlen = kslen - *ksoffset - 42; - if (conlen < 10) - { + if (conlen < 10) { UserMessage("hitag2crack_consume_keystream:\r\n conlen < 10\r\n"); return false; } - + // sanitise conlen - if (conlen > 510) - { + if (conlen > 510) { conlen = 510; } - + // calculate how many repeated commands to send in this extended command. numcmds = conlen / 10; - + // build extended command - for (i=0; i= DBG_EXTENDED) + Dbprintf("hitag_send_frame: (%i) %02X %02X %02X %02X", frame_len, frame[0], frame[1], frame[2], frame[3]); + // The beginning of the frame is hidden in some high level; pause until our bits will have an effect + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + HIGH(GPIO_SSC_DOUT); + switch (m) { + case AC4K: + case MC8K: + while (AT91C_BASE_TC0->TC_CV < T0 * 40) {}; //FADV + break; + case AC2K: + case MC4K: + while (AT91C_BASE_TC0->TC_CV < T0 * 20) {}; //STD + ADV + break; + } + // SOF - send start of frame for (size_t i = 0; i < sof_bits; i++) { hitag_send_bit(1); @@ -299,6 +333,25 @@ static int check_select(uint8_t *rx, uint32_t uid) { return 0; } +void hitagS_set_frame_modulation() { + switch (tag.mode) { + case HT_STANDARD: + sof_bits = 1; + m = MC4K; + break; + case HT_ADVANCED: + sof_bits = 6; + m = MC4K; + break; + case HT_FAST_ADVANCED: + sof_bits = 6; + m = MC8K; + break; + default: + break; + } +} + /* * handles all commands from a reader */ @@ -318,20 +371,28 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, switch (rxlen) { case 5: { //UID request with a selected response protocol mode + if (DBGLEVEL >= DBG_EXTENDED) + Dbprintf("UID request: length: %i first byte: %02x", rxlen, rx[0]); tag.pstate = HT_READY; tag.tstate = HT_NO_OP; if ((rx[0] & 0xf0) == 0x30) { + if (DBGLEVEL >= DBG_EXTENDED) + Dbprintf("HT_STANDARD"); tag.mode = HT_STANDARD; sof_bits = 1; m = AC2K; } if ((rx[0] & 0xf0) == 0xc0) { tag.mode = HT_ADVANCED; + if (DBGLEVEL >= DBG_EXTENDED) + Dbprintf("HT_ADVANCED"); sof_bits = 3; m = AC2K; } if ((rx[0] & 0xf0) == 0xd0) { + if (DBGLEVEL >= DBG_EXTENDED) + Dbprintf("HT_FAST_ADVANCED"); tag.mode = HT_FAST_ADVANCED; sof_bits = 3; m = AC4K; @@ -344,29 +405,18 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, break; case 45: { //select command from reader received + if (DBGLEVEL >= DBG_EXTENDED) + DbpString("SELECT"); if (check_select(rx, tag.uid) == 1) { + if (DBGLEVEL >= DBG_EXTENDED) + DbpString("SELECT match"); //if the right tag was selected *txlen = 32; - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + hitagS_set_frame_modulation(); //send configuration for (int i = 0; i < 4; i++) - tx[i] = (tag.pages[0][1] >> (i * 8)) & 0xff; + tx[i] = tag.pages[1][i]; tx[3] = 0xff; if (tag.mode != HT_STANDARD) { *txlen = 40; @@ -390,22 +440,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, Dbprintf(",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}", rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + hitagS_set_frame_modulation(); for (int i = 0; i < 4; i++) _hitag2_byte(&state); @@ -438,7 +473,10 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, } */ } + break; case 40: + if (DBGLEVEL >= DBG_EXTENDED) + Dbprintf("WRITE"); //data received to be written if (tag.tstate == HT_WRITING_PAGE_DATA) { tag.tstate = HT_NO_OP; @@ -448,44 +486,14 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, *txlen = 2; tx[0] = 0x40; page_to_be_written = 0; - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + hitagS_set_frame_modulation(); } else if (tag.tstate == HT_WRITING_BLOCK_DATA) { tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0] << 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3]; //send ack *txlen = 2; tx[0] = 0x40; - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + hitagS_set_frame_modulation(); page_to_be_written++; block_data_left--; if (block_data_left == 0) { @@ -500,29 +508,14 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, //send page data uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); *txlen = 32; - tx[0] = (tag.pages[page / 4][page % 4]) & 0xff; - tx[1] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; - tx[2] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; - tx[3] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; + tx[0] = tag.pages[page][0]; + tx[1] = tag.pages[page][1]; + tx[2] = tag.pages[page][2]; + tx[3] = tag.pages[page][3]; if (tag.LKP && page == 1) tx[3] = 0xff; - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + hitagS_set_frame_modulation(); if (tag.mode != HT_STANDARD) { //add crc8 @@ -543,29 +536,13 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, *txlen = 32 * 4; //send page,...,page+3 data for (int i = 0; i < 4; i++) { - tx[0 + i * 4] = (tag.pages[page / 4][page % 4]) & 0xff; - tx[1 + i * 4] = (tag.pages[page / 4][page % 4] >> 8) & 0xff; - tx[2 + i * 4] = (tag.pages[page / 4][page % 4] >> 16) & 0xff; - tx[3 + i * 4] = (tag.pages[page / 4][page % 4] >> 24) & 0xff; - page++; + tx[0 + i * 4] = tag.pages[page + 0 + i * 4][0]; + tx[1 + i * 4] = tag.pages[page + 1 + i * 4][1]; + tx[2 + i * 4] = tag.pages[page + 2 + i * 4][2]; + tx[3 + i * 4] = tag.pages[page + 3 + i * 4][3]; } - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + hitagS_set_frame_modulation(); if (tag.mode != HT_STANDARD) { //add crc8 @@ -576,29 +553,12 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, tx[16] = crc; } - if ((page - 4) % 4 != 0 || (tag.LKP && (page - 4) == 0)) { + if ((page) % 4 != 0 || (tag.LKP && (page) == 0)) { sof_bits = 0; *txlen = 0; } } else if ((rx[0] & 0xf0) == 0x80) { //write page uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16); - - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } if ((tag.LCON && page == 1) || (tag.LKP && (page == 2 || page == 3))) { //deny @@ -613,22 +573,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, } else if ((rx[0] & 0xf0) == 0x90) { //write block uint8_t page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16); - switch (tag.mode) { - case HT_STANDARD: - sof_bits = 1; - m = MC4K; - break; - case HT_ADVANCED: - sof_bits = 6; - m = MC4K; - break; - case HT_FAST_ADVANCED: - sof_bits = 6; - m = MC8K; - break; - default: - break; - } + hitagS_set_frame_modulation(); if (page % 4 != 0 || page == 0) { //deny *txlen = 0; @@ -644,7 +589,8 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen, } break; default: - + if (DBGLEVEL >= DBG_EXTENDED) + Dbprintf("unknown rxlen: (%i) %02X %02X %02X %02X ...", rxlen, rx[0], rx[1], rx[2], rx[3]); break; } } @@ -722,7 +668,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA | (uid[30] << 1) | uid[31]; - if (DEBUG) + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4); tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1); @@ -816,7 +762,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA tag.LCK1 = response_bit[26]; tag.LCK0 = response_bit[27]; - if (DEBUG) + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]); if (tag.auth == 1) { @@ -839,7 +785,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA tx[5] = auth_ks[1]; tx[6] = auth_ks[2]; tx[7] = auth_ks[3]; - if (DEBUG) + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X", tx[0], tx[1], tx[2], tx[3], tx[4], tx[5], tx[6], tx[7]); } else if (htf == 01 || htf == 03) { //RHTS_CHALLENGE //WHTS_CHALLENGE @@ -864,7 +810,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8); calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8); calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8); - if (DEBUG) { + if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf("UID:::%X", tag.uid); Dbprintf("RND:::%X", rnd); } @@ -884,7 +830,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) ^ _hitag2_byte(&state); } - if (DEBUG) + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1); //Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16)); @@ -930,28 +876,30 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) { tag.pstate = HT_READY; tag.tstate = HT_NO_OP; - for (i = 0; i < 16; i++) - for (j = 0; j < 4; j++) - tag.pages[i][j] = 0x0; - // read tag data into memory if (tag_mem_supplied) { + for (i = 0; i < 16; i++) + for (j = 0; j < 4; j++) + tag.pages[i][j] = 0x0; + DbpString("Loading hitagS memory..."); memcpy((uint8_t *)tag.pages, data, 4 * 64); + } else { + // use the last read tag } - tag.uid = (uint32_t)tag.pages[0]; - tag.key = (intptr_t)tag.pages[3]; + tag.uid = ((tag.pages[0][3]) << 24) | ((tag.pages[0][2]) << 16) | ((tag.pages[0][1]) << 8) | tag.pages[0][0]; + tag.key = ((tag.pages[3][3]) << 24) | ((tag.pages[3][2]) << 16) | ((tag.pages[3][1]) << 8) | tag.pages[3][0]; tag.key <<= 16; - tag.key += ((tag.pages[2][0]) << 8) + tag.pages[2][1]; - tag.pwdl0 = tag.pages[2][3]; - tag.pwdl1 = tag.pages[2][2]; - tag.pwdh0 = tag.pages[1][0]; + tag.key += ((tag.pages[2][3]) << 8) + tag.pages[2][2]; + tag.pwdl0 = tag.pages[2][0]; + tag.pwdl1 = tag.pages[2][1]; + tag.pwdh0 = tag.pages[1][3]; //con0 tag.max_page = 64; - if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 1) + if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 1) tag.max_page = 8; - if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 0) + if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 0) tag.max_page = 0; if (DBGLEVEL >= DBG_EXTENDED) for (i = 0; i < tag.max_page; i++) @@ -962,41 +910,42 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) { tag.pages[i][0] & 0xff); //con1 tag.auth = 0; - if ((tag.pages[1][2] & 0x80) == 0x80) + if ((tag.pages[1][1] & 0x80) == 0x80) tag.auth = 1; tag.LCON = 0; - if ((tag.pages[1][2] & 0x2) == 0x02) + if ((tag.pages[1][1] & 0x2) == 0x02) tag.LCON = 1; tag.LKP = 0; - if ((tag.pages[1][2] & 0x1) == 0x01) + if ((tag.pages[1][1] & 0x1) == 0x01) tag.LKP = 1; //con2 //0=read write 1=read only tag.LCK7 = 0; - if ((tag.pages[1][1] & 0x80) == 0x80) + if ((tag.pages[1][2] & 0x80) == 0x80) tag.LCK7 = 1; tag.LCK6 = 0; - if ((tag.pages[1][1] & 0x40) == 0x040) + if ((tag.pages[1][2] & 0x40) == 0x040) tag.LCK6 = 1; tag.LCK5 = 0; - if ((tag.pages[1][1] & 0x20) == 0x20) + if ((tag.pages[1][2] & 0x20) == 0x20) tag.LCK5 = 1; tag.LCK4 = 0; - if ((tag.pages[1][1] & 0x10) == 0x10) + if ((tag.pages[1][2] & 0x10) == 0x10) tag.LCK4 = 1; tag.LCK3 = 0; - if ((tag.pages[1][1] & 0x8) == 0x08) + if ((tag.pages[1][2] & 0x8) == 0x08) tag.LCK3 = 1; tag.LCK2 = 0; - if ((tag.pages[1][1] & 0x4) == 0x04) + if ((tag.pages[1][2] & 0x4) == 0x04) tag.LCK2 = 1; tag.LCK1 = 0; - if ((tag.pages[1][1] & 0x2) == 0x02) + if ((tag.pages[1][2] & 0x2) == 0x02) tag.LCK1 = 1; tag.LCK0 = 0; - if ((tag.pages[1][1] & 0x1) == 0x01) + if ((tag.pages[1][2] & 0x1) == 0x01) tag.LCK0 = 1; + // Set up simulator mode, frequency divisor which will drive the FPGA // and analog mux selection. FpgaDownloadAndGo(FPGA_BITSTREAM_LF); @@ -1028,7 +977,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) { // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, // external trigger rising edge, load RA on rising edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK - | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; + | AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING; // Enable and reset counter AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; @@ -1100,12 +1049,13 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) { LogTrace(tx, nbytes(txlen), 0, 0, NULL, false); } + // Enable and reset external trigger in timer for capturing future frames + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + // Reset the received frame and response timing info memset(rx, 0x00, sizeof(rx)); response = 0; - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; LED_B_OFF(); } // Reset the frame length @@ -1114,22 +1064,92 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) { overflow += (AT91C_BASE_TC1->TC_CV / T0); // Reset the timer to restart while-loop that receives frames AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG; + } - LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); set_tracing(false); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - + lf_finalize(); // release allocated memory from BigBuff. BigBuf_free(); - StartTicks(); - DbpString("Sim Stopped"); } +void hitagS_receive_frame(uint8_t *rx, size_t *rxlen, int *response) { + + // Reset values for receiving frames + memset(rx, 0x00, HITAG_FRAME_LEN * sizeof(uint8_t)); + *rxlen = 0; + int lastbit = 1; + bool bSkip = true; + int tag_sof = 1; + *response = 0; + uint32_t errorCount = 0; + + // Receive frame, watch for at most T0*EOF periods + while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { + // Check if falling edge in tag modulation is detected + if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { + // Retrieve the new timing values + int ra = (AT91C_BASE_TC1->TC_RA / T0); + + // Reset timer every frame, we have to capture the last edge for timing + AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + + LED_B_ON(); + + // Capture tag frame (manchester decoding using only falling edges) + if (ra >= HITAG_T_EOF) { + if (*rxlen != 0) { + //DbpString("wierd1?"); + } + // Capture the T0 periods that have passed since last communication or field drop (reset) + // We always recieve a 'one' first, which has the falling edge after a half period |-_| + *response = ra - HITAG_T_TAG_HALF_PERIOD; + } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { + // Manchester coding example |-_|_-|-_| (101) + rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8)); + (*rxlen)++; + rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8)); + (*rxlen)++; + } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { + // Manchester coding example |_-|...|_-|-_| (0...01) + rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8)); + (*rxlen)++; + // We have to skip this half period at start and add the 'one' the second time + if (!bSkip) { + rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8)); + (*rxlen)++; + } + lastbit = !lastbit; + bSkip = !bSkip; + } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { + // Manchester coding example |_-|_-| (00) or |-_|-_| (11) + if (tag_sof) { + // Ignore bits that are transmitted during SOF + tag_sof--; + } else { + // bit is same as last bit + rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8)); + (*rxlen)++; + } + } else { + // Ignore wierd value, is to small to mean anything + errorCount++; + } + } + + // if we saw over 100 wierd values break it probably isn't hitag... + if (errorCount > 100) break; + + // We can break this loop if we received the last bit from a frame + if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { + if ((*rxlen) > 0) + break; + } + } +} + /* * Authenticates to the Tag with the given key or challenge. * If the key was given the password will be decrypted. @@ -1149,7 +1169,6 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) { uint8_t *tx = txbuf; size_t txlen = 0; int lastbit = 1; - int reset_sof = 1; int t_wait = HITAG_T_WAIT_MAX; bool bStop = false; int pageNum = 0; @@ -1164,6 +1183,9 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) { uint64_t NrAr = 0; uint8_t key_[6]; + tag.pstate = HT_READY; + tag.tstate = HT_NO_OP; + switch (htf) { case RHTSF_CHALLENGE: { DbpString("Authenticating using nr,ar pair:"); @@ -1238,10 +1260,8 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) { // synchronized startup procedure while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero - // Reset the received frame, frame count and timing info t_wait = 200; - while (!bStop && !BUTTON_PRESS() && !data_available()) { WDT_HIT(); @@ -1381,85 +1401,12 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) { LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); } - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - bool bSkip = true; - int tag_sof = reset_sof; - response = 0; - - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { - // Check if falling edge in tag modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0); - - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - LED_B_ON(); - - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } - - // We can break this loop if we received the last bit from a frame - if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { - if (rxlen > 0) - break; - } - } + hitagS_receive_frame(rx, &rxlen, &response); } end = false; - - LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); set_tracing(false); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - - StartTicks(); - + lf_finalize(); reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); } @@ -1479,7 +1426,6 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) { uint8_t *tx = txbuf; size_t txlen = 0; int lastbit; - int reset_sof; int t_wait = HITAG_T_WAIT_MAX; bool bStop; unsigned char crc; @@ -1555,6 +1501,7 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; // external trigger rising edge, load RA on falling edge of TIOA. AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK | AT91C_TC_ETRGEDG_FALLING @@ -1570,7 +1517,6 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) { // Reset the received frame, frame count and timing info lastbit = 1; bStop = false; - reset_sof = 1; t_wait = 200; while (!bStop && !BUTTON_PRESS() && !data_available()) { @@ -1670,87 +1616,13 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) { LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); } - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - bool bSkip = true; - int tag_sof = reset_sof; - response = 0; - uint32_t errorCount = 0; + hitagS_receive_frame(rx, &rxlen, &response); - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { - // Check if falling edge in tag modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0); - - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - LED_B_ON(); - - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - errorCount++; - } - } - - // if we saw over 100 wierd values break it probably isn't hitag... - if (errorCount > 100) break; - - // We can break this loop if we received the last bit from a frame - if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { - if (rxlen > 0) - break; - } - } } end = false; - LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); set_tracing(false); - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - - StartTicks(); + lf_finalize(); reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); } @@ -1773,7 +1645,7 @@ void check_challenges(bool file_given, uint8_t *data) { size_t rxlen = 0; uint8_t txbuf[HITAG_FRAME_LEN]; int t_wait = HITAG_T_WAIT_MAX; - int lastbit, reset_sof, STATE = 0;; + int lastbit, STATE = 0;; bool bStop; int response_bit[200]; unsigned char mask = 1; @@ -1834,7 +1706,6 @@ void check_challenges(bool file_given, uint8_t *data) { // Reset the received frame, frame count and timing info lastbit = 1; bStop = false; - reset_sof = 1; t_wait = 200; if (file_given) { @@ -1952,11 +1823,11 @@ void check_challenges(bool file_given, uint8_t *data) { u1++; } else if (STATE == 2 && rxlen >= 44) { - Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X", - unlocker[u1 - 1][0], unlocker[u1 - 1][1], - unlocker[u1 - 1][2], unlocker[u1 - 1][3], - unlocker[u1 - 1][4], unlocker[u1 - 1][5], - unlocker[u1 - 1][6], unlocker[u1 - 1][7]); + Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X", + unlocker[u1 - 1][0], unlocker[u1 - 1][1], + unlocker[u1 - 1][2], unlocker[u1 - 1][3], + unlocker[u1 - 1][4], unlocker[u1 - 1][5], + unlocker[u1 - 1][6], unlocker[u1 - 1][7]); STATE = 0; } @@ -1984,85 +1855,10 @@ void check_challenges(bool file_given, uint8_t *data) { LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true); } - // Reset values for receiving frames - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - lastbit = 1; - bool bSkip = true; - int tag_sof = reset_sof; - response = 0; - - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) { - // Check if falling edge in tag modulation is detected - if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) { - // Retrieve the new timing values - int ra = (AT91C_BASE_TC1->TC_RA / T0); - - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - LED_B_ON(); - - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - if (rxlen != 0) { - //DbpString("wierd1?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - // We always recieve a 'one' first, which has the falling edge after a half period |-_| - response = ra - HITAG_T_TAG_HALF_PERIOD; - } else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) { - // Manchester coding example |-_|_-|-_| (101) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) { - // Manchester coding example |_-|...|_-|-_| (0...01) - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - // We have to skip this half period at start and add the 'one' the second time - if (!bSkip) { - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } - lastbit = !lastbit; - bSkip = !bSkip; - } else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) { - // Manchester coding example |_-|_-| (00) or |-_|-_| (11) - if (tag_sof) { - // Ignore bits that are transmitted during SOF - tag_sof--; - } else { - // bit is same as last bit - rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8)); - rxlen++; - } - } else { - // Ignore wierd value, is to small to mean anything - } - } - - // We can break this loop if we received the last bit from a frame - if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) { - if (rxlen > 0) - break; - } - } + hitagS_receive_frame(rx, &rxlen, &response); } - LEDsoff(); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); set_tracing(false); - - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - - StartTicks(); - + lf_finalize(); reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); } - - - diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 2cd3c6f3e..3d1f050c3 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -709,7 +709,7 @@ void SmartCardAtr(void) { set_tracing(true); I2C_Reset_EnterMainProgram(); bool isOK = GetATR(&card); - reply_old(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); + reply_mix(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t)); set_tracing(false); LEDsoff(); } @@ -760,7 +760,7 @@ void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data) { } } OUT: - reply_old(CMD_ACK, len, 0, 0, resp, len); + reply_mix(CMD_ACK, len, 0, 0, resp, len); BigBuf_free(); set_tracing(false); LEDsoff(); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index abfe07f10..23b3a2239 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1817,15 +1817,15 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { ++check; // test if the field exists -#if defined RDV4 +#if defined RDV4 if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_RDV40)) { - + analogCnt++; - + analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_RDV40]; - + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - + if (analogCnt >= 32) { if ((MAX_ADC_HF_VOLTAGE_RDV40 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { @@ -1847,13 +1847,13 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { } #else if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) { - + analogCnt++; - + analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF]; - + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; - + if (analogCnt >= 32) { if ((MAX_ADC_HF_VOLTAGE * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 7ea08e59c..a35ac4c57 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -93,8 +93,6 @@ #define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len)) #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) -#define sprintUID(target,uid) Iso15693sprintUID((target), (uid)) - static void BuildIdentifyRequest(uint8_t *cmdout); //static void BuildReadBlockRequest(uint8_t *cmdout, uint8_t *uid, uint8_t blockNumber ); static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid); @@ -946,7 +944,7 @@ void BruteforceIso15693Afi(uint32_t speed) { WDT_HIT(); if (recvlen >= 12) { - Dbprintf("NoAFI UID = %s", sprintUID(NULL, buf + 2)); + Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, buf + 2)); } // now with AFI @@ -964,7 +962,7 @@ void BruteforceIso15693Afi(uint32_t speed) { recvlen = SendDataTag(data, datalen, false, speed, buf); WDT_HIT(); if (recvlen >= 12) { - Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2)); + Dbprintf("AFI = %i UID = %s", i, iso15693_sprintUID(NULL, buf + 2)); } aborted = BUTTON_PRESS(); diff --git a/armsrc/legicrf.c b/armsrc/legicrf.c index 0665705b6..35b638298 100644 --- a/armsrc/legicrf.c +++ b/armsrc/legicrf.c @@ -404,6 +404,10 @@ bool write_byte(uint16_t index, uint8_t byte, uint8_t addr_sz) { // // Only this functions are public / called from appmain.c //----------------------------------------------------------------------------- +legic_card_select_t* getLegicCardInfo(void) { + return &card; +} + void LegicRfInfo(void) { // configure ARM and FPGA init_reader(false); @@ -441,6 +445,44 @@ OUT: StopTicks(); } +int LegicRfReaderEx(uint16_t offset, uint16_t len, uint8_t iv) { + + int res = PM3_SUCCESS; + + // configure ARM and FPGA + init_reader(false); + + // establish shared secret and detect card type + uint8_t card_type = setup_phase(iv); + if (init_card(card_type, &card) != 0) { + res = PM3_ESOFT; + goto OUT; + } + + // do not read beyond card memory + if (len + offset > card.cardsize) { + len = card.cardsize - offset; + } + + for (uint16_t i = 0; i < len; ++i) { + int16_t byte = read_byte(offset + i, card.cmdsize); + if (byte == -1) { + res = PM3_EOVFLOW; + goto OUT; + } + legic_mem[i] = byte; + + if (i < 4) { + card.uid[i] = byte; + } + } + +OUT: + switch_off(); + StopTicks(); + return res; +} + void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) { // configure ARM and FPGA init_reader(false); @@ -464,6 +506,10 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) { goto OUT; } legic_mem[i] = byte; + + if (i < 4) { + card.uid[i] = byte; + } } // OK diff --git a/armsrc/legicrf.h b/armsrc/legicrf.h index 47a7f89d6..ae4c78cdc 100644 --- a/armsrc/legicrf.h +++ b/armsrc/legicrf.h @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // (c) 2009 Henryk Plötz // 2018 AntiCat +// 2020 iceman // // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of @@ -13,9 +14,12 @@ #define __LEGICRF_H #include "common.h" +#include "legic.h" /* legic_card_select_t struct */ void LegicRfInfo(void); +int LegicRfReaderEx(uint16_t offset, uint16_t len, uint8_t iv); void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv); void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data); +legic_card_select_t* getLegicCardInfo(void); #endif /* __LEGICRF_H */ diff --git a/armsrc/legicrfsim.c b/armsrc/legicrfsim.c index 34f8458ce..bbec86fa5 100644 --- a/armsrc/legicrfsim.c +++ b/armsrc/legicrfsim.c @@ -460,12 +460,12 @@ void LegicRfSimulate(uint8_t cardtype) { // verify command line input if (init_card(cardtype, &card) != 0) { - DbpString("Unknown tagtype."); + DbpString("[!] Unknown tagtype."); goto OUT; } LED_A_ON(); - DbpString("Starting Legic emulator, press button to end"); + DbpString("[=] Starting Legic emulator, press " _YELLOW_("button") "to end"); while (!BUTTON_PRESS() && !data_available()) { WDT_HIT(); @@ -486,7 +486,7 @@ void LegicRfSimulate(uint8_t cardtype) { } OUT: - DbpString("Stopped"); + DbpString("[=] Sim stopped"); switch_off(); StopTicks(); } diff --git a/armsrc/lfadc.c b/armsrc/lfadc.c index 04f293e1d..0a85312bc 100644 --- a/armsrc/lfadc.c +++ b/armsrc/lfadc.c @@ -10,6 +10,7 @@ #include "lfsampling.h" #include "fpgaloader.h" #include "ticks.h" +#include "dbprint.h" // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) // TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz @@ -46,27 +47,43 @@ bool lf_test_periods(size_t expected, size_t count) { // Low frequency (LF) adc passthrough functionality ////////////////////////////////////////////////////////////////////////////// uint8_t previous_adc_val = 0; +uint8_t adc_avg = 0; + +void lf_sample_mean(void) { + uint8_t periods = 0; + uint32_t adc_sum = 0; + while (periods < 32) { + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + adc_sum += AT91C_BASE_SSC->SSC_RHR; + periods++; + } + } + // division by 32 + adc_avg = adc_sum >> 5; + + if (DBGLEVEL >= DBG_EXTENDED) + Dbprintf("LF ADC average %u", adc_avg); +} size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) { size_t periods = 0; volatile uint8_t adc_val; - //uint8_t avg_peak = 140, avg_through = 96; - // 140 - 127 - 114 - uint8_t avg_peak = 140, avg_through = 106; - int16_t checked = 0; + uint8_t avg_peak = adc_avg + 3, avg_through = adc_avg - 3; +// int16_t checked = 0; while (!BUTTON_PRESS()) { // only every 100th times, in order to save time when collecting samples. - if (checked == 1000) { - if (data_available()) { - break; - } else { - checked = 0; - } - } - ++checked; - + /* + if (checked == 1000) { + if (data_available()) { + break; + } else { + checked = 0; + } + } + ++checked; + */ WDT_HIT(); if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { @@ -98,8 +115,8 @@ size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) { } } } - previous_adc_val = adc_val; + if (periods >= max) return 0; } } @@ -116,23 +133,26 @@ size_t lf_detect_gap(size_t max) { } void lf_reset_counter() { + // TODO: find out the correct reset settings for tag and reader mode - if (reader_mode) { - // Reset values for reader mode - rising_edge = false; - previous_adc_val = 0xFF; - } else { - // Reset values for tag/transponder mode - rising_edge = false; - previous_adc_val = 0xFF; - } +// if (reader_mode) { + // Reset values for reader mode + rising_edge = false; + previous_adc_val = 0xFF; + +// } else { + // Reset values for tag/transponder mode +// rising_edge = false; +// previous_adc_val = 0xFF; +// } } bool lf_get_tag_modulation() { return (rising_edge == false); } + bool lf_get_reader_modulation() { - return rising_edge; + return rising_edge; } void lf_wait_periods(size_t periods) { @@ -147,7 +167,11 @@ void lf_init(bool reader, bool simulate) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + sample_config *sc = getSamplingConfig(); + sc->decimation = 1; + sc->averaging = 0; + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); if (reader) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); } else { @@ -155,7 +179,8 @@ void lf_init(bool reader, bool simulate) { // FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); else - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); + // Sniff + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); } @@ -168,8 +193,8 @@ void lf_init(bool reader, bool simulate) { // When in reader mode, give the field a bit of time to settle. // 313T0 = 313 * 8us = 2504us = 2.5ms Hitag2 tags needs to be fully powered. if (reader) { - // 50 ms - SpinDelay(50); + // 10 ms + SpinDelay(10); } // Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation @@ -195,14 +220,12 @@ void lf_init(bool reader, bool simulate) { AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // Prepare data trace - uint32_t bufsize = 20000; + uint32_t bufsize = 10000; // use malloc if (logging) initSampleBufferEx(&bufsize, true); - sample_config *sc = getSamplingConfig(); - sc->decimation = 1; - sc->averaging = 0; + lf_sample_mean(); } void lf_finalize() { @@ -218,36 +241,33 @@ void lf_finalize() { LEDsoff(); - sample_config *sc = getSamplingConfig(); - sc->decimation = 1; - sc->averaging = 0; - StartTicks(); } size_t lf_detect_field_drop(size_t max) { size_t periods = 0; - volatile uint8_t adc_val; - int16_t checked = 0; +// int16_t checked = 0; while (!BUTTON_PRESS()) { - // only every 1000th times, in order to save time when collecting samples. - if (checked == 1000) { - if (data_available()) { - checked = -1; - break; - } else { - checked = 0; - } - } - ++checked; + /* + // only every 1000th times, in order to save time when collecting samples. + if (checked == 1000) { + if (data_available()) { + checked = -1; + break; + } else { + checked = 0; + } + } + ++checked; + */ WDT_HIT(); if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { periods++; - adc_val = AT91C_BASE_SSC->SSC_RHR; + volatile uint8_t adc_val = AT91C_BASE_SSC->SSC_RHR; if (logging) logSampleSimple(adc_val); @@ -275,7 +295,7 @@ static void lf_manchester_send_bit(uint8_t bit) { lf_modulation(bit != 0); lf_wait_periods(16); lf_modulation(bit == 0); - lf_wait_periods(16); + lf_wait_periods(32); } // simulation diff --git a/armsrc/lfadc.h b/armsrc/lfadc.h index 8c33aa778..09e5762c6 100644 --- a/armsrc/lfadc.h +++ b/armsrc/lfadc.h @@ -17,6 +17,7 @@ extern bool logging; +void lf_sample_mean(void); bool lf_test_periods(size_t expected, size_t count); size_t lf_count_edge_periods(size_t max); size_t lf_detect_gap(size_t max); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index b7b928ff2..904d37c61 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -1291,7 +1291,7 @@ void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) cardnum = (lo >> 1) & 0x7FFFF; fac = ((hi & 0xF) << 12) | (lo >> 20); } - Dbprintf("TAG ID: " _YELLOW_("%x%08x (%d)") "- Format Len: " _YELLOW_("%d") "bit - FC: " _YELLOW_("%d") "- Card: "_YELLOW_("%d"), + Dbprintf("TAG ID: " _GREEN_("%x%08x (%d)") "- Format Len: " _GREEN_("%d") "bit - FC: " _GREEN_("%d") "- Card: "_GREEN_("%d"), hi, lo, (lo >> 1) & 0xFFFF, @@ -2399,13 +2399,13 @@ void SendForward(uint8_t fwd_bit_count) { TurnReadLF_off(EM_START_GAP); TurnReadLFOn(18 * 8); - // now start writting with bitbanging the antenna. + // now start writting with bitbanging the antenna. (each bit should be 32*8 total length) while (fwd_bit_sz-- > 0) { //prepare next bit modulation if (((*fwd_write_ptr++) & 1) == 1) { WaitUS(32 * 8); } else { TurnReadLF_off(23 * 8); - TurnReadLFOn(18 * 8); + TurnReadLFOn(32-23 * 8); } } } diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index c492a4eda..3769e3565 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -81,7 +81,7 @@ void setSamplingConfig(sample_config *sc) { printConfig(); } -sample_config *getSamplingConfig() { +sample_config *getSamplingConfig(void) { return &config; } @@ -117,8 +117,8 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) { if (use_malloc) { - if (sample_size == NULL || *sample_size == 0 ) { - *sample_size = BigBuf_max_traceLen(); + if (sample_size == NULL || *sample_size == 0) { + *sample_size = BigBuf_max_traceLen(); data.buffer = BigBuf_get_addr(); } else { *sample_size = MIN(*sample_size, BigBuf_max_traceLen()); @@ -127,7 +127,7 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) { } } else { - if (sample_size == NULL || *sample_size == 0 ) { + if (sample_size == NULL || *sample_size == 0) { *sample_size = BigBuf_max_traceLen(); } data.buffer = BigBuf_get_addr(); @@ -221,7 +221,7 @@ void LFSetupFPGAForADC(int divisor, bool reader_field) { SetAdcMuxFor(GPIO_MUXSEL_LOPKD); // 50ms for the resonant antenna to settle. if (reader_field) - SpinDelay(50); + SpinDelay(50); // Now set up the SSC to get the ADC samples that are now streaming at us. FpgaSetupSsc(); @@ -253,11 +253,11 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in uint32_t cancel_counter = 0; int16_t checked = 0; - while (true) { + while (!BUTTON_PRESS()) { // only every 1000th times, in order to save time when collecting samples. if (checked == 1000) { - if (BUTTON_PRESS() || data_available()) { + if (data_available()) { checked = -1; break; } else { diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 9e9c721bd..a8f829144 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -82,22 +82,22 @@ void MifareReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *datain) { while (true) { if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); break; }; if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { - if (DBGLEVEL >= 1) Dbprintf("Auth error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error"); break; }; if (mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { - if (DBGLEVEL >= 1) Dbprintf("Read block error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read block error"); break; }; if (mifare_classic_halt(pcs, cuid)) { - if (DBGLEVEL >= 1) Dbprintf("Halt error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); break; }; @@ -243,25 +243,25 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain) { isOK = 1; if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { isOK = 0; - if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); } if (isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { isOK = 0; - if (DBGLEVEL >= 1) Dbprintf("Auth error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error"); } for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) { isOK = 0; - if (DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo); break; } } if (mifare_classic_halt(pcs, cuid)) { - if (DBGLEVEL >= 1) Dbprintf("Halt error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); } if (DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED"); @@ -409,22 +409,22 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { while (true) { if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); break; }; if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { - if (DBGLEVEL >= 1) Dbprintf("Auth error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error"); break; }; if (mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { - if (DBGLEVEL >= 1) Dbprintf("Write block error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error"); break; }; if (mifare_classic_halt(pcs, cuid)) { - if (DBGLEVEL >= 1) Dbprintf("Halt error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); break; }; @@ -460,18 +460,18 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain) iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); if(!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) { - if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); OnError(0); return; }; if(mifare_ultra_writeblock_compat(blockNo, blockdata)) { - if (DBGLEVEL >= 1) Dbprintf("Write block error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error"); OnError(0); return; }; if(mifare_ultra_halt()) { - if (DBGLEVEL >= 1) Dbprintf("Halt error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); OnError(0); return; }; @@ -506,7 +506,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { set_tracing(true); if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { - if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); OnError(0); return; }; @@ -534,13 +534,13 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) { } if (mifare_ultra_writeblock(blockNo, blockdata)) { - if (DBGLEVEL >= 1) Dbprintf("Write block error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error"); OnError(0); return; }; if (mifare_ultra_halt()) { - if (DBGLEVEL >= 1) Dbprintf("Halt error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); OnError(0); return; }; @@ -569,7 +569,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { set_tracing(true); if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { - if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); OnError(0); return; }; @@ -579,7 +579,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { blockdata[2] = pwd[5]; blockdata[3] = pwd[4]; if (mifare_ultra_writeblock(44, blockdata)) { - if (DBGLEVEL >= 1) Dbprintf("Write block error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error"); OnError(44); return; }; @@ -589,7 +589,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { blockdata[2] = pwd[1]; blockdata[3] = pwd[0]; if (mifare_ultra_writeblock(45, blockdata)) { - if (DBGLEVEL >= 1) Dbprintf("Write block error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error"); OnError(45); return; }; @@ -599,7 +599,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { blockdata[2] = pwd[13]; blockdata[3] = pwd[12]; if (mifare_ultra_writeblock(46, blockdata)) { - if (DBGLEVEL >= 1) Dbprintf("Write block error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error"); OnError(46); return; }; @@ -609,13 +609,13 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) { blockdata[2] = pwd[9]; blockdata[3] = pwd[8]; if (mifare_ultra_writeblock(47, blockdata)) { - if (DBGLEVEL >= 1) Dbprintf("Write block error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error"); OnError(47); return; }; if (mifare_ultra_halt()) { - if (DBGLEVEL >= 1) Dbprintf("Halt error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); OnError(0); return; }; @@ -674,7 +674,7 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) { 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)) { - if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (ALL)"); continue; } switch (card_info.uidlen) { @@ -693,7 +693,7 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) { have_uid = true; } else { // no need for anticollision. We can directly select the card if (!iso14443a_fast_select_card(uid, cascade_levels)) { - if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (UID)"); continue; } } @@ -792,7 +792,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, 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)) { - if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (ALL)"); continue; } switch (card_info.uidlen) { @@ -811,7 +811,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, have_uid = true; } else { // no need for anticollision. We can directly select the card if (!iso14443a_fast_select_card(uid, cascade_levels)) { - if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (UID)"); continue; } } @@ -821,7 +821,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint32_t nt1; if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) { - if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Auth1 error"); continue; } @@ -832,7 +832,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, CHK_TIMEOUT(); if (len != 4) { - if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Auth2 error len=%d", len); continue; } @@ -1422,7 +1422,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da iso14a_card_select_t card_info; if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) { - if (DBGLEVEL >= 1) Dbprintf("ChkKeys_fast: Can't select card (ALL)"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("ChkKeys_fast: Can't select card (ALL)"); goto OUT; } @@ -1470,7 +1470,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da for (uint16_t i = s_point; i < keyCount; ++i) { // Allow button press / usb cmd to interrupt device - if (BUTTON_PRESS() && data_available()) { + if (BUTTON_PRESS() || data_available()) { goto OUT; } @@ -1562,7 +1562,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da for (uint16_t i = 0; i < keyCount; i++) { // Allow button press / usb cmd to interrupt device - if (BUTTON_PRESS() && data_available()) break; + if (BUTTON_PRESS() || data_available()) break; // found all keys? if (foundkeys == allkeys) @@ -1731,7 +1731,7 @@ void MifareChkKeys(uint8_t *datain) { 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)) { - if (DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (ALL)"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (ALL)"); --i; // try same key once again continue; } @@ -1751,7 +1751,7 @@ void MifareChkKeys(uint8_t *datain) { have_uid = true; } else { // no need for anticollision. We can directly select the card if (!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) { - if (DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (UID)"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (UID)"); --i; // try same key once again continue; } @@ -1805,6 +1805,63 @@ void MifareChkKeys_file(uint8_t *fn) { #endif } +//----------------------------------------------------------------------------- +// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID +//----------------------------------------------------------------------------- +void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) { + + uint16_t isOK = PM3_EUNDEF; + uint8_t uid[10]; + uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + LED_A_ON(); + + while (true) { + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); + break; + } + + uint8_t block_number = 0; + if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error"); + break; + } + + uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE]; + uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE]; + int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL); + if (len != 1 || receivedAnswer[0] != CARD_ACK) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + break;; + } + + if (mifare_classic_halt(pcs, cuid)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); + break; + } + isOK = PM3_SUCCESS; + break; + } + + crypto1_deinit(pcs); + + LED_B_ON(); + reply_ng(CMD_HF_MIFARE_PERSONALIZE_UID, isOK, NULL, 0); + LED_B_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + + //----------------------------------------------------------------------------- // Work with emulator memory // @@ -2229,7 +2286,7 @@ void MifareHasStaticNonce() { nt = bytes_to_num(rec, 4); -// CHK_TIMEOUT(); + CHK_TIMEOUT(); } OUT: @@ -2276,23 +2333,23 @@ void MifareSetMod(uint8_t *datain) { while (true) { if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); break; } if (mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) { - if (DBGLEVEL >= 1) Dbprintf("Auth error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error"); break; } int respLen; if (((respLen = mifare_sendcmd_short(pcs, CRYPT_ALL, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) { - if (DBGLEVEL >= 1) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen); break; } if (mifare_classic_halt(pcs, cuid)) { - if (DBGLEVEL >= 1) Dbprintf("Halt error"); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error"); break; } @@ -2304,7 +2361,6 @@ void MifareSetMod(uint8_t *datain) { LED_B_ON(); reply_ng(CMD_HF_MIFARE_SETMOD, isOK, NULL, 0); - LED_B_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 1f5ee63a4..91adba3b1 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -45,6 +45,8 @@ void MifareCIdent(); // is "magic chinese" card? void MifareHasStaticNonce(); // Has the tag a static nonce? void MifareSetMod(uint8_t *datain); +void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key); + void MifareUSetPwd(uint8_t arg0, uint8_t *datain); void OnSuccessMagic(); void OnErrorMagic(uint8_t reason); diff --git a/armsrc/mifaredesfire.c b/armsrc/mifaredesfire.c index c13311051..5b8ed289e 100644 --- a/armsrc/mifaredesfire.c +++ b/armsrc/mifaredesfire.c @@ -14,6 +14,8 @@ #include "crc16.h" #include "mbedtls/aes.h" #include "commonutil.h" +#include "util.h" +#include "mifare.h" #define MAX_APPLICATION_COUNT 28 #define MAX_FILE_COUNT 16 @@ -31,8 +33,11 @@ static uint8_t deselect_cmd[] = {0xc2, 0xe0, 0xb4}; /* PCB CID CMD PAYLOAD */ //static uint8_t __res[MAX_FRAME_SIZE]; + bool InitDesfireCard() { + pcb_blocknum = 0; + iso14a_card_select_t card; iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); @@ -46,28 +51,14 @@ bool InitDesfireCard() { return true; } -// ARG0 flag enums -enum { - NONE = 0x00, - INIT = 0x01, - DISCONNECT = 0x02, - CLEARTRACE = 0x04, - BAR = 0x08, -} CmdOptions ; - void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) { - /* ARG0 contains flags. - 0x01 = init card. - 0x02 = Disconnect - 0x03 - */ uint8_t flags = arg0; size_t datalen = arg1; uint8_t resp[RECEIVE_SIZE]; memset(resp, 0, sizeof(resp)); - if (DBGLEVEL >= 4) { + if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf(" flags : %02X", flags); Dbprintf(" len : %02X", datalen); print_result(" RX : ", datain, datalen); @@ -77,35 +68,42 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) { clear_trace(); if (flags & INIT) { - if (!InitDesfireCard()) + if (!InitDesfireCard()) { return; + } } int len = DesfireAPDU(datain, datalen, resp); - if (DBGLEVEL >= 4) - print_result("ERR <--: ", resp, len); + if (DBGLEVEL >= DBG_EXTENDED) + print_result("RESP <--: ", resp, len); if (!len) { OnError(2); return; } - // reset the pcb_blocknum, - pcb_blocknum = 0; - if (flags & DISCONNECT) OnSuccess(); - reply_old(CMD_ACK, 1, len, 0, resp, len); + reply_mix(CMD_ACK, 1, len, 0, resp, len); } void MifareDesfireGetInformation() { + LEDsoff(); + int len = 0; iso14a_card_select_t card; uint8_t resp[PM3_CMD_DATA_SIZE] = {0x00}; - uint8_t dataout[PM3_CMD_DATA_SIZE] = {0x00}; + struct p { + uint8_t isOK; + uint8_t uid[7]; + uint8_t versionHW[7]; + uint8_t versionSW[7]; + uint8_t details[14]; + } PACKED payload; + /* 1 = PCB 1 2 = cid 2 @@ -122,61 +120,65 @@ void MifareDesfireGetInformation() { // card select - information if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) { if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card"); - OnError(1); + payload.isOK = 1; // 2 == can not select + reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload)); + switch_off(); return; } if (card.uidlen != 7) { if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen); - OnError(2); + payload.isOK = 2; // 2 == WRONG UID + reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload)); + switch_off(); return; } - - memcpy(dataout, card.uid, 7); + // add uid. + memcpy(payload.uid, card.uid, sizeof(payload.uid)); LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - uint8_t cmd[] = {GET_VERSION}; + uint8_t cmd[] = {GET_VERSION, 0x00, 0x00, 0x00}; size_t cmd_len = sizeof(cmd); len = DesfireAPDU(cmd, cmd_len, resp); if (!len) { print_result("ERROR <--: ", resp, len); - OnError(3); + payload.isOK = 3; // 3 == DOESNT ANSWER TO GET_VERSION + reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload)); + switch_off(); return; } - LED_A_OFF(); - LED_B_ON(); - memcpy(dataout + 7, resp + 3, 7); + memcpy(payload.versionHW, resp + 1, sizeof(payload.versionHW)); // ADDITION_FRAME 1 cmd[0] = ADDITIONAL_FRAME; len = DesfireAPDU(cmd, cmd_len, resp); if (!len) { print_result("ERROR <--: ", resp, len); - OnError(3); + payload.isOK = 3; // 3 == DOESNT ANSWER TO GET_VERSION + reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload)); + switch_off(); return; } - - LED_B_OFF(); - LED_C_ON(); - memcpy(dataout + 7 + 7, resp + 3, 7); + memcpy(payload.versionSW, resp + 1, sizeof(payload.versionSW)); // ADDITION_FRAME 2 len = DesfireAPDU(cmd, cmd_len, resp); if (!len) { print_result("ERROR <--: ", resp, len); - OnError(3); + payload.isOK = 3; // 3 == DOESNT ANSWER TO GET_VERSION + reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload)); + switch_off(); return; } - memcpy(dataout + 7 + 7 + 7, resp + 3, 14); - - reply_old(CMD_ACK, 1, 0, 0, dataout, sizeof(dataout)); + memcpy(payload.details, resp + 1, sizeof(payload.details)); + LED_B_ON(); + reply_ng(CMD_HF_DESFIRE_INFO, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); + LED_B_OFF(); + // reset the pcb_blocknum, pcb_blocknum = 0; OnSuccess(); @@ -467,7 +469,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // dekryptera tagnonce. if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) { - if (DBGLEVEL >= 4) { + if (DBGLEVEL >= DBG_EXTENDED) { DbpString("mbedtls_aes_setkey_dec failed"); } OnError(7); @@ -480,7 +482,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) memcpy(both + 16, decRndB, 16); uint8_t encBoth[32] = {0x00}; if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) { - if (DBGLEVEL >= 4) { + if (DBGLEVEL >= DBG_EXTENDED) { DbpString("mbedtls_aes_setkey_enc failed"); } OnError(7); @@ -517,7 +519,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) } OnSuccess(); - reply_old(CMD_ACK, 1, len, 0, resp, len); + reply_mix(CMD_ACK, 1, len, 0, resp, len); } // 3 different ISO ways to send data to a DESFIRE (direct, capsuled, capsuled ISO) @@ -534,23 +536,23 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout) { wrappedLen = CreateAPDU(cmd, cmd_len, wCmd); - if (DBGLEVEL >= 4) + if (DBGLEVEL >= DBG_EXTENDED) print_result("WCMD <--: ", wCmd, wrappedLen); ReaderTransmit(wCmd, wrappedLen, NULL); len = ReaderReceive(resp, par); if (!len) { - if (DBGLEVEL >= 4) Dbprintf("fukked"); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("fukked"); return false; //DATA LINK ERROR } // if we received an I- or R(ACK)-Block with a block number equal to the // current block number, toggle the current block number - else if (len >= 4 // PCB+CID+CRC = 4 bytes + if (len >= 4 // PCB+CID+CRC = 4 bytes && ((resp[0] & 0xC0) == 0 // I-Block || (resp[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0 && (resp[0] & 0x01) == pcb_blocknum) { // equal block numbers - pcb_blocknum ^= 1; //toggle next block + pcb_blocknum ^= 1; //toggle next block } memcpy(dataout, resp, len); @@ -565,15 +567,22 @@ size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout) { uint8_t cmd[cmdlen]; memset(cmd, 0, cmdlen); - cmd[0] = 0x0A; // 0x0A = send cid, 0x02 = no cid. + cmd[0] = 0x02; // 0x0A = send cid, 0x02 = no cid. cmd[0] |= pcb_blocknum; // OR the block number into the PCB - cmd[1] = 0x00; // CID: 0x00 //TODO: allow multiple selected cards + + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("pcb_blocknum %d == %d ", pcb_blocknum, cmd[0] ); + + cmd[1] = 0x90; // CID: 0x00 //TODO: allow multiple selected cards memcpy(cmd + 2, datain, len); AddCrc14A(cmd, len + 2); - + +/* +hf 14a apdu -sk 90 60 00 00 00 +hf 14a apdu -k 90 AF 00 00 00 +hf 14a apdu 90AF000000 +*/ memcpy(dataout, cmd, cmdlen); - return cmdlen; } diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index 0dcbe404a..0fbfecb85 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -537,13 +537,13 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 // find reader field if (cardSTATE == MFEMUL_NOFIELD) { - + #if defined RDV4 vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; #else vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; #endif - + if (vHf > MF_MINFIELDV) { cardSTATE_TO_IDLE(); LED_A_ON(); diff --git a/armsrc/mifaresniff_disabled.c b/armsrc/mifaresniff_disabled.c index 799fd62be..6ccdc8e6c 100644 --- a/armsrc/mifaresniff_disabled.c +++ b/armsrc/mifaresniff_disabled.c @@ -8,7 +8,7 @@ // Routines to support mifare classic sniffer. //----------------------------------------------------------------------------- -#include "mifaresniff.h" +#include "mifaresniff_disabled.h" #ifndef CheckCrc14A # define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len)) diff --git a/armsrc/util.h b/armsrc/util.h index 9748152ef..052ae266c 100644 --- a/armsrc/util.h +++ b/armsrc/util.h @@ -13,6 +13,11 @@ #include "common.h" +// PRIx64 definition missing with gcc-arm-none-eabi v8? +#ifndef PRIx64 + #define PRIx64 "llx" +#endif + // Basic macros #ifndef SHORT_COIL diff --git a/client/Makefile b/client/Makefile index 6e2ebd001..a09a033d9 100644 --- a/client/Makefile +++ b/client/Makefile @@ -250,7 +250,8 @@ CMDSRCS = crapto1/crapto1.c \ bucketsort.c \ flash.c \ wiegand_formats.c \ - wiegand_formatutils.c + wiegand_formatutils.c \ + cardhelper.c cpu_arch = $(shell uname -m) ifneq ($(findstring 86, $(cpu_arch)), ) diff --git a/client/cmddata.c b/client/cmddata.c index 613ce11e5..74c33da55 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -10,22 +10,22 @@ // Data and Graph commands //----------------------------------------------------------------------------- #include "cmddata.h" - #include #include #include // for CmdNorm INT_MIN && INT_MAX #include // pow #include // tolower - -#include "commonutil.h" // ARRAYLEN -#include "cmdparser.h" // for command_t -#include "ui.h" // for show graph controls -#include "graph.h" // for graph data +#include "commonutil.h" // ARRAYLEN +#include "cmdparser.h" // for command_t +#include "ui.h" // for show graph controls +#include "graph.h" // for graph data #include "comms.h" -#include "lfdemod.h" // for demod code +#include "lfdemod.h" // for demod code #include "loclass/cipherutils.h" // for decimating samples in getsamples -#include "cmdlfem4x.h" // askem410xdecode -#include "fileutils.h" // searchFile +#include "cmdlfem4x.h" // askem410xdecode +#include "fileutils.h" // searchFile +#include "mifare/ndef.h" +#include "cliparser/cliparser.h" uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; size_t DemodBufferLen = 0; @@ -1662,16 +1662,15 @@ int CmdTuneSamples(const char *Cmd) { #define LF_MARGINAL_V 10000 #define HF_UNUSABLE_V 3000 #define HF_MARGINAL_V 5000 -#define ANTENNA_ERROR 1.03 // current algo has 3% error margin. +#define ANTENNA_ERROR 1.00 // current algo has 3% error margin. // hide demod plot line DemodBufferLen = 0; setClockGrid(0, 0); RepaintGraphWindow(); - int timeout = 0; - PrintAndLogEx(INFO, "\nMeasuring antenna characteristics, please wait..."); + PrintAndLogEx(INFO, "Measuring antenna characteristics, please wait..."); clearCommandBuffer(); SendCommandNG(CMD_MEASURE_ANTENNA_TUNING, NULL, 0); @@ -1691,7 +1690,7 @@ int CmdTuneSamples(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); // in mVolt struct p { uint32_t v_lf134; @@ -2290,6 +2289,34 @@ static int CmdDataIIR(const char *Cmd) { return PM3_SUCCESS; } +static int CmdDataNDEF(const char *Cmd) { + +#ifndef MAX_NDEF_LEN +#define MAX_NDEF_LEN 2048 +#endif + + CLIParserInit("data ndef", + "Prints NFC Data Exchange Format (NDEF)", + "Usage:\n\tdata ndef -d 9101085402656e48656c6c6f5101085402656e576f726c64\n"); + + void *argtable[] = { + arg_param_begin, + arg_strx0("dD", "data", "", "NDEF data to decode"), + arg_param_end + }; + CLIExecWithReturn(Cmd, argtable, true); + + int datalen = 0; + uint8_t data[MAX_NDEF_LEN] = {0}; + CLIGetHexWithReturn(1, data, &datalen); + CLIParserFree(); + if (datalen == 0) + return PM3_EINVARG; + + PrintAndLogEx(INFO, "Parsed NDEF Records"); + return NDEFRecordsDecodeAndPrint(data, datalen); +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"askedgedetect", CmdAskEdgeDetect, AlwaysAvailable, "[threshold] Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave (use 20-45, def:25)"}, @@ -2328,6 +2355,7 @@ static command_t CommandTable[] = { {"undec", CmdUndec, AlwaysAvailable, "Un-decimate samples by 2"}, {"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"}, {"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"}, + {"ndef", CmdDataNDEF, AlwaysAvailable, "Decode NDEF records"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/cmdflashmemspiffs.c b/client/cmdflashmemspiffs.c index bdc51dc5d..788851f1a 100644 --- a/client/cmdflashmemspiffs.c +++ b/client/cmdflashmemspiffs.c @@ -18,48 +18,6 @@ static int CmdHelp(const char *Cmd); -static int CmdFlashMemSpiFFSMount(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - clearCommandBuffer(); - SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0); - return PM3_SUCCESS; -} - -static int CmdFlashMemSpiFFSUnmount(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - clearCommandBuffer(); - SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0); - return PM3_SUCCESS; -} - -static int CmdFlashMemSpiFFSTest(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - clearCommandBuffer(); - SendCommandNG(CMD_SPIFFS_TEST, NULL, 0); - return PM3_SUCCESS; -} - -static int CmdFlashMemSpiFFSCheck(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - clearCommandBuffer(); - SendCommandNG(CMD_SPIFFS_CHECK, NULL, 0); - return PM3_SUCCESS; -} - -static int CmdFlashMemSpiFFSTree(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - clearCommandBuffer(); - SendCommandNG(CMD_SPIFFS_PRINT_TREE, NULL, 0); - return PM3_SUCCESS; -} - -static int CmdFlashMemSpiFFSInfo(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - clearCommandBuffer(); - SendCommandNG(CMD_SPIFFS_PRINT_FSINFO, NULL, 0); - return PM3_SUCCESS; -} - static int usage_flashmemspiffs_remove(void) { PrintAndLogEx(NORMAL, "Remove a file from spiffs filesystem"); PrintAndLogEx(NORMAL, " Usage: mem spiffs remove "); @@ -107,16 +65,64 @@ static int usage_flashmemspiffs_load(void) { return PM3_SUCCESS; } + +static int CmdFlashMemSpiFFSMount(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + clearCommandBuffer(); + SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0); + return PM3_SUCCESS; +} + +static int CmdFlashMemSpiFFSUnmount(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + clearCommandBuffer(); + SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0); + return PM3_SUCCESS; +} + +static int CmdFlashMemSpiFFSTest(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + clearCommandBuffer(); + SendCommandNG(CMD_SPIFFS_TEST, NULL, 0); + return PM3_SUCCESS; +} + +static int CmdFlashMemSpiFFSCheck(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + clearCommandBuffer(); + SendCommandNG(CMD_SPIFFS_CHECK, NULL, 0); + return PM3_SUCCESS; +} + +static int CmdFlashMemSpiFFSTree(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + clearCommandBuffer(); + SendCommandNG(CMD_SPIFFS_PRINT_TREE, NULL, 0); + return PM3_SUCCESS; +} + +static int CmdFlashMemSpiFFSInfo(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + clearCommandBuffer(); + SendCommandNG(CMD_SPIFFS_PRINT_FSINFO, NULL, 0); + return PM3_SUCCESS; +} + static int CmdFlashMemSpiFFSRemove(const char *Cmd) { + int len = strlen(Cmd); + if (len < 1) { + return usage_flashmemspiffs_remove(); + } + + char ctmp = tolower(param_getchar(Cmd, 0)); + if (len == 1 && ctmp == 'h') { + return usage_flashmemspiffs_remove(); + } + char filename[32] = {0}; bool errors = false; - /*char ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || ctmp == 'h') { - return usage_flashmemspiffs_remove(); - }*/ - if (param_getstr(Cmd, 0, filename, 32) >= 32) { PrintAndLogEx(FAILED, "Filename too long"); errors = true; @@ -134,15 +140,20 @@ static int CmdFlashMemSpiFFSRemove(const char *Cmd) { static int CmdFlashMemSpiFFSRename(const char *Cmd) { + int len = strlen(Cmd); + if (len < 1) { + return usage_flashmemspiffs_rename(); + } + + char ctmp = tolower(param_getchar(Cmd, 0)); + if (len == 1 && ctmp == 'h') { + return usage_flashmemspiffs_rename(); + } + char srcfilename[32] = {0}; char destfilename[32] = {0}; bool errors = false; - /*char ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || ctmp == 'h') { - return usage_flashmemspiffs_rename(); - }*/ - if (param_getstr(Cmd, 0, srcfilename, 32) >= 32) { PrintAndLogEx(FAILED, "Source Filename too long"); errors = true; @@ -174,16 +185,21 @@ static int CmdFlashMemSpiFFSRename(const char *Cmd) { } static int CmdFlashMemSpiFFSCopy(const char *Cmd) { + int len = strlen(Cmd); + if (len < 1) { + return usage_flashmemspiffs_copy(); + } + char ctmp = tolower(param_getchar(Cmd, 0)); + if (len == 1 && ctmp == 'h') { + return usage_flashmemspiffs_copy(); + } + + char srcfilename[32] = {0}; char destfilename[32] = {0}; bool errors = false; - /*char ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || ctmp == 'h') { - return usage_flashmemspiffs_copy(); - }*/ - if (param_getstr(Cmd, 0, srcfilename, 32) >= 32) { PrintAndLogEx(FAILED, "Source Filename too long"); errors = true; @@ -315,7 +331,7 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) { } int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) { - + int ret_val = PM3_SUCCESS; // We want to mount before multiple operation so the lazy writes/append will not @@ -349,7 +365,7 @@ int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) { bytes_sent += bytes_in_packet; PacketResponseNG resp; - + uint8_t retry = 3; while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); @@ -377,7 +393,7 @@ out: // We want to unmount after these to set things back to normal but more than this // unmouting ensure that SPIFFS CACHES are all flushed so our file is actually written on memory SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0); - + return ret_val; } @@ -400,8 +416,8 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) { cmdp += 2; break; case 'o': - param_getstr(Cmd, cmdp + 1, (char*)destfilename, 32); - if (strlen((char*)destfilename) == 0) { + param_getstr(Cmd, cmdp + 1, (char *)destfilename, 32); + if (strlen((char *)destfilename) == 0) { PrintAndLogEx(FAILED, "Destination Filename missing or invalid"); errors = true; } @@ -429,20 +445,19 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) { } res = flashmem_spiffs_load(destfilename, data, datalen); - + free(data); - - if ( res == PM3_SUCCESS ) + + if (res == PM3_SUCCESS) PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename); - + return res; } static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - { - "copy", CmdFlashMemSpiFFSCopy, IfPm3Flash, + {"copy", CmdFlashMemSpiFFSCopy, IfPm3Flash, "Copy a file to another (destructively) in SPIFFS FileSystem in FlashMEM (spiffs)" }, {"check", CmdFlashMemSpiFFSCheck, IfPm3Flash, "Check/try to defrag faulty/fragmented Filesystem"}, diff --git a/client/cmdhf.c b/client/cmdhf.c index e90f2ea28..e1ed4c799 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -85,12 +85,14 @@ int CmdHFSearch(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_hf_search(); + int res = PM3_ESOFT; + PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, "Searching for ThinFilm tag..."); if (IfPm3NfcBarcode()) { if (infoThinFilm(false) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Thinfilm tag") "found\n"); - return PM3_SUCCESS; + res = PM3_SUCCESS; } } @@ -99,7 +101,7 @@ int CmdHFSearch(const char *Cmd) { if (IfPm3Iso14443a()) { if (infoLTO(false) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LTO-CM tag") "found\n"); - return PM3_SUCCESS; + res = PM3_SUCCESS; } } @@ -108,7 +110,7 @@ int CmdHFSearch(const char *Cmd) { if (IfPm3Iso14443a()) { if (infoHF14A(false, false, false) > 0) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") "found\n"); - return PM3_SUCCESS; + res = PM3_SUCCESS; } } @@ -117,7 +119,7 @@ int CmdHFSearch(const char *Cmd) { if (IfPm3Iso15693()) { if (readHF15Uid(false)) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") "found\n"); - return PM3_SUCCESS; + res = PM3_SUCCESS; } } @@ -126,16 +128,16 @@ int CmdHFSearch(const char *Cmd) { if (IfPm3Legicrf()) { if (readLegicUid(false) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC tag") "found\n"); - return PM3_SUCCESS; + res = PM3_SUCCESS; } } PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, "Searching for Topaz tag..."); if (IfPm3Iso14443a()) { - if (readTopazUid() == PM3_SUCCESS) { + if (readTopazUid(false) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") "found\n"); - return PM3_SUCCESS; + res = PM3_SUCCESS; } } @@ -144,7 +146,7 @@ int CmdHFSearch(const char *Cmd) { if (IfPm3Felica()) { if (readFelicaUid(false) == PM3_SUCCESS) { PrintAndLogEx(NORMAL, "\nValid " _GREEN_("ISO18092 / FeliCa tag") "found\n"); - return PM3_SUCCESS; + res = PM3_SUCCESS; } } @@ -154,7 +156,7 @@ int CmdHFSearch(const char *Cmd) { if (IfPm3Iso14443a()) { if (readHF14B(false) == 1) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-B tag") "found\n"); - return PM3_SUCCESS; + res = PM3_SUCCESS; } } @@ -163,14 +165,18 @@ int CmdHFSearch(const char *Cmd) { if (IfPm3Iclass()) { if (readIclass(false, false) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") "found\n"); - return PM3_SUCCESS; + res = PM3_SUCCESS; } } PROMPT_CLEARLINE; - PrintAndLogEx(INPLACE, _RED_("No known/supported 13.56 MHz tags found")); - PrintAndLogEx(NORMAL, ""); - return PM3_ESOFT; + if (res != PM3_SUCCESS) { + + PrintAndLogEx(INPLACE, _RED_("No known/supported 13.56 MHz tags found")); + res = PM3_ESOFT; + } + printf("\n"); + return res; } int CmdHFTune(const char *Cmd) { @@ -178,39 +184,47 @@ int CmdHFTune(const char *Cmd) { if (cmdp == 'h') return usage_hf_tune(); int iter = param_get32ex(Cmd, 0, 0, 10); + PrintAndLogEx(INFO, "Measuring HF antenna, click " _GREEN_("pm3 button") "or press " _GREEN_("Enter") "to exit"); PacketResponseNG resp; - PrintAndLogEx(SUCCESS, "Measuring HF antenna," _YELLOW_("click button") " or press" _YELLOW_("Enter") "to exit"); clearCommandBuffer(); + uint8_t mode[] = {1}; SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode)); if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) { PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF initialization, aborting"); return PM3_ETIMEOUT; } + mode[0] = 2; // loop forever (till button pressed) if iter = 0 (default) for (uint8_t i = 0; iter == 0 || i < iter; i++) { - if (kbd_enter_pressed()) { // abort by keyboard press + if (kbd_enter_pressed()) { break; } + SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode)); if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) { + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF measure, aborting"); return PM3_ETIMEOUT; } - if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint16_t))) + + if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint16_t))) { break; + } + uint16_t volt = resp.data.asDwords[0] & 0xFFFF; - PrintAndLogEx(INPLACE, "%u mV / %5u V", volt, (uint16_t)(volt / 1000)); + PrintAndLogEx(INPLACE, "%u mV / %2u V", volt, (uint16_t)(volt / 1000)); } mode[0] = 3; + SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode)); if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) { PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF shutdown, aborting"); return PM3_ETIMEOUT; } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, "Done."); + PrintAndLogEx(INFO, "Done."); return PM3_SUCCESS; } diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index c611caa1f..a3ee49503 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -189,9 +189,9 @@ static int usage_hf_14a_sim(void) { PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys"); PrintAndLogEx(NORMAL, " v : (Optional) Verbose"); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344 x"); - PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344"); - PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344556677"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344 x")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677")); // PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n"); return 0; } @@ -202,7 +202,7 @@ static int usage_hf_14a_sniff(void) { PrintAndLogEx(NORMAL, "c - triggered by first data from card"); PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)"); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf 14a sniff c r"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sniff c r")); return 0; } static int usage_hf_14a_raw(void) { @@ -230,7 +230,6 @@ static int usage_hf_14a_reader(void) { static int CmdHF14AList(const char *Cmd) { (void)Cmd; // Cmd is not used so far - //PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead"); CmdTraceList("14a"); return 0; } @@ -261,7 +260,7 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) { return 1; } - PrintAndLogEx(SUCCESS, " UID: %s", sprint_hex(card->uid, card->uidlen)); + PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card->uid, card->uidlen)); PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]); PrintAndLogEx(SUCCESS, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]); if (card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes @@ -335,17 +334,17 @@ static int CmdHF14AReader(const char *Cmd) { if (select_status == 3) { PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]); DropField(); return 1; } - PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); + 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]); if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len)); + PrintAndLogEx(SUCCESS, " ATS: " _GREEN_("%s"), sprint_hex(card.ats, card.ats_len)); } if (!disconnectAfter) { @@ -354,14 +353,14 @@ static int CmdHF14AReader(const char *Cmd) { } if (disconnectAfter) { - if (!silent) PrintAndLogEx(SUCCESS, "field dropped."); + if (!silent) PrintAndLogEx(INFO, "field dropped."); } return 0; } static int CmdHF14AInfo(const char *Cmd) { - bool verbose = false; + bool verbose = true; bool do_nack_test = false; bool do_aid_search = false; @@ -467,7 +466,7 @@ int CmdHF14ASim(const char *Cmd) { break; } if (!errors) { - PrintAndLogEx(SUCCESS, "Emulating ISO/IEC 14443 type A tag with %d byte UID (%s)", uidlen, sprint_hex(uid, uidlen)); + PrintAndLogEx(SUCCESS, "Emulating " _YELLOW_("ISO/IEC 14443 type A tag")"with " _GREEN_("%d byte UID (%s)"), uidlen, sprint_hex(uid, uidlen)); useUIDfromEML = false; } cmdp += 2; @@ -485,7 +484,7 @@ int CmdHF14ASim(const char *Cmd) { cmdp++; break; default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + PrintAndLogEx(WARNING, "Unknown parameter " _RED_("'%c'"), param_getchar(Cmd, cmdp)); errors = true; break; } @@ -511,7 +510,7 @@ int CmdHF14ASim(const char *Cmd) { SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload)); PacketResponseNG resp; - PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation"); + PrintAndLogEx(INFO, "Press pm3-button to abort simulation"); bool keypress = kbd_enter_pressed(); while (!keypress) { @@ -558,6 +557,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav if (activateField) { PacketResponseNG resp; + responseNum = 0; // Anticollision + SELECT card SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); @@ -1276,16 +1276,24 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (select_status == 3) { PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]); DropField(); return select_status; } - PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); + if (verbose) { + PrintAndLogEx(SUCCESS, "-- ISO14443-a Information -----------------------------------"); + PrintAndLogEx(SUCCESS, "-------------------------------------------------------------"); + } + 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]); bool isMifareClassic = true; + bool isMifareDesfire = false; + bool isMifarePlus = false; + bool isMifareUltralight = false; + switch (card.sak) { case 0x00: isMifareClassic = false; @@ -1294,10 +1302,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { DropField(); uint32_t tagT = GetHF14AMfU_Type(); - if (tagT != UL_ERROR) + if (tagT != UL_ERROR) { ul_print_type(tagT, 0); - else + isMifareUltralight = true; + } else { PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)"); + } // reconnect for further tests clearCommandBuffer(); @@ -1314,49 +1324,55 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } break; case 0x01: - PrintAndLogEx(SUCCESS, "TYPE : NXP TNP3xxx Activision Game Appliance"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP TNP3xxx Activision Game Appliance")); break; case 0x04: - PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE (various !DESFire !DESFire EV1)")); isMifareClassic = false; + isMifareDesfire = true; break; case 0x08: - PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1")); break; case 0x09: - PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Mini 0.3k"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Mini 0.3k")); break; case 0x0A: - PrintAndLogEx(SUCCESS, "TYPE : FM11RF005SH (Shanghai Metro)"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("FM11RF005SH (Shanghai Metro)")); break; case 0x10: - PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 2k SL2"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 2k SL2")); + isMifarePlus = true; break; case 0x11: - PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 4k SL2"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 4k SL2")); + isMifarePlus = true; break; case 0x18: - PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1")); break; case 0x20: - PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41")); isMifareClassic = false; + isMifareDesfire = true; + isMifarePlus = true; break; case 0x24: - PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire | DESFire EV1"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE DESFire | DESFire EV1")); isMifareClassic = false; + isMifareDesfire = true; break; case 0x28: - PrintAndLogEx(SUCCESS, "TYPE : JCOP31 or JCOP41 v2.3.1"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("JCOP31 or JCOP41 v2.3.1")); break; case 0x38: - PrintAndLogEx(SUCCESS, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Nokia 6212 or 6131 MIFARE CLASSIC 4K")); break; case 0x88: - PrintAndLogEx(SUCCESS, "TYPE : Infineon MIFARE CLASSIC 1K"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Infineon MIFARE CLASSIC 1K")); break; case 0x98: - PrintAndLogEx(SUCCESS, "TYPE : Gemplus MPCOS"); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Gemplus MPCOS")); break; default: ; @@ -1364,7 +1380,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { // Double & triple sized UID, can be mapped to a manufacturer. if (card.uidlen > 4) { - PrintAndLogEx(SUCCESS, "MANUFACTURER : %s", getTagInfo(card.uid[0])); + PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0])); } // try to request ATS even if tag claims not to support it @@ -1385,7 +1401,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (select_status == 2) { PrintAndLogEx(INFO, "SAK incorrectly claims that card doesn't support RATS"); } - PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len)); + PrintAndLogEx(SUCCESS, " ATS: %s", sprint_hex(card.ats, card.ats_len)); PrintAndLogEx(SUCCESS, " - TL : length is %d bytes", card.ats[0]); if (card.ats[0] != card.ats_len - 2) { PrintAndLogEx(SUCCESS, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); @@ -1461,9 +1477,15 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { switch (card.ats[pos + 2] & 0xf0) { case 0x10: PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire"); + isMifareDesfire = true; + isMifareClassic = false; + isMifarePlus = false; break; case 0x20: PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus"); + isMifarePlus = true; + isMifareDesfire = false; + isMifareClassic = false; break; } switch (card.ats[pos + 2] & 0x0f) { @@ -1590,22 +1612,32 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (isMifareClassic) { int 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) - detect_classic_nackbug(!verbose); + detect_classic_nackbug(false); res = detect_classic_static_nonce(); if (res == 1) - PrintAndLogEx(SUCCESS, "Static nonce detected"); + PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes") ); if (res == 2 && verbose) - PrintAndLogEx(SUCCESS, "Static nonce detection failed"); + PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("fail")); } + if (isMifareUltralight) { + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu info`")); + } + if (isMifarePlus) { + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfp info`")); + } + if (isMifareDesfire) { + PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`")); + } + + return select_status; } - diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index c57055e4b..859df4a23 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -1142,4 +1142,3 @@ int readHF14B(bool verbose) { if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found"); return 0; } - diff --git a/client/cmdhf15.c b/client/cmdhf15.c index 9a5665a31..b6a601391 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -23,16 +23,13 @@ // the client. Signal Processing & decoding is done on the pc. This is the slowest // variant, but offers the possibility to analyze the waveforms directly. #include "cmdhf15.h" - #include - #include "cmdparser.h" // command_t #include "commonutil.h" // ARRAYLEN #include "comms.h" // clearCommandBuffer #include "cmdtrace.h" #include "iso15693tools.h" #include "crypto/libpcrypto.h" - #include "graph.h" #include "crc16.h" // iso15 crc #include "cmddata.h" // getsamples @@ -53,9 +50,11 @@ #define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1) #endif -#ifndef sprintUID -# define sprintUID(target, uid) Iso15693sprintUID((target), (uid)) -#endif +typedef struct { + uint8_t lock; + uint8_t block[4]; +} t15memory_t; + // structure and database for uid -> tagtype lookups typedef struct { uint64_t uid; @@ -63,6 +62,7 @@ typedef struct { const char *desc; } productName; + const productName uidmapping[] = { // UID, #significant Bits, "Vendor(+Product)" @@ -208,18 +208,90 @@ const productName uidmapping[] = { { 0, 0, "no tag-info available" } // must be the last entry }; -uint8_t nxp_public_keys[][33] = { - // ICODE SLIX2 / DNA - { - 0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3, - 0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71, - 0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64, - 0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0 - }, -}; - static int CmdHF15Help(const char *Cmd); +static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) { + + #define PUBLIC_ECDA_KEYLEN 33 + const ecdsa_publickey_t nxp_15693_public_keys[] = { + {"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"}, + {"Manufacturer Mifare Classic MFC1C14_x", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"}, + {"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"}, + {"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"}, + {"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"}, + {"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"}, + {"MICRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"}, + }; +/* + uint8_t nxp_15693_public_keys[][PUBLIC_ECDA_KEYLEN] = { + // ICODE SLIX2 / DNA + { + 0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3, + 0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71, + 0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64, + 0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0 + }, + // unknown. Needs identification + { + 0x04, 0x4F, 0x6D, 0x3F, 0x29, 0x4D, 0xEA, 0x57, + 0x37, 0xF0, 0xF4, 0x6F, 0xFE, 0xE8, 0x8A, 0x35, + 0x6E, 0xED, 0x95, 0x69, 0x5D, 0xD7, 0xE0, 0xC2, + 0x7A, 0x59, 0x1E, 0x6F, 0x6F, 0x65, 0x96, 0x2B, 0xAF + }, + // unknown. Needs identification + { + 0x04, 0xA7, 0x48, 0xB6, 0xA6, 0x32, 0xFB, 0xEE, + 0x2C, 0x08, 0x97, 0x70, 0x2B, 0x33, 0xBE, 0xA1, + 0xC0, 0x74, 0x99, 0x8E, 0x17, 0xB8, 0x4A, 0xCA, + 0x04, 0xFF, 0x26, 0x7E, 0x5D, 0x2C, 0x91, 0xF6, 0xDC + }, + // manufacturer public key + { + 0x04, 0x6F, 0x70, 0xAC, 0x55, 0x7F, 0x54, 0x61, + 0xCE, 0x50, 0x52, 0xC8, 0xE4, 0xA7, 0x83, 0x8C, + 0x11, 0xC7, 0xA2, 0x36, 0x79, 0x7E, 0x8A, 0x07, + 0x30, 0xA1, 0x01, 0x83, 0x7C, 0x00, 0x40, 0x39, 0xC2 + }, + // MIKRON public key. + { + 0x04, 0xf9, 0x71, 0xed, 0xa7, 0x42, 0xa4, 0xa8, + 0x0d, 0x32, 0xdc, 0xf6, 0xa8, 0x14, 0xa7, 0x07, + 0xcc, 0x3d, 0xc3, 0x96, 0xd3, 0x59, 0x02, 0xf7, + 0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2 + } + }; +*/ + + uint8_t i; + int res; + bool is_valid = false; + for (i = 0; i< ARRAYLEN(nxp_15693_public_keys); i++) { + + int dl = 0; + uint8_t key[PUBLIC_ECDA_KEYLEN]; + param_gethex_to_eol(nxp_15693_public_keys[i].value, 0, key, PUBLIC_ECDA_KEYLEN, &dl); + + res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, false); + is_valid = (res == 0); + if (is_valid) + break; + } + + PrintAndLogEx(NORMAL, ""); + if (is_valid == false) { + PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed")); + return PM3_ESOFT; + } + + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); + PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_15693_public_keys[i].desc); + PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_15693_public_keys[i].value); + PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); + PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex(signature, 32)); + PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful")); + return PM3_SUCCESS; +} + // fast method to just read the UID of a tag (collision detection not supported) // *buf should be large enough to fit the 64bit uid // returns 1 if succeeded @@ -399,7 +471,7 @@ static int usage_15_restore(void) { {"-2", "use slower '1 out of 256' mode"}, {"-o", "set OPTION Flag (needed for TI)"}, {"r ", "numbers of retries on error, default is 3"}, - {"u ", "load hf-15-dump-.bin"}, + {"u ", "load hf-15--dump.bin"}, {"f ", "load "}, {"b ", "block size, default is 4"} }; @@ -517,7 +589,7 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t return false; } memcpy(&req[tmpreqlen], uid, sizeof(uid)); - PrintAndLogEx(SUCCESS, "Detected UID %s", sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "Detected UID " _GREEN_("%s"), iso15693_sprintUID(NULL,uid)); tmpreqlen += sizeof(uid); break; default: @@ -530,7 +602,7 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t uid[7 - i] = temp & 0xff; } - PrintAndLogEx(SUCCESS, "Using UID %s", sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "Using UID " _GREEN_("%s"), iso15693_sprintUID(NULL,uid)); memcpy(&req[tmpreqlen], uid, sizeof(uid)); tmpreqlen += sizeof(uid); break; @@ -796,16 +868,8 @@ static int NxpSysInfo(uint8_t *uid) { uint8_t signature[32] = {0x00}; memcpy(signature, recv + 1, 32); - int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, nxp_public_keys[0], uid, 8, signature, 32, false); - bool is_valid = (res == 0); + nxp_15693_print_signature(uid, signature); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Tag Signature"); - PrintAndLogEx(NORMAL, " IC signature public key name : NXP ICODE SLIX2 / DNA"); - PrintAndLogEx(NORMAL, " IC signature public key value : %s", sprint_hex(nxp_public_keys[0], 33)); - PrintAndLogEx(NORMAL, " Elliptic curve parameters : NID_secp128r1"); - PrintAndLogEx(NORMAL, " TAG IC Signature : %s", sprint_hex(signature, 32)); - PrintAndLogEx(NORMAL, " Signature verification %s", (is_valid) ? _GREEN_("successful") : _RED_("failed")); } } @@ -818,8 +882,8 @@ static int NxpSysInfo(uint8_t *uid) { */ static int CmdHF15Info(const char *Cmd) { - char cmdp = param_getchar(Cmd, 0); - if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') return usage_15_info(); + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_info(); PacketResponseNG resp; uint8_t *recv; @@ -838,11 +902,8 @@ static int CmdHF15Info(const char *Cmd) { AddCrc15(req, reqlen); reqlen += 2; - //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); - clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { PrintAndLogEx(WARNING, "iso15693 card select failed"); DropField(); @@ -866,11 +927,12 @@ static int CmdHF15Info(const char *Cmd) { } memcpy(uid, recv + 2, sizeof(uid)); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid)); - PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(recv + 2)); - PrintAndLogEx(SUCCESS, " SYSINFO : %s", sprint_hex(recv, status - 2)); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------"); + PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(SUCCESS, " TYPE: " _YELLOW_("%s"), getTagInfo_15(recv + 2)); + PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL,uid)); + PrintAndLogEx(SUCCESS, " SYSINFO: %s", sprint_hex(recv, status - 2)); // DSFID if (recv[1] & 0x01) @@ -901,12 +963,12 @@ static int CmdHF15Info(const char *Cmd) { } // Check if SLIX2 and attempt to get NXP System Information + PrintAndLogEx(DEBUG, "4 & 08 :: %02x 7 == 1 :: %u 8 == 4 :: %u", recv[4], recv[7], recv[8]); if (recv[8] == 0x04 && recv[7] == 0x01 && recv[4] & 0x80) { return NxpSysInfo(uid); } PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; } @@ -941,7 +1003,7 @@ static int CmdHF15Sim(const char *Cmd) { return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid))); + PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid)); clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO15693_SIMULATE, 0, 0, 0, uid, 8); @@ -1011,7 +1073,7 @@ static int CmdHF15WriteAfi(const char *Cmd) { AddCrc15(req, reqlen); reqlen += 2; - //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); + // PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); @@ -1070,7 +1132,7 @@ static int CmdHF15WriteDsfid(const char *Cmd) { AddCrc15(req, reqlen); reqlen += 2; - //PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); + // PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) ); clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); @@ -1096,11 +1158,6 @@ static int CmdHF15WriteDsfid(const char *Cmd) { return PM3_SUCCESS; } -typedef struct { - uint8_t lock; - uint8_t block[4]; -} t15memory; - // Reads all memory pages // need to write to file static int CmdHF15Dump(const char *Cmd) { @@ -1144,13 +1201,13 @@ static int CmdHF15Dump(const char *Cmd) { } // detect blocksize from card :) - PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid)); int blocknum = 0; uint8_t *recv = NULL; // memory. - t15memory mem[256]; + t15memory_t mem[256]; uint8_t data[256 * 4] = {0}; memset(data, 0, sizeof(data)); @@ -1214,14 +1271,14 @@ static int CmdHF15Dump(const char *Cmd) { PrintAndLogEx(NORMAL, "\n"); size_t datalen = blocknum * 4; + saveFile(filename, ".bin", data, datalen); saveFileEML(filename, data, datalen, 4); - saveFile(filename, ".bin", data, datalen); + saveFileJSON(filename, jsf15, data, datalen); return PM3_SUCCESS; } static int CmdHF15List(const char *Cmd) { (void)Cmd; // Cmd is not used so far - //PrintAndLogEx(WARNING, "Deprecated command, use 'hf list 15' instead"); CmdTraceList("15"); return PM3_SUCCESS; } @@ -1348,7 +1405,7 @@ static int CmdHF15Readmulti(const char *Cmd) { pagenum = param_get8ex(cmd, 0, 0, 10); pagecount = param_get8ex(cmd, 1, 0, 10); - //PrintAndLogEx(NORMAL, "ice %d %d\n", pagenum, pagecount); + // PrintAndLogEx(NORMAL, "ice %d %d\n", pagenum, pagecount); // 0 means 1 page, // 1 means 2 pages, ... @@ -1388,7 +1445,8 @@ static int CmdHF15Readmulti(const char *Cmd) { return PM3_EWRONGANSVER; } - int start = 1; // skip status byte + // skip status byte + int start = 1; int stop = (pagecount + 1) * 5; int currblock = pagenum; // print response @@ -1603,7 +1661,7 @@ static int CmdHF15Restore(const char *Cmd) { case 'u': param_getstr(Cmd, cmdp + 1, buff, FILE_PATH_SIZE); cmdp++; - snprintf(filename, sizeof(filename), "hf-15-dump-%s-bin", buff); + snprintf(filename, sizeof(filename), "hf-15-%s-dump.bin", buff); break; case 'h': return usage_15_restore(); @@ -1622,6 +1680,7 @@ static int CmdHF15Restore(const char *Cmd) { } if ((f = fopen(filename, "rb")) == NULL) { + PrintAndLogEx(WARNING, "Could not find file %s", filename); return PM3_EFILE; } @@ -1703,7 +1762,7 @@ static int CmdHF15CSetUID(const char *Cmd) { return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "Input new UID | %s", sprint_hex(uid, sizeof(uid))); + PrintAndLogEx(SUCCESS, "Input new UID | " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid)); if (!getUID(oldUid)) { PrintAndLogEx(FAILED, "Can't get old/current UID."); @@ -1774,31 +1833,33 @@ static int CmdHF15CSetUID(const char *Cmd) { PrintAndLogEx(FAILED, "Setting UID on tag failed."); return PM3_ESOFT; } else { - PrintAndLogEx(SUCCESS, "old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]); - PrintAndLogEx(SUCCESS, "new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]); + PrintAndLogEx(SUCCESS, "Old: %s", iso15693_sprintUID(NULL, oldUid)); + PrintAndLogEx(SUCCESS, "New: " _GREEN_("%s"), iso15693_sprintUID(NULL, newUid)); return PM3_SUCCESS; } } static command_t CommandTable[] = { {"help", CmdHF15Help, AlwaysAvailable, "This help"}, + {"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"}, {"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO15693 from tag"}, {"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO15693 tag, save to file"}, + {"info", CmdHF15Info, IfPm3Iso15693, "Tag information"}, +// {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"}, + {"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"}, + {"record", CmdHF15Record, IfPm3Iso15693, "Record Samples (ISO15693)"}, + {"read", CmdHF15Read, IfPm3Iso15693, "Read a block"}, + {"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"}, + {"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"}, + {"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"}, + {"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"}, + {"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"}, + {"write", CmdHF15Write, IfPm3Iso15693, "Write a block"}, + {"-----------", CmdHF15Help, IfPm3Iso15693, ""}, {"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"}, {"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"}, {"writedsfid", CmdHF15WriteDsfid, IfPm3Iso15693, "Writes the DSFID on an ISO15693 tag"}, - {"info", CmdHF15Info, IfPm3Iso15693, "Tag information"}, -// {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"}, - {"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"}, - {"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"}, - {"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"}, - {"record", CmdHF15Record, IfPm3Iso15693, "Record Samples (ISO15693)"}, - {"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"}, - {"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"}, - {"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"}, - {"read", CmdHF15Read, IfPm3Iso15693, "Read a block"}, - {"write", CmdHF15Write, IfPm3Iso15693, "Write a block"}, - {"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"}, + {"-----------", CmdHF15Help, IfPm3Iso15693, ""}, {"csetuid", CmdHF15CSetUID, IfPm3Iso15693, "Set UID for magic Chinese card"}, {NULL, NULL, NULL, NULL} }; @@ -1816,13 +1877,13 @@ int CmdHF15(const char *Cmd) { // used with 'hf search' bool readHF15Uid(bool verbose) { - uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + uint8_t uid[8] = {0}; if (!getUID(uid)) { if (verbose) PrintAndLogEx(WARNING, "No tag found."); return false; } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid)); - PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(uid)); + PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("%s"), getTagInfo_15(uid)); return true; } diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index 567600d15..72a7eaad2 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -1,8 +1,8 @@ //----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh , Hagen Fritsch // Copyright (C) 2011 Gerhard de Koning Gans // Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende +// Copyright (C) 2020 Iceman // // This code is licensed to you under the terms of the GNU GPL, version 2 or, // at your option, any later version. See the LICENSE.txt file for the text of @@ -12,14 +12,11 @@ //----------------------------------------------------------------------------- #include "cmdhficlass.h" - #include - #include "cmdparser.h" // command_t #include "commonutil.h" // ARRAYLEN #include "cmdtrace.h" #include "util_posix.h" - #include "comms.h" #include "mbedtls/des.h" #include "loclass/cipherutils.h" @@ -28,12 +25,14 @@ #include "loclass/elite_crack.h" #include "fileutils.h" #include "protocols.h" +#include "cardhelper.h" #include "wiegand_formats.h" #include "wiegand_formatutils.h" #define NUM_CSNS 9 #define ICLASS_KEYS_MAX 8 #define ICLASS_AUTH_RETRY 10 +#define ICLASS_DECRYPTION_BIN "iclass_decryptionkey.bin" static int CmdHelp(const char *Cmd); @@ -49,63 +48,78 @@ static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = { }; static int usage_hf_iclass_sim(void) { - PrintAndLogEx(NORMAL, "Usage: hf iclass sim