mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Merge pull request #28 from RfidResearchGroup/master
Update from master
This commit is contained in:
commit
c424a5f36c
217 changed files with 10191 additions and 9155 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -10,6 +10,7 @@
|
|||
.profile
|
||||
*.log
|
||||
*.eml
|
||||
*.html
|
||||
*.o
|
||||
*.a
|
||||
*.d
|
||||
|
|
10
.travis.yml
10
.travis.yml
|
@ -41,6 +41,16 @@ addons:
|
|||
- qt5
|
||||
- RfidResearchGroup/proxmark3/arm-none-eabi-gcc
|
||||
taps: RfidResearchGroup/proxmark3
|
||||
# update trick to fix https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296/14
|
||||
update: true
|
||||
|
||||
before_install:
|
||||
# bug?
|
||||
# homebrew update replaced python2.7 by python3.7 but
|
||||
# python3 link failed while python@2 still present, so let's do it again:
|
||||
if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
brew link --overwrite python;
|
||||
fi
|
||||
|
||||
install:
|
||||
if ! arm-none-eabi-gcc -v; then
|
||||
|
|
54
CHANGELOG.md
54
CHANGELOG.md
|
@ -3,6 +3,51 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Change `hf search` - now continue to search in case of dual tech cards (@iceman1001) Thanks to @ikarus23 for the suggestion!
|
||||
- Added `hf topas info` - old reader command, now also prints NDEF (@iceman1001)
|
||||
- Change `hf topaz reader` - now only prints lighter info, like UID. (@iceman1001)
|
||||
- Change `hf iclass readtagfile` - improved param handling (@iceman1001)
|
||||
- Change `hf mfu ndef` - text record now correctly decode language code and test (@iceman1001) Thanks to @bettse!
|
||||
- Updated the helptexts for `hf iclass` commands (@iceman1001)
|
||||
- Fix NDEF TLV lock / memory parsed correct (@merlokk)
|
||||
- Change `mem spiffs` commands now parse h param correct (@iceman1001)
|
||||
- Add colour to `hf mf chk` and `hf mf fchk` (@dunderhay)
|
||||
- Change - updated public keys info (@bkerler)
|
||||
- Change - mfc default keys removed dublicates (@iceman1001)
|
||||
. Change - mfc default keys got new entries found on TagInfo app (@bkerler)
|
||||
- Added `hf mfu ndef` - read and decode NDEF Type2 messages (@iceman1001)
|
||||
- Added `data ndef` - decode NDEF messages (@iceman1001)
|
||||
- Change - usb write's now waits for shiftregisters (@pwpiwi)
|
||||
- Change - NDEF supports more signatures now (@iceman1001)
|
||||
- OSX Makefile now supports `make style` and `make checks` (@Pizza_4u)
|
||||
- Added `HF_LEGIC` standalone mode to read and simulate a Legic prime tag (@Pizza_4u)
|
||||
- Added keri MS decode/encode and update 'lf keri clone' to support MS fc/cid cloning. (@mwalker33)
|
||||
- Fix 'hf mfdes enum' - now actually manages to enumerate files under all AID's. :smiley: (@iceman1001)
|
||||
- Fix 'hf mfdes info' - now detects DESFire light and work properly Wrapped commands :+1: (@iceman1001)
|
||||
- :smiling_imp: support (@doegox)
|
||||
- Additional colour changes as recommended by @iceman (@dunderhay)
|
||||
- Change type colour for `hf 14a` card types (@dunderhay)
|
||||
- Add colour to `hf mfdes` command (@dunderhay)
|
||||
- Add 'HINTS' command. Will turn off / on hint messages. Default mode is OFF. (@iceman1001)
|
||||
- Add colour to `hf 14a` and `hf mfu` commands (@dunderhay)
|
||||
- Add colour to `lf hid` commands (@dunderhay)
|
||||
- Change `script run hf_bruteforce -s start_id -e end_id -t timeout -x mifare_card_type` - The hf_bruteforce card script now requires Mifare type (mfc or mfu) (@dunderhay)
|
||||
- Updated `hf_bruteforce.lua` script - added support for brute forcing Mifare Ultralight EV1 cards (@dunderhay)
|
||||
- Added `hf mf personlize` - personalize the UID of a Mifare Classic EV1 card (@pwpiwi)
|
||||
- Change - hint texts added to all lf clone commands (@iceman1001)
|
||||
- Change `lf keri demod` - adjusted the internal id. (@mwalker33)
|
||||
- Added seamless integration with cryptohelper (@iceman1001)
|
||||
- Change `lf hid brute` - new params for direction (UP/DOWN); textual and main loop actually exit. (@capnkrunchy and @iceman1001)
|
||||
- Fix `lf hid brute` - made it work again (@capnkrunchy)
|
||||
- Fix standalone mode HF_MATTYRUN - correct logic when all keys found in printing. partial fix (@iceman1001)
|
||||
- Change static nonce detection got tighter (@iceman1001)
|
||||
- Improved termux notes (@msoose)
|
||||
- Fix `hf mf autopwn` - works on debian 10 *nix. Bad exit commands in hardnested (@iceman1001)
|
||||
- Fix `hf mf hardnested` - bad mutex strategies (@msoose)
|
||||
- Change `lf hitag` - now obeys `lf config` (@iceman1001)
|
||||
- Ported all python 2 scripts to python 3 (@doegox and @sigwinch28)
|
||||
- Removed undefined exit behaviour from `analyzesize` tool: it now exits with code 2 when called with wrong args (@sigwinch28)
|
||||
- Replaced shebangs in scripts with more portable versions which use `/usr/bin/env` (@sigwinch28)
|
||||
- Added `hf lto restore` - restore LTO cartridge memory from dump file [.bin|.eml] (@Kevin-Nakamoto)
|
||||
- Added `LF_ICEHID` standalone mode which searches for lf HID credentials and store to RDV4 flashmem (@iceman1001)
|
||||
- Added `HF_14ASNIFF` standalone mode with storing trace to RDV4 flashmem (@micolous)
|
||||
|
@ -12,7 +57,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Fix compilation under openSUSE (@hsanjuan)
|
||||
- Added `lf nexwatch sim` - use raw hex to simulate (@iceman1001)
|
||||
- Fix `lf indala read` - long id 224bits preamble identification less strict (@iceman1001)
|
||||
- Added `hf mf staticnested` - useful when targeting the strange cards with a static nonce. (@iceman100) Thanks to @xtigmh @uzlonewolf for their solutions.
|
||||
- Added `hf mf staticnested` - useful when targeting the strange cards with a static nonce. (@iceman1001) Thanks to @xtigmh @uzlonewolf for their solutions.
|
||||
- Added `hf plot` (@pwpiwi)
|
||||
- Fix `lf config` - when called with no params, it no longer mess up all device lf config settings. (@iceman1001)
|
||||
- Change `lf indala clone` - new option `--Q5` writes to q5/T5555 tags. (@iceman1001)
|
||||
|
@ -21,7 +66,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Added `commands.md` - document with all proxmark client commands. Generated with XX_internal_command_dump_markdown_XX. (@iceman1001)
|
||||
- Change `lf pac clone` - new option `c <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)
|
||||
- Change mifare classic keytable output refactored and uses colors (@iceman1001)
|
||||
- Fix `hf mf nested` - now writes the correct blockno (@iceman1001)
|
||||
- Change `lf t55xx dump` - now supports saving to JSON (@iceman1001)
|
||||
- Change `hf mf chk | fchk` faster authentication by lower timeout limit. (@pwpiwi)
|
||||
|
@ -417,6 +462,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Added `hf mf mad` and `hf mfp mad` MAD decode, check and print commands (@merlokk)
|
||||
- Added `script run luxeodump` (@0xdrrb)
|
||||
- Fix `lf hitag reader 02` - print all bytes (@bosb)
|
||||
- Fix hitag S simulation (still not working), write, add example HITAG S 256 (@bosb)
|
||||
|
||||
|
||||
### Fixed
|
||||
|
@ -591,8 +637,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Updated the Reveng 1.31 sourcecode to 1.40 from Reveng project homepage (@iceman1001)
|
||||
- Added possibility to write direct to a Legic Prime Tag (MIM256/1024) without using values from the `BigBuffer` -> `hf legic writeRaw <addr> <value>` (@icsom)
|
||||
- Added possibility to decrease DCF values at address 0x05 & 0x06 on a Legic Prime Tag
|
||||
DCF-value will be pulled from the BigBuffer (address 0x05 & 0x06) so you have to
|
||||
load the data into the BigBuffer before with `hf legic load <path/to/legic.dump>` & then
|
||||
DCF-value will be pulled from the BigBuffer (address 0x05 & 0x06) so you have to
|
||||
load the data into the BigBuffer before with `hf legic load <path/to/legic.dump>` & then
|
||||
write the DCF-Values (both at once) with `hf legic write 0x05 0x02` (@icsom)
|
||||
- Added script `legic.lua` for display and edit Data of Legic-Prime Tags (@icsom)
|
||||
- Added the experimental HITAG_S support (@spenneb)
|
||||
|
|
7
Makefile
7
Makefile
|
@ -210,13 +210,20 @@ style:
|
|||
|
||||
# Detecting weird codepages and tabs.
|
||||
checks:
|
||||
# Make sure recode is installed
|
||||
@which recode >/dev/null || ( echo "Please install 'recode' package first" ; exit 1 )
|
||||
@echo "Files with suspicious chars:"
|
||||
@find . \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \
|
||||
-exec sh -c "cat {} |recode utf8.. >/dev/null || echo {}" \;
|
||||
@echo "Files with tabs:"
|
||||
# to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq'
|
||||
ifeq ($(platform),Darwin)
|
||||
@find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \
|
||||
-exec egrep -l '\t' {} \;
|
||||
else
|
||||
@find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \
|
||||
-exec grep -lP '\t' {} \;
|
||||
endif
|
||||
# @echo "Files with printf \\\\t:"
|
||||
# @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \
|
||||
# -exec grep -lP '\\t' {} \;
|
||||
|
|
16
README.md
16
README.md
|
@ -11,16 +11,16 @@
|
|||
|
||||
| FAQ's & Updates | Installation | Use of the Proxmark |
|
||||
| ------------------- |:-------------------:| -------------------:|
|
||||
|[What has changed?](#what-has-changed) | [Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)|
|
||||
|[Development](#development) | [Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md) | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) |
|
||||
|[Why didn't you base it on official Proxmark3 Master?](#why-didnt-you-base-it-on-official-proxmark3-master)| [Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md) | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|
||||
|[Proxmark3 GUI](#proxmark3-gui)|[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|
||||
|[What has changed?](#what-has-changed) | **[Setup and build for Linux](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md)** | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)|
|
||||
|[Development](#development) | **[Important notes on ModemManager for Linux users](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md)** | [Validating proxmark client functionality](/doc/md/Use_of_Proxmark/1_Validation.md) |
|
||||
|[Why didn't you base it on official Proxmark3 Master?](#why-didnt-you-base-it-on-official-proxmark3-master)| **[Homebrew (Mac OS X) & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md)** | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|
||||
|[Proxmark3 GUI](#proxmark3-gui)|**[Setup and build for Windows](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md)**|[Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|
||||
|[Issues](#issues)|[Blue shark manual](/doc/bt_manual_v10.md) |[Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)|
|
||||
|[Notes on UART](/doc/uart_notes.md)|[Maintainers](/doc/md/Development/Maintainers.md)|[Command Cheat sheet](/doc/cheatsheet.md)|
|
||||
|[Notes on frame format](/doc/new_frame_format.md)||[More cheat sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)|
|
||||
|[Notes on external flash](/doc/ext_flash_notes.md)||[EMV](/doc/emv_notes.md)|
|
||||
|[Notes on Termux / Android](/doc/termux_notes.md)||[Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md)|
|
||||
|[Notes on wireshark / tracedata](/doc/trace_wireshark_notes.md)||[JTAG](/doc/jtag_notes.md)|
|
||||
|[Notes on tracedata / wireshark](/doc/trace_notes.md)||[JTAG](/doc/jtag_notes.md)|
|
||||
|[Notes on loclass](/doc/loclass_notes.md)||[Complete client command set](/doc/commands.md)|
|
||||
|[Notes on paths](/doc/path_notes.md)|||
|
||||
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode) ||
|
||||
|
@ -47,9 +47,9 @@ On the software side: quite a lot, see the [Changelog file](CHANGELOG.md).
|
|||
> ⚠ **Note**: This is a bleeding edge repository. The maintainers actively is working out of this repository and will be periodically re-structuring the code to make it easier to comprehend, navigate, build, test, and contribute to, so **DO expect significant changes to code layout on a regular basis**.
|
||||
|
||||
This repo compiles nicely on
|
||||
- Proxspace v3.2
|
||||
- Proxspace v3.x
|
||||
- Windows/mingw environment with Qt5.6.1 & GCC 4.8
|
||||
- Ubuntu 1404, 1510, 1604, 1804, 1904
|
||||
- Ubuntu 1604, 1804, 1904
|
||||
- Mac OS X / Homebrew
|
||||
- ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora
|
||||
- WSL, WSL2 (Windows subsystem linux) on Windows 10
|
||||
|
@ -67,7 +67,7 @@ We usually merge your contributions fast since we do like the idea of getting a
|
|||
- notes on [external flash](/doc/ext_flash_notes.md)
|
||||
- notes on [standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)
|
||||
- notes on [Termux / Android](/doc/termux_notes.md)
|
||||
- notes on [Wireshark / tracedata](/doc/trace_wireshark_notes.md)
|
||||
- notes on [tracedata / Wireshark](/doc/trace_notes.md)
|
||||
- notes on [loclass](/doc/loclass_notes.md)
|
||||
- notes on [EMV](/doc/emv_notes.md)
|
||||
- notes on [Paths](/doc/path_notes.md)
|
||||
|
|
|
@ -24,7 +24,7 @@ init:
|
|||
Add-AppveyorMessage -Message "[$env:APPVEYOR_REPO_COMMIT_SHORT]$env:appveyor_repo_name($env:APPVEYOR_REPO_BRANCH)" -Category Information -Details "repository: $env:appveyor_repo_name branch: $env:APPVEYOR_REPO_BRANCH release: $releasename"
|
||||
|
||||
|
||||
iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
# iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
clone_script:
|
||||
- ps: >-
|
||||
Write-Host "Removing ProxSpace..." -NoNewLine
|
||||
|
@ -409,4 +409,4 @@ on_success:
|
|||
on_failure:
|
||||
- ps: Write-Host "Build error." -ForegroundColor Red
|
||||
on_finish:
|
||||
- ps: $blockRdp = $false; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
- ps: # $blockRdp = $false; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// LCD code
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "LCD.h"
|
||||
#include "LCD_disabled.h"
|
||||
|
||||
void LCDSend(unsigned int data) {
|
||||
// 9th bit set for data, clear for command
|
||||
|
|
|
@ -41,10 +41,19 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| LF_ICEHID | LF HID collector to flashmem |
|
||||
| (RDV4 only) | |
|
||||
+----------------------------------------------------------+
|
||||
| LF_EM4100EMUL | Simulate predefined em4100 tags only |
|
||||
| | |
|
||||
+----------------------------------------------------------+
|
||||
| LF_EM4100RWC | Read/simulate em4100 tags & clone it |
|
||||
| | to T555x tags |
|
||||
+----------------------------------------------------------+
|
||||
| HF_LEGIC | Read/simulate Legic Prime tags |
|
||||
| | storing in flashmem |
|
||||
+----------------------------------------------------------+
|
||||
endef
|
||||
|
||||
STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE LF_ICEHID
|
||||
STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG HF_14ASNIFF
|
||||
STANDALONE_MODES := LF_SAMYRUN LF_ICERUN LF_PROXBRUTE LF_HIDBRUTE LF_ICEHID LF_EM4100EMUL LF_EM4100RWC
|
||||
STANDALONE_MODES += HF_YOUNG HF_MATTYRUN HF_COLIN HF_BOG HF_14ASNIFF HF_LEGIC
|
||||
STANDALONE_MODES_REQ_SMARTCARD :=
|
||||
STANDALONE_MODES_REQ_FLASH := HF_COLIN HF_BOG HF_14ASNIFF LF_ICEHID
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
|
||||
|
|
|
@ -40,4 +40,16 @@ endif
|
|||
# WITH_STANDALONE_LF_ICEHID
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_icehid.c
|
||||
endif
|
||||
endif
|
||||
# WITH_STANDALONE_LF_EM4100EMUL
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100EMUL,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100emul.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_EM4100RWC
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_EM4100RWC,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_em4100rwc.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_LEGIC
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_LEGIC,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_legic.c
|
||||
endif
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
* This module emits debug strings during normal operation -- so try it out in
|
||||
* the lab connected to PM3 client before taking it into the field.
|
||||
*
|
||||
* To delete the trace data from flash:
|
||||
* To delete the trace data from flash:
|
||||
*
|
||||
* Caveats / notes:
|
||||
* - Trace buffer will be cleared on starting stand-alone mode. Data in flash
|
||||
|
@ -97,7 +97,7 @@ void RunMod() {
|
|||
if (trace_len > 0) {
|
||||
Dbprintf("[!] Trace length (bytes) = %u", trace_len);
|
||||
|
||||
uint8_t* trace_buffer = BigBuf_get_addr();
|
||||
uint8_t *trace_buffer = BigBuf_get_addr();
|
||||
if (!exists_in_spiffs(HF_14ASNIFF_LOGFILE)) {
|
||||
rdv40_spiffs_write(
|
||||
HF_14ASNIFF_LOGFILE, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
@ -117,7 +117,7 @@ void RunMod() {
|
|||
|
||||
SpinErr(LED_A, 200, 5);
|
||||
SpinDelay(100);
|
||||
|
||||
|
||||
LEDsoff();
|
||||
SpinDelay(300);
|
||||
DownloadTraceInstructions();
|
||||
|
|
173
armsrc/Standalone/hf_legic.c
Normal file
173
armsrc/Standalone/hf_legic.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// (c) Stefanie Hofmann, 2020
|
||||
// (c) Uli Heilmeier, 2020
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// main code for Legic Prime read/sim
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "standalone.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "BigBuf.h"
|
||||
#include "appmain.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "util.h"
|
||||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
#include "legicrf.h"
|
||||
#include "legicrfsim.h"
|
||||
#include "legic.h" // legic_card_select_t struct
|
||||
#include "spiffs.h" // flashmem
|
||||
|
||||
|
||||
/*
|
||||
* To list all dump files from flash:
|
||||
*
|
||||
* 1. mem spiffs tree
|
||||
*
|
||||
*
|
||||
* To retrieve dump files from flash:
|
||||
*
|
||||
* 1. mem spiffs dump o hf-legic-XXYYZZWW-dump.bin f hf-legic-XXYYZZWW-dump.bin
|
||||
* Copies log file from flash to your client.
|
||||
*
|
||||
*
|
||||
* This module emits debug strings during normal operation -- so try it out in
|
||||
* the lab connected to PM3 client before taking it into the field.
|
||||
*
|
||||
* To delete a dump file from flash:
|
||||
*
|
||||
* 1. mem spiffs remove hf-legic-XXYYZZWW-dump.bin
|
||||
*
|
||||
*/
|
||||
|
||||
void DownloadLogInstructions() {
|
||||
Dbprintf("");
|
||||
Dbprintf("[=] List all dumps from flash:");
|
||||
Dbprintf("[=] " _YELLOW_("-") "mem spiffs tree");
|
||||
Dbprintf("");
|
||||
Dbprintf("[=] To save a dump file from flash to client:");
|
||||
Dbprintf("[=] " _YELLOW_("-") "mem spiffs dump o hf-legic-UID-dump.bin f hf-legic-UID-dump.bin");
|
||||
}
|
||||
|
||||
void save_dump_to_file(legic_card_select_t *p_card) {
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
|
||||
// legic functions puts it memory in Emulator reserved memory.
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
|
||||
char *preferredName = (char*)BigBuf_malloc(30);
|
||||
if (preferredName == NULL) {
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
sprintf(preferredName, "hf-legic-%02X%02X%02X%02X-dump", p_card->uid[0], p_card->uid[1], p_card->uid[2], p_card->uid[3]);
|
||||
uint16_t preferredNameLen = strlen(preferredName);
|
||||
|
||||
char *filename = (char*)BigBuf_malloc(preferredNameLen + 4 + 1 + 10);
|
||||
if (filename == NULL) {
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
sprintf(filename, "%.*s%s", preferredNameLen, preferredName, ".bin");
|
||||
uint16_t num = 1;
|
||||
while (exists_in_spiffs(filename)) {
|
||||
sprintf(filename, "%.*s-%d%s", preferredNameLen, preferredName, num, ".bin");
|
||||
num++;
|
||||
}
|
||||
|
||||
rdv40_spiffs_write(filename, mem, p_card->cardsize, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
||||
Dbprintf("[=] saved card dump to flashmem::" _YELLOW_("%s"), filename);
|
||||
OUT:
|
||||
BigBuf_free_keep_EM();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" HF Legic Prime standalone");
|
||||
}
|
||||
|
||||
// Searching for Legic card until found and read.
|
||||
// Simulating recorded Legic Prime card.
|
||||
// C = Searching
|
||||
// A, B, C = Reading
|
||||
// A, D = Simulating
|
||||
|
||||
void RunMod() {
|
||||
StandAloneMode();
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
Dbprintf("[=] >> HF Legic Prime Read/Simulate Started <<");
|
||||
DbpString("[=] press and HOLD button to exit standalone mode");
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
//exit from hf_legic, send usbcommand
|
||||
if (data_available()) break;
|
||||
|
||||
//Was our button held down or pressed?
|
||||
int button_pressed = BUTTON_HELD(280);
|
||||
if (button_pressed == BUTTON_HOLD) {
|
||||
break;
|
||||
}
|
||||
|
||||
LEDsoff();
|
||||
LED_C_ON();
|
||||
|
||||
DbpString("[=] looking for tags");
|
||||
int read_success = PM3_ESOFT;
|
||||
|
||||
//search for legic card until reading successfull or button pressed
|
||||
do {
|
||||
LED_C_ON();
|
||||
SpinDelay(500);
|
||||
// We don't care if we read a MIM256, MIM512 or MIM1024
|
||||
// we just read 1024 bytes
|
||||
read_success = LegicRfReaderEx(0, 1024, 0x55);
|
||||
|
||||
} while (read_success == PM3_ESOFT && !BUTTON_PRESS());
|
||||
|
||||
LEDsoff();
|
||||
|
||||
//simulate if read successfully
|
||||
if (read_success != PM3_ESOFT) {
|
||||
|
||||
legic_card_select_t *p_card;
|
||||
p_card = getLegicCardInfo();
|
||||
if (p_card->cardsize == 0)
|
||||
continue;
|
||||
|
||||
save_dump_to_file(p_card);
|
||||
|
||||
LED_D_ON();
|
||||
uint8_t ct;
|
||||
switch(p_card->tagtype) {
|
||||
case 0x0D:
|
||||
ct = 0;
|
||||
break;
|
||||
case 0x1D:
|
||||
ct = 1;
|
||||
break;
|
||||
case 0x3D:
|
||||
ct = 2;
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
// The read data is migrated to a MIM1024 card
|
||||
LegicRfSimulate(ct);
|
||||
}
|
||||
}
|
||||
|
||||
LEDsoff();
|
||||
#ifdef WITH_FLASH
|
||||
DownloadLogInstructions();
|
||||
#endif
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
}
|
|
@ -323,7 +323,7 @@ void RunMod() {
|
|||
Dbprintf("\tCurrent sector:%3d, block:%3d, key type: %c, key count: %i ", sec, block, type ? 'B' : 'A', mfKeysCnt);
|
||||
int key = saMifareChkKeys(block, type, true, size, &keyBlock[0], &key64);
|
||||
if (key == -1) {
|
||||
LED(LED_RED, 50); //red
|
||||
LED(LED_RED, 50);
|
||||
Dbprintf("\t✕ Key not found for this sector!");
|
||||
allKeysFound = false;
|
||||
// break;
|
||||
|
@ -348,21 +348,24 @@ void RunMod() {
|
|||
TODO:
|
||||
- Get UID from tag and set accordingly in emulator memory and call mifaresim with right flags (iceman)
|
||||
*/
|
||||
if (!allKeysFound && keyFound) {
|
||||
Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!");
|
||||
LED_C_ON(); //red
|
||||
LED_A_ON(); //yellow
|
||||
// no room to run nested attack on device (iceman)
|
||||
// Do nested attack, set allKeysFound = true;
|
||||
// allKeysFound = true;
|
||||
if (allKeysFound) {
|
||||
Dbprintf("\t✓ All keys found");
|
||||
} else {
|
||||
Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!");
|
||||
LED_C_ON(); //red
|
||||
if (keyFound) {
|
||||
Dbprintf("\t✕ There's currently no nested attack in MattyRun, sorry!");
|
||||
LED_C_ON(); //red
|
||||
LED_A_ON(); //yellow
|
||||
// no room to run nested attack on device (iceman)
|
||||
// Do nested attack, set allKeysFound = true;
|
||||
// allKeysFound = true;
|
||||
} else {
|
||||
Dbprintf("\t✕ There's nothing I can do without at least a one valid key, sorry!");
|
||||
LED_C_ON(); //red
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned.
|
||||
*/
|
||||
// If enabled, transfers found keys to memory and loads target content in emulator memory. Then it simulates to be the tag it has basically cloned.
|
||||
|
||||
if ((transferToEml) && (allKeysFound)) {
|
||||
|
||||
emlClearMem();
|
||||
|
|
100
armsrc/Standalone/lf_em4100emul.c
Normal file
100
armsrc/Standalone/lf_em4100emul.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Artyom Gnatyuk, 2020
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// LF emul - Very simple mode. Simulate only predefined in low[] IDs
|
||||
// Short click - select next slot and start simulation
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "standalone.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "lfops.h"
|
||||
#include "util.h"
|
||||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
#include "string.h"
|
||||
#include "BigBuf.h"
|
||||
|
||||
#define MAX_IND 16 // 4 LEDs - 2^4 combinations
|
||||
#define CLOCK 64 //for 125kHz
|
||||
|
||||
// low & high - array for storage IDs. Its length must be equal.
|
||||
// Predefined IDs must be stored in low[].
|
||||
// In high[] must be nulls
|
||||
uint64_t low[] = {0x565A1140BE, 0x365A398149, 0x5555555555, 0xFFFFFFFFFF};
|
||||
uint32_t high[] = {0, 0, 0, 0};
|
||||
uint8_t *bba, slots_count;
|
||||
int buflen;
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" LF EM4100 simulator standalone mode");
|
||||
}
|
||||
|
||||
uint64_t ReversQuads(uint64_t bits) {
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
result += ((bits >> (60 - 4 * i)) & 0xf) << (4 * i);
|
||||
}
|
||||
return result >> 24;
|
||||
}
|
||||
|
||||
void FillBuff(uint8_t bit) {
|
||||
memset(bba + buflen, bit, CLOCK / 2);
|
||||
buflen += (CLOCK / 2);
|
||||
memset(bba + buflen, bit ^ 1, CLOCK / 2);
|
||||
buflen += (CLOCK / 2);
|
||||
}
|
||||
|
||||
void ConstructEM410xEmulBuf(uint64_t id) {
|
||||
|
||||
int i, j, binary[4], parity[4];
|
||||
buflen = 0;
|
||||
for (i = 0; i < 9; i++)
|
||||
FillBuff(1);
|
||||
parity[0] = parity[1] = parity[2] = parity[3] = 0;
|
||||
for (i = 0; i < 10; i++) {
|
||||
for (j = 3; j >= 0; j--, id /= 2)
|
||||
binary[j] = id % 2;
|
||||
for (j = 0; j < 4; j++)
|
||||
FillBuff(binary[j]);
|
||||
FillBuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
for (j = 0; j < 4; j++)
|
||||
parity[j] ^= binary[j];
|
||||
}
|
||||
for (j = 0; j < 4; j++)
|
||||
FillBuff(parity[j]);
|
||||
FillBuff(0);
|
||||
}
|
||||
|
||||
void LED_Slot(int i) {
|
||||
LEDsoff();
|
||||
if (slots_count > 4) {
|
||||
LED(i % MAX_IND, 0); //binary indication for slots_count > 4
|
||||
} else {
|
||||
LED(1 << i, 0); //simple indication for slots_count <=4
|
||||
}
|
||||
}
|
||||
|
||||
void RunMod() {
|
||||
StandAloneMode();
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
Dbprintf("[=] >> LF EM4100 simulator started <<");
|
||||
|
||||
int selected = 0; //selected slot after start
|
||||
slots_count = sizeof(low) / sizeof(low[0]);
|
||||
bba = BigBuf_get_addr();
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
if (data_available()) break;
|
||||
SpinDelay(100);
|
||||
SpinUp(100);
|
||||
LED_Slot(selected);
|
||||
ConstructEM410xEmulBuf(ReversQuads(low[selected]));
|
||||
SimulateTagLowFrequency(buflen, 0, true);
|
||||
selected = (selected + 1) % slots_count;
|
||||
}
|
||||
}
|
204
armsrc/Standalone/lf_em4100rwc.c
Normal file
204
armsrc/Standalone/lf_em4100rwc.c
Normal file
|
@ -0,0 +1,204 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Artyom Gnatyuk, 2020
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// LF rwc - This mode can simulate ID from selected slot, read ID to
|
||||
// selected slot, write from selected slot to T5555 tag and store
|
||||
// readed ID to flash (only RDV4). Also you can set predefined IDs
|
||||
// in any slot.
|
||||
// To recall stored ID from flash execute:
|
||||
// mem spifss dump o emdump p
|
||||
// or:
|
||||
// mem spifss dump o emdump f emdump
|
||||
// then from shell:
|
||||
// hexdump emdump -e '5/1 "%02X" /0 "\n"'
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "standalone.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "lfops.h"
|
||||
#include "util.h"
|
||||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
#include "string.h"
|
||||
#include "BigBuf.h"
|
||||
#include "spiffs.h"
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
#include "flashmem.h"
|
||||
#endif
|
||||
|
||||
#define MAX_IND 16 // 4 LEDs - 2^4 combinations
|
||||
#define CLOCK 64 //for 125kHz
|
||||
|
||||
// low & high - array for storage IDs. Its length must be equal.
|
||||
// Predefined IDs must be stored in low[].
|
||||
// In high[] must be nulls
|
||||
uint64_t low[] = {0x565AF781C7, 0x540053E4E2, 0x1234567890, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint32_t high[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t *bba, slots_count;
|
||||
int buflen;
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" LF EM4100 read/write/clone mode");
|
||||
}
|
||||
|
||||
uint64_t ReversQuads(uint64_t bits) {
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
result += ((bits >> (60 - 4 * i)) & 0xf) << (4 * i);
|
||||
}
|
||||
return result >> 24;
|
||||
}
|
||||
|
||||
void FillBuff(uint8_t bit) {
|
||||
memset(bba + buflen, bit, CLOCK / 2);
|
||||
buflen += (CLOCK / 2);
|
||||
memset(bba + buflen, bit ^ 1, CLOCK / 2);
|
||||
buflen += (CLOCK / 2);
|
||||
}
|
||||
|
||||
void ConstructEM410xEmulBuf(uint64_t id) {
|
||||
|
||||
int i, j, binary[4], parity[4];
|
||||
buflen = 0;
|
||||
for (i = 0; i < 9; i++)
|
||||
FillBuff(1);
|
||||
parity[0] = parity[1] = parity[2] = parity[3] = 0;
|
||||
for (i = 0; i < 10; i++) {
|
||||
for (j = 3; j >= 0; j--, id /= 2)
|
||||
binary[j] = id % 2;
|
||||
for (j = 0; j < 4; j++)
|
||||
FillBuff(binary[j]);
|
||||
FillBuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
for (j = 0; j < 4; j++)
|
||||
parity[j] ^= binary[j];
|
||||
}
|
||||
for (j = 0; j < 4; j++)
|
||||
FillBuff(parity[j]);
|
||||
FillBuff(0);
|
||||
}
|
||||
|
||||
void LED_Slot(int i) {
|
||||
LEDsoff();
|
||||
if (slots_count > 4) {
|
||||
LED(i % MAX_IND, 0); //binary indication, usefully for slots_count > 4
|
||||
} else {
|
||||
LED(1 << i, 0); //simple indication for slots_count <=4
|
||||
}
|
||||
}
|
||||
|
||||
void FlashLEDs(uint32_t speed, uint8_t times) {
|
||||
for (int i = 0; i < times * 2; i++) {
|
||||
LED_A_INV();
|
||||
LED_B_INV();
|
||||
LED_C_INV();
|
||||
LED_D_INV();
|
||||
SpinDelay(speed);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
void SaveIDtoFlash(int addr, uint64_t id) {
|
||||
uint8_t bt[5];
|
||||
char *filename = "emdump";
|
||||
rdv40_spiffs_mount();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
bt[4 - i] = (uint8_t)(id >> 8 * i & 0xff);
|
||||
}
|
||||
if (exists_in_spiffs(filename) == false) {
|
||||
rdv40_spiffs_write(filename, &bt[0], 5, RDV40_SPIFFS_SAFETY_NORMAL);
|
||||
} else {
|
||||
rdv40_spiffs_append(filename, &bt[0], 5, RDV40_SPIFFS_SAFETY_NORMAL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void RunMod() {
|
||||
StandAloneMode();
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
Dbprintf("[=] >> LF EM4100 read/write/clone started <<");
|
||||
|
||||
int selected = 0;
|
||||
//state 0 - select slot
|
||||
// 1 - read tag to selected slot,
|
||||
// 2 - simulate tag from selected slot
|
||||
// 3 - write to T5555 tag
|
||||
uint8_t state = 0;
|
||||
slots_count = sizeof(low) / sizeof(low[0]);
|
||||
bba = BigBuf_get_addr();
|
||||
LED_Slot(selected);
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
if (data_available()) break;
|
||||
int button_pressed = BUTTON_HELD(1000);
|
||||
SpinDelay(300);
|
||||
switch (state) {
|
||||
case 0:
|
||||
// Select mode
|
||||
if (button_pressed == 1) {
|
||||
// Long press - switch to simulate mode
|
||||
SpinUp(100);
|
||||
LED_Slot(selected);
|
||||
state = 2;
|
||||
} else if (button_pressed < 0) {
|
||||
// Click - switch to next slot
|
||||
selected = (selected + 1) % slots_count;
|
||||
LED_Slot(selected);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
// Read mode.
|
||||
if (button_pressed > 0) {
|
||||
// Long press - switch to read mode
|
||||
SpinUp(100);
|
||||
LED_Slot(selected);
|
||||
state = 3;
|
||||
} else if (button_pressed < 0) {
|
||||
// Click - exit to select mode
|
||||
CmdEM410xdemod(1, &high[selected], &low[selected], 0);
|
||||
FlashLEDs(100, 5);
|
||||
#ifdef WITH_FLASH
|
||||
SaveIDtoFlash(selected, low[selected]);
|
||||
#endif
|
||||
state = 0;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
// Simulate mode
|
||||
if (button_pressed > 0) {
|
||||
// Long press - switch to read mode
|
||||
SpinDown(100);
|
||||
LED_Slot(selected);
|
||||
state = 1;
|
||||
} else if (button_pressed < 0) {
|
||||
// Click - start simulating. Click again to exit from simulate mode
|
||||
LED_Slot(selected);
|
||||
ConstructEM410xEmulBuf(ReversQuads(low[selected]));
|
||||
FlashLEDs(100, 5);
|
||||
SimulateTagLowFrequency(buflen, 0, 1);
|
||||
LED_Slot(selected);
|
||||
state = 0; // Switch to select mode
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
// Write tag mode
|
||||
if (button_pressed > 0) {
|
||||
// Long press - switch to select mode
|
||||
SpinDown(100);
|
||||
LED_Slot(selected);
|
||||
state = 0;
|
||||
} else if (button_pressed < 0) {
|
||||
// Click - write ID to tag
|
||||
WriteEM410x(0, (uint32_t)(low[selected] >> 32), (uint32_t)(low[selected] & 0xffffffff));
|
||||
LED_Slot(selected);
|
||||
state = 0; // Switch to select mode
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// main code for HID collector aka IceHID by Iceman
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <inttypes.h>
|
||||
#include "standalone.h" // standalone definitions
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
|
@ -36,7 +37,7 @@
|
|||
* To retrieve log file from flash:
|
||||
*
|
||||
* 1. mem spiffs dump o lf_hidcollect.log f lf_hidcollect.log
|
||||
* Copies log file from flash to your PC.
|
||||
* Copies log file from flash to your client.
|
||||
*
|
||||
* 2. exit the Proxmark3 client
|
||||
*
|
||||
|
@ -63,7 +64,7 @@ void DownloadLogInstructions() {
|
|||
|
||||
bool log_exists;
|
||||
|
||||
void append(uint8_t* entry, size_t entry_len) {
|
||||
void append(uint8_t *entry, size_t entry_len) {
|
||||
|
||||
LED_B_ON();
|
||||
if (log_exists == false) {
|
||||
|
@ -105,23 +106,23 @@ uint32_t IceEM410xdemod() {
|
|||
memset(entry, 0, sizeof(entry));
|
||||
|
||||
if (size == 128) {
|
||||
sprintf((char *)entry, "EM XL TAG ID: %06lx%08lx%08lx - (%05ld_%03ld_%08ld)\n",
|
||||
hi,
|
||||
(uint32_t)(lo >> 32),
|
||||
(uint32_t)lo,
|
||||
(uint32_t)(lo & 0xFFFF),
|
||||
(uint32_t)((lo >> 16LL) & 0xFF),
|
||||
(uint32_t)(lo & 0xFFFFFF));
|
||||
sprintf((char *)entry, "EM XL TAG ID: %06"PRIx32"%08"PRIx32"%08"PRIx32" - (%05"PRIu32"_%03"PRIu32"_%08"PRIu32")\n",
|
||||
hi,
|
||||
(uint32_t)(lo >> 32),
|
||||
(uint32_t)lo,
|
||||
(uint32_t)(lo & 0xFFFF),
|
||||
(uint32_t)((lo >> 16LL) & 0xFF),
|
||||
(uint32_t)(lo & 0xFFFFFF));
|
||||
} else {
|
||||
sprintf((char *)entry, "EM TAG ID: %02lx%08lx - (%05ld_%03ld_%08ld)\n",
|
||||
(uint32_t)(lo >> 32),
|
||||
(uint32_t)lo,
|
||||
(uint32_t)(lo & 0xFFFF),
|
||||
(uint32_t)((lo >> 16LL) & 0xFF),
|
||||
(uint32_t)(lo & 0xFFFFFF));
|
||||
sprintf((char *)entry, "EM TAG ID: %02"PRIx32"%08"PRIx32" - (%05"PRIu32"_%03"PRIu32"_%08"PRIu32")\n",
|
||||
(uint32_t)(lo >> 32),
|
||||
(uint32_t)lo,
|
||||
(uint32_t)(lo & 0xFFFF),
|
||||
(uint32_t)((lo >> 16LL) & 0xFF),
|
||||
(uint32_t)(lo & 0xFFFFFF));
|
||||
}
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
Dbprintf("%s", entry);
|
||||
BigBuf_free();
|
||||
return PM3_SUCCESS;
|
||||
|
@ -160,20 +161,20 @@ uint32_t IceAWIDdemod() {
|
|||
uint8_t fac = bytebits_to_byte(dest + 9, 8);
|
||||
uint32_t cardnum = bytebits_to_byte(dest + 17, 16);
|
||||
uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen);
|
||||
sprintf((char *)entry, "AWID bit len: %d, FC: %d, Card: %ld - Wiegand: %lx, Raw: %08lx%08lx%08lx\n", fmtLen, fac, cardnum, code1, rawHi2, rawHi, rawLo);
|
||||
sprintf((char *)entry, "AWID bit len: %d, FC: %d, Card: %"PRIu32" - Wiegand: %"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, fac, cardnum, code1, rawHi2, rawHi, rawLo);
|
||||
} else {
|
||||
uint32_t cardnum = bytebits_to_byte(dest + 8 + (fmtLen - 17), 16);
|
||||
if (fmtLen > 32) {
|
||||
uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen - 32);
|
||||
uint32_t code2 = bytebits_to_byte(dest + 8 + (fmtLen - 32), 32);
|
||||
sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %ld - Wiegand: %lx%08lx, Raw: %08lx%08lx%08lx\n", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %"PRIu32" - Wiegand: %"PRIx32"%08"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, cardnum, code1, code2, rawHi2, rawHi, rawLo);
|
||||
} else {
|
||||
uint32_t code1 = bytebits_to_byte(dest + 8, fmtLen);
|
||||
sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %ld - Wiegand: %lx, Raw: %08lx%08lx%08lx\n", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo);
|
||||
sprintf((char *)entry, "AWID bit len: %d -unk bit len - Card: %"PRIu32" - Wiegand: %"PRIx32", Raw: %08"PRIx32"%08"PRIx32"%08"PRIx32"\n", fmtLen, cardnum, code1, rawHi2, rawHi, rawLo);
|
||||
}
|
||||
}
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
Dbprintf("%s", entry);
|
||||
BigBuf_free();
|
||||
return PM3_SUCCESS;
|
||||
|
@ -209,15 +210,15 @@ uint32_t IceIOdemod() {
|
|||
uint8_t entry[64];
|
||||
memset(entry, 0, sizeof(entry));
|
||||
|
||||
sprintf((char *)entry, "IO Prox XSF(%02d)%02x:%05d (%08lx%08lx)\n"
|
||||
, version
|
||||
, facilitycode
|
||||
, number
|
||||
, hi
|
||||
, lo
|
||||
);
|
||||
sprintf((char *)entry, "IO Prox XSF(%02u)%02x:%05u (%08"PRIx32"%08"PRIx32")\n"
|
||||
, version
|
||||
, facilitycode
|
||||
, number
|
||||
, hi
|
||||
, lo
|
||||
);
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
Dbprintf("%s", entry);
|
||||
BigBuf_free();
|
||||
return PM3_SUCCESS;
|
||||
|
@ -249,14 +250,14 @@ uint32_t IceHIDDemod() {
|
|||
// go over previously decoded manchester data and decode into usable tag ID
|
||||
if (hi2 != 0) { //extra large HID tags 88/192 bits
|
||||
|
||||
sprintf((char *)entry, "HID large: %lx%08lx%08lx (%ld)\n",
|
||||
hi2,
|
||||
hi,
|
||||
lo,
|
||||
(lo >> 1) & 0xFFFF
|
||||
);
|
||||
sprintf((char *)entry, "HID large: %"PRIx32"%08"PRIx32"%08"PRIx32" (%"PRIu32")\n",
|
||||
hi2,
|
||||
hi,
|
||||
lo,
|
||||
(lo >> 1) & 0xFFFF
|
||||
);
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
|
||||
} else { //standard HID tags 44/96 bits
|
||||
uint8_t bitlen = 0;
|
||||
|
@ -296,16 +297,16 @@ uint32_t IceHIDDemod() {
|
|||
fac = ((hi & 0xF) << 12) | (lo >> 20);
|
||||
}
|
||||
|
||||
sprintf((char *)entry, "HID: %lx%08lx (%ld) Format: %d bit FC: %ld Card: %ld\n",
|
||||
hi,
|
||||
lo,
|
||||
(lo >> 1) & 0xFFFF,
|
||||
bitlen,
|
||||
fac,
|
||||
cardnum
|
||||
);
|
||||
sprintf((char *)entry, "HID: %"PRIx32"%08"PRIx32" (%"PRIu32") Format: %d bit FC: %"PRIu32" Card: %"PRIu32"\n",
|
||||
hi,
|
||||
lo,
|
||||
(lo >> 1) & 0xFFFF,
|
||||
bitlen,
|
||||
fac,
|
||||
cardnum
|
||||
);
|
||||
|
||||
append(entry, strlen((char*)entry));
|
||||
append(entry, strlen((char *)entry));
|
||||
}
|
||||
|
||||
Dbprintf("%s", entry);
|
||||
|
@ -349,7 +350,7 @@ void RunMod() {
|
|||
|
||||
uint32_t res;
|
||||
|
||||
// since we steal 12800 from bigbuffer, no need to sample it.
|
||||
// since we steal 12800 from bigbuffer, no need to sample it.
|
||||
DoAcquisition_config(false, 28000);
|
||||
res = IceHIDDemod();
|
||||
if (res == PM3_SUCCESS) {
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
#include "Standalone/standalone.h"
|
||||
#include "util.h"
|
||||
#include "ticks.h"
|
||||
#include "commonutil.h"
|
||||
|
||||
#ifdef WITH_LCD
|
||||
#include "LCD.h"
|
||||
|
@ -548,7 +549,7 @@ void ListenReaderField(uint8_t limit) {
|
|||
// iceman, useless, since we are measuring readerfield, not our field. My tests shows a max of 20v from a reader.
|
||||
hf_av = hf_max = AvgAdc(ADC_CHAN_HF_RDV40);
|
||||
#else
|
||||
hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
|
||||
hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
|
||||
#endif
|
||||
Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10);
|
||||
hf_baseline = hf_av;
|
||||
|
@ -721,12 +722,20 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
setT55xxConfig(packet->oldarg[0], (t55xx_configurations_t *) packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SAMPLING_GET_CONFIG: {
|
||||
case CMD_LF_SAMPLING_PRINT_CONFIG: {
|
||||
printConfig();
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SAMPLING_GET_CONFIG: {
|
||||
sample_config *config = getSamplingConfig();
|
||||
reply_ng(CMD_LF_SAMPLING_GET_CONFIG, PM3_SUCCESS, (uint8_t *)config, sizeof(sample_config));
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SAMPLING_SET_CONFIG: {
|
||||
setSamplingConfig((sample_config *) packet->data.asBytes);
|
||||
sample_config c;
|
||||
memcpy(&c, packet->data.asBytes, sizeof(sample_config));
|
||||
setSamplingConfig(&c);
|
||||
// setSamplingConfig((sample_config *) packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_ACQ_RAW_ADC: {
|
||||
|
@ -1239,6 +1248,17 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
// SniffMifare(packet->oldarg[0]);
|
||||
// break;
|
||||
// }
|
||||
case CMD_HF_MIFARE_PERSONALIZE_UID: {
|
||||
struct p {
|
||||
uint8_t keytype;
|
||||
uint8_t pers_option;
|
||||
uint8_t key[6];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
uint64_t authkey = bytes_to_num(payload->key, 6);
|
||||
MifarePersonalizeUID(payload->keytype, payload->pers_option, authkey);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_SETMOD: {
|
||||
MifareSetMod(packet->data.asBytes);
|
||||
break;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "buzzer.h"
|
||||
#include "buzzer_disabled.h"
|
||||
|
||||
void Ring_BEE_ONCE(uint16_t music_note) {
|
||||
BEE_ON();
|
||||
|
|
|
@ -26,9 +26,7 @@
|
|||
* May 2005
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "desfire_crypto.h"
|
||||
|
||||
#include "desfire_crypto_disabled.h"
|
||||
#include "crc32.h"
|
||||
#include "printf.h"
|
||||
#include "desfire.h"
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Fonts for the LCD
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "fonts.h"
|
||||
#include "fonts_disabled.h"
|
||||
|
||||
const char FONT6x8[97][8] = {
|
||||
{0x06, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00}, // columns, rows, bytes per char
|
||||
|
|
228
armsrc/hitag2.c
228
armsrc/hitag2.c
|
@ -20,6 +20,8 @@
|
|||
// Anon, 2019
|
||||
// Doegox, 2020
|
||||
|
||||
#define DBG if (DBGLEVEL >= DBG_EXTENDED)
|
||||
|
||||
#include "hitag2.h"
|
||||
#include "hitag2_crypto.h"
|
||||
#include "string.h"
|
||||
|
@ -92,7 +94,7 @@ uint8_t nonce[4];
|
|||
bool key_no;
|
||||
static uint64_t cipher_state;
|
||||
|
||||
size_t blocknr;
|
||||
int16_t blocknr;
|
||||
size_t flipped_bit = 0;
|
||||
uint32_t byte_value = 0;
|
||||
|
||||
|
@ -305,6 +307,9 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
|
|||
break;
|
||||
}
|
||||
|
||||
// LogTrace(rx, nbytes(rxlen), 0, 0, NULL, false);
|
||||
// LogTrace(tx, nbytes(txlen), 0, 0, NULL, true);
|
||||
|
||||
if (tag.crypto_active) {
|
||||
hitag2_cipher_transcrypt(&(tag.cs), tx, *txlen / 8, *txlen % 8);
|
||||
}
|
||||
|
@ -337,12 +342,12 @@ static uint32_t hitag_reader_send_bit(int bit) {
|
|||
lf_wait_periods(HITAG_T_1 - HITAG_T_LOW); // wait for 26-32 times the carrier period
|
||||
wait += HITAG_T_1 - HITAG_T_LOW;
|
||||
}
|
||||
/*lf_wait_periods(10);*/
|
||||
|
||||
LED_A_OFF();
|
||||
return wait;
|
||||
}
|
||||
|
||||
// reader/writer
|
||||
// reader / writer commands
|
||||
static uint32_t hitag_reader_send_frame(const uint8_t *frame, size_t frame_len) {
|
||||
|
||||
uint32_t wait = 0;
|
||||
|
@ -403,7 +408,7 @@ void fix_ac_decoding(uint8_t *input, size_t len) {
|
|||
*/
|
||||
|
||||
|
||||
// looks at number of received bits.
|
||||
// looks at number of received bits.
|
||||
// 0 = collision?
|
||||
// 32 = good response
|
||||
bool hitag_plain(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *txlen, bool hitag_s) {
|
||||
|
@ -539,7 +544,7 @@ bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *t
|
|||
// will receive 32-bit configuration page
|
||||
} else if (bSelecting) {
|
||||
// Initiate auth
|
||||
tx[0] = 0xa0 | key_no >> 4; // WRCPAGE
|
||||
tx[0] = 0xa0 | (key_no); // WRCPAGE
|
||||
tx[1] = blocknr << 4;
|
||||
crc = hitag_crc(tx, 12);
|
||||
tx[1] |= crc >> 4;
|
||||
|
@ -577,14 +582,15 @@ bool hitag1_authenticate(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t *t
|
|||
Dbhexdump(4, logdata_1, false);
|
||||
bSuccessful = true;
|
||||
return false;
|
||||
|
||||
// read next page of card until done
|
||||
tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE
|
||||
tx[1] = blocknr << 4;
|
||||
crc = hitag_crc(tx, 12);
|
||||
tx[1] |= crc >> 4;
|
||||
tx[2] = crc << 4;
|
||||
*txlen = 20;
|
||||
/*
|
||||
// read next page of card until done
|
||||
tx[0] = 0xe0 | blocknr >> 4; // RDCPAGE
|
||||
tx[1] = blocknr << 4;
|
||||
crc = hitag_crc(tx, 12);
|
||||
tx[1] |= crc >> 4;
|
||||
tx[2] = crc << 4;
|
||||
*txlen = 20;
|
||||
*/
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -953,17 +959,18 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
|
|||
memcpy(tag.sectors[blocknr], rx, 4);
|
||||
blocknr++;
|
||||
|
||||
Dbhexdump(4, rx, false);
|
||||
DBG Dbhexdump(4, rx, false);
|
||||
}
|
||||
if (blocknr > 0) {
|
||||
DBG DbpString("Read successful!");
|
||||
bSuccessful = true;
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
// Unexpected response
|
||||
default: {
|
||||
Dbprintf("Unknown frame length: %d", rxlen);
|
||||
DBG Dbprintf("Unknown frame length: %d", rxlen);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
@ -1017,7 +1024,7 @@ void SniffHitag2(void) {
|
|||
|
||||
|
||||
// Receive frame, watch for at most T0*EOF periods
|
||||
lf_reset_counter();
|
||||
// lf_reset_counter();
|
||||
|
||||
// Wait "infinite" for reader modulation
|
||||
periods = lf_detect_gap(20000);
|
||||
|
@ -1071,8 +1078,6 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
|
|||
|
||||
DbpString("Starting Hitag2 simulation");
|
||||
|
||||
LED_D_ON();
|
||||
|
||||
// hitag2 state machine?
|
||||
hitag2_init();
|
||||
|
||||
|
@ -1086,7 +1091,7 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
|
|||
uint32_t block = 0;
|
||||
for (size_t i = 0; i < 12; i++) {
|
||||
|
||||
// num2bytes?
|
||||
// num2bytes?
|
||||
for (size_t j = 0; j < 4; j++) {
|
||||
block <<= 8;
|
||||
block |= tag.sectors[i][j];
|
||||
|
@ -1094,31 +1099,36 @@ void SimulateHitag2(bool tag_mem_supplied, uint8_t *data) {
|
|||
Dbprintf("| %d | %08x |", i, block);
|
||||
}
|
||||
|
||||
uint8_t tag_modulation;
|
||||
uint8_t reader_modulation;
|
||||
size_t max_nrzs = 8 * HITAG_FRAME_LEN + 5;
|
||||
uint8_t nrz_samples[max_nrzs];
|
||||
size_t nrzs = 0, periods = 0;
|
||||
|
||||
// uint32_t command_start = 0, command_duration = 0;
|
||||
// int16_t checked = 0;
|
||||
|
||||
int16_t checked = 0;
|
||||
// SIMULATE
|
||||
|
||||
while (!BUTTON_PRESS()) {
|
||||
|
||||
loop1:
|
||||
LED_D_ON();
|
||||
|
||||
// lf_reset_counter();
|
||||
LED_A_OFF();
|
||||
WDT_HIT();
|
||||
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 100) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
/*
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 100) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
*/
|
||||
|
||||
rxlen = 0;
|
||||
|
||||
|
@ -1126,10 +1136,10 @@ loop1:
|
|||
bool waiting_for_first_edge = true;
|
||||
|
||||
// Did we detected any modulaiton at all
|
||||
bool detected_tag_modulation = false;
|
||||
bool detected_modulation = false;
|
||||
|
||||
// Use the current modulation state as starting point
|
||||
tag_modulation = lf_get_tag_modulation();
|
||||
reader_modulation = lf_get_reader_modulation();
|
||||
|
||||
// Receive frame, watch for at most max_nrzs periods
|
||||
// Reset the number of NRZ samples and use edge detection to detect them
|
||||
|
@ -1141,7 +1151,7 @@ loop1:
|
|||
// Just break out of loop after an initial time-out (tag is probably not available)
|
||||
// The function lf_count_edge_periods() returns 0 when a time-out occurs
|
||||
if (periods == 0) {
|
||||
goto loop1; //break;
|
||||
break;
|
||||
}
|
||||
|
||||
LED_A_ON();
|
||||
|
@ -1159,32 +1169,36 @@ loop1:
|
|||
periods = 16;
|
||||
|
||||
// We have received more than 0 periods, so we have detected a tag response
|
||||
detected_tag_modulation = true;
|
||||
detected_modulation = true;
|
||||
}
|
||||
|
||||
// Evaluate the number of periods before the next edge
|
||||
if (periods > 24 && periods <= 64) {
|
||||
// Detected two sequential equal bits and a modulation switch
|
||||
// NRZ modulation: (11 => --|) or (11 __|)
|
||||
nrz_samples[nrzs++] = tag_modulation;
|
||||
nrz_samples[nrzs++] = tag_modulation;
|
||||
nrz_samples[nrzs++] = reader_modulation;
|
||||
nrz_samples[nrzs++] = reader_modulation;
|
||||
// Invert tag modulation state
|
||||
tag_modulation ^= 1;
|
||||
reader_modulation ^= 1;
|
||||
} else if (periods > 0 && periods <= 24) {
|
||||
// Detected one bit and a modulation switch
|
||||
// NRZ modulation: (1 => -|) or (0 _|)
|
||||
nrz_samples[nrzs++] = tag_modulation;
|
||||
tag_modulation ^= 1;
|
||||
nrz_samples[nrzs++] = reader_modulation;
|
||||
reader_modulation ^= 1;
|
||||
} else {
|
||||
tag_modulation ^= 1;
|
||||
reader_modulation ^= 1;
|
||||
// The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods
|
||||
Dbprintf("Detected unexpected period count: %d", periods);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LED_D_OFF();
|
||||
|
||||
// If there is no response, just repeat the loop
|
||||
if (!detected_tag_modulation) continue;
|
||||
if (!detected_modulation) continue;
|
||||
|
||||
LED_A_OFF();
|
||||
|
||||
// Make sure we always have an even number of samples. This fixes the problem
|
||||
// of ending the manchester decoding with a zero. See the example below where
|
||||
|
@ -1194,7 +1208,7 @@ loop1:
|
|||
// The last modulation change of a zero is not detected, but we should take
|
||||
// the half period in account, otherwise the demodulator will fail.
|
||||
if ((nrzs % 2) != 0) {
|
||||
nrz_samples[nrzs++] = tag_modulation;
|
||||
nrz_samples[nrzs++] = reader_modulation;
|
||||
}
|
||||
|
||||
LED_B_ON();
|
||||
|
@ -1206,8 +1220,8 @@ loop1:
|
|||
if (nrzs < 5) {
|
||||
Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs);
|
||||
continue;
|
||||
} else {
|
||||
for (size_t i = 0; i < 5; i++){
|
||||
} else {
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
if (nrz_samples[i] != 1) {
|
||||
Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one", i);
|
||||
}
|
||||
|
@ -1215,7 +1229,7 @@ loop1:
|
|||
}
|
||||
|
||||
// Pack the response into a byte array
|
||||
for (size_t i = 5; i < 37; i++){
|
||||
for (size_t i = 5; i < 37; i++) {
|
||||
uint8_t bit = nrz_samples[i];
|
||||
rx[rxlen / 8] |= bit << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
|
@ -1233,8 +1247,8 @@ loop1:
|
|||
// not that since the clock counts since the rising edge, but T_Wait1 is
|
||||
// with respect to the falling edge, we need to wait actually (T_Wait1 - T_Low)
|
||||
// periods. The gap time T_Low varies (4..10). All timer values are in
|
||||
// terms of T0 units
|
||||
lf_wait_periods(200);
|
||||
// terms of T0 units (HITAG_T_WAIT_1_MIN - HITAG_T_LOW )
|
||||
lf_wait_periods(HITAG_T_WAIT_1_MIN);
|
||||
|
||||
// Send and store the tag answer (if there is any)
|
||||
if (txlen) {
|
||||
|
@ -1266,19 +1280,19 @@ loop1:
|
|||
|
||||
void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
||||
|
||||
uint32_t command_start = 0;
|
||||
uint32_t command_duration = 0;
|
||||
uint32_t response_start = 0;
|
||||
uint32_t response_duration = 0;
|
||||
uint32_t command_start = 0, command_duration = 0;
|
||||
uint32_t response_start = 0, response_duration = 0;
|
||||
|
||||
uint8_t rx[HITAG_FRAME_LEN];
|
||||
size_t rxlen = 0;
|
||||
uint8_t txbuf[HITAG_FRAME_LEN];
|
||||
uint8_t *tx = txbuf;
|
||||
size_t txlen = 0;
|
||||
int t_wait_1;
|
||||
|
||||
int t_wait_1 = 204;
|
||||
int t_wait_1_guard = 8;
|
||||
int t_wait_2;
|
||||
size_t tag_size;
|
||||
int t_wait_2 = 128;
|
||||
size_t tag_size = 48;
|
||||
bool bStop = false;
|
||||
|
||||
// Raw demodulation/decoding by sampling edge periods
|
||||
|
@ -1292,19 +1306,17 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
set_tracing(true);
|
||||
clear_trace();
|
||||
|
||||
DbpString("Starting Hitag reader family");
|
||||
|
||||
// Check configuration
|
||||
switch (htf) {
|
||||
case RHT1F_PLAIN: {
|
||||
Dbprintf("Read public blocks in plain mode");
|
||||
DBG Dbprintf("Read public blocks in plain mode");
|
||||
// this part will be unreadable
|
||||
memset(tag.sectors + 2, 0x0, 30);
|
||||
blocknr = 0;
|
||||
break;
|
||||
}
|
||||
case RHT1F_AUTHENTICATE: {
|
||||
Dbprintf("Read all blocks in authed mode");
|
||||
DBG Dbprintf("Read all blocks in authed mode");
|
||||
memcpy(nonce, htd->ht1auth.nonce, 4);
|
||||
memcpy(key, htd->ht1auth.key, 4);
|
||||
memcpy(logdata_0, htd->ht1auth.logdata_0, 4);
|
||||
|
@ -1314,19 +1326,19 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
memset(logdata_1, 0x00, 4);
|
||||
byte_value = 0;
|
||||
key_no = htd->ht1auth.key_no;
|
||||
Dbprintf("Authenticating using key #%d:", key_no);
|
||||
Dbhexdump(4, key, false);
|
||||
DbpString("Nonce:");
|
||||
Dbhexdump(4, nonce, false);
|
||||
DbpString("Logdata_0:");
|
||||
Dbhexdump(4, logdata_0, false);
|
||||
DbpString("Logdata_1:");
|
||||
Dbhexdump(4, logdata_1, false);
|
||||
DBG Dbprintf("Authenticating using key #%d:", key_no);
|
||||
DBG Dbhexdump(4, key, false);
|
||||
DBG DbpString("Nonce:");
|
||||
DBG Dbhexdump(4, nonce, false);
|
||||
DBG DbpString("Logdata_0:");
|
||||
DBG Dbhexdump(4, logdata_0, false);
|
||||
DBG DbpString("Logdata_1:");
|
||||
DBG Dbhexdump(4, logdata_1, false);
|
||||
blocknr = 0;
|
||||
break;
|
||||
}
|
||||
case RHT2F_PASSWORD: {
|
||||
Dbprintf("List identifier in password mode");
|
||||
DBG Dbprintf("List identifier in password mode");
|
||||
if (memcmp(htd->pwd.password, "\x00\x00\x00\x00", 4) == 0)
|
||||
memcpy(password, tag.sectors[1], sizeof(password));
|
||||
else
|
||||
|
@ -1338,19 +1350,19 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
break;
|
||||
}
|
||||
case RHT2F_AUTHENTICATE: {
|
||||
DbpString("Authenticating using nr,ar pair:");
|
||||
DBG DbpString("Authenticating using nr,ar pair:");
|
||||
memcpy(NrAr, htd->auth.NrAr, 8);
|
||||
Dbhexdump(8, NrAr, false);
|
||||
DBG Dbhexdump(8, NrAr, false);
|
||||
bCrypto = false;
|
||||
bAuthenticating = false;
|
||||
break;
|
||||
}
|
||||
case RHT2F_CRYPTO: {
|
||||
DbpString("Authenticating using key:");
|
||||
DBG DbpString("Authenticating using key:");
|
||||
memcpy(key, htd->crypto.key, 6); //HACK; 4 or 6?? I read both in the code.
|
||||
Dbhexdump(6, key, false);
|
||||
DbpString("Nonce:");
|
||||
Dbhexdump(4, nonce, false);
|
||||
DBG Dbhexdump(6, key, false);
|
||||
DBG DbpString("Nonce:");
|
||||
DBG Dbhexdump(4, nonce, false);
|
||||
memcpy(nonce, htd->crypto.data, 4);
|
||||
blocknr = 0;
|
||||
bCrypto = false;
|
||||
|
@ -1358,7 +1370,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
break;
|
||||
}
|
||||
case RHT2F_TEST_AUTH_ATTEMPTS: {
|
||||
Dbprintf("Testing %d authentication attempts", (auth_table_len / 8));
|
||||
DBG Dbprintf("Testing %d authentication attempts", (auth_table_len / 8));
|
||||
auth_table_pos = 0;
|
||||
memcpy(NrAr, auth_table, 8);
|
||||
bCrypto = false;
|
||||
|
@ -1371,7 +1383,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
break;
|
||||
}
|
||||
default: {
|
||||
Dbprintf("Error, unknown function: %d", htf);
|
||||
DBG Dbprintf("Error, unknown function: %d", htf);
|
||||
set_tracing(false);
|
||||
return;
|
||||
}
|
||||
|
@ -1382,9 +1394,6 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
// hitag2 state machine?
|
||||
hitag2_init();
|
||||
|
||||
// init as reader
|
||||
lf_init(true, false);
|
||||
|
||||
uint8_t attempt_count = 0;
|
||||
|
||||
// Tag specific configuration settings (sof, timings, etc.)
|
||||
|
@ -1392,41 +1401,40 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
// hitagS settings
|
||||
t_wait_1 = 204;
|
||||
t_wait_2 = 128;
|
||||
/*tag_size = 256;*/
|
||||
flipped_bit = 0;
|
||||
tag_size = 8;
|
||||
DbpString("Configured for hitagS reader");
|
||||
DBG DbpString("Configured for hitagS reader");
|
||||
} else if (htf < 20) {
|
||||
// hitag1 settings
|
||||
t_wait_1 = 204;
|
||||
t_wait_2 = 128;
|
||||
tag_size = 256;
|
||||
flipped_bit = 0;
|
||||
DbpString("Configured for hitag1 reader");
|
||||
DBG DbpString("Configured for hitag1 reader");
|
||||
} else if (htf < 30) {
|
||||
// hitag2 settings
|
||||
t_wait_1 = HITAG_T_WAIT_1_MIN;
|
||||
t_wait_2 = HITAG_T_WAIT_2_MIN;
|
||||
tag_size = 48;
|
||||
DbpString("Configured for hitag2 reader");
|
||||
} else {
|
||||
Dbprintf("Error, unknown hitag reader type: %d", htf);
|
||||
return;
|
||||
DBG DbpString("Configured for hitag2 reader");
|
||||
}
|
||||
|
||||
// init as reader
|
||||
lf_init(true, false);
|
||||
|
||||
uint8_t tag_modulation;
|
||||
size_t max_nrzs = (8 * HITAG_FRAME_LEN + 5) * 2; // up to 2 nrzs per bit
|
||||
uint8_t nrz_samples[max_nrzs];
|
||||
size_t nrzs = 0;
|
||||
int16_t checked = 0;
|
||||
|
||||
while (!bStop) {
|
||||
while (!bStop && !BUTTON_PRESS()) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 1000) {
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
|
@ -1471,7 +1479,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
break;
|
||||
}
|
||||
default: {
|
||||
Dbprintf("Error, unknown function: %d", htf);
|
||||
DBG Dbprintf("Error, unknown function: %d", htf);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
@ -1531,7 +1539,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
} else {
|
||||
// The function lf_count_edge_periods() returns 0 when a time-out occurs
|
||||
if (periods == 0) {
|
||||
//Dbprintf("Detected timeout after [%d] nrz samples", nrzs);
|
||||
DBG Dbprintf("Detected timeout after [%d] nrz samples", nrzs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1552,7 +1560,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
tag_modulation ^= 1;
|
||||
} else {
|
||||
// The function lf_count_edge_periods() returns > 64 periods, this is not a valid number periods
|
||||
//Dbprintf("Detected unexpected period count: %d", periods);
|
||||
DBG Dbprintf("Detected unexpected period count: %d", periods);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1591,13 +1599,13 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
|
||||
// Verify if the header consists of five consecutive ones
|
||||
if (nrzs < 5) {
|
||||
Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs);
|
||||
DBG Dbprintf("Detected unexpected number of manchester decoded samples [%d]", nrzs);
|
||||
break;
|
||||
} else {
|
||||
size_t i;
|
||||
for (i = 0; i < 5; i++) {
|
||||
if (nrz_samples[i] != 1) {
|
||||
Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one, abort", i);
|
||||
DBG Dbprintf("Detected incorrect header, the bit [%d] is zero instead of one, abort", i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1608,7 +1616,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
for (size_t i = 5; i < nrzs; i++) {
|
||||
uint8_t bit = nrz_samples[i];
|
||||
if (bit > 1) { // When Manchester detects impossible symbol it writes "7"
|
||||
Dbprintf("Error in Manchester decoding, abort");
|
||||
DBG Dbprintf("Error in Manchester decoding, abort");
|
||||
break;
|
||||
}
|
||||
rx[rxlen / 8] |= bit << (7 - (rxlen % 8));
|
||||
|
@ -1648,16 +1656,18 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
uint32_t command_start = 0;
|
||||
uint32_t command_duration = 0;
|
||||
uint32_t response_start = 0;
|
||||
uint32_t response_duration = 0;
|
||||
uint32_t response_duration = 0;
|
||||
uint8_t rx[HITAG_FRAME_LEN];
|
||||
size_t rxlen = 0;
|
||||
uint8_t txbuf[HITAG_FRAME_LEN];
|
||||
uint8_t *tx = txbuf;
|
||||
size_t txlen = 0;
|
||||
int t_wait_1;
|
||||
|
||||
int t_wait_1 = 204;
|
||||
int t_wait_1_guard = 8;
|
||||
int t_wait_2;
|
||||
size_t tag_size;
|
||||
int t_wait_2 = 128;
|
||||
size_t tag_size = 48;
|
||||
|
||||
bool bStop = false;
|
||||
|
||||
// Raw demodulation/decoding by sampling edge periods
|
||||
|
@ -1671,8 +1681,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
set_tracing(true);
|
||||
clear_trace();
|
||||
|
||||
DbpString("Starting Hitag writer family");
|
||||
|
||||
|
||||
// Check configuration
|
||||
switch (htf) {
|
||||
case WHT2F_CRYPTO: {
|
||||
|
@ -1710,7 +1719,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
|
||||
// init as reader
|
||||
lf_init(true, false);
|
||||
|
||||
|
||||
// Tag specific configuration settings (sof, timings, etc.)
|
||||
if (htf < 10) {
|
||||
// hitagS settings
|
||||
|
@ -1721,21 +1730,18 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
tag_size = 8;
|
||||
DbpString("Configured for hitagS writer");
|
||||
} else if (htf < 20) {
|
||||
// hitag1 settings
|
||||
// hitag1 settings
|
||||
t_wait_1 = 204;
|
||||
t_wait_2 = 128;
|
||||
tag_size = 256;
|
||||
flipped_bit = 0;
|
||||
DbpString("Configured for hitag1 writer");
|
||||
} else if (htf < 30) {
|
||||
// hitag2 settings
|
||||
// hitag2 settings
|
||||
t_wait_1 = HITAG_T_WAIT_1_MIN;
|
||||
t_wait_2 = HITAG_T_WAIT_2_MIN;
|
||||
tag_size = 48;
|
||||
DbpString("Configured for hitag2 writer");
|
||||
} else {
|
||||
Dbprintf("Error, unknown hitag writer type: %d", htf);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t tag_modulation;
|
||||
|
@ -1744,11 +1750,11 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
size_t nrzs = 0;
|
||||
|
||||
int16_t checked = 0;
|
||||
while (!bStop) {
|
||||
while (!bStop && !BUTTON_PRESS()) {
|
||||
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 1000) {
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
|
@ -1776,7 +1782,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
}
|
||||
}
|
||||
|
||||
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
||||
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
||||
lf_wait_periods(t_wait_2);
|
||||
command_start += t_wait_2;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
// hitag2 attack functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "hitagcrypto.h"
|
||||
#include "hitag2_crypto.h"
|
||||
#include "hitag2crack.h"
|
||||
|
||||
#define READP0CMD "1100000111"
|
||||
|
@ -38,70 +38,60 @@ bool hitag2_crack(uint8_t *response, uint8_t *nrarhex) {
|
|||
uint8_t temp[20];
|
||||
int i;
|
||||
uint8_t *spaceptr = NULL;
|
||||
|
||||
|
||||
// get uid as hexstring
|
||||
if(!hitag2_get_uid(uidhex))
|
||||
{
|
||||
if (!hitag2_get_uid(uidhex)) {
|
||||
UserMessage("Cannot get UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert uid hexstring to binarray
|
||||
hextobinarray(uid, uidhex);
|
||||
|
||||
|
||||
// convert nR and aR hexstrings to binarray
|
||||
spaceptr = strchr(nrarhex, ' ');
|
||||
if (!spaceptr)
|
||||
{
|
||||
if (!spaceptr) {
|
||||
UserMessage("Please supply a valid nR aR pair\r\n");
|
||||
return false;
|
||||
}
|
||||
*spaceptr = 0x00;
|
||||
|
||||
if (hextobinarray(nrar, nrarhex) != 32)
|
||||
{
|
||||
|
||||
if (hextobinarray(nrar, nrarhex) != 32) {
|
||||
UserMessage("nR is not 32 bits long\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hextobinarray(nrar + 32, spaceptr + 1) != 32)
|
||||
{
|
||||
|
||||
if (hextobinarray(nrar + 32, spaceptr + 1) != 32) {
|
||||
UserMessage("aR is not 32 bits long\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// find a valid encrypted command
|
||||
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar))
|
||||
{
|
||||
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) {
|
||||
UserMessage("Cannot find a valid encrypted command\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// find the 'read page 0' command and recover key stream
|
||||
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid))
|
||||
{
|
||||
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) {
|
||||
UserMessage("Cannot find encrypted 'read page0' command\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// empty the response string
|
||||
response[0] = 0x00;
|
||||
|
||||
|
||||
// read all pages using key stream
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
if (hitag2crack_read_page(pagehex, i, nrar, keybits))
|
||||
{
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (hitag2crack_read_page(pagehex, i, nrar, keybits)) {
|
||||
sprintf(temp, "%1d: %s\r\n", i, pagehex);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
sprintf(temp, "%1d:\r\n", i);
|
||||
}
|
||||
// add page string to response
|
||||
strcat(response, temp);
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -113,16 +103,16 @@ bool hitag2_crack(uint8_t *response, uint8_t *nrarhex) {
|
|||
bool hitag2crack_find_valid_e_cmd(uint8_t e_cmd[], uint8_t nrar[]) {
|
||||
uint8_t guess[10];
|
||||
uint8_t responsestr[9];
|
||||
|
||||
|
||||
// UserMessage("Finding valid encrypted command:");
|
||||
// we're going to hold bits 5, 7, 8 and 9 and brute force the rest
|
||||
// e.g. x x x x x 0 x 0 0 0
|
||||
for (uint8_t a=0; a<2; a++) {
|
||||
for (uint8_t b=0; b<2; b++) {
|
||||
for (uint8_t c=0; c<2; c++) {
|
||||
for (uint8_t d=0; d<2; d++) {
|
||||
for (uint8_t e=0; e<2; e++) {
|
||||
for (uint8_t g=0; g<2; g++) {
|
||||
for (uint8_t a = 0; a < 2; a++) {
|
||||
for (uint8_t b = 0; b < 2; b++) {
|
||||
for (uint8_t c = 0; c < 2; c++) {
|
||||
for (uint8_t d = 0; d < 2; d++) {
|
||||
for (uint8_t e = 0; e < 2; e++) {
|
||||
for (uint8_t g = 0; g < 2; g++) {
|
||||
// build binarray
|
||||
guess[0] = a;
|
||||
guess[1] = b;
|
||||
|
@ -175,65 +165,50 @@ bool hitag2crack_find_e_page0_cmd(uint8_t keybits[], uint8_t e_firstcmd[], uint8
|
|||
|
||||
UserMessage("Finding 'read page 0' command:");
|
||||
// we're going to brute the missing 4 bits of the valid encrypted command
|
||||
for (a=0; a<2; a++)
|
||||
{
|
||||
for (b=0; b<2; b++)
|
||||
{
|
||||
for (c=0; c<2; c++)
|
||||
{
|
||||
for (d=0; d<2; d++)
|
||||
{
|
||||
for (a = 0; a < 2; a++) {
|
||||
for (b = 0; b < 2; b++) {
|
||||
for (c = 0; c < 2; c++) {
|
||||
for (d = 0; d < 2; d++) {
|
||||
// create our guess by bit flipping the pattern of bits
|
||||
// representing the inverted bit and the 3 page bits
|
||||
// in both the non-inverted and inverted parts of the
|
||||
// encrypted command.
|
||||
memcpy(guess, e_firstcmd, 10);
|
||||
if (a)
|
||||
{
|
||||
if (a) {
|
||||
guess[5] = !guess[5];
|
||||
guess[0] = !guess[0];
|
||||
}
|
||||
if (b)
|
||||
{
|
||||
if (b) {
|
||||
guess[7] = !guess[7];
|
||||
guess[2] = !guess[2];
|
||||
}
|
||||
if (c)
|
||||
{
|
||||
if (c) {
|
||||
guess[8] = !guess[8];
|
||||
guess[3] = !guess[3];
|
||||
}
|
||||
if (d)
|
||||
{
|
||||
if (d) {
|
||||
guess[9] = !guess[9];
|
||||
guess[4] = !guess[4];
|
||||
}
|
||||
|
||||
|
||||
// try the guess
|
||||
if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10))
|
||||
{
|
||||
if (hitag2crack_send_e_cmd(responsestr, nrar, guess, 10)) {
|
||||
// check if it was valid
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) != 0)
|
||||
{
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) != 0) {
|
||||
// convert response to binarray
|
||||
hextobinarray(e_uid, responsestr);
|
||||
// test if the guess was 'read page 0' command
|
||||
if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid))
|
||||
{
|
||||
|
||||
if (hitag2crack_test_e_p0cmd(keybits, nrar, guess, uid, e_uid)) {
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef RFIDLER_DEBUG
|
||||
} else {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_find_e_page0_cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
|
||||
#endif
|
||||
}
|
||||
|
@ -262,56 +237,51 @@ bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, u
|
|||
uint8_t e_ext_cmd[40];
|
||||
uint8_t responsestr[9];
|
||||
int i;
|
||||
|
||||
|
||||
// copy encrypted cmd to cipherbits
|
||||
memcpy(cipherbits, e_cmd, 10);
|
||||
|
||||
|
||||
// copy encrypted uid to cipherbits
|
||||
memcpy(cipherbits + 10, e_uid, 32);
|
||||
|
||||
|
||||
// copy cmd to plainbits
|
||||
binstringtobinarray(plainbits, READP0CMD);
|
||||
|
||||
|
||||
// copy uid to plainbits
|
||||
memcpy(plainbits + 10, uid, 32);
|
||||
|
||||
// xor the plainbits with the cipherbits to get keybits
|
||||
hitag2crack_xor(keybits, plainbits, cipherbits, 42);
|
||||
|
||||
|
||||
// create extended cmd -> 4 * READP0CMD = 40 bits
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
for (i = 0; i < 4; i++) {
|
||||
binstringtobinarray(ext_cmd + (i * 10), READP0CMD);
|
||||
}
|
||||
|
||||
|
||||
// xor extended cmd with keybits
|
||||
hitag2crack_xor(e_ext_cmd, ext_cmd, keybits, 40);
|
||||
|
||||
|
||||
// send extended encrypted cmd
|
||||
if (hitag2crack_send_e_cmd(responsestr, nrar, e_ext_cmd, 40))
|
||||
{
|
||||
if (hitag2crack_send_e_cmd(responsestr, nrar, e_ext_cmd, 40)) {
|
||||
// test if it was valid
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) != 0)
|
||||
{
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_test_e_p0cmd:\r\n hitag2crack_send_e_cmd failed\r\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
// hitag2crack_xor XORs the source with the pad to produce the target.
|
||||
// source, target and pad are binarrays of length len.
|
||||
void hitag2crack_xor(uint8_t *target, uint8_t *source, uint8_t *pad, unsigned int len) {
|
||||
|
||||
for (int i=0; i<len; i++) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
target[i] = source[i] ^ pad[i];
|
||||
}
|
||||
}
|
||||
|
@ -329,40 +299,34 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar,
|
|||
uint8_t e_response[32];
|
||||
uint8_t response[32];
|
||||
int i;
|
||||
|
||||
if ((pagenum < 0) || (pagenum > 7))
|
||||
{
|
||||
|
||||
if (pagenum > 7) {
|
||||
UserMessage("hitag2crack_read_page:\r\n invalid pagenum\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// create cmd
|
||||
binstringtobinarray(cmd, READP0CMD);
|
||||
if (pagenum & 0x1)
|
||||
{
|
||||
if (pagenum & 0x1) {
|
||||
cmd[9] = !cmd[9];
|
||||
cmd[4] = !cmd[4];
|
||||
}
|
||||
if (pagenum & 0x2)
|
||||
{
|
||||
if (pagenum & 0x2) {
|
||||
cmd[8] = !cmd[8];
|
||||
cmd[3] = !cmd[3];
|
||||
}
|
||||
if (pagenum & 0x4)
|
||||
{
|
||||
if (pagenum & 0x4) {
|
||||
cmd[7] = !cmd[7];
|
||||
cmd[2] = !cmd[2];
|
||||
}
|
||||
|
||||
|
||||
// encrypt command
|
||||
hitag2crack_xor(e_cmd, cmd, keybits, 10);
|
||||
|
||||
|
||||
// send encrypted command
|
||||
if (hitag2crack_send_e_cmd(e_responsestr, nrar, e_cmd, 10))
|
||||
{
|
||||
if (hitag2crack_send_e_cmd(e_responsestr, nrar, e_cmd, 10)) {
|
||||
// check if it is valid
|
||||
if (strcmp(e_responsestr, ERROR_RESPONSE) != 0)
|
||||
{
|
||||
if (strcmp(e_responsestr, ERROR_RESPONSE) != 0) {
|
||||
// convert to binarray
|
||||
hextobinarray(e_response, e_responsestr);
|
||||
// decrypt response
|
||||
|
@ -370,17 +334,13 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar,
|
|||
// convert to hexstring
|
||||
binarraytohex(responsestr, response, 32);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd failed\r\n");
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -391,14 +351,13 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar,
|
|||
// cmd is the binarray of the encrypted command to send;
|
||||
// len is the length of the encrypted command.
|
||||
bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, int len) {
|
||||
uint8_t tmp[37];
|
||||
// uint8_t tmp[37];
|
||||
uint8_t uid[9];
|
||||
uint8_t e_page3str[9];
|
||||
int ret = 0;
|
||||
|
||||
// get the UID
|
||||
if(!hitag2_get_uid(uid))
|
||||
{
|
||||
if (!hitag2_get_uid(uid)) {
|
||||
UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -407,22 +366,19 @@ bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, i
|
|||
CryptoActive = false;
|
||||
|
||||
// get the UID again
|
||||
if(!hitag2_get_uid(uid))
|
||||
{
|
||||
if (!hitag2_get_uid(uid)) {
|
||||
UserMessage("hitag2crack_send_e_cmd:\r\n cannot get UID (2nd time)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// send nrar and receive (useless) encrypted page 3 value
|
||||
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false))
|
||||
{
|
||||
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) {
|
||||
UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx nrar failed\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// send encrypted command
|
||||
if (!hitag2crack_tx_rx(responsestr, cmd, len, RWD_STATE_WAKING, false))
|
||||
{
|
||||
if (!hitag2crack_tx_rx(responsestr, cmd, len, RWD_STATE_WAKING, false)) {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_send_e_cmd:\r\n tx/rx cmd failed\r\n");
|
||||
#endif
|
||||
|
@ -442,34 +398,29 @@ bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, b
|
|||
int ret = 0;
|
||||
|
||||
// START_AUTH kills active crypto session
|
||||
CryptoActive= false;
|
||||
|
||||
if(!rwd_send(msg, len, reset, BLOCK, state, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX))
|
||||
{
|
||||
CryptoActive = false;
|
||||
|
||||
if (!rwd_send(msg, len, reset, BLOCK, state, RFIDlerConfig.FrameClock, 0, RFIDlerConfig.RWD_Wait_Switch_RX_TX, RFIDlerConfig.RWD_Zero_Period, RFIDlerConfig.RWD_One_Period, RFIDlerConfig.RWD_Gap_Period, RFIDlerConfig.RWD_Wait_Switch_TX_RX)) {
|
||||
UserMessage("hitag2crack_tx_rx: rwd_send failed\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// skip 1/2 bit to synchronise manchester
|
||||
HW_Skip_Bits = 1;
|
||||
ret = read_ask_data(RFIDlerConfig.FrameClock, RFIDlerConfig.DataRate, tmp, 37, RFIDlerConfig.Sync, RFIDlerConfig.SyncBits, RFIDlerConfig.Timeout, ONESHOT_READ, BINARY);
|
||||
|
||||
// check if response was a valid length (5 sync bits + 32 bits response)
|
||||
if (ret == 37)
|
||||
{
|
||||
if (ret == 37) {
|
||||
// check sync bits
|
||||
if (memcmp(tmp, Hitag2Sync, 5) != 0)
|
||||
{
|
||||
if (memcmp(tmp, Hitag2Sync, 5) != 0) {
|
||||
UserMessage("hitag2crack_tx_rx: no sync\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// convert response to hexstring
|
||||
binarraytohex(responsestr, tmp + 5, 32);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
UserMessage("hitag2crack_tx_rx: wrong rx len\r\n");
|
||||
#endif
|
||||
|
@ -485,58 +436,53 @@ bool hitag2crack_rng_init(uint8_t *response, uint8_t *input) {
|
|||
uint32_t initvector;
|
||||
uint8_t *spaceptr;
|
||||
uint8_t *dataptr;
|
||||
|
||||
|
||||
// extract vals from input
|
||||
dataptr = input;
|
||||
spaceptr = strchr(dataptr, ' ');
|
||||
if (!spaceptr)
|
||||
{
|
||||
if (!spaceptr) {
|
||||
UserMessage("/r/nformat is 'sharedkey UID nR' in hex\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
*spaceptr = 0x00;
|
||||
|
||||
if (strlen(dataptr) != 12)
|
||||
{
|
||||
|
||||
if (strlen(dataptr) != 12) {
|
||||
UserMessage("/r/nsharedkey should be 48 bits long (12 hexchars)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
sharedkey = rev64(hexreversetoulonglong(dataptr));
|
||||
|
||||
dataptr = spaceptr+1;
|
||||
|
||||
dataptr = spaceptr + 1;
|
||||
spaceptr = strchr(dataptr, ' ');
|
||||
if (!spaceptr)
|
||||
{
|
||||
if (!spaceptr) {
|
||||
UserMessage("/r/nno UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
*spaceptr = 0x00;
|
||||
if (strlen(dataptr) != 8)
|
||||
{
|
||||
if (strlen(dataptr) != 8) {
|
||||
UserMessage("/r/nUID should be 32 bits long (8 hexchars)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
serialnum = rev32(hexreversetoulong(dataptr));
|
||||
|
||||
dataptr = spaceptr+1;
|
||||
|
||||
if (strlen(dataptr) != 8)
|
||||
{
|
||||
|
||||
dataptr = spaceptr + 1;
|
||||
|
||||
if (strlen(dataptr) != 8) {
|
||||
UserMessage("/r/nnR should be 32 bits long (8 hexchars)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
initvector = rev32(hexreversetoulong(dataptr));
|
||||
|
||||
|
||||
// start up crypto engine
|
||||
hitag2_init(&Hitag_Crypto_State, sharedkey, serialnum, initvector);
|
||||
|
||||
|
||||
strcpy(response, "Success\r\n");
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -545,21 +491,20 @@ bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex) {
|
|||
uint8_t binhex[9];
|
||||
uint8_t binstr[33];
|
||||
uint32_t binulong;
|
||||
|
||||
if (strlen(hex) != 8)
|
||||
{
|
||||
|
||||
if (strlen(hex) != 8) {
|
||||
UserMessage("/r/nhex must be 32bits (8 hex chars)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
binulong = hextoulong(hex);
|
||||
|
||||
|
||||
ulongtobinarray(bin, hitag2_crypt(binulong, 32), 32);
|
||||
binarraytobinstring(binstr, bin, 32);
|
||||
binarraytohex(binhex, bin, 32);
|
||||
// UserMessage("ar = %s\r\n", binstr);
|
||||
// UserMessage("arhex = %s\r\n", binhex);
|
||||
|
||||
|
||||
strcpy(response, binhex);
|
||||
return true;
|
||||
}
|
||||
|
@ -570,17 +515,16 @@ bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *e_binstr) {
|
|||
uint8_t binstr[33];
|
||||
uint32_t binulong;
|
||||
int len;
|
||||
|
||||
|
||||
len = strlen(e_binstr);
|
||||
if (len > 32)
|
||||
{
|
||||
if (len > 32) {
|
||||
UserMessage("\r\nbinary string must be <= 32 bits\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
binstringtobinarray(e_bin, e_binstr);
|
||||
binulong = binarraytoulong(e_bin, len);
|
||||
|
||||
|
||||
ulongtobinarray(bin, hitag2_crypt(binulong, len), len);
|
||||
binarraytobinstring(binstr, bin, len);
|
||||
strcpy(response, binstr);
|
||||
|
@ -595,7 +539,7 @@ bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex) {
|
|||
bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *e_binstr) {
|
||||
return hitag2crack_decrypt_bin(response, e_binstr);
|
||||
}
|
||||
|
||||
|
||||
// hitag2_keystream uses the first crack algorithm described in the paper,
|
||||
// Gone In 360 Seconds by Verdult, Garcia and Balasch, to retrieve 2048 bits
|
||||
// of keystream.
|
||||
|
@ -607,113 +551,101 @@ bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex) {
|
|||
uint8_t uid[32];
|
||||
uint8_t nrar[64];
|
||||
uint8_t e_firstcmd[10];
|
||||
uint8_t e_page0cmd[10];
|
||||
// uint8_t e_page0cmd[10];
|
||||
// uint8_t keybits[2080];
|
||||
uint8_t *keybits = DataBuff;
|
||||
uint8_t keybitshex[67];
|
||||
int kslen;
|
||||
int ksoffset;
|
||||
uint8_t pagehex[9];
|
||||
uint8_t temp[20];
|
||||
// uint8_t pagehex[9];
|
||||
// uint8_t temp[20];
|
||||
int i;
|
||||
uint8_t *spaceptr = NULL;
|
||||
|
||||
/*
|
||||
keybits = malloc(2080);
|
||||
if (!keybits) {
|
||||
UserMessage("cannot malloc keybits\r\n");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
keybits = malloc(2080);
|
||||
if (!keybits) {
|
||||
UserMessage("cannot malloc keybits\r\n");
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
// get uid as hexstring
|
||||
if(!hitag2_get_uid(uidhex))
|
||||
{
|
||||
if (!hitag2_get_uid(uidhex)) {
|
||||
UserMessage("Cannot get UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert uid hexstring to binarray
|
||||
hextobinarray(uid, uidhex);
|
||||
|
||||
|
||||
// convert nR and aR hexstrings to binarray
|
||||
spaceptr = strchr(nrarhex, ' ');
|
||||
if (!spaceptr)
|
||||
{
|
||||
if (!spaceptr) {
|
||||
UserMessage("Please supply a valid nR aR pair\r\n");
|
||||
return false;
|
||||
}
|
||||
*spaceptr = 0x00;
|
||||
|
||||
if (hextobinarray(nrar, nrarhex) != 32)
|
||||
{
|
||||
|
||||
if (hextobinarray(nrar, nrarhex) != 32) {
|
||||
UserMessage("nR is not 32 bits long\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hextobinarray(nrar + 32, spaceptr + 1) != 32)
|
||||
{
|
||||
|
||||
if (hextobinarray(nrar + 32, spaceptr + 1) != 32) {
|
||||
UserMessage("aR is not 32 bits long\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
// find a valid encrypted command
|
||||
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar))
|
||||
{
|
||||
if (!hitag2crack_find_valid_e_cmd(e_firstcmd, nrar)) {
|
||||
UserMessage("Cannot find a valid encrypted command\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// find the 'read page 0' command and recover key stream
|
||||
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid))
|
||||
{
|
||||
if (!hitag2crack_find_e_page0_cmd(keybits, e_firstcmd, nrar, uid)) {
|
||||
UserMessage("Cannot find encrypted 'read page0' command\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// using the 40 bits of keystream in keybits, sending commands with ever
|
||||
// increasing lengths to acquire 2048 bits of key stream.
|
||||
kslen = 40;
|
||||
|
||||
while (kslen < 2048)
|
||||
{
|
||||
|
||||
while (kslen < 2048) {
|
||||
ksoffset = 0;
|
||||
if (!hitag2crack_send_auth(nrar))
|
||||
{
|
||||
if (!hitag2crack_send_auth(nrar)) {
|
||||
UserMessage("hitag2crack_send_auth failed\r\n");
|
||||
return false;
|
||||
}
|
||||
// while we have at least 52 bits of keystream, consume it with
|
||||
// extended read page 0 commands. 52 = 10 (min command len) +
|
||||
// 32 (response) + 10 (min command len we'll send)
|
||||
while ((kslen - ksoffset) >= 52)
|
||||
{
|
||||
while ((kslen - ksoffset) >= 52) {
|
||||
// consume the keystream, updating ksoffset as we go
|
||||
if (!hitag2crack_consume_keystream(keybits, kslen, &ksoffset, nrar))
|
||||
{
|
||||
if (!hitag2crack_consume_keystream(keybits, kslen, &ksoffset, nrar)) {
|
||||
UserMessage("hitag2crack_consume_keystream failed\r\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// send an extended command to retrieve more keystream, updating kslen
|
||||
// as we go
|
||||
if (!hitag2crack_extend_keystream(keybits, &kslen, ksoffset, nrar, uid))
|
||||
{
|
||||
if (!hitag2crack_extend_keystream(keybits, &kslen, ksoffset, nrar, uid)) {
|
||||
UserMessage("hitag2crack_extend_keystream failed\r\n");
|
||||
return false;
|
||||
}
|
||||
UserMessage("Recovered %d bits of keystream\r\n", kslen);
|
||||
|
||||
}
|
||||
|
||||
for (i=0; i<2048; i+=256)
|
||||
{
|
||||
|
||||
for (i = 0; i < 2048; i += 256) {
|
||||
binarraytohex(keybitshex, keybits + i, 256);
|
||||
UserMessage("%s\r\n", keybitshex);
|
||||
}
|
||||
|
||||
response[0] = 0x00;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -724,8 +656,7 @@ bool hitag2crack_send_auth(uint8_t *nrar) {
|
|||
uint8_t e_page3str[9];
|
||||
|
||||
// get the UID
|
||||
if(!hitag2_get_uid(uid))
|
||||
{
|
||||
if (!hitag2_get_uid(uid)) {
|
||||
UserMessage("hitag2crack_send_auth:\r\n cannot get UID\r\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -734,15 +665,13 @@ bool hitag2crack_send_auth(uint8_t *nrar) {
|
|||
CryptoActive = false;
|
||||
|
||||
// get the UID again
|
||||
if(!hitag2_get_uid(uid))
|
||||
{
|
||||
if (!hitag2_get_uid(uid)) {
|
||||
UserMessage("hitag2crack_send_auth:\r\n cannot get UID (2nd time)\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// send nrar and receive (useless) encrypted page 3 value
|
||||
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false))
|
||||
{
|
||||
if (!hitag2crack_tx_rx(e_page3str, nrar, 64, RWD_STATE_WAKING, false)) {
|
||||
UserMessage("hitag2crack_send_auth:\r\n tx/rx nrar failed\r\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -767,46 +696,41 @@ bool hitag2crack_consume_keystream(uint8_t *keybits, int kslen, int *ksoffset, u
|
|||
// 42 = 32 bit response + 10 bit command reserved for next command. conlen
|
||||
// cannot be longer than 510 bits to fit into the small RWD buffer.
|
||||
conlen = kslen - *ksoffset - 42;
|
||||
if (conlen < 10)
|
||||
{
|
||||
if (conlen < 10) {
|
||||
UserMessage("hitag2crack_consume_keystream:\r\n conlen < 10\r\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// sanitise conlen
|
||||
if (conlen > 510)
|
||||
{
|
||||
if (conlen > 510) {
|
||||
conlen = 510;
|
||||
}
|
||||
|
||||
|
||||
// calculate how many repeated commands to send in this extended command.
|
||||
numcmds = conlen / 10;
|
||||
|
||||
|
||||
// build extended command
|
||||
for (i=0; i<numcmds; i++)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
@ -825,36 +749,32 @@ bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, ui
|
|||
uint8_t responsestr[9];
|
||||
uint8_t e_response[32];
|
||||
int i;
|
||||
|
||||
|
||||
// calc number of command iterations to send
|
||||
cmdlen = *kslen - ksoffset;
|
||||
if (cmdlen < 10)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
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))
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (strcmp(responsestr, ERROR_RESPONSE) == 0) {
|
||||
UserMessage("hitag2crack_extend_keystream:\r\n got error response from card\r\n");
|
||||
return false;
|
||||
}
|
||||
|
@ -867,7 +787,7 @@ bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, ui
|
|||
|
||||
// update kslen
|
||||
*kslen = ksoffset + (numcmds * 10) + 32;
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
@ -875,49 +795,39 @@ bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, ui
|
|||
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))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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 (!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");
|
||||
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");
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
hitag2_nvm_store_tag(response);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UserMessage("%s", "\r\n");
|
||||
} else {
|
||||
hitag2_nvm_store_tag(response);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@ bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, b
|
|||
|
||||
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_decrypt_bin(uint8_t *response, uint8_t *e_binstr);
|
||||
bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex);
|
||||
bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *hex);
|
||||
bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *e_binstr);
|
||||
|
||||
bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex);
|
||||
bool hitag2crack_send_auth(uint8_t *nrar);
|
||||
|
|
636
armsrc/hitagS.c
636
armsrc/hitagS.c
|
@ -10,6 +10,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Some code was copied from Hitag2.c
|
||||
//-----------------------------------------------------------------------------
|
||||
// bosb 2020
|
||||
|
||||
#include "hitagS.h"
|
||||
|
||||
|
@ -23,6 +24,7 @@
|
|||
#include "string.h"
|
||||
#include "commonutil.h"
|
||||
#include "hitag2_crypto.h"
|
||||
#include "lfadc.h"
|
||||
|
||||
#define CRC_PRESET 0xFF
|
||||
#define CRC_POLYNOM 0x1D
|
||||
|
@ -50,6 +52,22 @@ size_t blocknr;
|
|||
bool end = false;
|
||||
//#define SENDBIT_TEST
|
||||
|
||||
/* array index 3 2 1 0 // bytes in sim.bin file are 0 1 2 3
|
||||
// UID is 0 1 2 3 // tag.uid is 3210
|
||||
// datasheet HitagS_V11.pdf bytes in tables printed 3 2 1 0
|
||||
|
||||
#db# UID: 5F C2 11 84
|
||||
#db# conf0: C9 conf1: 00 conf2: 00
|
||||
3 2 1 0
|
||||
#db# Page[ 0]: 84 11 C2 5F uid
|
||||
#db# Page[ 1]: AA 00 00 C9 conf, HITAG S 256
|
||||
#db# Page[ 2]: 4E 4F 54 48
|
||||
#db# Page[ 3]: 52 4B 49 4D
|
||||
#db# Page[ 4]: 00 00 00 00
|
||||
#db# Page[ 5]: 00 00 00 00
|
||||
#db# Page[ 6]: 00 00 00 00
|
||||
#db# Page[ 7]: 4B 4F 5F 57 */
|
||||
|
||||
#define ht2bs_4a(a,b,c,d) (~(((a|b)&c)^(a|d)^b))
|
||||
#define ht2bs_4b(a,b,c,d) (~(((d|c)&(a^b))^(d|a|b)))
|
||||
#define ht2bs_5c(a,b,c,d,e) (~((((((c^e)|d)&a)^b)&(c^b))^(((d^e)|a)&((d^b)|c))))
|
||||
|
@ -86,7 +104,7 @@ bool end = false;
|
|||
#define HITAG_T_TAG_CAPTURE_THREE_HALF 41
|
||||
#define HITAG_T_TAG_CAPTURE_FOUR_HALF 57
|
||||
|
||||
#define DEBUG 0
|
||||
#define DBGLEVEL 0
|
||||
|
||||
/*
|
||||
* Implementation of the crc8 calculation from Hitag S
|
||||
|
@ -207,6 +225,22 @@ static void hitag_send_bit(int bit) {
|
|||
}
|
||||
|
||||
static void hitag_send_frame(const uint8_t *frame, size_t frame_len) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("hitag_send_frame: (%i) %02X %02X %02X %02X", frame_len, frame[0], frame[1], frame[2], frame[3]);
|
||||
// The beginning of the frame is hidden in some high level; pause until our bits will have an effect
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
switch (m) {
|
||||
case AC4K:
|
||||
case MC8K:
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * 40) {}; //FADV
|
||||
break;
|
||||
case AC2K:
|
||||
case MC4K:
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * 20) {}; //STD + ADV
|
||||
break;
|
||||
}
|
||||
|
||||
// SOF - send start of frame
|
||||
for (size_t i = 0; i < sof_bits; i++) {
|
||||
hitag_send_bit(1);
|
||||
|
@ -299,6 +333,25 @@ static int check_select(uint8_t *rx, uint32_t uid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void hitagS_set_frame_modulation() {
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* handles all commands from a reader
|
||||
*/
|
||||
|
@ -318,20 +371,28 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
switch (rxlen) {
|
||||
case 5: {
|
||||
//UID request with a selected response protocol mode
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("UID request: length: %i first byte: %02x", rxlen, rx[0]);
|
||||
tag.pstate = HT_READY;
|
||||
tag.tstate = HT_NO_OP;
|
||||
if ((rx[0] & 0xf0) == 0x30) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("HT_STANDARD");
|
||||
tag.mode = HT_STANDARD;
|
||||
sof_bits = 1;
|
||||
m = AC2K;
|
||||
}
|
||||
if ((rx[0] & 0xf0) == 0xc0) {
|
||||
tag.mode = HT_ADVANCED;
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("HT_ADVANCED");
|
||||
sof_bits = 3;
|
||||
m = AC2K;
|
||||
}
|
||||
|
||||
if ((rx[0] & 0xf0) == 0xd0) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("HT_FAST_ADVANCED");
|
||||
tag.mode = HT_FAST_ADVANCED;
|
||||
sof_bits = 3;
|
||||
m = AC4K;
|
||||
|
@ -344,29 +405,18 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
break;
|
||||
case 45: {
|
||||
//select command from reader received
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
DbpString("SELECT");
|
||||
if (check_select(rx, tag.uid) == 1) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
DbpString("SELECT match");
|
||||
//if the right tag was selected
|
||||
*txlen = 32;
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hitagS_set_frame_modulation();
|
||||
|
||||
//send configuration
|
||||
for (int i = 0; i < 4; i++)
|
||||
tx[i] = (tag.pages[0][1] >> (i * 8)) & 0xff;
|
||||
tx[i] = tag.pages[1][i];
|
||||
tx[3] = 0xff;
|
||||
if (tag.mode != HT_STANDARD) {
|
||||
*txlen = 40;
|
||||
|
@ -390,22 +440,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
Dbprintf(",{0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X}",
|
||||
rx[0], rx[1], rx[2], rx[3], rx[4], rx[5], rx[6], rx[7]);
|
||||
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hitagS_set_frame_modulation();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
_hitag2_byte(&state);
|
||||
|
@ -438,7 +473,10 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
}
|
||||
*/
|
||||
}
|
||||
break;
|
||||
case 40:
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("WRITE");
|
||||
//data received to be written
|
||||
if (tag.tstate == HT_WRITING_PAGE_DATA) {
|
||||
tag.tstate = HT_NO_OP;
|
||||
|
@ -448,44 +486,14 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
*txlen = 2;
|
||||
tx[0] = 0x40;
|
||||
page_to_be_written = 0;
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hitagS_set_frame_modulation();
|
||||
} else if (tag.tstate == HT_WRITING_BLOCK_DATA) {
|
||||
tag.pages[page_to_be_written / 4][page_to_be_written % 4] = (rx[0]
|
||||
<< 24) + (rx[1] << 16) + (rx[2] << 8) + rx[3];
|
||||
//send ack
|
||||
*txlen = 2;
|
||||
tx[0] = 0x40;
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hitagS_set_frame_modulation();
|
||||
page_to_be_written++;
|
||||
block_data_left--;
|
||||
if (block_data_left == 0) {
|
||||
|
@ -500,29 +508,14 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
//send page data
|
||||
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16);
|
||||
*txlen = 32;
|
||||
tx[0] = (tag.pages[page / 4][page % 4]) & 0xff;
|
||||
tx[1] = (tag.pages[page / 4][page % 4] >> 8) & 0xff;
|
||||
tx[2] = (tag.pages[page / 4][page % 4] >> 16) & 0xff;
|
||||
tx[3] = (tag.pages[page / 4][page % 4] >> 24) & 0xff;
|
||||
tx[0] = tag.pages[page][0];
|
||||
tx[1] = tag.pages[page][1];
|
||||
tx[2] = tag.pages[page][2];
|
||||
tx[3] = tag.pages[page][3];
|
||||
if (tag.LKP && page == 1)
|
||||
tx[3] = 0xff;
|
||||
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hitagS_set_frame_modulation();
|
||||
|
||||
if (tag.mode != HT_STANDARD) {
|
||||
//add crc8
|
||||
|
@ -543,29 +536,13 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
*txlen = 32 * 4;
|
||||
//send page,...,page+3 data
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tx[0 + i * 4] = (tag.pages[page / 4][page % 4]) & 0xff;
|
||||
tx[1 + i * 4] = (tag.pages[page / 4][page % 4] >> 8) & 0xff;
|
||||
tx[2 + i * 4] = (tag.pages[page / 4][page % 4] >> 16) & 0xff;
|
||||
tx[3 + i * 4] = (tag.pages[page / 4][page % 4] >> 24) & 0xff;
|
||||
page++;
|
||||
tx[0 + i * 4] = tag.pages[page + 0 + i * 4][0];
|
||||
tx[1 + i * 4] = tag.pages[page + 1 + i * 4][1];
|
||||
tx[2 + i * 4] = tag.pages[page + 2 + i * 4][2];
|
||||
tx[3 + i * 4] = tag.pages[page + 3 + i * 4][3];
|
||||
}
|
||||
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hitagS_set_frame_modulation();
|
||||
|
||||
if (tag.mode != HT_STANDARD) {
|
||||
//add crc8
|
||||
|
@ -576,29 +553,12 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
tx[16] = crc;
|
||||
}
|
||||
|
||||
if ((page - 4) % 4 != 0 || (tag.LKP && (page - 4) == 0)) {
|
||||
if ((page) % 4 != 0 || (tag.LKP && (page) == 0)) {
|
||||
sof_bits = 0;
|
||||
*txlen = 0;
|
||||
}
|
||||
} else if ((rx[0] & 0xf0) == 0x80) { //write page
|
||||
uint8_t page = ((rx[0] & 0x0f) * 16) + ((rx[1] & 0xf0) / 16);
|
||||
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ((tag.LCON && page == 1)
|
||||
|| (tag.LKP && (page == 2 || page == 3))) {
|
||||
//deny
|
||||
|
@ -613,22 +573,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
|
||||
} else if ((rx[0] & 0xf0) == 0x90) { //write block
|
||||
uint8_t page = ((rx[0] & 0x0f) * 6) + ((rx[1] & 0xf0) / 16);
|
||||
switch (tag.mode) {
|
||||
case HT_STANDARD:
|
||||
sof_bits = 1;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC4K;
|
||||
break;
|
||||
case HT_FAST_ADVANCED:
|
||||
sof_bits = 6;
|
||||
m = MC8K;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
hitagS_set_frame_modulation();
|
||||
if (page % 4 != 0 || page == 0) {
|
||||
//deny
|
||||
*txlen = 0;
|
||||
|
@ -644,7 +589,8 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
}
|
||||
break;
|
||||
default:
|
||||
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("unknown rxlen: (%i) %02X %02X %02X %02X ...", rxlen, rx[0], rx[1], rx[2], rx[3]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -722,7 +668,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
|
|||
| (uid[30] << 1)
|
||||
| uid[31];
|
||||
|
||||
if (DEBUG)
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("UID: %02X %02X %02X %02X", uid1, uid2, uid3, uid4);
|
||||
|
||||
tag.uid = (uid4 << 24 | uid3 << 16 | uid2 << 8 | uid1);
|
||||
|
@ -816,7 +762,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
|
|||
tag.LCK1 = response_bit[26];
|
||||
tag.LCK0 = response_bit[27];
|
||||
|
||||
if (DEBUG)
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("conf0: %02X conf1: %02X conf2: %02X", conf_pages[0], conf_pages[1], conf_pages[2]);
|
||||
|
||||
if (tag.auth == 1) {
|
||||
|
@ -839,7 +785,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
|
|||
tx[5] = auth_ks[1];
|
||||
tx[6] = auth_ks[2];
|
||||
tx[7] = auth_ks[3];
|
||||
if (DEBUG)
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("%02X %02X %02X %02X %02X %02X %02X %02X", tx[0],
|
||||
tx[1], tx[2], tx[3], tx[4], tx[5], tx[6], tx[7]);
|
||||
} else if (htf == 01 || htf == 03) { //RHTS_CHALLENGE //WHTS_CHALLENGE
|
||||
|
@ -864,7 +810,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
|
|||
calc_crc(&crc, ((rx[1] & 0x0f) * 16 + ((rx[2] & 0xf0) / 16)), 8);
|
||||
calc_crc(&crc, ((rx[2] & 0x0f) * 16 + ((rx[3] & 0xf0) / 16)), 8);
|
||||
calc_crc(&crc, ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)), 8);
|
||||
if (DEBUG) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED) {
|
||||
Dbprintf("UID:::%X", tag.uid);
|
||||
Dbprintf("RND:::%X", rnd);
|
||||
}
|
||||
|
@ -884,7 +830,7 @@ static int hitagS_handle_tag_auth(hitag_function htf, uint64_t key, uint64_t NrA
|
|||
pwdl1 = ((rx[3] & 0x0f) * 16 + ((rx[4] & 0xf0) / 16)) ^ _hitag2_byte(&state);
|
||||
}
|
||||
|
||||
if (DEBUG)
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("pwdh0 %02X pwdl0 %02X pwdl1 %02X", pwdh0, pwdl0, pwdl1);
|
||||
|
||||
//Dbprintf("%X %02X", rnd, ((rx[4] & 0x0f) * 16) + ((rx[5] & 0xf0) / 16));
|
||||
|
@ -930,28 +876,30 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
|
|||
tag.pstate = HT_READY;
|
||||
tag.tstate = HT_NO_OP;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
for (j = 0; j < 4; j++)
|
||||
tag.pages[i][j] = 0x0;
|
||||
|
||||
// read tag data into memory
|
||||
if (tag_mem_supplied) {
|
||||
for (i = 0; i < 16; i++)
|
||||
for (j = 0; j < 4; j++)
|
||||
tag.pages[i][j] = 0x0;
|
||||
|
||||
DbpString("Loading hitagS memory...");
|
||||
memcpy((uint8_t *)tag.pages, data, 4 * 64);
|
||||
} else {
|
||||
// use the last read tag
|
||||
}
|
||||
|
||||
tag.uid = (uint32_t)tag.pages[0];
|
||||
tag.key = (intptr_t)tag.pages[3];
|
||||
tag.uid = ((tag.pages[0][3]) << 24) | ((tag.pages[0][2]) << 16) | ((tag.pages[0][1]) << 8) | tag.pages[0][0];
|
||||
tag.key = ((tag.pages[3][3]) << 24) | ((tag.pages[3][2]) << 16) | ((tag.pages[3][1]) << 8) | tag.pages[3][0];
|
||||
tag.key <<= 16;
|
||||
tag.key += ((tag.pages[2][0]) << 8) + tag.pages[2][1];
|
||||
tag.pwdl0 = tag.pages[2][3];
|
||||
tag.pwdl1 = tag.pages[2][2];
|
||||
tag.pwdh0 = tag.pages[1][0];
|
||||
tag.key += ((tag.pages[2][3]) << 8) + tag.pages[2][2];
|
||||
tag.pwdl0 = tag.pages[2][0];
|
||||
tag.pwdl1 = tag.pages[2][1];
|
||||
tag.pwdh0 = tag.pages[1][3];
|
||||
//con0
|
||||
tag.max_page = 64;
|
||||
if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 1)
|
||||
if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 1)
|
||||
tag.max_page = 8;
|
||||
if ((tag.pages[1][3] & 0x2) == 0 && (tag.pages[1][3] & 0x1) == 0)
|
||||
if ((tag.pages[1][0] & 0x2) == 0 && (tag.pages[1][0] & 0x1) == 0)
|
||||
tag.max_page = 0;
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
for (i = 0; i < tag.max_page; i++)
|
||||
|
@ -962,41 +910,42 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
|
|||
tag.pages[i][0] & 0xff);
|
||||
//con1
|
||||
tag.auth = 0;
|
||||
if ((tag.pages[1][2] & 0x80) == 0x80)
|
||||
if ((tag.pages[1][1] & 0x80) == 0x80)
|
||||
tag.auth = 1;
|
||||
tag.LCON = 0;
|
||||
if ((tag.pages[1][2] & 0x2) == 0x02)
|
||||
if ((tag.pages[1][1] & 0x2) == 0x02)
|
||||
tag.LCON = 1;
|
||||
tag.LKP = 0;
|
||||
if ((tag.pages[1][2] & 0x1) == 0x01)
|
||||
if ((tag.pages[1][1] & 0x1) == 0x01)
|
||||
tag.LKP = 1;
|
||||
//con2
|
||||
//0=read write 1=read only
|
||||
tag.LCK7 = 0;
|
||||
if ((tag.pages[1][1] & 0x80) == 0x80)
|
||||
if ((tag.pages[1][2] & 0x80) == 0x80)
|
||||
tag.LCK7 = 1;
|
||||
tag.LCK6 = 0;
|
||||
if ((tag.pages[1][1] & 0x40) == 0x040)
|
||||
if ((tag.pages[1][2] & 0x40) == 0x040)
|
||||
tag.LCK6 = 1;
|
||||
tag.LCK5 = 0;
|
||||
if ((tag.pages[1][1] & 0x20) == 0x20)
|
||||
if ((tag.pages[1][2] & 0x20) == 0x20)
|
||||
tag.LCK5 = 1;
|
||||
tag.LCK4 = 0;
|
||||
if ((tag.pages[1][1] & 0x10) == 0x10)
|
||||
if ((tag.pages[1][2] & 0x10) == 0x10)
|
||||
tag.LCK4 = 1;
|
||||
tag.LCK3 = 0;
|
||||
if ((tag.pages[1][1] & 0x8) == 0x08)
|
||||
if ((tag.pages[1][2] & 0x8) == 0x08)
|
||||
tag.LCK3 = 1;
|
||||
tag.LCK2 = 0;
|
||||
if ((tag.pages[1][1] & 0x4) == 0x04)
|
||||
if ((tag.pages[1][2] & 0x4) == 0x04)
|
||||
tag.LCK2 = 1;
|
||||
tag.LCK1 = 0;
|
||||
if ((tag.pages[1][1] & 0x2) == 0x02)
|
||||
if ((tag.pages[1][2] & 0x2) == 0x02)
|
||||
tag.LCK1 = 1;
|
||||
tag.LCK0 = 0;
|
||||
if ((tag.pages[1][1] & 0x1) == 0x01)
|
||||
if ((tag.pages[1][2] & 0x1) == 0x01)
|
||||
tag.LCK0 = 1;
|
||||
|
||||
|
||||
// Set up simulator mode, frequency divisor which will drive the FPGA
|
||||
// and analog mux selection.
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
@ -1028,7 +977,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
|
|||
// TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
|
||||
// external trigger rising edge, load RA on rising edge of TIOA.
|
||||
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK
|
||||
| AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING;
|
||||
| AT91C_TC_ETRGEDG_RISING | AT91C_TC_ABETRG | AT91C_TC_LDRA_RISING;
|
||||
|
||||
// Enable and reset counter
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
@ -1100,12 +1049,13 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
|
|||
LogTrace(tx, nbytes(txlen), 0, 0, NULL, false);
|
||||
}
|
||||
|
||||
// Enable and reset external trigger in timer for capturing future frames
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
||||
// Reset the received frame and response timing info
|
||||
memset(rx, 0x00, sizeof(rx));
|
||||
response = 0;
|
||||
|
||||
// Enable and reset external trigger in timer for capturing future frames
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
LED_B_OFF();
|
||||
}
|
||||
// Reset the frame length
|
||||
|
@ -1114,22 +1064,92 @@ void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data) {
|
|||
overflow += (AT91C_BASE_TC1->TC_CV / T0);
|
||||
// Reset the timer to restart while-loop that receives frames
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
|
||||
|
||||
}
|
||||
|
||||
LEDsoff();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
set_tracing(false);
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
|
||||
lf_finalize();
|
||||
// release allocated memory from BigBuff.
|
||||
BigBuf_free();
|
||||
|
||||
StartTicks();
|
||||
|
||||
DbpString("Sim Stopped");
|
||||
}
|
||||
|
||||
void hitagS_receive_frame(uint8_t *rx, size_t *rxlen, int *response) {
|
||||
|
||||
// Reset values for receiving frames
|
||||
memset(rx, 0x00, HITAG_FRAME_LEN * sizeof(uint8_t));
|
||||
*rxlen = 0;
|
||||
int lastbit = 1;
|
||||
bool bSkip = true;
|
||||
int tag_sof = 1;
|
||||
*response = 0;
|
||||
uint32_t errorCount = 0;
|
||||
|
||||
// Receive frame, watch for at most T0*EOF periods
|
||||
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
|
||||
// Check if falling edge in tag modulation is detected
|
||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
||||
// Retrieve the new timing values
|
||||
int ra = (AT91C_BASE_TC1->TC_RA / T0);
|
||||
|
||||
// Reset timer every frame, we have to capture the last edge for timing
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
|
||||
LED_B_ON();
|
||||
|
||||
// Capture tag frame (manchester decoding using only falling edges)
|
||||
if (ra >= HITAG_T_EOF) {
|
||||
if (*rxlen != 0) {
|
||||
//DbpString("wierd1?");
|
||||
}
|
||||
// Capture the T0 periods that have passed since last communication or field drop (reset)
|
||||
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
|
||||
*response = ra - HITAG_T_TAG_HALF_PERIOD;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
|
||||
// Manchester coding example |-_|_-|-_| (101)
|
||||
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
|
||||
// Manchester coding example |_-|...|_-|-_| (0...01)
|
||||
rx[(*rxlen) / 8] |= 0 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
// We have to skip this half period at start and add the 'one' the second time
|
||||
if (!bSkip) {
|
||||
rx[(*rxlen) / 8] |= 1 << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
}
|
||||
lastbit = !lastbit;
|
||||
bSkip = !bSkip;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
|
||||
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
|
||||
if (tag_sof) {
|
||||
// Ignore bits that are transmitted during SOF
|
||||
tag_sof--;
|
||||
} else {
|
||||
// bit is same as last bit
|
||||
rx[(*rxlen) / 8] |= lastbit << (7 - ((*rxlen) % 8));
|
||||
(*rxlen)++;
|
||||
}
|
||||
} else {
|
||||
// Ignore wierd value, is to small to mean anything
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// if we saw over 100 wierd values break it probably isn't hitag...
|
||||
if (errorCount > 100) break;
|
||||
|
||||
// We can break this loop if we received the last bit from a frame
|
||||
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
|
||||
if ((*rxlen) > 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Authenticates to the Tag with the given key or challenge.
|
||||
* If the key was given the password will be decrypted.
|
||||
|
@ -1149,7 +1169,6 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
|
|||
uint8_t *tx = txbuf;
|
||||
size_t txlen = 0;
|
||||
int lastbit = 1;
|
||||
int reset_sof = 1;
|
||||
int t_wait = HITAG_T_WAIT_MAX;
|
||||
bool bStop = false;
|
||||
int pageNum = 0;
|
||||
|
@ -1164,6 +1183,9 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
|
|||
uint64_t NrAr = 0;
|
||||
uint8_t key_[6];
|
||||
|
||||
tag.pstate = HT_READY;
|
||||
tag.tstate = HT_NO_OP;
|
||||
|
||||
switch (htf) {
|
||||
case RHTSF_CHALLENGE: {
|
||||
DbpString("Authenticating using nr,ar pair:");
|
||||
|
@ -1238,10 +1260,8 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
|
|||
|
||||
// synchronized startup procedure
|
||||
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
|
||||
|
||||
// Reset the received frame, frame count and timing info
|
||||
t_wait = 200;
|
||||
|
||||
while (!bStop && !BUTTON_PRESS() && !data_available()) {
|
||||
|
||||
WDT_HIT();
|
||||
|
@ -1381,85 +1401,12 @@ void ReadHitagS(hitag_function htf, hitag_data *htd) {
|
|||
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true);
|
||||
}
|
||||
|
||||
// Reset values for receiving frames
|
||||
memset(rx, 0x00, sizeof(rx));
|
||||
rxlen = 0;
|
||||
lastbit = 1;
|
||||
bool bSkip = true;
|
||||
int tag_sof = reset_sof;
|
||||
response = 0;
|
||||
|
||||
// Receive frame, watch for at most T0*EOF periods
|
||||
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
|
||||
// Check if falling edge in tag modulation is detected
|
||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
||||
// Retrieve the new timing values
|
||||
int ra = (AT91C_BASE_TC1->TC_RA / T0);
|
||||
|
||||
// Reset timer every frame, we have to capture the last edge for timing
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
|
||||
LED_B_ON();
|
||||
|
||||
// Capture tag frame (manchester decoding using only falling edges)
|
||||
if (ra >= HITAG_T_EOF) {
|
||||
if (rxlen != 0) {
|
||||
//DbpString("wierd1?");
|
||||
}
|
||||
// Capture the T0 periods that have passed since last communication or field drop (reset)
|
||||
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
|
||||
response = ra - HITAG_T_TAG_HALF_PERIOD;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
|
||||
// Manchester coding example |-_|_-|-_| (101)
|
||||
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
|
||||
// Manchester coding example |_-|...|_-|-_| (0...01)
|
||||
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
// We have to skip this half period at start and add the 'one' the second time
|
||||
if (!bSkip) {
|
||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
}
|
||||
lastbit = !lastbit;
|
||||
bSkip = !bSkip;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
|
||||
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
|
||||
if (tag_sof) {
|
||||
// Ignore bits that are transmitted during SOF
|
||||
tag_sof--;
|
||||
} else {
|
||||
// bit is same as last bit
|
||||
rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
}
|
||||
} else {
|
||||
// Ignore wierd value, is to small to mean anything
|
||||
}
|
||||
}
|
||||
|
||||
// We can break this loop if we received the last bit from a frame
|
||||
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
|
||||
if (rxlen > 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
hitagS_receive_frame(rx, &rxlen, &response);
|
||||
}
|
||||
end = false;
|
||||
|
||||
LEDsoff();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
set_tracing(false);
|
||||
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
StartTicks();
|
||||
|
||||
lf_finalize();
|
||||
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -1479,7 +1426,6 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) {
|
|||
uint8_t *tx = txbuf;
|
||||
size_t txlen = 0;
|
||||
int lastbit;
|
||||
int reset_sof;
|
||||
int t_wait = HITAG_T_WAIT_MAX;
|
||||
bool bStop;
|
||||
unsigned char crc;
|
||||
|
@ -1555,6 +1501,7 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) {
|
|||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
|
||||
// Capture mode, defaul timer source = MCK/2 (TIMER_CLOCK1), TIOA is external trigger,
|
||||
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
|
||||
// external trigger rising edge, load RA on falling edge of TIOA.
|
||||
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK
|
||||
| AT91C_TC_ETRGEDG_FALLING
|
||||
|
@ -1570,7 +1517,6 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) {
|
|||
// Reset the received frame, frame count and timing info
|
||||
lastbit = 1;
|
||||
bStop = false;
|
||||
reset_sof = 1;
|
||||
t_wait = 200;
|
||||
|
||||
while (!bStop && !BUTTON_PRESS() && !data_available()) {
|
||||
|
@ -1670,87 +1616,13 @@ void WritePageHitagS(hitag_function htf, hitag_data *htd, int page) {
|
|||
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true);
|
||||
}
|
||||
|
||||
// Reset values for receiving frames
|
||||
memset(rx, 0x00, sizeof(rx));
|
||||
rxlen = 0;
|
||||
lastbit = 1;
|
||||
bool bSkip = true;
|
||||
int tag_sof = reset_sof;
|
||||
response = 0;
|
||||
uint32_t errorCount = 0;
|
||||
hitagS_receive_frame(rx, &rxlen, &response);
|
||||
|
||||
// Receive frame, watch for at most T0*EOF periods
|
||||
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
|
||||
// Check if falling edge in tag modulation is detected
|
||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
||||
// Retrieve the new timing values
|
||||
int ra = (AT91C_BASE_TC1->TC_RA / T0);
|
||||
|
||||
// Reset timer every frame, we have to capture the last edge for timing
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
|
||||
LED_B_ON();
|
||||
|
||||
// Capture tag frame (manchester decoding using only falling edges)
|
||||
if (ra >= HITAG_T_EOF) {
|
||||
if (rxlen != 0) {
|
||||
//DbpString("wierd1?");
|
||||
}
|
||||
// Capture the T0 periods that have passed since last communication or field drop (reset)
|
||||
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
|
||||
response = ra - HITAG_T_TAG_HALF_PERIOD;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
|
||||
// Manchester coding example |-_|_-|-_| (101)
|
||||
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
|
||||
// Manchester coding example |_-|...|_-|-_| (0...01)
|
||||
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
// We have to skip this half period at start and add the 'one' the second time
|
||||
if (!bSkip) {
|
||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
}
|
||||
lastbit = !lastbit;
|
||||
bSkip = !bSkip;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
|
||||
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
|
||||
if (tag_sof) {
|
||||
// Ignore bits that are transmitted during SOF
|
||||
tag_sof--;
|
||||
} else {
|
||||
// bit is same as last bit
|
||||
rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
}
|
||||
} else {
|
||||
// Ignore wierd value, is to small to mean anything
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// if we saw over 100 wierd values break it probably isn't hitag...
|
||||
if (errorCount > 100) break;
|
||||
|
||||
// We can break this loop if we received the last bit from a frame
|
||||
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
|
||||
if (rxlen > 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
end = false;
|
||||
LEDsoff();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
set_tracing(false);
|
||||
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
|
||||
StartTicks();
|
||||
lf_finalize();
|
||||
|
||||
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0);
|
||||
}
|
||||
|
@ -1773,7 +1645,7 @@ void check_challenges(bool file_given, uint8_t *data) {
|
|||
size_t rxlen = 0;
|
||||
uint8_t txbuf[HITAG_FRAME_LEN];
|
||||
int t_wait = HITAG_T_WAIT_MAX;
|
||||
int lastbit, reset_sof, STATE = 0;;
|
||||
int lastbit, STATE = 0;;
|
||||
bool bStop;
|
||||
int response_bit[200];
|
||||
unsigned char mask = 1;
|
||||
|
@ -1834,7 +1706,6 @@ void check_challenges(bool file_given, uint8_t *data) {
|
|||
// Reset the received frame, frame count and timing info
|
||||
lastbit = 1;
|
||||
bStop = false;
|
||||
reset_sof = 1;
|
||||
t_wait = 200;
|
||||
|
||||
if (file_given) {
|
||||
|
@ -1952,11 +1823,11 @@ void check_challenges(bool file_given, uint8_t *data) {
|
|||
u1++;
|
||||
|
||||
} else if (STATE == 2 && rxlen >= 44) {
|
||||
Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X",
|
||||
unlocker[u1 - 1][0], unlocker[u1 - 1][1],
|
||||
unlocker[u1 - 1][2], unlocker[u1 - 1][3],
|
||||
unlocker[u1 - 1][4], unlocker[u1 - 1][5],
|
||||
unlocker[u1 - 1][6], unlocker[u1 - 1][7]);
|
||||
Dbprintf("Challenge success: %02X%02X%02X%02X %02X%02X%02X%02X",
|
||||
unlocker[u1 - 1][0], unlocker[u1 - 1][1],
|
||||
unlocker[u1 - 1][2], unlocker[u1 - 1][3],
|
||||
unlocker[u1 - 1][4], unlocker[u1 - 1][5],
|
||||
unlocker[u1 - 1][6], unlocker[u1 - 1][7]);
|
||||
STATE = 0;
|
||||
}
|
||||
|
||||
|
@ -1984,85 +1855,10 @@ void check_challenges(bool file_given, uint8_t *data) {
|
|||
LogTrace(tx, nbytes(txlen), HITAG_T_WAIT_2, 0, NULL, true);
|
||||
}
|
||||
|
||||
// Reset values for receiving frames
|
||||
memset(rx, 0x00, sizeof(rx));
|
||||
rxlen = 0;
|
||||
lastbit = 1;
|
||||
bool bSkip = true;
|
||||
int tag_sof = reset_sof;
|
||||
response = 0;
|
||||
|
||||
// Receive frame, watch for at most T0*EOF periods
|
||||
while (AT91C_BASE_TC1->TC_CV < T0 * HITAG_T_WAIT_MAX) {
|
||||
// Check if falling edge in tag modulation is detected
|
||||
if (AT91C_BASE_TC1->TC_SR & AT91C_TC_LDRAS) {
|
||||
// Retrieve the new timing values
|
||||
int ra = (AT91C_BASE_TC1->TC_RA / T0);
|
||||
|
||||
// Reset timer every frame, we have to capture the last edge for timing
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
|
||||
LED_B_ON();
|
||||
|
||||
// Capture tag frame (manchester decoding using only falling edges)
|
||||
if (ra >= HITAG_T_EOF) {
|
||||
if (rxlen != 0) {
|
||||
//DbpString("wierd1?");
|
||||
}
|
||||
// Capture the T0 periods that have passed since last communication or field drop (reset)
|
||||
// We always recieve a 'one' first, which has the falling edge after a half period |-_|
|
||||
response = ra - HITAG_T_TAG_HALF_PERIOD;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_FOUR_HALF) {
|
||||
// Manchester coding example |-_|_-|-_| (101)
|
||||
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_THREE_HALF) {
|
||||
// Manchester coding example |_-|...|_-|-_| (0...01)
|
||||
rx[rxlen / 8] |= 0 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
// We have to skip this half period at start and add the 'one' the second time
|
||||
if (!bSkip) {
|
||||
rx[rxlen / 8] |= 1 << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
}
|
||||
lastbit = !lastbit;
|
||||
bSkip = !bSkip;
|
||||
} else if (ra >= HITAG_T_TAG_CAPTURE_TWO_HALF) {
|
||||
// Manchester coding example |_-|_-| (00) or |-_|-_| (11)
|
||||
if (tag_sof) {
|
||||
// Ignore bits that are transmitted during SOF
|
||||
tag_sof--;
|
||||
} else {
|
||||
// bit is same as last bit
|
||||
rx[rxlen / 8] |= lastbit << (7 - (rxlen % 8));
|
||||
rxlen++;
|
||||
}
|
||||
} else {
|
||||
// Ignore wierd value, is to small to mean anything
|
||||
}
|
||||
}
|
||||
|
||||
// We can break this loop if we received the last bit from a frame
|
||||
if (AT91C_BASE_TC1->TC_CV > T0 * HITAG_T_EOF) {
|
||||
if (rxlen > 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
hitagS_receive_frame(rx, &rxlen, &response);
|
||||
}
|
||||
|
||||
LEDsoff();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
set_tracing(false);
|
||||
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
|
||||
|
||||
StartTicks();
|
||||
|
||||
lf_finalize();
|
||||
reply_old(CMD_ACK, bSuccessful, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -709,7 +709,7 @@ void SmartCardAtr(void) {
|
|||
set_tracing(true);
|
||||
I2C_Reset_EnterMainProgram();
|
||||
bool isOK = GetATR(&card);
|
||||
reply_old(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
|
||||
reply_mix(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
|
||||
set_tracing(false);
|
||||
LEDsoff();
|
||||
}
|
||||
|
@ -760,7 +760,7 @@ void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data) {
|
|||
}
|
||||
}
|
||||
OUT:
|
||||
reply_old(CMD_ACK, len, 0, 0, resp, len);
|
||||
reply_mix(CMD_ACK, len, 0, 0, resp, len);
|
||||
BigBuf_free();
|
||||
set_tracing(false);
|
||||
LEDsoff();
|
||||
|
|
|
@ -1817,15 +1817,15 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
|
|||
++check;
|
||||
|
||||
// test if the field exists
|
||||
#if defined RDV4
|
||||
#if defined RDV4
|
||||
if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF_RDV40)) {
|
||||
|
||||
|
||||
analogCnt++;
|
||||
|
||||
|
||||
analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF_RDV40];
|
||||
|
||||
|
||||
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
|
||||
|
||||
|
||||
if (analogCnt >= 32) {
|
||||
|
||||
if ((MAX_ADC_HF_VOLTAGE_RDV40 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) {
|
||||
|
@ -1847,13 +1847,13 @@ int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *par) {
|
|||
}
|
||||
#else
|
||||
if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) {
|
||||
|
||||
|
||||
analogCnt++;
|
||||
|
||||
|
||||
analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF];
|
||||
|
||||
|
||||
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
|
||||
|
||||
|
||||
if (analogCnt >= 32) {
|
||||
|
||||
if ((MAX_ADC_HF_VOLTAGE * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) {
|
||||
|
|
|
@ -93,8 +93,6 @@
|
|||
#define CheckCrc15(data, len) check_crc(CRC_15693, (data), (len))
|
||||
#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
|
||||
#define sprintUID(target,uid) Iso15693sprintUID((target), (uid))
|
||||
|
||||
static void BuildIdentifyRequest(uint8_t *cmdout);
|
||||
//static void BuildReadBlockRequest(uint8_t *cmdout, uint8_t *uid, uint8_t blockNumber );
|
||||
static void BuildInventoryResponse(uint8_t *cmdout, uint8_t *uid);
|
||||
|
@ -946,7 +944,7 @@ void BruteforceIso15693Afi(uint32_t speed) {
|
|||
WDT_HIT();
|
||||
|
||||
if (recvlen >= 12) {
|
||||
Dbprintf("NoAFI UID = %s", sprintUID(NULL, buf + 2));
|
||||
Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, buf + 2));
|
||||
}
|
||||
|
||||
// now with AFI
|
||||
|
@ -964,7 +962,7 @@ void BruteforceIso15693Afi(uint32_t speed) {
|
|||
recvlen = SendDataTag(data, datalen, false, speed, buf);
|
||||
WDT_HIT();
|
||||
if (recvlen >= 12) {
|
||||
Dbprintf("AFI = %i UID = %s", i, sprintUID(NULL, buf + 2));
|
||||
Dbprintf("AFI = %i UID = %s", i, iso15693_sprintUID(NULL, buf + 2));
|
||||
}
|
||||
|
||||
aborted = BUTTON_PRESS();
|
||||
|
|
|
@ -404,6 +404,10 @@ bool write_byte(uint16_t index, uint8_t byte, uint8_t addr_sz) {
|
|||
//
|
||||
// Only this functions are public / called from appmain.c
|
||||
//-----------------------------------------------------------------------------
|
||||
legic_card_select_t* getLegicCardInfo(void) {
|
||||
return &card;
|
||||
}
|
||||
|
||||
void LegicRfInfo(void) {
|
||||
// configure ARM and FPGA
|
||||
init_reader(false);
|
||||
|
@ -441,6 +445,44 @@ OUT:
|
|||
StopTicks();
|
||||
}
|
||||
|
||||
int LegicRfReaderEx(uint16_t offset, uint16_t len, uint8_t iv) {
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
|
||||
// configure ARM and FPGA
|
||||
init_reader(false);
|
||||
|
||||
// establish shared secret and detect card type
|
||||
uint8_t card_type = setup_phase(iv);
|
||||
if (init_card(card_type, &card) != 0) {
|
||||
res = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
// do not read beyond card memory
|
||||
if (len + offset > card.cardsize) {
|
||||
len = card.cardsize - offset;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < len; ++i) {
|
||||
int16_t byte = read_byte(offset + i, card.cmdsize);
|
||||
if (byte == -1) {
|
||||
res = PM3_EOVFLOW;
|
||||
goto OUT;
|
||||
}
|
||||
legic_mem[i] = byte;
|
||||
|
||||
if (i < 4) {
|
||||
card.uid[i] = byte;
|
||||
}
|
||||
}
|
||||
|
||||
OUT:
|
||||
switch_off();
|
||||
StopTicks();
|
||||
return res;
|
||||
}
|
||||
|
||||
void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
|
||||
// configure ARM and FPGA
|
||||
init_reader(false);
|
||||
|
@ -464,6 +506,10 @@ void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
|
|||
goto OUT;
|
||||
}
|
||||
legic_mem[i] = byte;
|
||||
|
||||
if (i < 4) {
|
||||
card.uid[i] = byte;
|
||||
}
|
||||
}
|
||||
|
||||
// OK
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
|
||||
// 2018 AntiCat
|
||||
// 2020 iceman
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
|
@ -13,9 +14,12 @@
|
|||
#define __LEGICRF_H
|
||||
|
||||
#include "common.h"
|
||||
#include "legic.h" /* legic_card_select_t struct */
|
||||
|
||||
void LegicRfInfo(void);
|
||||
int LegicRfReaderEx(uint16_t offset, uint16_t len, uint8_t iv);
|
||||
void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv);
|
||||
void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data);
|
||||
|
||||
legic_card_select_t* getLegicCardInfo(void);
|
||||
#endif /* __LEGICRF_H */
|
||||
|
|
|
@ -460,12 +460,12 @@ void LegicRfSimulate(uint8_t cardtype) {
|
|||
|
||||
// verify command line input
|
||||
if (init_card(cardtype, &card) != 0) {
|
||||
DbpString("Unknown tagtype.");
|
||||
DbpString("[!] Unknown tagtype.");
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
LED_A_ON();
|
||||
DbpString("Starting Legic emulator, press button to end");
|
||||
DbpString("[=] Starting Legic emulator, press " _YELLOW_("button") "to end");
|
||||
while (!BUTTON_PRESS() && !data_available()) {
|
||||
WDT_HIT();
|
||||
|
||||
|
@ -486,7 +486,7 @@ void LegicRfSimulate(uint8_t cardtype) {
|
|||
}
|
||||
|
||||
OUT:
|
||||
DbpString("Stopped");
|
||||
DbpString("[=] Sim stopped");
|
||||
switch_off();
|
||||
StopTicks();
|
||||
}
|
||||
|
|
120
armsrc/lfadc.c
120
armsrc/lfadc.c
|
@ -10,6 +10,7 @@
|
|||
#include "lfsampling.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "ticks.h"
|
||||
#include "dbprint.h"
|
||||
|
||||
// Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK)
|
||||
// TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz
|
||||
|
@ -46,27 +47,43 @@ bool lf_test_periods(size_t expected, size_t count) {
|
|||
// Low frequency (LF) adc passthrough functionality
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
uint8_t previous_adc_val = 0;
|
||||
uint8_t adc_avg = 0;
|
||||
|
||||
void lf_sample_mean(void) {
|
||||
uint8_t periods = 0;
|
||||
uint32_t adc_sum = 0;
|
||||
while (periods < 32) {
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
adc_sum += AT91C_BASE_SSC->SSC_RHR;
|
||||
periods++;
|
||||
}
|
||||
}
|
||||
// division by 32
|
||||
adc_avg = adc_sum >> 5;
|
||||
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
Dbprintf("LF ADC average %u", adc_avg);
|
||||
}
|
||||
|
||||
size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
|
||||
size_t periods = 0;
|
||||
volatile uint8_t adc_val;
|
||||
//uint8_t avg_peak = 140, avg_through = 96;
|
||||
// 140 - 127 - 114
|
||||
uint8_t avg_peak = 140, avg_through = 106;
|
||||
int16_t checked = 0;
|
||||
uint8_t avg_peak = adc_avg + 3, avg_through = adc_avg - 3;
|
||||
// int16_t checked = 0;
|
||||
|
||||
while (!BUTTON_PRESS()) {
|
||||
|
||||
// only every 100th times, in order to save time when collecting samples.
|
||||
if (checked == 1000) {
|
||||
if (data_available()) {
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
|
||||
/*
|
||||
if (checked == 1000) {
|
||||
if (data_available()) {
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
*/
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
|
@ -98,8 +115,8 @@ size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
previous_adc_val = adc_val;
|
||||
|
||||
if (periods >= max) return 0;
|
||||
}
|
||||
}
|
||||
|
@ -116,23 +133,26 @@ size_t lf_detect_gap(size_t max) {
|
|||
}
|
||||
|
||||
void lf_reset_counter() {
|
||||
|
||||
// TODO: find out the correct reset settings for tag and reader mode
|
||||
if (reader_mode) {
|
||||
// Reset values for reader mode
|
||||
rising_edge = false;
|
||||
previous_adc_val = 0xFF;
|
||||
} else {
|
||||
// Reset values for tag/transponder mode
|
||||
rising_edge = false;
|
||||
previous_adc_val = 0xFF;
|
||||
}
|
||||
// if (reader_mode) {
|
||||
// Reset values for reader mode
|
||||
rising_edge = false;
|
||||
previous_adc_val = 0xFF;
|
||||
|
||||
// } else {
|
||||
// Reset values for tag/transponder mode
|
||||
// rising_edge = false;
|
||||
// previous_adc_val = 0xFF;
|
||||
// }
|
||||
}
|
||||
|
||||
bool lf_get_tag_modulation() {
|
||||
return (rising_edge == false);
|
||||
}
|
||||
|
||||
bool lf_get_reader_modulation() {
|
||||
return rising_edge;
|
||||
return rising_edge;
|
||||
}
|
||||
|
||||
void lf_wait_periods(size_t periods) {
|
||||
|
@ -147,7 +167,11 @@ void lf_init(bool reader, bool simulate) {
|
|||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz
|
||||
sample_config *sc = getSamplingConfig();
|
||||
sc->decimation = 1;
|
||||
sc->averaging = 0;
|
||||
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor);
|
||||
if (reader) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
||||
} else {
|
||||
|
@ -155,7 +179,8 @@ void lf_init(bool reader, bool simulate) {
|
|||
// FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
|
||||
else
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC);
|
||||
// Sniff
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT | FPGA_LF_EDGE_DETECT_TOGGLE_MODE);
|
||||
|
||||
}
|
||||
|
||||
|
@ -168,8 +193,8 @@ void lf_init(bool reader, bool simulate) {
|
|||
// When in reader mode, give the field a bit of time to settle.
|
||||
// 313T0 = 313 * 8us = 2504us = 2.5ms Hitag2 tags needs to be fully powered.
|
||||
if (reader) {
|
||||
// 50 ms
|
||||
SpinDelay(50);
|
||||
// 10 ms
|
||||
SpinDelay(10);
|
||||
}
|
||||
|
||||
// Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation
|
||||
|
@ -195,14 +220,12 @@ void lf_init(bool reader, bool simulate) {
|
|||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
||||
// Prepare data trace
|
||||
uint32_t bufsize = 20000;
|
||||
uint32_t bufsize = 10000;
|
||||
|
||||
// use malloc
|
||||
if (logging) initSampleBufferEx(&bufsize, true);
|
||||
|
||||
sample_config *sc = getSamplingConfig();
|
||||
sc->decimation = 1;
|
||||
sc->averaging = 0;
|
||||
lf_sample_mean();
|
||||
}
|
||||
|
||||
void lf_finalize() {
|
||||
|
@ -218,36 +241,33 @@ void lf_finalize() {
|
|||
|
||||
LEDsoff();
|
||||
|
||||
sample_config *sc = getSamplingConfig();
|
||||
sc->decimation = 1;
|
||||
sc->averaging = 0;
|
||||
|
||||
StartTicks();
|
||||
}
|
||||
|
||||
size_t lf_detect_field_drop(size_t max) {
|
||||
size_t periods = 0;
|
||||
volatile uint8_t adc_val;
|
||||
int16_t checked = 0;
|
||||
// int16_t checked = 0;
|
||||
|
||||
while (!BUTTON_PRESS()) {
|
||||
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 1000) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
/*
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 1000) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
*/
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
periods++;
|
||||
adc_val = AT91C_BASE_SSC->SSC_RHR;
|
||||
volatile uint8_t adc_val = AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
if (logging) logSampleSimple(adc_val);
|
||||
|
||||
|
@ -275,7 +295,7 @@ static void lf_manchester_send_bit(uint8_t bit) {
|
|||
lf_modulation(bit != 0);
|
||||
lf_wait_periods(16);
|
||||
lf_modulation(bit == 0);
|
||||
lf_wait_periods(16);
|
||||
lf_wait_periods(32);
|
||||
}
|
||||
|
||||
// simulation
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
extern bool logging;
|
||||
|
||||
void lf_sample_mean(void);
|
||||
bool lf_test_periods(size_t expected, size_t count);
|
||||
size_t lf_count_edge_periods(size_t max);
|
||||
size_t lf_detect_gap(size_t max);
|
||||
|
|
|
@ -1291,7 +1291,7 @@ void CmdHIDdemodFSK(int findone, uint32_t *high, uint32_t *low, int ledcontrol)
|
|||
cardnum = (lo >> 1) & 0x7FFFF;
|
||||
fac = ((hi & 0xF) << 12) | (lo >> 20);
|
||||
}
|
||||
Dbprintf("TAG ID: " _YELLOW_("%x%08x (%d)") "- Format Len: " _YELLOW_("%d") "bit - FC: " _YELLOW_("%d") "- Card: "_YELLOW_("%d"),
|
||||
Dbprintf("TAG ID: " _GREEN_("%x%08x (%d)") "- Format Len: " _GREEN_("%d") "bit - FC: " _GREEN_("%d") "- Card: "_GREEN_("%d"),
|
||||
hi,
|
||||
lo,
|
||||
(lo >> 1) & 0xFFFF,
|
||||
|
@ -2399,13 +2399,13 @@ void SendForward(uint8_t fwd_bit_count) {
|
|||
TurnReadLF_off(EM_START_GAP);
|
||||
TurnReadLFOn(18 * 8);
|
||||
|
||||
// now start writting with bitbanging the antenna.
|
||||
// now start writting with bitbanging the antenna. (each bit should be 32*8 total length)
|
||||
while (fwd_bit_sz-- > 0) { //prepare next bit modulation
|
||||
if (((*fwd_write_ptr++) & 1) == 1) {
|
||||
WaitUS(32 * 8);
|
||||
} else {
|
||||
TurnReadLF_off(23 * 8);
|
||||
TurnReadLFOn(18 * 8);
|
||||
TurnReadLFOn(32-23 * 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ void setSamplingConfig(sample_config *sc) {
|
|||
printConfig();
|
||||
}
|
||||
|
||||
sample_config *getSamplingConfig() {
|
||||
sample_config *getSamplingConfig(void) {
|
||||
return &config;
|
||||
}
|
||||
|
||||
|
@ -117,8 +117,8 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) {
|
|||
|
||||
if (use_malloc) {
|
||||
|
||||
if (sample_size == NULL || *sample_size == 0 ) {
|
||||
*sample_size = BigBuf_max_traceLen();
|
||||
if (sample_size == NULL || *sample_size == 0) {
|
||||
*sample_size = BigBuf_max_traceLen();
|
||||
data.buffer = BigBuf_get_addr();
|
||||
} else {
|
||||
*sample_size = MIN(*sample_size, BigBuf_max_traceLen());
|
||||
|
@ -127,7 +127,7 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) {
|
|||
}
|
||||
|
||||
} else {
|
||||
if (sample_size == NULL || *sample_size == 0 ) {
|
||||
if (sample_size == NULL || *sample_size == 0) {
|
||||
*sample_size = BigBuf_max_traceLen();
|
||||
}
|
||||
data.buffer = BigBuf_get_addr();
|
||||
|
@ -221,7 +221,7 @@ void LFSetupFPGAForADC(int divisor, bool reader_field) {
|
|||
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
|
||||
// 50ms for the resonant antenna to settle.
|
||||
if (reader_field)
|
||||
SpinDelay(50);
|
||||
SpinDelay(50);
|
||||
|
||||
// Now set up the SSC to get the ADC samples that are now streaming at us.
|
||||
FpgaSetupSsc();
|
||||
|
@ -253,11 +253,11 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
|||
uint32_t cancel_counter = 0;
|
||||
int16_t checked = 0;
|
||||
|
||||
while (true) {
|
||||
while (!BUTTON_PRESS()) {
|
||||
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 1000) {
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
|
|
|
@ -82,22 +82,22 @@ void MifareReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *datain) {
|
|||
|
||||
while (true) {
|
||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Auth error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
|
||||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Read block error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read block error");
|
||||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_halt(pcs, cuid)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Halt error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
break;
|
||||
};
|
||||
|
||||
|
@ -243,25 +243,25 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
isOK = 1;
|
||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||
isOK = 0;
|
||||
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
}
|
||||
|
||||
|
||||
if (isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
|
||||
isOK = 0;
|
||||
if (DBGLEVEL >= 1) Dbprintf("Auth error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
|
||||
}
|
||||
|
||||
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
|
||||
if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf + 16 * blockNo)) {
|
||||
isOK = 0;
|
||||
if (DBGLEVEL >= 1) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo);
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read sector %2d block %2d error", sectorNo, blockNo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mifare_classic_halt(pcs, cuid)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Halt error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
}
|
||||
|
||||
if (DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED");
|
||||
|
@ -409,22 +409,22 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
|
||||
while (true) {
|
||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Auth error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
|
||||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Write block error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
|
||||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_halt(pcs, cuid)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Halt error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
break;
|
||||
};
|
||||
|
||||
|
@ -460,18 +460,18 @@ void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
|
|||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
||||
if(!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
||||
if(mifare_ultra_writeblock_compat(blockNo, blockdata)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Write block error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
|
||||
OnError(0);
|
||||
return; };
|
||||
|
||||
if(mifare_ultra_halt()) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Halt error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
@ -506,7 +506,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
@ -534,13 +534,13 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
}
|
||||
|
||||
if (mifare_ultra_writeblock(blockNo, blockdata)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Write block error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
||||
if (mifare_ultra_halt()) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Halt error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
@ -569,7 +569,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
@ -579,7 +579,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
blockdata[2] = pwd[5];
|
||||
blockdata[3] = pwd[4];
|
||||
if (mifare_ultra_writeblock(44, blockdata)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Write block error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
|
||||
OnError(44);
|
||||
return;
|
||||
};
|
||||
|
@ -589,7 +589,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
blockdata[2] = pwd[1];
|
||||
blockdata[3] = pwd[0];
|
||||
if (mifare_ultra_writeblock(45, blockdata)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Write block error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
|
||||
OnError(45);
|
||||
return;
|
||||
};
|
||||
|
@ -599,7 +599,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
blockdata[2] = pwd[13];
|
||||
blockdata[3] = pwd[12];
|
||||
if (mifare_ultra_writeblock(46, blockdata)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Write block error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
|
||||
OnError(46);
|
||||
return;
|
||||
};
|
||||
|
@ -609,13 +609,13 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
blockdata[2] = pwd[9];
|
||||
blockdata[3] = pwd[8];
|
||||
if (mifare_ultra_writeblock(47, blockdata)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Write block error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
|
||||
OnError(47);
|
||||
return;
|
||||
};
|
||||
|
||||
if (mifare_ultra_halt()) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Halt error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
@ -674,7 +674,7 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) {
|
|||
if (!have_uid) { // need a full select cycle to get the uid first
|
||||
iso14a_card_select_t card_info;
|
||||
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (ALL)");
|
||||
continue;
|
||||
}
|
||||
switch (card_info.uidlen) {
|
||||
|
@ -693,7 +693,7 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) {
|
|||
have_uid = true;
|
||||
} else { // no need for anticollision. We can directly select the card
|
||||
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (UID)");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -792,7 +792,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
if (!have_uid) { // need a full select cycle to get the uid first
|
||||
iso14a_card_select_t card_info;
|
||||
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (ALL)");
|
||||
continue;
|
||||
}
|
||||
switch (card_info.uidlen) {
|
||||
|
@ -811,7 +811,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
have_uid = true;
|
||||
} else { // no need for anticollision. We can directly select the card
|
||||
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (UID)");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -821,7 +821,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
|
||||
uint32_t nt1;
|
||||
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth1 error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Auth1 error");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -832,7 +832,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
CHK_TIMEOUT();
|
||||
|
||||
if (len != 4) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("AcquireNonces: Auth2 error len=%d", len);
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Auth2 error len=%d", len);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1422,7 +1422,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
|||
|
||||
iso14a_card_select_t card_info;
|
||||
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("ChkKeys_fast: Can't select card (ALL)");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("ChkKeys_fast: Can't select card (ALL)");
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
|
@ -1470,7 +1470,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
|||
for (uint16_t i = s_point; i < keyCount; ++i) {
|
||||
|
||||
// Allow button press / usb cmd to interrupt device
|
||||
if (BUTTON_PRESS() && data_available()) {
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
|
@ -1562,7 +1562,7 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
|||
for (uint16_t i = 0; i < keyCount; i++) {
|
||||
|
||||
// Allow button press / usb cmd to interrupt device
|
||||
if (BUTTON_PRESS() && data_available()) break;
|
||||
if (BUTTON_PRESS() || data_available()) break;
|
||||
|
||||
// found all keys?
|
||||
if (foundkeys == allkeys)
|
||||
|
@ -1731,7 +1731,7 @@ void MifareChkKeys(uint8_t *datain) {
|
|||
if (!have_uid) { // need a full select cycle to get the uid first
|
||||
iso14a_card_select_t card_info;
|
||||
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (ALL)");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (ALL)");
|
||||
--i; // try same key once again
|
||||
continue;
|
||||
}
|
||||
|
@ -1751,7 +1751,7 @@ void MifareChkKeys(uint8_t *datain) {
|
|||
have_uid = true;
|
||||
} else { // no need for anticollision. We can directly select the card
|
||||
if (!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (UID)");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("ChkKeys: Can't select card (UID)");
|
||||
--i; // try same key once again
|
||||
continue;
|
||||
}
|
||||
|
@ -1805,6 +1805,63 @@ void MifareChkKeys_file(uint8_t *fn) {
|
|||
#endif
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// MIFARE Personalize UID. Only for Mifare Classic EV1 7Byte UID
|
||||
//-----------------------------------------------------------------------------
|
||||
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key) {
|
||||
|
||||
uint16_t isOK = PM3_EUNDEF;
|
||||
uint8_t uid[10];
|
||||
uint32_t cuid;
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
pcs = &mpcs;
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
while (true) {
|
||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t block_number = 0;
|
||||
if (mifare_classic_auth(pcs, cuid, block_number, keyType, key, AUTH_FIRST)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
|
||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
|
||||
int len = mifare_sendcmd_short(pcs, true, MIFARE_EV1_PERSONAL_UID, perso_option, receivedAnswer, receivedAnswerPar, NULL);
|
||||
if (len != 1 || receivedAnswer[0] != CARD_ACK) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
break;;
|
||||
}
|
||||
|
||||
if (mifare_classic_halt(pcs, cuid)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
break;
|
||||
}
|
||||
isOK = PM3_SUCCESS;
|
||||
break;
|
||||
}
|
||||
|
||||
crypto1_deinit(pcs);
|
||||
|
||||
LED_B_ON();
|
||||
reply_ng(CMD_HF_MIFARE_PERSONALIZE_UID, isOK, NULL, 0);
|
||||
LED_B_OFF();
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Work with emulator memory
|
||||
//
|
||||
|
@ -2229,7 +2286,7 @@ void MifareHasStaticNonce() {
|
|||
|
||||
nt = bytes_to_num(rec, 4);
|
||||
|
||||
// CHK_TIMEOUT();
|
||||
CHK_TIMEOUT();
|
||||
}
|
||||
|
||||
OUT:
|
||||
|
@ -2276,23 +2333,23 @@ void MifareSetMod(uint8_t *datain) {
|
|||
|
||||
while (true) {
|
||||
if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Can't select card");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
break;
|
||||
}
|
||||
|
||||
if (mifare_classic_auth(pcs, cuid, 0, 0, ui64Key, AUTH_FIRST)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Auth error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Auth error");
|
||||
break;
|
||||
}
|
||||
|
||||
int respLen;
|
||||
if (((respLen = mifare_sendcmd_short(pcs, CRYPT_ALL, 0x43, mod, receivedAnswer, receivedAnswerPar, NULL)) != 1) || (receivedAnswer[0] != 0x0a)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen);
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("SetMod error; response[0]: %hhX, len: %d", receivedAnswer[0], respLen);
|
||||
break;
|
||||
}
|
||||
|
||||
if (mifare_classic_halt(pcs, cuid)) {
|
||||
if (DBGLEVEL >= 1) Dbprintf("Halt error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2304,7 +2361,6 @@ void MifareSetMod(uint8_t *datain) {
|
|||
|
||||
LED_B_ON();
|
||||
reply_ng(CMD_HF_MIFARE_SETMOD, isOK, NULL, 0);
|
||||
|
||||
LED_B_OFF();
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
|
|
@ -45,6 +45,8 @@ void MifareCIdent(); // is "magic chinese" card?
|
|||
void MifareHasStaticNonce(); // Has the tag a static nonce?
|
||||
|
||||
void MifareSetMod(uint8_t *datain);
|
||||
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
|
||||
|
||||
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);
|
||||
void OnSuccessMagic();
|
||||
void OnErrorMagic(uint8_t reason);
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "crc16.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "commonutil.h"
|
||||
#include "util.h"
|
||||
#include "mifare.h"
|
||||
|
||||
#define MAX_APPLICATION_COUNT 28
|
||||
#define MAX_FILE_COUNT 16
|
||||
|
@ -31,8 +33,11 @@ static uint8_t deselect_cmd[] = {0xc2, 0xe0, 0xb4};
|
|||
/* PCB CID CMD PAYLOAD */
|
||||
//static uint8_t __res[MAX_FRAME_SIZE];
|
||||
|
||||
|
||||
bool InitDesfireCard() {
|
||||
|
||||
pcb_blocknum = 0;
|
||||
|
||||
iso14a_card_select_t card;
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
@ -46,28 +51,14 @@ bool InitDesfireCard() {
|
|||
return true;
|
||||
}
|
||||
|
||||
// ARG0 flag enums
|
||||
enum {
|
||||
NONE = 0x00,
|
||||
INIT = 0x01,
|
||||
DISCONNECT = 0x02,
|
||||
CLEARTRACE = 0x04,
|
||||
BAR = 0x08,
|
||||
} CmdOptions ;
|
||||
|
||||
void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
|
||||
/* ARG0 contains flags.
|
||||
0x01 = init card.
|
||||
0x02 = Disconnect
|
||||
0x03
|
||||
*/
|
||||
uint8_t flags = arg0;
|
||||
size_t datalen = arg1;
|
||||
uint8_t resp[RECEIVE_SIZE];
|
||||
memset(resp, 0, sizeof(resp));
|
||||
|
||||
if (DBGLEVEL >= 4) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED) {
|
||||
Dbprintf(" flags : %02X", flags);
|
||||
Dbprintf(" len : %02X", datalen);
|
||||
print_result(" RX : ", datain, datalen);
|
||||
|
@ -77,35 +68,42 @@ void MifareSendCommand(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
clear_trace();
|
||||
|
||||
if (flags & INIT) {
|
||||
if (!InitDesfireCard())
|
||||
if (!InitDesfireCard()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int len = DesfireAPDU(datain, datalen, resp);
|
||||
if (DBGLEVEL >= 4)
|
||||
print_result("ERR <--: ", resp, len);
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
print_result("RESP <--: ", resp, len);
|
||||
|
||||
if (!len) {
|
||||
OnError(2);
|
||||
return;
|
||||
}
|
||||
|
||||
// reset the pcb_blocknum,
|
||||
pcb_blocknum = 0;
|
||||
|
||||
if (flags & DISCONNECT)
|
||||
OnSuccess();
|
||||
|
||||
reply_old(CMD_ACK, 1, len, 0, resp, len);
|
||||
reply_mix(CMD_ACK, 1, len, 0, resp, len);
|
||||
}
|
||||
|
||||
void MifareDesfireGetInformation() {
|
||||
|
||||
LEDsoff();
|
||||
|
||||
int len = 0;
|
||||
iso14a_card_select_t card;
|
||||
uint8_t resp[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
uint8_t dataout[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
|
||||
struct p {
|
||||
uint8_t isOK;
|
||||
uint8_t uid[7];
|
||||
uint8_t versionHW[7];
|
||||
uint8_t versionSW[7];
|
||||
uint8_t details[14];
|
||||
} PACKED payload;
|
||||
|
||||
/*
|
||||
1 = PCB 1
|
||||
2 = cid 2
|
||||
|
@ -122,61 +120,65 @@ void MifareDesfireGetInformation() {
|
|||
// card select - information
|
||||
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, false)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) DbpString("Can't select card");
|
||||
OnError(1);
|
||||
payload.isOK = 1; // 2 == can not select
|
||||
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
|
||||
switch_off();
|
||||
return;
|
||||
}
|
||||
|
||||
if (card.uidlen != 7) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen);
|
||||
OnError(2);
|
||||
payload.isOK = 2; // 2 == WRONG UID
|
||||
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
|
||||
switch_off();
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dataout, card.uid, 7);
|
||||
// add uid.
|
||||
memcpy(payload.uid, card.uid, sizeof(payload.uid));
|
||||
|
||||
LED_A_ON();
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
|
||||
uint8_t cmd[] = {GET_VERSION};
|
||||
uint8_t cmd[] = {GET_VERSION, 0x00, 0x00, 0x00};
|
||||
size_t cmd_len = sizeof(cmd);
|
||||
|
||||
len = DesfireAPDU(cmd, cmd_len, resp);
|
||||
if (!len) {
|
||||
print_result("ERROR <--: ", resp, len);
|
||||
OnError(3);
|
||||
payload.isOK = 3; // 3 == DOESNT ANSWER TO GET_VERSION
|
||||
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
|
||||
switch_off();
|
||||
return;
|
||||
}
|
||||
|
||||
LED_A_OFF();
|
||||
LED_B_ON();
|
||||
memcpy(dataout + 7, resp + 3, 7);
|
||||
memcpy(payload.versionHW, resp + 1, sizeof(payload.versionHW));
|
||||
|
||||
// ADDITION_FRAME 1
|
||||
cmd[0] = ADDITIONAL_FRAME;
|
||||
len = DesfireAPDU(cmd, cmd_len, resp);
|
||||
if (!len) {
|
||||
print_result("ERROR <--: ", resp, len);
|
||||
OnError(3);
|
||||
payload.isOK = 3; // 3 == DOESNT ANSWER TO GET_VERSION
|
||||
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
|
||||
switch_off();
|
||||
return;
|
||||
}
|
||||
|
||||
LED_B_OFF();
|
||||
LED_C_ON();
|
||||
memcpy(dataout + 7 + 7, resp + 3, 7);
|
||||
memcpy(payload.versionSW, resp + 1, sizeof(payload.versionSW));
|
||||
|
||||
// ADDITION_FRAME 2
|
||||
len = DesfireAPDU(cmd, cmd_len, resp);
|
||||
if (!len) {
|
||||
print_result("ERROR <--: ", resp, len);
|
||||
OnError(3);
|
||||
payload.isOK = 3; // 3 == DOESNT ANSWER TO GET_VERSION
|
||||
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
|
||||
switch_off();
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(dataout + 7 + 7 + 7, resp + 3, 14);
|
||||
|
||||
reply_old(CMD_ACK, 1, 0, 0, dataout, sizeof(dataout));
|
||||
memcpy(payload.details, resp + 1, sizeof(payload.details));
|
||||
|
||||
LED_B_ON();
|
||||
reply_ng(CMD_HF_DESFIRE_INFO, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
|
||||
LED_B_OFF();
|
||||
|
||||
// reset the pcb_blocknum,
|
||||
pcb_blocknum = 0;
|
||||
OnSuccess();
|
||||
|
@ -467,7 +469,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
|
|||
|
||||
// dekryptera tagnonce.
|
||||
if (mbedtls_aes_setkey_dec(&ctx, key->data, 128) != 0) {
|
||||
if (DBGLEVEL >= 4) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED) {
|
||||
DbpString("mbedtls_aes_setkey_dec failed");
|
||||
}
|
||||
OnError(7);
|
||||
|
@ -480,7 +482,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
|
|||
memcpy(both + 16, decRndB, 16);
|
||||
uint8_t encBoth[32] = {0x00};
|
||||
if (mbedtls_aes_setkey_enc(&ctx, key->data, 128) != 0) {
|
||||
if (DBGLEVEL >= 4) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED) {
|
||||
DbpString("mbedtls_aes_setkey_enc failed");
|
||||
}
|
||||
OnError(7);
|
||||
|
@ -517,7 +519,7 @@ void MifareDES_Auth1(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
|
|||
}
|
||||
|
||||
OnSuccess();
|
||||
reply_old(CMD_ACK, 1, len, 0, resp, len);
|
||||
reply_mix(CMD_ACK, 1, len, 0, resp, len);
|
||||
}
|
||||
|
||||
// 3 different ISO ways to send data to a DESFIRE (direct, capsuled, capsuled ISO)
|
||||
|
@ -534,23 +536,23 @@ int DesfireAPDU(uint8_t *cmd, size_t cmd_len, uint8_t *dataout) {
|
|||
|
||||
wrappedLen = CreateAPDU(cmd, cmd_len, wCmd);
|
||||
|
||||
if (DBGLEVEL >= 4)
|
||||
if (DBGLEVEL >= DBG_EXTENDED)
|
||||
print_result("WCMD <--: ", wCmd, wrappedLen);
|
||||
|
||||
ReaderTransmit(wCmd, wrappedLen, NULL);
|
||||
|
||||
len = ReaderReceive(resp, par);
|
||||
if (!len) {
|
||||
if (DBGLEVEL >= 4) Dbprintf("fukked");
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("fukked");
|
||||
return false; //DATA LINK ERROR
|
||||
}
|
||||
// if we received an I- or R(ACK)-Block with a block number equal to the
|
||||
// current block number, toggle the current block number
|
||||
else if (len >= 4 // PCB+CID+CRC = 4 bytes
|
||||
if (len >= 4 // PCB+CID+CRC = 4 bytes
|
||||
&& ((resp[0] & 0xC0) == 0 // I-Block
|
||||
|| (resp[0] & 0xD0) == 0x80) // R-Block with ACK bit set to 0
|
||||
&& (resp[0] & 0x01) == pcb_blocknum) { // equal block numbers
|
||||
pcb_blocknum ^= 1; //toggle next block
|
||||
pcb_blocknum ^= 1; //toggle next block
|
||||
}
|
||||
|
||||
memcpy(dataout, resp, len);
|
||||
|
@ -565,15 +567,22 @@ size_t CreateAPDU(uint8_t *datain, size_t len, uint8_t *dataout) {
|
|||
uint8_t cmd[cmdlen];
|
||||
memset(cmd, 0, cmdlen);
|
||||
|
||||
cmd[0] = 0x0A; // 0x0A = send cid, 0x02 = no cid.
|
||||
cmd[0] = 0x02; // 0x0A = send cid, 0x02 = no cid.
|
||||
cmd[0] |= pcb_blocknum; // OR the block number into the PCB
|
||||
cmd[1] = 0x00; // CID: 0x00 //TODO: allow multiple selected cards
|
||||
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("pcb_blocknum %d == %d ", pcb_blocknum, cmd[0] );
|
||||
|
||||
cmd[1] = 0x90; // CID: 0x00 //TODO: allow multiple selected cards
|
||||
|
||||
memcpy(cmd + 2, datain, len);
|
||||
AddCrc14A(cmd, len + 2);
|
||||
|
||||
|
||||
/*
|
||||
hf 14a apdu -sk 90 60 00 00 00
|
||||
hf 14a apdu -k 90 AF 00 00 00
|
||||
hf 14a apdu 90AF000000
|
||||
*/
|
||||
memcpy(dataout, cmd, cmdlen);
|
||||
|
||||
return cmdlen;
|
||||
}
|
||||
|
||||
|
|
|
@ -537,13 +537,13 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
|
||||
// find reader field
|
||||
if (cardSTATE == MFEMUL_NOFIELD) {
|
||||
|
||||
|
||||
#if defined RDV4
|
||||
vHf = (MAX_ADC_HF_VOLTAGE_RDV40 * AvgAdc(ADC_CHAN_HF_RDV40)) >> 10;
|
||||
#else
|
||||
vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
|
||||
#endif
|
||||
|
||||
|
||||
if (vHf > MF_MINFIELDV) {
|
||||
cardSTATE_TO_IDLE();
|
||||
LED_A_ON();
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// Routines to support mifare classic sniffer.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "mifaresniff.h"
|
||||
#include "mifaresniff_disabled.h"
|
||||
|
||||
#ifndef CheckCrc14A
|
||||
# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len))
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
// PRIx64 definition missing with gcc-arm-none-eabi v8?
|
||||
#ifndef PRIx64
|
||||
#define PRIx64 "llx"
|
||||
#endif
|
||||
|
||||
// Basic macros
|
||||
|
||||
#ifndef SHORT_COIL
|
||||
|
|
|
@ -250,7 +250,8 @@ CMDSRCS = crapto1/crapto1.c \
|
|||
bucketsort.c \
|
||||
flash.c \
|
||||
wiegand_formats.c \
|
||||
wiegand_formatutils.c
|
||||
wiegand_formatutils.c \
|
||||
cardhelper.c
|
||||
|
||||
cpu_arch = $(shell uname -m)
|
||||
ifneq ($(findstring 86, $(cpu_arch)), )
|
||||
|
|
|
@ -10,22 +10,22 @@
|
|||
// Data and Graph commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "cmddata.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h> // for CmdNorm INT_MIN && INT_MAX
|
||||
#include <math.h> // pow
|
||||
#include <ctype.h> // tolower
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // for command_t
|
||||
#include "ui.h" // for show graph controls
|
||||
#include "graph.h" // for graph data
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdparser.h" // for command_t
|
||||
#include "ui.h" // for show graph controls
|
||||
#include "graph.h" // for graph data
|
||||
#include "comms.h"
|
||||
#include "lfdemod.h" // for demod code
|
||||
#include "lfdemod.h" // for demod code
|
||||
#include "loclass/cipherutils.h" // for decimating samples in getsamples
|
||||
#include "cmdlfem4x.h" // askem410xdecode
|
||||
#include "fileutils.h" // searchFile
|
||||
#include "cmdlfem4x.h" // askem410xdecode
|
||||
#include "fileutils.h" // searchFile
|
||||
#include "mifare/ndef.h"
|
||||
#include "cliparser/cliparser.h"
|
||||
|
||||
uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
|
||||
size_t DemodBufferLen = 0;
|
||||
|
@ -1662,16 +1662,15 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
#define LF_MARGINAL_V 10000
|
||||
#define HF_UNUSABLE_V 3000
|
||||
#define HF_MARGINAL_V 5000
|
||||
#define ANTENNA_ERROR 1.03 // current algo has 3% error margin.
|
||||
#define ANTENNA_ERROR 1.00 // current algo has 3% error margin.
|
||||
|
||||
// hide demod plot line
|
||||
DemodBufferLen = 0;
|
||||
setClockGrid(0, 0);
|
||||
RepaintGraphWindow();
|
||||
|
||||
|
||||
int timeout = 0;
|
||||
PrintAndLogEx(INFO, "\nMeasuring antenna characteristics, please wait...");
|
||||
PrintAndLogEx(INFO, "Measuring antenna characteristics, please wait...");
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING, NULL, 0);
|
||||
|
@ -1691,7 +1690,7 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
// in mVolt
|
||||
struct p {
|
||||
uint32_t v_lf134;
|
||||
|
@ -2290,6 +2289,34 @@ static int CmdDataIIR(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdDataNDEF(const char *Cmd) {
|
||||
|
||||
#ifndef MAX_NDEF_LEN
|
||||
#define MAX_NDEF_LEN 2048
|
||||
#endif
|
||||
|
||||
CLIParserInit("data ndef",
|
||||
"Prints NFC Data Exchange Format (NDEF)",
|
||||
"Usage:\n\tdata ndef -d 9101085402656e48656c6c6f5101085402656e576f726c64\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0("dD", "data", "<hex>", "NDEF data to decode"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(Cmd, argtable, true);
|
||||
|
||||
int datalen = 0;
|
||||
uint8_t data[MAX_NDEF_LEN] = {0};
|
||||
CLIGetHexWithReturn(1, data, &datalen);
|
||||
CLIParserFree();
|
||||
if (datalen == 0)
|
||||
return PM3_EINVARG;
|
||||
|
||||
PrintAndLogEx(INFO, "Parsed NDEF Records");
|
||||
return NDEFRecordsDecodeAndPrint(data, datalen);
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"askedgedetect", CmdAskEdgeDetect, AlwaysAvailable, "[threshold] Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave (use 20-45, def:25)"},
|
||||
|
@ -2328,6 +2355,7 @@ static command_t CommandTable[] = {
|
|||
{"undec", CmdUndec, AlwaysAvailable, "Un-decimate samples by 2"},
|
||||
{"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"},
|
||||
{"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"},
|
||||
{"ndef", CmdDataNDEF, AlwaysAvailable, "Decode NDEF records"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -18,48 +18,6 @@
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int CmdFlashMemSpiFFSMount(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSUnmount(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSTest(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_TEST, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSCheck(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_CHECK, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSTree(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_PRINT_TREE, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSInfo(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_PRINT_FSINFO, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_flashmemspiffs_remove(void) {
|
||||
PrintAndLogEx(NORMAL, "Remove a file from spiffs filesystem");
|
||||
PrintAndLogEx(NORMAL, " Usage: mem spiffs remove <filename>");
|
||||
|
@ -107,16 +65,64 @@ static int usage_flashmemspiffs_load(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int CmdFlashMemSpiFFSMount(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSUnmount(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSTest(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_TEST, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSCheck(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_CHECK, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSTree(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_PRINT_TREE, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSInfo(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SPIFFS_PRINT_FSINFO, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSRemove(const char *Cmd) {
|
||||
|
||||
int len = strlen(Cmd);
|
||||
if (len < 1) {
|
||||
return usage_flashmemspiffs_remove();
|
||||
}
|
||||
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (len == 1 && ctmp == 'h') {
|
||||
return usage_flashmemspiffs_remove();
|
||||
}
|
||||
|
||||
char filename[32] = {0};
|
||||
bool errors = false;
|
||||
|
||||
/*char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || ctmp == 'h') {
|
||||
return usage_flashmemspiffs_remove();
|
||||
}*/
|
||||
|
||||
if (param_getstr(Cmd, 0, filename, 32) >= 32) {
|
||||
PrintAndLogEx(FAILED, "Filename too long");
|
||||
errors = true;
|
||||
|
@ -134,15 +140,20 @@ static int CmdFlashMemSpiFFSRemove(const char *Cmd) {
|
|||
|
||||
static int CmdFlashMemSpiFFSRename(const char *Cmd) {
|
||||
|
||||
int len = strlen(Cmd);
|
||||
if (len < 1) {
|
||||
return usage_flashmemspiffs_rename();
|
||||
}
|
||||
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (len == 1 && ctmp == 'h') {
|
||||
return usage_flashmemspiffs_rename();
|
||||
}
|
||||
|
||||
char srcfilename[32] = {0};
|
||||
char destfilename[32] = {0};
|
||||
bool errors = false;
|
||||
|
||||
/*char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || ctmp == 'h') {
|
||||
return usage_flashmemspiffs_rename();
|
||||
}*/
|
||||
|
||||
if (param_getstr(Cmd, 0, srcfilename, 32) >= 32) {
|
||||
PrintAndLogEx(FAILED, "Source Filename too long");
|
||||
errors = true;
|
||||
|
@ -174,16 +185,21 @@ static int CmdFlashMemSpiFFSRename(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSCopy(const char *Cmd) {
|
||||
int len = strlen(Cmd);
|
||||
if (len < 1) {
|
||||
return usage_flashmemspiffs_copy();
|
||||
}
|
||||
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (len == 1 && ctmp == 'h') {
|
||||
return usage_flashmemspiffs_copy();
|
||||
}
|
||||
|
||||
|
||||
char srcfilename[32] = {0};
|
||||
char destfilename[32] = {0};
|
||||
bool errors = false;
|
||||
|
||||
/*char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || ctmp == 'h') {
|
||||
return usage_flashmemspiffs_copy();
|
||||
}*/
|
||||
|
||||
if (param_getstr(Cmd, 0, srcfilename, 32) >= 32) {
|
||||
PrintAndLogEx(FAILED, "Source Filename too long");
|
||||
errors = true;
|
||||
|
@ -315,7 +331,7 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
|
|||
}
|
||||
|
||||
int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
|
||||
|
||||
|
||||
int ret_val = PM3_SUCCESS;
|
||||
|
||||
// We want to mount before multiple operation so the lazy writes/append will not
|
||||
|
@ -349,7 +365,7 @@ int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
|
|||
bytes_sent += bytes_in_packet;
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
||||
|
||||
uint8_t retry = 3;
|
||||
while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
|
@ -377,7 +393,7 @@ out:
|
|||
// We want to unmount after these to set things back to normal but more than this
|
||||
// unmouting ensure that SPIFFS CACHES are all flushed so our file is actually written on memory
|
||||
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
|
||||
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
@ -400,8 +416,8 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
|
|||
cmdp += 2;
|
||||
break;
|
||||
case 'o':
|
||||
param_getstr(Cmd, cmdp + 1, (char*)destfilename, 32);
|
||||
if (strlen((char*)destfilename) == 0) {
|
||||
param_getstr(Cmd, cmdp + 1, (char *)destfilename, 32);
|
||||
if (strlen((char *)destfilename) == 0) {
|
||||
PrintAndLogEx(FAILED, "Destination Filename missing or invalid");
|
||||
errors = true;
|
||||
}
|
||||
|
@ -429,20 +445,19 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
|
|||
}
|
||||
|
||||
res = flashmem_spiffs_load(destfilename, data, datalen);
|
||||
|
||||
|
||||
free(data);
|
||||
|
||||
if ( res == PM3_SUCCESS )
|
||||
|
||||
if (res == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename);
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{
|
||||
"copy", CmdFlashMemSpiFFSCopy, IfPm3Flash,
|
||||
{"copy", CmdFlashMemSpiFFSCopy, IfPm3Flash,
|
||||
"Copy a file to another (destructively) in SPIFFS FileSystem in FlashMEM (spiffs)"
|
||||
},
|
||||
{"check", CmdFlashMemSpiFFSCheck, IfPm3Flash, "Check/try to defrag faulty/fragmented Filesystem"},
|
||||
|
|
|
@ -85,12 +85,14 @@ int CmdHFSearch(const char *Cmd) {
|
|||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_hf_search();
|
||||
|
||||
int res = PM3_ESOFT;
|
||||
|
||||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, "Searching for ThinFilm tag...");
|
||||
if (IfPm3NfcBarcode()) {
|
||||
if (infoThinFilm(false) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Thinfilm tag") "found\n");
|
||||
return PM3_SUCCESS;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +101,7 @@ int CmdHFSearch(const char *Cmd) {
|
|||
if (IfPm3Iso14443a()) {
|
||||
if (infoLTO(false) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LTO-CM tag") "found\n");
|
||||
return PM3_SUCCESS;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -108,7 +110,7 @@ int CmdHFSearch(const char *Cmd) {
|
|||
if (IfPm3Iso14443a()) {
|
||||
if (infoHF14A(false, false, false) > 0) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-A tag") "found\n");
|
||||
return PM3_SUCCESS;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,7 +119,7 @@ int CmdHFSearch(const char *Cmd) {
|
|||
if (IfPm3Iso15693()) {
|
||||
if (readHF15Uid(false)) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO15693 tag") "found\n");
|
||||
return PM3_SUCCESS;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,16 +128,16 @@ int CmdHFSearch(const char *Cmd) {
|
|||
if (IfPm3Legicrf()) {
|
||||
if (readLegicUid(false) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC tag") "found\n");
|
||||
return PM3_SUCCESS;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, "Searching for Topaz tag...");
|
||||
if (IfPm3Iso14443a()) {
|
||||
if (readTopazUid() == PM3_SUCCESS) {
|
||||
if (readTopazUid(false) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") "found\n");
|
||||
return PM3_SUCCESS;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -144,7 +146,7 @@ int CmdHFSearch(const char *Cmd) {
|
|||
if (IfPm3Felica()) {
|
||||
if (readFelicaUid(false) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(NORMAL, "\nValid " _GREEN_("ISO18092 / FeliCa tag") "found\n");
|
||||
return PM3_SUCCESS;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -154,7 +156,7 @@ int CmdHFSearch(const char *Cmd) {
|
|||
if (IfPm3Iso14443a()) {
|
||||
if (readHF14B(false) == 1) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("ISO14443-B tag") "found\n");
|
||||
return PM3_SUCCESS;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,14 +165,18 @@ int CmdHFSearch(const char *Cmd) {
|
|||
if (IfPm3Iclass()) {
|
||||
if (readIclass(false, false) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("iClass tag / PicoPass tag") "found\n");
|
||||
return PM3_SUCCESS;
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, _RED_("No known/supported 13.56 MHz tags found"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_ESOFT;
|
||||
if (res != PM3_SUCCESS) {
|
||||
|
||||
PrintAndLogEx(INPLACE, _RED_("No known/supported 13.56 MHz tags found"));
|
||||
res = PM3_ESOFT;
|
||||
}
|
||||
printf("\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
int CmdHFTune(const char *Cmd) {
|
||||
|
@ -178,39 +184,47 @@ int CmdHFTune(const char *Cmd) {
|
|||
if (cmdp == 'h') return usage_hf_tune();
|
||||
int iter = param_get32ex(Cmd, 0, 0, 10);
|
||||
|
||||
PrintAndLogEx(INFO, "Measuring HF antenna, click " _GREEN_("pm3 button") "or press " _GREEN_("Enter") "to exit");
|
||||
PacketResponseNG resp;
|
||||
PrintAndLogEx(SUCCESS, "Measuring HF antenna," _YELLOW_("click button") " or press" _YELLOW_("Enter") "to exit");
|
||||
clearCommandBuffer();
|
||||
|
||||
uint8_t mode[] = {1};
|
||||
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
|
||||
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) {
|
||||
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF initialization, aborting");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
mode[0] = 2;
|
||||
// loop forever (till button pressed) if iter = 0 (default)
|
||||
for (uint8_t i = 0; iter == 0 || i < iter; i++) {
|
||||
if (kbd_enter_pressed()) { // abort by keyboard press
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
|
||||
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
|
||||
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF measure, aborting");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint16_t)))
|
||||
|
||||
if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint16_t))) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t volt = resp.data.asDwords[0] & 0xFFFF;
|
||||
PrintAndLogEx(INPLACE, "%u mV / %5u V", volt, (uint16_t)(volt / 1000));
|
||||
PrintAndLogEx(INPLACE, "%u mV / %2u V", volt, (uint16_t)(volt / 1000));
|
||||
}
|
||||
mode[0] = 3;
|
||||
|
||||
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
|
||||
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) {
|
||||
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF shutdown, aborting");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Done.");
|
||||
PrintAndLogEx(INFO, "Done.");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,9 +189,9 @@ static int usage_hf_14a_sim(void) {
|
|||
PrintAndLogEx(NORMAL, " e : (Optional) Fill simulator keys from found keys");
|
||||
PrintAndLogEx(NORMAL, " v : (Optional) Verbose");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344 x");
|
||||
PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344");
|
||||
PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223344556677");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344 x"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sim t 1 u 11223344556677"));
|
||||
// PrintAndLogEx(NORMAL, " hf 14a sim t 1 u 11223445566778899AA\n");
|
||||
return 0;
|
||||
}
|
||||
|
@ -202,7 +202,7 @@ static int usage_hf_14a_sniff(void) {
|
|||
PrintAndLogEx(NORMAL, "c - triggered by first data from card");
|
||||
PrintAndLogEx(NORMAL, "r - triggered by first 7-bit request from reader (REQ,WUP,...)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf 14a sniff c r");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a sniff c r"));
|
||||
return 0;
|
||||
}
|
||||
static int usage_hf_14a_raw(void) {
|
||||
|
@ -230,7 +230,6 @@ static int usage_hf_14a_reader(void) {
|
|||
|
||||
static int CmdHF14AList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
//PrintAndLogEx(NORMAL, "Deprecated command, use 'hf list 14a' instead");
|
||||
CmdTraceList("14a");
|
||||
return 0;
|
||||
}
|
||||
|
@ -261,7 +260,7 @@ int Hf14443_4aGetCardData(iso14a_card_select_t *card) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " UID: %s", sprint_hex(card->uid, card->uidlen));
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card->uid, card->uidlen));
|
||||
PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card->atqa[1], card->atqa[0]);
|
||||
PrintAndLogEx(SUCCESS, " SAK: %02x [%" PRIu64 "]", card->sak, resp.oldarg[0]);
|
||||
if (card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
||||
|
@ -335,17 +334,17 @@ static int CmdHF14AReader(const char *Cmd) {
|
|||
|
||||
if (select_status == 3) {
|
||||
PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
|
||||
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
||||
PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]);
|
||||
DropField();
|
||||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
||||
PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]);
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]);
|
||||
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
|
||||
|
||||
if (card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
|
||||
PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len));
|
||||
PrintAndLogEx(SUCCESS, " ATS: " _GREEN_("%s"), sprint_hex(card.ats, card.ats_len));
|
||||
}
|
||||
|
||||
if (!disconnectAfter) {
|
||||
|
@ -354,14 +353,14 @@ static int CmdHF14AReader(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (disconnectAfter) {
|
||||
if (!silent) PrintAndLogEx(SUCCESS, "field dropped.");
|
||||
if (!silent) PrintAndLogEx(INFO, "field dropped.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CmdHF14AInfo(const char *Cmd) {
|
||||
bool verbose = false;
|
||||
bool verbose = true;
|
||||
bool do_nack_test = false;
|
||||
bool do_aid_search = false;
|
||||
|
||||
|
@ -467,7 +466,7 @@ int CmdHF14ASim(const char *Cmd) {
|
|||
break;
|
||||
}
|
||||
if (!errors) {
|
||||
PrintAndLogEx(SUCCESS, "Emulating ISO/IEC 14443 type A tag with %d byte UID (%s)", uidlen, sprint_hex(uid, uidlen));
|
||||
PrintAndLogEx(SUCCESS, "Emulating " _YELLOW_("ISO/IEC 14443 type A tag")"with " _GREEN_("%d byte UID (%s)"), uidlen, sprint_hex(uid, uidlen));
|
||||
useUIDfromEML = false;
|
||||
}
|
||||
cmdp += 2;
|
||||
|
@ -485,7 +484,7 @@ int CmdHF14ASim(const char *Cmd) {
|
|||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
PrintAndLogEx(WARNING, "Unknown parameter " _RED_("'%c'"), param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
|
@ -511,7 +510,7 @@ int CmdHF14ASim(const char *Cmd) {
|
|||
SendCommandNG(CMD_HF_ISO14443A_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "press pm3-button to abort simulation");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
|
||||
bool keypress = kbd_enter_pressed();
|
||||
while (!keypress) {
|
||||
|
||||
|
@ -558,6 +557,7 @@ int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leav
|
|||
|
||||
if (activateField) {
|
||||
PacketResponseNG resp;
|
||||
responseNum = 0;
|
||||
|
||||
// Anticollision + SELECT card
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
@ -1276,16 +1276,24 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
|
||||
if (select_status == 3) {
|
||||
PrintAndLogEx(INFO, "Card doesn't support standard iso14443-3 anticollision");
|
||||
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
||||
PrintAndLogEx(SUCCESS, "ATQA: %02x %02x", card.atqa[1], card.atqa[0]);
|
||||
DropField();
|
||||
return select_status;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " UID : %s", sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
|
||||
PrintAndLogEx(SUCCESS, " SAK : %02x [%" PRIu64 "]", card.sak, resp.oldarg[0]);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "-- ISO14443-a Information -----------------------------------");
|
||||
PrintAndLogEx(SUCCESS, "-------------------------------------------------------------");
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, "ATQA: " _GREEN_("%02x %02x"), card.atqa[1], card.atqa[0]);
|
||||
PrintAndLogEx(SUCCESS, " SAK: " _GREEN_("%02x [%" PRIu64 "]"), card.sak, resp.oldarg[0]);
|
||||
|
||||
bool isMifareClassic = true;
|
||||
bool isMifareDesfire = false;
|
||||
bool isMifarePlus = false;
|
||||
bool isMifareUltralight = false;
|
||||
|
||||
switch (card.sak) {
|
||||
case 0x00:
|
||||
isMifareClassic = false;
|
||||
|
@ -1294,10 +1302,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
DropField();
|
||||
|
||||
uint32_t tagT = GetHF14AMfU_Type();
|
||||
if (tagT != UL_ERROR)
|
||||
if (tagT != UL_ERROR) {
|
||||
ul_print_type(tagT, 0);
|
||||
else
|
||||
isMifareUltralight = true;
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "TYPE: Possible AZTEK (iso14443a compliant)");
|
||||
}
|
||||
|
||||
// reconnect for further tests
|
||||
clearCommandBuffer();
|
||||
|
@ -1314,49 +1324,55 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
}
|
||||
break;
|
||||
case 0x01:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : NXP TNP3xxx Activision Game Appliance");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP TNP3xxx Activision Game Appliance"));
|
||||
break;
|
||||
case 0x04:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE (various !DESFire !DESFire EV1)");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE (various !DESFire !DESFire EV1)"));
|
||||
isMifareClassic = false;
|
||||
isMifareDesfire = true;
|
||||
break;
|
||||
case 0x08:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE CLASSIC 1k | Plus 2k SL1 | 1k Ev1"));
|
||||
break;
|
||||
case 0x09:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Mini 0.3k");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Mini 0.3k"));
|
||||
break;
|
||||
case 0x0A:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : FM11RF005SH (Shanghai Metro)");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("FM11RF005SH (Shanghai Metro)"));
|
||||
break;
|
||||
case 0x10:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 2k SL2");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 2k SL2"));
|
||||
isMifarePlus = true;
|
||||
break;
|
||||
case 0x11:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Plus 4k SL2");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Plus 4k SL2"));
|
||||
isMifarePlus = true;
|
||||
break;
|
||||
case 0x18:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE Classic 4k | Plus 4k SL1 | 4k Ev1"));
|
||||
break;
|
||||
case 0x20:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE DESFire 4k | DESFire EV1 2k/4k/8k | Plus 2k/4k SL3 | JCOP 31/41"));
|
||||
isMifareClassic = false;
|
||||
isMifareDesfire = true;
|
||||
isMifarePlus = true;
|
||||
break;
|
||||
case 0x24:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : NXP MIFARE DESFire | DESFire EV1");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("NXP MIFARE DESFire | DESFire EV1"));
|
||||
isMifareClassic = false;
|
||||
isMifareDesfire = true;
|
||||
break;
|
||||
case 0x28:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : JCOP31 or JCOP41 v2.3.1");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("JCOP31 or JCOP41 v2.3.1"));
|
||||
break;
|
||||
case 0x38:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : Nokia 6212 or 6131 MIFARE CLASSIC 4K");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Nokia 6212 or 6131 MIFARE CLASSIC 4K"));
|
||||
break;
|
||||
case 0x88:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : Infineon MIFARE CLASSIC 1K");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Infineon MIFARE CLASSIC 1K"));
|
||||
break;
|
||||
case 0x98:
|
||||
PrintAndLogEx(SUCCESS, "TYPE : Gemplus MPCOS");
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("Gemplus MPCOS"));
|
||||
break;
|
||||
default:
|
||||
;
|
||||
|
@ -1364,7 +1380,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
|
||||
// Double & triple sized UID, can be mapped to a manufacturer.
|
||||
if (card.uidlen > 4) {
|
||||
PrintAndLogEx(SUCCESS, "MANUFACTURER : %s", getTagInfo(card.uid[0]));
|
||||
PrintAndLogEx(SUCCESS, "MANUFACTURER: " _YELLOW_("%s"), getTagInfo(card.uid[0]));
|
||||
}
|
||||
|
||||
// try to request ATS even if tag claims not to support it
|
||||
|
@ -1385,7 +1401,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
if (select_status == 2) {
|
||||
PrintAndLogEx(INFO, "SAK incorrectly claims that card doesn't support RATS");
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, " ATS : %s", sprint_hex(card.ats, card.ats_len));
|
||||
PrintAndLogEx(SUCCESS, " ATS: %s", sprint_hex(card.ats, card.ats_len));
|
||||
PrintAndLogEx(SUCCESS, " - TL : length is %d bytes", card.ats[0]);
|
||||
if (card.ats[0] != card.ats_len - 2) {
|
||||
PrintAndLogEx(SUCCESS, "ATS may be corrupted. Length of ATS (%d bytes incl. 2 Bytes CRC) doesn't match TL", card.ats_len);
|
||||
|
@ -1461,9 +1477,15 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
switch (card.ats[pos + 2] & 0xf0) {
|
||||
case 0x10:
|
||||
PrintAndLogEx(SUCCESS, " 1x -> MIFARE DESFire");
|
||||
isMifareDesfire = true;
|
||||
isMifareClassic = false;
|
||||
isMifarePlus = false;
|
||||
break;
|
||||
case 0x20:
|
||||
PrintAndLogEx(SUCCESS, " 2x -> MIFARE Plus");
|
||||
isMifarePlus = true;
|
||||
isMifareDesfire = false;
|
||||
isMifareClassic = false;
|
||||
break;
|
||||
}
|
||||
switch (card.ats[pos + 2] & 0x0f) {
|
||||
|
@ -1590,22 +1612,32 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
if (isMifareClassic) {
|
||||
int res = detect_classic_prng();
|
||||
if (res == 1)
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("WEAK"));
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("weak"));
|
||||
else if (res == 0)
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("HARD"));
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard"));
|
||||
else
|
||||
PrintAndLogEx(FAILED, "prng detection: " _RED_("Fail"));
|
||||
PrintAndLogEx(FAILED, "prng detection: " _RED_("fail"));
|
||||
|
||||
if (do_nack_test)
|
||||
detect_classic_nackbug(!verbose);
|
||||
detect_classic_nackbug(false);
|
||||
|
||||
res = detect_classic_static_nonce();
|
||||
if (res == 1)
|
||||
PrintAndLogEx(SUCCESS, "Static nonce detected");
|
||||
PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes") );
|
||||
if (res == 2 && verbose)
|
||||
PrintAndLogEx(SUCCESS, "Static nonce detection failed");
|
||||
PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("fail"));
|
||||
}
|
||||
|
||||
if (isMifareUltralight) {
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfu info`"));
|
||||
}
|
||||
if (isMifarePlus) {
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfp info`"));
|
||||
}
|
||||
if (isMifareDesfire) {
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`hf mfdes info`"));
|
||||
}
|
||||
|
||||
|
||||
return select_status;
|
||||
}
|
||||
|
||||
|
|
|
@ -1142,4 +1142,3 @@ int readHF14B(bool verbose) {
|
|||
if (verbose) PrintAndLogEx(FAILED, "no 14443-B tag found");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
203
client/cmdhf15.c
203
client/cmdhf15.c
|
@ -23,16 +23,13 @@
|
|||
// the client. Signal Processing & decoding is done on the pc. This is the slowest
|
||||
// variant, but offers the possibility to analyze the waveforms directly.
|
||||
#include "cmdhf15.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "comms.h" // clearCommandBuffer
|
||||
#include "cmdtrace.h"
|
||||
#include "iso15693tools.h"
|
||||
#include "crypto/libpcrypto.h"
|
||||
|
||||
#include "graph.h"
|
||||
#include "crc16.h" // iso15 crc
|
||||
#include "cmddata.h" // getsamples
|
||||
|
@ -53,9 +50,11 @@
|
|||
#define AddCrc15(data, len) compute_crc(CRC_15693, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
#endif
|
||||
|
||||
#ifndef sprintUID
|
||||
# define sprintUID(target, uid) Iso15693sprintUID((target), (uid))
|
||||
#endif
|
||||
typedef struct {
|
||||
uint8_t lock;
|
||||
uint8_t block[4];
|
||||
} t15memory_t;
|
||||
|
||||
// structure and database for uid -> tagtype lookups
|
||||
typedef struct {
|
||||
uint64_t uid;
|
||||
|
@ -63,6 +62,7 @@ typedef struct {
|
|||
const char *desc;
|
||||
} productName;
|
||||
|
||||
|
||||
const productName uidmapping[] = {
|
||||
|
||||
// UID, #significant Bits, "Vendor(+Product)"
|
||||
|
@ -208,18 +208,90 @@ const productName uidmapping[] = {
|
|||
{ 0, 0, "no tag-info available" } // must be the last entry
|
||||
};
|
||||
|
||||
uint8_t nxp_public_keys[][33] = {
|
||||
// ICODE SLIX2 / DNA
|
||||
{
|
||||
0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3,
|
||||
0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71,
|
||||
0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64,
|
||||
0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0
|
||||
},
|
||||
};
|
||||
|
||||
static int CmdHF15Help(const char *Cmd);
|
||||
|
||||
static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
|
||||
|
||||
#define PUBLIC_ECDA_KEYLEN 33
|
||||
const ecdsa_publickey_t nxp_15693_public_keys[] = {
|
||||
{"NXP Mifare Classic MFC1C14_x", "044F6D3F294DEA5737F0F46FFEE88A356EED95695DD7E0C27A591E6F6F65962BAF"},
|
||||
{"Manufacturer Mifare Classic MFC1C14_x", "046F70AC557F5461CE5052C8E4A7838C11C7A236797E8A0730A101837C004039C2"},
|
||||
{"NXP ICODE DNA, ICODE SLIX2", "048878A2A2D3EEC336B4F261A082BD71F9BE11C4E2E896648B32EFA59CEA6E59F0"},
|
||||
{"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"},
|
||||
{"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
|
||||
{"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
|
||||
{"MICRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"},
|
||||
};
|
||||
/*
|
||||
uint8_t nxp_15693_public_keys[][PUBLIC_ECDA_KEYLEN] = {
|
||||
// ICODE SLIX2 / DNA
|
||||
{
|
||||
0x04, 0x88, 0x78, 0xA2, 0xA2, 0xD3, 0xEE, 0xC3,
|
||||
0x36, 0xB4, 0xF2, 0x61, 0xA0, 0x82, 0xBD, 0x71,
|
||||
0xF9, 0xBE, 0x11, 0xC4, 0xE2, 0xE8, 0x96, 0x64,
|
||||
0x8B, 0x32, 0xEF, 0xA5, 0x9C, 0xEA, 0x6E, 0x59, 0xF0
|
||||
},
|
||||
// unknown. Needs identification
|
||||
{
|
||||
0x04, 0x4F, 0x6D, 0x3F, 0x29, 0x4D, 0xEA, 0x57,
|
||||
0x37, 0xF0, 0xF4, 0x6F, 0xFE, 0xE8, 0x8A, 0x35,
|
||||
0x6E, 0xED, 0x95, 0x69, 0x5D, 0xD7, 0xE0, 0xC2,
|
||||
0x7A, 0x59, 0x1E, 0x6F, 0x6F, 0x65, 0x96, 0x2B, 0xAF
|
||||
},
|
||||
// unknown. Needs identification
|
||||
{
|
||||
0x04, 0xA7, 0x48, 0xB6, 0xA6, 0x32, 0xFB, 0xEE,
|
||||
0x2C, 0x08, 0x97, 0x70, 0x2B, 0x33, 0xBE, 0xA1,
|
||||
0xC0, 0x74, 0x99, 0x8E, 0x17, 0xB8, 0x4A, 0xCA,
|
||||
0x04, 0xFF, 0x26, 0x7E, 0x5D, 0x2C, 0x91, 0xF6, 0xDC
|
||||
},
|
||||
// manufacturer public key
|
||||
{
|
||||
0x04, 0x6F, 0x70, 0xAC, 0x55, 0x7F, 0x54, 0x61,
|
||||
0xCE, 0x50, 0x52, 0xC8, 0xE4, 0xA7, 0x83, 0x8C,
|
||||
0x11, 0xC7, 0xA2, 0x36, 0x79, 0x7E, 0x8A, 0x07,
|
||||
0x30, 0xA1, 0x01, 0x83, 0x7C, 0x00, 0x40, 0x39, 0xC2
|
||||
},
|
||||
// MIKRON public key.
|
||||
{
|
||||
0x04, 0xf9, 0x71, 0xed, 0xa7, 0x42, 0xa4, 0xa8,
|
||||
0x0d, 0x32, 0xdc, 0xf6, 0xa8, 0x14, 0xa7, 0x07,
|
||||
0xcc, 0x3d, 0xc3, 0x96, 0xd3, 0x59, 0x02, 0xf7,
|
||||
0x29, 0x29, 0xfd, 0xcd, 0x69, 0x8b, 0x34, 0x68, 0xf2
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
uint8_t i;
|
||||
int res;
|
||||
bool is_valid = false;
|
||||
for (i = 0; i< ARRAYLEN(nxp_15693_public_keys); i++) {
|
||||
|
||||
int dl = 0;
|
||||
uint8_t key[PUBLIC_ECDA_KEYLEN];
|
||||
param_gethex_to_eol(nxp_15693_public_keys[i].value, 0, key, PUBLIC_ECDA_KEYLEN, &dl);
|
||||
|
||||
res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, false);
|
||||
is_valid = (res == 0);
|
||||
if (is_valid)
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
if (is_valid == false) {
|
||||
PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed"));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
|
||||
PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_15693_public_keys[i].desc);
|
||||
PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_15693_public_keys[i].value);
|
||||
PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1");
|
||||
PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex(signature, 32));
|
||||
PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// fast method to just read the UID of a tag (collision detection not supported)
|
||||
// *buf should be large enough to fit the 64bit uid
|
||||
// returns 1 if succeeded
|
||||
|
@ -399,7 +471,7 @@ static int usage_15_restore(void) {
|
|||
{"-2", "use slower '1 out of 256' mode"},
|
||||
{"-o", "set OPTION Flag (needed for TI)"},
|
||||
{"r <NUM>", "numbers of retries on error, default is 3"},
|
||||
{"u <UID>", "load hf-15-dump-<UID>.bin"},
|
||||
{"u <UID>", "load hf-15-<UID>-dump.bin"},
|
||||
{"f <filename>", "load <filename>"},
|
||||
{"b <block size>", "block size, default is 4"}
|
||||
};
|
||||
|
@ -517,7 +589,7 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t
|
|||
return false;
|
||||
}
|
||||
memcpy(&req[tmpreqlen], uid, sizeof(uid));
|
||||
PrintAndLogEx(SUCCESS, "Detected UID %s", sprintUID(NULL, uid));
|
||||
PrintAndLogEx(SUCCESS, "Detected UID " _GREEN_("%s"), iso15693_sprintUID(NULL,uid));
|
||||
tmpreqlen += sizeof(uid);
|
||||
break;
|
||||
default:
|
||||
|
@ -530,7 +602,7 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t
|
|||
uid[7 - i] = temp & 0xff;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Using UID %s", sprintUID(NULL, uid));
|
||||
PrintAndLogEx(SUCCESS, "Using UID " _GREEN_("%s"), iso15693_sprintUID(NULL,uid));
|
||||
memcpy(&req[tmpreqlen], uid, sizeof(uid));
|
||||
tmpreqlen += sizeof(uid);
|
||||
break;
|
||||
|
@ -796,16 +868,8 @@ static int NxpSysInfo(uint8_t *uid) {
|
|||
uint8_t signature[32] = {0x00};
|
||||
memcpy(signature, recv + 1, 32);
|
||||
|
||||
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, nxp_public_keys[0], uid, 8, signature, 32, false);
|
||||
bool is_valid = (res == 0);
|
||||
nxp_15693_print_signature(uid, signature);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, " Tag Signature");
|
||||
PrintAndLogEx(NORMAL, " IC signature public key name : NXP ICODE SLIX2 / DNA");
|
||||
PrintAndLogEx(NORMAL, " IC signature public key value : %s", sprint_hex(nxp_public_keys[0], 33));
|
||||
PrintAndLogEx(NORMAL, " Elliptic curve parameters : NID_secp128r1");
|
||||
PrintAndLogEx(NORMAL, " TAG IC Signature : %s", sprint_hex(signature, 32));
|
||||
PrintAndLogEx(NORMAL, " Signature verification %s", (is_valid) ? _GREEN_("successful") : _RED_("failed"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -818,8 +882,8 @@ static int NxpSysInfo(uint8_t *uid) {
|
|||
*/
|
||||
static int CmdHF15Info(const char *Cmd) {
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd) < 1 || cmdp == 'h' || cmdp == 'H') return usage_15_info();
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_info();
|
||||
|
||||
PacketResponseNG resp;
|
||||
uint8_t *recv;
|
||||
|
@ -838,11 +902,8 @@ static int CmdHF15Info(const char *Cmd) {
|
|||
AddCrc15(req, reqlen);
|
||||
reqlen += 2;
|
||||
|
||||
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "iso15693 card select failed");
|
||||
DropField();
|
||||
|
@ -866,11 +927,12 @@ static int CmdHF15Info(const char *Cmd) {
|
|||
}
|
||||
|
||||
memcpy(uid, recv + 2, sizeof(uid));
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid));
|
||||
PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(recv + 2));
|
||||
PrintAndLogEx(SUCCESS, " SYSINFO : %s", sprint_hex(recv, status - 2));
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") "---------");
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(SUCCESS, " TYPE: " _YELLOW_("%s"), getTagInfo_15(recv + 2));
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL,uid));
|
||||
PrintAndLogEx(SUCCESS, " SYSINFO: %s", sprint_hex(recv, status - 2));
|
||||
|
||||
// DSFID
|
||||
if (recv[1] & 0x01)
|
||||
|
@ -901,12 +963,12 @@ static int CmdHF15Info(const char *Cmd) {
|
|||
}
|
||||
|
||||
// Check if SLIX2 and attempt to get NXP System Information
|
||||
PrintAndLogEx(DEBUG, "4 & 08 :: %02x 7 == 1 :: %u 8 == 4 :: %u", recv[4], recv[7], recv[8]);
|
||||
if (recv[8] == 0x04 && recv[7] == 0x01 && recv[4] & 0x80) {
|
||||
return NxpSysInfo(uid);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -941,7 +1003,7 @@ static int CmdHF15Sim(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Starting simulating UID %s", sprint_hex(uid, sizeof(uid)));
|
||||
PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid));
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_HF_ISO15693_SIMULATE, 0, 0, 0, uid, 8);
|
||||
|
@ -1011,7 +1073,7 @@ static int CmdHF15WriteAfi(const char *Cmd) {
|
|||
AddCrc15(req, reqlen);
|
||||
reqlen += 2;
|
||||
|
||||
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||
// PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||
|
@ -1070,7 +1132,7 @@ static int CmdHF15WriteDsfid(const char *Cmd) {
|
|||
AddCrc15(req, reqlen);
|
||||
reqlen += 2;
|
||||
|
||||
//PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||
// PrintAndLogEx(NORMAL, "cmd %s", sprint_hex(req, reqlen) );
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_HF_ISO15693_COMMAND, reqlen, arg1, 1, req, reqlen);
|
||||
|
@ -1096,11 +1158,6 @@ static int CmdHF15WriteDsfid(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint8_t lock;
|
||||
uint8_t block[4];
|
||||
} t15memory;
|
||||
|
||||
// Reads all memory pages
|
||||
// need to write to file
|
||||
static int CmdHF15Dump(const char *Cmd) {
|
||||
|
@ -1144,13 +1201,13 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
}
|
||||
// detect blocksize from card :)
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), sprintUID(NULL, uid));
|
||||
PrintAndLogEx(SUCCESS, "Reading memory from tag UID " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid));
|
||||
|
||||
int blocknum = 0;
|
||||
uint8_t *recv = NULL;
|
||||
|
||||
// memory.
|
||||
t15memory mem[256];
|
||||
t15memory_t mem[256];
|
||||
|
||||
uint8_t data[256 * 4] = {0};
|
||||
memset(data, 0, sizeof(data));
|
||||
|
@ -1214,14 +1271,14 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "\n");
|
||||
|
||||
size_t datalen = blocknum * 4;
|
||||
saveFile(filename, ".bin", data, datalen);
|
||||
saveFileEML(filename, data, datalen, 4);
|
||||
saveFile(filename, ".bin", data, datalen);
|
||||
saveFileJSON(filename, jsf15, data, datalen);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF15List(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
//PrintAndLogEx(WARNING, "Deprecated command, use 'hf list 15' instead");
|
||||
CmdTraceList("15");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1348,7 +1405,7 @@ static int CmdHF15Readmulti(const char *Cmd) {
|
|||
pagenum = param_get8ex(cmd, 0, 0, 10);
|
||||
pagecount = param_get8ex(cmd, 1, 0, 10);
|
||||
|
||||
//PrintAndLogEx(NORMAL, "ice %d %d\n", pagenum, pagecount);
|
||||
// PrintAndLogEx(NORMAL, "ice %d %d\n", pagenum, pagecount);
|
||||
|
||||
// 0 means 1 page,
|
||||
// 1 means 2 pages, ...
|
||||
|
@ -1388,7 +1445,8 @@ static int CmdHF15Readmulti(const char *Cmd) {
|
|||
return PM3_EWRONGANSVER;
|
||||
}
|
||||
|
||||
int start = 1; // skip status byte
|
||||
// skip status byte
|
||||
int start = 1;
|
||||
int stop = (pagecount + 1) * 5;
|
||||
int currblock = pagenum;
|
||||
// print response
|
||||
|
@ -1603,7 +1661,7 @@ static int CmdHF15Restore(const char *Cmd) {
|
|||
case 'u':
|
||||
param_getstr(Cmd, cmdp + 1, buff, FILE_PATH_SIZE);
|
||||
cmdp++;
|
||||
snprintf(filename, sizeof(filename), "hf-15-dump-%s-bin", buff);
|
||||
snprintf(filename, sizeof(filename), "hf-15-%s-dump.bin", buff);
|
||||
break;
|
||||
case 'h':
|
||||
return usage_15_restore();
|
||||
|
@ -1622,6 +1680,7 @@ static int CmdHF15Restore(const char *Cmd) {
|
|||
}
|
||||
|
||||
if ((f = fopen(filename, "rb")) == NULL) {
|
||||
|
||||
PrintAndLogEx(WARNING, "Could not find file %s", filename);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
@ -1703,7 +1762,7 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Input new UID | %s", sprint_hex(uid, sizeof(uid)));
|
||||
PrintAndLogEx(SUCCESS, "Input new UID | " _YELLOW_("%s"), iso15693_sprintUID(NULL,uid));
|
||||
|
||||
if (!getUID(oldUid)) {
|
||||
PrintAndLogEx(FAILED, "Can't get old/current UID.");
|
||||
|
@ -1774,31 +1833,33 @@ static int CmdHF15CSetUID(const char *Cmd) {
|
|||
PrintAndLogEx(FAILED, "Setting UID on tag failed.");
|
||||
return PM3_ESOFT;
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "old UID : %02X %02X %02X %02X %02X %02X %02X %02X", oldUid[7], oldUid[6], oldUid[5], oldUid[4], oldUid[3], oldUid[2], oldUid[1], oldUid[0]);
|
||||
PrintAndLogEx(SUCCESS, "new UID : %02X %02X %02X %02X %02X %02X %02X %02X", newUid[7], newUid[6], newUid[5], newUid[4], newUid[3], newUid[2], newUid[1], newUid[0]);
|
||||
PrintAndLogEx(SUCCESS, "Old: %s", iso15693_sprintUID(NULL, oldUid));
|
||||
PrintAndLogEx(SUCCESS, "New: " _GREEN_("%s"), iso15693_sprintUID(NULL, newUid));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHF15Help, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"},
|
||||
{"demod", CmdHF15Demod, AlwaysAvailable, "Demodulate ISO15693 from tag"},
|
||||
{"dump", CmdHF15Dump, IfPm3Iso15693, "Read all memory pages of an ISO15693 tag, save to file"},
|
||||
{"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
|
||||
// {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"},
|
||||
{"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"},
|
||||
{"record", CmdHF15Record, IfPm3Iso15693, "Record Samples (ISO15693)"},
|
||||
{"read", CmdHF15Read, IfPm3Iso15693, "Read a block"},
|
||||
{"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"},
|
||||
{"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"},
|
||||
{"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"},
|
||||
{"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"},
|
||||
{"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"},
|
||||
{"write", CmdHF15Write, IfPm3Iso15693, "Write a block"},
|
||||
{"-----------", CmdHF15Help, IfPm3Iso15693, ""},
|
||||
{"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"},
|
||||
{"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"},
|
||||
{"writedsfid", CmdHF15WriteDsfid, IfPm3Iso15693, "Writes the DSFID on an ISO15693 tag"},
|
||||
{"info", CmdHF15Info, IfPm3Iso15693, "Tag information"},
|
||||
// {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"},
|
||||
{"list", CmdHF15List, AlwaysAvailable, "List ISO15693 history"},
|
||||
{"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"},
|
||||
{"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"},
|
||||
{"record", CmdHF15Record, IfPm3Iso15693, "Record Samples (ISO15693)"},
|
||||
{"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"},
|
||||
{"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"},
|
||||
{"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"},
|
||||
{"read", CmdHF15Read, IfPm3Iso15693, "Read a block"},
|
||||
{"write", CmdHF15Write, IfPm3Iso15693, "Write a block"},
|
||||
{"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"},
|
||||
{"-----------", CmdHF15Help, IfPm3Iso15693, ""},
|
||||
{"csetuid", CmdHF15CSetUID, IfPm3Iso15693, "Set UID for magic Chinese card"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
@ -1816,13 +1877,13 @@ int CmdHF15(const char *Cmd) {
|
|||
|
||||
// used with 'hf search'
|
||||
bool readHF15Uid(bool verbose) {
|
||||
uint8_t uid[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t uid[8] = {0};
|
||||
if (!getUID(uid)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "No tag found.");
|
||||
return false;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " UID : %s", sprintUID(NULL, uid));
|
||||
PrintAndLogEx(SUCCESS, " TYPE : %s", getTagInfo_15(uid));
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), iso15693_sprintUID(NULL, uid));
|
||||
PrintAndLogEx(SUCCESS, "TYPE: " _YELLOW_("%s"), getTagInfo_15(uid));
|
||||
return true;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -25,8 +25,8 @@ static int CmdHelp(const char *Cmd);
|
|||
|
||||
static int usage_legic_calccrc(void) {
|
||||
PrintAndLogEx(NORMAL, "Calculates the legic crc8/crc16 on the given data.");
|
||||
PrintAndLogEx(NORMAL, "There must be an even number of hexsymbols as input.");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic crc [h] d <data> u <uidcrc> c <8|16>");
|
||||
PrintAndLogEx(NORMAL, "There must be an even number of hexsymbols as input.\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic crc [h] d <data> u <uidcrc> c <8|16>\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " d <data> : (hex symbols) bytes to calculate crc over");
|
||||
|
@ -34,29 +34,29 @@ static int usage_legic_calccrc(void) {
|
|||
PrintAndLogEx(NORMAL, " c <8|16> : Crc type");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic crc d deadbeef1122");
|
||||
PrintAndLogEx(NORMAL, " hf legic crc d deadbeef1122 u 9A c 16");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic crc d deadbeef1122"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic crc d deadbeef1122 u 9A c 16"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_rdmem(void) {
|
||||
PrintAndLogEx(NORMAL, "Read data from a legic tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic rdmem [h] <offset> <length> <IV>");
|
||||
static int usage_legic_rdbl(void) {
|
||||
PrintAndLogEx(NORMAL, "Read data from a LEGIC Prime tag\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic rdbl [h] [o <offset>] [l <length>] [iv <IV>]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " <offset> : (hex) offset in data array to start download from");
|
||||
PrintAndLogEx(NORMAL, " <length> : (hex) number of bytes to read");
|
||||
PrintAndLogEx(NORMAL, " <IV> : (hex) (optional) Initialization vector to use. Must be odd and 7bits max");
|
||||
PrintAndLogEx(NORMAL, " o <offset> : (hex) offset in data array to start download from");
|
||||
PrintAndLogEx(NORMAL, " l <length> : (hex) number of bytes to read");
|
||||
PrintAndLogEx(NORMAL, " i <IV> : (hex) (optional) Initialization vector to use. Must be odd and 7bits max");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic rdmem 0 16 - reads from byte[0] 0x16 bytes(system header)");
|
||||
PrintAndLogEx(NORMAL, " hf legic rdmem 0 4 55 - reads from byte[0] 0x4 bytes with IV 0x55");
|
||||
PrintAndLogEx(NORMAL, " hf legic rdmem 0 100 55 - reads 0x100 bytes with IV 0x55");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 16 - reads from byte[0] 0x16 bytes(system header)"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 4 iv 55 - reads from byte[0] 0x4 bytes with IV 0x55"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic rdbl o 0 l 100 iv 55 - reads 0x100 bytes with IV 0x55"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Simulates a LEGIC Prime tag. MIM22, MIM256, MIM1024 types can be emulated");
|
||||
PrintAndLogEx(NORMAL, "Use ELOAD/ESAVE to upload a dump into emulator memory");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic sim [h] <tagtype>");
|
||||
PrintAndLogEx(NORMAL, "Use " _YELLOW_("`hf legic eload`") "to upload a dump into emulator memory\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic sim [h] <tagtype>\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " <tagtype> : 0 = MIM22");
|
||||
|
@ -64,12 +64,12 @@ static int usage_legic_sim(void) {
|
|||
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic sim 2");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic sim 2"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_write(void) {
|
||||
PrintAndLogEx(NORMAL, "Write data to a LEGIC Prime tag. It autodetects tagsize to make sure size");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic write [h] o <offset> d <data (hex symbols)>");
|
||||
static int usage_legic_wrbl(void) {
|
||||
PrintAndLogEx(NORMAL, "Write data to a LEGIC Prime tag. It autodetects tagsize to make sure size\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic wrbl [h] [o <offset>] [d <data (hex symbols)>]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " o <offset> : (hex) offset in data array to start writing");
|
||||
|
@ -77,94 +77,121 @@ static int usage_legic_write(void) {
|
|||
PrintAndLogEx(NORMAL, " d <data> : (hex symbols) bytes to write ");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic write o 10 d 11223344 - Write 0x11223344 starting from offset 0x10");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic wrbl o 10 d 11223344 - Write 0x11223344 starting from offset 0x10"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_reader(void) {
|
||||
PrintAndLogEx(NORMAL, "Read UID and type information from a legic tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic reader [h]");
|
||||
PrintAndLogEx(NORMAL, "Read UID and type information from a LEGIC Prime tag\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic reader [h]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic reader");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic reader"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_info(void) {
|
||||
PrintAndLogEx(NORMAL, "Reads information from a legic prime tag.");
|
||||
PrintAndLogEx(NORMAL, "Shows systemarea, user areas etc");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic info [h]");
|
||||
PrintAndLogEx(NORMAL, "Reads information from a LEGIC Prime tag like systemarea, user areas etc\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic info [h]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic info");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic info"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_dump(void) {
|
||||
PrintAndLogEx(NORMAL, "Reads all pages from LEGIC Prime MIM22, MIM256, MIM1024");
|
||||
PrintAndLogEx(NORMAL, "and saves binary dump into the file `filename.bin` or `cardUID.bin`");
|
||||
PrintAndLogEx(NORMAL, "Read all memory from LEGIC Prime MIM22, MIM256, MIM1024");
|
||||
PrintAndLogEx(NORMAL, "and saves bin/eml/json dump file");
|
||||
PrintAndLogEx(NORMAL, "It autodetects card type.\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic dump [h] o <filename w/o .bin>");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic dump [h] [x] [f <filename w/o .bin>]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " o <filename> : filename w/o '.bin' to dump bytes");
|
||||
PrintAndLogEx(NORMAL, " f <filename> : filename w/o '.bin' to dump bytes");
|
||||
PrintAndLogEx(NORMAL, " x : deobfuscate dump data (xor with MCC)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic dump");
|
||||
PrintAndLogEx(NORMAL, " hf legic dump o myfile");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic dump -- uses UID as filename"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic dump f myfile"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic dump x"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_restore(void) {
|
||||
PrintAndLogEx(NORMAL, "Reads binary file and it autodetects card type and verifies that the file has the same size");
|
||||
PrintAndLogEx(NORMAL, "Then write the data back to card. All bytes except the first 7bytes [UID(4) MCC(1) DCF(2)]\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic restore [h] i <filename w/o .bin>");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic restore [h] [x] [f <filename w/o .bin>]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " i <filename> : filename w/o '.bin' to restore bytes on to card from");
|
||||
PrintAndLogEx(NORMAL, " f <filename> : filename w/o '.bin' to restore bytes on to card from");
|
||||
PrintAndLogEx(NORMAL, " x : obfuscate dump data (xor with MCC)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic restore i myfile");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic restore f myfile"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_eload(void) {
|
||||
PrintAndLogEx(NORMAL, "It loads binary dump from the file `filename.bin`");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic eload [h] [card memory] <file name w/o `.bin`>");
|
||||
PrintAndLogEx(NORMAL, "It loads a binary dump into emulator memory\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic eload [h] [card memory] [f <file name w/o `.bin`>]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22");
|
||||
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
|
||||
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
|
||||
PrintAndLogEx(NORMAL, " <filename> : filename w/o .bin to load");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22");
|
||||
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
|
||||
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
|
||||
PrintAndLogEx(NORMAL, " f <filename> : filename w/o .bin to load");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic eload 2 myfile");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic eload 2 myfile"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_esave(void) {
|
||||
PrintAndLogEx(NORMAL, "It saves binary dump into the file `filename.bin` or `cardID.bin`");
|
||||
PrintAndLogEx(NORMAL, " Usage: hf legic esave [h] [card memory] [file name w/o `.bin`]");
|
||||
PrintAndLogEx(NORMAL, "It saves bin/eml/json dump file of emulator memory\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic esave [h] [card memory] f <file name w/o `.bin`>\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22");
|
||||
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
|
||||
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
|
||||
PrintAndLogEx(NORMAL, " <filename> : filename w/o .bin to load");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, " [card memory] : 0 = MIM22");
|
||||
PrintAndLogEx(NORMAL, " : 1 = MIM256 (default)");
|
||||
PrintAndLogEx(NORMAL, " : 2 = MIM1024");
|
||||
PrintAndLogEx(NORMAL, " f <filename> : filename w/o .bin to load");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic esave 2 myfile");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic esave 2 -- uses UID as filename"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic esave 2 f myfile"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_legic_wipe(void) {
|
||||
PrintAndLogEx(NORMAL, "Fills a legic tag memory with zeros. From byte7 and to the end.");
|
||||
PrintAndLogEx(NORMAL, " Usage: hf legic wipe [h]");
|
||||
PrintAndLogEx(NORMAL, "Fills a LEGIC Prime tags memory with zeros. From byte7 and to the end");
|
||||
PrintAndLogEx(NORMAL, "It autodetects card type\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf legic wipe [h]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : this help");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf legic wipe");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf legic wipe"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static bool legic_xor(uint8_t *data, uint16_t cardsize) {
|
||||
|
||||
if (cardsize <= 22) {
|
||||
PrintAndLogEx(INFO, "No obsfuscation such small dump");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t crc = data[4];
|
||||
uint32_t calc_crc = CRC8Legic(data, 4);
|
||||
if (crc != calc_crc) {
|
||||
PrintAndLogEx(INFO, "Crc mismatch, obsfuscation not possible");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for(uint16_t i = 22; i < cardsize; i++) {
|
||||
data[i] ^= crc;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "(De)Obsfuscation done");
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Output BigBuf and deobfuscate LEGIC RF tag data.
|
||||
* This is based on information given in the talk held
|
||||
|
@ -495,14 +522,35 @@ out:
|
|||
// params:
|
||||
// offset in data memory
|
||||
// number of bytes to read
|
||||
static int CmdLegicRdmem(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_legic_rdmem();
|
||||
static int CmdLegicRdbl(const char *Cmd) {
|
||||
|
||||
uint32_t offset = 0, len = 0, iv = 1;
|
||||
uint16_t datalen = 0;
|
||||
sscanf(Cmd, "%x %x %x", &offset, &len, &iv);
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h' :
|
||||
return usage_legic_rdbl();
|
||||
case 'o' :
|
||||
offset = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'l' :
|
||||
len = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'i' :
|
||||
iv = param_get32ex(Cmd, cmdp + 1, 1, 16);
|
||||
cmdp += 2;
|
||||
break;
|
||||
default :
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Validations
|
||||
if (errors || strlen(Cmd) == 0) return usage_legic_rdbl();
|
||||
|
||||
// sanity checks
|
||||
if (len + offset >= MAX_LENGTH) {
|
||||
|
@ -519,6 +567,7 @@ static int CmdLegicRdmem(const char *Cmd) {
|
|||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
uint16_t datalen = 0;
|
||||
int status = legic_read_mem(offset, len, iv, data, &datalen);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(NORMAL, "\n ## | 0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F");
|
||||
|
@ -529,8 +578,7 @@ static int CmdLegicRdmem(const char *Cmd) {
|
|||
return status;
|
||||
}
|
||||
|
||||
static int CmdLegicRfSim(const char *Cmd) {
|
||||
|
||||
static int CmdLegicSim(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_legic_sim();
|
||||
|
||||
|
@ -541,7 +589,7 @@ static int CmdLegicRfSim(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLegicRfWrite(const char *Cmd) {
|
||||
static int CmdLegicWrbl(const char *Cmd) {
|
||||
|
||||
uint8_t *data = NULL;
|
||||
uint8_t cmdp = 0;
|
||||
|
@ -551,7 +599,7 @@ static int CmdLegicRfWrite(const char *Cmd) {
|
|||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'd':
|
||||
case 'd': {
|
||||
// peek at length of the input string so we can
|
||||
// figure out how many elements to malloc in "data"
|
||||
bg = en = 0;
|
||||
|
@ -595,24 +643,28 @@ static int CmdLegicRfWrite(const char *Cmd) {
|
|||
len >>= 1;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'o':
|
||||
}
|
||||
case 'o': {
|
||||
offset = param_get32ex(Cmd, cmdp + 1, 4, 16);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'h':
|
||||
}
|
||||
case 'h': {
|
||||
errors = true;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Validations
|
||||
if (errors || cmdp == 0) {
|
||||
if (data)
|
||||
free(data);
|
||||
return usage_legic_write();
|
||||
return usage_legic_wrbl();
|
||||
}
|
||||
|
||||
// tagtype
|
||||
|
@ -865,28 +917,29 @@ static int CmdLegicReader(const char *Cmd) {
|
|||
|
||||
static int CmdLegicDump(const char *Cmd) {
|
||||
|
||||
FILE *f;
|
||||
int fileNameLen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
char *fnameptr = filename;
|
||||
size_t fileNlen = 0;
|
||||
bool errors = false;
|
||||
char *fptr = filename;
|
||||
bool errors = false, shall_deobsfuscate = false;
|
||||
uint16_t dumplen;
|
||||
uint8_t cmdp = 0;
|
||||
|
||||
memset(filename, 0, sizeof(filename));
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_legic_dump();
|
||||
case 'o':
|
||||
fileNlen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
|
||||
if (!fileNlen)
|
||||
case 'f':
|
||||
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
|
||||
if (!fileNameLen)
|
||||
errors = true;
|
||||
if (fileNlen > FILE_PATH_SIZE - 5)
|
||||
fileNlen = FILE_PATH_SIZE - 5;
|
||||
if (fileNameLen > FILE_PATH_SIZE - 5)
|
||||
fileNameLen = FILE_PATH_SIZE - 5;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'x':
|
||||
shall_deobsfuscate = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
|
@ -947,34 +1000,30 @@ static int CmdLegicDump(const char *Cmd) {
|
|||
}
|
||||
|
||||
// user supplied filename?
|
||||
if (fileNlen < 1)
|
||||
sprintf(fnameptr, "%02X%02X%02X%02X.bin", data[0], data[1], data[2], data[3]);
|
||||
else
|
||||
sprintf(fnameptr + fileNlen, ".bin");
|
||||
|
||||
f = fopen(filename, "wb");
|
||||
if (!f) {
|
||||
PrintAndLogEx(WARNING, "Could not create file name %s", filename);
|
||||
if (data)
|
||||
free(data);
|
||||
return PM3_EFILE;
|
||||
if (fileNameLen < 1) {
|
||||
PrintAndLogEx(INFO, "Using UID as filename");
|
||||
fptr += sprintf(fptr, "hf-legic-");
|
||||
FillFileNameByUID(fptr, data, "-dump", 4);
|
||||
}
|
||||
fwrite(data, 1, readlen, f);
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
free(data);
|
||||
PrintAndLogEx(SUCCESS, "Wrote %d bytes to %s", readlen, filename);
|
||||
|
||||
if (shall_deobsfuscate) {
|
||||
// Deobfuscate the whole dump. Unused data (after the last sector) will be MCC since
|
||||
// 0x00 ^ MCC = MCC. Finding the end of used data is not part of this function.
|
||||
legic_xor(data, dumplen);
|
||||
}
|
||||
|
||||
saveFile(filename, ".bin", data, readlen);
|
||||
saveFileEML(filename, data, readlen, 8);
|
||||
saveFileJSON(filename, jsfLegic, data, readlen);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLegicRestore(const char *Cmd) {
|
||||
|
||||
FILE *f;
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
char *fnameptr = filename;
|
||||
size_t fileNlen = 0;
|
||||
bool errors = false;
|
||||
uint16_t numofbytes;
|
||||
bool errors = false, shall_obsfuscate = false;
|
||||
size_t numofbytes;
|
||||
uint8_t cmdp = 0;
|
||||
|
||||
memset(filename, 0, sizeof(filename));
|
||||
|
@ -984,7 +1033,7 @@ static int CmdLegicRestore(const char *Cmd) {
|
|||
case 'h':
|
||||
errors = true;
|
||||
break;
|
||||
case 'i':
|
||||
case 'f':
|
||||
fileNlen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
|
||||
if (!fileNlen)
|
||||
errors = true;
|
||||
|
@ -993,6 +1042,10 @@ static int CmdLegicRestore(const char *Cmd) {
|
|||
fileNlen = FILE_PATH_SIZE - 5;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'x':
|
||||
shall_obsfuscate = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
|
@ -1008,48 +1061,30 @@ static int CmdLegicRestore(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "Failed to identify tagtype");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
numofbytes = card.cardsize;
|
||||
|
||||
legic_print_type(card.cardsize, 0);
|
||||
|
||||
// set up buffer
|
||||
uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
|
||||
uint8_t *data = calloc(card.cardsize, sizeof(uint8_t));
|
||||
if (!data) {
|
||||
PrintAndLogEx(WARNING, "Fail, cannot allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
legic_print_type(numofbytes, 0);
|
||||
if (loadFile_safe(filename, ".bin", (void **)&data, &numofbytes) != PM3_SUCCESS) {
|
||||
free(data);
|
||||
PrintAndLogEx(WARNING, "Error, reading file");
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
// set up file
|
||||
fnameptr += fileNlen;
|
||||
sprintf(fnameptr, ".bin");
|
||||
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
PrintAndLogEx(WARNING, "File %s not found or locked", filename);
|
||||
if (card.cardsize != numofbytes) {
|
||||
PrintAndLogEx(WARNING, "Fail, filesize and cardsize is not equal. [%zu != %u]", card.cardsize, numofbytes);
|
||||
free(data);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
// verify size of dumpfile is the same as card.
|
||||
fseek(f, 0, SEEK_END); // seek to end of file
|
||||
size_t filesize = ftell(f); // get current file pointer
|
||||
fseek(f, 0, SEEK_SET); // seek back to beginning of file
|
||||
|
||||
if (filesize != numofbytes) {
|
||||
PrintAndLogEx(WARNING, "Fail, filesize and cardsize is not equal. [%zu != %u]", filesize, numofbytes);
|
||||
free(data);
|
||||
fclose(f);
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
// load file
|
||||
size_t bytes_read = fread(data, 1, numofbytes, f);
|
||||
fclose(f);
|
||||
|
||||
if (bytes_read == 0) {
|
||||
PrintAndLogEx(ERR, "File reading error");
|
||||
free(data);
|
||||
return PM3_EFILE;
|
||||
if (shall_obsfuscate){
|
||||
legic_xor(data, card.cardsize);
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Restoring to card");
|
||||
|
@ -1092,37 +1127,54 @@ static int CmdLegicRestore(const char *Cmd) {
|
|||
}
|
||||
|
||||
free(data);
|
||||
PrintAndLogEx(SUCCESS, "\nWrote %d bytes to card from file %s", numofbytes, filename);
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLegicELoad(const char *Cmd) {
|
||||
FILE *f;
|
||||
char filename[FILE_PATH_SIZE];
|
||||
char *fnameptr = filename;
|
||||
int len, numofbytes;
|
||||
int nameParamNo = 1;
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h' || cmdp == 0x00)
|
||||
return usage_legic_eload();
|
||||
size_t numofbytes = 256;
|
||||
int fileNameLen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
bool errors = false, shall_obsfuscate = false;
|
||||
uint8_t cmdp = 0;
|
||||
|
||||
switch (cmdp) {
|
||||
case '0' :
|
||||
numofbytes = 22;
|
||||
break;
|
||||
case '1' :
|
||||
case '\0':
|
||||
numofbytes = 256;
|
||||
break;
|
||||
case '2' :
|
||||
numofbytes = 1024;
|
||||
break;
|
||||
default :
|
||||
numofbytes = 256;
|
||||
nameParamNo = 0;
|
||||
break;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h' :
|
||||
return usage_legic_eload();
|
||||
case 'f' :
|
||||
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
|
||||
if (!fileNameLen)
|
||||
errors = true;
|
||||
if (fileNameLen > FILE_PATH_SIZE - 5)
|
||||
fileNameLen = FILE_PATH_SIZE - 5;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'x':
|
||||
shall_obsfuscate = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case '0' :
|
||||
numofbytes = 22;
|
||||
cmdp++;
|
||||
break;
|
||||
case '1' :
|
||||
numofbytes = 256;
|
||||
cmdp++;
|
||||
break;
|
||||
case '2' :
|
||||
numofbytes = 1024;
|
||||
cmdp++;
|
||||
break;
|
||||
default :
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Validations
|
||||
if (errors || strlen(Cmd) == 0) return usage_legic_eload();
|
||||
|
||||
// set up buffer
|
||||
uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
|
||||
|
@ -1131,75 +1183,68 @@ static int CmdLegicELoad(const char *Cmd) {
|
|||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
// set up file
|
||||
len = param_getstr(Cmd, nameParamNo, filename, FILE_PATH_SIZE);
|
||||
if (len > FILE_PATH_SIZE - 5)
|
||||
len = FILE_PATH_SIZE - 5;
|
||||
fnameptr += len;
|
||||
sprintf(fnameptr, ".bin");
|
||||
|
||||
// open file
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
PrintAndLogEx(WARNING, "File %s not found or locked", filename);
|
||||
if (loadFile_safe(filename, ".bin", (void **)&data, &numofbytes) != PM3_SUCCESS) {
|
||||
free(data);
|
||||
PrintAndLogEx(WARNING, "Error, reading file");
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
// load file
|
||||
size_t bytes_read = fread(data, 1, numofbytes, f);
|
||||
if (bytes_read == 0) {
|
||||
PrintAndLogEx(ERR, "File reading error");
|
||||
free(data);
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
return PM3_EFILE;
|
||||
if (shall_obsfuscate) {
|
||||
legic_xor(data, numofbytes);
|
||||
}
|
||||
fclose(f);
|
||||
f = NULL;
|
||||
|
||||
// transfer to device
|
||||
PrintAndLogEx(SUCCESS, "Uploading to emulator memory");
|
||||
legic_seteml(data, 0, numofbytes);
|
||||
|
||||
free(data);
|
||||
PrintAndLogEx(SUCCESS, "\nLoaded %d bytes from file: %s to emulator memory", numofbytes, filename);
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLegicESave(const char *Cmd) {
|
||||
|
||||
char filename[FILE_PATH_SIZE];
|
||||
char *fnameptr = filename;
|
||||
int fileNlen, numofbytes, nameParamNo = 1;
|
||||
|
||||
memset(filename, 0, sizeof(filename));
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
|
||||
if (cmdp == 'h' || cmdp == 0x00)
|
||||
return usage_legic_esave();
|
||||
|
||||
switch (cmdp) {
|
||||
case '0' :
|
||||
numofbytes = 22;
|
||||
break;
|
||||
case '1' :
|
||||
case '\0':
|
||||
numofbytes = 256;
|
||||
break;
|
||||
case '2' :
|
||||
numofbytes = 1024;
|
||||
break;
|
||||
default :
|
||||
numofbytes = 256;
|
||||
nameParamNo = 0;
|
||||
break;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
char *fptr = filename;
|
||||
int fileNameLen = 0;
|
||||
size_t numofbytes = 256;
|
||||
bool errors = false, shall_deobsfuscate = false;
|
||||
uint8_t cmdp = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h' :
|
||||
return usage_legic_esave();
|
||||
case 'f' :
|
||||
fileNameLen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
|
||||
if (!fileNameLen)
|
||||
errors = true;
|
||||
if (fileNameLen > FILE_PATH_SIZE - 5)
|
||||
fileNameLen = FILE_PATH_SIZE - 5;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'x':
|
||||
shall_deobsfuscate = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case '0' :
|
||||
numofbytes = 22;
|
||||
cmdp++;
|
||||
break;
|
||||
case '1' :
|
||||
numofbytes = 256;
|
||||
cmdp++;
|
||||
break;
|
||||
case '2' :
|
||||
numofbytes = 1024;
|
||||
cmdp++;
|
||||
break;
|
||||
default :
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fileNlen = param_getstr(Cmd, nameParamNo, filename, FILE_PATH_SIZE);
|
||||
|
||||
if (fileNlen > FILE_PATH_SIZE - 5)
|
||||
fileNlen = FILE_PATH_SIZE - 5;
|
||||
//Validations
|
||||
if (errors || strlen(Cmd) == 0) return usage_legic_esave();
|
||||
|
||||
// set up buffer
|
||||
uint8_t *data = calloc(numofbytes, sizeof(uint8_t));
|
||||
|
@ -1215,14 +1260,21 @@ static int CmdLegicESave(const char *Cmd) {
|
|||
free(data);
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
// user supplied filename?
|
||||
if (fileNlen < 1)
|
||||
sprintf(fnameptr, "%02X%02X%02X%02X.bin", data[0], data[1], data[2], data[3]);
|
||||
else
|
||||
sprintf(fnameptr + fileNlen, ".bin");
|
||||
|
||||
saveFileEML(filename, data, numofbytes, 8);
|
||||
// user supplied filename?
|
||||
if (fileNameLen < 1) {
|
||||
PrintAndLogEx(INFO, "Using UID as filename");
|
||||
fptr += sprintf(fptr, "hf-legic-");
|
||||
FillFileNameByUID(fptr, data, "-dump", 4);
|
||||
}
|
||||
|
||||
if (shall_deobsfuscate) {
|
||||
legic_xor(data, numofbytes);
|
||||
}
|
||||
|
||||
saveFile(filename, ".bin", data, numofbytes);
|
||||
saveFileEML(filename, data, numofbytes, 8);
|
||||
saveFileJSON(filename, jsfLegic, data, numofbytes);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1299,17 +1351,17 @@ static int CmdLegicList(const char *Cmd) {
|
|||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdLegicList, AlwaysAvailable, "List LEGIC history"},
|
||||
{"reader", CmdLegicReader, IfPm3Legicrf, "LEGIC Prime Reader UID and tag info"},
|
||||
{"info", CmdLegicInfo, IfPm3Legicrf, "Display deobfuscated and decoded LEGIC Prime tag data"},
|
||||
{"dump", CmdLegicDump, IfPm3Legicrf, "Dump LEGIC Prime tag to binary file"},
|
||||
{"restore", CmdLegicRestore, IfPm3Legicrf, "Restore a dump file onto a LEGIC Prime tag"},
|
||||
{"rdmem", CmdLegicRdmem, IfPm3Legicrf, "Read bytes from a LEGIC Prime tag"},
|
||||
{"sim", CmdLegicRfSim, IfPm3Legicrf, "Start tag simulator"},
|
||||
{"write", CmdLegicRfWrite, IfPm3Legicrf, "Write data to a LEGIC Prime tag"},
|
||||
{"rdbl", CmdLegicRdbl, IfPm3Legicrf, "Read bytes from a LEGIC Prime tag"},
|
||||
{"sim", CmdLegicSim, IfPm3Legicrf, "Start tag simulator"},
|
||||
{"wrbl", CmdLegicWrbl, IfPm3Legicrf, "Write data to a LEGIC Prime tag"},
|
||||
{"crc", CmdLegicCalcCrc, AlwaysAvailable, "Calculate Legic CRC over given bytes"},
|
||||
{"eload", CmdLegicELoad, IfPm3Legicrf, "Load binary dump to emulator memory"},
|
||||
{"esave", CmdLegicESave, IfPm3Legicrf, "Save emulator memory to binary file"},
|
||||
{"list", CmdLegicList, AlwaysAvailable, "List LEGIC history"},
|
||||
{"wipe", CmdLegicWipe, IfPm3Legicrf, "Wipe a LEGIC Prime tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
|
|
@ -218,15 +218,15 @@ static int lto_rdbl(uint8_t blk, uint8_t *block_responce, uint8_t *block_cnt_res
|
|||
|
||||
uint16_t resp_len = 18;
|
||||
uint8_t rdbl_cmd[] = {0x30, blk};
|
||||
uint8_t rdbl_cnt_cmd[] ={0x80};
|
||||
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 ) {
|
||||
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 ) {
|
||||
if (status == PM3_ETIMEOUT || status == PM3_ESOFT) {
|
||||
return PM3_EWRONGANSVER; // READ BLOCK CONTINUE failed
|
||||
}
|
||||
|
||||
|
@ -252,7 +252,7 @@ int rdblLTO(uint8_t st_blk, uint8_t end_blk, bool verbose) {
|
|||
uint8_t block_data_d16_d31[18];
|
||||
uint8_t block_data[32];
|
||||
|
||||
for(uint8_t i = st_blk; i < end_blk + 1; i++) {
|
||||
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);
|
||||
|
||||
|
@ -286,8 +286,8 @@ static int CmdHfLTOReadBlock(const char *Cmd) {
|
|||
case 'h':
|
||||
return usage_lto_rdbl();
|
||||
case 's':
|
||||
st_blk = param_get8(Cmd, cmdp+1);
|
||||
if ( end_blk < st_blk ) {
|
||||
st_blk = param_get8(Cmd, cmdp + 1);
|
||||
if (end_blk < st_blk) {
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
|
@ -295,10 +295,11 @@ static int CmdHfLTOReadBlock(const char *Cmd) {
|
|||
break;
|
||||
|
||||
case 'e':
|
||||
end_blk = param_get8(Cmd, cmdp+1);
|
||||
if ( end_blk < st_blk ) {
|
||||
end_blk = param_get8(Cmd, cmdp + 1);
|
||||
if (end_blk < st_blk) {
|
||||
errors = true;
|
||||
break; }
|
||||
break;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
|
||||
|
@ -328,7 +329,7 @@ static int lto_wrbl(uint8_t blk, uint8_t *data, bool verbose) {
|
|||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
wrbl_d00_d15[i] = data[i];
|
||||
wrbl_d16_d31[i] = data[i+16];
|
||||
wrbl_d16_d31[i] = data[i + 16];
|
||||
}
|
||||
|
||||
int status = lto_send_cmd_raw(wrbl_cmd, sizeof(wrbl_cmd), resp, &resp_len, true, false, verbose);
|
||||
|
@ -390,15 +391,15 @@ static int CmdHfLTOWriteBlock(const char *Cmd) {
|
|||
case 'h':
|
||||
return usage_lto_wrbl();
|
||||
case 'b':
|
||||
blk = param_get8(Cmd, cmdp+1);
|
||||
blk = param_get8(Cmd, cmdp + 1);
|
||||
b_opt_selected = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
if (param_gethex(Cmd, cmdp+1, blkData, 64)) {
|
||||
if (param_gethex(Cmd, cmdp + 1, blkData, 64)) {
|
||||
PrintAndLogEx(WARNING, "block data must include 64 HEX symbols");
|
||||
errors = true;
|
||||
break;
|
||||
break;
|
||||
}
|
||||
d_opt_selected = true;
|
||||
cmdp += 2;
|
||||
|
@ -409,7 +410,7 @@ static int CmdHfLTOWriteBlock(const char *Cmd) {
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Validations
|
||||
if (errors) {
|
||||
usage_lto_wrbl();
|
||||
|
@ -440,7 +441,7 @@ int dumpLTO(uint8_t *dump, bool verbose) {
|
|||
uint8_t block_data_d00_d15[18];
|
||||
uint8_t block_data_d16_d31[18];
|
||||
|
||||
for(uint8_t i = 0; i < 255; i++) {
|
||||
for (uint8_t i = 0; i < 255; i++) {
|
||||
|
||||
ret_val = lto_rdbl(i, block_data_d00_d15, block_data_d16_d31, verbose);
|
||||
|
||||
|
@ -504,10 +505,10 @@ static int CmdHfLTODump(const char *Cmd) {
|
|||
int ret_val = dumpLTO(dump, true);
|
||||
if (ret_val != PM3_SUCCESS) {
|
||||
free(dump);
|
||||
return ret_val;
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
// save to file
|
||||
// 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_";
|
||||
|
@ -523,7 +524,7 @@ static int CmdHfLTODump(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int restoreLTO(uint8_t *dump_data, bool verbose) {
|
||||
int restoreLTO(uint8_t *dump, bool verbose) {
|
||||
|
||||
clearCommandBuffer();
|
||||
lto_switch_on_field();
|
||||
|
@ -538,19 +539,19 @@ int restoreLTO(uint8_t *dump_data, bool verbose) {
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
uint8_t blkData[32] = {0};
|
||||
uint8_t blkData[32] = {0};
|
||||
|
||||
//Block address 0 and 1 are read-only
|
||||
for(uint8_t blk = 2; blk < 255; blk++) {
|
||||
for (uint8_t blk = 2; blk < 255; blk++) {
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
blkData[i] = dump_data[i + blk * 32];
|
||||
blkData[i] = dump[i + blk * 32];
|
||||
}
|
||||
|
||||
ret_val = lto_wrbl(blk, blkData, verbose);
|
||||
|
||||
if (ret_val == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "BLK %03d: " _YELLOW_("write success"), blk);
|
||||
PrintAndLogEx(SUCCESS, "Block %03d - " _YELLOW_("write success"), blk);
|
||||
} else {
|
||||
lto_switch_off_field();
|
||||
return ret_val;
|
||||
|
@ -566,7 +567,7 @@ 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};
|
||||
|
||||
|
@ -623,7 +624,7 @@ static int CmdHfLTRestore(const char *Cmd) {
|
|||
} else {
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
|
189
client/cmdhfmf.c
189
client/cmdhfmf.c
|
@ -248,10 +248,10 @@ static int usage_hf14_chk(void) {
|
|||
PrintAndLogEx(NORMAL, " t write keys to emulator memory\n");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf mf chk 0 A 1234567890ab -- target block 0, Key A using key 1234567890ab");
|
||||
PrintAndLogEx(NORMAL, " hf mf chk 0 A mfc_default_keys.dic -- target block 0, Key A using default dictionary file");
|
||||
PrintAndLogEx(NORMAL, " hf mf chk *1 ? t -- target all blocks, all keys, 1K, write to emulator memory");
|
||||
PrintAndLogEx(NORMAL, " hf mf chk *1 ? d -- target all blocks, all keys, 1K, write to file");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk 0 A 1234567890ab")" -- target block 0, Key A using key 1234567890ab");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk 0 A mfc_default_keys.dic")" -- target block 0, Key A using default dictionary file");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk *1 ? t")" -- target all blocks, all keys, 1K, write to emulator memory");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf chk *1 ? d")" -- target all blocks, all keys, 1K, write to file");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf14_chk_fast(void) {
|
||||
|
@ -269,12 +269,12 @@ static int usage_hf14_chk_fast(void) {
|
|||
PrintAndLogEx(NORMAL, " m use dictionary from flashmemory\n");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf mf fchk 1 1234567890ab -- target 1K using key 1234567890ab");
|
||||
PrintAndLogEx(NORMAL, " hf mf fchk 1 mfc_default_keys.dic -- target 1K using default dictionary file");
|
||||
PrintAndLogEx(NORMAL, " hf mf fchk 1 t -- target 1K, write to emulator memory");
|
||||
PrintAndLogEx(NORMAL, " hf mf fchk 1 d -- target 1K, write to file");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 1234567890ab")" -- target 1K using key 1234567890ab");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 mfc_default_keys.dic")" -- target 1K using default dictionary file");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 t")" -- target 1K, write to emulator memory");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 d")" -- target 1K, write to file");
|
||||
if (IfPm3Flash())
|
||||
PrintAndLogEx(NORMAL, " hf mf fchk 1 m -- target 1K, use dictionary from flashmemory");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf fchk 1 m")" -- target 1K, use dictionary from flashmemory");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
/*
|
||||
|
@ -300,15 +300,15 @@ static int usage_hf14_restore(void) {
|
|||
PrintAndLogEx(NORMAL, "Usage: hf mf restore [card memory] u <UID> k <name> f <name>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");
|
||||
PrintAndLogEx(NORMAL, " u <UID> : uid, try to restore from hf-mf-<UID>-key.bin and hf-mf-<UID>-data.bin");
|
||||
PrintAndLogEx(NORMAL, " u <UID> : uid, try to restore from hf-mf-<UID>-key.bin and hf-mf-<UID>-dump.bin");
|
||||
PrintAndLogEx(NORMAL, " k <name> : key filename, specific the full filename of key file");
|
||||
PrintAndLogEx(NORMAL, " f <name> : data filename, specific the full filename of data file");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf mf restore -- read the UID from tag first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-data.bin");
|
||||
PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 -- restore from hf-mf-12345678-key.bin and hf-mf-12345678-data.bin");
|
||||
PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 k dumpkey.bin -- restore from dumpkey.bin and hf-mf-12345678-data.bin");
|
||||
PrintAndLogEx(NORMAL, " hf mf restore 4 -- read the UID from tag with 4K memory first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-data.bin");
|
||||
PrintAndLogEx(NORMAL, " hf mf restore -- read the UID from tag first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-dump.bin");
|
||||
PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 -- restore from hf-mf-12345678-key.bin and hf-mf-12345678-dump.bin");
|
||||
PrintAndLogEx(NORMAL, " hf mf restore 1 u 12345678 k dumpkey.bin -- restore from dumpkey.bin and hf-mf-12345678-dump.bin");
|
||||
PrintAndLogEx(NORMAL, " hf mf restore 4 -- read the UID from tag with 4K memory first, then restore from hf-mf-<UID>-key.bin and and hf-mf-<UID>-dump.bin");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf14_decryptbytes(void) {
|
||||
|
@ -1064,7 +1064,7 @@ static int CmdHF14AMfDump(const char *Cmd) {
|
|||
PrintAndLogEx(SUCCESS, "\nSucceeded in dumping all blocks");
|
||||
|
||||
if (strlen(dataFilename) < 1) {
|
||||
fptr = GenerateFilename("hf-mf-", "-data");
|
||||
fptr = GenerateFilename("hf-mf-", "-dump");
|
||||
if (fptr == NULL)
|
||||
return PM3_ESOFT;
|
||||
|
||||
|
@ -1103,7 +1103,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
|||
if (keyFilename[0] == 0x00)
|
||||
snprintf(keyFilename, FILE_PATH_SIZE, "hf-mf-%s-key.bin", szTemp);
|
||||
if (dataFilename[0] == 0x00)
|
||||
snprintf(dataFilename, FILE_PATH_SIZE, "hf-mf-%s-data.bin", szTemp);
|
||||
snprintf(dataFilename, FILE_PATH_SIZE, "hf-mf-%s-dump.bin", szTemp);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'k':
|
||||
|
@ -1161,7 +1161,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
|||
fclose(fkeys);
|
||||
|
||||
if (dataFilename[0] == 0x00) {
|
||||
fptr = GenerateFilename("hf-mf-", "-data.bin");
|
||||
fptr = GenerateFilename("hf-mf-", "-dump.bin");
|
||||
if (fptr == NULL)
|
||||
return 1;
|
||||
|
||||
|
@ -1279,7 +1279,7 @@ static int CmdHF14AMfNested(const char *Cmd) {
|
|||
}
|
||||
|
||||
// check if tag doesn't have static nonce
|
||||
if (detect_classic_static_nonce() != 0) {
|
||||
if (detect_classic_static_nonce() == 1) {
|
||||
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
|
||||
PrintAndLogEx(INFO, "\t Try use " _YELLOW_("`hf mf staticnested`"));
|
||||
return PM3_EOPABORTED;
|
||||
|
@ -1447,7 +1447,7 @@ static int CmdHF14AMfNested(const char *Cmd) {
|
|||
jumptoend:
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "found keys:");
|
||||
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
|
||||
|
||||
//print them
|
||||
printKeyTable(SectorsCnt, e_sector);
|
||||
|
@ -1652,7 +1652,7 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
|
|||
jumptoend:
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "found keys:");
|
||||
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
|
||||
|
||||
//print them
|
||||
printKeyTable(SectorsCnt, e_sector);
|
||||
|
@ -1839,7 +1839,7 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
|
|||
if (!know_target_key && nonce_file_read == false) {
|
||||
|
||||
// check if tag doesn't have static nonce
|
||||
if (detect_classic_static_nonce() != 0) {
|
||||
if (detect_classic_static_nonce() == 1) {
|
||||
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
|
||||
PrintAndLogEx(INFO, "\t Try use `" _YELLOW_("hf mf staticnested") "`");
|
||||
return PM3_EOPABORTED;
|
||||
|
@ -2463,7 +2463,7 @@ all_found:
|
|||
|
||||
// Show the results to the user
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "found keys:");
|
||||
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
|
||||
|
||||
printKeyTable(sectors_cnt, e_sector);
|
||||
|
||||
|
@ -2507,7 +2507,7 @@ all_found:
|
|||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
fnameptr = GenerateFilename("hf-mf-", "-data");
|
||||
fnameptr = GenerateFilename("hf-mf-", "-dump");
|
||||
if (fnameptr == NULL) {
|
||||
free(dump);
|
||||
free(e_sector);
|
||||
|
@ -2715,7 +2715,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
|
|||
|
||||
// strategys. 1= deep first on sector 0 AB, 2= width first on all sectors
|
||||
for (uint8_t strategy = 1; strategy < 3; strategy++) {
|
||||
PrintAndLogEx(SUCCESS, "Running strategy %u", strategy);
|
||||
PrintAndLogEx(INFO, "Running strategy %u", strategy);
|
||||
|
||||
// main keychunk loop
|
||||
for (i = 0; i < keycnt; i += chunksize) {
|
||||
|
@ -2746,7 +2746,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) {
|
|||
}
|
||||
out:
|
||||
t1 = msclock() - t1;
|
||||
PrintAndLogEx(SUCCESS, "Time in checkkeys (fast): %.1fs\n", (float)(t1 / 1000.0));
|
||||
PrintAndLogEx(INFO, "Time in checkkeys (fast): %.1fs\n", (float)(t1 / 1000.0));
|
||||
|
||||
// check..
|
||||
uint8_t found_keys = 0;
|
||||
|
@ -2764,7 +2764,7 @@ out:
|
|||
} else {
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "found keys:");
|
||||
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
|
||||
|
||||
printKeyTable(sectorsCnt, e_sector);
|
||||
|
||||
|
@ -3027,7 +3027,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
t1 = msclock() - t1;
|
||||
PrintAndLogEx(SUCCESS, "\nTime in checkkeys: %.0f seconds\n", (float)t1 / 1000.0);
|
||||
PrintAndLogEx(INFO, "\nTime in checkkeys: %.0f seconds\n", (float)t1 / 1000.0);
|
||||
|
||||
|
||||
// 20160116 If Sector A is found, but not Sector B, try just reading it of the tag?
|
||||
|
@ -3075,7 +3075,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
|
|||
|
||||
out:
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "found keys:");
|
||||
PrintAndLogEx(SUCCESS, _GREEN_("found keys:"));
|
||||
|
||||
//print keys
|
||||
if (SectorsCnt == 1)
|
||||
|
@ -3129,7 +3129,7 @@ out:
|
|||
}
|
||||
|
||||
sector_t *k_sector = NULL;
|
||||
uint8_t k_sectorsCount = 16;
|
||||
uint8_t k_sectorsCount = 40;
|
||||
|
||||
void showSectorTable() {
|
||||
if (k_sector != NULL) {
|
||||
|
@ -3217,18 +3217,22 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
|||
case 0:
|
||||
flags |= FLAG_MF_MINI;
|
||||
sprintf(csize, "MINI");
|
||||
k_sectorsCount = MIFARE_MINI_MAXSECTOR;
|
||||
break;
|
||||
case 1:
|
||||
flags |= FLAG_MF_1K;
|
||||
sprintf(csize, "1K");
|
||||
k_sectorsCount = MIFARE_1K_MAXSECTOR;
|
||||
break;
|
||||
case 2:
|
||||
flags |= FLAG_MF_2K;
|
||||
sprintf(csize, "2K with RATS");
|
||||
k_sectorsCount = MIFARE_2K_MAXSECTOR;
|
||||
break;
|
||||
case 4:
|
||||
flags |= FLAG_MF_4K;
|
||||
sprintf(csize, "4K");
|
||||
k_sectorsCount = MIFARE_4K_MAXSECTOR;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter for option t");
|
||||
|
@ -3342,6 +3346,8 @@ static int CmdHF14AMfSim(const char *Cmd) {
|
|||
}
|
||||
showSectorTable();
|
||||
}
|
||||
|
||||
k_sectorsCount = MIFARE_4K_MAXSECTOR;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
/*
|
||||
|
@ -3543,9 +3549,9 @@ void printKeyTable(uint8_t sectorscnt, sector_t *e_sector) {
|
|||
void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_sector) {
|
||||
char strA[12 + 1] = {0};
|
||||
char strB[12 + 1] = {0};
|
||||
PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|");
|
||||
PrintAndLogEx(NORMAL, "|sec| key A |res| key B |res|");
|
||||
PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|");
|
||||
PrintAndLogEx(SUCCESS, "|-----|----------------|---|----------------|---|");
|
||||
PrintAndLogEx(SUCCESS, "| Sec | key A |res| key B |res|");
|
||||
PrintAndLogEx(SUCCESS, "|-----|----------------|---|----------------|---|");
|
||||
for (uint8_t i = 0; i < sectorscnt; i++) {
|
||||
|
||||
snprintf(strA, sizeof(strA), "------------");
|
||||
|
@ -3558,7 +3564,7 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
|
|||
snprintf(strB, sizeof(strB), "%012" PRIx64, e_sector[i].Key[1]);
|
||||
|
||||
if (e_sector[i].foundKey[0] > 1) {
|
||||
PrintAndLogEx(NORMAL, "|%03d| %s | " _YELLOW_("%c")"| %s | " _YELLOW_("%c")"|"
|
||||
PrintAndLogEx(SUCCESS, "| "_YELLOW_("%03d")"| " _GREEN_("%s")" | " _YELLOW_("%c")"| " _GREEN_("%s")" | " _YELLOW_("%c")"|"
|
||||
, i
|
||||
, strA, e_sector[i].foundKey[0]
|
||||
, strB, e_sector[i].foundKey[1]
|
||||
|
@ -3570,14 +3576,14 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
|
|||
if (start_sector == 0)
|
||||
s = i;
|
||||
|
||||
PrintAndLogEx(NORMAL, "|%03d| %s | " _YELLOW_("%d")"| %s | " _YELLOW_("%d")"|"
|
||||
PrintAndLogEx(SUCCESS, "| "_YELLOW_("%03d")"| " _GREEN_("%s")" | " _YELLOW_("%d")"| " _GREEN_("%s")" | " _YELLOW_("%d")"|"
|
||||
, s
|
||||
, strA, e_sector[i].foundKey[0]
|
||||
, strB, e_sector[i].foundKey[1]
|
||||
);
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "|---|----------------|---|----------------|---|");
|
||||
PrintAndLogEx(SUCCESS, "|-----|----------------|---|----------------|---|");
|
||||
|
||||
if (e_sector[0].foundKey[0] > 1) {
|
||||
PrintAndLogEx(INFO, "( "
|
||||
|
@ -3591,7 +3597,7 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto
|
|||
")"
|
||||
);
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "( " _YELLOW_("0") ":Failed / " _YELLOW_("1") ":Success)");
|
||||
PrintAndLogEx(SUCCESS, "( " _YELLOW_("0") ":Failed / " _YELLOW_("1") ":Success)");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3745,7 +3751,7 @@ int CmdHF14AMfELoad(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Loaded %d blocks from file: " _YELLOW_("%s"), blockNum, filename);
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
free(data);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -3829,6 +3835,7 @@ static int CmdHF14AMfECFill(const char *Cmd) {
|
|||
mfc_eload_t payload;
|
||||
payload.sectorcnt = numSectors;
|
||||
payload.keytype = keyType;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload));
|
||||
return PM3_SUCCESS;
|
||||
|
@ -3836,8 +3843,6 @@ static int CmdHF14AMfECFill(const char *Cmd) {
|
|||
|
||||
static int CmdHF14AMfEKeyPrn(const char *Cmd) {
|
||||
|
||||
char filename[FILE_PATH_SIZE];
|
||||
char *fptr = filename;
|
||||
uint8_t sectors_cnt = MIFARE_1K_MAXSECTOR;
|
||||
uint8_t data[16];
|
||||
uint8_t uid[4];
|
||||
|
@ -3909,6 +3914,8 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) {
|
|||
// dump the keys
|
||||
if (createDumpFile) {
|
||||
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
char *fptr = filename;
|
||||
fptr += sprintf(fptr, "hf-mf-");
|
||||
FillFileNameByUID(fptr + strlen(fptr), uid, "-key", sizeof(uid));
|
||||
|
||||
|
@ -3975,8 +3982,8 @@ static int CmdHF14AMfCSetUID(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "old UID:%s", sprint_hex(oldUid, 4));
|
||||
PrintAndLogEx(SUCCESS, "new UID:%s", sprint_hex(uid, 4));
|
||||
PrintAndLogEx(SUCCESS, "Old UID : %s", sprint_hex(oldUid, 4));
|
||||
PrintAndLogEx(SUCCESS, "New UID : %s", sprint_hex(uid, 4));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -4798,6 +4805,95 @@ static int CmdHFMFNDEF(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHFMFPersonalize(const char *cmd) {
|
||||
|
||||
CLIParserInit("hf mf personalize",
|
||||
"Personalize the UID of a Mifare Classic EV1 card. This is only possible if it is a 7Byte UID card and if it is not already personalized.",
|
||||
"Usage:\n\thf mf personalize UIDF0 -> double size UID according to ISO/IEC14443-3\n"
|
||||
"\thf mf personalize UIDF1 -> double size UID according to ISO/IEC14443-3, optional usage of selection process shortcut\n"
|
||||
"\thf mf personalize UIDF2 -> single size random ID according to ISO/IEC14443-3\n"
|
||||
"\thf mf personalize UIDF3 -> single size NUID according to ISO/IEC14443-3\n"
|
||||
"\thf mf personalize -t B -k B0B1B2B3B4B5 UIDF3 -> use key B = 0xB0B1B2B3B4B5 instead of default key A\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("tT", "keytype", "<A|B>", "key type (A or B) to authenticate sector 0 (default: A)"),
|
||||
arg_str0("kK", "key", "<key (hex 6 Bytes)>", "key to authenticate sector 0 (default: FFFFFFFFFFFF)"),
|
||||
arg_str1(NULL, NULL, "<UIDF0|UIDF1|UIDF2|UIDF3>", "Personalization Option"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(cmd, argtable, true);
|
||||
|
||||
char keytypestr[2] = "a";
|
||||
uint8_t keytype = 0x00;
|
||||
int keytypestr_len;
|
||||
int res = CLIParamStrToBuf(arg_get_str(1), (uint8_t *)keytypestr, 1, &keytypestr_len);
|
||||
str_lower(keytypestr);
|
||||
|
||||
if (res || (keytypestr[0] != 'a' && keytypestr[0] != 'b')) {
|
||||
PrintAndLogEx(ERR, "ERROR: not a valid key type. Key type must be A or B");
|
||||
CLIParserFree();
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (keytypestr[0] == 'b') {
|
||||
keytype = 0x01;
|
||||
}
|
||||
|
||||
uint8_t key[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
int key_len;
|
||||
res = CLIParamHexToBuf(arg_get_str(2), key, 6, &key_len);
|
||||
if (res || (!res && key_len > 0 && key_len != 6)) {
|
||||
PrintAndLogEx(ERR, "ERROR: not a valid key. Key must be 12 hex digits");
|
||||
CLIParserFree();
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
char pers_optionstr[6];
|
||||
int opt_len;
|
||||
uint8_t pers_option;
|
||||
res = CLIParamStrToBuf(arg_get_str(3), (uint8_t *)pers_optionstr, 5, &opt_len);
|
||||
str_lower(pers_optionstr);
|
||||
|
||||
if (res || (!res && opt_len > 0 && opt_len != 5)
|
||||
|| (strncmp(pers_optionstr, "uidf0", 5) && strncmp(pers_optionstr, "uidf1", 5) && strncmp(pers_optionstr, "uidf2", 5) && strncmp(pers_optionstr, "uidf3", 5))) {
|
||||
PrintAndLogEx(ERR, "ERROR: invalid personalization option. Must be one of UIDF0, UIDF1, UIDF2, or UIDF3");
|
||||
CLIParserFree();
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (!strncmp(pers_optionstr, "uidf0", 5)) {
|
||||
pers_option = MIFARE_EV1_UIDF0;
|
||||
} else if (!strncmp(pers_optionstr, "uidf1", 5)) {
|
||||
pers_option = MIFARE_EV1_UIDF1;
|
||||
} else if (!strncmp(pers_optionstr, "uidf2", 5)) {
|
||||
pers_option = MIFARE_EV1_UIDF2;
|
||||
} else {
|
||||
pers_option = MIFARE_EV1_UIDF3;
|
||||
}
|
||||
|
||||
CLIParserFree();
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
struct {
|
||||
uint8_t keytype;
|
||||
uint8_t pers_option;
|
||||
uint8_t key[6];
|
||||
} PACKED payload;
|
||||
payload.keytype = keytype;
|
||||
payload.pers_option = pers_option;
|
||||
|
||||
memcpy(payload.key, key, 6);
|
||||
|
||||
SendCommandNG(CMD_HF_MIFARE_PERSONALIZE_UID, (uint8_t *)&payload, sizeof(payload));
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_HF_MIFARE_PERSONALIZE_UID, &resp, 2500)) return PM3_ETIMEOUT;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Personalization %s", resp.status == PM3_SUCCESS ? "SUCCEEDED" : "FAILED");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHF14AMfList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
return CmdTraceList("mf");
|
||||
|
@ -4817,13 +4913,16 @@ static command_t CommandTable[] = {
|
|||
{"fchk", CmdHF14AMfChk_fast, IfPm3Iso14443a, "Check keys fast, targets all keys on card"},
|
||||
{"decrypt", CmdHf14AMfDecryptBytes, AlwaysAvailable, "[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
|
||||
{"auth4", CmdHF14AMfAuth4, IfPm3Iso14443a, "ISO14443-4 AES authentication"},
|
||||
{"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE classic tag to binary file"},
|
||||
{"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"},
|
||||
{"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||
{"personalize", CmdHFMFPersonalize, IfPm3Iso14443a, "Personalize UID (Mifare Classic EV1 only)"},
|
||||
{"rdbl", CmdHF14AMfRdBl, IfPm3Iso14443a, "Read MIFARE classic block"},
|
||||
{"rdsc", CmdHF14AMfRdSc, IfPm3Iso14443a, "Read MIFARE classic sector"},
|
||||
{"dump", CmdHF14AMfDump, IfPm3Iso14443a, "Dump MIFARE classic tag to binary file"},
|
||||
{"restore", CmdHF14AMfRestore, IfPm3Iso14443a, "Restore MIFARE classic binary file to BLANK tag"},
|
||||
{"wrbl", CmdHF14AMfWrBl, IfPm3Iso14443a, "Write MIFARE classic block"},
|
||||
{"setmod", CmdHf14AMfSetMod, IfPm3Iso14443a, "Set MIFARE Classic EV1 load modulation strength"},
|
||||
{"auth4", CmdHF14AMfAuth4, IfPm3Iso14443a, "ISO14443-4 AES authentication"},
|
||||
// {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
|
||||
{"sim", CmdHF14AMfSim, IfPm3Iso14443a, "Simulate MIFARE card"},
|
||||
|
@ -4843,9 +4942,6 @@ static command_t CommandTable[] = {
|
|||
{"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump (magic chinese card)"},
|
||||
{"csave", CmdHF14AMfCSave, IfPm3Iso14443a, "Save dump from magic chinese card into file or emulator"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, ""},
|
||||
{"mad", CmdHF14AMfMAD, IfPm3Iso14443a, "Checks and prints MAD"},
|
||||
{"ndef", CmdHFMFNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
|
||||
|
||||
{"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
@ -4860,4 +4956,3 @@ int CmdHFMF(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,16 +19,6 @@ char *getProtocolStr(uint8_t id);
|
|||
char *getVersionStr(uint8_t major, uint8_t minor);
|
||||
void getKeySettings(uint8_t *aid);
|
||||
|
||||
// Command options for Desfire behavior.
|
||||
enum {
|
||||
NONE = 0x00,
|
||||
INIT = 0x01,
|
||||
DISCONNECT = 0x02,
|
||||
CLEARTRACE = 0x04,
|
||||
BAR = 0x08,
|
||||
} CmdOptions ;
|
||||
|
||||
|
||||
#define CREATE_APPLICATION 0xca
|
||||
#define DELETE_APPLICATION 0xda
|
||||
#define GET_APPLICATION_IDS 0x6a
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// High frequency MIFARE commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdhfmfdesfire.h"
|
||||
#include "cmdhfmfdesfire_disabled.h"
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
|
||||
|
|
|
@ -1390,7 +1390,6 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
|
|||
char progress_text[80];
|
||||
FILE *fnonces = NULL;
|
||||
PacketResponseNG resp;
|
||||
|
||||
num_acquired_nonces = 0;
|
||||
|
||||
clearCommandBuffer();
|
||||
|
@ -1402,24 +1401,35 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
|
|||
flags |= field_off ? 0x0004 : 0;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, key, 6);
|
||||
|
||||
if (field_off) break;
|
||||
if (field_off) {
|
||||
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
|
||||
break;
|
||||
} else {
|
||||
SendCommandMIX(CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, key, 6);
|
||||
}
|
||||
|
||||
if (initialize) {
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
|
||||
uint8_t nullkey[6] = {0};
|
||||
//strange second call (iceman)
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, 4, nullkey, sizeof(nullkey));
|
||||
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
if (resp.oldarg[0]) return resp.oldarg[0]; // error during nested_hard
|
||||
|
||||
// error during nested_hard
|
||||
if (resp.oldarg[0]) {
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
|
||||
return resp.oldarg[0];
|
||||
}
|
||||
|
||||
cuid = resp.oldarg[1];
|
||||
if (nonce_file_write && fnonces == NULL) {
|
||||
if ((fnonces = fopen(filename, "wb")) == NULL) {
|
||||
PrintAndLogEx(WARNING, "Could not create file %s", filename);
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
|
||||
return 3;
|
||||
}
|
||||
snprintf(progress_text, 80, "Writing acquired nonces to binary file %s", filename);
|
||||
|
@ -1486,17 +1496,24 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
|
|||
}
|
||||
|
||||
if (!initialize) {
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) {
|
||||
if (nonce_file_write) {
|
||||
fclose(fnonces);
|
||||
}
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// error during nested_hard
|
||||
if (resp.oldarg[0]) {
|
||||
if (nonce_file_write) {
|
||||
fclose(fnonces);
|
||||
}
|
||||
return resp.oldarg[0]; // error during nested_hard
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_FPGA_MAJOR_MODE_OFF, NULL, 0);
|
||||
return resp.oldarg[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1513,11 +1530,6 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
|
|||
fclose(fnonces);
|
||||
}
|
||||
|
||||
// PrintAndLogEx(NORMAL, "Sampled a total of %d nonces in %d seconds (%0.0f nonces/minute)",
|
||||
// total_num_nonces,
|
||||
// time(NULL)-time1,
|
||||
// (float)total_num_nonces*60.0/(time(NULL)-time1));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1681,11 +1693,12 @@ static bool all_bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_even
|
|||
for (uint8_t remaining_bits = 0; remaining_bits <= (~mask & 0xff); remaining_bits++) {
|
||||
if (remaining_bits_match(num_common, bytes_diff, state, (state & mask) | remaining_bits, odd_even)) {
|
||||
|
||||
#ifdef DEBUG_KEY_ELIMINATION
|
||||
if (bitflips_match(byte2, (state & mask) | remaining_bits, odd_even, true)) {
|
||||
#else
|
||||
if (bitflips_match(byte2, (state & mask) | remaining_bits, odd_even)) {
|
||||
#endif
|
||||
# ifdef DEBUG_KEY_ELIMINATION
|
||||
if (bitflips_match(byte2, (state & mask) | remaining_bits, odd_even, true))
|
||||
# else
|
||||
if (bitflips_match(byte2, (state & mask) | remaining_bits, odd_even))
|
||||
# endif
|
||||
{
|
||||
found_match = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1694,7 +1707,7 @@ static bool all_bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_even
|
|||
|
||||
if (!found_match) {
|
||||
|
||||
#ifdef DEBUG_KEY_ELIMINATION
|
||||
# ifdef DEBUG_KEY_ELIMINATION
|
||||
if (known_target_key != -1 && state == test_state[odd_even]) {
|
||||
PrintAndLogEx(NORMAL, "all_bitflips_match() 1st Byte: %s test state (0x%06x): Eliminated. Bytes = %02x, %02x, Common Bits = %d\n",
|
||||
odd_even == ODD_STATE ? "odd" : "even",
|
||||
|
@ -1706,7 +1719,7 @@ static bool all_bitflips_match(uint8_t byte, uint32_t state, odd_even_t odd_even
|
|||
sprintf(failstr, "Other 1st Byte %s, all_bitflips_match(), no match", odd_even ? "odd" : "even");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
# endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1851,7 +1864,6 @@ static bool TestIfKeyExists(uint64_t key) {
|
|||
|
||||
num_keys_tested += count;
|
||||
hardnested_print_progress(num_acquired_nonces, "(Test: Key NOT found)", 0.0, 0);
|
||||
|
||||
crypto1_destroy(pcs);
|
||||
return false;
|
||||
}
|
||||
|
@ -2019,13 +2031,13 @@ __attribute__((force_align_arg_pointer))
|
|||
|
||||
static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) {
|
||||
|
||||
init_statelist_cache();
|
||||
init_book_of_work();
|
||||
|
||||
// create mutexes for accessing the statelist cache and our "book of work"
|
||||
pthread_mutex_init(&statelist_cache_mutex, NULL);
|
||||
pthread_mutex_init(&book_of_work_mutex, NULL);
|
||||
|
||||
init_statelist_cache();
|
||||
init_book_of_work();
|
||||
|
||||
// create and run worker threads
|
||||
pthread_t thread_id[NUM_REDUCTION_WORKING_THREADS];
|
||||
|
||||
|
@ -2042,9 +2054,6 @@ static void generate_candidates(uint8_t sum_a0_idx, uint8_t sum_a8_idx) {
|
|||
pthread_join(thread_id[i], NULL);
|
||||
}
|
||||
|
||||
// clean up mutex
|
||||
pthread_mutex_destroy(&statelist_cache_mutex);
|
||||
|
||||
maximum_states = 0;
|
||||
for (statelist_t *sl = candidates; sl != NULL; sl = sl->next) {
|
||||
maximum_states += (uint64_t)sl->len[ODD_STATE] * sl->len[EVEN_STATE];
|
||||
|
|
|
@ -39,11 +39,15 @@ static int CmdHFMFPInfo(const char *Cmd) {
|
|||
if (Cmd && strlen(Cmd) > 0)
|
||||
PrintAndLogEx(WARNING, "command don't have any parameters.\n");
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "-- Mifare Plus Tag Information ------------------------------");
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
|
||||
// info about 14a part
|
||||
infoHF14A(false, false, false);
|
||||
|
||||
// Mifare Plus info
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0, NULL, 0);
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0);
|
||||
|
||||
PacketResponseNG resp;
|
||||
WaitForResponse(CMD_ACK, &resp);
|
||||
|
@ -54,61 +58,106 @@ static int CmdHFMFPInfo(const char *Cmd) {
|
|||
uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
|
||||
|
||||
if (select_status == 1 || select_status == 2) {
|
||||
PrintAndLogEx(NORMAL, "----------------------------------------------");
|
||||
PrintAndLogEx(NORMAL, "Mifare Plus info:");
|
||||
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, " Fingerprint");
|
||||
|
||||
// MIFARE Type Identification Procedure
|
||||
// https://www.nxp.com/docs/en/application-note/AN10833.pdf
|
||||
uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8);
|
||||
if (ATQA == 0x0004) PrintAndLogEx(INFO, "ATQA: Mifare Plus 2k 4bUID");
|
||||
if (ATQA == 0x0002) PrintAndLogEx(INFO, "ATQA: Mifare Plus 4k 4bUID");
|
||||
if (ATQA == 0x0044) PrintAndLogEx(INFO, "ATQA: Mifare Plus 2k 7bUID");
|
||||
if (ATQA == 0x0042) PrintAndLogEx(INFO, "ATQA: Mifare Plus 4k 7bUID");
|
||||
bool isPlus = false;
|
||||
|
||||
if (ATQA == 0x0004) {
|
||||
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 2K") " (4b UID)");
|
||||
isPlus = true;
|
||||
}
|
||||
if (ATQA == 0x0002) {
|
||||
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 4K") " (4b UID)");
|
||||
isPlus = true;
|
||||
}
|
||||
if (ATQA == 0x0044) {
|
||||
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 2K") " (7b UID)");
|
||||
isPlus = true;
|
||||
}
|
||||
if (ATQA == 0x0042) {
|
||||
PrintAndLogEx(INFO, " ATQA - " _GREEN_("Mifare Plus 4K") " (7b UID)");
|
||||
isPlus = true;
|
||||
}
|
||||
|
||||
uint8_t SLmode = 0xff;
|
||||
if (card.sak == 0x08) {
|
||||
PrintAndLogEx(INFO, "SAK: Mifare Plus 2k 7bUID");
|
||||
if (select_status == 2) SLmode = 1;
|
||||
if (isPlus) {
|
||||
if (card.sak == 0x08) {
|
||||
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 2K 7b UID"));
|
||||
if (select_status == 2) SLmode = 1;
|
||||
}
|
||||
if (card.sak == 0x18) {
|
||||
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 4K 7b UID"));
|
||||
if (select_status == 2) SLmode = 1;
|
||||
}
|
||||
if (card.sak == 0x10) {
|
||||
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 2K"));
|
||||
if (select_status == 2) SLmode = 2;
|
||||
}
|
||||
if (card.sak == 0x11) {
|
||||
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus 4K"));
|
||||
if (select_status == 2) SLmode = 2;
|
||||
}
|
||||
}
|
||||
if (card.sak == 0x18) {
|
||||
PrintAndLogEx(INFO, "SAK: Mifare Plus 4k 7bUID");
|
||||
if (select_status == 2) SLmode = 1;
|
||||
}
|
||||
if (card.sak == 0x10) {
|
||||
PrintAndLogEx(INFO, "SAK: Mifare Plus 2k");
|
||||
if (select_status == 2) SLmode = 2;
|
||||
}
|
||||
if (card.sak == 0x11) {
|
||||
PrintAndLogEx(INFO, "SAK: Mifare Plus 4k");
|
||||
if (select_status == 2) SLmode = 2;
|
||||
}
|
||||
if (card.sak == 0x20) {
|
||||
PrintAndLogEx(INFO, "SAK: Mifare Plus SL0/SL3 or Mifare desfire");
|
||||
if (card.ats_len > 0) {
|
||||
SLmode = 3;
|
||||
|
||||
if (card.sak == 0x20) {
|
||||
PrintAndLogEx(INFO, " SAK - " _GREEN_("Mifare Plus SL0/SL3") "or " _GREEN_("Mifare DESFire"));
|
||||
|
||||
if (card.ats_len > 0) {
|
||||
|
||||
SLmode = 3;
|
||||
// check SL0
|
||||
uint8_t data[250] = {0};
|
||||
int datalen = 0;
|
||||
// https://github.com/Proxmark/proxmark3/blob/master/client/luascripts/mifarePlus.lua#L161
|
||||
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
|
||||
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen, false);
|
||||
int res = ExchangeRAW14a(cmd, sizeof(cmd), true, false, data, sizeof(data), &datalen, false);
|
||||
|
||||
if (memcmp(data, "\x67\x00", 2) == 0) {
|
||||
PrintAndLogEx(INFO, "\tMost likely a Mifare DESFire tag");
|
||||
PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf mfdes info`"));
|
||||
DropField();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (!res && datalen > 1 && data[0] == 0x09) {
|
||||
SLmode = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SLmode != 0xff)
|
||||
PrintAndLogEx(INFO, "Mifare Plus SL mode: SL%d", SLmode);
|
||||
// How do we detect SL0 / SL1 / SL2 / SL3 modes?!?
|
||||
PrintAndLogEx(INFO, "Security Level (SL)");
|
||||
switch(SLmode) {
|
||||
case 0:
|
||||
PrintAndLogEx(INFO, "SL 0: initial delivery configuration, used for card personalization");
|
||||
break;
|
||||
case 1:
|
||||
PrintAndLogEx(INFO, "SL 1: backwards functional compatibility mode (with MIFARE Classic 1K / 4K) with an optional AES authentication");
|
||||
break;
|
||||
case 2:
|
||||
PrintAndLogEx(INFO, "SL 2: 3-Pass Authentication based on AES followed by MIFARE CRYPTO1 authentication, communication secured by MIFARE CRYPTO1");
|
||||
break;
|
||||
case 3:
|
||||
PrintAndLogEx(INFO, "SL 3: 3-Pass authentication based on AES, data manipulation commands secured by AES encryption and an AES based MACing method.");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (SLmode != 0xFF)
|
||||
PrintAndLogEx(SUCCESS, "\tMifare Plus SL mode: " _YELLOW_("SL%d"), SLmode);
|
||||
else
|
||||
PrintAndLogEx(WARNING, "Mifare Plus SL mode: unknown(");
|
||||
PrintAndLogEx(WARNING, "\tMifare Plus SL mode: " _YELLOW_("unknown"));
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Mifare Plus info not available.");
|
||||
PrintAndLogEx(INFO, "\tMifare Plus info not available.");
|
||||
}
|
||||
|
||||
DropField();
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -916,9 +965,9 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
if (foundKeys[0][sector][0] || foundKeys[1][sector][0]) {
|
||||
if (!printedHeader) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, ".------.--------------------------------.--------------------------------.");
|
||||
PrintAndLogEx(INFO, "-------+--------------------------------+---------------------------------");
|
||||
PrintAndLogEx(INFO, "|sector| key A | key B |");
|
||||
PrintAndLogEx(INFO, "|------|--------------------------------|--------------------------------|");
|
||||
PrintAndLogEx(INFO, "|------+--------------------------------+--------------------------------|");
|
||||
printedHeader = true;
|
||||
}
|
||||
PrintAndLogEx(INFO, "| %02d |%32s|%32s|",
|
||||
|
@ -930,7 +979,7 @@ static int CmdHFMFPChk(const char *Cmd) {
|
|||
if (!printedHeader)
|
||||
PrintAndLogEx(INFO, "No keys found(");
|
||||
else
|
||||
PrintAndLogEx(INFO, "'------'--------------------------------'--------------------------------'\n");
|
||||
PrintAndLogEx(INFO, "'------+--------------------------------+--------------------------------'\n");
|
||||
|
||||
// save keys to json
|
||||
if ((jsonnamelen > 0) && printedHeader) {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -14,15 +14,14 @@
|
|||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
#include "cmdtrace.h"
|
||||
|
||||
#include "cmdhf14a.h"
|
||||
#include "ui.h"
|
||||
#include "crc16.h"
|
||||
#include "protocols.h"
|
||||
#include "mifare/ndef.h"
|
||||
|
||||
#define TOPAZ_STATIC_MEMORY (0x0f * 8) // 15 blocks with 8 Bytes each
|
||||
|
||||
|
@ -35,7 +34,6 @@ typedef struct dynamic_lock_area {
|
|||
uint16_t bytes_locked_per_bit;
|
||||
} dynamic_lock_area_t;
|
||||
|
||||
|
||||
static struct {
|
||||
uint8_t HR01[2];
|
||||
uint8_t uid[7];
|
||||
|
@ -67,7 +65,7 @@ static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint
|
|||
if (resp.oldarg[0] == *response_len) {
|
||||
*response_len = resp.oldarg[0];
|
||||
|
||||
PrintAndLogEx(INFO, "%s", sprint_hex(resp.data.asBytes, *response_len));
|
||||
PrintAndLogEx(DEBUG, "%s", sprint_hex(resp.data.asBytes, *response_len));
|
||||
if (*response_len > 0) {
|
||||
memcpy(response, resp.data.asBytes, *response_len);
|
||||
}
|
||||
|
@ -78,7 +76,6 @@ static int topaz_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// calculate CRC bytes and send topaz command, returns the length of the response (0 in case of error)
|
||||
static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response, uint16_t *response_len, bool verbose) {
|
||||
if (len > 1) {
|
||||
|
@ -91,7 +88,6 @@ static int topaz_send_cmd(uint8_t *cmd, uint8_t len, uint8_t *response, uint16_t
|
|||
return topaz_send_cmd_raw(cmd, len, response, response_len, verbose);
|
||||
}
|
||||
|
||||
|
||||
// select a topaz tag. Send WUPA and RID.
|
||||
static int topaz_select(uint8_t *atqa, uint8_t atqa_len, uint8_t *rid_response, uint8_t rid_len, bool verbose) {
|
||||
// ToDo: implement anticollision
|
||||
|
@ -119,7 +115,6 @@ static int topaz_select(uint8_t *atqa, uint8_t atqa_len, uint8_t *rid_response,
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// read all of the static memory of a selected Topaz tag.
|
||||
static int topaz_rall(uint8_t *uid, uint8_t *response) {
|
||||
uint16_t resp_len = 0;
|
||||
|
@ -134,7 +129,6 @@ static int topaz_rall(uint8_t *uid, uint8_t *response) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// read a block (8 Bytes) of a selected Topaz tag.
|
||||
static int topaz_read_block(uint8_t *uid, uint8_t blockno, uint8_t *block_data) {
|
||||
uint16_t resp_len = 0;
|
||||
|
@ -212,7 +206,6 @@ static bool topaz_byte_is_locked(uint16_t byteno) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// read and print the Capability Container
|
||||
static int topaz_print_CC(uint8_t *data) {
|
||||
if (data[0] != 0xe1) {
|
||||
|
@ -233,7 +226,6 @@ static int topaz_print_CC(uint8_t *data) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// return type, length and value of a TLV, starting at memory position *TLV_ptr
|
||||
static void get_TLV(uint8_t **TLV_ptr, uint8_t *TLV_type, uint16_t *TLV_length, uint8_t **TLV_value) {
|
||||
*TLV_length = 0;
|
||||
|
@ -265,7 +257,6 @@ static void get_TLV(uint8_t **TLV_ptr, uint8_t *TLV_type, uint16_t *TLV_length,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// lock area TLVs contain no information on the start of the respective lockable area. Lockable areas
|
||||
// do not include the lock bits and reserved memory. We therefore need to adjust the start of the
|
||||
// respective lockable areas accordingly
|
||||
|
@ -279,7 +270,6 @@ static void adjust_lock_areas(uint16_t block_start, uint16_t block_size) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// read and print the lock area and reserved memory TLVs
|
||||
static void topaz_print_control_TLVs(uint8_t *memory) {
|
||||
uint8_t *TLV_ptr = memory;
|
||||
|
@ -372,7 +362,6 @@ static int topaz_read_dynamic_data(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// read and print the dynamic memory
|
||||
static void topaz_print_dynamic_data(void) {
|
||||
if (topaz_tag.size > TOPAZ_STATIC_MEMORY) {
|
||||
|
@ -399,79 +388,30 @@ static void topaz_print_lifecycle_state(uint8_t *data) {
|
|||
// to be done
|
||||
}
|
||||
|
||||
static void topaz_print_NDEF(uint8_t *data) {
|
||||
// to be done.
|
||||
static int topaz_print_NDEF(uint8_t *data, size_t maxsize) {
|
||||
return NDEFDecodeAndPrint(data, maxsize, true);
|
||||
}
|
||||
|
||||
// read a Topaz tag and print some useful information
|
||||
static int CmdHFTopazReader(const char *Cmd) {
|
||||
int status;
|
||||
uint8_t atqa[2];
|
||||
uint8_t rid_response[8];
|
||||
uint8_t *uid_echo = &rid_response[2];
|
||||
uint8_t rall_response[124];
|
||||
bool verbose = true;
|
||||
|
||||
bool verbose = true;
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 's') verbose = false;
|
||||
|
||||
status = topaz_select(atqa, sizeof(atqa), rid_response, sizeof(rid_response), verbose);
|
||||
return readTopazUid(verbose);
|
||||
}
|
||||
|
||||
if (status == PM3_ESOFT) {
|
||||
if (verbose) PrintAndLogEx(ERR, "Error: couldn't receive ATQA");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
// read a Topaz tag and print some useful information
|
||||
static int CmdHFTopazInfo(const char *Cmd) {
|
||||
|
||||
if (atqa[1] != 0x0c && atqa[0] != 0x00) {
|
||||
if (verbose) PrintAndLogEx(ERR, "Tag doesn't support the Topaz protocol.");
|
||||
topaz_switch_off_field();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
bool verbose = true;
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 's') verbose = false;
|
||||
|
||||
if (status == PM3_EWRONGANSVER) {
|
||||
if (verbose) PrintAndLogEx(ERR, "Error: tag didn't answer to RID");
|
||||
topaz_switch_off_field();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
int status = readTopazUid(verbose);
|
||||
if (status != PM3_SUCCESS)
|
||||
return status;
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", atqa[1], atqa[0]);
|
||||
|
||||
topaz_tag.HR01[0] = rid_response[0];
|
||||
topaz_tag.HR01[1] = rid_response[1];
|
||||
|
||||
// ToDo: CRC check
|
||||
PrintAndLogEx(SUCCESS, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)",
|
||||
rid_response[0],
|
||||
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
|
||||
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
|
||||
(rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic");
|
||||
|
||||
PrintAndLogEx(SUCCESS, "HR1 : %02x", rid_response[1]);
|
||||
|
||||
status = topaz_rall(uid_echo, rall_response);
|
||||
|
||||
if (status == PM3_ESOFT) {
|
||||
PrintAndLogEx(ERR, "Error: tag didn't answer to RALL");
|
||||
topaz_switch_off_field();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
memcpy(topaz_tag.uid, rall_response + 2, 7);
|
||||
PrintAndLogEx(SUCCESS, "UID : %02x %02x %02x %02x %02x %02x %02x",
|
||||
topaz_tag.uid[6],
|
||||
topaz_tag.uid[5],
|
||||
topaz_tag.uid[4],
|
||||
topaz_tag.uid[3],
|
||||
topaz_tag.uid[2],
|
||||
topaz_tag.uid[1],
|
||||
topaz_tag.uid[0]);
|
||||
|
||||
PrintAndLogEx(SUCCESS, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"),
|
||||
topaz_tag.uid[6],
|
||||
getTagInfo(topaz_tag.uid[6]));
|
||||
|
||||
memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Static Data blocks " _YELLOW_("0x00") "to " _YELLOW_("0x0C")":");
|
||||
PrintAndLogEx(NORMAL, "block# | offset | Data | Locked");
|
||||
|
@ -520,7 +460,7 @@ static int CmdHFTopazReader(const char *Cmd) {
|
|||
|
||||
topaz_print_lifecycle_state(&topaz_tag.data_blocks[1][0]);
|
||||
|
||||
topaz_print_NDEF(&topaz_tag.data_blocks[1][0]);
|
||||
topaz_print_NDEF(&topaz_tag.data_blocks[1][0], TOPAZ_STATIC_MEMORY);
|
||||
|
||||
topaz_switch_off_field();
|
||||
return PM3_SUCCESS;
|
||||
|
@ -548,11 +488,12 @@ static int CmdHelp(const char *Cmd);
|
|||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"},
|
||||
{"info", CmdHFTopazInfo, IfPm3Iso14443a, "Tag information"},
|
||||
{"reader", CmdHFTopazReader, IfPm3Iso14443a, "Act like a Topaz reader"},
|
||||
{"sim", CmdHFTopazSim, IfPm3Iso14443a, "<UID> -- Simulate Topaz tag"},
|
||||
{"sniff", CmdHF14ASniff, IfPm3Iso14443a, "Sniff Topaz reader-tag communication"},
|
||||
{"raw", CmdHFTopazCmdRaw, IfPm3Iso14443a, "Send raw hex data to tag"},
|
||||
{"list", CmdHFTopazList, AlwaysAvailable, "List Topaz history"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
|
@ -567,6 +508,71 @@ int CmdHFTopaz(const char *Cmd) {
|
|||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
int readTopazUid(void) {
|
||||
return CmdHFTopazReader("s");
|
||||
int readTopazUid(bool verbose) {
|
||||
|
||||
uint8_t atqa[2];
|
||||
uint8_t rid_response[8];
|
||||
uint8_t *uid_echo = &rid_response[2];
|
||||
uint8_t rall_response[124];
|
||||
|
||||
int status = topaz_select(atqa, sizeof(atqa), rid_response, sizeof(rid_response), verbose);
|
||||
if (status == PM3_ESOFT) {
|
||||
if (verbose) PrintAndLogEx(ERR, "Error: couldn't receive ATQA");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (atqa[1] != 0x0c && atqa[0] != 0x00) {
|
||||
if (verbose) PrintAndLogEx(ERR, "Tag doesn't support the Topaz protocol.");
|
||||
topaz_switch_off_field();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (status == PM3_EWRONGANSVER) {
|
||||
if (verbose) PrintAndLogEx(ERR, "Error: tag didn't answer to RID");
|
||||
topaz_switch_off_field();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
status = topaz_rall(uid_echo, rall_response);
|
||||
if (status == PM3_ESOFT) {
|
||||
PrintAndLogEx(ERR, "Error: tag didn't answer to RALL");
|
||||
topaz_switch_off_field();
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
memcpy(topaz_tag.uid, rall_response + 2, 7);
|
||||
memcpy(topaz_tag.data_blocks, rall_response + 2, 0x0f * 8);
|
||||
|
||||
// printing
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "UID : %02x %02x %02x %02x %02x %02x %02x",
|
||||
topaz_tag.uid[6],
|
||||
topaz_tag.uid[5],
|
||||
topaz_tag.uid[4],
|
||||
topaz_tag.uid[3],
|
||||
topaz_tag.uid[2],
|
||||
topaz_tag.uid[1],
|
||||
topaz_tag.uid[0]);
|
||||
|
||||
PrintAndLogEx(SUCCESS, " UID[6] (Manufacturer Byte) = " _YELLOW_("%02x")", Manufacturer: " _YELLOW_("%s"),
|
||||
topaz_tag.uid[6],
|
||||
getTagInfo(topaz_tag.uid[6])
|
||||
);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "ATQA : %02x %02x", atqa[1], atqa[0]);
|
||||
|
||||
topaz_tag.HR01[0] = rid_response[0];
|
||||
topaz_tag.HR01[1] = rid_response[1];
|
||||
|
||||
// ToDo: CRC check
|
||||
PrintAndLogEx(SUCCESS, "HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)",
|
||||
rid_response[0],
|
||||
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
|
||||
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
|
||||
(rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic");
|
||||
|
||||
PrintAndLogEx(SUCCESS, "HR1 : %02x", rid_response[1]);
|
||||
|
||||
topaz_switch_off_field();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -15,5 +15,5 @@
|
|||
|
||||
int CmdHFTopaz(const char *Cmd);
|
||||
|
||||
int readTopazUid(void);
|
||||
int readTopazUid(bool verbose);
|
||||
#endif
|
||||
|
|
|
@ -253,34 +253,41 @@ static int CmdLFTune(const char *Cmd) {
|
|||
//Validations
|
||||
if (errors) return usage_lf_tune();
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Measuring LF antenna at %.2f kHz, click button or press Enter to exit", LF_DIV2FREQ(divisor));
|
||||
PrintAndLogEx(INFO, "Measuring LF antenna at " _YELLOW_("%.2f") "kHz, click " _GREEN_("pm3 button") "or press " _GREEN_("Enter") "to exit", LF_DIV2FREQ(divisor));
|
||||
|
||||
uint8_t params[] = {1, 0};
|
||||
params[1] = divisor;
|
||||
PacketResponseNG resp;
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_LF, params, sizeof(params));
|
||||
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000)) {
|
||||
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark LF initialization, aborting");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
params[0] = 2;
|
||||
// loop forever (till button pressed) if iter = 0 (default)
|
||||
for (uint8_t i = 0; iter == 0 || i < iter; i++) {
|
||||
if (kbd_enter_pressed()) { // abort by keyboard press
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
|
||||
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_LF, params, sizeof(params));
|
||||
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark LF measure, aborting");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint32_t)))
|
||||
|
||||
if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint32_t))) {
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t volt = resp.data.asDwords[0];
|
||||
PrintAndLogEx(INPLACE, "%u mV / %5u V", volt, (uint32_t)(volt / 1000));
|
||||
PrintAndLogEx(INPLACE, "%u mV / %3u V", volt, (uint32_t)(volt / 1000));
|
||||
}
|
||||
|
||||
params[0] = 3;
|
||||
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_LF, params, sizeof(params));
|
||||
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000)) {
|
||||
|
@ -288,11 +295,10 @@ static int CmdLFTune(const char *Cmd) {
|
|||
return PM3_ETIMEOUT;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Done.");
|
||||
PrintAndLogEx(INFO, "Done.");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* send a LF command before reading */
|
||||
int CmdLFCommandRead(const char *Cmd) {
|
||||
|
||||
|
@ -451,6 +457,24 @@ int CmdFlexdemod(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int lf_getconfig(sample_config *config) {
|
||||
if (!session.pm3_present) return PM3_ENOTTY;
|
||||
|
||||
if (config == NULL)
|
||||
return PM3_EINVARG;
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
SendCommandNG(CMD_LF_SAMPLING_GET_CONFIG, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_SAMPLING_GET_CONFIG, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
memcpy(config, resp.data.asBytes, sizeof(sample_config));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int lf_config(sample_config *config) {
|
||||
if (!session.pm3_present) return PM3_ENOTTY;
|
||||
|
||||
|
@ -458,7 +482,7 @@ int lf_config(sample_config *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);
|
||||
SendCommandNG(CMD_LF_SAMPLING_PRINT_CONFIG, NULL, 0);
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1165,7 +1189,7 @@ static bool CheckChipType(bool getDeviceData) {
|
|||
uint32_t word = 0;
|
||||
if (EM4x05IsBlock0(&word)) {
|
||||
PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("EM4x05/EM4x69"));
|
||||
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf em 4x05`") "commands");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05`") "commands");
|
||||
retval = true;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1173,7 +1197,7 @@ static bool CheckChipType(bool getDeviceData) {
|
|||
//check for t55xx chip...
|
||||
if (tryDetectP1(true)) {
|
||||
PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("T55xx"));
|
||||
PrintAndLogEx(INFO, "Hint: try " _YELLOW_("`lf t55xx`") "commands");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf t55xx`") "commands");
|
||||
retval = true;
|
||||
}
|
||||
|
||||
|
@ -1327,16 +1351,16 @@ static command_t CommandTable[] = {
|
|||
{"fdx", CmdLFFdx, AlwaysAvailable, "{ FDX-B RFIDs... }"},
|
||||
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
|
||||
{"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"},
|
||||
{"hid", CmdLFHID, AlwaysAvailable, "{ HID RFIDs... }"},
|
||||
{"hid", CmdLFHID, AlwaysAvailable, "{ HID Prox RFIDs... }"},
|
||||
{"hitag", CmdLFHitag, AlwaysAvailable, "{ Hitag CHIPs... }"},
|
||||
{"indala", CmdLFINDALA, AlwaysAvailable, "{ Indala RFIDs... }"},
|
||||
{"io", CmdLFIO, AlwaysAvailable, "{ ioProx RFIDs... }"},
|
||||
{"jablotron", CmdLFJablotron, AlwaysAvailable, "{ Jablotron RFIDs... }"},
|
||||
{"keri", CmdLFKeri, AlwaysAvailable, "{ KERI RFIDs... }"},
|
||||
{"motorola", CmdLFMotorola, AlwaysAvailable, "{ Motorola RFIDs... }"},
|
||||
{"nedap", CmdLFNedap, AlwaysAvailable, "{ Nedap RFIDs... }"},
|
||||
{"nexwatch", CmdLFNEXWATCH, AlwaysAvailable, "{ NexWatch RFIDs... }"},
|
||||
{"noralsy", CmdLFNoralsy, AlwaysAvailable, "{ Noralsy RFIDs... }"},
|
||||
{"motorola", CmdLFMotorola, AlwaysAvailable, "{ Motorola RFIDs... }"},
|
||||
{"pac", CmdLFPac, AlwaysAvailable, "{ PAC/Stanley RFIDs... }"},
|
||||
{"paradox", CmdLFParadox, AlwaysAvailable, "{ Paradox RFIDs... }"},
|
||||
{"pcf7931", CmdLFPCF7931, AlwaysAvailable, "{ PCF7931 CHIPs... }"},
|
||||
|
|
|
@ -34,5 +34,6 @@ int CmdLFfind(const char *Cmd);
|
|||
|
||||
int lf_read(bool verbose, uint32_t samples);
|
||||
int lf_config(sample_config *config);
|
||||
int lf_getconfig(sample_config *config);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -422,7 +422,10 @@ static int CmdAWIDClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone AWID %u to T55x7 with FC: %u, CN: %u", fmtlen, fc, cn);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf awid read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdAWIDBrute(const char *Cmd) {
|
||||
|
|
|
@ -700,6 +700,8 @@ static int CmdEM410xWrite(const char *Cmd) {
|
|||
}
|
||||
|
||||
SendCommandMIX(CMD_LF_EM410X_WRITE, card, (uint32_t)(id >> 32), (uint32_t)id, NULL, 0);
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 410x_read`") "to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1037,6 +1039,9 @@ static int CmdEM4x50Write(const char *Cmd) {
|
|||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_lf_em4x50_write();
|
||||
PrintAndLogEx(NORMAL, "no implemented yet");
|
||||
//
|
||||
// PrintAndLogEx(SUCCESS, "Done");
|
||||
// PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x50_read`") "to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1344,7 +1349,7 @@ static int CmdEM4x05Dump(const char *Cmd) {
|
|||
// saveFileEML will add .eml extension to filename
|
||||
// saveFile (binary) passes in the .bin extension.
|
||||
if (strcmp(preferredName, "") == 0) // Set default filename, if not set by user
|
||||
sprintf(preferredName, "lf-4x05-%08X-data", BSWAP_32(data[1]));
|
||||
sprintf(preferredName, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
|
||||
|
||||
saveFileEML(preferredName, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
|
||||
saveFile(preferredName, ".bin", data, sizeof(data));
|
||||
|
@ -1434,9 +1439,10 @@ static int CmdEM4x05Write(const char *Cmd) {
|
|||
uint32_t dummy = 0;
|
||||
int status = demodEM4x05resp(&dummy);
|
||||
if (status == PM3_SUCCESS)
|
||||
PrintAndLogEx(NORMAL, "Write " _GREEN_("Verified"));
|
||||
else
|
||||
PrintAndLogEx(NORMAL, "Write could " _RED_("not") "be verified");
|
||||
PrintAndLogEx(SUCCESS, "Success writing to tag");
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05_read`") "to verify");
|
||||
return status;
|
||||
}
|
||||
static int CmdEM4x05Wipe(const char *Cmd) {
|
||||
|
|
|
@ -301,7 +301,10 @@ static int CmdFdxClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone FDX-B to T55x7 with animal ID: %04u-%"PRIu64, countryid, animalid);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdx read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdFdxSim(const char *Cmd) {
|
||||
|
|
|
@ -178,7 +178,10 @@ static int CmdGallagherClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Gallagher to T55x7 with raw hex");
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gallagher read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdGallagherSim(const char *Cmd) {
|
||||
|
|
|
@ -187,7 +187,10 @@ static int CmdGuardClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Guardall to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf gprox read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdGuardSim(const char *Cmd) {
|
||||
|
|
|
@ -50,7 +50,7 @@ static int usage_lf_hid_watch(void) {
|
|||
PrintAndLogEx(NORMAL, "Usage: lf hid watch");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf hid watch");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid watch"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_hid_sim(void) {
|
||||
|
@ -62,11 +62,11 @@ static int usage_lf_hid_sim(void) {
|
|||
PrintAndLogEx(NORMAL, " h - This help");
|
||||
PrintAndLogEx(NORMAL, " ID - HID id");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf hid sim 2006ec0c86");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid sim 2006ec0c86"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_hid_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "Clone HID to T55x7. Tag must be on antenna. ");
|
||||
PrintAndLogEx(NORMAL, "Clone HID to T55x7. " _BLUE_("Tag must be on antenna!"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf hid clone [h] [l] ID");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
|
@ -74,8 +74,8 @@ static int usage_lf_hid_clone(void) {
|
|||
PrintAndLogEx(NORMAL, " l - 84bit ID");
|
||||
PrintAndLogEx(NORMAL, " ID - HID id");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf hid clone 2006ec0c86");
|
||||
PrintAndLogEx(NORMAL, " lf hid clone l 2006ec0c86");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid clone 2006ec0c86"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid clone l 2006ec0c86"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_hid_brute(void) {
|
||||
|
@ -83,21 +83,23 @@ static int usage_lf_hid_brute(void) {
|
|||
PrintAndLogEx(NORMAL, "This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step");
|
||||
PrintAndLogEx(NORMAL, "if cardnumber is not given, it starts with 1 and goes up to 65535");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w <format> [<field> (decimal)>] {...}");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w <format> [<field> (decimal)>] [up|down] {...}");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " w <format> : see `wiegand list` for available formats");
|
||||
PrintAndLogEx(NORMAL, " w <format> : see " _YELLOW_("`wiegand list`") "for available formats");
|
||||
PrintAndLogEx(NORMAL, " f <facility-code> : facility code");
|
||||
PrintAndLogEx(NORMAL, " c <cardnumber> : card number to start with");
|
||||
PrintAndLogEx(NORMAL, " i <issuelevel> : issue level");
|
||||
PrintAndLogEx(NORMAL, " o <oem> : OEM code");
|
||||
PrintAndLogEx(NORMAL, " d <delay> : delay betweens attempts in ms. Default 1000ms");
|
||||
PrintAndLogEx(NORMAL, " v : verbose logging, show all tries");
|
||||
PrintAndLogEx(NORMAL, " up : direction to increment card number. (default is both directions)");
|
||||
PrintAndLogEx(NORMAL, " down : direction to decrement card number. (default is both directions)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 224");
|
||||
PrintAndLogEx(NORMAL, " lf hid brute w H10301 f 21 d 2000");
|
||||
PrintAndLogEx(NORMAL, " lf hid brute v w H10301 f 21 c 200 d 2000");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute w H10301 f 224"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute w H10301 f 21 d 2000"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute v w H10301 f 21 c 200 d 2000"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -160,7 +162,7 @@ static int CmdHIDDemod(const char *Cmd) {
|
|||
uint8_t bits[GraphTraceLen];
|
||||
size_t size = getFromGraphBuf(bits);
|
||||
if (size == 0) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - HID not enough samples");
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID not enough samples"));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
//get binary from fsk wave
|
||||
|
@ -169,17 +171,17 @@ static int CmdHIDDemod(const char *Cmd) {
|
|||
if (idx < 0) {
|
||||
|
||||
if (idx == -1)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - HID not enough samples");
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID not enough samples"));
|
||||
else if (idx == -2)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - HID just noise detected");
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID just noise detected"));
|
||||
else if (idx == -3)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - HID problem during FSK demod");
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID problem during FSK demod"));
|
||||
else if (idx == -4)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - HID preamble not found");
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID preamble not found"));
|
||||
else if (idx == -5)
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - HID error in Manchester data, size %zu", size);
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID error in Manchester data, size %zu"), size);
|
||||
else
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - HID error demoding fsk %d", idx);
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID error demoding fsk %d"), idx);
|
||||
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
@ -188,12 +190,12 @@ static int CmdHIDDemod(const char *Cmd) {
|
|||
setClockGrid(50, waveIdx + (idx * 50));
|
||||
|
||||
if (hi2 == 0 && hi == 0 && lo == 0) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - HID no values found");
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - " _RED_("HID no values found"));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (hi2 != 0) { //extra large HID tags
|
||||
PrintAndLogEx(SUCCESS, "HID Prox TAG ID: %x%08x%08x (%u)", hi2, hi, lo, (lo >> 1) & 0xFFFF);
|
||||
PrintAndLogEx(SUCCESS, "HID Prox TAG ID: " _GREEN_("%x%08x%08x (%u)"), hi2, hi, lo, (lo >> 1) & 0xFFFF);
|
||||
} else { //standard HID tags <38 bits
|
||||
uint8_t fmtLen = 0;
|
||||
uint32_t cc = 0;
|
||||
|
@ -239,14 +241,14 @@ static int CmdHIDDemod(const char *Cmd) {
|
|||
fc = ((hi & 0xF) << 12) | (lo >> 20);
|
||||
}
|
||||
if (fmtLen == 32 && (lo & 0x40000000)) { //if 32 bit and Kastle bit set
|
||||
PrintAndLogEx(SUCCESS, "HID Prox TAG (Kastle format) ID: %x%08x (%u) - Format Len: 32bit - CC: %u - FC: %u - Card: %u", hi, lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum);
|
||||
PrintAndLogEx(SUCCESS, "HID Prox TAG (Kastle format) ID: " _GREEN_("%x%08x (%u)")"- Format Len: 32bit - CC: %u - FC: %u - Card: %u", hi, lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "HID Prox TAG ID: %x%08x (%u) - Format Len: %ubit - OEM: %03u - FC: %u - Card: %u",
|
||||
PrintAndLogEx(SUCCESS, "HID Prox TAG ID: " _GREEN_("%x%08x (%u)")"- Format Len: " _GREEN_("%u bit")"- OEM: %03u - FC: " _GREEN_("%u")"- Card: " _GREEN_("%u"),
|
||||
hi, lo, cardnum, fmtLen, oem, fc, cardnum);
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer:", idx, size);
|
||||
PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer: ", idx, size);
|
||||
if (g_debugMode)
|
||||
printDemodBuff();
|
||||
|
||||
|
@ -266,6 +268,8 @@ static int CmdHIDWatch(const char *Cmd) {
|
|||
if (ctmp == 'h') return usage_lf_hid_watch();
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_HID_DEMOD, NULL, 0);
|
||||
PrintAndLogEx(SUCCESS, "Watching for new HID cards - place tag on antenna");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to stop reading new cards");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -286,18 +290,18 @@ static int CmdHIDSim(const char *Cmd) {
|
|||
lo = (lo << 4) | (n & 0xf);
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Simulating HID tag with long ID %x%08x%08x", hi2, hi, lo);
|
||||
PrintAndLogEx(INFO, "Simulating HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
|
||||
payload.longFMT = 1;
|
||||
} else {
|
||||
while (sscanf(&Cmd[i++], "%1x", &n) == 1) {
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (n & 0xf);
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Simulating HID tag with ID %x%08x", hi, lo);
|
||||
PrintAndLogEx(SUCCESS, "Simulating HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
|
||||
hi2 = 0;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Press pm3-button to abort simulation");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
|
||||
|
||||
payload.hi2 = hi2;
|
||||
payload.hi = hi;
|
||||
|
@ -329,7 +333,7 @@ static int CmdHIDClone(const char *Cmd) {
|
|||
lo = (lo << 4) | (n & 0xf);
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID %x%08x%08x", hi2, hi, lo);
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
|
||||
|
||||
longid[0] = 1;
|
||||
} else {
|
||||
|
@ -337,13 +341,14 @@ static int CmdHIDClone(const char *Cmd) {
|
|||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (n & 0xf);
|
||||
}
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag with ID %x%08x", hi, lo);
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
|
||||
hi2 = 0;
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid));
|
||||
PrintAndLogEx(INFO, "Clone command sent. Try "_YELLOW_("'lf hid read'") " to verify");
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf hid read`") "to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -365,14 +370,31 @@ static int CmdHIDClone(const char *Cmd) {
|
|||
static int CmdHIDBrute(const char *Cmd) {
|
||||
|
||||
bool errors = false, verbose = false;
|
||||
uint32_t delay = 1000;
|
||||
uint32_t delay = 1000;
|
||||
uint8_t cmdp = 0;
|
||||
int format_idx = -1;
|
||||
int direction = 0;
|
||||
char format[16] = {0};
|
||||
wiegand_card_t data;
|
||||
memset(&data, 0, sizeof(wiegand_card_t));
|
||||
|
||||
wiegand_card_t cn_hi, cn_low;
|
||||
memset(&cn_hi, 0, sizeof(wiegand_card_t));
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
|
||||
char s[10] = {0};
|
||||
if (param_getstr(Cmd, cmdp, s, sizeof(s)) > 0) {
|
||||
if (strlen(s) > 1) {
|
||||
str_lower((char *)s);
|
||||
if (str_startswith(s, "up")) {
|
||||
direction = 1;
|
||||
} else if (str_startswith(s, "do")) {
|
||||
direction = 2;
|
||||
}
|
||||
cmdp++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_hid_brute();
|
||||
|
@ -380,13 +402,13 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
param_getstr(Cmd, cmdp + 1, format, sizeof(format));
|
||||
format_idx = HIDFindCardFormat(format);
|
||||
if (format_idx == -1) {
|
||||
PrintAndLogEx(WARNING, "Unknown format: %s", format);
|
||||
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
|
||||
errors = true;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'c':
|
||||
data.CardNumber = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cn_hi.CardNumber = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'd':
|
||||
|
@ -395,15 +417,15 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
cmdp += 2;
|
||||
break;
|
||||
case 'f':
|
||||
data.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cn_hi.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'i':
|
||||
data.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cn_hi.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'o':
|
||||
data.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cn_hi.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'v':
|
||||
|
@ -411,18 +433,51 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
PrintAndLogEx(WARNING, "Unknown parameter: " _YELLOW_("'%c'"), param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (format_idx == -1) {
|
||||
PrintAndLogEx(ERR, "You must select a wiegand format. See " _YELLOW_("`wiegand list`") "for available formats\n");
|
||||
errors = true;
|
||||
}
|
||||
|
||||
if (errors) return usage_lf_hid_brute();
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "Wiegand format#.. %i", format_idx);
|
||||
PrintAndLogEx(INFO, "OEM#............. %u", cn_hi.OEM);
|
||||
PrintAndLogEx(INFO, "ISSUE#........... %u", cn_hi.IssueLevel);
|
||||
PrintAndLogEx(INFO, "Facility#........ %u", cn_hi.FacilityCode);
|
||||
PrintAndLogEx(INFO, "Card#............ %" PRIu64, cn_hi.CardNumber);
|
||||
switch (direction) {
|
||||
case 0:
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("BOTH"));
|
||||
break;
|
||||
case 1:
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("UP"));
|
||||
break;
|
||||
case 2:
|
||||
PrintAndLogEx(INFO, "Brute-forcing direction: " _YELLOW_("DOWN"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(INFO, "Brute-forcing HID reader");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation or run another command");
|
||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation or press `enter` to exit");
|
||||
|
||||
// copy values to low.
|
||||
cn_low = cn_hi;
|
||||
|
||||
// main loop
|
||||
for (;;) {
|
||||
// iceman: could add options for bruteforcing OEM, ISSUE or FC aswell..
|
||||
bool exitloop = false;
|
||||
bool fin_hi, fin_low;
|
||||
fin_hi = fin_low = false;
|
||||
do {
|
||||
|
||||
if (!session.pm3_present) {
|
||||
PrintAndLogEx(WARNING, "Device offline\n");
|
||||
|
@ -434,18 +489,45 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
return sendPing();
|
||||
}
|
||||
|
||||
// Do one up
|
||||
if (data.CardNumber < 0xFFFF) {
|
||||
data.CardNumber++;
|
||||
if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
|
||||
// do one up
|
||||
if (direction != 2) {
|
||||
if (cn_hi.CardNumber < 0xFFFF) {
|
||||
cn_hi.CardNumber++;
|
||||
if (sendTry(format_idx, &cn_hi, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
|
||||
} else {
|
||||
fin_hi = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Do one down (if cardnumber is given)
|
||||
if (data.CardNumber > 1) {
|
||||
data.CardNumber--;
|
||||
if (sendTry(format_idx, &data, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
|
||||
// do one down
|
||||
if (direction != 1) {
|
||||
if (cn_low.CardNumber > 0) {
|
||||
cn_low.CardNumber--;
|
||||
if (sendTry(format_idx, &cn_low, delay, verbose) != PM3_SUCCESS) return PM3_ESOFT;
|
||||
} else {
|
||||
fin_low = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (direction) {
|
||||
case 0:
|
||||
if (fin_hi && fin_low) {
|
||||
exitloop = true;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
exitloop = fin_hi;
|
||||
break;
|
||||
case 2:
|
||||
exitloop = fin_low;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
} while (exitloop == false);
|
||||
|
||||
PrintAndLogEx(INFO, "Brute forcing finished");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
#include "protocols.h" // t55 defines
|
||||
#include "cmdlft55xx.h" // verifywrite
|
||||
|
||||
#define INDALA_ARR_LEN 64
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
//large 224 bit indala formats (different preamble too...)
|
||||
|
@ -140,7 +142,7 @@ static void decodeHeden2L(uint8_t *bits) {
|
|||
if (bits[offset + 7]) cardnumber += 16384;
|
||||
if (bits[offset + 23]) cardnumber += 32768;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "\tHeden-2L | %u", cardnumber);
|
||||
PrintAndLogEx(SUCCESS, "\tHeden-2L | " _YELLOW_("%u"), cardnumber);
|
||||
}
|
||||
|
||||
// Indala 26 bit decode
|
||||
|
@ -192,7 +194,7 @@ static int CmdIndalaDemod(const char *Cmd) {
|
|||
if (DemodBufferLen == 64) {
|
||||
PrintAndLogEx(
|
||||
SUCCESS
|
||||
, "Indala Found - bitlength %zu, Raw %x%08x"
|
||||
, "Indala Found - bitlength %zu, Raw " _YELLOW_("%x%08x")
|
||||
, DemodBufferLen
|
||||
, uid1
|
||||
, uid2
|
||||
|
@ -244,14 +246,18 @@ static int CmdIndalaDemod(const char *Cmd) {
|
|||
checksum |= DemodBuffer[63] << 0; // b1
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Fmt 26 bit FC " _YELLOW_("%u") ", CN " _YELLOW_("%u") ", checksum " _YELLOW_("%1d%1d")
|
||||
, fc
|
||||
, csn
|
||||
, checksum >> 1 & 0x01
|
||||
, checksum & 0x01
|
||||
);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Possible de-scramble patterns");
|
||||
PrintAndLogEx(SUCCESS, "\tPrinted | __%04d__ [0x%X]", p1, p1);
|
||||
PrintAndLogEx(SUCCESS, "\tInternal ID | %" PRIu64, foo);
|
||||
decodeHeden2L(DemodBuffer);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Fmt 26 bit FC %u , CSN %u , checksum %1d%1d", fc, csn, checksum >> 1 & 0x01, checksum & 0x01);
|
||||
|
||||
|
||||
} else {
|
||||
uint32_t uid3 = bytebits_to_byte(DemodBuffer + 64, 32);
|
||||
uint32_t uid4 = bytebits_to_byte(DemodBuffer + 96, 32);
|
||||
|
@ -499,6 +505,7 @@ static int CmdIndalaSim(const char *Cmd) {
|
|||
uint8_t hexuid[100];
|
||||
int len = 0;
|
||||
param_gethex_ex(Cmd, 0, hexuid, &len);
|
||||
|
||||
if (len > 28)
|
||||
return usage_lf_indala_sim();
|
||||
|
||||
|
@ -542,49 +549,62 @@ static int CmdIndalaSim(const char *Cmd) {
|
|||
|
||||
static int CmdIndalaClone(const char *Cmd) {
|
||||
|
||||
bool is_long_uid = false, got_cn = false;
|
||||
bool is_long_uid = false, got_cn = false, got_26 = false;
|
||||
bool is_t5555 = false;
|
||||
int32_t cardnumber;
|
||||
uint32_t blocks[8] = {0};
|
||||
uint8_t max = 0;
|
||||
uint8_t data[7 * 4];
|
||||
int datalen = 0;
|
||||
uint8_t fc = 0;
|
||||
uint16_t cn = 0;
|
||||
|
||||
CLIParserInit("lf indala clone",
|
||||
"clone INDALA tag to T55x7 (or to q5/T5555)",
|
||||
"Examples:\n"
|
||||
"\tlf indala clone -c 888\n"
|
||||
"\tlf indala clone --heden 888\n"
|
||||
"\tlf indala clone --fc 123 --cn 1337\n"
|
||||
"\tlf indala clone -r a0000000a0002021\n"
|
||||
"\tlf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("lL", "long", "optional - long UID 224 bits"),
|
||||
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_lit0("lL", "long", "optional - long UID 224 bits"),
|
||||
arg_int0("cC", "heden", "<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_int0("", "fc", "<decimal>", "Facility Code (26 bit format)"),
|
||||
arg_int0("", "cn", "<decimal>", "Cardnumber (26 bit format)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(Cmd, argtable, false);
|
||||
|
||||
is_long_uid = arg_get_lit(1);
|
||||
if (is_long_uid == false) {
|
||||
cardnumber = arg_get_int_def(2, -1);
|
||||
got_cn = (cardnumber != -1);
|
||||
}
|
||||
|
||||
if (got_cn == false) {
|
||||
CLIGetHexWithReturn(3, data, &datalen);
|
||||
}
|
||||
// raw param
|
||||
CLIGetHexWithReturn(3, data, &datalen);
|
||||
|
||||
is_t5555 = arg_get_lit(4);
|
||||
|
||||
if (is_long_uid == false) {
|
||||
|
||||
// Heden param
|
||||
cardnumber = arg_get_int_def(2, -1);
|
||||
got_cn = (cardnumber != -1);
|
||||
|
||||
// 26b FC/CN param
|
||||
fc = arg_get_int_def(5, 0);
|
||||
cn = arg_get_int_def(6, 0);
|
||||
got_26 = (fc != 0 && cn != 0);
|
||||
}
|
||||
|
||||
CLIParserFree();
|
||||
|
||||
if (is_long_uid) {
|
||||
// 224 BIT UID
|
||||
// config for Indala (RF/32;PSK2 with RF/2;Maxblock=7)
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag with RawID %s", sprint_hex(data, datalen));
|
||||
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag");
|
||||
PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen));
|
||||
|
||||
if (is_t5555)
|
||||
blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT);
|
||||
|
@ -602,12 +622,41 @@ static int CmdIndalaClone(const char *Cmd) {
|
|||
} else {
|
||||
// 64 BIT UID
|
||||
if (got_cn) {
|
||||
PrintAndLogEx(INFO, "Using Indala HEDEN cardnumber %u", cardnumber);
|
||||
encodeHeden2L(data, cardnumber);
|
||||
datalen = 8;
|
||||
} else if (got_26) {
|
||||
|
||||
PrintAndLogEx(INFO, "Using Indala 26b FC %u CN %u", fc, cn);
|
||||
|
||||
// Used with the 26bit FC/CSN
|
||||
uint8_t *bits = calloc(INDALA_ARR_LEN, sizeof(uint8_t));
|
||||
if (bits == NULL) {
|
||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
if (getIndalaBits(fc, cn, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
data[0] = bytebits_to_byte(bits, 8);
|
||||
data[1] = bytebits_to_byte(bits + 8, 8);
|
||||
data[2] = bytebits_to_byte(bits + 16, 8);
|
||||
data[3] = bytebits_to_byte(bits + 24, 8);
|
||||
data[4] = bytebits_to_byte(bits + 32, 8);
|
||||
data[5] = bytebits_to_byte(bits + 40, 8);
|
||||
data[6] = bytebits_to_byte(bits + 48, 8);
|
||||
data[7] = bytebits_to_byte(bits + 56, 8);
|
||||
datalen = 8;
|
||||
|
||||
free(bits);
|
||||
}
|
||||
|
||||
// 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");
|
||||
PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen));
|
||||
|
||||
if (is_t5555)
|
||||
blocks[0] = T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT);
|
||||
|
@ -620,7 +669,10 @@ static int CmdIndalaClone(const char *Cmd) {
|
|||
}
|
||||
|
||||
print_blocks(blocks, max);
|
||||
return clone_t55xx_tag(blocks, max);
|
||||
int res = clone_t55xx_tag(blocks, max);
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf indala read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
@ -644,6 +696,71 @@ int CmdLFINDALA(const char *Cmd) {
|
|||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
int getIndalaBits(uint8_t fc, uint16_t cn, uint8_t *bits) {
|
||||
// preamble
|
||||
// is there a preamble?
|
||||
bits[0] = 1;
|
||||
bits[2] = 1;
|
||||
bits[32] = 1;
|
||||
|
||||
// add fc
|
||||
bits[57] = ((fc >> 7) & 1); // b8
|
||||
bits[49] = ((fc >> 6) & 1); // b7
|
||||
bits[44] = ((fc >> 5) & 1); // b6
|
||||
bits[47] = ((fc >> 4) & 1); // b5
|
||||
bits[48] = ((fc >> 3) & 1); // b4
|
||||
bits[53] = ((fc >> 2) & 1); // b3
|
||||
bits[39] = ((fc >> 1) & 1); // b2
|
||||
bits[58] = (fc & 1); // b1
|
||||
|
||||
// add cn
|
||||
bits[42] = ((cn >> 15) & 1); // b16
|
||||
bits[45] = ((cn >> 14) & 1); // b15 - c
|
||||
bits[43] = ((cn >> 13) & 1); // b14
|
||||
bits[40] = ((cn >> 12) & 1); // b13 - c
|
||||
bits[52] = ((cn >> 11) & 1); // b12
|
||||
bits[36] = ((cn >> 10) & 1); // b11
|
||||
bits[35] = ((cn >> 9) & 1); // b10 - c
|
||||
bits[51] = ((cn >> 8) & 1); // b9 - c
|
||||
bits[46] = ((cn >> 7) & 1); // b8
|
||||
bits[33] = ((cn >> 6) & 1); // b7 - c
|
||||
bits[37] = ((cn >> 5) & 1); // b6 - c
|
||||
bits[54] = ((cn >> 4) & 1); // b5
|
||||
bits[56] = ((cn >> 3) & 1); // b4
|
||||
bits[59] = ((cn >> 2) & 1); // b3 - c
|
||||
bits[50] = ((cn >> 1) & 1); // b2
|
||||
bits[41] = (cn & 1); // b1 - c
|
||||
|
||||
// checksum
|
||||
uint8_t chk = 0;
|
||||
//sum(y2, y4, y7, y8, y10, y11, y14, y16
|
||||
chk += ((cn >> 14) & 1); //y2 == 75 - 30 = 45
|
||||
chk += ((cn >> 12) & 1); //y4 == 70 - 30 = 40
|
||||
chk += ((cn >> 9) & 1); //y7 == 65 - 30 = 35
|
||||
chk += ((cn >> 8) & 1); //y8 == 81 - 30 = 51
|
||||
chk += ((cn >> 6) & 1); //y10 == 63 - 30 = 33
|
||||
chk += ((cn >> 5) & 1); //y11 == 67 - 30 = 37
|
||||
chk += ((cn >> 2) & 1); //y14 == 89 - 30 = 59
|
||||
chk += (cn & 1); //y16 == 71 - 30 = 41
|
||||
|
||||
if ((chk & 1) == 0) {
|
||||
bits[62] = 0;
|
||||
bits[63] = 1;
|
||||
} else {
|
||||
bits[62] = 1;
|
||||
bits[63] = 0;
|
||||
}
|
||||
|
||||
// add parity
|
||||
bits[34] = 1; // p1 64 - 30 = 34
|
||||
bits[38] = 1; // p2 68 - 30 = 38
|
||||
|
||||
// 92 = 62
|
||||
// 93 = 63
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// redesigned by marshmellow adjusted from existing decode functions
|
||||
// indala id decoding
|
||||
int detectIndala(uint8_t *dest, size_t *size, uint8_t *invert) {
|
||||
|
|
|
@ -19,5 +19,6 @@ int detectIndala26(uint8_t *bitStream, size_t *size, uint8_t *invert);
|
|||
int detectIndala64(uint8_t *bitStream, size_t *size, uint8_t *invert);
|
||||
int detectIndala224(uint8_t *bitStream, size_t *size, uint8_t *invert);
|
||||
int demodIndala(void);
|
||||
int getIndalaBits(uint8_t fc, uint16_t cn, uint8_t *bits);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -275,7 +275,10 @@ static int CmdIOProxClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone IOProx to T55x7 with Version: %u FC: %u, CN: %u", version, fc, cn);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf io read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
|
|
@ -30,13 +30,21 @@ static int CmdHelp(const char *Cmd);
|
|||
static int usage_lf_keri_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "clone a KERI tag to a T55x7 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf keri clone [h] <id> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Usage extended: lf keri clone [h] t <m|i> [f <fc>] c <cardid> [Q5]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <id> : Keri Internal ID");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : specify write to Q5 (t5555 instead of t55x7)");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <id> : Keri Internal ID");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : specify write to Q5 (t5555 instead of t55x7)");
|
||||
// New format
|
||||
PrintAndLogEx(NORMAL, " <t> [m|i] : Type. m - MS, i - Internal ID");
|
||||
PrintAndLogEx(NORMAL, " <f> <fc> : Facility Code");
|
||||
PrintAndLogEx(NORMAL, " <c> <cn> : Card Number");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf keri clone 112233");
|
||||
PrintAndLogEx(NORMAL, " lf keri clone type ms fc 6 cn 12345");
|
||||
PrintAndLogEx(NORMAL, " lf keri clone t m f 6 c 12345");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -54,6 +62,79 @@ static int usage_lf_keri_sim(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
typedef enum {Scramble = 0,Descramble = 1} KeriMSScramble_t;
|
||||
|
||||
static int CmdKeriMSScramble (KeriMSScramble_t Action, uint32_t *FC, uint32_t *ID, uint32_t *CardID)
|
||||
{
|
||||
// 255 = Not used/Unknown other values are the bit offset in the ID/FC values
|
||||
uint8_t CardToID [] = { 255,255,255,255, 13, 12, 20, 5, 16, 6, 21, 17, 8,255, 0, 7,
|
||||
10, 15,255, 11, 4, 1,255, 18,255, 19, 2, 14, 3, 9,255,255 };
|
||||
|
||||
uint8_t CardToFC [] = { 255,255,255,255,255,255,255,255,255,255,255,255,255, 0,255,255,
|
||||
255,255, 2,255,255,255, 3,255, 4,255,255,255,255,255, 1,255 };
|
||||
|
||||
uint8_t CardIdx; // 0 - 31
|
||||
bool BitState;
|
||||
|
||||
if (Action == Descramble) {
|
||||
*FC = 0;
|
||||
*ID = 0;
|
||||
for (CardIdx = 0; CardIdx < 32; CardIdx++) {
|
||||
// Get Bit State
|
||||
BitState = (*CardID >> CardIdx) & 1;
|
||||
// Card ID
|
||||
if (CardToID[CardIdx] < 32) {
|
||||
*ID = *ID | (BitState << CardToID[CardIdx]);
|
||||
}
|
||||
// Card FC
|
||||
if (CardToFC[CardIdx] < 32) {
|
||||
*FC = *FC | (BitState << CardToFC[CardIdx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Action == Scramble)
|
||||
{
|
||||
*CardID = 0; // set to 0
|
||||
|
||||
for (CardIdx = 0; CardIdx < 32; CardIdx++)
|
||||
{
|
||||
// Card ID
|
||||
if (CardToID[CardIdx] < 32) {
|
||||
if ((*ID & (1 << CardToID[CardIdx])) > 0)
|
||||
*CardID |= (1 << CardIdx);
|
||||
}
|
||||
// Card FC
|
||||
if (CardToFC[CardIdx] < 32) {
|
||||
if ((*FC & (1 << CardToFC[CardIdx])) > 0)
|
||||
*CardID |= (1 << CardIdx);
|
||||
}
|
||||
}
|
||||
|
||||
// Fixed bits and parity/check bits
|
||||
/*
|
||||
Add Parity and Fixed bits
|
||||
Bit 3 - Note Used/Fixed 1 - TBC
|
||||
Bit 31 - 1 Fixed Not in check/parity
|
||||
Bit 0,1 - 2 Bit Parity
|
||||
*/
|
||||
*CardID |= (1 << 3);
|
||||
|
||||
// Check/Parity Bits
|
||||
int Parity = 1;
|
||||
for (CardIdx = 4; CardIdx <= 31; CardIdx += 2) {
|
||||
Parity = Parity ^ ((*CardID >> CardIdx) & 11);
|
||||
}
|
||||
*CardID = *CardID | Parity;
|
||||
|
||||
// Bit 31 was fixed but not in check/parity bits
|
||||
*CardID |= 1UL << 31;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Scrambled MS : FC %d - CN %d to RAW : E0000000%08X",*FC,*ID,*CardID);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdKeriDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
|
||||
|
@ -84,7 +165,10 @@ static int CmdKeriDemod(const char *Cmd) {
|
|||
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
|
||||
|
||||
//get internal id
|
||||
uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32);
|
||||
// uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32);
|
||||
// Due to the 3 sync bits being at the start of the capture
|
||||
// We can take the last 32bits as the internal ID.
|
||||
uint32_t ID = raw2;
|
||||
ID &= 0x7FFFFFFF;
|
||||
|
||||
/*
|
||||
|
@ -103,6 +187,16 @@ static int CmdKeriDemod(const char *Cmd) {
|
|||
|
||||
PrintAndLogEx(SUCCESS, "KERI Tag Found -- Internal ID: %u", ID);
|
||||
PrintAndLogEx(SUCCESS, "Raw: %08X%08X", raw1, raw2);
|
||||
/*
|
||||
Descramble Data.
|
||||
*/
|
||||
uint32_t fc = 0;
|
||||
uint32_t cardid = 0;
|
||||
|
||||
// Just need to the low 32 bits without the 111 trailer
|
||||
CmdKeriMSScramble (Descramble,&fc,&cardid,&raw2);
|
||||
|
||||
PrintAndLogEx (SUCCESS,"Descrambled MS : FC %d - CN %d\n",fc,cardid);
|
||||
|
||||
if (invert) {
|
||||
PrintAndLogEx(INFO, "Had to Invert - probably KERI");
|
||||
|
@ -121,6 +215,10 @@ static int CmdKeriRead(const char *Cmd) {
|
|||
|
||||
static int CmdKeriClone(const char *Cmd) {
|
||||
|
||||
uint8_t cmdidx = 0;
|
||||
char keritype = 'i'; // default to internalid
|
||||
uint32_t fc = 0;
|
||||
uint32_t cid = 0;
|
||||
uint32_t internalid = 0;
|
||||
uint32_t blocks[3] = {
|
||||
T55x7_TESTMODE_DISABLED |
|
||||
|
@ -138,8 +236,44 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_keri_clone();
|
||||
|
||||
internalid = param_get32ex(Cmd, 0, 0, 10);
|
||||
// Assume old format for backwards compatibility and only parameter is the internal id
|
||||
cid = param_get32ex(Cmd, 0, 0, 10);
|
||||
|
||||
// find other options
|
||||
while (param_getchar(Cmd, cmdidx) != 0x00) { // && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdidx))) {
|
||||
case 'h': // help
|
||||
return usage_lf_keri_clone();
|
||||
case 't': // format type
|
||||
keritype = tolower(param_getchar(Cmd,cmdidx+1));
|
||||
cmdidx += 2;
|
||||
break;
|
||||
case 'f': // fc
|
||||
fc = param_get32ex(Cmd,cmdidx+1,0,10);
|
||||
cmdidx += 2;
|
||||
break;
|
||||
case 'c': // cardid
|
||||
cid = param_get32ex(Cmd,cmdidx+1,0,10);
|
||||
cmdidx += 2;
|
||||
break;
|
||||
case 'q': // q5
|
||||
blocks[0] =
|
||||
T5555_MODULATION_PSK1 |
|
||||
T5555_SET_BITRATE(128) |
|
||||
T5555_PSK_RF_2 |
|
||||
2 << T5555_MAXBLOCK_SHIFT;
|
||||
cmdidx++;
|
||||
break;
|
||||
default:
|
||||
// Skip unknown
|
||||
cmdidx++;
|
||||
}
|
||||
}
|
||||
|
||||
// this is managed in above code
|
||||
// internalid = param_get32ex(Cmd, 0, 0, 10);
|
||||
/*
|
||||
// Q5 is caught in the while loop
|
||||
//Q5
|
||||
if (tolower(param_getchar(Cmd, 1)) == 'q') {
|
||||
blocks[0] =
|
||||
|
@ -148,10 +282,19 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
T5555_PSK_RF_2 |
|
||||
2 << T5555_MAXBLOCK_SHIFT;
|
||||
}
|
||||
|
||||
// MSB is ONE
|
||||
internalid |= 0x80000000;
|
||||
|
||||
*/
|
||||
// Setup card data/build internal id
|
||||
switch (keritype) {
|
||||
case 'i' : // Internal ID
|
||||
// MSB is ONE
|
||||
internalid = cid | 0x80000000;
|
||||
break;
|
||||
case 'm' : // MS
|
||||
CmdKeriMSScramble (Scramble,&fc,&cid,&internalid);
|
||||
break;
|
||||
}
|
||||
|
||||
// Prepare and write to card
|
||||
// 3 LSB is ONE
|
||||
uint64_t data = ((uint64_t)internalid << 3) + 7;
|
||||
PrintAndLogEx(INFO, "Preparing to clone KERI to T55x7 with Internal Id: %" PRIx32, internalid);
|
||||
|
@ -161,7 +304,10 @@ static int CmdKeriClone(const char *Cmd) {
|
|||
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf keri read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdKeriSim(const char *Cmd) {
|
||||
|
|
|
@ -177,7 +177,10 @@ static int CmdMotorolaClone(const char *Cmd) {
|
|||
blocks[2] = bytes_to_num(data + 4, 4);
|
||||
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf motorola read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdMotorolaSim(const char *Cmd) {
|
||||
|
|
|
@ -475,6 +475,8 @@ static int CmdLFNedapClone(const char *Cmd) {
|
|||
} else {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nedap read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -158,8 +158,10 @@ static int CmdNexWatchClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone NexWatch to T55x7 with raw hex");
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf nexwatch read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdNexWatchSim(const char *Cmd) {
|
||||
|
|
|
@ -169,7 +169,10 @@ static int CmdNoralsyClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Noralsy to T55x7 with CardId: %u", id);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf noralsy read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdNoralsySim(const char *Cmd) {
|
||||
|
|
|
@ -239,7 +239,10 @@ static int CmdPacClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone PAC/Stanley tag to T55x7 with raw hex");
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pac read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdPacSim(const char *Cmd) {
|
||||
|
|
|
@ -36,7 +36,7 @@ static int usage_lf_paradox_clone(void) {
|
|||
PrintAndLogEx(NORMAL, " b <raw hex> : raw hex data. 12 bytes max");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf paradox clone 0f55555695596a6a9999a59a");
|
||||
PrintAndLogEx(NORMAL, " lf paradox clone b 0f55555695596a6a9999a59a");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,10 @@ static int CmdParadoxClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Paradox to T55x7 with raw hex");
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf paradox read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdParadoxSim(const char *Cmd) {
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "cmdlfpcf7931.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h"
|
||||
|
@ -36,7 +37,7 @@ int pcf7931_resetConfig() {
|
|||
configPcf.InitDelay = PCF7931_DEFAULT_INITDELAY;
|
||||
configPcf.OffsetWidth = PCF7931_DEFAULT_OFFSET_WIDTH;
|
||||
configPcf.OffsetPosition = PCF7931_DEFAULT_OFFSET_POSITION;
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int pcf7931_printConfig() {
|
||||
|
@ -44,7 +45,7 @@ int pcf7931_printConfig() {
|
|||
PrintAndLogEx(NORMAL, "Tag initialization delay : %d us", configPcf.InitDelay);
|
||||
PrintAndLogEx(NORMAL, "Offset low pulses width : %d us", configPcf.OffsetWidth);
|
||||
PrintAndLogEx(NORMAL, "Offset low pulses position : %d us", configPcf.OffsetPosition);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_pcf7931_read() {
|
||||
|
@ -54,7 +55,7 @@ static int usage_pcf7931_read() {
|
|||
PrintAndLogEx(NORMAL, " h This help");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 read");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_pcf7931_write() {
|
||||
|
@ -67,7 +68,7 @@ static int usage_pcf7931_write() {
|
|||
PrintAndLogEx(NORMAL, " data one byte of data (hex)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 write 2 1 FF");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_pcf7931_config() {
|
||||
|
@ -87,30 +88,30 @@ static int usage_pcf7931_config() {
|
|||
PrintAndLogEx(NORMAL, " lf pcf7931 config r");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 config 11223344556677 20000");
|
||||
PrintAndLogEx(NORMAL, " lf pcf7931 config 11223344556677 17500 -10 30");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFPCF7931Read(const char *Cmd) {
|
||||
|
||||
uint8_t ctmp = param_getchar(Cmd, 0);
|
||||
if (ctmp == 'H' || ctmp == 'h') return usage_pcf7931_read();
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_pcf7931_read();
|
||||
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_PCF7931_READ, NULL, 0);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return 1;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFPCF7931Config(const char *Cmd) {
|
||||
|
||||
uint8_t ctmp = param_getchar(Cmd, 0);
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 0) return pcf7931_printConfig();
|
||||
if (ctmp == 'H' || ctmp == 'h') return usage_pcf7931_config();
|
||||
if (ctmp == 'R' || ctmp == 'r') return pcf7931_resetConfig();
|
||||
if (ctmp == 'h') return usage_pcf7931_config();
|
||||
if (ctmp == 'r') return pcf7931_resetConfig();
|
||||
|
||||
if (param_gethex(Cmd, 0, configPcf.Pwd, 14)) return usage_pcf7931_config();
|
||||
|
||||
|
@ -119,13 +120,13 @@ static int CmdLFPCF7931Config(const char *Cmd) {
|
|||
configPcf.OffsetPosition = (int)(param_get32ex(Cmd, 3, 0, 10) & 0xFFFF);
|
||||
|
||||
pcf7931_printConfig();
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFPCF7931Write(const char *Cmd) {
|
||||
|
||||
uint8_t ctmp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd) < 1 || ctmp == 'h' || ctmp == 'H') return usage_pcf7931_write();
|
||||
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || ctmp == 'h') return usage_pcf7931_write();
|
||||
|
||||
uint8_t block = 0, bytepos = 0, data = 0;
|
||||
|
||||
|
@ -136,9 +137,9 @@ static int CmdLFPCF7931Write(const char *Cmd) {
|
|||
|
||||
data = param_get8ex(Cmd, 2, 0, 16);
|
||||
|
||||
PrintAndLogEx(NORMAL, "Writing block: %d", block);
|
||||
PrintAndLogEx(NORMAL, " pos: %d", bytepos);
|
||||
PrintAndLogEx(NORMAL, " data: 0x%02X", data);
|
||||
PrintAndLogEx(INFO, "Writing block: %d", block);
|
||||
PrintAndLogEx(INFO, " pos: %d", bytepos);
|
||||
PrintAndLogEx(INFO, " data: 0x%02X", data);
|
||||
|
||||
uint32_t buf[10]; // TODO sparse struct, 7 *bytes* then words at offset 4*7!
|
||||
memcpy(buf, configPcf.Pwd, sizeof(configPcf.Pwd));
|
||||
|
@ -147,9 +148,11 @@ static int CmdLFPCF7931Write(const char *Cmd) {
|
|||
buf[9] = configPcf.InitDelay;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_LF_PCF7931_WRITE, block, bytepos, data, buf, sizeof(buf));
|
||||
//no ack?
|
||||
return 0;
|
||||
SendCommandMIX(CMD_LF_PCF7931_WRITE, block, bytepos, data, buf, sizeof(buf));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pcf7931 read`") "to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
@ -163,7 +166,7 @@ static command_t CommandTable[] = {
|
|||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdLFPCF7931(const char *Cmd) {
|
||||
|
|
|
@ -136,7 +136,10 @@ static int CmdPrescoClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Presco to T55x7 with SiteCode: %u, UserCode: %u, FullCode: %08x", sitecode, usercode, fullcode);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf presco read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
// takes base 12 ID converts to hex
|
||||
|
|
|
@ -250,7 +250,10 @@ static int CmdPyramidClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Farpointe/Pyramid to T55x7 with Facility Code: %u, Card Number: %u", facilitycode, cardnumber);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf pyramid read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdPyramidSim(const char *Cmd) {
|
||||
|
|
|
@ -168,7 +168,10 @@ static int CmdSecurakeyClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Securakey to T55x7 with raw hex");
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf securakey read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdSecurakeySim(const char *Cmd) {
|
||||
|
|
|
@ -202,7 +202,7 @@ static int usage_t55xx_restore() {
|
|||
PrintAndLogEx(NORMAL, _YELLOW_(" Assumes lf t55 detect has been run first!"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf t55xx restore f lf-t55xx-00148040-data.bin");
|
||||
PrintAndLogEx(NORMAL, " lf t55xx restore f lf-t55xx-00148040-dump.bin");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -482,12 +482,16 @@ static bool t55xxProtect(bool lock, bool usepwd, uint8_t override, uint32_t pass
|
|||
|
||||
int res = T55xxReadBlockEx(T55x7_CONFIGURATION_BLOCK, T55x7_PAGE0, usepwd, override, password, downlink_mode, false);
|
||||
if (res != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Failed to read block0, use `p` password parameter?");
|
||||
PrintAndLogEx(WARNING, "Failed to read block0, use " _YELLOW_("`p`") "password parameter?");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GetT55xxBlockData(&block0) == false)
|
||||
if (GetT55xxBlockData(&block0) == false) {
|
||||
PrintAndLogEx(DEBUG, "ERROR decoded block0 == %08x", block0);
|
||||
return false;
|
||||
}
|
||||
PrintAndLogEx(DEBUG, "OK read block0 == %08x", block0);
|
||||
|
||||
|
||||
bool isPwdBitAlreadySet = (block0 >> (32 - 28) & 1);
|
||||
if (isPwdBitAlreadySet) {
|
||||
|
@ -1028,7 +1032,6 @@ void T55xx_Print_DownlinkMode(uint8_t downlink_mode) {
|
|||
PrintAndLogEx(NORMAL, msg);
|
||||
}
|
||||
|
||||
|
||||
static int CmdT55xxDetect(const char *Cmd) {
|
||||
|
||||
bool errors = false;
|
||||
|
@ -2316,7 +2319,7 @@ static int CmdT55xxDump(const char *Cmd) {
|
|||
else
|
||||
break;
|
||||
}
|
||||
strcat(preferredName, "-data");
|
||||
strcat(preferredName, "-dump");
|
||||
}
|
||||
|
||||
// Swap endian so the files match the txt display
|
||||
|
@ -3680,7 +3683,7 @@ static int CmdT55xxProtect(const char *Cmd) {
|
|||
|
||||
// lock
|
||||
if (t55xxProtect(true, usepwd, override, password, downlink_mode, new_password) == false) {
|
||||
PrintAndLogEx(WARNING, "Command failed. Did you run `lf t55xx detect` before?");
|
||||
PrintAndLogEx(WARNING, "Command failed. Did you run " _YELLOW_("`lf t55xx detect`") "before?");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
|
|
|
@ -296,6 +296,8 @@ static int CmdTIWrite(const char *Cmd) {
|
|||
}
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_LF_TI_WRITE, arg0, arg1, arg2, NULL, 0);
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf ti read`") "to verify");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,10 @@ static int CmdVerichipClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Verichip to T55x7 with raw hex");
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf verichip read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdVerichipSim(const char *Cmd) {
|
||||
|
|
|
@ -117,6 +117,8 @@ static int CmdVikingClone(const char *Cmd) {
|
|||
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf viking read`") "to verify");
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,10 @@ static int CmdVisa2kClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to T55x7 with CardId: %"PRIu64, id);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
return clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 read`") "to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdVisa2kSim(const char *Cmd) {
|
||||
|
|
112
client/cmdmain.c
112
client/cmdmain.c
|
@ -36,9 +36,23 @@
|
|||
#include "cmdwiegand.h" // wiegand commands
|
||||
#include "ui.h"
|
||||
#include "util_posix.h"
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_hints(void) {
|
||||
PrintAndLogEx(NORMAL, "Turn on/off hints");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: hints [h] <0|1>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
PrintAndLogEx(NORMAL, " <0|1> off or on");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hints 1");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_msleep(void) {
|
||||
PrintAndLogEx(NORMAL, "Sleep for given amount of milliseconds");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -78,6 +92,70 @@ static void AppendDate(char *s, size_t slen, char *fmt) {
|
|||
strftime(s, slen, fmt, ct);
|
||||
}
|
||||
|
||||
static int lf_search_plus(const char *Cmd) {
|
||||
|
||||
sample_config oldconfig;
|
||||
memset(&oldconfig, 0, sizeof(sample_config));
|
||||
|
||||
int retval = lf_getconfig(&oldconfig);
|
||||
|
||||
if (retval != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "failed to get current device config");
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Divisor : frequency(khz)
|
||||
// 95 88 47 31 23
|
||||
// 125.00 134.83 250.00 375.00 500.00
|
||||
|
||||
int16_t default_divisor[] = {95, 88, 47, 31, 23};
|
||||
|
||||
/*
|
||||
default LF config is set to:
|
||||
decimation = 1
|
||||
bits_per_sample = 8
|
||||
averaging = YES
|
||||
divisor = 95 (125kHz)
|
||||
trigger_threshold = 0
|
||||
samples_to_skip = 0
|
||||
verbose = YES
|
||||
*/
|
||||
sample_config config = {
|
||||
.decimation = 1,
|
||||
.bits_per_sample = 8,
|
||||
.averaging = 1,
|
||||
.trigger_threshold = 0,
|
||||
.samples_to_skip = 0,
|
||||
.verbose = false
|
||||
};
|
||||
|
||||
// Iteration defaults
|
||||
for (int i = 0; i < ARRAYLEN(default_divisor); ++i) {
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
PrintAndLogEx(INFO, "Keyboard pressed. Done.");
|
||||
break;
|
||||
}
|
||||
// Try to change config!
|
||||
uint32_t d;
|
||||
d = config.divisor = default_divisor[i];
|
||||
PrintAndLogEx(INFO, "--> trying ( " _GREEN_("%d.%02d kHz")")", 12000 / (d + 1), ((1200000 + (d + 1) / 2) / (d + 1)) - ((12000 / (d + 1)) * 100));
|
||||
|
||||
retval = lf_config(&config);
|
||||
if (retval != PM3_SUCCESS)
|
||||
break;
|
||||
|
||||
// The config for pm3 is changed, we can trying search!
|
||||
retval = CmdLFfind(Cmd);
|
||||
if (retval == PM3_SUCCESS)
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
lf_config(&oldconfig);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int CmdAuto(const char *Cmd) {
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_auto();
|
||||
|
@ -90,8 +168,12 @@ static int CmdAuto(const char *Cmd) {
|
|||
if (ret == PM3_SUCCESS)
|
||||
return ret;
|
||||
|
||||
ret = lf_search_plus("");
|
||||
if (ret == PM3_SUCCESS)
|
||||
return ret;
|
||||
|
||||
PrintAndLogEx(INFO, "Failed both LF / HF SEARCH,");
|
||||
PrintAndLogEx(INFO, "Trying 'lf read' and save a trace for you...");
|
||||
PrintAndLogEx(INFO, "Trying " _YELLOW_("`lf read`") "and save a trace for you");
|
||||
|
||||
CmdPlot("");
|
||||
lf_read(false, 40000);
|
||||
|
@ -109,6 +191,33 @@ int CmdRem(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHints(const char *Cmd) {
|
||||
uint32_t ms = 0;
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_hints();
|
||||
|
||||
if (strlen(Cmd) > 1){
|
||||
str_lower((char *)Cmd);
|
||||
if (str_startswith(Cmd, "of")) {
|
||||
session.show_hints = false;
|
||||
} else {
|
||||
session.show_hints = true;
|
||||
}
|
||||
} else if (strlen(Cmd) == 1) {
|
||||
if (param_getchar(Cmd, 0) != 0x00) {
|
||||
ms = param_get32ex(Cmd, 0, 0, 10);
|
||||
if (ms == 0) {
|
||||
session.show_hints = false;
|
||||
} else {
|
||||
session.show_hints = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Hints are %s", (session.show_hints) ? "ON" : "OFF");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdMsleep(const char *Cmd) {
|
||||
uint32_t ms = 0;
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
|
@ -149,6 +258,7 @@ static command_t CommandTable[] = {
|
|||
{"usart", CmdUsart, IfPm3FpcUsartFromUsb, "{ USART commands... }"},
|
||||
{"wiegand", CmdWiegand, AlwaysAvailable, "{ Wiegand format manipulation... }"},
|
||||
{"", CmdHelp, AlwaysAvailable, ""},
|
||||
{"hints", CmdHints, AlwaysAvailable, "Turn hints on / off"},
|
||||
{"msleep", CmdMsleep, AlwaysAvailable, "Add a pause in milliseconds"},
|
||||
{"rem", CmdRem, AlwaysAvailable, "Add a text line in log file"},
|
||||
{"quit", CmdQuit, AlwaysAvailable, ""},
|
||||
|
|
|
@ -59,11 +59,13 @@ static int CmdScriptRun(const char *Cmd) {
|
|||
if ((!str_endswith(preferredName, ".cmd")) && (searchFile(&script_path, LUA_SCRIPTS_SUBDIR, preferredName, ".lua", true) == PM3_SUCCESS)) {
|
||||
int error;
|
||||
if (luascriptfile_idx == MAX_NESTED_LUASCRIPT) {
|
||||
PrintAndLogEx(ERR, "Too many nested scripts, skipping %s\n", script_path);
|
||||
PrintAndLogEx(ERR, "too many nested scripts, skipping %s\n", script_path);
|
||||
free(script_path);
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Executing Lua script: %s, args '%s'\n", script_path, arguments);
|
||||
PrintAndLogEx(SUCCESS, "executing lua " _YELLOW_("%s"), script_path);
|
||||
PrintAndLogEx(SUCCESS, "args " _YELLOW_("'%s'"), arguments);
|
||||
|
||||
luascriptfile_idx++;
|
||||
|
||||
// create new Lua state
|
||||
|
@ -94,7 +96,7 @@ static int CmdScriptRun(const char *Cmd) {
|
|||
if (error) { // if non-0, then an error
|
||||
// the top of the stack should be the error string
|
||||
if (!lua_isstring(lua_state, lua_gettop(lua_state)))
|
||||
PrintAndLogEx(FAILED, "Error - but no error (?!)");
|
||||
PrintAndLogEx(FAILED, "error - but no error (?!)");
|
||||
|
||||
// get the top of the stack as the error and pop it off
|
||||
const char *str = lua_tostring(lua_state, lua_gettop(lua_state));
|
||||
|
@ -106,17 +108,22 @@ static int CmdScriptRun(const char *Cmd) {
|
|||
// close the Lua state
|
||||
lua_close(lua_state);
|
||||
luascriptfile_idx--;
|
||||
PrintAndLogEx(SUCCESS, "\nFinished %s\n", preferredName);
|
||||
PrintAndLogEx(SUCCESS, "\nfinished " _YELLOW_("%s"), preferredName);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if ((!str_endswith(preferredName, ".lua")) && (searchFile(&script_path, CMD_SCRIPTS_SUBDIR, preferredName, ".cmd", true) == PM3_SUCCESS)) {
|
||||
PrintAndLogEx(SUCCESS, "Executing Cmd script: %s, args '%s'\n", script_path, arguments);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "executing Cmd " _YELLOW_("%s"), script_path);
|
||||
PrintAndLogEx(SUCCESS, "args " _YELLOW_("'%s'"), arguments);
|
||||
|
||||
int ret = push_cmdscriptfile(script_path, true);
|
||||
if (ret != PM3_SUCCESS)
|
||||
PrintAndLogEx(ERR, "could not open " _YELLOW_("%s") "...", script_path);
|
||||
free(script_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// file not found, let's search again to display the error messages
|
||||
int ret = PM3_EUNDEF;
|
||||
if (!str_endswith(preferredName, ".cmd")) ret = searchFile(&script_path, LUA_SCRIPTS_SUBDIR, preferredName, ".lua", false);
|
||||
|
@ -141,7 +148,7 @@ static command_t CommandTable[] = {
|
|||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
PrintAndLogEx(NORMAL, "This is a feature to run Lua-scripts. You can place Lua-scripts within the luascripts/-folder. ");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -216,23 +216,23 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
bool protocol_T15_present = false;
|
||||
|
||||
if (T0 & 0x10) {
|
||||
PrintAndLogEx(NORMAL, "\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]);
|
||||
PrintAndLogEx(INFO, "\t- TA1 (Maximum clock frequency, proposed bit duration) [ 0x%02x ]", atr[2 + T1len]);
|
||||
T1len++;
|
||||
}
|
||||
|
||||
if (T0 & 0x20) {
|
||||
PrintAndLogEx(NORMAL, "\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]);
|
||||
PrintAndLogEx(INFO, "\t- TB1 (Deprecated: VPP requirements) [ 0x%02x ]", atr[2 + T1len]);
|
||||
T1len++;
|
||||
}
|
||||
|
||||
if (T0 & 0x40) {
|
||||
PrintAndLogEx(NORMAL, "\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]);
|
||||
PrintAndLogEx(INFO, "\t- TC1 (Extra delay between bytes required by card) [ 0x%02x ]", atr[2 + T1len]);
|
||||
T1len++;
|
||||
}
|
||||
|
||||
if (T0 & 0x80) {
|
||||
uint8_t TD1 = atr[2 + T1len];
|
||||
PrintAndLogEx(NORMAL, "\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f);
|
||||
PrintAndLogEx(INFO, "\t- TD1 (First offered transmission protocol, presence of TA2..TD2) [ 0x%02x ] Protocol T%d", TD1, TD1 & 0x0f);
|
||||
protocol_T0_present = false;
|
||||
if ((TD1 & 0x0f) == 0) {
|
||||
protocol_T0_present = true;
|
||||
|
@ -244,20 +244,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
T1len++;
|
||||
|
||||
if (TD1 & 0x10) {
|
||||
PrintAndLogEx(NORMAL, "\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
PrintAndLogEx(INFO, "\t- TA2 (Specific protocol and parameters to be used after the ATR) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
TD1len++;
|
||||
}
|
||||
if (TD1 & 0x20) {
|
||||
PrintAndLogEx(NORMAL, "\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
PrintAndLogEx(INFO, "\t- TB2 (Deprecated: VPP precise voltage requirement) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
TD1len++;
|
||||
}
|
||||
if (TD1 & 0x40) {
|
||||
PrintAndLogEx(NORMAL, "\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
PrintAndLogEx(INFO, "\t- TC2 (Maximum waiting time for protocol T=0) [ 0x%02x ]", atr[2 + T1len + TD1len]);
|
||||
TD1len++;
|
||||
}
|
||||
if (TD1 & 0x80) {
|
||||
uint8_t TDi = atr[2 + T1len + TD1len];
|
||||
PrintAndLogEx(NORMAL, "\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f);
|
||||
PrintAndLogEx(INFO, "\t- TD2 (A supported protocol or more global parameters, presence of TA3..TD3) [ 0x%02x ] Protocol T%d", TDi, TDi & 0x0f);
|
||||
if ((TDi & 0x0f) == 0) {
|
||||
protocol_T0_present = true;
|
||||
}
|
||||
|
@ -271,20 +271,20 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
while (nextCycle) {
|
||||
nextCycle = false;
|
||||
if (TDi & 0x10) {
|
||||
PrintAndLogEx(NORMAL, "\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLogEx(INFO, "\t- TA%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
TDilen++;
|
||||
}
|
||||
if (TDi & 0x20) {
|
||||
PrintAndLogEx(NORMAL, "\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLogEx(INFO, "\t- TB%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
TDilen++;
|
||||
}
|
||||
if (TDi & 0x40) {
|
||||
PrintAndLogEx(NORMAL, "\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLogEx(INFO, "\t- TC%d: 0x%02x", vi, atr[2 + T1len + TD1len + TDilen]);
|
||||
TDilen++;
|
||||
}
|
||||
if (TDi & 0x80) {
|
||||
TDi = atr[2 + T1len + TD1len + TDilen];
|
||||
PrintAndLogEx(NORMAL, "\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f);
|
||||
PrintAndLogEx(INFO, "\t- TD%d [ 0x%02x ] Protocol T%d", vi, TDi, TDi & 0x0f);
|
||||
TDilen++;
|
||||
|
||||
nextCycle = true;
|
||||
|
@ -314,7 +314,7 @@ static int PrintATR(uint8_t *atr, size_t atrlen) {
|
|||
PrintAndLogEx(WARNING, "Invalid ATR length. len: %zu, T1len: %d, TD1len: %d, TDilen: %d, K: %d", atrlen, T1len, TD1len, TDilen, K);
|
||||
|
||||
if (K > 0)
|
||||
PrintAndLogEx(INFO, "\nHistorical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]);
|
||||
PrintAndLogEx(INFO, "Historical bytes | len 0x%02d | format %02x", K, atr[2 + T1len + TD1len + TDilen]);
|
||||
|
||||
if (K > 1) {
|
||||
PrintAndLogEx(INFO, "\tHistorical bytes");
|
||||
|
@ -361,7 +361,9 @@ static int smart_responseEx(uint8_t *data, bool silent) {
|
|||
|
||||
if (needGetData) {
|
||||
int len = data[datalen - 1];
|
||||
|
||||
if (!silent) PrintAndLogEx(INFO, "Requesting 0x%02X bytes response", len);
|
||||
|
||||
uint8_t getstatus[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, len};
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_SMART_RAW, SC_RAW, sizeof(getstatus), 0, getstatus, sizeof(getstatus));
|
||||
|
@ -740,10 +742,9 @@ static int CmdSmartInfo(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "--- Smartcard Information ---------");
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, "ISO7618-3 ATR : %s", sprint_hex(card.atr, card.atr_len));
|
||||
PrintAndLogEx(INFO, "\nhttp://smartcard-atr.apdu.fr/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len));
|
||||
PrintAndLogEx(INFO, "http://smartcard-atr.apdu.fr/parse?ATR=%s", sprint_hex_inrow(card.atr, card.atr_len));
|
||||
|
||||
// print ATR
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "ATR");
|
||||
PrintATR(card.atr, card.atr_len);
|
||||
|
||||
|
@ -756,14 +757,14 @@ static int CmdSmartInfo(const char *Cmd) {
|
|||
if (GetATRTA1(card.atr, card.atr_len) == 0x11)
|
||||
PrintAndLogEx(INFO, "Using default values...");
|
||||
|
||||
PrintAndLogEx(NORMAL, "\t- Di %d", Di);
|
||||
PrintAndLogEx(NORMAL, "\t- Fi %d", Fi);
|
||||
PrintAndLogEx(NORMAL, "\t- F %.1f MHz", F);
|
||||
PrintAndLogEx(INFO, "\t- Di %d", Di);
|
||||
PrintAndLogEx(INFO, "\t- Fi %d", Fi);
|
||||
PrintAndLogEx(INFO, "\t- F %.1f MHz", F);
|
||||
|
||||
if (Di && Fi) {
|
||||
PrintAndLogEx(NORMAL, "\t- Cycles/ETU %d", Fi / Di);
|
||||
PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at 4 MHz", (float)4000000 / (Fi / Di));
|
||||
PrintAndLogEx(NORMAL, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi / Di), F);
|
||||
PrintAndLogEx(INFO, "\t- Cycles/ETU %d", Fi / Di);
|
||||
PrintAndLogEx(INFO, "\t- %.1f bits/sec at 4 MHz", (float)4000000 / (Fi / Di));
|
||||
PrintAndLogEx(INFO, "\t- %.1f bits/sec at Fmax (%.1fMHz)", (F * 1000000) / (Fi / Di), F);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "\t- Di or Fi is RFU.");
|
||||
};
|
||||
|
@ -1156,11 +1157,12 @@ int CmdSmartcard(const char *Cmd) {
|
|||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
||||
int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
|
||||
*dataoutlen = 0;
|
||||
|
||||
if (activateCard)
|
||||
smart_select(false, NULL);
|
||||
smart_select(true, NULL);
|
||||
|
||||
PrintAndLogEx(DEBUG, "APDU SC");
|
||||
|
||||
|
@ -1168,10 +1170,11 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
|
|||
if (activateCard) {
|
||||
flags |= SC_SELECT | SC_CONNECT;
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_SMART_RAW, flags, datainlen, 0, datain, datainlen);
|
||||
|
||||
int len = smart_responseEx(dataout, true);
|
||||
int len = smart_responseEx(dataout, silent);
|
||||
|
||||
if (len < 0) {
|
||||
return 1;
|
||||
|
@ -1189,7 +1192,7 @@ int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leave
|
|||
// something fishy: we have only 5 bytes but we put datainlen in arg1?
|
||||
SendCommandOLD(CMD_SMART_RAW, SC_RAW_T0, datainlen, 0, data, sizeof(data));
|
||||
|
||||
len = smart_responseEx(dataout, true);
|
||||
len = smart_responseEx(dataout, silent);
|
||||
}
|
||||
|
||||
*dataoutlen = len;
|
||||
|
@ -1204,6 +1207,7 @@ bool smart_select(bool silent, smart_card_atr_t *atr) {
|
|||
SendCommandNG(CMD_SMART_ATR, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||
|
||||
if (!silent) PrintAndLogEx(WARNING, "smart card select failed");
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,6 @@
|
|||
int CmdSmartcard(const char *Cmd);
|
||||
|
||||
bool smart_select(bool silent, smart_card_atr_t *atr);
|
||||
int ExchangeAPDUSC(uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
int ExchangeAPDUSC(bool silent, uint8_t *datain, int datainlen, bool activateCard, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -671,7 +671,13 @@ void CloseProxmark(void) {
|
|||
|
||||
// Clean up our state
|
||||
sp = NULL;
|
||||
#ifdef __BIONIC__
|
||||
if (communication_thread != 0) {
|
||||
memset(&communication_thread, 0, sizeof(pthread_t));
|
||||
}
|
||||
#else
|
||||
memset(&communication_thread, 0, sizeof(pthread_t));
|
||||
#endif
|
||||
|
||||
session.pm3_present = false;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
#
|
||||
ffffffffffff # Defaultkey(firstkeyusedbyprogramifnouserdefinedkey)
|
||||
000000000000 # Blankkey
|
||||
a0a1a2a3a4a5 # NFCForumMADkey
|
||||
a0a1a2a3a4a5 # NFC Forum MADkey
|
||||
A5A4A3A2A1A0 # MAD access key (reversed)
|
||||
b0b1b2b3b4b5
|
||||
c0c1c2c3c4c5
|
||||
d0d1d2d3d4d5
|
||||
|
@ -20,19 +21,49 @@ a0478cc39091
|
|||
533cb6c723f6
|
||||
8fd0a4f256e9
|
||||
#
|
||||
d2ece8b9395e # lib
|
||||
d2ece8b9395e # lib / Nat Bieb
|
||||
# NSCP default key
|
||||
1494E81663D7
|
||||
#
|
||||
# Kiev keys
|
||||
569369c5a0e5 # kiev
|
||||
632193be1c3c # kiev
|
||||
644672bd4afe # kiev
|
||||
8fe644038790 # kiev
|
||||
9de89e070277 # kiev
|
||||
b5ff67cba951 # kiev / ov-chipkaart
|
||||
eff603e1efe9 # kiev
|
||||
f14ee7cae863 # kiev
|
||||
#
|
||||
# RKF
|
||||
fc00018778f7 # Västtrafiken KeyA, RKF ÖstgötaTrafiken KeyA
|
||||
0297927c0f77 # Västtrafiken KeyA
|
||||
54726176656c # Västtrafiken KeyA
|
||||
00000ffe2488 # Västtrafiken KeyB
|
||||
776974687573 # Västtrafiken KeyB
|
||||
ee0042f88840 # Västtrafiken KeyB
|
||||
26940b21ff5d # RKF SLKeyA
|
||||
a64598a77478 # RKF SLKeyA
|
||||
5c598c9c58b5 # RKF SLKeyB
|
||||
e4d2770a89be # RKF SLKeyB
|
||||
722bfcc5375f # RKF RejskortDanmark KeyA
|
||||
f1d83f964314 # RKF RejskortDanmark KeyB
|
||||
505249564141 # RKF JOJOPRIVAKeyA
|
||||
505249564142 # RKF JOJOPRIVAKeyB
|
||||
47524f555041 # RKF JOJOGROUPKeyA
|
||||
47524f555042 # RKF JOJOGROUPKeyB
|
||||
434f4d4d4f41 # RKF JOJOGROUPKeyA
|
||||
434f4d4d4f42 # RKF JOJOGROUPKeyB
|
||||
#
|
||||
4b0b20107ccb # TNP3xxx
|
||||
#
|
||||
# more Keys from mfc_default_keys.lua
|
||||
000000000001
|
||||
000000000002
|
||||
00000000000a
|
||||
00000000000b
|
||||
00000ffe2488 # VästtrafikenKeyB
|
||||
010203040506
|
||||
0123456789ab
|
||||
0297927c0f77 # VästtrafikenKeyA
|
||||
100000000000
|
||||
111111111111
|
||||
123456789abc
|
||||
|
@ -41,72 +72,39 @@ d2ece8b9395e # lib
|
|||
1999a3554a55
|
||||
200000000000
|
||||
222222222222
|
||||
26940b21ff5d # RKFSLKeyA
|
||||
27dd91f1fcf1
|
||||
2BA9621E0A36 # DirectoryandeventlogKeyB
|
||||
4AF9D7ADEBE4 # DirectoryandeventlogKeyA
|
||||
333333333333
|
||||
33f974b42769
|
||||
34d1df9934c5
|
||||
434f4d4d4f41 # RKFJOJOGROUPKeyA
|
||||
434f4d4d4f42 # RKFJOJOGROUPKeyB
|
||||
43ab19ef5c31
|
||||
444444444444
|
||||
47524f555041 # RKFJOJOGROUPKeyA
|
||||
47524f555042 # RKFJOJOGROUPKeyB
|
||||
4AF9D7ADEBE4 # DirectoryandeventlogKeyA
|
||||
4b0b20107ccb # TNP3xxx
|
||||
505249564141 # RKFJOJOPRIVAKeyA
|
||||
505249564142 # RKFJOJOPRIVAKeyB
|
||||
505249565441
|
||||
505249565442
|
||||
54726176656c # VästtrafikenKeyA
|
||||
555555555555
|
||||
55f5a5dd38c9
|
||||
569369c5a0e5 # kiev
|
||||
5c598c9c58b5 # RKFSLKeyB
|
||||
632193be1c3c # kiev
|
||||
644672bd4afe # kiev
|
||||
666666666666
|
||||
722bfcc5375f # RKFRejskortDanmarkKeyA
|
||||
776974687573 # VästtrafikenKeyB
|
||||
777777777777
|
||||
888888888888
|
||||
8fe644038790 # kiev
|
||||
999999999999
|
||||
99c636334433
|
||||
9de89e070277 # kiev
|
||||
a00000000000
|
||||
a053a292a4af
|
||||
a64598a77478 # RKFSLKeyA
|
||||
a94133013401
|
||||
aaaaaaaaaaaa
|
||||
abcdef123456 # Keyfromladyada.net
|
||||
b00000000000
|
||||
b127c6f41436
|
||||
b5ff67cba951 # kiev
|
||||
bbbbbbbbbbbb
|
||||
bd493a3962b6
|
||||
c934fe34d934
|
||||
cccccccccccc
|
||||
dddddddddddd
|
||||
e4d2770a89be # RKFSLKeyB
|
||||
ee0042f88840 # VästtrafikenKeyB
|
||||
eeeeeeeeeeee
|
||||
eff603e1efe9 # kiev
|
||||
f14ee7cae863 # kiev
|
||||
f1a97341a9fc
|
||||
f1d83f964314 # RKFRejskortDanmarkKeyB
|
||||
fc00018778f7 # VästtrafikenKeyA, RKFÖstgötaTrafikenKeyA
|
||||
44ab09010845 # hotel system
|
||||
85fed980ea5a # hotel system
|
||||
314B49474956 # VIGIK1 A
|
||||
564c505f4d41 # VIGIK1 B
|
||||
ba5b895da162 # VIGIK1 B
|
||||
# Vigik mystery Keys Mifare 1k EV1 (S50)
|
||||
5c8ff9990da2 # 16 A
|
||||
75ccb59c9bed # 17 A
|
||||
d01afeeb890a # 16 B
|
||||
4b791bea7bcc # 17 B
|
||||
#
|
||||
43454952534E # ARD (fr) key A
|
||||
4A2B29111213 # ARD (fr) key B
|
||||
|
@ -361,11 +359,29 @@ a56c2df9a26d
|
|||
#
|
||||
68d3f7307c89
|
||||
568c9083f71c # Smart Rider. Western Australian Public Transport Cards
|
||||
#
|
||||
#
|
||||
97F5DA640B18 # Bangkok metro key
|
||||
A8844B0BCA06 # Metro Valencia key
|
||||
857464D3AAD1 # HTC Eindhoven key
|
||||
#
|
||||
# Vigik Keys
|
||||
# Various sources :
|
||||
# * https://github.com/DumpDos/Vigik
|
||||
# * http://newffr.com/viewtopic.php?&forum=235&topic=11559
|
||||
# * Own dumps
|
||||
#
|
||||
# French VIGIK
|
||||
314B49474956 # VIGIK1 A
|
||||
564c505f4d41 # VIGIK1 B
|
||||
ba5b895da162 # VIGIK1 B
|
||||
#
|
||||
# Vigik mystery Keys Mifare 1k EV1 (S50)
|
||||
5c8ff9990da2 # 16 A
|
||||
75ccb59c9bed # 17 A
|
||||
d01afeeb890a # 16 B
|
||||
4b791bea7bcc # 17 B
|
||||
#
|
||||
021209197591 # BTCINO UNDETERMINED SPREAKD 0x01->0x13 key
|
||||
2ef720f2af76
|
||||
414c41524f4e
|
||||
|
@ -543,11 +559,13 @@ B66AC040203A
|
|||
2E641D99AD5B
|
||||
AD4FB33388BF
|
||||
69FB7B7CD8EE
|
||||
2A6D9205E7CA
|
||||
2A6D9205E7CA # Hotel
|
||||
2a2c13cc242a
|
||||
27FBC86A00D0
|
||||
01FA3FC68349
|
||||
#
|
||||
13B91C226E56 # Hotel
|
||||
#
|
||||
6D44B5AAF464 # Smart Rider. Western Australian Public Transport Cards
|
||||
1717E34A7A8A # Smart Rider. Western Australian Public Transport Cards
|
||||
#
|
||||
|
@ -1044,42 +1062,59 @@ a2a3cca2a3cc
|
|||
#
|
||||
# Granada, ES Transport Card
|
||||
000000270000
|
||||
0172066b2f03
|
||||
0172066b2f33
|
||||
066b2f230172
|
||||
0b0172066b2f
|
||||
0f385ffb6529
|
||||
172066b2f2f0
|
||||
2066b2f27017
|
||||
29173860fc76
|
||||
2f130172066b
|
||||
2fca8492f386
|
||||
385efa542907
|
||||
3864fcba5937
|
||||
3b0172066b2f
|
||||
3f3865fccb69
|
||||
5c8ff9990da2
|
||||
6291b3860fc8
|
||||
63fca9492f38
|
||||
66b2f1f01720
|
||||
6b2f1b017206
|
||||
70172066b2f0
|
||||
70172066b2f3
|
||||
72066b2f2b01
|
||||
863fcb959373
|
||||
87291f3861fc
|
||||
913385ffb752
|
||||
b2f170172066
|
||||
b385efa64290
|
||||
c9739233861f
|
||||
f0f0172066b2
|
||||
f3864fcca693
|
||||
f3f0172066b2
|
||||
fc9839273862
|
||||
|
||||
#
|
||||
# various hotel keys
|
||||
34D3C568B348
|
||||
91FF18E63887
|
||||
4D8B8B95FDEE
|
||||
354A787087F1
|
||||
4a306e62e9b6
|
||||
B9C874AE63D0
|
||||
#
|
||||
# Data from offical repo
|
||||
f00dfeedd0d0
|
||||
0bb31dc123e5
|
||||
7578bf2c66a9
|
||||
cd212889c3ed
|
||||
6936c035ae1b
|
||||
c6c866aa421e
|
||||
590bd659cdd2
|
||||
aa734d2f40e0
|
||||
09800ff94aaf
|
||||
5a12f83326e7
|
||||
c554ef6a6015
|
||||
0d8ca561bdf3
|
||||
b8937130b6ba
|
||||
d7744a1a0c44
|
||||
82908b57ef4f
|
||||
fe04ecfe5577
|
||||
# comfort inn hotel
|
||||
4d57414c5648
|
||||
4d48414c5648
|
||||
#
|
||||
# unknown hotel key
|
||||
6d9b485a4845
|
||||
#
|
||||
5a7a52d5e20d # Bosch Solution 6000
|
||||
#
|
||||
# Found in TagInfo app
|
||||
8A19D40CF2B5 # Hotel key card key
|
||||
C1E51C63B8F5 # RATB key
|
||||
1DB710648A65
|
||||
18F34C92A56E # E-GO card key
|
||||
|
|
|
@ -25,3 +25,6 @@ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
|||
15141312111009080706050403020100
|
||||
0f0e0d0c0b0a09080706050403020100
|
||||
100f0e0d0c0b0a090807060504030201
|
||||
404142434445464748494a4b4c4d4e4f
|
||||
303132333435363738393a3b3c3d3e3f
|
||||
|
||||
|
|
1861
client/emojis.h
Normal file
1861
client/emojis.h
Normal file
File diff suppressed because it is too large
Load diff
15
client/emojis_alt.h
Normal file
15
client/emojis_alt.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef EMOJIS_ALT_H__
|
||||
#define EMOJIS_ALT_H__
|
||||
|
||||
typedef struct emoji_alt_s {
|
||||
const char *alias;
|
||||
const char *alttext;
|
||||
} emoji_alt_t;
|
||||
// emoji_alt_t array are expected to be NULL terminated
|
||||
|
||||
static emoji_alt_t EmojiAltTable[] = {
|
||||
{":wink:", ";)"},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
#endif
|
38
client/emojis_scrap_github.py
Executable file
38
client/emojis_scrap_github.py
Executable file
|
@ -0,0 +1,38 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Mostly derived from https://github.com/mrowa44/emojify Copyright (c) 2015 Justyna Rachowicz
|
||||
|
||||
from urllib.request import urlopen
|
||||
import json
|
||||
|
||||
|
||||
EMOJI_JSON_URL = 'https://raw.githubusercontent.com/github/gemoji/master/db/emoji.json'
|
||||
|
||||
def print_emoji(emoji_json):
|
||||
for alias in emoji_json['aliases']:
|
||||
print(' {{":{0}:", "{1}"}}, // {2}'.format(alias,
|
||||
|
||||
''.join('\\x{:02x}'.format(b) for b in emoji_json['emoji'].encode('utf8')),
|
||||
|
||||
emoji_json['emoji']))
|
||||
|
||||
print(
|
||||
"""#ifndef EMOJIS_H__
|
||||
#define EMOJIS_H__
|
||||
|
||||
typedef struct emoji_s {
|
||||
const char *alias;
|
||||
const char *emoji;
|
||||
} emoji_t;
|
||||
// emoji_t array are expected to be NULL terminated
|
||||
|
||||
static emoji_t EmojiTable[] = {""")
|
||||
|
||||
with urlopen(EMOJI_JSON_URL) as conn:
|
||||
emojis_json = json.loads(conn.read().decode('utf-8'))
|
||||
for emoji_json in emojis_json:
|
||||
print_emoji(emoji_json)
|
||||
|
||||
print(""" {NULL, NULL}
|
||||
};
|
||||
#endif""")
|
|
@ -662,10 +662,7 @@ static void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON,
|
|||
}
|
||||
|
||||
//9F66:(Terminal Transaction Qualifiers (TTQ)) len:4
|
||||
const char *qVSDC = "\x26\x00\x00\x00";
|
||||
if (GenACGPO) {
|
||||
qVSDC = "\x26\x80\x00\x00";
|
||||
}
|
||||
|
||||
switch (TrType) {
|
||||
case TT_MSD:
|
||||
TLV_ADD(0x9F66, "\x86\x00\x00\x00"); // MSD
|
||||
|
@ -675,10 +672,20 @@ static void InitTransactionParameters(struct tlvdb *tlvRoot, bool paramLoadJSON,
|
|||
TLV_ADD(0x9F66, "\x46\x00\x00\x00"); // VSDC
|
||||
break;
|
||||
case TT_QVSDCMCHIP:
|
||||
TLV_ADD(0x9F66, qVSDC); // qVSDC
|
||||
// qVSDC
|
||||
if (GenACGPO) {
|
||||
TLV_ADD(0x9F66, "\x26\x80\x00\x00");
|
||||
} else {
|
||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00");
|
||||
}
|
||||
break;
|
||||
case TT_CDA:
|
||||
TLV_ADD(0x9F66, qVSDC); // qVSDC (VISA CDA not enabled)
|
||||
// qVSDC (VISA CDA not enabled)
|
||||
if (GenACGPO) {
|
||||
TLV_ADD(0x9F66, "\x26\x80\x00\x00");
|
||||
} else {
|
||||
TLV_ADD(0x9F66, "\x26\x00\x00\x00");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -305,7 +305,7 @@ static int EMVExchangeEx(EMVCommandChannel channel, bool ActivateField, bool Lea
|
|||
break;
|
||||
case ECC_CONTACT:
|
||||
if (IfPm3Smartcard())
|
||||
res = ExchangeAPDUSC(data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||
res = ExchangeAPDUSC(true, data, datalen, ActivateField, LeaveFieldON, Result, (int)MaxResultLen, (int *)ResultLen);
|
||||
else
|
||||
res = 1;
|
||||
if (res) {
|
||||
|
|
|
@ -70,7 +70,7 @@ struct wave_info_t {
|
|||
char tag[4];
|
||||
uint32_t size;
|
||||
} PACKED audio_data;
|
||||
} PACKED wave_info;
|
||||
} PACKED;
|
||||
|
||||
/**
|
||||
* @brief checks if a file exists
|
||||
|
@ -180,7 +180,7 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si
|
|||
fwrite(data, 1, datalen, f);
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu")" bytes to binary file " _YELLOW_("%s"), datalen, fileName);
|
||||
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") "bytes to binary file " _YELLOW_("%s"), datalen, fileName);
|
||||
free(fileName);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -223,7 +223,7 @@ int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t
|
|||
}
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%" PRId32)" blocks to text file " _YELLOW_("%s"), blocks, fileName);
|
||||
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%" PRId32) "blocks to text file " _YELLOW_("%s"), blocks, fileName);
|
||||
|
||||
out:
|
||||
free(fileName);
|
||||
|
@ -233,6 +233,7 @@ out:
|
|||
int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen) {
|
||||
|
||||
if (data == NULL) return PM3_EINVARG;
|
||||
|
||||
char *fileName = newfilenamemcopy(preferredName, ".json");
|
||||
if (fileName == NULL) return PM3_EMALLOC;
|
||||
|
||||
|
@ -368,10 +369,34 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s
|
|||
}
|
||||
break;
|
||||
}
|
||||
case jsf14b:
|
||||
case jsf15:
|
||||
case jsfLegic:
|
||||
case jsfT5555:
|
||||
case jsf14b: {
|
||||
JsonSaveStr(root, "FileType", "14b");
|
||||
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
|
||||
break;
|
||||
}
|
||||
case jsf15: {
|
||||
JsonSaveStr(root, "FileType", "15693");
|
||||
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
|
||||
break;
|
||||
}
|
||||
case jsfLegic: {
|
||||
JsonSaveStr(root, "FileType", "legic");
|
||||
JsonSaveBufAsHexCompact(root, "raw", data, datalen);
|
||||
break;
|
||||
}
|
||||
case jsfT5555: {
|
||||
JsonSaveStr(root, "FileType", "t5555");
|
||||
uint8_t conf[4] = {0};
|
||||
memcpy(conf, data, 4);
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.ConfigBlock", conf, sizeof(conf));
|
||||
|
||||
for (size_t i = 0; i < (datalen / 4); i++) {
|
||||
char path[PATH_MAX_LENGTH] = {0};
|
||||
sprintf(path, "$.blocks.%zu", i);
|
||||
JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case jsfMfPlusKeys:
|
||||
JsonSaveStr(root, "FileType", "mfp");
|
||||
JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 7);
|
||||
|
@ -455,7 +480,7 @@ int saveFileWAVE(const char *preferredName, int *data, size_t datalen) {
|
|||
}
|
||||
fclose(wave_file);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu")" bytes to wave file " _YELLOW_("'%s'"), 2 * datalen, fileName);
|
||||
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") "bytes to wave file " _YELLOW_("'%s'"), 2 * datalen, fileName);
|
||||
|
||||
out:
|
||||
free(fileName);
|
||||
|
@ -482,7 +507,7 @@ int saveFilePM3(const char *preferredName, int *data, size_t datalen) {
|
|||
|
||||
fflush(f);
|
||||
fclose(f);
|
||||
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu")" bytes to PM3 file " _YELLOW_("'%s'"), datalen, fileName);
|
||||
PrintAndLogEx(SUCCESS, "saved " _YELLOW_("%zu") "bytes to PM3 file " _YELLOW_("'%s'"), datalen, fileName);
|
||||
|
||||
out:
|
||||
free(fileName);
|
||||
|
@ -581,7 +606,7 @@ int loadFile(const char *preferredName, const char *suffix, void *data, size_t m
|
|||
memcpy((data), dump, bytes_read);
|
||||
free(dump);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "loaded %zu bytes from binary file " _YELLOW_("%s"), bytes_read, fileName);
|
||||
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") "bytes from binary file " _YELLOW_("%s"), bytes_read, fileName);
|
||||
|
||||
*datalen = bytes_read;
|
||||
|
||||
|
@ -637,7 +662,7 @@ int loadFile_safe(const char *preferredName, const char *suffix, void **pdata, s
|
|||
|
||||
*datalen = bytes_read;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "loaded %zu bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName);
|
||||
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") "bytes from binary file " _YELLOW_("%s"), bytes_read, preferredName);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -688,7 +713,7 @@ int loadFileEML(const char *preferredName, void *data, size_t *datalen) {
|
|||
}
|
||||
}
|
||||
fclose(f);
|
||||
PrintAndLogEx(SUCCESS, "loaded %zu bytes from text file " _YELLOW_("%s"), counter, fileName);
|
||||
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") "bytes from text file " _YELLOW_("%s"), counter, fileName);
|
||||
|
||||
if (datalen)
|
||||
*datalen = counter;
|
||||
|
|
|
@ -529,7 +529,7 @@ const char ice[] =
|
|||
" !!: :!! !!: !!: !!: !!: !!! !!: !!!\n : :: :: : : :: ::: : : : : : :: : \n"
|
||||
_RED_(" . .. .. . . .. ... . . . . . .. . ")
|
||||
"\n...................................................................\n"
|
||||
;
|
||||
;
|
||||
|
||||
// Write a file's segments to Flash
|
||||
int flash_write(flash_file_t *ctx) {
|
||||
|
@ -566,8 +566,8 @@ int flash_write(flash_file_t *ctx) {
|
|||
baddr += block_size;
|
||||
length -= block_size;
|
||||
block++;
|
||||
if ( len < strlen(ice) ) {
|
||||
if (filter_ansi && !isalpha(ice[len]) ) {
|
||||
if (len < strlen(ice)) {
|
||||
if (filter_ansi && !isalpha(ice[len])) {
|
||||
len++;
|
||||
} else {
|
||||
fprintf(stdout, "%c", ice[len++]);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Andrei Costin <zveriu@gmail.com>, 2011
|
||||
# gen_pm3mfsim_script.sh
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue