mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Merge pull request #5 from RfidResearchGroup/master
Update from upstream.
This commit is contained in:
commit
29d17dbe84
479 changed files with 802627 additions and 300629 deletions
47
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
Normal file
47
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
name: Checklist for release
|
||||
about: A template when making a release (usage reserved to repo maintainers)
|
||||
title: "[RELEASE 4.x] Checklist"
|
||||
labels: Release
|
||||
assignees: doegox, iceman1001
|
||||
|
||||
---
|
||||
|
||||
# Checklist
|
||||
|
||||
- [ ] CHANGELOG.md
|
||||
- [ ] `make style`
|
||||
- [ ] `make clean; make client CC=clang CXX=clang++ LD=clang++` on recent Debian or Ubuntu
|
||||
- [ ] `mymanualchecks.sh`
|
||||
- [ ] `mycppcheck.sh` no alarming warning?
|
||||
- [ ] `mymakeclang.sh` no alarming error/warning ?
|
||||
- [ ] `mystandalone_makes.sh` compile all standalone modes (linux only)
|
||||
- [ ] [Travis](https://travis-ci.org/github/RfidResearchGroup/proxmark3/builds) green (linux noqt / osx+qt ; with makefile (w/wo bt) / with cmake)
|
||||
- [ ] [Appveyor](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/history) green (PS)
|
||||
|
||||
# OS compilation and tests
|
||||
|
||||
```bash
|
||||
make clean && make -j PLATFORM=PM3OTHER && tools/pm3test.sh
|
||||
make clean && make -j PLATFORM=PM3RDV4 && tools/pm3test.sh
|
||||
make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && tools/pm3test.sh
|
||||
make install; pushd /tmp; proxmark3 -c 'data load em4x05.pm3;lf search 1'; popd; make uninstall
|
||||
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3OTHER && PM3BIN=./proxmark3 ../../tools/pm3test.sh client )
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 && PM3BIN=./proxmark3 ../../tools/pm3test.sh client )
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && PM3BIN=./proxmark3 ../../tools/pm3test.sh client )
|
||||
```
|
||||
|
||||
- [ ] RPI Zero
|
||||
- [ ] WSL
|
||||
- [ ] PSv3.3
|
||||
- [ ] Kali
|
||||
- [ ] Debian
|
||||
- [ ] Ubuntu20
|
||||
- [ ] ParrotOS
|
||||
- [ ] Fedora
|
||||
- [ ] OpenSuse
|
||||
- [ ] OSX
|
||||
- [ ] Android
|
||||
- [ ] Termux
|
||||
|
11
.gitignore
vendored
11
.gitignore
vendored
|
@ -32,6 +32,7 @@ version.c
|
|||
*.swp
|
||||
*.json.bak
|
||||
*.pyc
|
||||
*.bmp
|
||||
|
||||
# new build file for add-ons.
|
||||
Makefile.platform
|
||||
|
@ -41,6 +42,7 @@ Makefile.platform
|
|||
# cmake
|
||||
client/build/
|
||||
client/android/build/
|
||||
client/deps/bzip2/
|
||||
|
||||
# Coverity
|
||||
cov-int/
|
||||
|
@ -65,6 +67,10 @@ tools/fpga_compress/fpga_compress
|
|||
tools/mfkey/mfkey32
|
||||
tools/mfkey/mfkey64
|
||||
tools/nonce2key/nonce2key
|
||||
tools/cryptorf/cm
|
||||
tools/cryptorf/sm
|
||||
tools/cryptorf/sma
|
||||
tools/cryptorf/sma_multi
|
||||
|
||||
fpga/*
|
||||
!fpga/tests
|
||||
|
@ -77,17 +83,16 @@ fpga/*
|
|||
!fpga/xst_hf.scr
|
||||
!fpga/go.bat
|
||||
!fpga/sim.tcl
|
||||
|
||||
# offcial dumps folder
|
||||
dumps/*
|
||||
traces/*
|
||||
|
||||
#client/*
|
||||
# my own traces folder
|
||||
client/traces/*
|
||||
# my own dumps folder
|
||||
client/dumps/*
|
||||
*.ice
|
||||
*.new
|
||||
armsrc/TEMP EMV/*
|
||||
tools/mf_nonce_brute/mf_nonce_brute
|
||||
tools/andrew/*
|
||||
tools/jtag_openocd/openocd_configuration
|
||||
|
|
1
.lsan_suppressions
Normal file
1
.lsan_suppressions
Normal file
|
@ -0,0 +1 @@
|
|||
leak:libfontconfig.so
|
25
CHANGELOG.md
25
CHANGELOG.md
|
@ -3,8 +3,27 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added lf em function: 4x50_sread (@tharexde)
|
||||
- Added lf em functions: 4x50_info, 4x50_write, 4x50_write_password (@tharexde)
|
||||
- Add low level support for 14b' aka Innovatron (@doegox)
|
||||
- Add doc/cliparser.md (@mwalker33)
|
||||
- Add `hf 14b apdu` - send APDU over ISO14443B (@iceman1001)
|
||||
- Add `lf t55xx chk e <EM4100> option` - Checks calculated password based on the EM4100 id from some white cloners forumla by paleopterix (@mwalker33)
|
||||
- Add `lf t55xx sniff` to allow extracting commands and passwords used be cloners. (@mwalker33)
|
||||
- Add options to `lf read`, `lf cmdread`, `lf sniff` for repeated acquisitions (@doegox)
|
||||
- Change options of `lf read` to match `lf cmdread`, this affects historical `d` and `s` options (@doegox)
|
||||
- Add `hf waveshare` to upload picture to Waveshare NFC-Powered e-Paper (@doegox)
|
||||
- Add `hf 14a config` to deal with badly configured cards: invalid ATQA/BCC/SAK (@doegox)
|
||||
- Mikron JSC Russia Ultralight EV1 41 pages tag type support (@McEloff)
|
||||
- Add test for Ultralight gen2 magic 'hf search' (@McEloff)
|
||||
- Add test for Ultralight EV1 gen2 magic 'hf search' (@McEloff)
|
||||
- Added `hf mf gen3*`magic gen 3 card operations (@McEloff)
|
||||
- Readded verichip command which seems missing (@iceman1001)
|
||||
- Fix missing t55x7 config block detection (@iceman1001)
|
||||
- Fix missing define on proxspace (@mwalker33)
|
||||
- Added `lf em 4x50_dump` (@iceman1001)
|
||||
- Added `lf em 4x50_read` (@tharexde)
|
||||
- Added `lf em 4x50_info` (@tharexde)
|
||||
- Added `4x50_write` (@tharexde)
|
||||
- Added `4x50_write_password` (@tharexde)
|
||||
- Fix em4x50 demodulation error (@tharexde)
|
||||
- Fix `hf mfdes` authentification issues, DES working (@bkerler)
|
||||
- Add Android cross-compilation to client cmake (@dxl, @doegox)
|
||||
|
@ -90,7 +109,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Change appveyor verbose (@doegox)
|
||||
- Change `lf nexwatch demod` - now detects type, and show parity /chksum (@iceman1001)
|
||||
- Change `lfsampling` - interruptible only when logging not yet triggered (@doegox)
|
||||
- Change `lf keri demod - more leanient when it comes to bits (@iceman1001)
|
||||
- Change `lf keri demod` - more leanient when it comes to bits (@iceman1001)
|
||||
- fix, proper filtering of RL markers (@doegox)
|
||||
- Change, clean deps [compiler trials] (@doegox)
|
||||
- Change, remove c99 restrictions [compiler trials] (@doegox)
|
||||
|
|
34
Makefile
34
Makefile
|
@ -173,6 +173,9 @@ help:
|
|||
@echo "+ .../check - Run offline tests against specific target. See above."
|
||||
@echo "+ miscchecks - Detect various encoding issues in source code"
|
||||
@echo
|
||||
@echo "+ udev - Sets udev rules on *nix"
|
||||
@echo "+ accessrights - Ensure user belongs to correct group on *nix"
|
||||
@echo
|
||||
@echo "Possible platforms: try \"make PLATFORM=\" for more info, default is PM3RDV4"
|
||||
@echo "To activate verbose mode, use make V=1"
|
||||
|
||||
|
@ -248,8 +251,8 @@ print-%: ; @echo $* = $($*)
|
|||
style:
|
||||
# Make sure astyle is installed
|
||||
@which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 )
|
||||
# Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile
|
||||
find . \( -not -path "./cov-int/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \) \
|
||||
# Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile, *.v
|
||||
find . \( -not -path "./cov-int/*" -and -not -path "./fpga/xst/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \) \
|
||||
-exec perl -pi -e 's/[ \t]+$$//' {} \; \
|
||||
-exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \
|
||||
-exec sh -c "echo >> {}" \;
|
||||
|
@ -259,23 +262,32 @@ style:
|
|||
--keep-one-line-blocks --max-instatement-indent=60 \
|
||||
--style=google --pad-oper --unpad-paren --pad-header \
|
||||
--align-pointer=name {} \;
|
||||
# Update commands.md
|
||||
[ -x client/proxmark3 ] && client/proxmark3 -m > doc/commands.md
|
||||
|
||||
# Detecting weird codepages and tabs.
|
||||
ifeq ($(platform),Darwin)
|
||||
miscchecks: TABSCMD=egrep -l '\t' {}
|
||||
else
|
||||
miscchecks: TABSCMD=grep -lP '\t' {}
|
||||
endif
|
||||
ifneq (,$(EDIT))
|
||||
miscchecks: TABSCMD+= && vi {} -c ':set tabstop=4' -c ':set et|retab' -c ':wq'
|
||||
endif
|
||||
miscchecks:
|
||||
# Make sure recode is installed
|
||||
# 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" \) \
|
||||
@find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -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' {} \;
|
||||
ifneq (,$(EDIT))
|
||||
@echo "Files with tabs: (EDIT enabled, files will be rewritten!)"
|
||||
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' {} \;
|
||||
@echo "Files with tabs: (rerun with EDIT=1 if you want to convert them with vim)"
|
||||
endif
|
||||
# to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq'
|
||||
@find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -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 sh -c "$(TABSCMD)" \;
|
||||
# @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' {} \;
|
||||
|
|
|
@ -48,7 +48,15 @@ else
|
|||
RANLIB= ranlib
|
||||
endif
|
||||
|
||||
DEFCXXFLAGS = -Wall -Werror -O3 -pipe
|
||||
DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe
|
||||
DEFLDFLAGS =
|
||||
# Next ones are activated only if SANITIZE=1
|
||||
ifeq ($(SANITIZE),1)
|
||||
DEFCFLAGS += -g -fsanitize=address -fno-omit-frame-pointer
|
||||
DEFCXXFLAGS += -g -fsanitize=address -fno-omit-frame-pointer
|
||||
DEFLDFLAGS += -g -fsanitize=address
|
||||
endif
|
||||
# Some more warnings we want as errors:
|
||||
DEFCFLAGS += -Wbad-function-cast -Wredundant-decls -Wmissing-prototypes -Wchar-subscripts -Wshadow -Wundef -Wwrite-strings -Wunused -Wuninitialized -Wpointer-arith -Winline -Wformat -Wformat-security -Winit-self -Wmissing-include-dirs -Wnested-externs -Wmissing-declarations -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wtype-limits -Wold-style-definition
|
||||
# Some more warnings we need first to eliminate, so temporarely tolerated:
|
||||
|
|
|
@ -17,6 +17,9 @@ endif
|
|||
|
||||
CFLAGS ?= $(DEFCFLAGS)
|
||||
CFLAGS += $(MYDEFS) $(MYCFLAGS) $(MYINCLUDES)
|
||||
CXXFLAGS ?= $(DEFCXXFLAGS)
|
||||
CXXFLAGS += $(MYDEFS) $(MYCXXFLAGS) $(MYINCLUDES)
|
||||
LDFLAGS ?= $(DEFLDFLAGS)
|
||||
LDFLAGS += $(MYLDFLAGS)
|
||||
LDLIBS += $(MYLDLIBS)
|
||||
|
||||
|
@ -31,6 +34,7 @@ BINDIR := .
|
|||
OBJDIR := obj
|
||||
|
||||
MYOBJS ?= $(MYSRCS:%.c=$(OBJDIR)/%.o)
|
||||
MYCXXOBJS ?= $(MYCXXSRCS:%.cpp=$(OBJDIR)/%.o)
|
||||
CLEAN = $(foreach bin,$(MYLIBS) $(BINS) $(LIB_A),$(BINDIR)/$(bin))
|
||||
|
||||
all: $(foreach bin,$(MYLIBS) $(BINS) $(LIB_A),$(BINDIR)/$(bin))
|
||||
|
@ -61,24 +65,31 @@ endif
|
|||
|
||||
.PHONY: all clean install uninstall
|
||||
|
||||
$(BINDIR)/$(LIB_A): $(MYOBJS)
|
||||
$(BINDIR)/$(LIB_A): $(MYOBJS) $(MYCXXOBJS)
|
||||
$(info [=] AR $(notdir $@))
|
||||
$(Q)$(AR) $@ $(MYOBJS)
|
||||
$(Q)$(AR) $@ $(MYOBJS) $(MYCXXOBJS)
|
||||
$(Q)$(RANLIB) $@
|
||||
|
||||
$(BINDIR)/% : $(OBJDIR)/%.o $(MYOBJS) $(MYLIBS)
|
||||
$(BINDIR)/% : $(OBJDIR)/%.o $(MYOBJS) $(MYCXXOBJS) $(MYLIBS)
|
||||
$(info [=] LD $(notdir $@))
|
||||
$(Q)$(LD) $(LDFLAGS) $(MYOBJS) $< -o $@ $(MYLIBS) $(MYLDLIBS)
|
||||
$(Q)$(LD) $(LDFLAGS) $(MYOBJS) $(MYCXXOBJS) $< -o $@ $(MYLIBS) $(MYLDLIBS)
|
||||
|
||||
$(OBJDIR)/%.o : %.c | $(OBJDIR)
|
||||
%.o: %.c
|
||||
$(OBJDIR)/%.o : %.c $(OBJDIR)/%.d | $(OBJDIR)
|
||||
$(info [-] CC $<)
|
||||
$(Q)$(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $<
|
||||
$(Q)$(POSTCOMPILE)
|
||||
|
||||
%.o: %.cpp
|
||||
$(OBJDIR)/%.o : %.cpp $(OBJDIR)/%.d | $(OBJDIR)
|
||||
$(info [-] CXX $<)
|
||||
$(Q)$(CXX) $(DEPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
||||
$(Q)$(POSTCOMPILE)
|
||||
|
||||
$(OBJDIR):
|
||||
$(Q)$(MKDIR) $(OBJDIR)
|
||||
|
||||
DEPENDENCY_FILES = $(MYOBJS:%.o=%.d) $(BINS:%=$(OBJDIR)/%.d)
|
||||
DEPENDENCY_FILES = $(MYOBJS:%.o=%.d) $(MYCXXOBJS:%.o=%.d) $(BINS:%=$(OBJDIR)/%.d)
|
||||
|
||||
$(DEPENDENCY_FILES): ;
|
||||
.PRECIOUS: $(DEPENDENCY_FILES)
|
||||
|
|
39
README.md
39
README.md
|
@ -3,9 +3,9 @@
|
|||
|
||||
|
||||
|
||||
| Releases | Linux & OSX CI | Windows CI | Coverity |
|
||||
| ------------------- |:-------------------:| -------------------:| -------------------:|
|
||||
| [](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [](https://travis-ci.org/RfidResearchGroup/proxmark3) | [](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)|
|
||||
| Releases | Linux & OSX CI | Windows CI | Coverity | Contributors |
|
||||
| ------------------- |:-------------------:| -------------------:| -------------------:| -------------------:|
|
||||
| [](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [](https://travis-ci.com/RfidResearchGroup/proxmark3) | [](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)|  |
|
||||
|
||||
|
||||
|
||||
|
@ -30,11 +30,11 @@
|
|||
| ------------------- |:-------------------:| -------------------:|
|
||||
|[Notes on UART](/doc/uart_notes.md)|[Notes on Termux / Android](/doc/termux_notes.md)|[Notes on paths](/doc/path_notes.md)|
|
||||
|[Notes on frame format](/doc/new_frame_format.md)|[Notes on tracelog / wireshark](/doc/trace_notes.md)|[Notes on EMV](/doc/emv_notes.md)|
|
||||
|[Notes on external flash](/doc/ext_flash_notes.md)|[Notes on loclass](/doc/loclass_notes.md)|[Notes on Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-%26-Run.md)|
|
||||
|[Notes on external flash](/doc/ext_flash_notes.md)|[Notes on loclass](/doc/loclass_notes.md)|[Notes on Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-and-Run.md)|
|
||||
|[Notes on file formats used with Proxmark3](/doc/extensions_notes.md)|[Notes on MFU binary format](/doc/mfu_binary_format_notes.md)|[Notes on FPGA & ARM](/doc/fpga_arm_notes.md)|
|
||||
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)||
|
||||
|[Notes on Color usage](/doc/colors_notes.md)|[Makefile vs CMake](/doc/md/Development/Makefile-vs-CMake.md)|
|
||||
|
||||
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)|[Notes on Magic cards](/doc/magic_cards_notes.md)|
|
||||
|[Notes on Color usage](/doc/colors_notes.md)|[Makefile vs CMake](/doc/md/Development/Makefile-vs-CMake.md)|[Notes on Cloner guns](/doc/cloner_notes.md)|
|
||||
|[Notes on cliparser usage](/doc/cliparser.md)|||
|
||||
|
||||
## Build for non-RDV4 Proxmark3 platforms
|
||||
|
||||
|
@ -57,14 +57,14 @@ On the software side: quite a lot, see the [Changelog file](CHANGELOG.md).
|
|||
|
||||
This repo compiles nicely on
|
||||
- Proxspace v3.x
|
||||
- [latest release v3.4](https://github.com/Gator96100/ProxSpace/releases)
|
||||
- [latest release v3.7](https://github.com/Gator96100/ProxSpace/releases)
|
||||
- Windows/mingw environment with Qt5.6.1 & GCC 4.9
|
||||
- Ubuntu 1604 -> 2004
|
||||
- Ubuntu 16.04 -> 20.04
|
||||
- ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian
|
||||
- Rasbian
|
||||
- Android / Termux
|
||||
- Mac OS X / Homebrew
|
||||
- WSL, WSL2 (Windows subsystem linux) on Windows 10
|
||||
- WSL1 (Windows subsystem linux) on Windows 10
|
||||
- Docker container
|
||||
- [ RRG / Iceman repo based ubuntu 18.04 container ](https://hub.docker.com/r/secopsconsult/proxmark3)
|
||||
- [ Iceman fork based container v1.7 ](https://hub.docker.com/r/iceman1001/proxmark3/)
|
||||
|
@ -73,7 +73,7 @@ Hardware to run client on
|
|||
- PC
|
||||
- Android
|
||||
- Raspberry Pi & Raspberry Pi Zero
|
||||
- Jetson Nano
|
||||
- Nvidia Jetson Nano
|
||||
|
||||
## Precompiled binaries
|
||||
We don't maintain any precompiled binaries in this repo. There is community effort over at the Proxmark3 forum where @gator96100 has set up a google drive with many mingw binaries which is up-to-date. We link to these files here as to make it easier for users.
|
||||
|
@ -81,14 +81,15 @@ If you are having troubles with these files, contact the package maintainer @gat
|
|||
|
||||
|
||||
Ref:
|
||||
|
||||
For Proxmark3 RDV4
|
||||
- [Precompiled builds for RDV40 dedicated x86](https://drive.google.com/open?id=13zUs-aiQkYaSl5KWrBtuW5IWCoHJPsue)
|
||||
- [Precompiled builds for RDV40 dedicated x64](https://drive.google.com/open?id=1SyPB8t5Vo8O0Lh7PjNm3Kv-mO4BNbxjX)
|
||||
|
||||
For Proxmark3 RDV4 with blueshark addon
|
||||
- [Precompiled builds for RDV40 dedicated with Bluetooth addon x86](https://drive.google.com/open?id=1TqWYctkRvkLshQ1ZRBHPLDzYHR-asuMO)
|
||||
- [Precompiled builds for RDV40 dedicated with Bluetooth addon x64](https://drive.google.com/open?id=17ful7u2QyYmMQzQzc5fAf8nJvyoDJfSL)
|
||||
|
||||
Generice Proxmark3 devices (non RDV4)
|
||||
Generice Proxmark3 devices (non RDV4), for Proxmark3 Easy, RDV1, RDV2, RDV3, etc etc
|
||||
- [Precompiled builds for RRG / Iceman repository x86](https://drive.google.com/open?id=1PI3Xr1mussPBPnYGu4ZjWzGPARK4N7JR)
|
||||
- [Precompiled builds for RRG / Iceman repository x64](https://drive.google.com/open?id=1uX9RtYGinuFrpHybu4xq_BE3HrobI20e)
|
||||
|
||||
|
@ -101,16 +102,18 @@ We usually merge your contributions fast since we do like the idea of getting a
|
|||
|
||||
|
||||
## Issues & Troubleshooting
|
||||
Please search the [issues](https://github.com/rfidresearchgroup/proxmark3/issues) page here and see if your issue is listed in the first instance. Next place to visit is the [Proxmark Forum](http://www.proxmark.org/forum/index.php). Learn to search it well and finally Google / duckduckgo is your friend :) You will find many blogposts, youtube videos, tweets, reddit
|
||||
|
||||
Please search the [issues](https://github.com/rfidresearchgroup/proxmark3/issues) page here and see if your issue is listed in the first instance.
|
||||
Read the [Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md) guide to weed out most known problems.
|
||||
|
||||
Offical channels
|
||||
Next place to visit is the [Proxmark Forum](http://www.proxmark.org/forum/index.php). Learn to search it well and finally Google / duckduckgo is your friend :) You will find many blogposts, youtube videos, tweets, reddit
|
||||
|
||||
### Offical channels
|
||||
- [Proxmark3 IRC channel](http://webchat.freenode.net/?channels=#proxmark3)
|
||||
- [Proxmark3 sub reddit](https://www.reddit.com/r/proxmark3/)
|
||||
- [Twitter](https://twitter.com/proxmark3/)
|
||||
- [Proxmark3 community discord server](https://discord.gg/zjxc8ZB)
|
||||
|
||||
_no discord or slack channel_
|
||||
_no slack channel_
|
||||
|
||||
Iceman has quite a few videos on his [youtube channel](https://www.youtube.com/c/ChrisHerrmann1001)
|
||||
|
||||
|
@ -130,7 +133,7 @@ The separation from official Proxmark3 repo gives us a lot of freedom to create
|
|||
## Proxmark3 GUI
|
||||
|
||||
The official PM3-GUI from Gaucho will not work.
|
||||
The new universal GUI will work. [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) Almost, change needed in order to show helptext when client isn't connected to a device.
|
||||
The new [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) will work more or less. Change is needed in order to show helptext when client isn't connected to a device. We don't know how active the maintainers.
|
||||
|
||||
## The end
|
||||
|
||||
|
|
426
appveyor.yml
426
appveyor.yml
|
@ -1,6 +1,18 @@
|
|||
version: 3.0.1.{build}
|
||||
image: Visual Studio 2019
|
||||
clone_folder: C:\ProxSpace\pm3
|
||||
clone_folder: C:\ProxSpace\pm3\proxmark
|
||||
cache:
|
||||
- C:\ps-cache -> appveyor.yml
|
||||
environment:
|
||||
proxspace_url: https://github.com/Gator96100/ProxSpace/archive/master.zip
|
||||
proxspace_zip_file: \proxspace.zip
|
||||
proxspace_zip_folder_name: ProxSpace-*
|
||||
proxspace_path: C:\ProxSpace
|
||||
proxspace_home_path: \ProxSpace\pm3
|
||||
proxspace_cache_path: C:\ps-cache
|
||||
wsl_git_path: C:\proxmark
|
||||
APPVEYOR_SAVE_CACHE_ON_ERROR: true
|
||||
|
||||
init:
|
||||
- ps: >-
|
||||
$psversiontable
|
||||
|
@ -17,7 +29,6 @@ init:
|
|||
|
||||
$releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT_SHORT + "]"
|
||||
|
||||
|
||||
Write-Host "repository: $env:appveyor_repo_name branch:$env:APPVEYOR_REPO_BRANCH release: $releasename" -ForegroundColor Yellow
|
||||
|
||||
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"
|
||||
|
@ -25,240 +36,301 @@ init:
|
|||
# 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
|
||||
|
||||
$CloneTime=[System.Environment]::TickCount
|
||||
|
||||
cd \
|
||||
|
||||
Remove-Item -Recurse -Force -Path c:\ProxSpace\*
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
|
||||
Write-Host "Git clone ProxSpace..." -NoNewLine
|
||||
|
||||
git clone -q https://github.com/Gator96100/ProxSpace c:\ProxSpace
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
|
||||
if(!(Test-Path -Path C:\ProxSpace\pm3)){
|
||||
|
||||
New-Item -ItemType Directory -Force -Path C:\ProxSpace\pm3
|
||||
|
||||
}
|
||||
|
||||
Write-Host "Removing pm3 dir..." -NoNewLine
|
||||
|
||||
Remove-Item -Recurse -Force -Path c:\ProxSpace\pm3\*
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
|
||||
Write-Host "Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." -NoNewLine
|
||||
|
||||
Function GitClone($Text, $Folder) {
|
||||
Write-Host "$Text" -NoNewLine
|
||||
if(-not $env:appveyor_pull_request_number) {
|
||||
git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder
|
||||
cd $env:appveyor_build_folder
|
||||
git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $Folder
|
||||
cd $Folder
|
||||
git checkout -qf $env:appveyor_repo_commit
|
||||
} else {
|
||||
git clone -q https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder
|
||||
cd $env:appveyor_build_folder
|
||||
git clone -q https://github.com/$env:appveyor_repo_name.git $Folder
|
||||
cd $Folder
|
||||
git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge:
|
||||
git checkout -qf FETCH_HEAD
|
||||
}
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
|
||||
Write-Host "Fill msys2\etc\fstab file..." -NoNewLine
|
||||
|
||||
New-Item c:\ProxSpace\msys2\etc\fstab -type file -force -value "# For a description of the file format, see the Users Guide`n# http://cygwin.com/cygwin-ug-net/using.html#mount-table`nnone / cygdrive binary,posix=0,noacl,user 0 0 `nC:\ProxSpace\pm3 /pm3 ntfs noacl 0 0 `nC:\ProxSpace\gcc-arm-none-eabi /gcc-arm-none-eabi ntfs noacl 0 0 `n"
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
|
||||
Write-Host "Update msys2 packages..."
|
||||
|
||||
$env:Path = "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path"
|
||||
|
||||
Function ExecUpdate($Name, $Cmd, $ErrorLine) {
|
||||
|
||||
Write-Host "Exec [$Name]... " -NoNewLine
|
||||
#--- begin Job
|
||||
|
||||
$Job = Start-Job -Name "$Name" -ScriptBlock {
|
||||
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
|
||||
Set-Location $using:PWD
|
||||
|
||||
$sb=[scriptblock]::Create("$using:Cmd")
|
||||
#execute scriptblock
|
||||
$Cond=&$sb
|
||||
|
||||
return $Cond
|
||||
}
|
||||
|
||||
#--- end Job
|
||||
$WSLjob = Start-Job -Name WSLInstall -ScriptBlock {
|
||||
Function WSLExec($Text, $Cmd) {
|
||||
Write-Host "$Text"
|
||||
wsl -- bash -c $Cmd
|
||||
Write-Host "$Text" -NoNewLine
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
}
|
||||
|
||||
$JobTime=[System.Environment]::TickCount
|
||||
$WSLInstallTime=[System.Environment]::TickCount
|
||||
WSLExec "WSL update..." "sudo apt-get update 1>/dev/null"
|
||||
WSLExec "WSL upgrade..." "sudo apt-get upgrade -y 1>/dev/null"
|
||||
WSLExec "WSL cleanup..." "sudo apt-get auto-remove -y 1>/dev/null"
|
||||
WSLExec "WSL install..." "sudo apt-get -y install --reinstall --no-install-recommends git ca-certificates build-essential pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev qtbase5-dev cmake 1>/dev/null"
|
||||
WSLExec "WSL QT fix..." "sudo strip --remove-section=.note.ABI-tag /usr/lib/x86_64-linux-gnu/libQt5Core.so.5"
|
||||
Add-AppveyorMessage -Message "WSL setup took $(([System.Environment]::TickCount-$WSLInstallTime) / 1000) sec" -Category Information
|
||||
New-Item -ItemType "file" -Path "C:\WSL-Finished.txt" -Force | Out-Null
|
||||
}
|
||||
|
||||
$env:PSInstallTime=[System.Environment]::TickCount
|
||||
|
||||
Write-Host "ProxSpace: Removing folder..." -NoNewLine
|
||||
|
||||
cd \
|
||||
|
||||
Remove-Item -Recurse -Force -Path $env:proxspace_path -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
Write-Host "ProxSpace: downloading..." -NoNewLine
|
||||
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
Invoke-WebRequest "$env:proxspace_url" -outfile "$env:proxspace_zip_file"
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
Write-Host "ProxSpace: extracting..." -NoNewLine
|
||||
|
||||
Expand-Archive -LiteralPath "$env:proxspace_zip_file" -DestinationPath "\"
|
||||
|
||||
Remove-Item "$env:proxspace_zip_file"
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
Write-Host "ProxSpace: renaming folder..." -NoNewLine
|
||||
|
||||
Get-ChildItem -Path "\$env:proxspace_zip_folder_name" | Rename-Item -NewName (Split-Path $env:proxspace_path -Leaf)
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Gree
|
||||
|
||||
$psversion = (Select-String -Pattern 'PSVERSION=' -SimpleMatch -Path "$env:proxspace_path\msys2\ps\09-proxspace_setup.post").Line.Split("""")[1]
|
||||
|
||||
Write-Host "ProxSpace version: $psversion" -ForegroundColor Yellow
|
||||
|
||||
GitClone "ProxSpace: Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." $env:appveyor_build_folder
|
||||
|
||||
GitClone "WSL: Cloning repository <$env:appveyor_repo_name> to $env:wsl_git_path ..." $env:wsl_git_path
|
||||
|
||||
|
||||
install:
|
||||
- ps: >-
|
||||
|
||||
Function ExecUpdate($Text, $firstStart) {
|
||||
Write-Host "$Text"
|
||||
|
||||
$PSjob = Start-Job -Name PSInstall -ScriptBlock {
|
||||
cd $env:proxspace_path
|
||||
./runme64.bat -c "exit"
|
||||
}
|
||||
|
||||
$StartTime=[System.Environment]::TickCount
|
||||
Start-Sleep -s 10
|
||||
while($true) {
|
||||
Try {
|
||||
$Res = Receive-Job -Job $Job -Keep 2>&1 6>&1
|
||||
}
|
||||
Catch {
|
||||
$Res = ""
|
||||
Write-host "error in Receive-Job"
|
||||
}
|
||||
|
||||
if ($Res -is "String" -and $Res -like "*$ErrorLine*"){
|
||||
Write-host "Exit by stop phrase" -ForegroundColor Green
|
||||
if ($PSjob.State -eq 'Completed') {
|
||||
Write-Host "$Text" -NoNewLine
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
break
|
||||
}
|
||||
|
||||
if ($Res -is [Object]){
|
||||
[bool]$needexit = $false
|
||||
ForEach($line in $Res){
|
||||
if ($line -like "*$ErrorLine*"){
|
||||
Write-host "Exit by stop phrase [obj]" -ForegroundColor Green
|
||||
$needexit = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ($needexit) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if(Wait-Job $Job -Timeout 5){
|
||||
Write-host "Exit by end job" -ForegroundColor Green
|
||||
if ($PSjob.State -eq 'Failed') {
|
||||
Write-Host "$Text" -NoNewLine
|
||||
Write-Host "[ Failed ]" -ForegroundColor Red
|
||||
break
|
||||
}
|
||||
|
||||
if ([System.Environment]::TickCount-$JobTime -gt 1000000) {
|
||||
if ($firstStart -And (Test-Path "$env:proxspace_path\msys2\etc\pacman.conf.pacnew")) {
|
||||
Start-Sleep -s 5
|
||||
Stop-Job -Job $PSjob
|
||||
Start-Sleep -s 5
|
||||
Write-Host "$Text" -NoNewLine
|
||||
Write-Host "Exit by pacman.conf" -ForegroundColor Green
|
||||
break
|
||||
}
|
||||
|
||||
if ([System.Environment]::TickCount-$StartTime -gt 1000000) {
|
||||
Stop-Job -Job $PSjob
|
||||
Write-Host "$Text" -NoNewLine
|
||||
Write-host "Exit by timeout" -ForegroundColor Yellow
|
||||
break
|
||||
}
|
||||
|
||||
Start-Sleep -s 5
|
||||
Receive-Job -Name WSLInstall -ErrorAction SilentlyContinue
|
||||
}
|
||||
#Receive-Job -Wait -Name PSInstall
|
||||
}
|
||||
|
||||
Remove-Job -Force $Job
|
||||
Function GitClone($Text, $Folder) {
|
||||
Write-Host "$Text" -NoNewLine
|
||||
if(-not $env:appveyor_pull_request_number) {
|
||||
git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $Folder
|
||||
cd $Folder
|
||||
git checkout -qf $env:appveyor_repo_commit
|
||||
} else {
|
||||
git clone -q https://github.com/$env:appveyor_repo_name.git $Folder
|
||||
cd $Folder
|
||||
git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge:
|
||||
git checkout -qf FETCH_HEAD
|
||||
}
|
||||
|
||||
cd C:\ProxSpace\
|
||||
|
||||
C:\ProxSpace\msys2\ps\setup.cmd
|
||||
|
||||
ExecUpdate "update1" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2"
|
||||
|
||||
ExecUpdate "update2" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2"
|
||||
|
||||
Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$CloneTime) / 1000) sec" -Category Information
|
||||
|
||||
Write-Host "Update " -NoNewLine
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
install:
|
||||
}
|
||||
|
||||
Write-Host "ProxSpace: move cache..." -NoNewLine
|
||||
|
||||
New-Item -ItemType Directory -Force -Path "$env:proxspace_path\msys2\var\cache\" | Out-Null
|
||||
|
||||
Copy-Item -Path "$env:proxspace_cache_path\*" -Destination "$env:proxspace_path\msys2\var\cache\" -Force -Recurse -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Gree
|
||||
|
||||
ExecUpdate "ProxSpace: initial msys2 startup..." $true
|
||||
|
||||
ExecUpdate "ProxSpace: installing required packages..." $false
|
||||
|
||||
Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$env:PSInstallTime) / 1000) sec" -Category Information
|
||||
|
||||
build_script:
|
||||
- ps: >-
|
||||
$env:Path="C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;c:\Python38;c:\Python38\Scripts;$env:Path"
|
||||
|
||||
$env:MINGW_HOME="C:\ProxSpace\msys2\mingw32"
|
||||
|
||||
$env:MSYS_HOME="C:\ProxSpace\msys2"
|
||||
|
||||
$env:MSYSTEM="MINGW32"
|
||||
|
||||
$env:MINGW_PREFIX="/mingw32"
|
||||
|
||||
$env:SHELL="/bin/bash"
|
||||
|
||||
$env:MSYSTEM_CHOST="i686-w64-mingw32"
|
||||
|
||||
cd C:\ProxSpace\pm3
|
||||
|
||||
Write-Host "---------- make ----------" -ForegroundColor Yellow
|
||||
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
|
||||
#make
|
||||
|
||||
bash -c -i 'echo $PATH;pwd;make clean;make V=1'
|
||||
|
||||
|
||||
#some checks
|
||||
|
||||
if(!(Test-Path C:\ProxSpace\pm3\client\proxmark3.exe)){
|
||||
|
||||
throw "Main file proxmark3.exe not exists."
|
||||
$pmfolder = Split-Path $env:appveyor_build_folder -Leaf
|
||||
|
||||
Function ExecMinGWCmd($Cmd) {
|
||||
cd $env:proxspace_path
|
||||
./runme64.bat -c "cd $pmfolder && $Cmd"
|
||||
}
|
||||
|
||||
cd c:\ProxSpace\pm3
|
||||
|
||||
bash -c -i 'make check'
|
||||
|
||||
Function ExecCheck($Name) {
|
||||
$testspass = ($LASTEXITCODE -eq 0)
|
||||
|
||||
$global:TestsPassed=$testspass
|
||||
|
||||
if ($testspass) {
|
||||
Add-AppveyorTest -Name "make Tests" -Framework NUnit -Filename "make check" -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "make Tests [ OK ]" -ForegroundColor Green
|
||||
Add-AppveyorTest -Name $Name -Framework NUnit -Filename $Name -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "$Name [ OK ]" -ForegroundColor Green
|
||||
} else {
|
||||
Add-AppveyorTest -Name "make Tests" -Framework NUnit -Filename "make check" -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "make Tests [ ERROR ]" -ForegroundColor Red
|
||||
Add-AppveyorTest -Name $Name -Framework NUnit -Filename $Name -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "$Name [ ERROR ]" -ForegroundColor Red
|
||||
throw "Tests error."
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "---------- btaddon ----------" -ForegroundColor Yellow
|
||||
$WSLjob = Start-Job -Name WSLCompile -ScriptBlock {
|
||||
Function ExecWSLCmd($Cmd) {
|
||||
cd $env:wsl_git_path
|
||||
wsl -- bash -c $Cmd
|
||||
}
|
||||
|
||||
Function ExecCheck($Name) {
|
||||
$testspass = ($LASTEXITCODE -eq 0)
|
||||
|
||||
$global:TestsPassed=$testspass
|
||||
|
||||
if ($testspass) {
|
||||
Add-AppveyorTest -Name $Name -Framework NUnit -Filename $Name -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "$Name [ OK ]" -ForegroundColor Green
|
||||
} else {
|
||||
Add-AppveyorTest -Name $Name -Framework NUnit -Filename $Name -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "$Name [ ERROR ]" -ForegroundColor Red
|
||||
throw "Tests error."
|
||||
}
|
||||
}
|
||||
|
||||
#WSL: wait for installation to finish
|
||||
if(!(Test-Path "C:\WSL-Finished.txt")){
|
||||
Write-Host "Waiting for WSL installation to finish..." -NoNewLine
|
||||
while(!(Test-Path "C:\WSL-Finished.txt")) {
|
||||
Start-Sleep -s 5
|
||||
}
|
||||
Remove-Item -Force "C:\WSL-Finished.txt" -ErrorAction SilentlyContinue
|
||||
Write-Host "$Name [ OK ]" -ForegroundColor Green
|
||||
}
|
||||
|
||||
#Windows Subsystem for Linux (WSL)
|
||||
Write-Host "---------- WSL make ----------" -ForegroundColor Yellow
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
ExecWSLCmd "make clean;make V=1"
|
||||
#some checks
|
||||
if(!(Test-Path "$env:wsl_git_path\client\proxmark3")){
|
||||
throw "Main file proxmark3 not exists."
|
||||
}
|
||||
|
||||
ExecWSLCmd "make check"
|
||||
ExecCheck "WSL make Tests"
|
||||
Start-Sleep -s 2
|
||||
Write-Host "---------- WSL btaddon ----------" -ForegroundColor Yellow
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
ExecWSLCmd "make clean;make V=1 PLATFORM_EXTRAS=BTADDON"
|
||||
ExecWSLCmd "make check"
|
||||
ExecCheck "WSL BTaddon Tests"
|
||||
Start-Sleep -s 2
|
||||
Write-Host "---------- WSL make clean ----------" -ForegroundColor Yellow
|
||||
ExecWSLCmd 'make clean'
|
||||
Write-Host "---------- WSL cmake ----------" -ForegroundColor Yellow
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
ExecWSLCmd 'mkdir -p client/build; cd client/build; cmake ..; make VERBOSE=1;'
|
||||
Write-Host "---------- WSL cmake tests ----------" -ForegroundColor Yellow
|
||||
ExecWSLCmd './tools/pm3_tests.sh --clientbin client/build/proxmark3 client'
|
||||
ExecCheck "WSL cmake Tests"
|
||||
}
|
||||
|
||||
#ProxSpace
|
||||
|
||||
Write-Host "ProxSpace: create new cache..." -NoNewLine
|
||||
|
||||
cd $env:proxspace_path
|
||||
|
||||
./runme64.bat -c "yes | pacman -Sc > /dev/null 2>&1"
|
||||
|
||||
Remove-Item -Recurse -Force -Path "$env:proxspace_cache_path" -ErrorAction SilentlyContinue
|
||||
|
||||
Move-Item -Path "$env:proxspace_path\msys2\var\cache" -Destination "$env:proxspace_cache_path" -Force
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Gree
|
||||
|
||||
Write-Host "---------- PS make ----------" -ForegroundColor Yellow
|
||||
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
|
||||
bash -c -i 'pwd;make clean;make PLATFORM_EXTRAS=BTADDON'
|
||||
ExecMinGWCmd "make clean;make V=1"
|
||||
|
||||
cd c:\ProxSpace\pm3
|
||||
if(!(Test-Path "$env:proxspace_home_path\$pmfolder\client\proxmark3.exe")){
|
||||
|
||||
bash -c -i 'make check'
|
||||
throw "Main file proxmark3.exe not exists."
|
||||
|
||||
$testspass = ($LASTEXITCODE -eq 0)
|
||||
|
||||
$global:TestsPassed=(($global:TestsPassed) -and ($testspass))
|
||||
|
||||
if ($testspass) {
|
||||
Add-AppveyorTest -Name "BTaddon Tests" -Framework NUnit -Filename "make check" -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "BTaddon Tests [ OK ]" -ForegroundColor Green
|
||||
} else {
|
||||
Add-AppveyorTest -Name "BTaddon Tests" -Framework NUnit -Filename "make check" -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "BTaddon Tests [ ERROR ]" -ForegroundColor Red
|
||||
}
|
||||
|
||||
Write-Host "---------- make clean ----------" -ForegroundColor Yellow
|
||||
ExecMinGWCmd 'make check'
|
||||
|
||||
bash -c -i 'make clean'
|
||||
ExecCheck "PS make Tests"
|
||||
|
||||
Write-Host "---------- cmake ----------" -ForegroundColor Yellow
|
||||
Write-Host "---------- PS btaddon ----------" -ForegroundColor Yellow
|
||||
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
|
||||
cmd.exe /c 'C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start -c "mkdir -p client/build; cd client/build; cmake -G""MSYS Makefiles"" ..; make VERBOSE=1;"'
|
||||
ExecMinGWCmd 'make clean;make V=1 PLATFORM_EXTRAS=BTADDON'
|
||||
|
||||
Write-Host "---------- cmake tests ----------" -ForegroundColor Yellow
|
||||
ExecMinGWCmd 'make check'
|
||||
|
||||
cd c:\ProxSpace\pm3
|
||||
ExecCheck "PS BTaddon Tests"
|
||||
|
||||
bash -c -i './tools/pm3_tests.sh --clientbin client/build/proxmark3.exe client'
|
||||
Write-Host "---------- PS make clean ----------" -ForegroundColor Yellow
|
||||
|
||||
$testspass = ($LASTEXITCODE -eq 0)
|
||||
ExecMinGWCmd 'make clean'
|
||||
|
||||
$global:TestsPassed=(($global:TestsPassed) -and ($testspass))
|
||||
Write-Host "---------- PS cmake ----------" -ForegroundColor Yellow
|
||||
|
||||
if ($testspass) {
|
||||
Add-AppveyorTest -Name "cmake Tests" -Framework NUnit -Filename "make client/check" -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "cmake Tests [ OK ]" -ForegroundColor Green
|
||||
} else {
|
||||
Add-AppveyorTest -Name "cmake Tests" -Framework NUnit -Filename "make client/check" -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)"
|
||||
Write-Host "cmake Tests [ ERROR ]" -ForegroundColor Red
|
||||
}
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
|
||||
ExecMinGWCmd 'mkdir -p client/build; cd client/build; cmake -G""MSYS Makefiles"" ..; make VERBOSE=1;'
|
||||
|
||||
Write-Host "---------- PS cmake tests ----------" -ForegroundColor Yellow
|
||||
|
||||
ExecMinGWCmd './tools/pm3_tests.sh --clientbin client/build/proxmark3.exe client'
|
||||
|
||||
ExecCheck "PS cmake Tests"
|
||||
|
||||
Receive-Job -Wait -Name WSLInstall -ErrorAction SilentlyContinue
|
||||
|
||||
Receive-Job -Wait -Job $WSLjob
|
||||
|
||||
test_script:
|
||||
- ps: >-
|
||||
|
|
191
armsrc/BigBuf.c
191
armsrc/BigBuf.c
|
@ -22,29 +22,56 @@ extern uint8_t _stack_start, __bss_end__;
|
|||
static uint8_t *BigBuf = &__bss_end__;
|
||||
|
||||
/* BigBuf memory layout:
|
||||
Pointer to highest available memory: BigBuf_hi
|
||||
high BigBuf_size
|
||||
reserved = BigBuf_malloc() subtracts amount from BigBuf_hi,
|
||||
Pointer to highest available memory: s_bigbuf_hi
|
||||
high s_bigbuf_size
|
||||
reserved = BigBuf_malloc() subtracts amount from s_bigbuf_hi,
|
||||
low 0x00
|
||||
*/
|
||||
|
||||
static uint32_t BigBuf_size = 0;
|
||||
static uint32_t s_bigbuf_size = 0;
|
||||
|
||||
// High memory mark
|
||||
static uint32_t BigBuf_hi = 0;
|
||||
static uint32_t s_bigbuf_hi = 0;
|
||||
|
||||
// pointer to the emulator memory.
|
||||
static uint8_t *emulator_memory = NULL;
|
||||
|
||||
//=============================================================================
|
||||
// The ToSend buffer.
|
||||
// A buffer where we can queue things up to be sent through the FPGA, for
|
||||
// any purpose (fake tag, as reader, whatever). We go MSB first, since that
|
||||
// is the order in which they go out on the wire.
|
||||
//=============================================================================
|
||||
static tosend_t toSend = {
|
||||
.max = -1,
|
||||
.bit = 8,
|
||||
.buf = NULL
|
||||
};
|
||||
//=============================================================================
|
||||
// The dmaBuf 16bit buffer.
|
||||
// A buffer where we recive IQ samples sent from the FPGA, for demodulating
|
||||
//=============================================================================
|
||||
static dmabuf16_t dma_16 = {
|
||||
.size = DMA_BUFFER_SIZE,
|
||||
.buf = NULL
|
||||
};
|
||||
// dmaBuf 8bit buffer
|
||||
static dmabuf8_t dma_8 = {
|
||||
.size = DMA_BUFFER_SIZE,
|
||||
.buf = NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
// trace related variables
|
||||
static uint32_t traceLen = 0;
|
||||
static uint32_t trace_len = 0;
|
||||
static bool tracing = true;
|
||||
|
||||
// compute the available size for BigBuf
|
||||
void BigBuf_initialize(void) {
|
||||
BigBuf_size = (uint32_t)&_stack_start - (uint32_t)&__bss_end__;
|
||||
BigBuf_hi = BigBuf_size;
|
||||
traceLen = 0;
|
||||
s_bigbuf_size = (uint32_t)&_stack_start - (uint32_t)&__bss_end__;
|
||||
s_bigbuf_hi = s_bigbuf_size;
|
||||
trace_len = 0;
|
||||
}
|
||||
|
||||
// get the address of BigBuf
|
||||
|
@ -53,7 +80,7 @@ uint8_t *BigBuf_get_addr(void) {
|
|||
}
|
||||
|
||||
uint32_t BigBuf_get_size(void) {
|
||||
return BigBuf_size;
|
||||
return s_bigbuf_size;
|
||||
}
|
||||
|
||||
// get the address of the emulator memory. Allocate part of Bigbuf for it, if not yet done
|
||||
|
@ -64,6 +91,11 @@ uint8_t *BigBuf_get_EM_addr(void) {
|
|||
|
||||
return emulator_memory;
|
||||
}
|
||||
/*
|
||||
uint32_t BigBuf_get_EM_size(void) {
|
||||
return CARD_MEMORY_SIZE;
|
||||
}
|
||||
*/
|
||||
|
||||
// clear ALL of BigBuf
|
||||
void BigBuf_Clear(void) {
|
||||
|
@ -72,9 +104,10 @@ void BigBuf_Clear(void) {
|
|||
|
||||
// clear ALL of BigBuf
|
||||
void BigBuf_Clear_ext(bool verbose) {
|
||||
memset(BigBuf, 0, BigBuf_size);
|
||||
memset(BigBuf, 0, s_bigbuf_size);
|
||||
clear_trace();
|
||||
if (verbose)
|
||||
Dbprintf("Buffer cleared (%i bytes)", BigBuf_size);
|
||||
Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size);
|
||||
}
|
||||
|
||||
void BigBuf_Clear_EM(void) {
|
||||
|
@ -82,57 +115,66 @@ void BigBuf_Clear_EM(void) {
|
|||
}
|
||||
|
||||
void BigBuf_Clear_keep_EM(void) {
|
||||
memset(BigBuf, 0, BigBuf_hi);
|
||||
memset(BigBuf, 0, s_bigbuf_hi);
|
||||
}
|
||||
|
||||
// allocate a chunk of memory from BigBuf. We allocate high memory first. The unallocated memory
|
||||
// at the beginning of BigBuf is always for traces/samples
|
||||
uint8_t *BigBuf_malloc(uint16_t chunksize) {
|
||||
if (BigBuf_hi < chunksize)
|
||||
if (s_bigbuf_hi < chunksize)
|
||||
return NULL; // no memory left
|
||||
|
||||
chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4
|
||||
BigBuf_hi -= chunksize; // aligned to 4 Byte boundary
|
||||
return (uint8_t *)BigBuf + BigBuf_hi;
|
||||
s_bigbuf_hi -= chunksize; // aligned to 4 Byte boundary
|
||||
return (uint8_t *)BigBuf + s_bigbuf_hi;
|
||||
}
|
||||
|
||||
// free ALL allocated chunks. The whole BigBuf is available for traces or samples again.
|
||||
void BigBuf_free(void) {
|
||||
BigBuf_hi = BigBuf_size;
|
||||
s_bigbuf_hi = s_bigbuf_size;
|
||||
emulator_memory = NULL;
|
||||
// shouldn't this empty BigBuf also?
|
||||
toSend.buf = NULL;
|
||||
dma_16.buf = NULL;
|
||||
dma_8.buf = NULL;
|
||||
}
|
||||
|
||||
// free allocated chunks EXCEPT the emulator memory
|
||||
void BigBuf_free_keep_EM(void) {
|
||||
if (emulator_memory != NULL)
|
||||
BigBuf_hi = emulator_memory - (uint8_t *)BigBuf;
|
||||
s_bigbuf_hi = emulator_memory - (uint8_t *)BigBuf;
|
||||
else
|
||||
BigBuf_hi = BigBuf_size;
|
||||
s_bigbuf_hi = s_bigbuf_size;
|
||||
|
||||
// shouldn't this empty BigBuf also?
|
||||
toSend.buf = NULL;
|
||||
dma_16.buf = NULL;
|
||||
dma_8.buf = NULL;
|
||||
}
|
||||
|
||||
void BigBuf_print_status(void) {
|
||||
DbpString(_CYAN_("Memory"));
|
||||
Dbprintf(" BigBuf_size.............%d", BigBuf_size);
|
||||
Dbprintf(" Available memory........%d", BigBuf_hi);
|
||||
Dbprintf(" BigBuf_size.............%d", s_bigbuf_size);
|
||||
Dbprintf(" Available memory........%d", s_bigbuf_hi);
|
||||
DbpString(_CYAN_("Tracing"));
|
||||
Dbprintf(" tracing ................%d", tracing);
|
||||
Dbprintf(" traceLen ...............%d", traceLen);
|
||||
Dbprintf(" traceLen ...............%d", trace_len);
|
||||
|
||||
Dbprintf(" dma8 memory.............%d", dma_8.buf - BigBuf_get_addr());
|
||||
Dbprintf(" dma16 memory............%d", (uint8_t *)dma_16.buf - BigBuf_get_addr());
|
||||
Dbprintf(" toSend memory...........%d", toSend.buf - BigBuf_get_addr());
|
||||
}
|
||||
|
||||
// return the maximum trace length (i.e. the unallocated size of BigBuf)
|
||||
uint16_t BigBuf_max_traceLen(void) {
|
||||
return BigBuf_hi;
|
||||
return s_bigbuf_hi;
|
||||
}
|
||||
|
||||
void clear_trace(void) {
|
||||
traceLen = 0;
|
||||
trace_len = 0;
|
||||
}
|
||||
|
||||
void set_tracelen(uint32_t value) {
|
||||
traceLen = value;
|
||||
trace_len = value;
|
||||
}
|
||||
|
||||
void set_tracing(bool enable) {
|
||||
|
@ -148,7 +190,7 @@ bool get_tracing(void) {
|
|||
* @return
|
||||
*/
|
||||
uint32_t BigBuf_get_traceLen(void) {
|
||||
return traceLen;
|
||||
return trace_len;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -158,16 +200,18 @@ uint32_t BigBuf_get_traceLen(void) {
|
|||
annotation of commands/responses.
|
||||
**/
|
||||
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag) {
|
||||
if (!tracing) return false;
|
||||
if (tracing == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t *trace = BigBuf_get_addr();
|
||||
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + traceLen);
|
||||
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + trace_len);
|
||||
|
||||
uint32_t num_paritybytes = (iLen - 1) / 8 + 1; // number of valid paritybytes in *parity
|
||||
|
||||
// Return when trace is full
|
||||
if (TRACELOG_HDR_LEN + iLen + num_paritybytes >= BigBuf_max_traceLen() - traceLen) {
|
||||
tracing = false; // don't trace any more
|
||||
if (TRACELOG_HDR_LEN + iLen + num_paritybytes >= BigBuf_max_traceLen() - trace_len) {
|
||||
tracing = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -178,39 +222,48 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_
|
|||
duration = (UINT32_MAX - timestamp_start) + timestamp_end;
|
||||
}
|
||||
|
||||
if (duration > 0x7FFF) {
|
||||
if (duration > 0xFFFF) {
|
||||
/*
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Error in LogTrace: duration too long for 15 bits encoding: 0x%08x start:0x%08x end:0x%08x", duration, timestamp_start, timestamp_end);
|
||||
Dbprintf("Forcing duration = 0");
|
||||
Dbprintf("Error in LogTrace: duration too long for 16 bits encoding: 0x%08x start: 0x%08x end: 0x%08x", duration, timestamp_start, timestamp_end);
|
||||
}
|
||||
*/
|
||||
duration = 0;
|
||||
}
|
||||
|
||||
hdr->timestamp = timestamp_start;
|
||||
hdr->duration = duration;
|
||||
hdr->duration = duration & 0xFFFF;
|
||||
hdr->data_len = iLen;
|
||||
hdr->isResponse = !readerToTag;
|
||||
traceLen += TRACELOG_HDR_LEN;
|
||||
trace_len += TRACELOG_HDR_LEN;
|
||||
|
||||
// data bytes
|
||||
if (btBytes != NULL && iLen != 0) {
|
||||
memcpy(trace + traceLen, btBytes, iLen);
|
||||
memcpy(hdr->frame, btBytes, iLen);
|
||||
trace_len += iLen;
|
||||
}
|
||||
traceLen += iLen;
|
||||
|
||||
// parity bytes
|
||||
if (num_paritybytes != 0) {
|
||||
if (parity != NULL) {
|
||||
memcpy(trace + traceLen, parity, num_paritybytes);
|
||||
memcpy(trace + trace_len, parity, num_paritybytes);
|
||||
} else {
|
||||
memset(trace + traceLen, 0x00, num_paritybytes);
|
||||
memset(trace + trace_len, 0x00, num_paritybytes);
|
||||
}
|
||||
trace_len += num_paritybytes;
|
||||
}
|
||||
traceLen += num_paritybytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// specific LogTrace function for ISO15693: the duration needs to be scaled because otherwise it won't fit into a uint16_t
|
||||
bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, uint8_t *parity, bool reader2tag) {
|
||||
uint32_t duration = ts_end - ts_start;
|
||||
duration /= 32;
|
||||
ts_end = ts_start + duration;
|
||||
return LogTrace(bytes, len, ts_start, ts_end, parity, reader2tag);
|
||||
}
|
||||
|
||||
|
||||
// Emulator memory
|
||||
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length) {
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
|
@ -221,3 +274,57 @@ uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length) {
|
|||
Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset + length), CARD_MEMORY_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// get the address of the ToSend buffer. Allocate part of Bigbuf for it, if not yet done
|
||||
tosend_t *get_tosend(void) {
|
||||
|
||||
if (toSend.buf == NULL)
|
||||
toSend.buf = BigBuf_malloc(TOSEND_BUFFER_SIZE);
|
||||
|
||||
return &toSend;
|
||||
}
|
||||
|
||||
void tosend_reset(void) {
|
||||
toSend.max = -1;
|
||||
toSend.bit = 8;
|
||||
}
|
||||
|
||||
void tosend_stuffbit(int b) {
|
||||
|
||||
if (toSend.max >= TOSEND_BUFFER_SIZE - 1) {
|
||||
Dbprintf(_RED_("toSend overflow"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (toSend.bit >= 8) {
|
||||
toSend.max++;
|
||||
toSend.buf[toSend.max] = 0;
|
||||
toSend.bit = 0;
|
||||
}
|
||||
|
||||
if (b)
|
||||
toSend.buf[toSend.max] |= (1 << (7 - toSend.bit));
|
||||
|
||||
toSend.bit++;
|
||||
|
||||
if (toSend.max >= TOSEND_BUFFER_SIZE) {
|
||||
toSend.bit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dmabuf16_t *get_dma16(void) {
|
||||
if (dma_16.buf == NULL)
|
||||
dma_16.buf = (uint16_t *)BigBuf_malloc(DMA_BUFFER_SIZE * sizeof(uint16_t));
|
||||
|
||||
return &dma_16;
|
||||
}
|
||||
|
||||
dmabuf8_t *get_dma8(void) {
|
||||
if (dma_8.buf == NULL)
|
||||
dma_8.buf = BigBuf_malloc(DMA_BUFFER_SIZE);
|
||||
|
||||
return &dma_8;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,10 @@
|
|||
#define MAX_MIFARE_FRAME_SIZE 18 // biggest Mifare frame is answer to a read (one block = 16 Bytes) + 2 Bytes CRC
|
||||
#define MAX_MIFARE_PARITY_SIZE 3 // need 18 parity bits for the 18 Byte above. 3 Bytes are enough to store these
|
||||
#define CARD_MEMORY_SIZE 4096
|
||||
#define DMA_BUFFER_SIZE 256 //128 (how big is the dma?!?
|
||||
#define DMA_BUFFER_SIZE 256
|
||||
|
||||
// 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits
|
||||
#define TOSEND_BUFFER_SIZE (9 * MAX_FRAME_SIZE + 1 + 1 + 2)
|
||||
|
||||
uint8_t *BigBuf_get_addr(void);
|
||||
uint32_t BigBuf_get_size(void);
|
||||
|
@ -39,7 +42,34 @@ void clear_trace(void);
|
|||
void set_tracing(bool enable);
|
||||
void set_tracelen(uint32_t value);
|
||||
bool get_tracing(void);
|
||||
|
||||
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
|
||||
bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, uint8_t *parity, bool reader2tag);
|
||||
|
||||
|
||||
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length);
|
||||
|
||||
|
||||
typedef struct {
|
||||
int max;
|
||||
int bit;
|
||||
uint8_t *buf;
|
||||
} tosend_t;
|
||||
|
||||
tosend_t *get_tosend(void);
|
||||
void tosend_reset(void);
|
||||
void tosend_stuffbit(int b);
|
||||
|
||||
typedef struct {
|
||||
uint16_t size;
|
||||
uint8_t *buf;
|
||||
} dmabuf8_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t size;
|
||||
uint16_t *buf;
|
||||
} dmabuf16_t;
|
||||
|
||||
dmabuf8_t *get_dma8(void);
|
||||
dmabuf16_t *get_dma16(void);
|
||||
#endif /* __BIGBUF_H */
|
||||
|
|
|
@ -30,7 +30,7 @@ SRC_ISO14443b = iso14443b.c
|
|||
SRC_FELICA = felica.c
|
||||
SRC_CRAPTO1 = crypto1.c des.c desfire_crypto.c mifaredesfire.c aes.c platform_util.c
|
||||
SRC_CRC = crc.c crc16.c crc32.c
|
||||
SRC_ICLASS = iclass.c optimized_cipher.c
|
||||
SRC_ICLASS = iclass.c optimized_cipherutils.c optimized_ikeys.c optimized_elite.c optimized_cipher.c
|
||||
SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c
|
||||
SRC_NFCBARCODE = thinfilm.c
|
||||
|
||||
|
@ -79,7 +79,7 @@ endif
|
|||
include Standalone/Makefile.inc
|
||||
|
||||
#the FPGA bitstream files. Note: order matters!
|
||||
FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit
|
||||
FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit fpga_felica.bit
|
||||
|
||||
#the lz4 source files required for decompressing the fpga config at run time
|
||||
SRC_LZ4 = lz4.c
|
||||
|
|
|
@ -38,12 +38,18 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| HF_14ASNIFF | 14a sniff to flashmem |
|
||||
| (RDV4 only) | |
|
||||
+----------------------------------------------------------+
|
||||
| HF_AVEFUL | Mifare ultralight read/simulation |
|
||||
| | - Ave Ozkal |
|
||||
+----------------------------------------------------------+
|
||||
| HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth |
|
||||
| (RDV4 only) | storing in flashmem - Bogito |
|
||||
+----------------------------------------------------------+
|
||||
| HF_COLIN | Mifare ultra fast sniff/sim/clone |
|
||||
| (RDV4 only) | - Colin Brigato |
|
||||
+----------------------------------------------------------+
|
||||
| HF_ICECLASS | Simulate HID iCLASS legacy ags |
|
||||
| (RDV4 only) | storing in flashmem |
|
||||
+----------------------------------------------------------+
|
||||
| HF_LEGIC | Read/simulate Legic Prime tags |
|
||||
| | storing in flashmem |
|
||||
+----------------------------------------------------------+
|
||||
|
@ -59,9 +65,9 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
endef
|
||||
|
||||
STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_BOG HF_COLIN HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_YOUNG
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_AVEFUL HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_YOUNG
|
||||
STANDALONE_MODES_REQ_SMARTCARD :=
|
||||
STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN
|
||||
STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
|
||||
STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE)
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),)
|
||||
|
|
|
@ -37,6 +37,10 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_14ASNIFF,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_14asniff.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_AVEFUL
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_AVEFUL,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_aveful.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_ICEHID
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_ICEHID,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_icehid.c
|
||||
|
@ -57,7 +61,11 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_LEGIC,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_legic.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_MSDSAL
|
||||
# WITH_STANDALONE_HF_MSDSAL
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_MSDSAL,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_msdsal.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_ICECLASS
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_iceclass.c
|
||||
endif
|
||||
|
|
258
armsrc/Standalone/hf_aveful.c
Normal file
258
armsrc/Standalone/hf_aveful.c
Normal file
|
@ -0,0 +1,258 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// A. Ozkal, 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 HF Mifare Ultralight read/simulation by Ave Ozkal
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Several parts of this code is based on code by Craig Young from HF_YOUNG
|
||||
|
||||
// This code does not:
|
||||
// - Account for cards with non-default keys on authentication (MFU EV1 etc)
|
||||
|
||||
// This code is designed to work with:
|
||||
// - MIFARE Ultralight
|
||||
// - MIFARE Ultralight EV1 (default keys)
|
||||
// - MIFARE Ultralight Nano (untested, but should work)
|
||||
// - Infineon My-d Move (without password set)
|
||||
// - Infineon My-d Move Lean
|
||||
// - Any other Ultralight clones that have no auth and MAX_DEFAULT_BLOCKS (16) blocks
|
||||
|
||||
#include "standalone.h" // standalone definitions
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "util.h"
|
||||
#include "dbprint.h"
|
||||
|
||||
#include "ticks.h" // SpinDelay
|
||||
#include "protocols.h" // MIFARE_ULEV1_VERSION, MIFARE_ULEV1_READSIG, MIFARE_ULEV1_READ_CNT, MIFARE_ULEV1_CHECKTEAR
|
||||
#include <string.h> // memcmp
|
||||
#include "mifareutil.h"
|
||||
#include "iso14443a.h"
|
||||
|
||||
#define SAK 0x00
|
||||
#define ATQA0 0x44
|
||||
#define ATQA1 0x00
|
||||
|
||||
#define STATE_SEARCH 0
|
||||
#define STATE_READ 1
|
||||
#define STATE_EMUL 2
|
||||
|
||||
// Taken from cmdhfmfu.c, increased by 01h to be 1 indexed
|
||||
#define MAX_UL_BLOCKS 0x10
|
||||
#define MAX_UL_NANO_40 0x0B
|
||||
#define MAX_ULEV1a_BLOCKS 0x14
|
||||
#define MAX_ULEV1b_BLOCKS 0x29
|
||||
#define MAX_MY_D_MOVE 0x26
|
||||
#define MAX_MY_D_MOVE_LEAN 0x10
|
||||
#define MAX_DEFAULT_BLOCKS 0x10
|
||||
|
||||
typedef struct {
|
||||
uint8_t uid[10];
|
||||
uint8_t uidlen;
|
||||
uint8_t atqa[2];
|
||||
uint8_t sak;
|
||||
} PACKED card_clone_t;
|
||||
|
||||
int get_block_count(iso14a_card_select_t card, uint8_t version[], uint16_t version_len);
|
||||
uint16_t get_ev1_version(iso14a_card_select_t card, uint8_t *version);
|
||||
uint16_t get_ev1_signature(iso14a_card_select_t card, uint8_t *signature);
|
||||
uint16_t get_ev1_counter(iso14a_card_select_t card, uint8_t counter, uint8_t *response);
|
||||
uint16_t get_ev1_tearing(iso14a_card_select_t card, uint8_t counter, uint8_t *response);
|
||||
|
||||
uint16_t get_ev1_version(iso14a_card_select_t card, uint8_t *version) {
|
||||
return mifare_sendcmd(MIFARE_ULEV1_VERSION, NULL, 0, version, NULL, NULL);
|
||||
}
|
||||
|
||||
uint16_t get_ev1_signature(iso14a_card_select_t card, uint8_t *response) {
|
||||
uint8_t cmd[4] = {MIFARE_ULEV1_READSIG, 0x00, 0x00, 0x00};
|
||||
AddCrc14A(cmd, 2);
|
||||
ReaderTransmit(cmd, sizeof(cmd), NULL);
|
||||
return ReaderReceive(response, NULL);
|
||||
}
|
||||
|
||||
uint16_t get_ev1_counter(iso14a_card_select_t card, uint8_t counter, uint8_t *response) {
|
||||
uint8_t cmd[4] = {MIFARE_ULEV1_READ_CNT, counter, 0x00, 0x00};
|
||||
AddCrc14A(cmd, 2);
|
||||
ReaderTransmit(cmd, sizeof(cmd), NULL);
|
||||
return ReaderReceive(response, NULL);
|
||||
}
|
||||
|
||||
uint16_t get_ev1_tearing(iso14a_card_select_t card, uint8_t counter, uint8_t *response) {
|
||||
uint8_t cmd[4] = {MIFARE_ULEV1_CHECKTEAR, counter, 0x00, 0x00};
|
||||
AddCrc14A(cmd, 2);
|
||||
ReaderTransmit(cmd, sizeof(cmd), NULL);
|
||||
return ReaderReceive(response, NULL);
|
||||
}
|
||||
|
||||
int get_block_count(iso14a_card_select_t card, uint8_t version[], uint16_t version_len) {
|
||||
// Default to MAX_DEFAULT_BLOCKS blocks
|
||||
int block_count = MAX_DEFAULT_BLOCKS;
|
||||
// Most of this code is from cmdhfmfu.c
|
||||
// Infineon manufacturer ID
|
||||
if (card.uid[0] == 0x05) {
|
||||
// Infinition MY-D tests Exam high nibble
|
||||
uint8_t nib = (card.uid[1] & 0xf0) >> 4;
|
||||
switch (nib) {
|
||||
case 3:
|
||||
block_count = MAX_MY_D_MOVE;
|
||||
break; // or SLE 66R01P // 38 pages of 4 bytes
|
||||
case 7:
|
||||
block_count = MAX_MY_D_MOVE_LEAN;
|
||||
break; // or SLE 66R01L // 16 pages of 4 bytes
|
||||
}
|
||||
} else {
|
||||
// Moved this from case to if as I only care about non-ultralight ev0.
|
||||
if (version_len == 0x0A) {
|
||||
if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0B", 7) == 0) { block_count = MAX_ULEV1a_BLOCKS; }
|
||||
else if (memcmp(version, "\x00\x04\x03\x01\x02\x00\x0B", 7) == 0) { block_count = MAX_UL_NANO_40; }
|
||||
else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0B", 7) == 0) { block_count = MAX_ULEV1a_BLOCKS; }
|
||||
else if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0E", 7) == 0) { block_count = MAX_ULEV1b_BLOCKS; }
|
||||
else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { block_count = MAX_ULEV1b_BLOCKS; }
|
||||
else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { block_count = MAX_ULEV1b_BLOCKS; } // Mikron JSC Russia EV1 41 pages tag
|
||||
else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { block_count = MAX_UL_BLOCKS; }
|
||||
else if (version[2] == 0x03) { block_count = MAX_ULEV1a_BLOCKS; }
|
||||
}
|
||||
}
|
||||
|
||||
return block_count;
|
||||
}
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" HF Mifare Ultralight read/simulation by Ave Ozkal");
|
||||
}
|
||||
|
||||
void RunMod(void) {
|
||||
StandAloneMode();
|
||||
Dbprintf("AveFUL (MF Ultralight read/emul) started");
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
// the main loop for your standalone mode
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
// exit from RunMod, send a usbcommand.
|
||||
if (data_available()) break;
|
||||
|
||||
iso14a_card_select_t card;
|
||||
|
||||
SpinDelay(500);
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
// 0 = search, 1 = read, 2 = emul
|
||||
int state = STATE_SEARCH;
|
||||
|
||||
DbpString("Scanning...");
|
||||
int button_pressed = BUTTON_NO_CLICK;
|
||||
for (;;) {
|
||||
// Was our button held down or pressed?
|
||||
button_pressed = BUTTON_HELD(1000);
|
||||
|
||||
if (button_pressed != BUTTON_NO_CLICK || data_available())
|
||||
break;
|
||||
else if (state == STATE_SEARCH) {
|
||||
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, true)) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
SpinDelay(500);
|
||||
continue;
|
||||
} else {
|
||||
if (card.sak == SAK && card.atqa[0] == ATQA0 && card.atqa[1] == ATQA1 && card.uidlen == 7) {
|
||||
DbpString("Found ultralight with UID: ");
|
||||
Dbhexdump(card.uidlen, card.uid, 0);
|
||||
state = STATE_READ;
|
||||
} else {
|
||||
DbpString("Found non-ultralight card, ignoring.");
|
||||
}
|
||||
}
|
||||
} else if (state == STATE_READ) {
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
iso14443a_select_card(NULL, NULL, NULL, true, 0, true);
|
||||
bool read_successful = true;
|
||||
|
||||
// Get version and re-select card as UL EV0s like to shut off after a 0x60
|
||||
uint8_t version[10] = {0x00};
|
||||
uint16_t version_len = 0;
|
||||
version_len = get_ev1_version(card, version);
|
||||
iso14443a_select_card(NULL, NULL, NULL, true, 0, true);
|
||||
|
||||
int block_count = get_block_count(card, version, version_len);
|
||||
Dbprintf("Card was determined as having %d blocks.", block_count);
|
||||
Dbprintf("Contents:");
|
||||
|
||||
for (int i = 0; i < block_count; i++) {
|
||||
uint8_t dataout[16] = {0x00};
|
||||
if (mifare_ultra_readblock(i, dataout)) {
|
||||
// If there's an error reading, go back to search state
|
||||
read_successful = false;
|
||||
break;
|
||||
}
|
||||
// We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on hf_mfu_dumptoemulator
|
||||
// When converting a bin, it's almost all 0 other than one 0x0F byte, and functionality seems to be unaffected if that byte is set to 0x00.
|
||||
emlSetMem_xt(dataout, 14 + i, 1, 4);
|
||||
Dbhexdump(4, dataout, 0);
|
||||
}
|
||||
|
||||
// It's not the best way to determine this,
|
||||
// but with what I'm trying to support It Should Be Okay
|
||||
bool is_ev1 = (version_len != 0) && (block_count != 16);
|
||||
|
||||
if (read_successful) {
|
||||
uint8_t signature[34] = {0x00};
|
||||
if (is_ev1) {
|
||||
get_ev1_signature(card, signature);
|
||||
}
|
||||
Dbprintf("Preparing emulator memory with:");
|
||||
// Fill first 14 blocks with 0x00 (see comment above)
|
||||
for (int i = 0; i < 14; i++) {
|
||||
uint8_t dataout[4] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
if (is_ev1 && (i == 0 || i == 1)) {
|
||||
// On block 0 and 1, set version on EV1
|
||||
memcpy(dataout, version + (i * 4), 4);
|
||||
} else if (i == 2) {
|
||||
// On block 2, set last byte to the card's block count
|
||||
dataout[3] = block_count;
|
||||
} else if (is_ev1 && ((i > 2 && i < 11))) {
|
||||
// On 3-10 add signature on EV1
|
||||
memcpy(dataout, signature + ((i - 3) * 4), 4);
|
||||
} else if (is_ev1 && (i > 10)) {
|
||||
// On 11-14 read and set counter and tearing on EV1
|
||||
uint8_t counter[5];
|
||||
uint8_t tearing[3];
|
||||
get_ev1_counter(card, i - 11, counter);
|
||||
get_ev1_tearing(card, i - 11, tearing);
|
||||
memcpy(dataout, counter, 3);
|
||||
memcpy(dataout + 3, tearing, 1);
|
||||
}
|
||||
|
||||
Dbhexdump(4, dataout, 0);
|
||||
emlSetMem_xt(dataout, i, 1, 4);
|
||||
}
|
||||
Dbprintf("Successfully loaded into emulator memory...");
|
||||
state = STATE_EMUL;
|
||||
} else {
|
||||
Dbprintf("Read failure, going back to search state.");
|
||||
state = STATE_SEARCH;
|
||||
}
|
||||
} else if (state == STATE_EMUL) {
|
||||
uint8_t flags = FLAG_7B_UID_IN_DATA;
|
||||
|
||||
Dbprintf("Starting simulation, press pm3-button to stop and go back to search state.");
|
||||
SimulateIso14443aTag(7, flags, card.uid);
|
||||
|
||||
// Go back to search state if user presses pm3-button
|
||||
state = STATE_SEARCH;
|
||||
}
|
||||
}
|
||||
if (button_pressed == BUTTON_HOLD) //Holding down the button
|
||||
break;
|
||||
}
|
||||
|
||||
DbpString("exiting");
|
||||
LEDsoff();
|
||||
}
|
|
@ -15,7 +15,7 @@ The retrieved sniffing session can be acquired by connecting the device
|
|||
to a client that supports the reconnect capability and issue 'hf 14a list'.
|
||||
|
||||
In order to view the grabbed authentication attempts in the flash mem,
|
||||
you can simply run 'script run read_pwd_mem' or just 'mem dump p l 256'
|
||||
you can simply run 'script run mem_readpwd' or just 'mem dump p l 256'
|
||||
from the client to view the stored quadlets.
|
||||
*/
|
||||
|
||||
|
@ -249,5 +249,5 @@ void RunMod(void) {
|
|||
LEDsoff();
|
||||
SpinDelay(300);
|
||||
Dbprintf("- [ End ] -> You can take shell back ...");
|
||||
Dbprintf("- [ ! ] -> use 'script run read_pwd_mem_spiffs' to print passwords");
|
||||
Dbprintf("- [ ! ] -> use 'script run data_read_pwd_mem_spiffs' to print passwords");
|
||||
}
|
||||
|
|
|
@ -484,22 +484,18 @@ failtag:
|
|||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
SpinOff(50);
|
||||
LED_A_ON();
|
||||
uint8_t ticker = 0;
|
||||
|
||||
while (!iso14443a_select_card(cjuid, &p_card, &cjcuid, true, 0, true)) {
|
||||
WDT_HIT();
|
||||
|
||||
ticker++;
|
||||
if (ticker % 64 == 0) {
|
||||
LED_A_INV();
|
||||
}
|
||||
|
||||
if (BUTTON_HELD(10) == BUTTON_HOLD) {
|
||||
WDT_HIT();
|
||||
DbprintfEx(FLAG_NEWLINE, "\t\t\t[ READING FLASH ]");
|
||||
ReadLastTagFromFlash();
|
||||
goto readysim;
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(500);
|
||||
LED_A_INV();
|
||||
}
|
||||
|
||||
SpinOff(50);
|
||||
|
|
521
armsrc/Standalone/hf_iceclass.c
Normal file
521
armsrc/Standalone/hf_iceclass.c
Normal file
|
@ -0,0 +1,521 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Christian Herrmann, 2020
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// main code for hf_iceclass by Iceman
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// Created for the live streamed talk 'DEFCON 28 Wireless Village-Omikron and Iceman - Ghosting the PACS-man: New Tools and Techniques'
|
||||
// https://www.youtube.com/watch?v=ghiHXK4GEzE
|
||||
//
|
||||
// I created a youtube video demostrating the HF_ICECLASS standalone mode
|
||||
// https://youtu.be/w_1GnAscNIU
|
||||
//
|
||||
//
|
||||
|
||||
#include "standalone.h" // standalone definitions
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
#include "BigBuf.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "util.h"
|
||||
#include "ticks.h"
|
||||
#include "dbprint.h"
|
||||
#include "spiffs.h"
|
||||
#include "iclass.h"
|
||||
#include "iso15693.h"
|
||||
#include "optimized_cipher.h"
|
||||
#include "pm3_cmd.h"
|
||||
#include "protocols.h"
|
||||
|
||||
|
||||
#define ICE_STATE_NONE 0
|
||||
#define ICE_STATE_FULLSIM 1
|
||||
#define ICE_STATE_ATTACK 2
|
||||
#define ICE_STATE_READER 3
|
||||
#define ICE_STATE_CONFIGCARD 4
|
||||
|
||||
// ====================================================
|
||||
// Select which standalone function to be active.
|
||||
// 4 possiblities. Uncomment the one you wanna use.
|
||||
|
||||
#define ICE_USE ICE_STATE_FULLSIM
|
||||
//#define ICE_USE ICE_STATE_ATTACK
|
||||
//#define ICE_USE ICE_STATE_READER
|
||||
//#define ICE_USE ICE_STATE_CONFIGCARD
|
||||
|
||||
// ====================================================
|
||||
|
||||
|
||||
#define NUM_CSNS 9
|
||||
#define MAC_RESPONSES_SIZE (16 * NUM_CSNS)
|
||||
#define HF_ICLASS_FULLSIM_ORIG_BIN "iceclass-orig.bin"
|
||||
#define HF_ICLASS_FULLSIM_MOD "iceclass-modified"
|
||||
#define HF_ICLASS_FULLSIM_MOD_BIN HF_ICLASS_FULLSIM_MOD".bin"
|
||||
#define HF_ICLASS_FULLSIM_MOD_EML HF_ICLASS_FULLSIM_MOD".eml"
|
||||
#define HF_ICLASS_ATTACK_BIN "iclass_mac_attack"
|
||||
|
||||
#define HF_ICLASS_CC_A "iceclass_cc_a.bin"
|
||||
#define HF_ICLASS_CC_B "iceclass_cc_b.bin"
|
||||
char *cc_files[] = { HF_ICLASS_CC_A, HF_ICLASS_CC_B };
|
||||
|
||||
|
||||
|
||||
// times in ssp_clk_cycles @ 3,3625MHz when acting as reader
|
||||
#ifndef DELAY_ICLASS_VICC_TO_VCD_READER
|
||||
#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER
|
||||
#endif
|
||||
|
||||
#ifndef ICLASS_16KS_SIZE
|
||||
#define ICLASS_16KS_SIZE 0x100 * 8
|
||||
#endif
|
||||
|
||||
// iclass card descriptors
|
||||
char *card_types[] = {
|
||||
"PicoPass 16K / 16", // 000
|
||||
"PicoPass 32K with current book 16K / 16", // 001
|
||||
"Unknown Card Type!", // 010
|
||||
"Unknown Card Type!", // 011
|
||||
"PicoPass 2K", // 100
|
||||
"Unknown Card Type!", // 101
|
||||
"PicoPass 16K / 2", // 110
|
||||
"PicoPass 32K with current book 16K / 2", // 111
|
||||
};
|
||||
|
||||
uint8_t card_app2_limit[] = {
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
0x1f,
|
||||
0xff,
|
||||
0xff,
|
||||
0xff,
|
||||
};
|
||||
|
||||
static uint8_t aa2_key[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
static uint8_t legacy_aa1_key[] = {0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78};
|
||||
|
||||
static bool have_aa2(void) {
|
||||
return memcmp(aa2_key, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 8);
|
||||
}
|
||||
|
||||
static uint8_t get_pagemap(const picopass_hdr *hdr) {
|
||||
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
||||
}
|
||||
|
||||
static uint8_t csns[8 * NUM_CSNS] = {
|
||||
0x01, 0x0A, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
|
||||
0x0C, 0x06, 0x0C, 0xFE, 0xF7, 0xFF, 0x12, 0xE0,
|
||||
0x10, 0x97, 0x83, 0x7B, 0xF7, 0xFF, 0x12, 0xE0,
|
||||
0x13, 0x97, 0x82, 0x7A, 0xF7, 0xFF, 0x12, 0xE0,
|
||||
0x07, 0x0E, 0x0D, 0xF9, 0xF7, 0xFF, 0x12, 0xE0,
|
||||
0x14, 0x96, 0x84, 0x76, 0xF7, 0xFF, 0x12, 0xE0,
|
||||
0x17, 0x96, 0x85, 0x71, 0xF7, 0xFF, 0x12, 0xE0,
|
||||
0xCE, 0xC5, 0x0F, 0x77, 0xF7, 0xFF, 0x12, 0xE0,
|
||||
0xD2, 0x5A, 0x82, 0xF8, 0xF7, 0xFF, 0x12, 0xE0
|
||||
};
|
||||
|
||||
static void download_instructions(uint8_t t) {
|
||||
DbpString("");
|
||||
switch (t) {
|
||||
case ICE_STATE_FULLSIM: {
|
||||
DbpString("The emulator memory was saved to SPIFFS");
|
||||
DbpString("1. " _YELLOW_("mem spiffs dump o " HF_ICLASS_FULLSIM_MOD_BIN " f " HF_ICLASS_FULLSIM_MOD" e"));
|
||||
DbpString("2. " _YELLOW_("hf iclass view -f " HF_ICLASS_FULLSIM_MOD_BIN));
|
||||
break;
|
||||
}
|
||||
case ICE_STATE_ATTACK: {
|
||||
DbpString("The collected data was saved to SPIFFS. The file names below may differ");
|
||||
DbpString("1. " _YELLOW_("mem spiffs tree"));
|
||||
DbpString("2. " _YELLOW_("mem spiffs dump o " HF_ICLASS_ATTACK_BIN " f " HF_ICLASS_ATTACK_BIN));
|
||||
DbpString("3. " _YELLOW_("hf iclass loclass f " HF_ICLASS_ATTACK_BIN));
|
||||
break;
|
||||
}
|
||||
case ICE_STATE_READER: {
|
||||
DbpString("The found tags was saved to SPIFFS");
|
||||
DbpString("1. " _YELLOW_("mem spiffs tree"));
|
||||
DbpString("2. " _YELLOW_("mem spiffs dump h"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save to flash if file doesn't exist.
|
||||
// Write over file if size of flash file is less than new datalen
|
||||
static void save_to_flash(uint8_t *data, uint16_t datalen) {
|
||||
|
||||
rdv40_spiffs_lazy_mount();
|
||||
|
||||
char fn[SPIFFS_OBJ_NAME_LEN];
|
||||
sprintf(fn, "iclass-%02X%02X%02X%02X%02X%02X%02X%02X.bin",
|
||||
data[0], data[1], data[2], data[3],
|
||||
data[4], data[5], data[6], data[7]
|
||||
);
|
||||
|
||||
int res;
|
||||
if (exists_in_spiffs(fn) == false) {
|
||||
res = rdv40_spiffs_write(fn, data, datalen, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
if (res == SPIFFS_OK) {
|
||||
Dbprintf("saved to " _GREEN_("%s"), fn);
|
||||
}
|
||||
} else {
|
||||
|
||||
// if already exist, see if saved file is smaller..
|
||||
uint32_t fsize = 0;
|
||||
res = rdv40_spiffs_stat(fn, &fsize, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
if (res == SPIFFS_OK) {
|
||||
|
||||
if (fsize < datalen) {
|
||||
res = rdv40_spiffs_write(fn, data, datalen, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
if (res == SPIFFS_OK) {
|
||||
Dbprintf("wrote over " _GREEN_("%s"), fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
}
|
||||
|
||||
static int fullsim_mode(void) {
|
||||
|
||||
rdv40_spiffs_lazy_mount();
|
||||
|
||||
SpinOff(0);
|
||||
uint8_t *emul = BigBuf_get_EM_addr();
|
||||
uint32_t fsize = size_in_spiffs(HF_ICLASS_FULLSIM_ORIG_BIN);
|
||||
int res = rdv40_spiffs_read_as_filetype(HF_ICLASS_FULLSIM_ORIG_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
if (res == SPIFFS_OK) {
|
||||
Dbprintf("loaded " _GREEN_(HF_ICLASS_FULLSIM_ORIG_BIN) " (%u bytes)", fsize);
|
||||
}
|
||||
|
||||
iclass_simulate(ICLASS_SIM_MODE_FULL, 0, false, NULL, NULL, NULL);
|
||||
|
||||
LED_B_ON();
|
||||
rdv40_spiffs_lazy_mount();
|
||||
res = rdv40_spiffs_write(HF_ICLASS_FULLSIM_MOD_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
LED_B_OFF();
|
||||
if (res == SPIFFS_OK) {
|
||||
Dbprintf("wrote emulator memory to " _GREEN_(HF_ICLASS_FULLSIM_MOD_BIN));
|
||||
} else {
|
||||
Dbprintf(_RED_("error") " writing "HF_ICLASS_FULLSIM_MOD_BIN" to flash ( %d )", res);
|
||||
}
|
||||
|
||||
DbpString("-=[ exiting " _CYAN_("`full simulation`") " mode ]=-");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int reader_attack_mode(void) {
|
||||
|
||||
BigBuf_free();
|
||||
uint16_t mac_response_len = 0;
|
||||
uint8_t *mac_responses = BigBuf_malloc(MAC_RESPONSES_SIZE);
|
||||
|
||||
iclass_simulate(ICLASS_SIM_MODE_READER_ATTACK, NUM_CSNS, false, csns, mac_responses, &mac_response_len);
|
||||
|
||||
if (mac_response_len > 0) {
|
||||
|
||||
bool success = (mac_response_len == MAC_RESPONSES_SIZE);
|
||||
uint8_t num_mac = (mac_response_len >> 4);
|
||||
Dbprintf("%u out of %d MAC obtained [%s]", num_mac, NUM_CSNS, (success) ? _GREEN_("ok") : _RED_("fail"));
|
||||
|
||||
size_t dumplen = NUM_CSNS * 24;
|
||||
|
||||
uint8_t *dump = BigBuf_malloc(dumplen);
|
||||
if (dump == false) {
|
||||
Dbprintf("failed to allocate memory");
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
// need zeroes for the EPURSE
|
||||
memset(dump, 0, dumplen);
|
||||
|
||||
for (uint8_t i = 0 ; i < NUM_CSNS ; i++) {
|
||||
//copy CSN
|
||||
memcpy(dump + (i * 24), csns + (i * 8), 8);
|
||||
//copy epurse
|
||||
memcpy(dump + (i * 24) + 8, mac_responses + (i * 16), 8);
|
||||
// NR_MAC (eight bytes from the response) ( 8b csn + 8b epurse == 16)
|
||||
memcpy(dump + (i * 24) + 16, mac_responses + (i * 16) + 8, 8);
|
||||
}
|
||||
|
||||
LED_B_ON();
|
||||
rdv40_spiffs_lazy_mount();
|
||||
|
||||
char fn[32];
|
||||
uint16_t p_namelen = strlen(HF_ICLASS_ATTACK_BIN);
|
||||
uint16_t num = 1;
|
||||
sprintf(fn, "%.*s%s", p_namelen, HF_ICLASS_ATTACK_BIN, ".bin");
|
||||
|
||||
while (exists_in_spiffs(fn)) {
|
||||
sprintf(fn, "%.*s-%u%s", p_namelen, HF_ICLASS_ATTACK_BIN, num, ".bin");
|
||||
num++;
|
||||
}
|
||||
int res = rdv40_spiffs_write(fn, dump, dumplen, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
LED_B_OFF();
|
||||
if (res == SPIFFS_OK) {
|
||||
Dbprintf("saved to " _GREEN_("%s"), fn);
|
||||
} else {
|
||||
Dbprintf(_RED_("error") " writing %s to flash ( %d )", fn, res);
|
||||
}
|
||||
}
|
||||
BigBuf_free();
|
||||
DbpString("-=[ exiting " _CYAN_("`reader attack`") " mode ]=-");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int reader_dump_mode(void) {
|
||||
|
||||
DbpString("this mode has no tracelog");
|
||||
if (have_aa2())
|
||||
DbpString("dumping of " _YELLOW_("AA2 enabled"));
|
||||
|
||||
for (;;) {
|
||||
|
||||
BigBuf_free();
|
||||
|
||||
uint8_t *card_data = BigBuf_malloc(ICLASS_16KS_SIZE);
|
||||
memset(card_data, 0xFF, ICLASS_16KS_SIZE);
|
||||
|
||||
if (BUTTON_PRESS()) {
|
||||
DbpString("button pressed");
|
||||
break;
|
||||
}
|
||||
|
||||
// setup authenticate AA1
|
||||
iclass_auth_req_t auth = {
|
||||
.use_raw = false,
|
||||
.use_elite = false,
|
||||
.use_credit_key = false,
|
||||
.do_auth = true,
|
||||
.send_reply = false,
|
||||
};
|
||||
memcpy(auth.key, legacy_aa1_key, sizeof(auth.key));
|
||||
|
||||
Iso15693InitReader();
|
||||
set_tracing(false);
|
||||
|
||||
// select tag.
|
||||
uint32_t eof_time = 0;
|
||||
bool res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time);
|
||||
if (res == false) {
|
||||
switch_off();
|
||||
continue;
|
||||
}
|
||||
|
||||
picopass_hdr *hdr = (picopass_hdr *)card_data;
|
||||
// sanity check of CSN.
|
||||
if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) {
|
||||
switch_off();
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
// get 3 config bits
|
||||
uint8_t type = (hdr->conf.chip_config & 0x10) >> 2;
|
||||
type |= (hdr->conf.mem_config & 0x80) >> 6;
|
||||
type |= (hdr->conf.mem_config & 0x20) >> 5;
|
||||
|
||||
Dbprintf(_GREEN_("%s") ", dumping...", card_types[type]);
|
||||
|
||||
uint8_t pagemap = get_pagemap(hdr);
|
||||
uint8_t app1_limit, app2_limit, start_block;
|
||||
|
||||
// tags configured for NON SECURE PAGE, acts different
|
||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
||||
app1_limit = card_app2_limit[type];
|
||||
app2_limit = 0;
|
||||
start_block = 3;
|
||||
} else {
|
||||
|
||||
app1_limit = hdr->conf.app_limit;
|
||||
app2_limit = card_app2_limit[type];
|
||||
start_block = 5;
|
||||
|
||||
res = authenticate_iclass_tag(&auth, hdr, &start_time, &eof_time, NULL);
|
||||
if (res == false) {
|
||||
switch_off();
|
||||
Dbprintf(_RED_("failed AA1 auth") ", skipping ");
|
||||
continue;
|
||||
}
|
||||
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
}
|
||||
|
||||
uint16_t dumped = 0;
|
||||
|
||||
// main read loop
|
||||
for (uint16_t i = start_block; i <= app1_limit; i++) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
|
||||
dumped++;
|
||||
}
|
||||
}
|
||||
|
||||
if (pagemap != PICOPASS_NON_SECURE_PAGEMODE && have_aa2()) {
|
||||
|
||||
// authenticate AA2
|
||||
auth.use_raw = false;
|
||||
auth.use_credit_key = true;
|
||||
memcpy(auth.key, aa2_key, sizeof(auth.key));
|
||||
|
||||
res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time);
|
||||
if (res) {
|
||||
|
||||
// sanity check of CSN.
|
||||
if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) {
|
||||
switch_off();
|
||||
continue;
|
||||
}
|
||||
|
||||
res = authenticate_iclass_tag(&auth, hdr, &start_time, &eof_time, NULL);
|
||||
if (res) {
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
for (uint16_t i = app1_limit + 1; i <= app2_limit; i++) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
|
||||
dumped++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DbpString(_RED_("failed AA2 auth"));
|
||||
}
|
||||
} else {
|
||||
DbpString(_RED_("failed selecting AA2"));
|
||||
|
||||
// sanity check of CSN.
|
||||
if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) {
|
||||
switch_off();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_off();
|
||||
save_to_flash(card_data, (start_block + dumped) * 8);
|
||||
Dbprintf("%u bytes saved", (start_block + dumped) * 8);
|
||||
}
|
||||
DbpString("-=[ exiting " _CYAN_("`read & dump`") " mode ]=-");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int config_sim_mode(void) {
|
||||
|
||||
uint8_t *emul = BigBuf_get_EM_addr();
|
||||
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
SpinOff(0);
|
||||
rdv40_spiffs_lazy_mount();
|
||||
uint32_t fsize = size_in_spiffs(cc_files[i]);
|
||||
int res = rdv40_spiffs_read_as_filetype(cc_files[i], emul, fsize, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
|
||||
if (res == SPIFFS_OK) {
|
||||
Dbprintf("loaded " _GREEN_("%s") " (%u bytes) to emulator memory", cc_files[i], fsize);
|
||||
iclass_simulate(ICLASS_SIM_MODE_FULL, 0, false, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
DbpString("-=[ exiting " _CYAN_("`glitch & config`") " mode ]=-");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" HF iCLASS mode - aka iceCLASS (iceman)");
|
||||
}
|
||||
|
||||
void RunMod(void) {
|
||||
|
||||
uint8_t mode = ICE_USE;
|
||||
uint8_t *bb = BigBuf_get_EM_addr();
|
||||
if (bb[0] > 0 && bb[0] < 5) {
|
||||
mode = bb[0];
|
||||
}
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
BigBuf_Clear_ext(false);
|
||||
|
||||
StandAloneMode();
|
||||
Dbprintf(_YELLOW_("HF iCLASS mode a.k.a iceCLASS started"));
|
||||
|
||||
|
||||
for (;;) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (mode == ICE_STATE_NONE) break;
|
||||
if (data_available()) break;
|
||||
|
||||
int res;
|
||||
switch (mode) {
|
||||
|
||||
case ICE_STATE_FULLSIM: {
|
||||
DbpString("-=[ enter " _CYAN_("`full simulation`") " mode ]=-");
|
||||
|
||||
// Look for iCLASS dump file
|
||||
rdv40_spiffs_lazy_mount();
|
||||
if (exists_in_spiffs(HF_ICLASS_FULLSIM_ORIG_BIN) == false) {
|
||||
Dbprintf(_RED_("error") " " _YELLOW_(HF_ICLASS_FULLSIM_ORIG_BIN) " file missing");
|
||||
mode = ICE_STATE_NONE;
|
||||
}
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
|
||||
if (mode == ICE_STATE_FULLSIM) {
|
||||
res = fullsim_mode();
|
||||
if (res == PM3_SUCCESS) {
|
||||
download_instructions(mode);
|
||||
}
|
||||
}
|
||||
// the button press to exit sim, is captured in main loop here
|
||||
mode = ICE_STATE_NONE;
|
||||
break;
|
||||
}
|
||||
case ICE_STATE_ATTACK: {
|
||||
DbpString("-=[ enter " _CYAN_("`reader attack`") " mode ]=-");
|
||||
res = reader_attack_mode();
|
||||
if (res == PM3_SUCCESS)
|
||||
download_instructions(mode);
|
||||
|
||||
mode = ICE_STATE_NONE;
|
||||
break;
|
||||
}
|
||||
case ICE_STATE_READER: {
|
||||
DbpString("-=[ enter " _CYAN_("`read & dump`") " mode, continuous scanning ]=-");
|
||||
res = reader_dump_mode();
|
||||
if (res == PM3_SUCCESS)
|
||||
download_instructions(mode);
|
||||
|
||||
mode = ICE_STATE_NONE;
|
||||
break;
|
||||
}
|
||||
case ICE_STATE_CONFIGCARD: {
|
||||
DbpString("-=[ enter " _CYAN_("`glitch & config`") " mode ]=-");
|
||||
|
||||
// Look for config cards
|
||||
rdv40_spiffs_lazy_mount();
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
if (exists_in_spiffs(cc_files[i]) == false) {
|
||||
Dbprintf(_RED_("error") ", " _YELLOW_("%s") " file missing", cc_files[i]);
|
||||
mode = ICE_STATE_NONE;
|
||||
}
|
||||
}
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
|
||||
if (mode == ICE_STATE_CONFIGCARD)
|
||||
config_sim_mode();
|
||||
|
||||
mode = ICE_STATE_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch_off();
|
||||
Dbprintf("-=[ exit ]=-");
|
||||
}
|
|
@ -22,7 +22,6 @@
|
|||
#include "legic.h" // legic_card_select_t struct
|
||||
#include "spiffs.h" // flashmem
|
||||
|
||||
|
||||
/*
|
||||
* To list all dump files from flash:
|
||||
*
|
||||
|
@ -106,6 +105,7 @@ void RunMod(void) {
|
|||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
Dbprintf("[=] >> HF Legic Prime Read/Simulate Started <<");
|
||||
DbpString("[=] press and HOLD button to exit standalone mode");
|
||||
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
|
@ -163,7 +163,7 @@ void RunMod(void) {
|
|||
}
|
||||
|
||||
// The read data is migrated to a MIM1024 card
|
||||
LegicRfSimulate(ct);
|
||||
LegicRfSimulate(ct, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -575,4 +575,5 @@ void RunMod(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
LEDsoff();
|
||||
}
|
||||
|
|
|
@ -305,6 +305,8 @@ void RunMod(void) {
|
|||
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader...");
|
||||
}
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
} else if (state == STATE_EMU) {
|
||||
LED_A_OFF();
|
||||
LED_C_ON();
|
||||
|
|
|
@ -54,7 +54,7 @@ void RunMod(void) {
|
|||
for (;;) {
|
||||
WDT_HIT();
|
||||
// exit from Standalone Mode, send a usbcommand.
|
||||
if (data_available()) return;
|
||||
if (data_available()) break;
|
||||
|
||||
SpinDelay(300);
|
||||
|
||||
|
@ -72,7 +72,7 @@ void RunMod(void) {
|
|||
|
||||
for (;;) {
|
||||
// exit from Standalone Mode, send a usbcommand.
|
||||
if (data_available()) return;
|
||||
if (data_available()) break;
|
||||
|
||||
if (BUTTON_PRESS()) {
|
||||
if (cardRead[selected]) {
|
||||
|
@ -89,6 +89,9 @@ void RunMod(void) {
|
|||
}
|
||||
|
||||
if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
SpinDelay(500);
|
||||
continue;
|
||||
} else {
|
||||
Dbprintf("Read UID:");
|
||||
|
@ -220,7 +223,7 @@ void RunMod(void) {
|
|||
DbpString("Playing");
|
||||
for (; ;) {
|
||||
// exit from Standalone Mode, send a usbcommand.
|
||||
if (data_available()) return;
|
||||
if (data_available()) break;
|
||||
|
||||
int button_pressed = BUTTON_HELD(1000);
|
||||
if (button_pressed == BUTTON_NO_CLICK) { // No button action, proceed with sim
|
||||
|
@ -277,4 +280,6 @@ void RunMod(void) {
|
|||
LED(selected + 1, 0);
|
||||
}
|
||||
}
|
||||
DbpString(_YELLOW_("[=]") "exiting");
|
||||
LEDsoff();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#endif
|
||||
|
||||
#define MAX_IND 16 // 4 LEDs - 2^4 combinations
|
||||
#define CLOCK 64 //for 125kHz
|
||||
#define LF_CLOCK 64 // for 125kHz
|
||||
|
||||
// low & high - array for storage IDs. Its length must be equal.
|
||||
// Predefined IDs must be stored in low[].
|
||||
|
@ -57,34 +57,35 @@ static uint64_t rev_quads(uint64_t bits) {
|
|||
}
|
||||
|
||||
static void fillbuff(uint8_t bit) {
|
||||
memset(bba + buflen, bit, CLOCK / 2);
|
||||
buflen += (CLOCK / 2);
|
||||
memset(bba + buflen, bit ^ 1, CLOCK / 2);
|
||||
buflen += (CLOCK / 2);
|
||||
memset(bba + buflen, bit, LF_CLOCK / 2);
|
||||
buflen += (LF_CLOCK / 2);
|
||||
memset(bba + buflen, bit ^ 1, LF_CLOCK / 2);
|
||||
buflen += (LF_CLOCK / 2);
|
||||
}
|
||||
|
||||
static void construct_EM410x_emul(uint64_t id) {
|
||||
|
||||
int i, j;
|
||||
int binary[4] = {0};
|
||||
int parity[4] = {0};
|
||||
buflen = 0;
|
||||
|
||||
for (uint8_t i = 0; i < 9; i++)
|
||||
for (i = 0; i < 9; i++)
|
||||
fillbuff(1);
|
||||
|
||||
for (uint8_t i = 0; i < 10; i++) {
|
||||
for (uint8_t j = 3; j > 0; j--, id /= 2)
|
||||
for (i = 0; i < 10; i++) {
|
||||
for (j = 3; j >= 0; j--, id /= 2)
|
||||
binary[j] = id % 2;
|
||||
|
||||
for (uint8_t j = 0; j < 4; j++)
|
||||
for (j = 0; j < 4; j++)
|
||||
fillbuff(binary[j]);
|
||||
|
||||
fillbuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
for (uint8_t j = 0; j < 4; j++)
|
||||
for (j = 0; j < 4; j++)
|
||||
parity[j] ^= binary[j];
|
||||
}
|
||||
|
||||
for (uint8_t j = 0; j < 4; j++)
|
||||
for (j = 0; j < 4; j++)
|
||||
fillbuff(parity[j]);
|
||||
|
||||
fillbuff(0);
|
||||
|
@ -207,7 +208,7 @@ void RunMod(void) {
|
|||
state = 0;
|
||||
} else if (button_pressed == BUTTON_SINGLE_CLICK) {
|
||||
// Click - write ID to tag
|
||||
copy_em410x_to_t55xx(0, CLOCK, (uint32_t)(low[selected] >> 32), (uint32_t)(low[selected] & 0xffffffff));
|
||||
copy_em410x_to_t55xx(0, LF_CLOCK, (uint32_t)(low[selected] >> 32), (uint32_t)(low[selected] & 0xffffffff));
|
||||
led_slot(selected);
|
||||
state = 0; // Switch to select mode
|
||||
}
|
||||
|
|
339
armsrc/appmain.c
339
armsrc/appmain.c
|
@ -20,6 +20,7 @@
|
|||
#include "fpga.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "string.h"
|
||||
#include "printf.h"
|
||||
#include "legicrf.h"
|
||||
#include "BigBuf.h"
|
||||
#include "iso14443a.h"
|
||||
|
@ -32,6 +33,7 @@
|
|||
#include "em4x50.h"
|
||||
#include "iclass.h"
|
||||
#include "legicrfsim.h"
|
||||
//#include "cryptorfsim.h"
|
||||
#include "epa.h"
|
||||
#include "hfsnoop.h"
|
||||
#include "lfops.h"
|
||||
|
@ -62,53 +64,35 @@
|
|||
#include "spiffs.h"
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// A buffer where we can queue things up to be sent through the FPGA, for
|
||||
// any purpose (fake tag, as reader, whatever). We go MSB first, since that
|
||||
// is the order in which they go out on the wire.
|
||||
//=============================================================================
|
||||
|
||||
#define TOSEND_BUFFER_SIZE (9*MAX_FRAME_SIZE + 1 + 1 + 2) // 8 data bits and 1 parity bit per payload byte, 1 correction bit, 1 SOC bit, 2 EOC bits
|
||||
uint8_t ToSend[TOSEND_BUFFER_SIZE];
|
||||
int ToSendMax = -1;
|
||||
|
||||
extern uint32_t _stack_start, _stack_end;
|
||||
|
||||
|
||||
static int ToSendBit;
|
||||
struct common_area common_area __attribute__((section(".commonarea")));
|
||||
static int button_status = BUTTON_NO_CLICK;
|
||||
static bool allow_send_wtx = false;
|
||||
static uint16_t tearoff_delay_us = 0;
|
||||
static bool tearoff_enabled = false;
|
||||
|
||||
inline void send_wtx(uint16_t wtx) {
|
||||
int tearoff_hook(void) {
|
||||
if (tearoff_enabled) {
|
||||
if (tearoff_delay_us == 0) {
|
||||
Dbprintf(_RED_("No tear-off delay configured!"));
|
||||
return PM3_SUCCESS; // SUCCESS = the hook didn't do anything
|
||||
}
|
||||
SpinDelayUsPrecision(tearoff_delay_us);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
tearoff_enabled = false;
|
||||
Dbprintf(_YELLOW_("Tear-off triggered!"));
|
||||
return PM3_ETEAROFF;
|
||||
} else {
|
||||
return PM3_SUCCESS; // SUCCESS = the hook didn't do anything
|
||||
}
|
||||
}
|
||||
|
||||
void send_wtx(uint16_t wtx) {
|
||||
if (allow_send_wtx) {
|
||||
reply_ng(CMD_WTX, PM3_SUCCESS, (uint8_t *)&wtx, sizeof(wtx));
|
||||
}
|
||||
}
|
||||
|
||||
void ToSendReset(void) {
|
||||
ToSendMax = -1;
|
||||
ToSendBit = 8;
|
||||
}
|
||||
|
||||
void ToSendStuffBit(int b) {
|
||||
if (ToSendBit >= 8) {
|
||||
ToSendMax++;
|
||||
ToSend[ToSendMax] = 0;
|
||||
ToSendBit = 0;
|
||||
}
|
||||
|
||||
if (b)
|
||||
ToSend[ToSendMax] |= (1 << (7 - ToSendBit));
|
||||
|
||||
ToSendBit++;
|
||||
|
||||
if (ToSendMax >= sizeof(ToSend)) {
|
||||
ToSendBit = 0;
|
||||
DbpString("ToSendStuffBit overflowed!");
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Read an ADC channel and block till it completes, then return the result
|
||||
// in ADC units (0 to 1023). Also a routine to sum up a number of samples and
|
||||
|
@ -213,7 +197,7 @@ static void MeasureAntennaTuning(void) {
|
|||
LED_A_ON();
|
||||
// Let the FPGA drive the high-frequency antenna around 13.56 MHz.
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER);
|
||||
SpinDelay(50);
|
||||
|
||||
#if defined RDV4
|
||||
|
@ -272,7 +256,7 @@ static void SendVersion(void) {
|
|||
*/
|
||||
char *bootrom_version = *(char **)&_bootphase1_version_pointer;
|
||||
|
||||
strncat(VersionString, " "_YELLOW_("[ ARM ]")"\n", sizeof(VersionString) - strlen(VersionString) - 1);
|
||||
strncat(VersionString, " [ "_YELLOW_("ARM")" ]\n", sizeof(VersionString) - strlen(VersionString) - 1);
|
||||
|
||||
if (bootrom_version < &_flash_start || bootrom_version >= &_flash_end) {
|
||||
strcat(VersionString, "bootrom version information appears invalid\n");
|
||||
|
@ -292,7 +276,7 @@ static void SendVersion(void) {
|
|||
strncat(VersionString, " compiled with GCC "__VERSION__"\n", sizeof(VersionString) - strlen(VersionString) - 1);
|
||||
#endif
|
||||
|
||||
strncat(VersionString, "\n "_YELLOW_("[ FPGA ]")"\n ", sizeof(VersionString) - strlen(VersionString) - 1);
|
||||
strncat(VersionString, "\n [ "_YELLOW_("FPGA")" ] \n ", sizeof(VersionString) - strlen(VersionString) - 1);
|
||||
|
||||
for (int i = 0; i < g_fpga_bitstream_num; i++) {
|
||||
strncat(VersionString, g_fpga_version_information[i], sizeof(VersionString) - strlen(VersionString) - 1);
|
||||
|
@ -328,6 +312,28 @@ static void TimingIntervalAcquisition(void) {
|
|||
StartTickCount();
|
||||
}
|
||||
|
||||
static void print_debug_level(void) {
|
||||
char dbglvlstr[20] = {0};
|
||||
switch (DBGLEVEL) {
|
||||
case DBG_NONE:
|
||||
sprintf(dbglvlstr, "NONE");
|
||||
break;
|
||||
case DBG_ERROR:
|
||||
sprintf(dbglvlstr, "ERROR");
|
||||
break;
|
||||
case DBG_INFO:
|
||||
sprintf(dbglvlstr, "INFO");
|
||||
break;
|
||||
case DBG_DEBUG:
|
||||
sprintf(dbglvlstr, "DEBUG");
|
||||
break;
|
||||
case DBG_EXTENDED:
|
||||
sprintf(dbglvlstr, "EXTENDED");
|
||||
break;
|
||||
}
|
||||
Dbprintf(" DBGLEVEL................%d ( " _YELLOW_("%s")" )", DBGLEVEL, dbglvlstr);
|
||||
}
|
||||
|
||||
// measure the Connection Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time.
|
||||
// Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the PacketCommandNG structure included.
|
||||
static void printConnSpeed(void) {
|
||||
|
@ -367,17 +373,20 @@ static void SendStatus(void) {
|
|||
I2C_print_status();
|
||||
#endif
|
||||
#ifdef WITH_LF
|
||||
printConfig(); // LF Sampling config
|
||||
printLFConfig(); // LF Sampling config
|
||||
printT55xxConfig(); // LF T55XX Config
|
||||
#endif
|
||||
#ifdef WITH_ISO14443a
|
||||
printHf14aConfig(); // HF 14a config
|
||||
#endif
|
||||
printConnSpeed();
|
||||
DbpString(_CYAN_("Various"));
|
||||
|
||||
print_stack_usage();
|
||||
print_debug_level();
|
||||
|
||||
Dbprintf(" DBGLEVEL................%d", DBGLEVEL);
|
||||
Dbprintf(" ToSendMax...............%d", ToSendMax);
|
||||
Dbprintf(" ToSendBit...............%d", ToSendBit);
|
||||
tosend_t *ts = get_tosend();
|
||||
Dbprintf(" ToSendMax...............%d", ts->max);
|
||||
Dbprintf(" ToSend BUFFERSIZE.......%d", TOSEND_BUFFER_SIZE);
|
||||
while ((AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINRDY) == 0); // Wait for MAINF value to become available...
|
||||
uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINF; // Get # main clocks within 16 slow clocks
|
||||
|
@ -515,6 +524,7 @@ static void SendCapabilities(void) {
|
|||
|
||||
// Show some leds in a pattern to identify StandAlone mod is running
|
||||
void StandAloneMode(void) {
|
||||
DbpString("");
|
||||
DbpString("Stand-alone mode, no computer necessary");
|
||||
SpinDown(50);
|
||||
SpinDelay(50);
|
||||
|
@ -735,10 +745,28 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
// emulator
|
||||
case CMD_SET_DBGMODE: {
|
||||
DBGLEVEL = packet->data.asBytes[0];
|
||||
Dbprintf("Debug level: %d", DBGLEVEL);
|
||||
print_debug_level();
|
||||
reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_SET_TEAROFF: {
|
||||
struct p {
|
||||
uint16_t delay_us;
|
||||
bool on;
|
||||
bool off;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
if (payload->on && payload->off)
|
||||
reply_ng(CMD_SET_TEAROFF, PM3_EINVARG, NULL, 0);
|
||||
if (payload->on)
|
||||
tearoff_enabled = true;
|
||||
if (payload->off)
|
||||
tearoff_enabled = false;
|
||||
if (payload->delay_us > 0)
|
||||
tearoff_delay_us = payload->delay_us;
|
||||
reply_ng(CMD_SET_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
// always available
|
||||
case CMD_HF_DROPFIELD: {
|
||||
hf_field_off();
|
||||
|
@ -750,7 +778,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_LF_SAMPLING_PRINT_CONFIG: {
|
||||
printConfig();
|
||||
printLFConfig();
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SAMPLING_GET_CONFIG: {
|
||||
|
@ -767,8 +795,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
case CMD_LF_ACQ_RAW_ADC: {
|
||||
struct p {
|
||||
uint8_t verbose;
|
||||
uint32_t samples;
|
||||
uint32_t samples : 31;
|
||||
bool verbose : 1;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
uint32_t bits = SampleLF(payload->verbose, payload->samples);
|
||||
|
@ -778,16 +806,29 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
case CMD_LF_MOD_THEN_ACQ_RAW_ADC: {
|
||||
struct p {
|
||||
uint32_t delay;
|
||||
uint16_t ones;
|
||||
uint16_t zeros;
|
||||
uint16_t period_0;
|
||||
uint16_t period_1;
|
||||
uint8_t symbol_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS];
|
||||
uint16_t period_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS];
|
||||
uint32_t samples : 31;
|
||||
bool verbose : 1;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
ModThenAcquireRawAdcSamples125k(payload->delay, payload->zeros, payload->ones, packet->data.asBytes + 8);
|
||||
uint8_t symbol_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS];
|
||||
uint16_t period_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS];
|
||||
memcpy(symbol_extra, payload->symbol_extra, sizeof(symbol_extra));
|
||||
memcpy(period_extra, payload->period_extra, sizeof(period_extra));
|
||||
ModThenAcquireRawAdcSamples125k(payload->delay, payload->period_0, payload->period_1, symbol_extra, period_extra, packet->data.asBytes + sizeof(struct p), payload->verbose, payload->samples);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SNIFF_RAW_ADC: {
|
||||
uint32_t bits = SniffLF();
|
||||
reply_mix(CMD_ACK, bits, 0, 0, 0, 0);
|
||||
struct p {
|
||||
uint32_t samples : 31;
|
||||
bool verbose : 1;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
uint32_t bits = SniffLF(payload->verbose, payload->samples);
|
||||
reply_ng(CMD_LF_SNIFF_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits));
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HID_WATCH: {
|
||||
|
@ -822,7 +863,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_LF_HID_CLONE: {
|
||||
CopyHIDtoT55x7(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes[0]);
|
||||
lf_hidsim_t *payload = (lf_hidsim_t *)packet->data.asBytes;
|
||||
CopyHIDtoT55x7(payload->hi2, payload->hi, payload->lo, payload->longFMT);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_IO_WATCH: {
|
||||
|
@ -949,6 +991,16 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
EM4xWriteWord(payload->address, payload->data, payload->password, payload->usepwd);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X_PROTECTWORD: {
|
||||
struct p {
|
||||
uint32_t password;
|
||||
uint32_t data;
|
||||
uint8_t usepwd;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
EM4xProtectWord(payload->data, payload->password, payload->usepwd);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_AWID_WATCH: {
|
||||
uint32_t high, low;
|
||||
int res = lf_awid_watch(0, &high, &low);
|
||||
|
@ -965,7 +1017,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_LF_COTAG_READ: {
|
||||
Cotag(packet->oldarg[0]);
|
||||
struct p {
|
||||
uint8_t mode;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
Cotag(payload->mode);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -974,6 +1030,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
case CMD_LF_HITAG_SNIFF: { // Eavesdrop Hitag tag, args = type
|
||||
SniffHitag2();
|
||||
// SniffHitag2(packet->oldarg[0]);
|
||||
reply_ng(CMD_LF_HITAG_SNIFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HITAG_SIMULATE: { // Simulate Hitag tag, args = memory content
|
||||
|
@ -1023,7 +1080,10 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
em4x50_read((em4x50_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_LF_EM4X50_WIPE: {
|
||||
em4x50_wipe((em4x50_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ISO15693
|
||||
|
@ -1031,8 +1091,9 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
AcquireRawAdcSamplesIso15693();
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_RAWADC: {
|
||||
RecordRawAdcSamplesIso15693();
|
||||
case CMD_HF_ISO15693_SNIFF: {
|
||||
SniffIso15693(0, NULL);
|
||||
reply_ng(CMD_HF_ISO15693_SNIFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_COMMAND: {
|
||||
|
@ -1048,14 +1109,31 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_SIMULATE: {
|
||||
SimTagIso15693(packet->oldarg[0], packet->data.asBytes);
|
||||
struct p {
|
||||
uint8_t uid[8];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
SimTagIso15693(payload->uid);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_CSETUID: {
|
||||
struct p {
|
||||
uint8_t uid[8];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
SetTag15693Uid(payload->uid);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_LEGICRF
|
||||
case CMD_HF_LEGIC_SIMULATE: {
|
||||
LegicRfSimulate(packet->oldarg[0]);
|
||||
struct p {
|
||||
uint8_t tagtype;
|
||||
bool send_reply;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
LegicRfSimulate(payload->tagtype, payload->send_reply);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_LEGIC_WRITER: {
|
||||
|
@ -1091,17 +1169,21 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
case CMD_HF_ISO14443B_SNIFF: {
|
||||
SniffIso14443b();
|
||||
reply_ng(CMD_HF_ISO14443B_SNIFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443B_SIMULATE: {
|
||||
SimulateIso14443bTag(packet->oldarg[0]);
|
||||
SimulateIso14443bTag(packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443B_COMMAND: {
|
||||
//SendRawCommand14443B(packet->oldarg[0],packet->oldarg[1],packet->oldarg[2],packet->data.asBytes);
|
||||
SendRawCommand14443B_Ex(packet);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_CRYPTORF_SIM : {
|
||||
// simulate_crf_tag();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_FELICA
|
||||
|
@ -1115,6 +1197,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
case CMD_HF_FELICA_SNIFF: {
|
||||
felica_sniff(packet->oldarg[0], packet->oldarg[1]);
|
||||
reply_ng(CMD_HF_FELICA_SNIFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_FELICALITE_DUMP: {
|
||||
|
@ -1124,8 +1207,24 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
#endif
|
||||
|
||||
#ifdef WITH_ISO14443a
|
||||
case CMD_HF_ISO14443A_PRINT_CONFIG: {
|
||||
printHf14aConfig();
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443A_GET_CONFIG: {
|
||||
hf14a_config *hf14aconfig = getHf14aConfig();
|
||||
reply_ng(CMD_HF_ISO14443A_GET_CONFIG, PM3_SUCCESS, (uint8_t *)hf14aconfig, sizeof(hf14a_config));
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443A_SET_CONFIG: {
|
||||
hf14a_config c;
|
||||
memcpy(&c, packet->data.asBytes, sizeof(hf14a_config));
|
||||
setHf14aConfig(&c);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443A_SNIFF: {
|
||||
SniffIso14443a(packet->data.asBytes[0]);
|
||||
reply_ng(CMD_HF_ISO14443A_SNIFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443A_READER: {
|
||||
|
@ -1197,6 +1296,10 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
MifareUWriteBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFAREU_WRITEBL_COMPAT: {
|
||||
MifareUWriteBlockCompat(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_ACQ_ENCRYPTED_NONCES: {
|
||||
MifareAcquireEncryptedNonces(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
|
||||
break;
|
||||
|
@ -1231,7 +1334,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_CHKKEYS: {
|
||||
MifareChkKeys(packet->data.asBytes);
|
||||
MifareChkKeys(packet->data.asBytes, false);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_CHKKEYS_FAST: {
|
||||
|
@ -1298,7 +1401,21 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_CIDENT: {
|
||||
MifareCIdent();
|
||||
bool is_mfc = packet->data.asBytes[0];
|
||||
MifareCIdent(is_mfc);
|
||||
break;
|
||||
}
|
||||
// Gen 3 magic cards
|
||||
case CMD_HF_MIFARE_GEN3UID: {
|
||||
MifareGen3UID(packet->oldarg[0], packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_GEN3BLK: {
|
||||
MifareGen3Blk(packet->oldarg[0], packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_GEN3FREEZ: {
|
||||
MifareGen3Freez();
|
||||
break;
|
||||
}
|
||||
// mifare sniffer
|
||||
|
@ -1356,6 +1473,15 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
MifareU_Otp_Tearoff(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MFU_COUNTER_TEAROFF: {
|
||||
struct p {
|
||||
uint8_t counter;
|
||||
uint32_t tearoff_time;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
MifareU_Counter_Tearoff(payload->counter, payload->tearoff_time);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_STATIC_NONCE: {
|
||||
MifareHasStaticNonce();
|
||||
break;
|
||||
|
@ -1376,7 +1502,13 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
#ifdef WITH_ICLASS
|
||||
// Makes use of ISO14443a FPGA Firmware
|
||||
case CMD_HF_ICLASS_SNIFF: {
|
||||
SniffIClass();
|
||||
struct p {
|
||||
uint8_t jam_search_len;
|
||||
uint8_t jam_search_string[];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
SniffIClass(payload->jam_search_len, payload->jam_search_string);
|
||||
reply_ng(CMD_HF_ICLASS_SNIFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_SIMULATE: {
|
||||
|
@ -1388,7 +1520,12 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_REPLAY: {
|
||||
ReaderIClass_Replay(packet->oldarg[0], packet->data.asBytes);
|
||||
struct p {
|
||||
uint8_t reader[4];
|
||||
uint8_t mac[4];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
ReaderIClass_Replay(payload->reader, payload->mac);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_EML_MEMSET: {
|
||||
|
@ -1398,36 +1535,14 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_WRITEBL: {
|
||||
struct p {
|
||||
uint8_t blockno;
|
||||
uint8_t data[12];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
iClass_WriteBlock(payload->blockno, payload->data);
|
||||
break;
|
||||
}
|
||||
// iceman2019, unused?
|
||||
case CMD_HF_ICLASS_READCHECK: { // auth step 1
|
||||
iClass_ReadCheck(packet->oldarg[0], packet->oldarg[1]);
|
||||
iClass_WriteBlock(packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_READBL: {
|
||||
/*
|
||||
struct p {
|
||||
uint8_t blockno;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
*/
|
||||
iClass_ReadBlk(packet->data.asBytes[0]);
|
||||
iClass_ReadBlock(packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_AUTH: { //check
|
||||
/*
|
||||
struct p {
|
||||
uint8_t mac[4];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
*/
|
||||
iClass_Authentication(packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
|
@ -1436,7 +1551,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_DUMP: {
|
||||
iClass_Dump(packet->oldarg[0], packet->oldarg[1]);
|
||||
iClass_Dump(packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_CLONE: {
|
||||
|
@ -1449,6 +1564,10 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
iClass_Clone(payload->startblock, payload->endblock, payload->data);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_RESTORE: {
|
||||
iClass_Restore(packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_HFSNIFF
|
||||
|
@ -1616,7 +1735,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
case 1: // MEASURE_ANTENNA_TUNING_HF_START
|
||||
// Let the FPGA drive the high-frequency antenna around 13.56 MHz.
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER);
|
||||
reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
case 2:
|
||||
|
@ -1796,12 +1915,9 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint8_t filename[32];
|
||||
uint8_t *pfilename = packet->data.asBytes;
|
||||
memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN);
|
||||
if (DBGLEVEL > 1) Dbprintf("> Filename received for spiffs dump : %s", filename);
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Filename received for spiffs dump : %s", filename);
|
||||
|
||||
//uint32_t size = 0;
|
||||
//rdv40_spiffs_stat((char *)filename, (uint32_t *)size,RDV40_SPIFFS_SAFETY_SAFE);
|
||||
uint32_t size = packet->oldarg[1];
|
||||
//uint8_t buff[size];
|
||||
|
||||
uint8_t *buff = BigBuf_malloc(size);
|
||||
rdv40_spiffs_read_as_filetype((char *)filename, (uint8_t *)buff, size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
@ -1826,7 +1942,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint8_t filename[32];
|
||||
uint8_t *pfilename = packet->data.asBytes;
|
||||
memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN);
|
||||
if (DBGLEVEL > 1) Dbprintf("> Filename received for spiffs STAT : %s", filename);
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Filename received for spiffs STAT : %s", filename);
|
||||
int changed = rdv40_spiffs_lazy_mount();
|
||||
uint32_t size = size_in_spiffs((char *)filename);
|
||||
if (changed) rdv40_spiffs_lazy_unmount();
|
||||
|
@ -1839,7 +1955,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint8_t filename[32];
|
||||
uint8_t *pfilename = packet->data.asBytes;
|
||||
memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN);
|
||||
if (DBGLEVEL > 1) Dbprintf("> Filename received for spiffs REMOVE : %s", filename);
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Filename received for spiffs REMOVE : %s", filename);
|
||||
rdv40_spiffs_remove((char *) filename, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
LED_B_OFF();
|
||||
break;
|
||||
|
@ -1854,9 +1970,9 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
strncpy((char *)src, token, sizeof(src) - 1);
|
||||
token = strtok(NULL, ",");
|
||||
strncpy((char *)dest, token, sizeof(dest) - 1);
|
||||
if (DBGLEVEL > 1) {
|
||||
Dbprintf("> Filename received as source for spiffs RENAME : %s", src);
|
||||
Dbprintf("> Filename received as destination for spiffs RENAME : %s", dest);
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Filename received as source for spiffs RENAME : %s", src);
|
||||
Dbprintf("Filename received as destination for spiffs RENAME : %s", dest);
|
||||
}
|
||||
rdv40_spiffs_rename((char *) src, (char *)dest, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
LED_B_OFF();
|
||||
|
@ -1872,9 +1988,9 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
strncpy((char *)src, token, sizeof(src) - 1);
|
||||
token = strtok(NULL, ",");
|
||||
strncpy((char *)dest, token, sizeof(dest) - 1);
|
||||
if (DBGLEVEL > 1) {
|
||||
Dbprintf("> Filename received as source for spiffs COPY : %s", src);
|
||||
Dbprintf("> Filename received as destination for spiffs COPY : %s", dest);
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Filename received as source for spiffs COPY : %s", src);
|
||||
Dbprintf("Filename received as destination for spiffs COPY : %s", dest);
|
||||
}
|
||||
rdv40_spiffs_copy((char *) src, (char *)dest, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
LED_B_OFF();
|
||||
|
@ -1886,14 +2002,12 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint32_t append = packet->oldarg[0];
|
||||
uint32_t size = packet->oldarg[1];
|
||||
uint8_t *data = packet->data.asBytes;
|
||||
|
||||
//rdv40_spiffs_lazy_mount();
|
||||
|
||||
uint8_t *pfilename = packet->data.asBytes;
|
||||
memcpy(filename, pfilename, SPIFFS_OBJ_NAME_LEN);
|
||||
data += SPIFFS_OBJ_NAME_LEN;
|
||||
|
||||
if (DBGLEVEL > 1) Dbprintf("> Filename received for spiffs WRITE : %s with APPEND SET TO : %d", filename, append);
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("> Filename received for spiffs WRITE : %s with APPEND SET TO : %d", filename, append);
|
||||
|
||||
if (!append) {
|
||||
rdv40_spiffs_write((char *) filename, (uint8_t *)data, size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
} else {
|
||||
|
@ -1903,6 +2017,13 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
LED_B_OFF();
|
||||
break;
|
||||
}
|
||||
case CMD_SPIFFS_WIPE: {
|
||||
LED_B_ON();
|
||||
rdv40_spiffs_safe_wipe();
|
||||
reply_ng(CMD_SPIFFS_WIPE, PM3_SUCCESS, NULL, 0);
|
||||
LED_B_OFF();
|
||||
break;
|
||||
}
|
||||
case CMD_FLASHMEM_SET_SPIBAUDRATE: {
|
||||
if (packet->length != sizeof(uint32_t))
|
||||
break;
|
||||
|
@ -2060,6 +2181,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_STANDALONE: {
|
||||
uint8_t *bb = BigBuf_get_EM_addr();
|
||||
bb[0] = packet->data.asBytes[0];
|
||||
RunMod();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
extern int g_rsamples; // = 0;
|
||||
extern uint8_t g_trigger;
|
||||
|
||||
int tearoff_hook(void);
|
||||
|
||||
// ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV
|
||||
#define MAX_ADC_HF_VOLTAGE 36300
|
||||
// ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV
|
||||
|
|
|
@ -69,8 +69,6 @@ enum DESFIRE_AUTH_SCHEME {
|
|||
AS_NEW
|
||||
};
|
||||
|
||||
|
||||
|
||||
#define DESFIRE_KEY(key) ((struct desfire_key *) key)
|
||||
struct desfire_key {
|
||||
enum DESFIRE_CRYPTOALGO type;
|
||||
|
|
164
armsrc/em4x50.c
164
armsrc/em4x50.c
|
@ -90,6 +90,7 @@ static em4x50_tag_t tag = {
|
|||
#define EM4X50_COMMAND_WRITE_PASSWORD 0x11
|
||||
#define EM4X50_COMMAND_SELECTIVE_READ 0x0A
|
||||
|
||||
#define EM4X50_COMMAND_TIMEOUT 5000
|
||||
#define FPGA_TIMER_0 0
|
||||
|
||||
int gHigh = 0;
|
||||
|
@ -99,8 +100,9 @@ int gLow = 0;
|
|||
|
||||
static void init_tag(void) {
|
||||
|
||||
// initialize global tag structure
|
||||
// iceman: memset(tag.sectors, 0x00, sizeof));
|
||||
|
||||
// initialize global tag structure
|
||||
for (int i = 0; i < 34; i++)
|
||||
for (int j = 0; j < 7; j++)
|
||||
tag.sectors[i][j] = 0x00;
|
||||
|
@ -109,14 +111,12 @@ static void init_tag(void) {
|
|||
static uint8_t bits2byte(uint8_t *bits, int length) {
|
||||
|
||||
// converts <length> separate bits into a single "byte"
|
||||
|
||||
uint8_t byte = 0;
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
|
||||
byte |= bits[i];
|
||||
|
||||
if (i != length-1)
|
||||
if (i != length - 1)
|
||||
byte <<= 1;
|
||||
}
|
||||
|
||||
|
@ -128,7 +128,6 @@ static void msb2lsb_word(uint8_t *word) {
|
|||
// reorders given <word> according to EM4x50 datasheet (msb -> lsb)
|
||||
|
||||
uint8_t buff[4];
|
||||
|
||||
buff[0] = reflect8(word[3]);
|
||||
buff[1] = reflect8(word[2]);
|
||||
buff[2] = reflect8(word[1]);
|
||||
|
@ -144,23 +143,22 @@ static void save_word(int pos, uint8_t bits[EM4X50_TAG_WORD]) {
|
|||
|
||||
// split "raw" word into data, row and column parity bits and stop bit and
|
||||
// save them in global tag structure
|
||||
|
||||
uint8_t row_parity[4];
|
||||
uint8_t col_parity[8];
|
||||
|
||||
// data and row parities
|
||||
for (int i = 0; i < 4; i++) {
|
||||
tag.sectors[pos][i] = bits2byte(&bits[9*i],8);
|
||||
row_parity[i] = bits[9*i+8];
|
||||
tag.sectors[pos][i] = bits2byte(&bits[9 * i], 8);
|
||||
row_parity[i] = bits[9 * i + 8];
|
||||
}
|
||||
|
||||
tag.sectors[pos][4] = bits2byte(row_parity,4);
|
||||
tag.sectors[pos][4] = bits2byte(row_parity, 4);
|
||||
|
||||
// column parities
|
||||
for (int i = 0; i < 8; i++)
|
||||
col_parity[i] = bits[36+i];
|
||||
col_parity[i] = bits[36 + i];
|
||||
|
||||
tag.sectors[pos][5] = bits2byte(col_parity,8);
|
||||
tag.sectors[pos][5] = bits2byte(col_parity, 8);
|
||||
|
||||
// stop bit
|
||||
tag.sectors[pos][6] = bits[44];
|
||||
|
@ -186,15 +184,13 @@ static void wait_timer(int timer, uint32_t period) {
|
|||
static void em4x50_setup_read(void) {
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
||||
|
||||
// 50ms for the resonant antenna to settle.
|
||||
SpinDelay(50);
|
||||
|
||||
// Now set up the SSC to get the ADC samples that are now streaming at us.
|
||||
FpgaSetupSsc();
|
||||
// start a 1.5ticks is 1us
|
||||
StartTicks();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER);
|
||||
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125);
|
||||
|
||||
|
@ -245,11 +241,11 @@ static bool get_signalproperties(void) {
|
|||
|
||||
bool signal_found = false;
|
||||
int no_periods = 32, pct = 75, noise = 140;
|
||||
uint8_t sample = 0, sample_ref = 127;
|
||||
uint8_t sample_ref = 127;
|
||||
uint8_t sample_max_mean = 0;
|
||||
uint8_t sample_max[no_periods];
|
||||
uint32_t sample_max_sum = 0;
|
||||
|
||||
memcpy(sample_max, 0x00, sizeof(sample_max));
|
||||
|
||||
// wait until signal/noise > 1 (max. 32 periods)
|
||||
for (int i = 0; i < T0 * no_periods; i++) {
|
||||
|
@ -261,10 +257,9 @@ static bool get_signalproperties(void) {
|
|||
signal_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!signal_found)
|
||||
if (signal_found == false)
|
||||
return false;
|
||||
|
||||
// calculate mean maximum value of 32 periods, each period has a length of
|
||||
|
@ -274,7 +269,7 @@ static bool get_signalproperties(void) {
|
|||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
while (AT91C_BASE_TC0->TC_CV < T0 * 3 * EM4X50_T_TAG_FULL_PERIOD) {
|
||||
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
if (sample > sample_max[i])
|
||||
sample_max[i] = sample;
|
||||
|
@ -289,7 +284,6 @@ static bool get_signalproperties(void) {
|
|||
// set global envelope variables
|
||||
gHigh = sample_ref + pct * (sample_max_mean - sample_ref) / 100;
|
||||
gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -301,11 +295,9 @@ static int get_next_bit(void) {
|
|||
// a listen window (return value = EM4X50_BIT_OTHER) in functions
|
||||
// "find_double_listen_window" and "check_ack"
|
||||
|
||||
uint8_t sample;
|
||||
|
||||
// get sample at 3/4 of bit period
|
||||
wait_timer(0, T0 * EM4X50_T_TAG_THREE_QUARTER_PERIOD);
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
// wait until end of bit period
|
||||
wait_timer(0, T0 * EM4X50_T_TAG_QUARTER_PERIOD);
|
||||
|
@ -321,35 +313,46 @@ static int get_next_bit(void) {
|
|||
|
||||
static uint32_t get_pulse_length(void) {
|
||||
|
||||
// Dbprintf( _CYAN_("4x50 get_pulse_length A") );
|
||||
|
||||
int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
|
||||
// iterates pulse length (low -> high -> low)
|
||||
|
||||
uint8_t sample = 0;
|
||||
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
while (sample > gLow && (timeout--)) {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}
|
||||
|
||||
while (sample > gLow)
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
if (timeout == 0)
|
||||
return 0;
|
||||
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
|
||||
timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
|
||||
while (sample < gHigh)
|
||||
while (sample < gHigh && (timeout--)) {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}
|
||||
|
||||
while (sample > gLow)
|
||||
if (timeout == 0)
|
||||
return 0;
|
||||
|
||||
timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD);
|
||||
while (sample > gLow && (timeout--)) {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}
|
||||
|
||||
if (timeout == 0)
|
||||
return 0;
|
||||
|
||||
return (uint32_t)AT91C_BASE_TC1->TC_CV;
|
||||
|
||||
}
|
||||
|
||||
static bool check_pulse_length(uint32_t pl, int length) {
|
||||
|
||||
// check if pulse length <pl> corresponds to given length <length>
|
||||
|
||||
if ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) &
|
||||
(pl <= T0 * (length + EM4X50_TAG_TOLERANCE)))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
return ((pl >= T0 * (length - EM4X50_TAG_TOLERANCE)) & (pl <= T0 * (length + EM4X50_TAG_TOLERANCE)));
|
||||
}
|
||||
|
||||
static void em4x50_send_bit(int bit) {
|
||||
|
@ -388,7 +391,7 @@ static void em4x50_send_byte(uint8_t byte) {
|
|||
// send byte (without parity)
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
em4x50_send_bit((byte >> (7-i)) & 1);
|
||||
em4x50_send_bit((byte >> (7 - i)) & 1);
|
||||
|
||||
}
|
||||
|
||||
|
@ -399,7 +402,7 @@ static void em4x50_send_byte_with_parity(uint8_t byte) {
|
|||
int parity = 0, bit = 0;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bit = (byte >> (7-i)) & 1;
|
||||
bit = (byte >> (7 - i)) & 1;
|
||||
em4x50_send_bit(bit);
|
||||
parity ^= bit;
|
||||
}
|
||||
|
@ -437,13 +440,9 @@ static bool find_single_listen_window(void) {
|
|||
|
||||
// listen window found
|
||||
return true;
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
cnt_pulses++;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -503,7 +502,6 @@ static bool find_double_listen_window(bool bcommand) {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cnt_pulses++;
|
||||
}
|
||||
}
|
||||
|
@ -515,9 +513,7 @@ static bool find_em4x50_tag(void) {
|
|||
|
||||
// function is used to check wether a tag on the proxmark is an
|
||||
// EM4x50 tag or not -> speed up "lf search" process
|
||||
|
||||
return (find_single_listen_window());
|
||||
|
||||
return find_single_listen_window();
|
||||
}
|
||||
|
||||
static bool request_receive_mode(void) {
|
||||
|
@ -525,9 +521,7 @@ static bool request_receive_mode(void) {
|
|||
// To issue a command we have to find a listen window first.
|
||||
// Because identification and sychronization at the same time is not
|
||||
// possible when using pulse lengths a double listen window is used.
|
||||
|
||||
bool bcommand = true;
|
||||
|
||||
return find_double_listen_window(bcommand);
|
||||
}
|
||||
|
||||
|
@ -625,7 +619,7 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) {
|
|||
if (check_pulse_length(pl, EM4X50_T_TAG_FULL_PERIOD)) {
|
||||
|
||||
// pulse length = 1 -> keep former bit value
|
||||
bits[i] = bits[i-1];
|
||||
bits[i] = bits[i - 1];
|
||||
|
||||
} else if (check_pulse_length(pl, 3 * EM4X50_T_TAG_HALF_PERIOD)) {
|
||||
|
||||
|
@ -634,10 +628,10 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) {
|
|||
if (bbitchange) {
|
||||
|
||||
// if number of pulse lengths with 1.5 periods is even -> add bit
|
||||
bits[i] = (bits[i-1] == 1) ? 1 : 0;
|
||||
bits[i] = (bits[i - 1] == 1) ? 1 : 0;
|
||||
|
||||
// pulse length of 1.5 changes bit value
|
||||
bits[i+1] = (bits[i] == 1) ? 0 : 1;
|
||||
bits[i + 1] = (bits[i] == 1) ? 0 : 1;
|
||||
i++;
|
||||
|
||||
// next time add only one bit
|
||||
|
@ -645,7 +639,7 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) {
|
|||
|
||||
} else {
|
||||
|
||||
bits[i] = (bits[i-1] == 1) ? 0 : 1;
|
||||
bits[i] = (bits[i - 1] == 1) ? 0 : 1;
|
||||
|
||||
// next time two bits have to be added
|
||||
bbitchange = true;
|
||||
|
@ -655,7 +649,7 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) {
|
|||
|
||||
// pulse length of 2 means: adding 2 bits "01"
|
||||
bits[i] = 0;
|
||||
bits[i+1] = 1;
|
||||
bits[i + 1] = 1;
|
||||
i++;
|
||||
|
||||
} else if (check_pulse_length(pl, 3 * EM4X50_T_TAG_FULL_PERIOD)) {
|
||||
|
@ -677,7 +671,7 @@ static bool login(uint8_t password[4]) {
|
|||
// simple login to EM4x50,
|
||||
// used in operations that require authentication
|
||||
|
||||
if (request_receive_mode ()) {
|
||||
if (request_receive_mode()) {
|
||||
|
||||
// send login command
|
||||
em4x50_send_byte_with_parity(EM4X50_COMMAND_LOGIN);
|
||||
|
@ -705,7 +699,7 @@ static bool reset(void) {
|
|||
|
||||
// resets EM4x50 tag (used by write function)
|
||||
|
||||
if (request_receive_mode ()) {
|
||||
if (request_receive_mode()) {
|
||||
|
||||
// send login command
|
||||
em4x50_send_byte_with_parity(EM4X50_COMMAND_RESET);
|
||||
|
@ -1028,3 +1022,61 @@ void em4x50_write_password(em4x50_data_t *etd) {
|
|||
lf_finalize();
|
||||
reply_ng(CMD_ACK, bsuccess, 0, 0);
|
||||
}
|
||||
|
||||
void em4x50_wipe(em4x50_data_t *etd) {
|
||||
|
||||
// set all data of EM4x50 tag to 0x0 including password
|
||||
|
||||
bool bsuccess = false;
|
||||
uint8_t zero[4] = {0, 0, 0, 0};
|
||||
uint8_t addresses[4] = {0, 0, EM4X50_NO_WORDS - 3, 1};
|
||||
|
||||
init_tag();
|
||||
em4x50_setup_read();
|
||||
|
||||
// set gHigh and gLow
|
||||
if (get_signalproperties() && find_em4x50_tag()) {
|
||||
|
||||
// login first
|
||||
if (login(etd->password)) {
|
||||
|
||||
// write 0x0 to each address but ignore addresses
|
||||
// 0 -> password, 32 -> serial, 33 -> uid
|
||||
// writing 34 words takes about 3.6 seconds -> high timeout needed
|
||||
for (int i = 1; i <= EM4X50_NO_WORDS - 3; i++)
|
||||
write(zero, i);
|
||||
|
||||
// to verify result reset EM4x50
|
||||
if (reset()) {
|
||||
|
||||
// login not necessary because protectd word has been set to 0
|
||||
// -> no read protected words
|
||||
// -> selective read can be called immediately
|
||||
if (selective_read(addresses)) {
|
||||
|
||||
// check if everything is zero
|
||||
bsuccess = true;
|
||||
for (int i = 1; i <= EM4X50_NO_WORDS - 3; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
bsuccess &= (tag.sectors[i][j] == 0) ? true : false;
|
||||
|
||||
}
|
||||
|
||||
if (bsuccess) {
|
||||
|
||||
// so far everything is fine
|
||||
// last task: reset password
|
||||
if (login(etd->password))
|
||||
bsuccess = write_password(etd->password, zero);
|
||||
|
||||
// verify by login with new password
|
||||
if (bsuccess)
|
||||
bsuccess = login(zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lf_finalize();
|
||||
reply_ng(CMD_ACK, bsuccess, (uint8_t *)tag.sectors, 238);
|
||||
}
|
||||
|
|
|
@ -21,5 +21,6 @@ void em4x50_info(em4x50_data_t *etd);
|
|||
void em4x50_write(em4x50_data_t *etd);
|
||||
void em4x50_write_password(em4x50_data_t *etd);
|
||||
void em4x50_read(em4x50_data_t *etd);
|
||||
void em4x50_wipe(em4x50_data_t *etd);
|
||||
|
||||
#endif /* EM4X50_H */
|
||||
|
|
133
armsrc/epa.c
133
armsrc/epa.c
|
@ -113,17 +113,14 @@ static char iso_type = 0;
|
|||
//-----------------------------------------------------------------------------
|
||||
// Wrapper for sending APDUs to type A and B cards
|
||||
//-----------------------------------------------------------------------------
|
||||
static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response) {
|
||||
static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t respmaxlen) {
|
||||
switch (iso_type) {
|
||||
case 'a':
|
||||
return iso14_apdu(apdu, (uint16_t) length, false, response, NULL);
|
||||
break;
|
||||
case 'b':
|
||||
return iso14443b_apdu(apdu, length, response);
|
||||
break;
|
||||
return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL);
|
||||
default:
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,9 +146,8 @@ void EPA_Finish(void) {
|
|||
// TODO: Support elements with long tags (tag is longer than 1 byte)
|
||||
// TODO: Support proprietary PACE domain parameters
|
||||
//-----------------------------------------------------------------------------
|
||||
size_t EPA_Parse_CardAccess(uint8_t *data,
|
||||
size_t length,
|
||||
pace_version_info_t *pace_info) {
|
||||
size_t EPA_Parse_CardAccess(uint8_t *data, size_t length, pace_version_info_t *pace_info) {
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
while (index <= length - 2) {
|
||||
|
@ -165,19 +161,22 @@ size_t EPA_Parse_CardAccess(uint8_t *data,
|
|||
index += (data[index - 1] & 0x7F);
|
||||
}
|
||||
}
|
||||
|
||||
// OID
|
||||
else if (data[index] == 0x06) {
|
||||
// is this a PACE OID?
|
||||
if (data[index + 1] == 0x0A // length matches
|
||||
&& memcmp(data + index + 2,
|
||||
oid_pace_start,
|
||||
sizeof(oid_pace_start)) == 0 // content matches
|
||||
&& memcmp(data + index + 2, oid_pace_start, sizeof(oid_pace_start)) == 0 // content matches
|
||||
&& pace_info != NULL) {
|
||||
|
||||
// first, clear the pace_info struct
|
||||
memset(pace_info, 0, sizeof(pace_version_info_t));
|
||||
|
||||
memcpy(pace_info->oid, data + index + 2, sizeof(pace_info->oid));
|
||||
|
||||
// a PACE OID is followed by the version
|
||||
index += data[index + 1] + 2;
|
||||
|
||||
if (data[index] == 02 && data[index + 1] == 01) {
|
||||
pace_info->version = data[index + 2];
|
||||
index += 3;
|
||||
|
@ -189,6 +188,7 @@ size_t EPA_Parse_CardAccess(uint8_t *data,
|
|||
pace_info->parameter_id = data[index + 2];
|
||||
index += 3;
|
||||
}
|
||||
|
||||
} else {
|
||||
// skip this OID
|
||||
index += 2 + data[index + 1];
|
||||
|
@ -222,12 +222,14 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) {
|
|||
// since the card doesn't always care for the expected length we send it,
|
||||
// we reserve 262 bytes here just to be safe (256-byte APDU + SW + ISO frame)
|
||||
uint8_t response_apdu[262];
|
||||
int rapdu_length = 0;
|
||||
|
||||
// select the file EF.CardAccess
|
||||
rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess,
|
||||
int rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess,
|
||||
sizeof(apdu_select_binary_cardaccess),
|
||||
response_apdu);
|
||||
response_apdu,
|
||||
sizeof(response_apdu)
|
||||
);
|
||||
|
||||
if (rapdu_length < 6
|
||||
|| response_apdu[rapdu_length - 4] != 0x90
|
||||
|| response_apdu[rapdu_length - 3] != 0x00) {
|
||||
|
@ -238,7 +240,10 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) {
|
|||
// read the file
|
||||
rapdu_length = EPA_APDU((uint8_t *)apdu_read_binary,
|
||||
sizeof(apdu_read_binary),
|
||||
response_apdu);
|
||||
response_apdu,
|
||||
sizeof(response_apdu)
|
||||
);
|
||||
|
||||
if (rapdu_length <= 6
|
||||
|| response_apdu[rapdu_length - 4] != 0x90
|
||||
|| response_apdu[rapdu_length - 3] != 0x00) {
|
||||
|
@ -248,22 +253,22 @@ int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) {
|
|||
|
||||
// copy the content into the buffer
|
||||
// length of data available: apdu_length - 4 (ISO frame) - 2 (SW)
|
||||
size_t to_copy = rapdu_length - 6;
|
||||
to_copy = to_copy < max_length ? to_copy : max_length;
|
||||
memcpy(buffer, response_apdu + 2, to_copy);
|
||||
return to_copy;
|
||||
size_t len = rapdu_length - 6;
|
||||
len = len < max_length ? len : max_length;
|
||||
memcpy(buffer, response_apdu + 2, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Abort helper function for EPA_PACE_Collect_Nonce
|
||||
// sets relevant data in ack, sends the response
|
||||
//-----------------------------------------------------------------------------
|
||||
static void EPA_PACE_Collect_Nonce_Abort(uint8_t step, int func_return) {
|
||||
static void EPA_PACE_Collect_Nonce_Abort(uint32_t cmd, uint8_t step, int func_return) {
|
||||
// power down the field
|
||||
EPA_Finish();
|
||||
|
||||
// send the USB packet
|
||||
reply_mix(CMD_ACK, step, func_return, 0, 0, 0);
|
||||
reply_mix(cmd, step, func_return, 0, 0, 0);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -283,28 +288,28 @@ void EPA_PACE_Collect_Nonce(PacketCommandNG *c) {
|
|||
// set up communication
|
||||
int func_return = EPA_Setup();
|
||||
if (func_return != 0) {
|
||||
EPA_PACE_Collect_Nonce_Abort(1, func_return);
|
||||
EPA_PACE_Collect_Nonce_Abort(CMD_HF_EPA_COLLECT_NONCE, 1, func_return);
|
||||
return;
|
||||
}
|
||||
|
||||
// read the CardAccess file
|
||||
// this array will hold the CardAccess file
|
||||
uint8_t card_access[256] = {0};
|
||||
int card_access_length = EPA_Read_CardAccess(card_access, 256);
|
||||
int cardlen = EPA_Read_CardAccess(card_access, 256);
|
||||
// the response has to be at least this big to hold the OID
|
||||
if (card_access_length < 18) {
|
||||
EPA_PACE_Collect_Nonce_Abort(2, card_access_length);
|
||||
if (cardlen < 18) {
|
||||
EPA_PACE_Collect_Nonce_Abort(CMD_HF_EPA_COLLECT_NONCE, 2, cardlen);
|
||||
return;
|
||||
}
|
||||
|
||||
// this will hold the PACE info of the card
|
||||
pace_version_info_t pace_version_info;
|
||||
|
||||
// search for the PACE OID
|
||||
func_return = EPA_Parse_CardAccess(card_access,
|
||||
card_access_length,
|
||||
&pace_version_info);
|
||||
func_return = EPA_Parse_CardAccess(card_access, cardlen, &pace_version_info);
|
||||
|
||||
if (func_return != 0 || pace_version_info.version == 0) {
|
||||
EPA_PACE_Collect_Nonce_Abort(3, func_return);
|
||||
EPA_PACE_Collect_Nonce_Abort(CMD_HF_EPA_COLLECT_NONCE, 3, func_return);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -313,25 +318,29 @@ void EPA_PACE_Collect_Nonce(PacketCommandNG *c) {
|
|||
func_return = EPA_PACE_MSE_Set_AT(pace_version_info, 2);
|
||||
// check if the command succeeded
|
||||
if (func_return != 0) {
|
||||
EPA_PACE_Collect_Nonce_Abort(4, func_return);
|
||||
EPA_PACE_Collect_Nonce_Abort(CMD_HF_EPA_COLLECT_NONCE, 4, func_return);
|
||||
return;
|
||||
}
|
||||
|
||||
// now get the nonce
|
||||
uint8_t nonce[256] = {0};
|
||||
uint8_t requested_size = (uint8_t)c->oldarg[0];
|
||||
func_return = EPA_PACE_Get_Nonce(requested_size, nonce);
|
||||
|
||||
struct p {
|
||||
uint32_t m;
|
||||
} PACKED;
|
||||
struct p *packet = (struct p *)c->data.asBytes;
|
||||
|
||||
func_return = EPA_PACE_Get_Nonce(packet->m, nonce);
|
||||
// check if the command succeeded
|
||||
if (func_return < 0) {
|
||||
EPA_PACE_Collect_Nonce_Abort(5, func_return);
|
||||
EPA_PACE_Collect_Nonce_Abort(CMD_HF_EPA_COLLECT_NONCE, 5, func_return);
|
||||
return;
|
||||
}
|
||||
|
||||
// all done, return
|
||||
EPA_Finish();
|
||||
|
||||
// save received information
|
||||
reply_mix(CMD_ACK, 0, func_return, 0, nonce, func_return);
|
||||
reply_mix(CMD_HF_EPA_COLLECT_NONCE, 0, func_return, 0, nonce, func_return);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -343,21 +352,18 @@ void EPA_PACE_Collect_Nonce(PacketCommandNG *c) {
|
|||
// code on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) {
|
||||
|
||||
// build the APDU
|
||||
uint8_t apdu[sizeof(apdu_general_authenticate_pace_get_nonce) + 1];
|
||||
|
||||
// copy the constant part
|
||||
memcpy(apdu,
|
||||
apdu_general_authenticate_pace_get_nonce,
|
||||
sizeof(apdu_general_authenticate_pace_get_nonce));
|
||||
memcpy(apdu, apdu_general_authenticate_pace_get_nonce, sizeof(apdu_general_authenticate_pace_get_nonce));
|
||||
|
||||
// append Le (requested length + 2 due to tag/length taking 2 bytes) in RAPDU
|
||||
apdu[sizeof(apdu_general_authenticate_pace_get_nonce)] = requested_length + 4;
|
||||
|
||||
// send it
|
||||
uint8_t response_apdu[262];
|
||||
int send_return = EPA_APDU(apdu,
|
||||
sizeof(apdu),
|
||||
response_apdu);
|
||||
// check if the command succeeded
|
||||
int send_return = EPA_APDU(apdu, sizeof(apdu), response_apdu, sizeof(response_apdu));
|
||||
if (send_return < 6
|
||||
|| response_apdu[send_return - 4] != 0x90
|
||||
|| response_apdu[send_return - 3] != 0x00) {
|
||||
|
@ -387,26 +393,31 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) {
|
|||
int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) {
|
||||
// create the MSE: Set AT APDU
|
||||
uint8_t apdu[23];
|
||||
|
||||
// the minimum length (will be increased as more data is added)
|
||||
size_t apdu_length = 20;
|
||||
|
||||
// copy the constant part
|
||||
memcpy(apdu,
|
||||
apdu_mse_set_at_start,
|
||||
sizeof(apdu_mse_set_at_start));
|
||||
memcpy(apdu, apdu_mse_set_at_start, sizeof(apdu_mse_set_at_start));
|
||||
|
||||
// type: OID
|
||||
apdu[5] = 0x80;
|
||||
|
||||
// length of the OID
|
||||
apdu[6] = sizeof(pace_version_info.oid);
|
||||
|
||||
// copy the OID
|
||||
memcpy(apdu + 7,
|
||||
pace_version_info.oid,
|
||||
sizeof(pace_version_info.oid));
|
||||
memcpy(apdu + 7, pace_version_info.oid, sizeof(pace_version_info.oid));
|
||||
|
||||
// type: password
|
||||
apdu[17] = 0x83;
|
||||
|
||||
// length: 1
|
||||
apdu[18] = 1;
|
||||
|
||||
// password
|
||||
apdu[19] = password;
|
||||
|
||||
// if standardized domain parameters are used, copy the ID
|
||||
if (pace_version_info.parameter_id != 0) {
|
||||
apdu_length += 3;
|
||||
|
@ -417,17 +428,23 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password)
|
|||
// copy the parameter ID
|
||||
apdu[22] = pace_version_info.parameter_id;
|
||||
}
|
||||
|
||||
// now set Lc to the actual length
|
||||
apdu[4] = apdu_length - 5;
|
||||
|
||||
// send it
|
||||
uint8_t response_apdu[6];
|
||||
int send_return = EPA_APDU(apdu,
|
||||
apdu_length,
|
||||
response_apdu);
|
||||
int send_return = EPA_APDU(apdu, apdu_length, response_apdu, sizeof(response_apdu));
|
||||
|
||||
Dbprintf("send ret %d bytes", send_return);
|
||||
|
||||
// Dbhexdump(send_return, response_apdu, false);
|
||||
|
||||
// check if the command succeeded
|
||||
if (send_return != 6
|
||||
|| response_apdu[send_return - 4] != 0x90
|
||||
|| response_apdu[send_return - 3] != 0x00) {
|
||||
if (send_return != 6)
|
||||
// && response_apdu[send_return - 4] != 0x90
|
||||
// || response_apdu[send_return - 3] != 0x00)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -480,7 +497,9 @@ void EPA_PACE_Replay(PacketCommandNG *c) {
|
|||
StartCountUS();
|
||||
func_return = EPA_APDU(apdus_replay[i].data,
|
||||
apdu_lengths_replay[i],
|
||||
response_apdu);
|
||||
response_apdu,
|
||||
sizeof(response_apdu)
|
||||
);
|
||||
timings[i] = GetCountUS();
|
||||
// every step but the last one should succeed
|
||||
if (i < ARRAYLEN(apdu_lengths_replay) - 1
|
||||
|
@ -536,6 +555,6 @@ int EPA_Setup(void) {
|
|||
iso_type = 'b';
|
||||
return 0;
|
||||
}
|
||||
Dbprintf("No card found.");
|
||||
Dbprintf("No card found");
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "commonutil.h"
|
||||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
#include "mifare.h"
|
||||
#include "iso18.h"
|
||||
|
||||
// FeliCa timings
|
||||
// minimum time between the start bits of consecutive transfers from reader to tag: 6800 carrier (13.56MHz) cycles
|
||||
|
@ -336,7 +336,7 @@ static void BuildFliteRdblk(uint8_t *idm, int blocknum, uint16_t *blocks) {
|
|||
}
|
||||
|
||||
static void TransmitFor18092_AsReader(uint8_t *frame, int len, uint32_t *timing, uint8_t power, uint8_t highspeed) {
|
||||
uint8_t flags = FPGA_MAJOR_MODE_HF_ISO18092;
|
||||
uint16_t flags = FPGA_MAJOR_MODE_HF_ISO18092;
|
||||
if (power)
|
||||
flags |= FPGA_HF_ISO18092_FLAG_READER;
|
||||
if (highspeed)
|
||||
|
@ -445,7 +445,7 @@ static void iso18092_setup(uint8_t fpga_minor_mode) {
|
|||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Start iso18092_setup");
|
||||
|
||||
LEDsoff();
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF_FELICA);
|
||||
|
||||
// allocate command receive buffer
|
||||
BigBuf_free();
|
||||
|
@ -464,7 +464,7 @@ static void iso18092_setup(uint8_t fpga_minor_mode) {
|
|||
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
|
||||
|
||||
// Set up the synchronous serial port
|
||||
FpgaSetupSsc();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO18092);
|
||||
|
||||
// LSB transfer. Remember to set it back to MSB with
|
||||
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
||||
|
|
|
@ -134,7 +134,7 @@ void SetupSpi(int mode) {
|
|||
// Set up the synchronous serial port with the set of options that fits
|
||||
// the FPGA mode. Both RX and TX are always enabled.
|
||||
//-----------------------------------------------------------------------------
|
||||
void FpgaSetupSsc(void) {
|
||||
void FpgaSetupSsc(uint16_t fpga_mode) {
|
||||
// First configure the GPIOs, and get ourselves a clock.
|
||||
AT91C_BASE_PIOA->PIO_ASR =
|
||||
GPIO_SSC_FRAME |
|
||||
|
@ -152,12 +152,16 @@ void FpgaSetupSsc(void) {
|
|||
// data and frame signal is sampled on falling edge of RK
|
||||
AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
|
||||
|
||||
// 8 bits per transfer, no loopback, MSB first, 1 transfer per sync
|
||||
// 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync
|
||||
// pulse, no output sync
|
||||
if ((fpga_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_READER && FpgaGetCurrent() == FPGA_BITSTREAM_HF) {
|
||||
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
||||
} else {
|
||||
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
||||
}
|
||||
|
||||
// TX clock comes from TK pin, no clock output, outputs change on falling
|
||||
// edge of TK, frame sync is sampled on rising edge of TK, start TX on rising edge of TF
|
||||
// TX clock comes from TK pin, no clock output, outputs change on rising edge of TK,
|
||||
// TF (frame sync) is sampled on falling edge of TK, start TX on rising edge of TF
|
||||
AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
|
||||
|
||||
// tx framing is the same as the rx framing
|
||||
|
@ -171,7 +175,7 @@ void FpgaSetupSsc(void) {
|
|||
// a single buffer as a circular buffer (so that we just chain back to
|
||||
// ourselves, not to another buffer).
|
||||
//-----------------------------------------------------------------------------
|
||||
bool FpgaSetupSscDma(uint8_t *buf, int len) {
|
||||
bool FpgaSetupSscDma(uint8_t *buf, uint16_t len) {
|
||||
if (buf == NULL) return false;
|
||||
|
||||
FpgaDisableSscDma();
|
||||
|
@ -184,8 +188,7 @@ bool FpgaSetupSscDma(uint8_t *buf, int len) {
|
|||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Uncompress (inflate) the FPGA data. Returns one decompressed byte with
|
||||
// each call.
|
||||
// Uncompress (inflate) the FPGA data. Returns one decompressed byte with each call.
|
||||
//----------------------------------------------------------------------------
|
||||
static int get_from_fpga_combined_stream(lz4_streamp compressed_fpga_stream, uint8_t *output_buffer) {
|
||||
if (fpga_image_ptr == output_buffer + FPGA_RING_BUFFER_BYTES) { // need more data
|
||||
|
@ -347,8 +350,10 @@ static void DownloadFPGA(int bitstream_version, int FpgaImageLen, lz4_streamp co
|
|||
* length.
|
||||
*/
|
||||
static int bitparse_find_section(int bitstream_version, char section_name, uint32_t *section_length, lz4_streamp compressed_fpga_stream, uint8_t *output_buffer) {
|
||||
int result = 0;
|
||||
|
||||
#define MAX_FPGA_BIT_STREAM_HEADER_SEARCH 100 // maximum number of bytes to search for the requested section
|
||||
|
||||
int result = 0;
|
||||
uint16_t numbytes = 0;
|
||||
while (numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) {
|
||||
char current_name = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
|
||||
|
@ -439,7 +444,7 @@ void FpgaDownloadAndGo(int bitstream_version) {
|
|||
// The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
|
||||
// where C is the 4 bit command and D is the 12 bit data
|
||||
//
|
||||
// @params cmd and v gets or over eachother. Take careful note of overlapping bits.
|
||||
// @params cmd and v gets OR:ED over each other. Take careful note of overlapping bits.
|
||||
//-----------------------------------------------------------------------------
|
||||
void FpgaSendCommand(uint16_t cmd, uint16_t v) {
|
||||
SetupSpi(SPI_FPGA_MODE);
|
||||
|
@ -520,10 +525,13 @@ int FpgaGetCurrent(void) {
|
|||
// if HF, Disable SSC DMA
|
||||
// turn off trace and leds off.
|
||||
void switch_off(void) {
|
||||
if (DBGLEVEL > 3) Dbprintf("switch_off");
|
||||
if (DBGLEVEL > 3) {
|
||||
Dbprintf("switch_off");
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
if (downloaded_bitstream == FPGA_BITSTREAM_HF)
|
||||
if (downloaded_bitstream == FPGA_BITSTREAM_HF) {
|
||||
FpgaDisableSscDma();
|
||||
}
|
||||
set_tracing(false);
|
||||
LEDsoff();
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
// definitions for multiple FPGA config files support
|
||||
#define FPGA_BITSTREAM_LF 1
|
||||
#define FPGA_BITSTREAM_HF 2
|
||||
#define FPGA_BITSTREAM_HF_FELICA 3
|
||||
|
||||
/*
|
||||
Communication between ARM / FPGA is done inside armsrc/fpgaloader.c (function FpgaSendCommand)
|
||||
|
@ -52,23 +53,26 @@ thres| x x x x x x x x
|
|||
#define FPGA_CMD_TRACE_ENABLE (2<<12) // C
|
||||
|
||||
// Definitions for the FPGA configuration word.
|
||||
#define FPGA_MAJOR_MODE_MASK 0x01C0
|
||||
#define FPGA_MINOR_MODE_MASK 0x003F
|
||||
|
||||
// LF
|
||||
#define FPGA_MAJOR_MODE_LF_READER (0<<5)
|
||||
#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<5)
|
||||
#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<5)
|
||||
#define FPGA_MAJOR_MODE_LF_ADC (3<<5)
|
||||
#define FPGA_MAJOR_MODE_LF_READER (0<<6)
|
||||
#define FPGA_MAJOR_MODE_LF_EDGE_DETECT (1<<6)
|
||||
#define FPGA_MAJOR_MODE_LF_PASSTHRU (2<<6)
|
||||
#define FPGA_MAJOR_MODE_LF_ADC (3<<6)
|
||||
|
||||
// HF
|
||||
#define FPGA_MAJOR_MODE_HF_READER_TX (0<<5) // D
|
||||
#define FPGA_MAJOR_MODE_HF_READER_RX_XCORR (1<<5) // D
|
||||
#define FPGA_MAJOR_MODE_HF_SIMULATOR (2<<5) // D
|
||||
#define FPGA_MAJOR_MODE_HF_ISO14443A (3<<5) // D
|
||||
#define FPGA_MAJOR_MODE_HF_SNOOP (4<<5) // D
|
||||
#define FPGA_MAJOR_MODE_HF_ISO18092 (5<<5) // D
|
||||
#define FPGA_MAJOR_MODE_HF_GET_TRACE (6<<5) // D
|
||||
#define FPGA_MAJOR_MODE_HF_READER (0<<6) // D
|
||||
#define FPGA_MAJOR_MODE_HF_SIMULATOR (1<<6) // D
|
||||
#define FPGA_MAJOR_MODE_HF_ISO14443A (2<<6) // D
|
||||
#define FPGA_MAJOR_MODE_HF_SNIFF (3<<6) // D
|
||||
#define FPGA_MAJOR_MODE_HF_ISO18092 (4<<6) // D
|
||||
#define FPGA_MAJOR_MODE_HF_GET_TRACE (5<<6) // D
|
||||
|
||||
// BOTH HF / LF
|
||||
#define FPGA_MAJOR_MODE_OFF (7<<5) // D
|
||||
#define FPGA_MAJOR_MODE_OFF (7<<6) // D
|
||||
|
||||
|
||||
// Options for LF_READER
|
||||
#define FPGA_LF_ADC_READER_FIELD 0x1
|
||||
|
@ -78,13 +82,20 @@ thres| x x x x x x x x
|
|||
#define FPGA_LF_EDGE_DETECT_READER_FIELD 0x1
|
||||
#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE 0x2
|
||||
|
||||
// Options for the HF reader, tx to tag
|
||||
#define FPGA_HF_READER_TX_SHALLOW_MOD 0x1
|
||||
// Options for the HF reader
|
||||
#define FPGA_HF_READER_MODE_RECEIVE_IQ (0<<0)
|
||||
#define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE (1<<0)
|
||||
#define FPGA_HF_READER_MODE_RECEIVE_PHASE (2<<0)
|
||||
#define FPGA_HF_READER_MODE_SEND_FULL_MOD (3<<0)
|
||||
#define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD (4<<0)
|
||||
#define FPGA_HF_READER_MODE_SNIFF_IQ (5<<0)
|
||||
#define FPGA_HF_READER_MODE_SNIFF_AMPLITUDE (6<<0)
|
||||
#define FPGA_HF_READER_MODE_SNIFF_PHASE (7<<0)
|
||||
#define FPGA_HF_READER_MODE_SEND_JAM (8<<0)
|
||||
|
||||
// Options for the HF reader, correlating against rx from tag
|
||||
#define FPGA_HF_READER_RX_XCORR_848_KHZ 0x1
|
||||
#define FPGA_HF_READER_RX_XCORR_SNOOP 0x2
|
||||
#define FPGA_HF_READER_RX_XCORR_QUARTER 0x4
|
||||
#define FPGA_HF_READER_SUBCARRIER_848_KHZ (0<<4)
|
||||
#define FPGA_HF_READER_SUBCARRIER_424_KHZ (1<<4)
|
||||
#define FPGA_HF_READER_SUBCARRIER_212_KHZ (2<<4)
|
||||
|
||||
// Options for the HF simulated tag, how to modulate
|
||||
#define FPGA_HF_SIMULATOR_NO_MODULATION 0x0 // 0000
|
||||
|
@ -112,9 +123,9 @@ void FpgaEnableTracing(void);
|
|||
void FpgaDisableTracing(void);
|
||||
void FpgaDownloadAndGo(int bitstream_version);
|
||||
// void FpgaGatherVersion(int bitstream_version, char *dst, int len);
|
||||
void FpgaSetupSsc(void);
|
||||
void FpgaSetupSsc(uint16_t fpga_mode);
|
||||
void SetupSpi(int mode);
|
||||
bool FpgaSetupSscDma(uint8_t *buf, int len);
|
||||
bool FpgaSetupSscDma(uint8_t *buf, uint16_t len);
|
||||
void Fpga_print_status(void);
|
||||
int FpgaGetCurrent(void);
|
||||
void SetAdcMuxFor(uint32_t whichGpio);
|
||||
|
|
|
@ -41,12 +41,12 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) {
|
|||
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
|
||||
|
||||
// Set up the synchronous serial port
|
||||
FpgaSetupSsc();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SNIFF);
|
||||
|
||||
// Setting Frame Mode For better performance on high speed data transfer.
|
||||
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16);
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNIFF);
|
||||
SpinDelay(100);
|
||||
|
||||
*len = (BigBuf_max_traceLen() & 0xFFFE);
|
||||
|
@ -97,7 +97,7 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) {
|
|||
}
|
||||
}
|
||||
|
||||
optimizedSniff((uint16_t*)mem, *len);
|
||||
optimizedSniff((uint16_t *)mem, *len);
|
||||
|
||||
if (DBGLEVEL >= DBG_INFO) {
|
||||
Dbprintf("Trigger kicked in (%d >= 180)", r);
|
||||
|
@ -114,17 +114,18 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) {
|
|||
}
|
||||
|
||||
void HfPlotDownload(void) {
|
||||
uint8_t *buf = ToSend;
|
||||
uint8_t *this_buf = buf;
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
uint8_t *this_buf = ts->buf;
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
FpgaSetupSsc();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_GET_TRACE);
|
||||
|
||||
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer
|
||||
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) this_buf; // start transfer to this memory address
|
||||
AT91C_BASE_PDC_SSC->PDC_RCR = PM3_CMD_DATA_SIZE; // transfer this many samples
|
||||
buf[0] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // clear receive register
|
||||
ts->buf[0] = (uint8_t)AT91C_BASE_SSC->SSC_RHR; // clear receive register
|
||||
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // Start DMA transfer
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_GET_TRACE); // let FPGA transfer its internal Block-RAM
|
||||
|
@ -132,7 +133,7 @@ void HfPlotDownload(void) {
|
|||
LED_B_ON();
|
||||
for (size_t i = 0; i < FPGA_TRACE_SIZE; i += PM3_CMD_DATA_SIZE) {
|
||||
// prepare next DMA transfer:
|
||||
uint8_t *next_buf = buf + ((i + PM3_CMD_DATA_SIZE) % (2 * PM3_CMD_DATA_SIZE));
|
||||
uint8_t *next_buf = ts->buf + ((i + PM3_CMD_DATA_SIZE) % (2 * PM3_CMD_DATA_SIZE));
|
||||
|
||||
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t)next_buf;
|
||||
AT91C_BASE_PDC_SSC->PDC_RNCR = PM3_CMD_DATA_SIZE;
|
||||
|
|
|
@ -130,6 +130,8 @@ static int hitag2_init(void) {
|
|||
#define HITAG_T_WAIT_2_MIN 90 /* T_wait2 should be at least 90 */
|
||||
#define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */
|
||||
#define HITAG_T_PROG 614
|
||||
#define HITAG_T_WAIT_POWERUP 313 /* transponder internal powerup time is 312.5 */
|
||||
#define HITAG_T_WAIT_START_AUTH_MAX 232 /* transponder waiting time to receive the START_AUTH command is 232.5, then it enters public mode */
|
||||
|
||||
#define HITAG_T_TAG_ONE_HALF_PERIOD 10
|
||||
#define HITAG_T_TAG_TWO_HALF_PERIOD 25
|
||||
|
@ -1002,7 +1004,7 @@ void SniffHitag2(void) {
|
|||
size_t periods = 0;
|
||||
uint8_t periods_bytes[4];
|
||||
|
||||
// int16_t checked = 0;
|
||||
// int16_t checked = 0;
|
||||
|
||||
/*bool waiting_for_first_edge = true;*/
|
||||
LED_C_ON();
|
||||
|
@ -1015,7 +1017,7 @@ void SniffHitag2(void) {
|
|||
|
||||
WDT_HIT();
|
||||
|
||||
/*
|
||||
/*
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 1000) {
|
||||
if (data_available()) {
|
||||
|
@ -1431,13 +1433,14 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
|
||||
// init as reader
|
||||
lf_init(true, false);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
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];
|
||||
bool turn_on = true;
|
||||
size_t nrzs = 0;
|
||||
int16_t checked = 0;
|
||||
|
||||
uint32_t signal_size = 10000;
|
||||
|
||||
while (bStop == false && BUTTON_PRESS() == false) {
|
||||
|
@ -1487,6 +1490,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
}
|
||||
case RHT2F_UID_ONLY: {
|
||||
bStop = !hitag2_read_uid(rx, rxlen, tx, &txlen);
|
||||
if (bSuccessful) bStop = true;
|
||||
attempt_count++; //attempt 3 times to get uid then quit
|
||||
if (!bStop && attempt_count == 3)
|
||||
bStop = true;
|
||||
|
@ -1498,11 +1502,20 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) {
|
|||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (bStop) break;
|
||||
if (turn_on) {
|
||||
// Wait 50ms with field off to be sure the transponder gets reset
|
||||
SpinDelay(50);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
||||
turn_on = false;
|
||||
// Wait with field on to be in "Wait for START_AUTH" timeframe
|
||||
lf_wait_periods(HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4);
|
||||
command_start += HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4;
|
||||
} else {
|
||||
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
||||
lf_wait_periods(t_wait_2);
|
||||
command_start += t_wait_2;
|
||||
|
||||
}
|
||||
// Transmit the reader frame
|
||||
command_duration = hitag_reader_send_frame(tx, txlen);
|
||||
response_start = command_start + command_duration;
|
||||
|
@ -1734,6 +1747,7 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
|
||||
// init as reader
|
||||
lf_init(true, false);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
// Tag specific configuration settings (sof, timings, etc.)
|
||||
// TODO HTS
|
||||
|
@ -1767,9 +1781,10 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
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;
|
||||
uint32_t signal_size = 10000;
|
||||
bool turn_on = true;
|
||||
|
||||
while (bStop == false && BUTTON_PRESS() == false) {
|
||||
|
||||
// use malloc
|
||||
|
@ -1805,9 +1820,20 @@ void WriterHitag(hitag_function htf, hitag_data *htd, int page) {
|
|||
}
|
||||
}
|
||||
|
||||
if (bStop) break;
|
||||
if (turn_on) {
|
||||
// Wait 50ms with field off to be sure the transponder gets reset
|
||||
SpinDelay(50);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
||||
turn_on = false;
|
||||
// Wait with field on to be in "Wait for START_AUTH" timeframe
|
||||
lf_wait_periods(HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4);
|
||||
command_start += HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4;
|
||||
} else {
|
||||
// Wait for t_wait_2 carrier periods after the last tag bit before transmitting,
|
||||
lf_wait_periods(t_wait_2);
|
||||
command_start += t_wait_2;
|
||||
}
|
||||
|
||||
// Transmit the reader frame
|
||||
command_duration = hitag_reader_send_frame(tx, txlen);
|
||||
|
|
26
armsrc/i2c.c
26
armsrc/i2c.c
|
@ -225,7 +225,7 @@ static bool I2C_WaitForSim(void) {
|
|||
// 8051 speaks with smart card.
|
||||
// 1000*50*3.07 = 153.5ms
|
||||
// 1byte transfer == 1ms with max frame being 256bytes
|
||||
if (!WaitSCL_H_delay(20 * 1000 * 50))
|
||||
if (!WaitSCL_H_delay(30 * 1000 * 50))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -631,7 +631,7 @@ int I2C_get_version(uint8_t *maj, uint8_t *min) {
|
|||
}
|
||||
|
||||
// Will read response from smart card module, retries 3 times to get the data.
|
||||
static bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen) {
|
||||
bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen) {
|
||||
|
||||
uint8_t i = 3;
|
||||
int16_t len = 0;
|
||||
|
@ -658,7 +658,7 @@ static bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GetATR(smart_card_atr_t *card_ptr) {
|
||||
bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
|
||||
|
||||
if (!card_ptr)
|
||||
return false;
|
||||
|
@ -666,19 +666,18 @@ bool GetATR(smart_card_atr_t *card_ptr) {
|
|||
card_ptr->atr_len = 0;
|
||||
memset(card_ptr->atr, 0, sizeof(card_ptr->atr));
|
||||
|
||||
|
||||
// Send ATR
|
||||
// start [C0 01] stop start C1 len aa bb cc stop]
|
||||
I2C_WriteCmd(I2C_DEVICE_CMD_GENERATE_ATR, I2C_DEVICE_ADDRESS_MAIN);
|
||||
|
||||
//wait for sim card to answer.
|
||||
// 1byte = 1ms , max frame 256bytes. SHould wait 256ms atleast just in case.
|
||||
if (!I2C_WaitForSim())
|
||||
// 1byte = 1ms , max frame 256bytes. Should wait 256ms atleast just in case.
|
||||
if (I2C_WaitForSim() == false)
|
||||
return false;
|
||||
|
||||
// read bytes from module
|
||||
uint8_t len = sizeof(card_ptr->atr);
|
||||
if (!sc_rx_bytes(card_ptr->atr, &len))
|
||||
if (sc_rx_bytes(card_ptr->atr, &len) == false)
|
||||
return false;
|
||||
|
||||
uint8_t pos_td = 1;
|
||||
|
@ -706,17 +705,19 @@ bool GetATR(smart_card_atr_t *card_ptr) {
|
|||
}
|
||||
|
||||
card_ptr->atr_len = len;
|
||||
if (verbose) {
|
||||
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SmartCardAtr(void) {
|
||||
smart_card_atr_t card;
|
||||
LED_D_ON();
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
I2C_Reset_EnterMainProgram();
|
||||
bool isOK = GetATR(&card);
|
||||
bool isOK = GetATR(&card, true);
|
||||
reply_mix(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
|
||||
set_tracing(false);
|
||||
LEDsoff();
|
||||
|
@ -730,10 +731,13 @@ void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data) {
|
|||
uint8_t *resp = BigBuf_malloc(ISO7618_MAX_FRAME);
|
||||
smartcard_command_t flags = arg0;
|
||||
|
||||
if ((flags & SC_CONNECT))
|
||||
if ((flags & SC_CLEARLOG) == SC_CLEARLOG)
|
||||
clear_trace();
|
||||
|
||||
if ((flags & SC_LOG) == SC_LOG)
|
||||
set_tracing(true);
|
||||
else
|
||||
set_tracing(false);
|
||||
|
||||
if ((flags & SC_CONNECT)) {
|
||||
|
||||
|
@ -741,7 +745,7 @@ void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data) {
|
|||
|
||||
if ((flags & SC_SELECT)) {
|
||||
smart_card_atr_t card;
|
||||
bool gotATR = GetATR(&card);
|
||||
bool gotATR = GetATR(&card, true);
|
||||
//reply_old(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
|
||||
if (!gotATR)
|
||||
goto OUT;
|
||||
|
|
|
@ -33,8 +33,9 @@ int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d
|
|||
int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address);
|
||||
bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address);
|
||||
|
||||
bool sc_rx_bytes(uint8_t *dest, uint8_t *destlen);
|
||||
//
|
||||
bool GetATR(smart_card_atr_t *card_ptr);
|
||||
bool GetATR(smart_card_atr_t *card_ptr, bool verbose);
|
||||
|
||||
// generice functions
|
||||
void SmartCardAtr(void);
|
||||
|
|
3378
armsrc/iclass.c
3378
armsrc/iclass.c
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Jonathan Westhues, Aug 2005
|
||||
// Gerhard de Koning Gans, April 2008, May 2011
|
||||
// Iceman, August 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
|
||||
|
@ -12,18 +13,30 @@
|
|||
#define __ICLASS_H
|
||||
|
||||
#include "common.h"
|
||||
#include "pm3_cmd.h"
|
||||
|
||||
void RAMFUNC SniffIClass(void);
|
||||
void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||
void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
|
||||
void ReaderIClass(uint8_t arg0);
|
||||
void ReaderIClass_Replay(uint8_t arg0, uint8_t *mac);
|
||||
void iClass_Authentication(uint8_t *mac);
|
||||
void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain);
|
||||
void iClass_WriteBlock(uint8_t blockno, uint8_t *data);
|
||||
void iClass_ReadBlk(uint8_t blockno);
|
||||
bool iClass_ReadBlock(uint8_t blockno, uint8_t *data, uint8_t len);
|
||||
void iClass_Dump(uint8_t blockno, uint8_t numblks);
|
||||
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data);
|
||||
void iClass_ReadCheck(uint8_t blockno, uint8_t keytype);
|
||||
void ReaderIClass_Replay(uint8_t *rnr, uint8_t *mac);
|
||||
|
||||
void iClass_WriteBlock(uint8_t *msg);
|
||||
void iClass_Dump(uint8_t *msg);
|
||||
|
||||
void iClass_Restore(uint8_t *msg);
|
||||
void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data);
|
||||
|
||||
int do_iclass_simulation_nonsec(void);
|
||||
int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf);
|
||||
void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||
void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_t *datain, uint8_t *dataout, uint16_t *dataoutlen);
|
||||
|
||||
void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain);
|
||||
void iClass_Authentication(uint8_t *bytes);
|
||||
bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out);
|
||||
|
||||
void iClass_ReadBlock(uint8_t *msg);
|
||||
bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time);
|
||||
|
||||
bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time);
|
||||
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out);
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -96,6 +96,9 @@ typedef struct {
|
|||
# define CheckCrc14A(data, len) check_crc(CRC_14443_A, (data), (len))
|
||||
#endif
|
||||
|
||||
void printHf14aConfig(void);
|
||||
void setHf14aConfig(hf14a_config *hc);
|
||||
hf14a_config *getHf14aConfig(void);
|
||||
void iso14a_set_timeout(uint32_t timeout);
|
||||
uint32_t iso14a_get_timeout(void);
|
||||
|
||||
|
|
1772
armsrc/iso14443b.c
1772
armsrc/iso14443b.c
File diff suppressed because it is too large
Load diff
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
#include "mifare.h"
|
||||
#include "iso14b.h"
|
||||
#include "pm3_cmd.h"
|
||||
|
||||
#ifndef AddCrc14A
|
||||
|
@ -27,21 +27,18 @@
|
|||
#endif
|
||||
|
||||
void iso14443b_setup(void);
|
||||
uint8_t iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *response);
|
||||
uint8_t iso14443b_select_card(iso14b_card_select_t *card);
|
||||
uint8_t iso14443b_select_card_srx(iso14b_card_select_t *card);
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res);
|
||||
|
||||
void SimulateIso14443bTag(uint32_t pupi);
|
||||
int iso14443b_select_card(iso14b_card_select_t *card);
|
||||
int iso14443b_select_card_srx(iso14b_card_select_t *card);
|
||||
|
||||
void SimulateIso14443bTag(uint8_t *pupi);
|
||||
void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
|
||||
void ReadSTMemoryIso14443b(uint8_t numofblocks);
|
||||
void RAMFUNC SniffIso14443b(void);
|
||||
void ReadSTMemoryIso14443b(uint16_t numofblocks);
|
||||
void SniffIso14443b(void);
|
||||
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
|
||||
void SendRawCommand14443B_Ex(PacketCommandNG *c);
|
||||
|
||||
// testfunctions
|
||||
void WaitForFpgaDelayQueueIsEmpty(uint16_t delay);
|
||||
void ClearFpgaShiftingRegisters(void);
|
||||
|
||||
// States for 14B SIM command
|
||||
#define SIM_NOFIELD 0
|
||||
#define SIM_IDLE 1
|
||||
|
|
2238
armsrc/iso15693.c
2238
armsrc/iso15693.c
File diff suppressed because it is too large
Load diff
|
@ -12,15 +12,41 @@
|
|||
#define __ISO15693_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "pm3_cmd.h" // struct
|
||||
|
||||
void RecordRawAdcSamplesIso15693(void);
|
||||
|
||||
// Delays in SSP_CLK ticks.
|
||||
// SSP_CLK runs at 13,56MHz / 32 = 423.75kHz when simulating a tag
|
||||
#define DELAY_ISO15693_VCD_TO_VICC_SIM 132 // 132/423.75kHz = 311.5us from end of command EOF to start of tag response
|
||||
|
||||
//SSP_CLK runs at 13.56MHz / 4 = 3,39MHz when acting as reader. All values should be multiples of 16
|
||||
#define DELAY_ISO15693_VCD_TO_VICC_READER 1056 // 1056/3,39MHz = 311.5us from end of command EOF to start of tag response
|
||||
#define DELAY_ISO15693_VICC_TO_VCD_READER 1024 // 1024/3.39MHz = 302.1us between end of tag response and next reader command
|
||||
|
||||
void Iso15693InitReader(void);
|
||||
void Iso15693InitTag(void);
|
||||
void CodeIso15693AsReader(uint8_t *cmd, int n);
|
||||
void CodeIso15693AsTag(uint8_t *cmd, size_t len);
|
||||
|
||||
void TransmitTo15693Reader(const uint8_t *cmd, size_t len, uint32_t *start_time, uint32_t slot_time, bool slow);
|
||||
int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eof_time);
|
||||
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time);
|
||||
int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeout, uint32_t *eof_time);
|
||||
|
||||
//void RecordRawAdcSamplesIso15693(void);
|
||||
void AcquireRawAdcSamplesIso15693(void);
|
||||
void ReaderIso15693(uint32_t parameter); // Simulate an ISO15693 reader - greg
|
||||
void SimTagIso15693(uint32_t parameter, uint8_t *uid); // simulate an ISO15693 tag - greg
|
||||
void SimTagIso15693(uint8_t *uid); // simulate an ISO15693 tag - greg
|
||||
void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag - atrox
|
||||
void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI - atrox
|
||||
void Iso15693InitReader(void);
|
||||
|
||||
void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string);
|
||||
|
||||
int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *recv,
|
||||
uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time);
|
||||
|
||||
int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time);
|
||||
|
||||
void SetTag15693Uid(uint8_t *uid);
|
||||
#endif
|
||||
|
|
113
armsrc/legicrf.c
113
armsrc/legicrf.c
|
@ -64,11 +64,11 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
|
|||
//-----------------------------------------------------------------------------
|
||||
// I/O interface abstraction (FPGA -> ARM)
|
||||
//-----------------------------------------------------------------------------
|
||||
static uint8_t rx_byte_from_fpga(void) {
|
||||
static uint16_t rx_frame_from_fpga(void) {
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
// wait for byte be become available in rx holding register
|
||||
// wait for frame be become available in rx holding register
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
return AT91C_BASE_SSC->SSC_RHR;
|
||||
}
|
||||
|
@ -76,48 +76,53 @@ static uint8_t rx_byte_from_fpga(void) {
|
|||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Demodulation
|
||||
// Demodulation (Reader)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Returns am aproximated power measurement
|
||||
// Returns a demedulated bit
|
||||
//
|
||||
// The FPGA running on the xcorrelation kernel samples the subcarrier at ~3 MHz.
|
||||
// The kernel was initialy designed to receive BSPK/2-PSK. Hance, it reports an
|
||||
// I/Q pair every 18.9us (8 bits i and 8 bits q).
|
||||
// The FPGA running xcorrelation samples the subcarrier at ~13.56 MHz. The mode
|
||||
// was initialy designed to receive BSPK/2-PSK. Hance, it reports an I/Q pair
|
||||
// every 4.7us (8 bits i and 8 bits q).
|
||||
//
|
||||
// The subcarrier amplitude can be calculated using Pythagoras sqrt(i^2 + q^2).
|
||||
// To reduce CPU time the amplitude is approximated by using linear functions:
|
||||
// am = MAX(ABS(i),ABS(q)) + 1/2*MIN(ABS(i),ABSq))
|
||||
//
|
||||
// Note: The SSC receiver is never synchronized the calculation may be performed
|
||||
// on a i/q pair from two subsequent correlations, but does not matter.
|
||||
// Note: inlining this function would fail with -Os
|
||||
static int32_t sample_power(void) {
|
||||
int32_t q = (int8_t)rx_byte_from_fpga();
|
||||
q = ABS(q);
|
||||
int32_t i = (int8_t)rx_byte_from_fpga();
|
||||
i = ABS(i);
|
||||
|
||||
return MAX(i, q) + (MIN(i, q) >> 1);
|
||||
}
|
||||
|
||||
// Returns a demedulated bit
|
||||
// The bit time is 99.1us (21 I/Q pairs). The receiver skips the first 5 samples
|
||||
// and averages the next (most stable) 8 samples. The final 8 samples are dropped
|
||||
// also.
|
||||
//
|
||||
// An aproximated power measurement is available every 18.9us. The bit time
|
||||
// is 100us. The code samples 5 times and uses the last (most stable) sample.
|
||||
// The demodulated should be alligned to the bit period by the caller. This is
|
||||
// done in rx_bit and rx_ack.
|
||||
//
|
||||
// Note: The demodulator would be drifting (18.9us * 5 != 100us), rx_frame
|
||||
// has a delay loop that aligns rx_bit calls to the TAG tx timeslots.
|
||||
|
||||
//
|
||||
// Note: inlining this function would fail with -Os
|
||||
static bool rx_bit(void) {
|
||||
int32_t power;
|
||||
int32_t sum_cq = 0;
|
||||
int32_t sum_ci = 0;
|
||||
|
||||
// skip first 5 I/Q pairs
|
||||
for (size_t i = 0; i < 5; ++i) {
|
||||
power = sample_power();
|
||||
(void)rx_frame_from_fpga();
|
||||
}
|
||||
|
||||
return (power > INPUT_THRESHOLD);
|
||||
// sample next 8 I/Q pairs
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
uint16_t iq = rx_frame_from_fpga();
|
||||
int8_t ci = (int8_t)(iq >> 8);
|
||||
int8_t cq = (int8_t)(iq & 0xff);
|
||||
sum_ci += ci;
|
||||
sum_cq += cq;
|
||||
}
|
||||
|
||||
// calculate power
|
||||
int32_t power = (MAX(ABS(sum_ci), ABS(sum_cq)) + (MIN(ABS(sum_ci), ABS(sum_cq)) >> 1));
|
||||
|
||||
// compare average (power / 8) to threshold
|
||||
return ((power >> 3) > INPUT_THRESHOLD);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -131,18 +136,18 @@ static bool rx_bit(void) {
|
|||
|
||||
static void tx_bit(bool bit) {
|
||||
// insert pause
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
last_frame_end += RWD_TIME_PAUSE;
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
|
||||
// return to high, wait for bit periode to end
|
||||
// return to carrier on, wait for bit periode to end
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
last_frame_end += (bit ? RWD_TIME_1 : RWD_TIME_0) - RWD_TIME_PAUSE;
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Frame Handling
|
||||
// Frame Handling (Reader)
|
||||
//
|
||||
// The LEGIC RF protocol from card to reader does not include explicit frame
|
||||
// start/stop information or length information. The reader must know beforehand
|
||||
|
@ -152,7 +157,7 @@ static void tx_bit(bool bit) {
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
static void tx_frame(uint32_t frame, uint8_t len) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_FULL_MOD);
|
||||
|
||||
// wait for next tx timeslot
|
||||
last_frame_end += RWD_FRAME_WAIT;
|
||||
|
@ -169,10 +174,10 @@ static void tx_frame(uint32_t frame, uint8_t len) {
|
|||
};
|
||||
|
||||
// add pause to mark end of the frame
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
last_frame_end += RWD_TIME_PAUSE;
|
||||
while (GET_TICKS < last_frame_end) { };
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
|
||||
// log
|
||||
uint8_t cmdbytes[] = {len, BYTEx(frame, 0), BYTEx(frame, 1), BYTEx(frame, 2)};
|
||||
|
@ -180,9 +185,7 @@ static void tx_frame(uint32_t frame, uint8_t len) {
|
|||
}
|
||||
|
||||
static uint32_t rx_frame(uint8_t len) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
|
||||
| FPGA_HF_READER_RX_XCORR_848_KHZ
|
||||
| FPGA_HF_READER_RX_XCORR_QUARTER);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
|
||||
|
||||
// hold sampling until card is expected to respond
|
||||
last_frame_end += TAG_FRAME_WAIT;
|
||||
|
@ -210,9 +213,7 @@ static uint32_t rx_frame(uint8_t len) {
|
|||
|
||||
static bool rx_ack(void) {
|
||||
// change fpga into rx mode
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
|
||||
| FPGA_HF_READER_RX_XCORR_848_KHZ
|
||||
| FPGA_HF_READER_RX_XCORR_QUARTER);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
|
||||
|
||||
// hold sampling until card is expected to respond
|
||||
last_frame_end += TAG_FRAME_WAIT;
|
||||
|
@ -271,27 +272,25 @@ static int init_card(uint8_t cardtype, legic_card_select_t *p_card) {
|
|||
p_card->cmdsize = 0;
|
||||
p_card->addrsize = 0;
|
||||
p_card->cardsize = 0;
|
||||
return 2;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void init_reader(bool clear_mem) {
|
||||
static void init_reader(void) {
|
||||
// configure FPGA
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR
|
||||
| FPGA_HF_READER_RX_XCORR_848_KHZ
|
||||
| FPGA_HF_READER_RX_XCORR_QUARTER);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_SUBCARRIER_212_KHZ | FPGA_HF_READER_MODE_RECEIVE_IQ);
|
||||
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
|
||||
LED_A_ON();
|
||||
|
||||
// configure SSC with defaults
|
||||
FpgaSetupSsc();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
|
||||
|
||||
// re-claim GPIO_SSC_DOUT as GPIO and enable output
|
||||
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
|
||||
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
|
||||
// reserve a cardmem, meaning we can use the tracelog function in bigbuff easier.
|
||||
legic_mem = BigBuf_get_EM_addr();
|
||||
|
@ -412,11 +411,11 @@ legic_card_select_t *getLegicCardInfo(void) {
|
|||
|
||||
void LegicRfInfo(void) {
|
||||
// configure ARM and FPGA
|
||||
init_reader(false);
|
||||
init_reader();
|
||||
|
||||
// establish shared secret and detect card type
|
||||
uint8_t card_type = setup_phase(0x01);
|
||||
if (init_card(card_type, &card) != 0) {
|
||||
if (init_card(card_type, &card) != PM3_SUCCESS) {
|
||||
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
|
@ -452,11 +451,11 @@ int LegicRfReaderEx(uint16_t offset, uint16_t len, uint8_t iv) {
|
|||
int res = PM3_SUCCESS;
|
||||
|
||||
// configure ARM and FPGA
|
||||
init_reader(false);
|
||||
init_reader();
|
||||
|
||||
// establish shared secret and detect card type
|
||||
uint8_t card_type = setup_phase(iv);
|
||||
if (init_card(card_type, &card) != 0) {
|
||||
if (init_card(card_type, &card) != PM3_SUCCESS) {
|
||||
res = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
@ -487,11 +486,11 @@ OUT:
|
|||
|
||||
void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv) {
|
||||
// configure ARM and FPGA
|
||||
init_reader(false);
|
||||
init_reader();
|
||||
|
||||
// establish shared secret and detect card type
|
||||
uint8_t card_type = setup_phase(iv);
|
||||
if (init_card(card_type, &card) != 0) {
|
||||
if (init_card(card_type, &card) != PM3_SUCCESS) {
|
||||
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
|
@ -524,7 +523,7 @@ OUT:
|
|||
|
||||
void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
|
||||
// configure ARM and FPGA
|
||||
init_reader(false);
|
||||
init_reader();
|
||||
|
||||
// uid is not writeable
|
||||
if (offset <= WRITE_LOWERLIMIT) {
|
||||
|
@ -534,7 +533,7 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
|
|||
|
||||
// establish shared secret and detect card type
|
||||
uint8_t card_type = setup_phase(iv);
|
||||
if (init_card(card_type, &card) != 0) {
|
||||
if (init_card(card_type, &card) != PM3_SUCCESS) {
|
||||
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
}
|
||||
|
@ -545,8 +544,8 @@ void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
|
|||
}
|
||||
|
||||
// write in reverse order, only then is DCF (decremental field) writable
|
||||
while (len-- > 0 && !BUTTON_PRESS()) {
|
||||
if (!write_byte(len + offset, data[len], card.addrsize)) {
|
||||
while (len-- > 0 && BUTTON_PRESS() == false) {
|
||||
if (write_byte(len + offset, data[len], card.addrsize) == false) {
|
||||
Dbprintf("operation failed | %02X | %02X | %02X", len + offset, len, data[len]);
|
||||
reply_mix(CMD_ACK, 0, 0, 0, 0, 0);
|
||||
goto OUT;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "crc.h" /* legic crc-4 */
|
||||
#include "legic_prng.h" /* legic PRNG impl */
|
||||
#include "legic.h" /* legic_card_select_t struct */
|
||||
|
||||
#include "cmd.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "BigBuf.h"
|
||||
#include "fpgaloader.h"
|
||||
|
@ -53,7 +53,7 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
|
|||
#define RWD_TIME_PAUSE 4 /* 18.9us */
|
||||
#define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */
|
||||
#define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */
|
||||
#define RWD_CMD_TIMEOUT 120 /* 120 * 99.1us (arbitrary value) */
|
||||
#define RWD_CMD_TIMEOUT 400 /* 120 * 99.1us (arbitrary value) */
|
||||
#define RWD_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */
|
||||
#define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 bits */
|
||||
|
||||
|
@ -68,6 +68,7 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
|
|||
// Note: inlining this function would fail with -Os
|
||||
static bool wait_for(bool value, const uint32_t timeout) {
|
||||
while ((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) {
|
||||
WDT_HIT();
|
||||
if (GetCountSspClk() > timeout) {
|
||||
return false;
|
||||
}
|
||||
|
@ -215,7 +216,7 @@ static int32_t rx_frame(uint8_t *len) {
|
|||
last_frame_end -= 2;
|
||||
|
||||
// wait for first pause (start of frame)
|
||||
for (uint8_t i = 0; true; ++i) {
|
||||
for (uint16_t i = 0; true; ++i) {
|
||||
// increment prng every TAG_BIT_PERIOD
|
||||
last_frame_end += TAG_BIT_PERIOD;
|
||||
legic_prng_forward(1);
|
||||
|
@ -295,20 +296,19 @@ static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) {
|
|||
p_card->cmdsize = 0;
|
||||
p_card->addrsize = 0;
|
||||
p_card->cardsize = 0;
|
||||
return 2;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void init_tag(void) {
|
||||
// configure FPGA
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR
|
||||
| FPGA_HF_SIMULATOR_MODULATE_212K);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_212K);
|
||||
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
|
||||
|
||||
// configure SSC with defaults
|
||||
FpgaSetupSsc();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
|
||||
|
||||
// first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
|
@ -456,23 +456,37 @@ static int32_t connected_phase(legic_card_select_t *p_card) {
|
|||
// Only this function is public / called from appmain.c
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void LegicRfSimulate(uint8_t cardtype) {
|
||||
void LegicRfSimulate(uint8_t tagtype, bool send_reply) {
|
||||
// configure ARM and FPGA
|
||||
init_tag();
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
// verify command line input
|
||||
if (init_card(cardtype, &card) != 0) {
|
||||
DbpString("[!] Unknown tagtype.");
|
||||
if (init_card(tagtype, &card) != PM3_SUCCESS) {
|
||||
DbpString("Unknown tagtype to simulate");
|
||||
res = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
uint16_t counter = 0;
|
||||
LED_A_ON();
|
||||
DbpString("[=] Starting Legic emulator, press " _YELLOW_("button") " to end");
|
||||
while (!BUTTON_PRESS() && !data_available()) {
|
||||
|
||||
Dbprintf("Legic Prime, simulating uid: %02X%02X%02X%02X", legic_mem[0], legic_mem[1], legic_mem[2], legic_mem[3]);
|
||||
|
||||
while (BUTTON_PRESS() == false) {
|
||||
WDT_HIT();
|
||||
|
||||
if (counter >= 2000) {
|
||||
if (data_available()) {
|
||||
res = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
counter++;
|
||||
|
||||
// wait for carrier, restart after timeout
|
||||
if (!wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD)) {
|
||||
if (wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -482,13 +496,25 @@ void LegicRfSimulate(uint8_t cardtype) {
|
|||
}
|
||||
|
||||
// conection is established, process commands until one fails
|
||||
while (!connected_phase(&card)) {
|
||||
while (connected_phase(&card) == false) {
|
||||
WDT_HIT();
|
||||
}
|
||||
}
|
||||
|
||||
OUT:
|
||||
DbpString("[=] Sim stopped");
|
||||
|
||||
if (DBGLEVEL >= DBG_ERROR) {
|
||||
Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen());
|
||||
}
|
||||
|
||||
if (res == PM3_EOPABORTED)
|
||||
DbpString("aborted by user");
|
||||
|
||||
switch_off();
|
||||
StopTicks();
|
||||
|
||||
if (send_reply)
|
||||
reply_ng(CMD_HF_LEGIC_SIMULATE, res, NULL, 0);
|
||||
|
||||
BigBuf_free_keep_EM();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
|
||||
// 2018 AntiCat
|
||||
//
|
||||
// 2019 Piwi
|
||||
// 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
|
||||
// the license.
|
||||
|
@ -14,6 +15,6 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
void LegicRfSimulate(uint8_t cardtype);
|
||||
void LegicRfSimulate(uint8_t tagtype, bool send_reply);
|
||||
|
||||
#endif /* __LEGICRFSIM_H */
|
||||
|
|
|
@ -181,7 +181,7 @@ void lf_init(bool reader, bool simulate) {
|
|||
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
|
||||
|
||||
// Now set up the SSC to get the ADC samples that are now streaming at us.
|
||||
FpgaSetupSsc();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER);
|
||||
|
||||
// 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.
|
||||
|
@ -238,9 +238,9 @@ void lf_finalize(void) {
|
|||
}
|
||||
|
||||
size_t lf_detect_field_drop(size_t max) {
|
||||
/*
|
||||
/*
|
||||
size_t periods = 0;
|
||||
// int16_t checked = 0;
|
||||
// int16_t checked = 0;
|
||||
|
||||
while (BUTTON_PRESS() == false) {
|
||||
|
||||
|
@ -271,7 +271,7 @@ size_t lf_detect_field_drop(size_t max) {
|
|||
if (periods == max) return 0;
|
||||
}
|
||||
}
|
||||
*/
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
270
armsrc/lfops.c
270
armsrc/lfops.c
|
@ -27,6 +27,7 @@
|
|||
#include "protocols.h"
|
||||
#include "pmflash.h"
|
||||
#include "flashmem.h" // persistence on flash
|
||||
#include "appmain.h" // print stack
|
||||
|
||||
/*
|
||||
Notes about EM4xxx timings.
|
||||
|
@ -382,13 +383,15 @@ void loadT55xxConfig(void) {
|
|||
* @param period_1
|
||||
* @param command (in binary char array)
|
||||
*/
|
||||
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command) {
|
||||
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint16_t period_0, uint16_t period_1, uint8_t *symbol_extra, uint16_t *period_extra, uint8_t *command, bool verbose, uint32_t samples) {
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
||||
// use lf config settings
|
||||
sample_config *sc = getSamplingConfig();
|
||||
|
||||
LFSetupFPGAForADC(sc->divisor, true);
|
||||
// this causes the field to turn on for uncontrolled amount of time, so we'll turn it off
|
||||
|
||||
// Make sure the tag is reset
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
@ -401,15 +404,14 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint
|
|||
// clear read buffer
|
||||
BigBuf_Clear_keep_EM();
|
||||
|
||||
LFSetupFPGAForADC(sc->divisor, true);
|
||||
|
||||
// little more time for the tag to fully power up
|
||||
WaitMS(20);
|
||||
|
||||
// if delay_off = 0 then just bitbang 1 = antenna on 0 = off for respective periods.
|
||||
bool bitbang = (delay_off == 0);
|
||||
// now modulate the reader field
|
||||
|
||||
// Some tags need to be interrogated very soon after activation else they enter their emulation mode
|
||||
// Therefore it's up to the caller to add an initial symbol of adequate duration, except for bitbang mode.
|
||||
if (bitbang) {
|
||||
TurnReadLFOn(20000);
|
||||
// HACK it appears the loop and if statements take up about 7us so adjust waits accordingly...
|
||||
uint8_t hack_cnt = 7;
|
||||
if (period_0 < hack_cnt || period_1 < hack_cnt) {
|
||||
|
@ -458,11 +460,19 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint
|
|||
} else { // old mode of cmd read using delay as off period
|
||||
while (*command != '\0' && *command != ' ') {
|
||||
LED_D_ON();
|
||||
if (*(command++) == '0')
|
||||
if (*command == '0') {
|
||||
TurnReadLFOn(period_0);
|
||||
else
|
||||
} else if (*command == '1') {
|
||||
TurnReadLFOn(period_1);
|
||||
|
||||
} else {
|
||||
for (uint8_t i = 0; i < LF_CMDREAD_MAX_EXTRA_SYMBOLS; i++) {
|
||||
if (*command == symbol_extra[i]) {
|
||||
TurnReadLFOn(period_extra[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
command++;
|
||||
LED_D_OFF();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
WaitUS(delay_off);
|
||||
|
@ -474,7 +484,7 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint
|
|||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD);
|
||||
|
||||
// now do the read
|
||||
DoAcquisition_config(true, 0);
|
||||
DoAcquisition_config(verbose, samples);
|
||||
|
||||
// Turn off antenna
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
@ -678,7 +688,7 @@ void AcquireTiType(void) {
|
|||
AT91C_BASE_SSC->SSC_TCMR = 0;
|
||||
// Transmit Frame Mode Register
|
||||
AT91C_BASE_SSC->SSC_TFMR = 0;
|
||||
// iceman, FpgaSetupSsc() ?? the code above? can it be replaced?
|
||||
// iceman, FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER) ?? the code above? can it be replaced?
|
||||
LED_D_ON();
|
||||
|
||||
// modulate antenna
|
||||
|
@ -721,7 +731,7 @@ void AcquireTiType(void) {
|
|||
}
|
||||
|
||||
// reset SSC
|
||||
FpgaSetupSsc();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER);
|
||||
}
|
||||
|
||||
// arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc
|
||||
|
@ -2010,13 +2020,12 @@ void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block,
|
|||
flags |= (downlink_mode & 3) << 3;
|
||||
if (brute_mem) flags |= 0x0100;
|
||||
|
||||
// T55xxReadBlockExt (flags,block,pwd);
|
||||
|
||||
size_t samples = 12000;
|
||||
// bool brute_mem = (flags & 0x0100) >> 8;
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
if (brute_mem) samples = 1024;
|
||||
if (brute_mem) samples = 2048;
|
||||
|
||||
//-- Set Read Flag to ensure SendCMD does not add "data" to the packet
|
||||
//-- flags |= 0x40;
|
||||
|
@ -2041,47 +2050,62 @@ void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block,
|
|||
|
||||
// Acquisition
|
||||
// Now do the acquisition
|
||||
DoPartialAcquisition(0, false, samples, 0);
|
||||
DoPartialAcquisition(0, false, samples, 1000);
|
||||
|
||||
// Turn the field off
|
||||
if (!brute_mem) {
|
||||
if (brute_mem == false) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
reply_ng(CMD_LF_T55XX_READBL, PM3_SUCCESS, NULL, 0);
|
||||
LED_A_OFF();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void T55xx_ChkPwds(uint8_t flags) {
|
||||
|
||||
DbpString("[+] T55XX Check pwds using flashmemory starting");
|
||||
#define CHK_SAMPLES_SIGNAL 2048
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
DbpString(_CYAN_("T55XX Check pwds using flashmemory starting"));
|
||||
#else
|
||||
DbpString(_CYAN_("T55XX Check pwds starting"));
|
||||
#endif
|
||||
|
||||
// First get baseline and setup LF mode.
|
||||
// tends to mess up BigBuf
|
||||
uint8_t *buf = BigBuf_get_addr();
|
||||
uint8_t ret = 0;
|
||||
uint8_t downlink_mode = (flags >> 3) & 0x03;
|
||||
uint32_t b1, baseline = 0;
|
||||
uint64_t b1, baseline_faulty = 0;
|
||||
|
||||
// collect baseline for failed attempt
|
||||
DbpString("Determine baseline...");
|
||||
|
||||
// collect baseline for failed attempt ( should give me block1 )
|
||||
uint8_t x = 32;
|
||||
while (x--) {
|
||||
b1 = 0;
|
||||
T55xxReadBlock(0, 0, true, 1, 0, downlink_mode);
|
||||
for (uint16_t j = 0; j < 1024; ++j)
|
||||
b1 += buf[j];
|
||||
|
||||
T55xxReadBlock(0, 0, true, 0, 0, downlink_mode);
|
||||
for (uint16_t j = 0; j < CHK_SAMPLES_SIGNAL; ++j) {
|
||||
b1 += (buf[j] * buf[j]);
|
||||
}
|
||||
b1 *= b1;
|
||||
b1 >>= 8;
|
||||
baseline += b1;
|
||||
baseline_faulty += b1;
|
||||
}
|
||||
baseline_faulty >>= 5;
|
||||
|
||||
baseline >>= 5;
|
||||
Dbprintf("[=] Baseline determined [%u]", baseline);
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("Baseline " _YELLOW_("%llu"), baseline_faulty);
|
||||
|
||||
uint8_t *pwds = BigBuf_get_EM_addr();
|
||||
uint16_t pwd_count = 0;
|
||||
uint32_t candidate = 0;
|
||||
|
||||
struct p {
|
||||
bool found;
|
||||
uint32_t candidate;
|
||||
} PACKED payload;
|
||||
|
||||
payload.found = false;
|
||||
payload.candidate = 0;
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
|
||||
BigBuf_Clear_EM();
|
||||
|
@ -2107,48 +2131,51 @@ void T55xx_ChkPwds(uint8_t flags) {
|
|||
if (isok != pwd_size_available)
|
||||
goto OUT;
|
||||
|
||||
Dbprintf("[=] Password dictionary count %d ", pwd_count);
|
||||
Dbprintf("Password dictionary count " _YELLOW_("%d"), pwd_count);
|
||||
|
||||
#endif
|
||||
|
||||
uint32_t pwd = 0, curr = 0, prev = 0;
|
||||
for (uint16_t i = 0; i < pwd_count; ++i) {
|
||||
uint64_t curr = 0, prev = 0;
|
||||
int32_t idx = -1;
|
||||
|
||||
if (BUTTON_PRESS() && !data_available()) {
|
||||
goto OUT;
|
||||
}
|
||||
for (uint32_t i = 0; i < pwd_count; i++) {
|
||||
|
||||
pwd = bytes_to_num(pwds + i * 4, 4);
|
||||
uint32_t pwd = bytes_to_num(pwds + (i * 4), 4);
|
||||
|
||||
T55xxReadBlock(0, true, true, 0, pwd, downlink_mode);
|
||||
|
||||
// calc mean of BigBuf 1024 samples.
|
||||
uint32_t sum = 0;
|
||||
for (uint16_t j = 0; j < 1024; ++j) {
|
||||
sum += buf[j];
|
||||
uint64_t sum = 0;
|
||||
for (uint16_t j = 0; j < CHK_SAMPLES_SIGNAL; ++j) {
|
||||
sum += (buf[j] * buf[j]);
|
||||
}
|
||||
|
||||
sum *= sum;
|
||||
sum >>= 8;
|
||||
|
||||
int32_t tmp = (sum - baseline);
|
||||
curr = ABS(tmp);
|
||||
int64_t tmp_dist = (baseline_faulty - sum);
|
||||
curr = ABS(tmp_dist);
|
||||
|
||||
Dbprintf("[=] Pwd %08X | ABS %u", pwd, curr);
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("%08x has distance " _YELLOW_("%llu"), pwd, curr);
|
||||
|
||||
if (curr > prev) {
|
||||
Dbprintf("[=] --> ABS %u Candidate %08X <--", curr, pwd);
|
||||
candidate = pwd;
|
||||
idx = i;
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
|
||||
if (candidate)
|
||||
ret = 1;
|
||||
if (idx != -1) {
|
||||
payload.found = true;
|
||||
payload.candidate = bytes_to_num(pwds + (idx * 4), 4);
|
||||
}
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
OUT:
|
||||
#endif
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
reply_mix(CMD_ACK, ret, candidate, 0, 0, 0);
|
||||
LEDsoff();
|
||||
reply_ng(CMD_LF_T55XX_CHK_PWDS, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
|
||||
BigBuf_free();
|
||||
}
|
||||
|
||||
void T55xxWakeUp(uint32_t pwd, uint8_t flags) {
|
||||
|
@ -2342,6 +2369,7 @@ int copy_em410x_to_t55xx(uint8_t card, uint8_t clock, uint32_t id_hi, uint32_t i
|
|||
#define FWD_CMD_LOGIN 0xC
|
||||
#define FWD_CMD_WRITE 0xA
|
||||
#define FWD_CMD_READ 0x9
|
||||
#define FWD_CMD_PROTECT 0x3
|
||||
#define FWD_CMD_DISABLE 0x5
|
||||
|
||||
static uint8_t forwardLink_data[64]; //array of forwarded bits
|
||||
|
@ -2474,36 +2502,37 @@ static void SendForward(uint8_t fwd_bit_count) {
|
|||
}
|
||||
|
||||
static void EM4xLogin(uint32_t pwd) {
|
||||
uint8_t len;
|
||||
forward_ptr = forwardLink_data;
|
||||
len = Prepare_Cmd(FWD_CMD_LOGIN);
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN);
|
||||
len += Prepare_Data(pwd & 0xFFFF, pwd >> 16);
|
||||
SendForward(len);
|
||||
//WaitUS(20); // no wait for login command.
|
||||
// should receive
|
||||
// 0000 1010 ok.
|
||||
// 0000 1010 ok
|
||||
// 0000 0001 fail
|
||||
}
|
||||
|
||||
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) {
|
||||
|
||||
LED_A_ON();
|
||||
uint8_t len;
|
||||
StartTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
WaitMS(20);
|
||||
|
||||
//clear buffer now so it does not interfere with timing later
|
||||
LED_A_ON();
|
||||
|
||||
// clear buffer now so it does not interfere with timing later
|
||||
BigBuf_Clear_ext(false);
|
||||
|
||||
StartTicks();
|
||||
/* should we read answer from Logincommand?
|
||||
*
|
||||
* should receive
|
||||
* 0000 1010 ok.
|
||||
* 0000 1010 ok
|
||||
* 0000 0001 fail
|
||||
**/
|
||||
if (usepwd) EM4xLogin(pwd);
|
||||
|
||||
forward_ptr = forwardLink_data;
|
||||
len = Prepare_Cmd(FWD_CMD_READ);
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_READ);
|
||||
len += Prepare_Addr(addr);
|
||||
|
||||
SendForward(len);
|
||||
|
@ -2512,19 +2541,23 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) {
|
|||
|
||||
DoPartialAcquisition(20, false, 6000, 1000);
|
||||
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
reply_ng(CMD_LF_EM4X_READWORD, PM3_SUCCESS, NULL, 0);
|
||||
LED_A_OFF();
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) {
|
||||
|
||||
LED_A_ON();
|
||||
uint8_t len;
|
||||
|
||||
//clear buffer now so it does not interfere with timing later
|
||||
BigBuf_Clear_ext(false);
|
||||
StartTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
WaitMS(50);
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
// clear buffer now so it does not interfere with timing later
|
||||
BigBuf_Clear_ext(false);
|
||||
|
||||
/* should we read answer from Logincommand?
|
||||
*
|
||||
* should receive
|
||||
|
@ -2534,20 +2567,68 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) {
|
|||
if (usepwd) EM4xLogin(pwd);
|
||||
|
||||
forward_ptr = forwardLink_data;
|
||||
len = Prepare_Cmd(FWD_CMD_WRITE);
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_WRITE);
|
||||
len += Prepare_Addr(addr);
|
||||
len += Prepare_Data(data & 0xFFFF, data >> 16);
|
||||
|
||||
SendForward(len);
|
||||
|
||||
//Wait 20ms for write to complete?
|
||||
WaitMS(7);
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||
StopTicks();
|
||||
reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_ETEAROFF, NULL, 0);
|
||||
} else {
|
||||
// Wait 20ms for write to complete?
|
||||
// No, when write is denied, err preamble comes much sooner
|
||||
//WaitUS(10820); // tPC+tWEE
|
||||
|
||||
DoPartialAcquisition(20, false, 6000, 1000);
|
||||
DoPartialAcquisition(0, false, 6000, 1000);
|
||||
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0);
|
||||
LED_A_OFF();
|
||||
}
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) {
|
||||
|
||||
StartTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
WaitMS(50);
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
// clear buffer now so it does not interfere with timing later
|
||||
BigBuf_Clear_ext(false);
|
||||
|
||||
/* should we read answer from Logincommand?
|
||||
*
|
||||
* should receive
|
||||
* 0000 1010 ok.
|
||||
* 0000 0001 fail
|
||||
**/
|
||||
if (usepwd) EM4xLogin(pwd);
|
||||
|
||||
forward_ptr = forwardLink_data;
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_PROTECT);
|
||||
len += Prepare_Data(data & 0xFFFF, data >> 16);
|
||||
|
||||
SendForward(len);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||
StopTicks();
|
||||
reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_ETEAROFF, NULL, 0);
|
||||
} else {
|
||||
// Wait 20ms for write to complete?
|
||||
// No, when write is denied, err preamble comes much sooner
|
||||
//WaitUS(13640); // tPC+tPR
|
||||
|
||||
DoPartialAcquisition(0, false, 6000, 1000);
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2594,32 +2675,53 @@ void Cotag(uint32_t arg0) {
|
|||
|
||||
LED_A_ON();
|
||||
|
||||
LFSetupFPGAForADC(LF_FREQ2DIV(132), true);
|
||||
LFSetupFPGAForADC(LF_FREQ2DIV(132), true); //132
|
||||
|
||||
//clear buffer now so it does not interfere with timing later
|
||||
BigBuf_free();
|
||||
BigBuf_Clear_ext(false);
|
||||
|
||||
//send COTAG start pulse
|
||||
// send COTAG start pulse
|
||||
// http://www.proxmark.org/forum/viewtopic.php?id=4455
|
||||
/*
|
||||
ON(740) OFF(2035)
|
||||
ON(3330) OFF(2035)
|
||||
ON(740) OFF(2035)
|
||||
ON(1000)
|
||||
ON(2000)
|
||||
*/
|
||||
ON(800) OFF(2200)
|
||||
ON(3600) OFF(2200)
|
||||
ON(800) OFF(2200)
|
||||
ON(2000) // ON(3400)
|
||||
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_FREQ2DIV(66)); // 66kHz
|
||||
|
||||
switch (rawsignal) {
|
||||
case 0:
|
||||
doCotagAcquisition(40000);
|
||||
break;
|
||||
case 1:
|
||||
doCotagAcquisitionManchester();
|
||||
break;
|
||||
case 2:
|
||||
DoAcquisition_config(false, 0);
|
||||
case 0: {
|
||||
doCotagAcquisition();
|
||||
reply_ng(CMD_LF_COTAG_READ, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
uint8_t *dest = BigBuf_malloc(COTAG_BITS);
|
||||
uint16_t bits = doCotagAcquisitionManchester(dest, COTAG_BITS);
|
||||
reply_ng(CMD_LF_COTAG_READ, PM3_SUCCESS, dest, bits);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
DoAcquisition_config(false, 0);
|
||||
reply_ng(CMD_LF_COTAG_READ, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
reply_ng(CMD_LF_COTAG_READ, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Turn the field off
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
|
||||
reply_ng(CMD_LF_COTAG_READ, PM3_SUCCESS, NULL, 0);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
#include "pm3_cmd.h" // struct
|
||||
|
||||
void AcquireRawAdcSamples125k(int divisor);
|
||||
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command);
|
||||
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint16_t period_0, uint16_t period_1, uint8_t *symbol_extra, uint16_t *period_extra, uint8_t *command, bool verbose, uint32_t samples);
|
||||
void ReadTItag(void);
|
||||
void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc);
|
||||
|
||||
|
@ -59,6 +58,7 @@ void TurnReadLFOn(uint32_t delay);
|
|||
|
||||
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd);
|
||||
void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd);
|
||||
void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd);
|
||||
|
||||
void Cotag(uint32_t arg0);
|
||||
void setT55xxConfig(uint8_t arg0, t55xx_configurations_t *c);
|
||||
|
|
|
@ -36,7 +36,7 @@ static BitstreamOut data = {0, 0, 0};
|
|||
// internal struct to keep track of samples gathered
|
||||
static sampling_t samples = {0, 0, 0, 0};
|
||||
|
||||
void printConfig(void) {
|
||||
void printLFConfig(void) {
|
||||
uint32_t d = config.divisor;
|
||||
DbpString(_CYAN_("LF Sampling config"));
|
||||
Dbprintf(" [q] divisor.............%d ( "_GREEN_("%d.%02d kHz")" )", d, 12000 / (d + 1), ((1200000 + (d + 1) / 2) / (d + 1)) - ((12000 / (d + 1)) * 100));
|
||||
|
@ -51,11 +51,11 @@ void printConfig(void) {
|
|||
}
|
||||
|
||||
void printSamples(void) {
|
||||
DbpString(_CYAN_("LF Sampling memory"));
|
||||
Dbprintf(" decimation counter.....%d ", samples.dec_counter);
|
||||
Dbprintf(" sum.....%u ", samples.sum);
|
||||
Dbprintf(" counter.....%u ", samples.counter);
|
||||
Dbprintf(" total saved.....%u ", samples.total_saved);
|
||||
DbpString(_CYAN_("LF Sampling memory usage"));
|
||||
// Dbprintf(" decimation counter...%d", samples.dec_counter);
|
||||
// Dbprintf(" sum..................%u", samples.sum);
|
||||
Dbprintf(" counter.............." _YELLOW_("%u"), samples.counter);
|
||||
Dbprintf(" total saved.........." _YELLOW_("%u"), samples.total_saved);
|
||||
print_stack_usage();
|
||||
}
|
||||
|
||||
|
@ -97,7 +97,7 @@ void setSamplingConfig(sample_config *sc) {
|
|||
config.samples_to_skip = sc->samples_to_skip;
|
||||
|
||||
if (sc->verbose)
|
||||
printConfig();
|
||||
printLFConfig();
|
||||
}
|
||||
|
||||
sample_config *getSamplingConfig(void) {
|
||||
|
@ -127,7 +127,7 @@ void initSampleBufferEx(uint32_t *sample_size, bool use_malloc) {
|
|||
Dbprintf("initSampleBufferEx, param NULL");
|
||||
return;
|
||||
}
|
||||
BigBuf_free();
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
// We can't erase the buffer now, it would drastically delay the acquisition
|
||||
if (use_malloc) {
|
||||
|
@ -236,15 +236,18 @@ void LFSetupFPGAForADC(int divisor, bool reader_field) {
|
|||
// Connect the A/D to the peak-detected low-frequency path.
|
||||
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
|
||||
|
||||
// 50ms for the resonant antenna to settle.
|
||||
if (reader_field)
|
||||
SpinDelay(50);
|
||||
|
||||
// Now set up the SSC to get the ADC samples that are now streaming at us.
|
||||
FpgaSetupSsc();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_LF_READER);
|
||||
|
||||
// start a 1.5ticks is 1us
|
||||
StartTicks();
|
||||
|
||||
// 50ms for the resonant antenna to settle.
|
||||
if (reader_field) {
|
||||
WaitMS(50);
|
||||
} else {
|
||||
WaitMS(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -268,18 +271,18 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
|||
initSampleBuffer(&sample_size);
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("lf sampling - after init");
|
||||
printSamples();
|
||||
}
|
||||
|
||||
bool trigger_hit = false;
|
||||
uint32_t cancel_counter = 0;
|
||||
int16_t checked = 0;
|
||||
|
||||
while (BUTTON_PRESS() == false) {
|
||||
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
// only every 4000th times, in order to save time when collecting samples.
|
||||
// interruptible only when logging not yet triggered
|
||||
if ((checked == 4000) && (trigger_threshold > 0)) {
|
||||
if ((checked >= 4000) && trigger_hit == false) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
|
@ -298,10 +301,11 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
|||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
// Testpoint 8 (TP8) can be used to trigger oscilliscope
|
||||
// Test point 8 (TP8) can be used to trigger oscilloscope
|
||||
LED_D_OFF();
|
||||
|
||||
// threshold either high or low values 128 = center 0. if trigger = 178
|
||||
if (trigger_hit == false) {
|
||||
if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) {
|
||||
if (cancel_after > 0) {
|
||||
cancel_counter++;
|
||||
|
@ -310,8 +314,9 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
|||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
trigger_threshold = 0;
|
||||
trigger_hit = true;
|
||||
|
||||
if (samples_to_skip > 0) {
|
||||
samples_to_skip--;
|
||||
|
@ -324,18 +329,19 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
|||
}
|
||||
}
|
||||
|
||||
if (checked == -1 && verbose) {
|
||||
if (verbose) {
|
||||
if (checked == -1) {
|
||||
Dbprintf("lf sampling aborted");
|
||||
} else if ((cancel_counter == cancel_after) && (cancel_after > 0)) {
|
||||
Dbprintf("lf sampling cancelled after %u", cancel_counter);
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
Dbprintf("Done, saved " _YELLOW_("%d")" out of " _YELLOW_("%d")" seen samples at " _YELLOW_("%d")" bits/sample", samples.total_saved, samples.counter, bits_per_sample);
|
||||
}
|
||||
|
||||
// Ensure that DC offset removal and noise check is performed for any device-side processing
|
||||
removeSignalOffset(data.buffer, samples.total_saved);
|
||||
computeSignalProperties(data.buffer, samples.total_saved);
|
||||
|
||||
return data.numbits;
|
||||
}
|
||||
/**
|
||||
|
@ -356,20 +362,28 @@ uint32_t DoAcquisition_config(bool verbose, uint32_t sample_size) {
|
|||
, config.trigger_threshold
|
||||
, verbose
|
||||
, sample_size
|
||||
, 0
|
||||
, 0 // cancel_after
|
||||
, config.samples_to_skip);
|
||||
}
|
||||
|
||||
uint32_t DoPartialAcquisition(int trigger_threshold, bool verbose, uint32_t sample_size, uint32_t cancel_after) {
|
||||
return DoAcquisition(1, 8, 0, trigger_threshold, verbose, sample_size, cancel_after, 0);
|
||||
return DoAcquisition(config.decimation
|
||||
, config.bits_per_sample
|
||||
, config.averaging
|
||||
, trigger_threshold
|
||||
, verbose
|
||||
, sample_size
|
||||
, cancel_after
|
||||
, 0); // samples to skip
|
||||
}
|
||||
|
||||
static uint32_t ReadLF(bool reader_field, bool verbose, uint32_t sample_size) {
|
||||
if (verbose)
|
||||
printConfig();
|
||||
printLFConfig();
|
||||
|
||||
LFSetupFPGAForADC(config.divisor, reader_field);
|
||||
uint32_t ret = DoAcquisition_config(verbose, sample_size);
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
return ret;
|
||||
}
|
||||
|
@ -386,9 +400,9 @@ uint32_t SampleLF(bool verbose, uint32_t sample_size) {
|
|||
* Initializes the FPGA for sniffer-mode (field off), and acquires the samples.
|
||||
* @return number of bits sampled
|
||||
**/
|
||||
uint32_t SniffLF(void) {
|
||||
uint32_t SniffLF(bool verbose, uint32_t sample_size) {
|
||||
BigBuf_Clear_ext(false);
|
||||
return ReadLF(false, true, 0);
|
||||
return ReadLF(false, verbose, sample_size);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -479,139 +493,102 @@ void doT55x7Acquisition(size_t sample_size) {
|
|||
**/
|
||||
|
||||
#define COTAG_T1 384
|
||||
#define COTAG_T2 (COTAG_T1>>1)
|
||||
#define COTAG_ONE_THRESHOLD 128+10
|
||||
#define COTAG_ZERO_THRESHOLD 128-10
|
||||
#define COTAG_T2 (COTAG_T1 >> 1)
|
||||
#define COTAG_ONE_THRESHOLD 127+5
|
||||
#define COTAG_ZERO_THRESHOLD 127-5
|
||||
#ifndef COTAG_BITS
|
||||
#define COTAG_BITS 264
|
||||
#endif
|
||||
void doCotagAcquisition(size_t sample_size) {
|
||||
void doCotagAcquisition(void) {
|
||||
|
||||
uint8_t *dest = BigBuf_get_addr();
|
||||
uint16_t bufsize = MIN(sample_size, BigBuf_max_traceLen());
|
||||
uint16_t bufsize = BigBuf_max_traceLen();
|
||||
uint8_t *dest = BigBuf_malloc(bufsize);
|
||||
|
||||
dest[0] = 0;
|
||||
uint8_t firsthigh = 0, firstlow = 0;
|
||||
uint16_t i = 0, noise_counter = 0, checker = 0;
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("doCotagAcquisition - after init");
|
||||
print_stack_usage();
|
||||
}
|
||||
bool firsthigh = false, firstlow = false;
|
||||
uint16_t i = 0, noise_counter = 0;
|
||||
|
||||
while ((i < bufsize) && (noise_counter < (COTAG_T1 << 1))) {
|
||||
while ((i < bufsize - 1) && (noise_counter < COTAG_T1 << 1)) {
|
||||
|
||||
if (BUTTON_PRESS())
|
||||
break;
|
||||
|
||||
if (checker == 4000) {
|
||||
if (data_available())
|
||||
break;
|
||||
else
|
||||
checker = 0;
|
||||
} else {
|
||||
++checker;
|
||||
}
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
|
||||
LED_D_ON();
|
||||
}
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
|
||||
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
// find first peak
|
||||
if (!firsthigh) {
|
||||
if (firsthigh == false) {
|
||||
if (sample < COTAG_ONE_THRESHOLD) {
|
||||
noise_counter++;
|
||||
continue;
|
||||
}
|
||||
|
||||
noise_counter = 0;
|
||||
firsthigh = 1;
|
||||
firsthigh = true;
|
||||
}
|
||||
if (!firstlow) {
|
||||
|
||||
if (firstlow == false) {
|
||||
if (sample > COTAG_ZERO_THRESHOLD) {
|
||||
noise_counter++;
|
||||
continue;
|
||||
}
|
||||
|
||||
noise_counter = 0;
|
||||
firstlow = 1;
|
||||
firstlow = true;
|
||||
}
|
||||
|
||||
++i;
|
||||
|
||||
if (sample > COTAG_ONE_THRESHOLD)
|
||||
if (sample > COTAG_ONE_THRESHOLD) {
|
||||
dest[i] = 255;
|
||||
else if (sample < COTAG_ZERO_THRESHOLD)
|
||||
} else if (sample < COTAG_ZERO_THRESHOLD) {
|
||||
dest[i] = 0;
|
||||
else
|
||||
} else {
|
||||
dest[i] = dest[i - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that DC offset removal and noise check is performed for any device-side processing
|
||||
removeSignalOffset(dest, bufsize);
|
||||
computeSignalProperties(dest, bufsize);
|
||||
removeSignalOffset(dest, i);
|
||||
computeSignalProperties(dest, i);
|
||||
}
|
||||
|
||||
uint32_t doCotagAcquisitionManchester(void) {
|
||||
uint16_t doCotagAcquisitionManchester(uint8_t *dest, uint16_t destlen) {
|
||||
|
||||
uint8_t *dest = BigBuf_get_addr();
|
||||
uint16_t bufsize = MIN(COTAG_BITS, BigBuf_max_traceLen());
|
||||
if (dest == NULL)
|
||||
return 0;
|
||||
|
||||
dest[0] = 0;
|
||||
uint8_t firsthigh = 0, firstlow = 0;
|
||||
|
||||
bool firsthigh = false, firstlow = false;
|
||||
uint8_t curr = 0, prev = 0;
|
||||
uint16_t sample_counter = 0, period = 0;
|
||||
uint16_t noise_counter = 0, checker = 0;
|
||||
uint16_t i = 0;
|
||||
uint16_t period = 0;
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("doCotagAcquisitionManchester - after init");
|
||||
print_stack_usage();
|
||||
}
|
||||
|
||||
while ((sample_counter < bufsize) && (noise_counter < (COTAG_T1 << 1))) {
|
||||
|
||||
if (BUTTON_PRESS())
|
||||
break;
|
||||
|
||||
if (checker == 4000) {
|
||||
if ( data_available())
|
||||
break;
|
||||
else
|
||||
checker = 0;
|
||||
} else {
|
||||
++checker;
|
||||
}
|
||||
while ((i < destlen) && BUTTON_PRESS() == false) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
|
||||
LED_D_ON();
|
||||
}
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY) {
|
||||
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
// find first peak
|
||||
if (!firsthigh) {
|
||||
if (firsthigh == false) {
|
||||
if (sample < COTAG_ONE_THRESHOLD) {
|
||||
noise_counter++;
|
||||
continue;
|
||||
}
|
||||
noise_counter = 0;
|
||||
firsthigh = 1;
|
||||
firsthigh = true;
|
||||
}
|
||||
|
||||
if (!firstlow) {
|
||||
if (firstlow == false) {
|
||||
if (sample > COTAG_ZERO_THRESHOLD) {
|
||||
noise_counter++;
|
||||
continue;
|
||||
}
|
||||
noise_counter = 0;
|
||||
firstlow = 1;
|
||||
firstlow = true;
|
||||
}
|
||||
|
||||
// set sample 255, 0, or previous
|
||||
|
@ -631,10 +608,11 @@ uint32_t doCotagAcquisitionManchester(void) {
|
|||
continue;
|
||||
}
|
||||
|
||||
dest[sample_counter] = curr;
|
||||
++sample_counter;
|
||||
dest[i] = curr;
|
||||
++i;
|
||||
period = COTAG_T1;
|
||||
}
|
||||
}
|
||||
return sample_counter;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
|
|
@ -21,8 +21,8 @@ typedef struct {
|
|||
* acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384
|
||||
* and is Manchester?, we directly gather the manchester data into bigbuff
|
||||
**/
|
||||
void doCotagAcquisition(size_t sample_size);
|
||||
uint32_t doCotagAcquisitionManchester(void);
|
||||
void doCotagAcquisition(void);
|
||||
uint16_t doCotagAcquisitionManchester(uint8_t *dest, uint16_t destlen);
|
||||
|
||||
/**
|
||||
* acquisition of T55x7 LF signal. Similar to other LF, but adjusted with @marshmellows thresholds
|
||||
|
@ -40,7 +40,7 @@ uint32_t SampleLF(bool verbose, uint32_t sample_size);
|
|||
* Initializes the FPGA for sniff-mode (field off), and acquires the samples.
|
||||
* @return number of bits sampled
|
||||
**/
|
||||
uint32_t SniffLF(void);
|
||||
uint32_t SniffLF(bool verbose, uint32_t sample_size);
|
||||
|
||||
uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, int16_t trigger_threshold,
|
||||
bool verbose, uint32_t sample_size, uint32_t cancel_after, int32_t samples_to_skip);
|
||||
|
@ -99,7 +99,7 @@ void setSamplingConfig(sample_config *sc);
|
|||
|
||||
sample_config *getSamplingConfig(void);
|
||||
|
||||
void printConfig(void);
|
||||
void printLFConfig(void);
|
||||
void printSamples(void);
|
||||
|
||||
#endif // __LFSAMPLING_H
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "ticks.h"
|
||||
#include "usb_cdc.h" // usb_poll_validate_length
|
||||
#include "spiffs.h" // spiffs
|
||||
#include "appmain.h" // print_stack_usage
|
||||
|
||||
#ifndef HARDNESTED_AUTHENTICATION_TIMEOUT
|
||||
# define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
|
||||
|
@ -369,7 +370,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
|
|||
|
||||
countblocks *= 4;
|
||||
|
||||
reply_mix(CMD_ACK, 1, countblocks, BigBuf_max_traceLen(), 0, 0);
|
||||
reply_mix(CMD_ACK, 1, countblocks, dataout - BigBuf_get_addr(), 0, 0);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
BigBuf_free();
|
||||
|
@ -443,47 +444,6 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
set_tracing(false);
|
||||
}
|
||||
|
||||
/* // Command not needed but left for future testing
|
||||
void MifareUWriteBlockCompat(uint8_t arg0, uint8_t *datain)
|
||||
{
|
||||
uint8_t blockNo = arg0;
|
||||
uint8_t blockdata[16] = {0x00};
|
||||
|
||||
memcpy(blockdata, datain, 16);
|
||||
|
||||
uint8_t uid[10] = {0x00};
|
||||
|
||||
LED_A_ON(); LED_B_OFF(); LED_C_OFF();
|
||||
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
||||
if(!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
||||
if(mifare_ultra_writeblock_compat(blockNo, blockdata)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
|
||||
OnError(0);
|
||||
return; };
|
||||
|
||||
if(mifare_ultra_halt()) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
||||
if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
|
||||
|
||||
reply_mix(CMD_ACK,1,0,0,0,0);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
}
|
||||
*/
|
||||
|
||||
// Arg0 : Block to write to.
|
||||
// Arg1 : 0 = use no authentication.
|
||||
// 1 = use 0x1A authentication.
|
||||
|
@ -553,6 +513,75 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
|||
set_tracing(false);
|
||||
}
|
||||
|
||||
// Arg0 : Block to write to.
|
||||
// Arg1 : 0 = use no authentication.
|
||||
// 1 = use 0x1A authentication.
|
||||
// 2 = use 0x1B authentication.
|
||||
// datain : 16 first bytes is data to be written.
|
||||
// : 4/16 next bytes is authentication key.
|
||||
void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain) {
|
||||
uint8_t blockNo = arg0;
|
||||
bool useKey = (arg1 == 1); //UL_C
|
||||
bool usePwd = (arg1 == 2); //UL_EV1/NTAG
|
||||
uint8_t blockdata[16] = {0x00};
|
||||
|
||||
memcpy(blockdata, datain, 16);
|
||||
|
||||
LEDsoff();
|
||||
LED_A_ON();
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
||||
// UL-C authentication
|
||||
if (useKey) {
|
||||
uint8_t key[16] = {0x00};
|
||||
memcpy(key, datain + 16, sizeof(key));
|
||||
|
||||
if (!mifare_ultra_auth(key)) {
|
||||
OnError(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// UL-EV1 / NTAG authentication
|
||||
if (usePwd) {
|
||||
uint8_t pwd[4] = {0x00};
|
||||
memcpy(pwd, datain + 16, 4);
|
||||
uint8_t pack[4] = {0, 0, 0, 0};
|
||||
if (!mifare_ul_ev1_auth(pwd, pack)) {
|
||||
OnError(1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (mifare_ultra_writeblock_compat(blockNo, blockdata)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Write block error");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
||||
if (mifare_ultra_halt()) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Halt error");
|
||||
OnError(0);
|
||||
return;
|
||||
};
|
||||
|
||||
if (DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED");
|
||||
|
||||
reply_mix(CMD_ACK, 1, 0, 0, 0, 0);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
set_tracing(false);
|
||||
}
|
||||
|
||||
void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
||||
|
||||
uint8_t pwd[16] = {0x00};
|
||||
|
@ -905,7 +934,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
|||
set_tracing(true);
|
||||
|
||||
// statistics on nonce distance
|
||||
int16_t isOK = 0;
|
||||
int16_t isOK = PM3_SUCCESS;
|
||||
#define NESTED_MAX_TRIES 12
|
||||
if (calibrate) { // calibrate: for first call only. Otherwise reuse previous calibration
|
||||
LED_B_ON();
|
||||
|
@ -921,7 +950,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
|||
|
||||
// Test if the action was cancelled
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
isOK = -2;
|
||||
isOK = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -976,7 +1005,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
|||
} else {
|
||||
unsuccessful_tries++;
|
||||
if (unsuccessful_tries > NESTED_MAX_TRIES) { // card isn't vulnerable to nested attack (random numbers are not predictable)
|
||||
isOK = -3;
|
||||
isOK = PM3_EFAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1002,7 +1031,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
|||
|
||||
// Test if the action was cancelled
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
isOK = -2;
|
||||
isOK = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1091,12 +1120,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
|||
memcpy(payload.nt_b, &target_nt[1], 4);
|
||||
memcpy(payload.ks_b, &target_ks[1], 4);
|
||||
|
||||
LED_B_ON();
|
||||
reply_ng(CMD_HF_MIFARE_NESTED, PM3_SUCCESS, (uint8_t *)&payload, sizeof(payload));
|
||||
LED_B_OFF();
|
||||
|
||||
if (DBGLEVEL >= 3) DbpString("NESTED FINISHED");
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
set_tracing(false);
|
||||
|
@ -1108,13 +1132,10 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
|||
|
||||
uint64_t ui64Key = 0;
|
||||
ui64Key = bytes_to_num(key, 6);
|
||||
|
||||
// variables
|
||||
uint16_t len;
|
||||
|
||||
uint8_t uid[10] = {0x00};
|
||||
uint32_t cuid = 0, nt1, nt2;
|
||||
uint32_t target_nt = {0x00}, target_ks = {0x00};
|
||||
uint32_t target_nt = 0, target_ks = 0;
|
||||
uint8_t par[1] = {0x00};
|
||||
uint8_t receivedAnswer[10] = {0x00};
|
||||
|
||||
|
@ -1132,7 +1153,6 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
|||
set_tracing(true);
|
||||
|
||||
int16_t isOK = 0;
|
||||
|
||||
LED_C_ON();
|
||||
|
||||
for (uint8_t retry = 0; retry < 3 && (isOK == 0); retry++) {
|
||||
|
@ -1152,7 +1172,7 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
|||
continue;
|
||||
};
|
||||
|
||||
// First authenticatoin. Normal auth.
|
||||
// First authentication. Normal auth.
|
||||
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
|
||||
if (DBGLEVEL >= DBG_INFO) Dbprintf("Nested: Auth1 error");
|
||||
retry--;
|
||||
|
@ -1167,9 +1187,8 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
|||
};
|
||||
|
||||
nt2 = bytes_to_num(receivedAnswer, 4);
|
||||
uint32_t nt_tmp = prng_successor(nt1, 160);
|
||||
target_ks = nt2 ^ nt_tmp;
|
||||
target_nt = nt_tmp;
|
||||
target_nt = prng_successor(nt1, 160);
|
||||
target_ks = nt2 ^ target_nt;
|
||||
isOK = 1;
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("Testing nt1=%08x nt2enc=%08x nt2par=%02x ks=%08x", nt1, nt2, par[0], target_ks);
|
||||
|
@ -1689,7 +1708,7 @@ OUT:
|
|||
DBGLEVEL = oldbg;
|
||||
}
|
||||
|
||||
void MifareChkKeys(uint8_t *datain) {
|
||||
void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem) {
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
|
@ -1715,7 +1734,12 @@ void MifareChkKeys(uint8_t *datain) {
|
|||
bool clearTrace = datain[2];
|
||||
uint16_t key_count = (datain[3] << 8) | datain[4];
|
||||
|
||||
uint16_t key_mem_available = MIN((PM3_CMD_DATA_SIZE - 5), key_count * 6);
|
||||
uint16_t key_mem_available;
|
||||
if (reserved_mem)
|
||||
key_mem_available = key_count * 6;
|
||||
else
|
||||
key_mem_available = MIN((PM3_CMD_DATA_SIZE - 5), key_count * 6);
|
||||
|
||||
key_count = key_mem_available / 6;
|
||||
|
||||
datain += 5;
|
||||
|
@ -1793,6 +1817,8 @@ void MifareChkKeys(uint8_t *datain) {
|
|||
void MifareChkKeys_file(uint8_t *fn) {
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
BigBuf_free();
|
||||
|
||||
SpinOff(0);
|
||||
|
||||
int changed = rdv40_spiffs_lazy_mount();
|
||||
|
@ -1807,7 +1833,7 @@ void MifareChkKeys_file(uint8_t *fn) {
|
|||
|
||||
SpinOff(0);
|
||||
|
||||
MifareChkKeys(mem);
|
||||
MifareChkKeys(mem, true);
|
||||
|
||||
BigBuf_free();
|
||||
#endif
|
||||
|
@ -1952,29 +1978,35 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) {
|
|||
uint64_t ui64Key = emlGetKey(sectorNo, keytype);
|
||||
if (sectorNo == 0) {
|
||||
if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_FIRST)) {
|
||||
retval = PM3_ESOFT;
|
||||
retval = PM3_EPARTIAL;
|
||||
if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth error", sectorNo);
|
||||
goto out;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_NESTED)) {
|
||||
retval = PM3_ESOFT;
|
||||
retval = PM3_EPARTIAL;
|
||||
if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth nested error", sectorNo);
|
||||
goto out;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (uint8_t blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
|
||||
if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {
|
||||
retval = PM3_ESOFT;
|
||||
retval = PM3_EPARTIAL;
|
||||
|
||||
if (DBGLEVEL > DBG_ERROR) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo);
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(dataoutbuf, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (blockNo < NumBlocksPerSector(sectorNo) - 1) {
|
||||
emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1);
|
||||
} else { // sector trailer, keep the keys, set only the AC
|
||||
emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
|
||||
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
|
||||
memcpy(dataoutbuf2 + 6, dataoutbuf + 6, 4);
|
||||
emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
|
||||
}
|
||||
}
|
||||
|
@ -2059,12 +2091,19 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) {
|
|||
break;
|
||||
}
|
||||
|
||||
uint32_t old_timeout = iso14a_get_timeout();
|
||||
|
||||
// 2000 ms timeout
|
||||
// 13560000 / 1000 / (8 * 16) * timeout
|
||||
iso14a_set_timeout(21190);
|
||||
|
||||
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
|
||||
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("wipeC error");
|
||||
errormsg = MAGIC_WIPE;
|
||||
break;
|
||||
}
|
||||
iso14a_set_timeout(old_timeout);
|
||||
|
||||
mifare_classic_halt_ex(NULL);
|
||||
}
|
||||
|
@ -2197,12 +2236,14 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) {
|
|||
OnSuccessMagic();
|
||||
}
|
||||
|
||||
void MifareCIdent(void) {
|
||||
void MifareCIdent(bool is_mfc) {
|
||||
// variables
|
||||
uint8_t isGen = 0;
|
||||
uint8_t rec[1] = {0x00};
|
||||
uint8_t recpar[1] = {0x00};
|
||||
uint8_t rats[4] = { ISO14443A_CMD_RATS, 0x80, 0x31, 0x73 };
|
||||
uint8_t rdblf0[4] = { ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
|
||||
uint8_t rdbl00[4] = { ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
|
||||
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
|
@ -2237,13 +2278,79 @@ void MifareCIdent(void) {
|
|||
|
||||
ReaderTransmit(rats, sizeof(rats), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
// test for some MFC gen2
|
||||
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
|
||||
|
||||
// super card ident
|
||||
uint8_t super[] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
|
||||
ReaderTransmit(super, sizeof(super), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 22) {
|
||||
isGen = MAGIC_SUPER;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some MFC 7b gen2
|
||||
if (memcmp(buf, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
}
|
||||
// test for Ultralight magic gen2
|
||||
if (memcmp(buf, "\x0A\x78\x00\x81\x02\xDB\xA0\xC1\x19\x40\x2A\xB5", 12) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x41\xDF", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight EV1 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xC3\x00\x04\x03\x01\x01\x00\x0B\x03\x16\xD7", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some other Ultralight magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x0A\x00\x0A\xB0\x00\x00\x00\x00\x00\x00\x00\x00\x18\x4D", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for NTAG213 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xA5\x00\x04\x04\x02\x01\x00\x0F\x03\x79\x0C", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
if (! is_mfc) {
|
||||
// magic ntag test
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(40);
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
|
||||
if (res == 2) {
|
||||
ReaderTransmit(rdblf0, sizeof(rdblf0), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 18) {
|
||||
isGen = MAGIC_NTAG21X;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_mfc) {
|
||||
// magic MFC Gen3 test
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(40);
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
|
||||
if (res == 2) {
|
||||
ReaderTransmit(rdbl00, sizeof(rdbl00), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 18) {
|
||||
isGen = MAGIC_GEN_3;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
OUT:
|
||||
|
@ -2258,29 +2365,29 @@ OUT:
|
|||
void MifareHasStaticNonce(void) {
|
||||
|
||||
// variables
|
||||
int retval = PM3_SUCCESS, len;
|
||||
|
||||
uint32_t nt = 0 ;
|
||||
uint8_t rec[1] = {0x00};
|
||||
uint8_t recpar[1] = {0x00};
|
||||
int retval = PM3_SUCCESS;
|
||||
uint32_t nt = 0;
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
uint8_t data[1] = {0x00};
|
||||
|
||||
uint8_t data[1] = { NONCE_FAIL };
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
pcs = &mpcs;
|
||||
iso14a_card_select_t card_info;
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
uint8_t counter = 0;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
|
||||
iso14a_card_select_t card_info;
|
||||
if (!iso14443a_select_card(uid, &card_info, NULL, true, 0, true)) {
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
uint8_t rec[1] = {0x00};
|
||||
uint8_t recpar[1] = {0x00};
|
||||
// Transmit MIFARE_CLASSIC_AUTH 0x60, block 0
|
||||
len = mifare_sendcmd_short(pcs, false, MIFARE_AUTH_KEYA, 0, rec, recpar, NULL);
|
||||
int len = mifare_sendcmd_short(pcs, false, MIFARE_AUTH_KEYA, 0, rec, recpar, NULL);
|
||||
if (len != 4) {
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
|
@ -2288,14 +2395,24 @@ void MifareHasStaticNonce(void) {
|
|||
|
||||
// Save the tag nonce (nt)
|
||||
if (nt == bytes_to_num(rec, 4)) {
|
||||
data[0]++;
|
||||
counter++;
|
||||
}
|
||||
|
||||
nt = bytes_to_num(rec, 4);
|
||||
|
||||
// some cards with static nonce need to be reset before next query
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
CHK_TIMEOUT();
|
||||
}
|
||||
|
||||
if (counter) {
|
||||
Dbprintf("%u static nonce %08x", data[0], nt);
|
||||
data[0] = NONCE_STATIC;
|
||||
} else {
|
||||
data[0] = NONCE_NORMAL;
|
||||
}
|
||||
|
||||
OUT:
|
||||
reply_ng(CMD_HF_MIFARE_STATIC_NONCE, retval, data, sizeof(data));
|
||||
// turns off
|
||||
|
@ -2315,6 +2432,154 @@ void OnErrorMagic(uint8_t reason) {
|
|||
OnSuccessMagic();
|
||||
}
|
||||
|
||||
int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len) {
|
||||
int retval = PM3_SUCCESS;
|
||||
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||
|
||||
LED_B_ON();
|
||||
uint32_t save_iso14a_timeout = iso14a_get_timeout();
|
||||
iso14a_set_timeout(13560000 / 1000 / (8 * 16) * 2000); // 2 seconds timeout
|
||||
|
||||
ReaderTransmit(cmd, cmd_len, NULL);
|
||||
int res = ReaderReceive(buf, par);
|
||||
if (res == 4 && memcmp(buf, "\x90\x00\xfd\x07", 4) == 0) {
|
||||
// timeout for card memory reset
|
||||
SpinDelay(1000);
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card operation not completed");
|
||||
retval = PM3_ESOFT;
|
||||
}
|
||||
iso14a_set_timeout(save_iso14a_timeout);
|
||||
LED_B_OFF();
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void MifareGen3UID(uint8_t uidlen, uint8_t *uid) {
|
||||
int retval = PM3_SUCCESS;
|
||||
uint8_t uid_cmd[5] = { 0x90, 0xfb, 0xcc, 0xcc, 0x07 };
|
||||
uint8_t *old_uid = BigBuf_malloc(10);
|
||||
uint8_t *cmd = BigBuf_malloc(sizeof(uid_cmd) + uidlen + 2);
|
||||
iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t));
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(old_uid, card_info, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
if (card_info->uidlen != uidlen) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID length");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
memcpy(cmd, uid_cmd, sizeof(uid_cmd));
|
||||
memcpy(&cmd[sizeof(uid_cmd)], uid, uidlen);
|
||||
AddCrc14A(cmd, sizeof(uid_cmd) + uidlen);
|
||||
|
||||
retval = DoGen3Cmd(cmd, sizeof(uid_cmd) + uidlen + 2);
|
||||
|
||||
OUT:
|
||||
reply_ng(CMD_HF_MIFARE_GEN3UID, retval, old_uid, uidlen);
|
||||
// turns off
|
||||
OnSuccessMagic();
|
||||
BigBuf_free();
|
||||
}
|
||||
|
||||
void MifareGen3Blk(uint8_t block_len, uint8_t *block) {
|
||||
#define MIFARE_BLOCK_SIZE (MAX_MIFARE_FRAME_SIZE - 2)
|
||||
int retval = PM3_SUCCESS;
|
||||
uint8_t block_cmd[5] = { 0x90, 0xf0, 0xcc, 0xcc, 0x10 };
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
uint8_t *cmd = BigBuf_malloc(sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE);
|
||||
iso14a_card_select_t *card_info = (iso14a_card_select_t *) BigBuf_malloc(sizeof(iso14a_card_select_t));
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(uid, card_info, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
bool doReselect = false;
|
||||
if (block_len < MIFARE_BLOCK_SIZE) {
|
||||
if ((mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_READBLOCK, 0, &cmd[sizeof(block_cmd)], NULL, NULL) != MAX_MIFARE_FRAME_SIZE)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Read manufacturer block failed");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
doReselect = true;
|
||||
}
|
||||
|
||||
if (block_len > 0) {
|
||||
memcpy(cmd, block_cmd, sizeof(block_cmd));
|
||||
memcpy(&cmd[sizeof(block_cmd)], block, block_len);
|
||||
int ofs = sizeof(block_cmd);
|
||||
if (card_info->uidlen == 4) {
|
||||
cmd[ofs + 4] = cmd[ofs + 0] ^ cmd[ofs + 1] ^ cmd[ofs + 2] ^ cmd[ofs + 3];
|
||||
ofs += 5;
|
||||
} else if (card_info->uidlen == 7) {
|
||||
ofs += 7;
|
||||
} else {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong Card UID length");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
cmd[ofs++] = card_info->sak;
|
||||
cmd[ofs++] = card_info->atqa[0];
|
||||
cmd[ofs++] = card_info->atqa[1];
|
||||
AddCrc14A(cmd, sizeof(block_cmd) + MIFARE_BLOCK_SIZE);
|
||||
|
||||
if (doReselect) {
|
||||
if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
}
|
||||
|
||||
retval = DoGen3Cmd(cmd, sizeof(block_cmd) + MAX_MIFARE_FRAME_SIZE);
|
||||
}
|
||||
|
||||
OUT:
|
||||
reply_ng(CMD_HF_MIFARE_GEN3BLK, retval, &cmd[sizeof(block_cmd)], MIFARE_BLOCK_SIZE);
|
||||
// turns off
|
||||
OnSuccessMagic();
|
||||
BigBuf_free();
|
||||
}
|
||||
|
||||
void MifareGen3Freez(void) {
|
||||
int retval = PM3_SUCCESS;
|
||||
uint8_t freeze_cmd[7] = { 0x90, 0xfd, 0x11, 0x11, 0x00, 0xe7, 0x91 };
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
if (!iso14443a_select_card(uid, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Card not selected");
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
retval = DoGen3Cmd(freeze_cmd, sizeof(freeze_cmd));
|
||||
|
||||
OUT:
|
||||
reply_ng(CMD_HF_MIFARE_GEN3FREEZ, retval, NULL, 0);
|
||||
// turns off
|
||||
OnSuccessMagic();
|
||||
BigBuf_free();
|
||||
}
|
||||
|
||||
void MifareSetMod(uint8_t *datain) {
|
||||
|
||||
uint8_t mod = datain[0];
|
||||
|
@ -2430,32 +2695,30 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
|
|||
//
|
||||
// Tear-off attack against MFU.
|
||||
// - Moebius et al
|
||||
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
|
||||
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
|
||||
uint8_t blockNo = arg0;
|
||||
uint32_t tearOffTime = arg1;
|
||||
uint8_t data_fullwrite[4] = {0x00};
|
||||
uint8_t data_testwrite[4] = {0x00};
|
||||
memcpy(data_fullwrite, datain, 4);
|
||||
memcpy(data_testwrite, datain + 4, 4);
|
||||
// optional authentication before?
|
||||
|
||||
if (DBGLEVEL >= DBG_ERROR) DbpString("Preparing OTP tear-off");
|
||||
if (DBGLEVEL >= DBG_DEBUG) DbpString("Preparing OTP tear-off");
|
||||
|
||||
if (tearoff_time > 43000)
|
||||
tearoff_time = 43000;
|
||||
|
||||
MifareUWriteBlock(blockNo, 0, data_fullwrite);
|
||||
|
||||
LEDsoff();
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
StartTicks();
|
||||
|
||||
// write cmd to send, include CRC
|
||||
// 1b write, 1b block, 4b data, 2 crc
|
||||
uint8_t cmd[] = {MIFARE_ULC_WRITE, blockNo, data_testwrite[0], data_testwrite[1], data_testwrite[2], data_testwrite[3], 0, 0};
|
||||
|
||||
MifareUWriteBlock(blockNo, 0, data_fullwrite);
|
||||
|
||||
AddCrc14A(cmd, sizeof(cmd) - 2);
|
||||
if (DBGLEVEL >= DBG_ERROR) DbpString("Transmitting");
|
||||
|
||||
// anticollision / select card
|
||||
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
|
@ -2467,11 +2730,51 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
|
|||
|
||||
// Wait before cutting power. aka tear-off
|
||||
LED_D_ON();
|
||||
WaitUS(tearOffTime);
|
||||
|
||||
SpinDelayUsPrecision(tearoff_time);
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!"));
|
||||
switch_off();
|
||||
|
||||
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||
StopTicks();
|
||||
|
||||
if (DBGLEVEL >= DBG_ERROR) DbpString("Done");
|
||||
}
|
||||
|
||||
//
|
||||
// Tear-off attack against MFU counter
|
||||
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) {
|
||||
|
||||
if (tearoff_time > 43000)
|
||||
tearoff_time = 43000;
|
||||
|
||||
LEDsoff();
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
// Send MFU counter increase cmd
|
||||
uint8_t cmd[] = {
|
||||
MIFARE_ULEV1_INCR_CNT,
|
||||
counter,
|
||||
0, // lsb
|
||||
0,
|
||||
0, // msb
|
||||
0, // rfu
|
||||
0,
|
||||
0,
|
||||
};
|
||||
AddCrc14A(cmd, sizeof(cmd) - 2);
|
||||
|
||||
// anticollision / select card
|
||||
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
OnError(1);
|
||||
return;
|
||||
};
|
||||
|
||||
// send
|
||||
ReaderTransmit(cmd, sizeof(cmd), NULL);
|
||||
LED_D_ON();
|
||||
SpinDelayUsPrecision(tearoff_time);
|
||||
switch_off();
|
||||
|
||||
reply_ng(CMD_HF_MFU_COUNTER_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes);
|
|||
void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
|
||||
void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t *datain);
|
||||
void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
|
||||
//void MifareUWriteBlockCompat(uint8_t arg0,uint8_t *datain);
|
||||
void MifareUWriteBlockCompat(uint8_t arg0, uint8_t arg1, uint8_t *datain);
|
||||
|
||||
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
|
||||
void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, bool calibrate, uint8_t *key);
|
||||
|
@ -29,7 +29,7 @@ void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo,
|
|||
|
||||
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
|
||||
void MifareAcquireNonces(uint32_t arg0, uint32_t flags);
|
||||
void MifareChkKeys(uint8_t *datain);
|
||||
void MifareChkKeys(uint8_t *datain, uint8_t reserved_mem);
|
||||
void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||
void MifareChkKeys_file(uint8_t *fn);
|
||||
|
||||
|
@ -41,9 +41,14 @@ int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype);
|
|||
|
||||
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work with "magic Chinese" card
|
||||
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain);
|
||||
void MifareCIdent(void); // is "magic chinese" card?
|
||||
void MifareCIdent(bool is_mfc); // is "magic chinese" card?
|
||||
void MifareHasStaticNonce(void); // Has the tag a static nonce?
|
||||
|
||||
int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len);
|
||||
void MifareGen3UID(uint8_t uidlen, uint8_t *uid); // Gen 3 magic card set UID without manufacturer block
|
||||
void MifareGen3Blk(uint8_t block_len, uint8_t *block); // Gen 3 magic card overwrite manufacturer block
|
||||
void MifareGen3Freez(void); // Gen 3 magic card lock further UID changes
|
||||
|
||||
void MifareSetMod(uint8_t *datain);
|
||||
void MifarePersonalizeUID(uint8_t keyType, uint8_t perso_option, uint64_t key);
|
||||
|
||||
|
@ -59,5 +64,5 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
|
|||
|
||||
// Tear-off test for MFU
|
||||
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain);
|
||||
|
||||
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time);
|
||||
#endif
|
||||
|
|
|
@ -118,6 +118,7 @@ void MifareDesfireGetInformation(void) {
|
|||
struct p {
|
||||
uint8_t isOK;
|
||||
uint8_t uid[7];
|
||||
uint8_t uidlen;
|
||||
uint8_t versionHW[7];
|
||||
uint8_t versionSW[7];
|
||||
uint8_t details[14];
|
||||
|
@ -148,15 +149,9 @@ void MifareDesfireGetInformation(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (card.uidlen != 7) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen);
|
||||
payload.isOK = 2; // 2 == WRONG UID
|
||||
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
|
||||
switch_off();
|
||||
return;
|
||||
}
|
||||
// add uid.
|
||||
memcpy(payload.uid, card.uid, sizeof(payload.uid));
|
||||
memcpy(payload.uid, card.uid, card.uidlen);
|
||||
payload.uidlen = card.uidlen;
|
||||
|
||||
LED_A_ON();
|
||||
uint8_t cmd[] = {0x90, MFDES_GET_VERSION, 0x00, 0x00, 0x00};
|
||||
|
|
|
@ -85,7 +85,6 @@ static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t act
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
|
||||
|
||||
uint8_t sector_trailer[16];
|
||||
|
@ -243,7 +242,7 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_
|
|||
rSAK[0] = block0[7];
|
||||
memcpy(rATQA, &block0[8], sizeof(rATQA));
|
||||
} else {
|
||||
Dbprintf("[-] ERROR: Invalid dump. UID/SAK/ATQA not found");
|
||||
Dbprintf("ERROR: " _RED_("Invalid dump. UID/SAK/ATQA not found"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -342,7 +341,7 @@ static bool MifareSimInit(uint16_t flags, uint8_t *datain, uint16_t atqa, uint8_
|
|||
// Correct uid size bits in ATQA
|
||||
rATQA[0] = (rATQA[0] & 0x3f) | 0x80; // triple size uid
|
||||
} else {
|
||||
Dbprintf("[-] ERROR: UID size not defined");
|
||||
Dbprintf("ERROR: " _RED_("UID size not defined"));
|
||||
return false;
|
||||
}
|
||||
if (flags & FLAG_FORCED_ATQA) {
|
||||
|
@ -529,12 +528,22 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
LED_D_ON();
|
||||
ResetSspClk();
|
||||
|
||||
int counter = 0;
|
||||
bool finished = false;
|
||||
bool button_pushed = BUTTON_PRESS();
|
||||
while (!button_pushed && !finished) {
|
||||
|
||||
while (!button_pushed && !finished && !data_available()) {
|
||||
WDT_HIT();
|
||||
|
||||
if (counter == 2000) {
|
||||
if (data_available()) {
|
||||
break;
|
||||
}
|
||||
counter = 0;
|
||||
} else {
|
||||
counter++;
|
||||
}
|
||||
|
||||
// find reader field
|
||||
if (cardSTATE == MFEMUL_NOFIELD) {
|
||||
|
||||
|
|
|
@ -203,14 +203,14 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN
|
|||
iso14a_set_timeout(save_timeout);
|
||||
|
||||
if (!len) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout.");
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Card timeout");
|
||||
return 2;
|
||||
}
|
||||
|
||||
ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0, 0);
|
||||
|
||||
if (ntpp != bytes_to_num(receivedAnswer, 4)) {
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Error card response.");
|
||||
if (DBGLEVEL >= DBG_EXTENDED) Dbprintf("Authentication failed. Error card response");
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
|
@ -225,18 +225,18 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo
|
|||
|
||||
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_READBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
if (len == 1) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error %02x", receivedAnswer[0]);
|
||||
return 1;
|
||||
}
|
||||
if (len != 18) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Cmd Error: wrong response len: %x (expected 18)", len);
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("wrong response len %d (expected 18)", len);
|
||||
return 2;
|
||||
}
|
||||
|
||||
memcpy(bt, receivedAnswer + 16, 2);
|
||||
AddCrc14A(receivedAnswer, 16);
|
||||
if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) {
|
||||
if (DBGLEVEL >= DBG_INFO) Dbprintf("Cmd CRC response error.");
|
||||
if (DBGLEVEL >= DBG_INFO) Dbprintf("CRC response error");
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -446,37 +446,37 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* // command not needed, but left for future testing
|
||||
int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
|
||||
uint16_t len;
|
||||
uint8_t par[3] = {0}; // enough for 18 parity bits
|
||||
uint8_t d_block[18] = {0x00};
|
||||
uint8_t receivedAnswer[MAX_FRAME_SIZE];
|
||||
uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
|
||||
// variables
|
||||
uint16_t len = 0;
|
||||
|
||||
uint8_t d_block[18];
|
||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
|
||||
|
||||
len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
||||
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
|
||||
if (DBGLEVEL >= DBG_ERROR)
|
||||
Dbprintf("Cmd Addr Error: %02x", receivedAnswer[0]);
|
||||
Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
memcpy(d_block, blockData, 16);
|
||||
AddCrc14A(d_block, 16);
|
||||
|
||||
ReaderTransmitPar(d_block, sizeof(d_block), par, NULL);
|
||||
ReaderTransmit(d_block, sizeof(d_block), NULL);
|
||||
|
||||
// Receive the response
|
||||
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
|
||||
|
||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
||||
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
|
||||
if (DBGLEVEL >= DBG_ERROR)
|
||||
Dbprintf("Cmd Data Error: %02x %d", receivedAnswer[0],len);
|
||||
Dbprintf("Cmd Send Data Error: %02x %d", receivedAnswer[0], len);
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) {
|
||||
uint16_t len = 0;
|
||||
|
@ -613,7 +613,7 @@ void emlClearMem(void) {
|
|||
memset(emCARD, 0, CARD_MEMORY_SIZE);
|
||||
|
||||
// fill sectors trailer data
|
||||
for (uint16_t b = 3; b <= MIFARE_4K_MAXBLOCK; ((b <= MIFARE_2K_MAXBLOCK) ? (b += 4) : (b += 16)))
|
||||
for (uint16_t b = 3; b < MIFARE_4K_MAXBLOCK; ((b < MIFARE_2K_MAXBLOCK - 4) ? (b += 4) : (b += 16)))
|
||||
emlSetMem((uint8_t *)trailer, b, 1);
|
||||
|
||||
// uid
|
||||
|
|
|
@ -73,7 +73,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl
|
|||
int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack);
|
||||
int mifare_ultra_auth(uint8_t *keybytes);
|
||||
int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData);
|
||||
//int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData);
|
||||
int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData);
|
||||
int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData);
|
||||
int mifare_ultra_halt(void);
|
||||
|
||||
|
|
|
@ -77,7 +77,15 @@
|
|||
-- piwi 2019
|
||||
**/
|
||||
|
||||
/**
|
||||
add the possibility to do iCLASS on device only
|
||||
-- iceman 2020
|
||||
**/
|
||||
|
||||
#include "optimized_cipher.h"
|
||||
#include "optimized_elite.h"
|
||||
#include "optimized_ikeys.h"
|
||||
#include "optimized_cipherutils.h"
|
||||
|
||||
static const uint8_t opt_select_LUT[256] = {
|
||||
00, 03, 02, 01, 02, 03, 00, 01, 04, 07, 07, 04, 06, 07, 05, 04,
|
||||
|
@ -241,11 +249,34 @@ static void opt_MAC(uint8_t *k, uint8_t *input, uint8_t *out) {
|
|||
opt_output(k, &_init, out);
|
||||
}
|
||||
|
||||
static void opt_MAC_N(uint8_t *k, uint8_t *input, uint8_t in_size, uint8_t *out) {
|
||||
State _init = {
|
||||
((k[0] ^ 0x4c) + 0xEC) & 0xFF,// l
|
||||
((k[0] ^ 0x4c) + 0x21) & 0xFF,// r
|
||||
0x4c, // b
|
||||
0xE012 // t
|
||||
};
|
||||
|
||||
opt_suc(k, &_init, input, in_size, false);
|
||||
opt_output(k, &_init, out);
|
||||
}
|
||||
|
||||
void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]) {
|
||||
uint8_t dest [] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
opt_MAC(div_key_p, cc_nr_p, dest);
|
||||
memcpy(mac, dest, 4);
|
||||
return;
|
||||
}
|
||||
|
||||
void opt_doReaderMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) {
|
||||
opt_suc(div_key_p, &_init, nr, 4, false);
|
||||
opt_output(div_key_p, &_init, mac);
|
||||
}
|
||||
|
||||
|
||||
void doMAC_N(uint8_t *in_p, uint8_t in_size, uint8_t *div_key_p, uint8_t mac[4]) {
|
||||
uint8_t dest [] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
opt_MAC_N(div_key_p, in_p, in_size, dest);
|
||||
memcpy(mac, dest, 4);
|
||||
}
|
||||
|
||||
void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) {
|
||||
|
@ -257,7 +288,6 @@ void opt_doTagMAC(uint8_t *cc_p, const uint8_t *div_key_p, uint8_t mac[4]) {
|
|||
};
|
||||
opt_suc(div_key_p, &_init, cc_p, 12, true);
|
||||
opt_output(div_key_p, &_init, mac);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -291,5 +321,24 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p) {
|
|||
void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p) {
|
||||
opt_suc(div_key_p, &_init, nr, 4, true);
|
||||
opt_output(div_key_p, &_init, mac);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void iclass_calc_div_key(uint8_t *csn, uint8_t *key, uint8_t *div_key, bool elite) {
|
||||
if (elite) {
|
||||
uint8_t keytable[128] = {0};
|
||||
uint8_t key_index[8] = {0};
|
||||
uint8_t key_sel[8] = { 0 };
|
||||
uint8_t key_sel_p[8] = { 0 };
|
||||
hash2(key, keytable);
|
||||
hash1(csn, key_index);
|
||||
for (uint8_t i = 0; i < 8 ; i++)
|
||||
key_sel[i] = keytable[key_index[i]];
|
||||
|
||||
//Permute from iclass format to standard format
|
||||
permutekey_rev(key_sel, key_sel_p);
|
||||
diversifyKey(csn, key_sel_p, div_key);
|
||||
} else {
|
||||
diversifyKey(csn, key, div_key);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,9 @@ typedef struct {
|
|||
/** The reader MAC is MAC(key, CC * NR )
|
||||
**/
|
||||
void opt_doReaderMAC(uint8_t *cc_nr_p, uint8_t *div_key_p, uint8_t mac[4]);
|
||||
|
||||
void opt_doReaderMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p);
|
||||
|
||||
/**
|
||||
* The tag MAC is MAC(key, CC * NR * 32x0))
|
||||
*/
|
||||
|
@ -46,4 +49,6 @@ State opt_doTagMAC_1(uint8_t *cc_p, const uint8_t *div_key_p);
|
|||
*/
|
||||
void opt_doTagMAC_2(State _init, uint8_t *nr, uint8_t mac[4], const uint8_t *div_key_p);
|
||||
|
||||
void doMAC_N(uint8_t *in_p, uint8_t in_size, uint8_t *div_key_p, uint8_t mac[4]);
|
||||
void iclass_calc_div_key(uint8_t *csn, uint8_t *key, uint8_t *div_key, bool elite);
|
||||
#endif // OPTIMIZED_CIPHER_H
|
||||
|
|
140
armsrc/optimized_cipherutils.c
Normal file
140
armsrc/optimized_cipherutils.c
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*****************************************************************************
|
||||
* WARNING
|
||||
*
|
||||
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
|
||||
*
|
||||
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
|
||||
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
|
||||
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
|
||||
*
|
||||
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
|
||||
*
|
||||
*****************************************************************************
|
||||
*
|
||||
* This file is part of loclass. It is a reconstructon of the cipher engine
|
||||
* used in iClass, and RFID techology.
|
||||
*
|
||||
* The implementation is based on the work performed by
|
||||
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
|
||||
* Milosch Meriac in the paper "Dismantling IClass".
|
||||
*
|
||||
* Copyright (C) 2014 Martin Holst Swende
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, or, at your option, any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "optimized_cipherutils.h"
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
*
|
||||
* @brief Return and remove the first bit (x0) in the stream : <x0 x1 x2 x3 ... xn >
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
bool headBit(BitstreamIn *stream) {
|
||||
int bytepos = stream->position >> 3; // divide by 8
|
||||
int bitpos = (stream->position++) & 7; // mask out 00000111
|
||||
return (*(stream->buffer + bytepos) >> (7 - bitpos)) & 1;
|
||||
}
|
||||
/**
|
||||
* @brief Return and remove the last bit (xn) in the stream: <x0 x1 x2 ... xn>
|
||||
* @param stream
|
||||
* @return
|
||||
*/
|
||||
bool tailBit(BitstreamIn *stream) {
|
||||
int bitpos = stream->numbits - 1 - (stream->position++);
|
||||
|
||||
int bytepos = bitpos >> 3;
|
||||
bitpos &= 7;
|
||||
return (*(stream->buffer + bytepos) >> (7 - bitpos)) & 1;
|
||||
}
|
||||
/**
|
||||
* @brief Pushes bit onto the stream
|
||||
* @param stream
|
||||
* @param bit
|
||||
*/
|
||||
void pushBit(BitstreamOut *stream, bool bit) {
|
||||
int bytepos = stream->position >> 3; // divide by 8
|
||||
int bitpos = stream->position & 7;
|
||||
*(stream->buffer + bytepos) |= (bit) << (7 - bitpos);
|
||||
stream->position++;
|
||||
stream->numbits++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pushes the lower six bits onto the stream
|
||||
* as b0 b1 b2 b3 b4 b5 b6
|
||||
* @param stream
|
||||
* @param bits
|
||||
*/
|
||||
void push6bits(BitstreamOut *stream, uint8_t bits) {
|
||||
pushBit(stream, bits & 0x20);
|
||||
pushBit(stream, bits & 0x10);
|
||||
pushBit(stream, bits & 0x08);
|
||||
pushBit(stream, bits & 0x04);
|
||||
pushBit(stream, bits & 0x02);
|
||||
pushBit(stream, bits & 0x01);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief bitsLeft
|
||||
* @param stream
|
||||
* @return number of bits left in stream
|
||||
*/
|
||||
int bitsLeft(BitstreamIn *stream) {
|
||||
return stream->numbits - stream->position;
|
||||
}
|
||||
/**
|
||||
* @brief numBits
|
||||
* @param stream
|
||||
* @return Number of bits stored in stream
|
||||
*/
|
||||
void x_num_to_bytes(uint64_t n, size_t len, uint8_t *dest) {
|
||||
while (len--) {
|
||||
dest[len] = (uint8_t) n;
|
||||
n >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t x_bytes_to_num(uint8_t *src, size_t len) {
|
||||
uint64_t num = 0;
|
||||
while (len--) {
|
||||
num = (num << 8) | (*src);
|
||||
src++;
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
uint8_t reversebytes(uint8_t b) {
|
||||
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
||||
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
||||
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||
return b;
|
||||
}
|
||||
|
||||
void reverse_arraybytes(uint8_t *arr, size_t len) {
|
||||
uint8_t i;
|
||||
for (i = 0; i < len ; i++) {
|
||||
arr[i] = reversebytes(arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void reverse_arraycopy(uint8_t *arr, uint8_t *dest, size_t len) {
|
||||
uint8_t i;
|
||||
for (i = 0; i < len ; i++) {
|
||||
dest[i] = reversebytes(arr[i]);
|
||||
}
|
||||
}
|
||||
|
66
armsrc/optimized_cipherutils.h
Normal file
66
armsrc/optimized_cipherutils.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*****************************************************************************
|
||||
* WARNING
|
||||
*
|
||||
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
|
||||
*
|
||||
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
|
||||
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
|
||||
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
|
||||
*
|
||||
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
|
||||
*
|
||||
*****************************************************************************
|
||||
*
|
||||
* This file is part of loclass. It is a reconstructon of the cipher engine
|
||||
* used in iClass, and RFID techology.
|
||||
*
|
||||
* The implementation is based on the work performed by
|
||||
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
|
||||
* Milosch Meriac in the paper "Dismantling IClass".
|
||||
*
|
||||
* Copyright (C) 2014 Martin Holst Swende
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, or, at your option, any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
#ifndef CIPHERUTILS_H
|
||||
#define CIPHERUTILS_H
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
uint8_t *buffer;
|
||||
uint8_t numbits;
|
||||
uint8_t position;
|
||||
} BitstreamIn;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *buffer;
|
||||
uint8_t numbits;
|
||||
uint8_t position;
|
||||
} BitstreamOut;
|
||||
|
||||
bool headBit(BitstreamIn *stream);
|
||||
bool tailBit(BitstreamIn *stream);
|
||||
void pushBit(BitstreamOut *stream, bool bit);
|
||||
int bitsLeft(BitstreamIn *stream);
|
||||
|
||||
void push6bits(BitstreamOut *stream, uint8_t bits);
|
||||
void x_num_to_bytes(uint64_t n, size_t len, uint8_t *dest);
|
||||
uint64_t x_bytes_to_num(uint8_t *src, size_t len);
|
||||
uint8_t reversebytes(uint8_t b);
|
||||
void reverse_arraybytes(uint8_t *arr, size_t len);
|
||||
void reverse_arraycopy(uint8_t *arr, uint8_t *dest, size_t len);
|
||||
#endif // CIPHERUTILS_H
|
238
armsrc/optimized_elite.c
Normal file
238
armsrc/optimized_elite.c
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*****************************************************************************
|
||||
* WARNING
|
||||
*
|
||||
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
|
||||
*
|
||||
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
|
||||
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
|
||||
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
|
||||
*
|
||||
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
|
||||
*
|
||||
*****************************************************************************
|
||||
*
|
||||
* This file is part of loclass. It is a reconstructon of the cipher engine
|
||||
* used in iClass, and RFID techology.
|
||||
*
|
||||
* The implementation is based on the work performed by
|
||||
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
|
||||
* Milosch Meriac in the paper "Dismantling IClass".
|
||||
*
|
||||
* Copyright (C) 2014 Martin Holst Swende
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, or, at your option, any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
#include "optimized_elite.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include "mbedtls/des.h"
|
||||
#include "optimized_ikeys.h"
|
||||
|
||||
/**
|
||||
* @brief Permutes a key from standard NIST format to Iclass specific format
|
||||
* from http://www.proxmark.org/forum/viewtopic.php?pid=11220#p11220
|
||||
*
|
||||
* If you permute [6c 8d 44 f9 2a 2d 01 bf] you get [8a 0d b9 88 bb a7 90 ea] as shown below.
|
||||
*
|
||||
* 1 0 1 1 1 1 1 1 bf
|
||||
* 0 0 0 0 0 0 0 1 01
|
||||
* 0 0 1 0 1 1 0 1 2d
|
||||
* 0 0 1 0 1 0 1 0 2a
|
||||
* 1 1 1 1 1 0 0 1 f9
|
||||
* 0 1 0 0 0 1 0 0 44
|
||||
* 1 0 0 0 1 1 0 1 8d
|
||||
* 0 1 1 0 1 1 0 0 6c
|
||||
*
|
||||
* 8 0 b 8 b a 9 e
|
||||
* a d 9 8 b 7 0 a
|
||||
*
|
||||
* @param key
|
||||
* @param dest
|
||||
*/
|
||||
void permutekey(uint8_t key[8], uint8_t dest[8]) {
|
||||
int i;
|
||||
for (i = 0 ; i < 8 ; i++) {
|
||||
dest[i] = (((key[7] & (0x80 >> i)) >> (7 - i)) << 7) |
|
||||
(((key[6] & (0x80 >> i)) >> (7 - i)) << 6) |
|
||||
(((key[5] & (0x80 >> i)) >> (7 - i)) << 5) |
|
||||
(((key[4] & (0x80 >> i)) >> (7 - i)) << 4) |
|
||||
(((key[3] & (0x80 >> i)) >> (7 - i)) << 3) |
|
||||
(((key[2] & (0x80 >> i)) >> (7 - i)) << 2) |
|
||||
(((key[1] & (0x80 >> i)) >> (7 - i)) << 1) |
|
||||
(((key[0] & (0x80 >> i)) >> (7 - i)) << 0);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Permutes a key from iclass specific format to NIST format
|
||||
* @brief permutekey_rev
|
||||
* @param key
|
||||
* @param dest
|
||||
*/
|
||||
void permutekey_rev(uint8_t key[8], uint8_t dest[8]) {
|
||||
int i;
|
||||
for (i = 0 ; i < 8 ; i++) {
|
||||
dest[7 - i] = (((key[0] & (0x80 >> i)) >> (7 - i)) << 7) |
|
||||
(((key[1] & (0x80 >> i)) >> (7 - i)) << 6) |
|
||||
(((key[2] & (0x80 >> i)) >> (7 - i)) << 5) |
|
||||
(((key[3] & (0x80 >> i)) >> (7 - i)) << 4) |
|
||||
(((key[4] & (0x80 >> i)) >> (7 - i)) << 3) |
|
||||
(((key[5] & (0x80 >> i)) >> (7 - i)) << 2) |
|
||||
(((key[6] & (0x80 >> i)) >> (7 - i)) << 1) |
|
||||
(((key[7] & (0x80 >> i)) >> (7 - i)) << 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for hash1
|
||||
* @brief rr
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
static uint8_t rr(uint8_t val) {
|
||||
return val >> 1 | ((val & 1) << 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for hash1
|
||||
* @brief rl
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
static uint8_t rl(uint8_t val) {
|
||||
return val << 1 | ((val & 0x80) >> 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for hash1
|
||||
* @brief swap
|
||||
* @param val
|
||||
* @return
|
||||
*/
|
||||
static uint8_t swap(uint8_t val) {
|
||||
return ((val >> 4) & 0xFF) | ((val & 0xFF) << 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash1 takes CSN as input, and determines what bytes in the keytable will be used
|
||||
* when constructing the K_sel.
|
||||
* @param csn the CSN used
|
||||
* @param k output
|
||||
*/
|
||||
void hash1(uint8_t csn[], uint8_t k[]) {
|
||||
k[0] = csn[0] ^ csn[1] ^ csn[2] ^ csn[3] ^ csn[4] ^ csn[5] ^ csn[6] ^ csn[7];
|
||||
k[1] = csn[0] + csn[1] + csn[2] + csn[3] + csn[4] + csn[5] + csn[6] + csn[7];
|
||||
k[2] = rr(swap(csn[2] + k[1]));
|
||||
k[3] = rl(swap(csn[3] + k[0]));
|
||||
k[4] = ~rr(csn[4] + k[2]) + 1;
|
||||
k[5] = ~rl(csn[5] + k[3]) + 1;
|
||||
k[6] = rr(csn[6] + (k[4] ^ 0x3c));
|
||||
k[7] = rl(csn[7] + (k[5] ^ 0xc3));
|
||||
|
||||
k[7] &= 0x7F;
|
||||
k[6] &= 0x7F;
|
||||
k[5] &= 0x7F;
|
||||
k[4] &= 0x7F;
|
||||
k[3] &= 0x7F;
|
||||
k[2] &= 0x7F;
|
||||
k[1] &= 0x7F;
|
||||
k[0] &= 0x7F;
|
||||
}
|
||||
/**
|
||||
Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8 as
|
||||
rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
|
||||
rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
|
||||
**/
|
||||
static void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) {
|
||||
memcpy(outp_key, key, 8);
|
||||
uint8_t j;
|
||||
while (n-- > 0) {
|
||||
for (j = 0; j < 8 ; j++)
|
||||
outp_key[j] = rl(outp_key[j]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static mbedtls_des_context ctx_enc;
|
||||
static mbedtls_des_context ctx_dec;
|
||||
|
||||
static void desdecrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) {
|
||||
uint8_t key_std_format[8] = {0};
|
||||
permutekey_rev(iclass_key, key_std_format);
|
||||
mbedtls_des_setkey_dec(&ctx_dec, key_std_format);
|
||||
mbedtls_des_crypt_ecb(&ctx_dec, input, output);
|
||||
}
|
||||
|
||||
static void desencrypt_iclass(uint8_t *iclass_key, uint8_t *input, uint8_t *output) {
|
||||
uint8_t key_std_format[8] = {0};
|
||||
permutekey_rev(iclass_key, key_std_format);
|
||||
mbedtls_des_setkey_enc(&ctx_enc, key_std_format);
|
||||
mbedtls_des_crypt_ecb(&ctx_enc, input, output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Insert uint8_t[8] custom master key to calculate hash2 and return key_select.
|
||||
* @param key unpermuted custom key
|
||||
* @param hash1 hash1
|
||||
* @param key_sel output key_sel=h[hash1[i]]
|
||||
*/
|
||||
void hash2(uint8_t *key64, uint8_t *outp_keytable) {
|
||||
/**
|
||||
*Expected:
|
||||
* High Security Key Table
|
||||
|
||||
00 F1 35 59 A1 0D 5A 26 7F 18 60 0B 96 8A C0 25 C1
|
||||
10 BF A1 3B B0 FF 85 28 75 F2 1F C6 8F 0E 74 8F 21
|
||||
20 14 7A 55 16 C8 A9 7D B3 13 0C 5D C9 31 8D A9 B2
|
||||
30 A3 56 83 0F 55 7E DE 45 71 21 D2 6D C1 57 1C 9C
|
||||
40 78 2F 64 51 42 7B 64 30 FA 26 51 76 D3 E0 FB B6
|
||||
50 31 9F BF 2F 7E 4F 94 B4 BD 4F 75 91 E3 1B EB 42
|
||||
60 3F 88 6F B8 6C 2C 93 0D 69 2C D5 20 3C C1 61 95
|
||||
70 43 08 A0 2F FE B3 26 D7 98 0B 34 7B 47 70 A0 AB
|
||||
|
||||
**** The 64-bit HS Custom Key Value = 5B7C62C491C11B39 ******/
|
||||
uint8_t key64_negated[8] = {0};
|
||||
uint8_t z[8][8] = {{0}, {0}};
|
||||
uint8_t temp_output[8] = {0};
|
||||
|
||||
//calculate complement of key
|
||||
int i;
|
||||
for (i = 0; i < 8; i++)
|
||||
key64_negated[i] = ~key64[i];
|
||||
|
||||
// Once again, key is on iclass-format
|
||||
desencrypt_iclass(key64, key64_negated, z[0]);
|
||||
|
||||
uint8_t y[8][8] = {{0}, {0}};
|
||||
|
||||
// y[0]=DES_dec(z[0],~key)
|
||||
// Once again, key is on iclass-format
|
||||
desdecrypt_iclass(z[0], key64_negated, y[0]);
|
||||
|
||||
for (i = 1; i < 8; i++) {
|
||||
rk(key64, i, temp_output);
|
||||
desdecrypt_iclass(temp_output, z[i - 1], z[i]);
|
||||
desencrypt_iclass(temp_output, y[i - 1], y[i]);
|
||||
}
|
||||
|
||||
if (outp_keytable != NULL) {
|
||||
for (i = 0 ; i < 8 ; i++) {
|
||||
memcpy(outp_keytable + i * 16, y[i], 8);
|
||||
memcpy(outp_keytable + 8 + i * 16, z[i], 8);
|
||||
}
|
||||
}
|
||||
}
|
62
armsrc/optimized_elite.h
Normal file
62
armsrc/optimized_elite.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*****************************************************************************
|
||||
* WARNING
|
||||
*
|
||||
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
|
||||
*
|
||||
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
|
||||
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
|
||||
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
|
||||
*
|
||||
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
|
||||
*
|
||||
*****************************************************************************
|
||||
*
|
||||
* This file is part of loclass. It is a reconstructon of the cipher engine
|
||||
* used in iClass, and RFID techology.
|
||||
*
|
||||
* The implementation is based on the work performed by
|
||||
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
|
||||
* Milosch Meriac in the paper "Dismantling IClass".
|
||||
*
|
||||
* Copyright (C) 2014 Martin Holst Swende
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, or, at your option, any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#ifndef ELITE_CRACK_H
|
||||
#define ELITE_CRACK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
void permutekey(uint8_t key[8], uint8_t dest[8]);
|
||||
/**
|
||||
* Permutes a key from iclass specific format to NIST format
|
||||
* @brief permutekey_rev
|
||||
* @param key
|
||||
* @param dest
|
||||
*/
|
||||
void permutekey_rev(uint8_t key[8], uint8_t dest[8]);
|
||||
/**
|
||||
* Hash1 takes CSN as input, and determines what bytes in the keytable will be used
|
||||
* when constructing the K_sel.
|
||||
* @param csn the CSN used
|
||||
* @param k output
|
||||
*/
|
||||
void hash1(uint8_t *csn, uint8_t *k);
|
||||
void hash2(uint8_t *key64, uint8_t *outp_keytable);
|
||||
|
||||
#endif
|
324
armsrc/optimized_ikeys.c
Normal file
324
armsrc/optimized_ikeys.c
Normal file
|
@ -0,0 +1,324 @@
|
|||
/*****************************************************************************
|
||||
* WARNING
|
||||
*
|
||||
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
|
||||
*
|
||||
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
|
||||
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
|
||||
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
|
||||
*
|
||||
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
|
||||
*
|
||||
*****************************************************************************
|
||||
*
|
||||
* This file is part of loclass. It is a reconstructon of the cipher engine
|
||||
* used in iClass, and RFID techology.
|
||||
*
|
||||
* The implementation is based on the work performed by
|
||||
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
|
||||
* Milosch Meriac in the paper "Dismantling IClass".
|
||||
*
|
||||
* Copyright (C) 2014 Martin Holst Swende
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, or, at your option, any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
From "Dismantling iclass":
|
||||
This section describes in detail the built-in key diversification algorithm of iClass.
|
||||
Besides the obvious purpose of deriving a card key from a master key, this
|
||||
algorithm intends to circumvent weaknesses in the cipher by preventing the
|
||||
usage of certain ‘weak’ keys. In order to compute a diversified key, the iClass
|
||||
reader first encrypts the card identity id with the master key K, using single
|
||||
DES. The resulting ciphertext is then input to a function called hash0 which
|
||||
outputs the diversified key k.
|
||||
|
||||
k = hash0(DES enc (id, K))
|
||||
|
||||
Here the DES encryption of id with master key K outputs a cryptogram c
|
||||
of 64 bits. These 64 bits are divided as c = x, y, z [0] , . . . , z [7] ∈ F 82 × F 82 × (F 62 ) 8
|
||||
which is used as input to the hash0 function. This function introduces some
|
||||
obfuscation by performing a number of permutations, complement and modulo
|
||||
operations, see Figure 2.5. Besides that, it checks for and removes patterns like
|
||||
similar key bytes, which could produce a strong bias in the cipher. Finally, the
|
||||
output of hash0 is the diversified card key k = k [0] , . . . , k [7] ∈ (F 82 ) 8 .
|
||||
|
||||
**/
|
||||
#include "optimized_ikeys.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include "mbedtls/des.h"
|
||||
#include "optimized_cipherutils.h"
|
||||
|
||||
uint8_t pi[35] = {
|
||||
0x0F, 0x17, 0x1B, 0x1D, 0x1E, 0x27, 0x2B, 0x2D,
|
||||
0x2E, 0x33, 0x35, 0x39, 0x36, 0x3A, 0x3C, 0x47,
|
||||
0x4B, 0x4D, 0x4E, 0x53, 0x55, 0x56, 0x59, 0x5A,
|
||||
0x5C, 0x63, 0x65, 0x66, 0x69, 0x6A, 0x6C, 0x71,
|
||||
0x72, 0x74, 0x78
|
||||
};
|
||||
|
||||
static mbedtls_des_context ctx_enc;
|
||||
|
||||
/**
|
||||
* @brief The key diversification algorithm uses 6-bit bytes.
|
||||
* This implementation uses 64 bit uint to pack seven of them into one
|
||||
* variable. When they are there, they are placed as follows:
|
||||
* XXXX XXXX N0 .... N7, occupying the last 48 bits.
|
||||
*
|
||||
* This function picks out one from such a collection
|
||||
* @param all
|
||||
* @param n bitnumber
|
||||
* @return
|
||||
*/
|
||||
static uint8_t getSixBitByte(uint64_t c, int n) {
|
||||
return (c >> (42 - 6 * n)) & 0x3F;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Puts back a six-bit 'byte' into a uint64_t.
|
||||
* @param c buffer
|
||||
* @param z the value to place there
|
||||
* @param n bitnumber.
|
||||
*/
|
||||
static void pushbackSixBitByte(uint64_t *c, uint8_t z, int n) {
|
||||
//0x XXXX YYYY ZZZZ ZZZZ ZZZZ
|
||||
// ^z0 ^z7
|
||||
//z0: 1111 1100 0000 0000
|
||||
|
||||
uint64_t masked = z & 0x3F;
|
||||
uint64_t eraser = 0x3F;
|
||||
masked <<= 42 - 6 * n;
|
||||
eraser <<= 42 - 6 * n;
|
||||
|
||||
//masked <<= 6*n;
|
||||
//eraser <<= 6*n;
|
||||
|
||||
eraser = ~eraser;
|
||||
(*c) &= eraser;
|
||||
(*c) |= masked;
|
||||
|
||||
}
|
||||
/**
|
||||
* @brief Swaps the z-values.
|
||||
* If the input value has format XYZ0Z1...Z7, the output will have the format
|
||||
* XYZ7Z6...Z0 instead
|
||||
* @param c
|
||||
* @return
|
||||
*/
|
||||
static uint64_t swapZvalues(uint64_t c) {
|
||||
uint64_t newz = 0;
|
||||
pushbackSixBitByte(&newz, getSixBitByte(c, 0), 7);
|
||||
pushbackSixBitByte(&newz, getSixBitByte(c, 1), 6);
|
||||
pushbackSixBitByte(&newz, getSixBitByte(c, 2), 5);
|
||||
pushbackSixBitByte(&newz, getSixBitByte(c, 3), 4);
|
||||
pushbackSixBitByte(&newz, getSixBitByte(c, 4), 3);
|
||||
pushbackSixBitByte(&newz, getSixBitByte(c, 5), 2);
|
||||
pushbackSixBitByte(&newz, getSixBitByte(c, 6), 1);
|
||||
pushbackSixBitByte(&newz, getSixBitByte(c, 7), 0);
|
||||
newz |= (c & 0xFFFF000000000000);
|
||||
return newz;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 4 six-bit bytes chunked into a uint64_t,as 00..00a0a1a2a3
|
||||
*/
|
||||
static uint64_t ck(int i, int j, uint64_t z) {
|
||||
if (i == 1 && j == -1) {
|
||||
// ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3]
|
||||
return z;
|
||||
} else if (j == -1) {
|
||||
// ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] )
|
||||
return ck(i - 1, i - 2, z);
|
||||
}
|
||||
|
||||
if (getSixBitByte(z, i) == getSixBitByte(z, j)) {
|
||||
//ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] )
|
||||
uint64_t newz = 0;
|
||||
int c;
|
||||
for (c = 0; c < 4; c++) {
|
||||
uint8_t val = getSixBitByte(z, c);
|
||||
if (c == i)
|
||||
pushbackSixBitByte(&newz, j, c);
|
||||
else
|
||||
pushbackSixBitByte(&newz, val, c);
|
||||
}
|
||||
return ck(i, j - 1, newz);
|
||||
} else {
|
||||
return ck(i, j - 1, z);
|
||||
}
|
||||
}
|
||||
/**
|
||||
|
||||
Definition 8.
|
||||
Let the function check : (F 62 ) 8 → (F 62 ) 8 be defined as
|
||||
check(z [0] . . . z [7] ) = ck(3, 2, z [0] . . . z [3] ) · ck(3, 2, z [4] . . . z [7] )
|
||||
|
||||
where ck : N × N × (F 62 ) 4 → (F 62 ) 4 is defined as
|
||||
|
||||
ck(1, −1, z [0] . . . z [3] ) = z [0] . . . z [3]
|
||||
ck(i, −1, z [0] . . . z [3] ) = ck(i − 1, i − 2, z [0] . . . z [3] )
|
||||
ck(i, j, z [0] . . . z [3] ) =
|
||||
ck(i, j − 1, z [0] . . . z [i] ← j . . . z [3] ), if z [i] = z [j] ;
|
||||
ck(i, j − 1, z [0] . . . z [3] ), otherwise
|
||||
|
||||
otherwise.
|
||||
**/
|
||||
|
||||
static uint64_t check(uint64_t z) {
|
||||
//These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
|
||||
|
||||
// ck(3, 2, z [0] . . . z [3] )
|
||||
uint64_t ck1 = ck(3, 2, z);
|
||||
|
||||
// ck(3, 2, z [4] . . . z [7] )
|
||||
uint64_t ck2 = ck(3, 2, z << 24);
|
||||
|
||||
//The ck function will place the values
|
||||
// in the middle of z.
|
||||
ck1 &= 0x00000000FFFFFF000000;
|
||||
ck2 &= 0x00000000FFFFFF000000;
|
||||
|
||||
return ck1 | ck2 >> 24;
|
||||
}
|
||||
|
||||
static void permute(BitstreamIn *p_in, uint64_t z, int l, int r, BitstreamOut *out) {
|
||||
if (bitsLeft(p_in) == 0)
|
||||
return;
|
||||
|
||||
bool pn = tailBit(p_in);
|
||||
if (pn) { // pn = 1
|
||||
uint8_t zl = getSixBitByte(z, l);
|
||||
|
||||
push6bits(out, zl + 1);
|
||||
permute(p_in, z, l + 1, r, out);
|
||||
} else { // otherwise
|
||||
uint8_t zr = getSixBitByte(z, r);
|
||||
|
||||
push6bits(out, zr);
|
||||
permute(p_in, z, l, r + 1, out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as
|
||||
* hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
|
||||
* z'[i] = (z[i] mod (63-i)) + i i = 0...3
|
||||
* z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3
|
||||
* ẑ = check(z');
|
||||
* @param c
|
||||
* @param k this is where the diversified key is put (should be 8 bytes)
|
||||
* @return
|
||||
*/
|
||||
void hash0(uint64_t c, uint8_t k[8]) {
|
||||
c = swapZvalues(c);
|
||||
|
||||
//These 64 bits are divided as c = x, y, z [0] , . . . , z [7]
|
||||
// x = 8 bits
|
||||
// y = 8 bits
|
||||
// z0-z7 6 bits each : 48 bits
|
||||
uint8_t x = (c & 0xFF00000000000000) >> 56;
|
||||
uint8_t y = (c & 0x00FF000000000000) >> 48;
|
||||
uint64_t zP = 0;
|
||||
|
||||
for (int n = 0; n < 4 ; n++) {
|
||||
uint8_t zn = getSixBitByte(c, n);
|
||||
uint8_t zn4 = getSixBitByte(c, n + 4);
|
||||
uint8_t _zn = (zn % (63 - n)) + n;
|
||||
uint8_t _zn4 = (zn4 % (64 - n)) + n;
|
||||
pushbackSixBitByte(&zP, _zn, n);
|
||||
pushbackSixBitByte(&zP, _zn4, n + 4);
|
||||
}
|
||||
|
||||
uint64_t zCaret = check(zP);
|
||||
uint8_t p = pi[x % 35];
|
||||
|
||||
if (x & 1) //Check if x7 is 1
|
||||
p = ~p;
|
||||
|
||||
BitstreamIn p_in = { &p, 8, 0 };
|
||||
uint8_t outbuffer[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
BitstreamOut out = {outbuffer, 0, 0};
|
||||
permute(&p_in, zCaret, 0, 4, &out); //returns 48 bits? or 6 8-bytes
|
||||
|
||||
//Out is now a buffer containing six-bit bytes, should be 48 bits
|
||||
// if all went well
|
||||
//Shift z-values down onto the lower segment
|
||||
|
||||
uint64_t zTilde = x_bytes_to_num(outbuffer, sizeof(outbuffer));
|
||||
|
||||
zTilde >>= 16;
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// the key on index i is first a bit from y
|
||||
// then six bits from z,
|
||||
// then a bit from p
|
||||
|
||||
// Init with zeroes
|
||||
k[i] = 0;
|
||||
// First, place yi leftmost in k
|
||||
//k[i] |= (y << i) & 0x80 ;
|
||||
|
||||
// First, place y(7-i) leftmost in k
|
||||
k[i] |= (y << (7 - i)) & 0x80 ;
|
||||
|
||||
uint8_t zTilde_i = getSixBitByte(zTilde, i);
|
||||
// zTildeI is now on the form 00XXXXXX
|
||||
// with one leftshift, it'll be
|
||||
// 0XXXXXX0
|
||||
// So after leftshift, we can OR it into k
|
||||
// However, when doing complement, we need to
|
||||
// again MASK 0XXXXXX0 (0x7E)
|
||||
zTilde_i <<= 1;
|
||||
|
||||
//Finally, add bit from p or p-mod
|
||||
//Shift bit i into rightmost location (mask only after complement)
|
||||
uint8_t p_i = p >> i & 0x1;
|
||||
|
||||
if (k[i]) { // yi = 1
|
||||
k[i] |= ~zTilde_i & 0x7E;
|
||||
k[i] |= p_i & 1;
|
||||
k[i] += 1;
|
||||
|
||||
} else { // otherwise
|
||||
k[i] |= zTilde_i & 0x7E;
|
||||
k[i] |= (~p_i) & 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief Performs Elite-class key diversification
|
||||
* @param csn
|
||||
* @param key
|
||||
* @param div_key
|
||||
*/
|
||||
void diversifyKey(uint8_t *csn, uint8_t *key, uint8_t *div_key) {
|
||||
// Prepare the DES key
|
||||
mbedtls_des_setkey_enc(&ctx_enc, key);
|
||||
|
||||
uint8_t crypted_csn[8] = {0};
|
||||
|
||||
// Calculate DES(CSN, KEY)
|
||||
mbedtls_des_crypt_ecb(&ctx_enc, csn, crypted_csn);
|
||||
|
||||
//Calculate HASH0(DES))
|
||||
uint64_t c_csn = x_bytes_to_num(crypted_csn, sizeof(crypted_csn));
|
||||
|
||||
hash0(c_csn, div_key);
|
||||
}
|
||||
|
69
armsrc/optimized_ikeys.h
Normal file
69
armsrc/optimized_ikeys.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*****************************************************************************
|
||||
* WARNING
|
||||
*
|
||||
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
|
||||
*
|
||||
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
|
||||
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
|
||||
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
|
||||
*
|
||||
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
|
||||
*
|
||||
*****************************************************************************
|
||||
*
|
||||
* This file is part of loclass. It is a reconstructon of the cipher engine
|
||||
* used in iClass, and RFID techology.
|
||||
*
|
||||
* The implementation is based on the work performed by
|
||||
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
|
||||
* Milosch Meriac in the paper "Dismantling IClass".
|
||||
*
|
||||
* Copyright (C) 2014 Martin Holst Swende
|
||||
*
|
||||
* This is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation, or, at your option, any later version.
|
||||
*
|
||||
* This file is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef IKEYS_H
|
||||
#define IKEYS_H
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*Definition 11. Let the function hash0 : F 82 × F 82 × (F 62 ) 8 → (F 82 ) 8 be defined as
|
||||
* hash0(x, y, z [0] . . . z [7] ) = k [0] . . . k [7] where
|
||||
* z'[i] = (z[i] mod (63-i)) + i i = 0...3
|
||||
* z'[i+4] = (z[i+4] mod (64-i)) + i i = 0...3
|
||||
* ẑ = check(z');
|
||||
* @param c
|
||||
* @param k this is where the diversified key is put (should be 8 bytes)
|
||||
* @return
|
||||
*/
|
||||
void hash0(uint64_t c, uint8_t k[8]);
|
||||
/**
|
||||
* @brief Performs Elite-class key diversification
|
||||
* @param csn
|
||||
* @param key
|
||||
* @param div_key
|
||||
*/
|
||||
|
||||
void diversifyKey(uint8_t csn[8], uint8_t key[8], uint8_t div_key[8]);
|
||||
/**
|
||||
* @brief Permutes a key from standard NIST format to Iclass specific format
|
||||
* @param key
|
||||
* @param dest
|
||||
*/
|
||||
|
||||
#endif // IKEYS_H
|
|
@ -67,30 +67,33 @@ static s32_t rdv40_spiffs_llwrite(u32_t addr, u32_t size, u8_t *src) {
|
|||
}
|
||||
|
||||
static s32_t rdv40_spiffs_llerase(u32_t addr, u32_t size) {
|
||||
|
||||
|
||||
uint8_t erased = 0;
|
||||
|
||||
if (!FlashInit()) {
|
||||
return 130;
|
||||
}
|
||||
if (DBGLEVEL > 2) Dbprintf("LLERASEDBG : Orig addr : %d\n", addr);
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("LLERASEDBG : Orig addr : %d\n", addr);
|
||||
|
||||
uint8_t block, sector = 0;
|
||||
block = addr / RDV40_LLERASE_BLOCKSIZE;
|
||||
if (block) {
|
||||
addr = addr - (block * RDV40_LLERASE_BLOCKSIZE);
|
||||
}
|
||||
if (DBGLEVEL > 2) Dbprintf("LLERASEDBG : Result addr : %d\n", addr);
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("LLERASEDBG : Result addr : %d\n", addr);
|
||||
|
||||
sector = addr / SPIFFS_CFG_LOG_BLOCK_SZ;
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
if (DBGLEVEL > 2) Dbprintf("LLERASEDBG : block : %d, sector : %d \n", block, sector);
|
||||
erased = Flash_Erase4k(block, sector);
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("LLERASEDBG : block : %d, sector : %d \n", block, sector);
|
||||
|
||||
erased = Flash_Erase4k(block, sector);
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
FlashStop();
|
||||
|
||||
return SPIFFS_OK == erased ;
|
||||
return (SPIFFS_OK == erased);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -252,7 +255,7 @@ static RDV40SpiFFSFileType filetype_in_spiffs(const char *filename) {
|
|||
filetype = RDV40_SPIFFS_FILETYPE_SYMLINK;
|
||||
}
|
||||
}
|
||||
if (DBGLEVEL > 1) {
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
switch (filetype) {
|
||||
case RDV40_SPIFFS_FILETYPE_REAL:
|
||||
Dbprintf("Filetype is : RDV40_SPIFFS_FILETYPE_REAL");
|
||||
|
@ -472,14 +475,21 @@ int rdv40_spiffs_is_symlink(const char *s) {
|
|||
// ATTENTION : you must NOT provide the whole filename (so please do not include the .lnk extension)
|
||||
// TODO : integrate in read_function
|
||||
int rdv40_spiffs_read_as_symlink(char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level) {
|
||||
RDV40_SPIFFS_SAFE_FUNCTION( //
|
||||
char linkdest[SPIFFS_OBJ_NAME_LEN]; //
|
||||
char linkfilename[SPIFFS_OBJ_NAME_LEN]; //
|
||||
|
||||
RDV40_SPIFFS_SAFE_FUNCTION(
|
||||
char linkdest[SPIFFS_OBJ_NAME_LEN];
|
||||
char linkfilename[SPIFFS_OBJ_NAME_LEN];
|
||||
sprintf(linkfilename, "%s.lnk", filename);
|
||||
if (DBGLEVEL > 1) Dbprintf("Linkk real filename is destination is : %s", linkfilename);
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("Linkk real filename is : " _YELLOW_("%s"), linkfilename);
|
||||
|
||||
read_from_spiffs((char *)linkfilename, (uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN);
|
||||
if (DBGLEVEL > 1) Dbprintf("Symlink destination is : %s", linkdest);
|
||||
read_from_spiffs((char *)linkdest, (uint8_t *)dst, size); //
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG)
|
||||
Dbprintf("Symlink destination is : " _YELLOW_("%s"), linkdest);
|
||||
|
||||
read_from_spiffs((char *)linkdest, (uint8_t *)dst, size);
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -496,10 +506,10 @@ int rdv40_spiffs_read_as_symlink(char *filename, uint8_t *dst, uint32_t size, RD
|
|||
// rdv40_spiffs_read_as_symlink((uint8_t *)"world",(uint8_t *) buffer, orig_file_size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
// TODO : FORBID creating a symlink with a basename (before.lnk) which already exists as a file !
|
||||
int rdv40_spiffs_make_symlink(char *linkdest, char *filename, RDV40SpiFFSSafetyLevel level) {
|
||||
RDV40_SPIFFS_SAFE_FUNCTION( //
|
||||
char linkfilename[SPIFFS_OBJ_NAME_LEN]; //
|
||||
RDV40_SPIFFS_SAFE_FUNCTION(
|
||||
char linkfilename[SPIFFS_OBJ_NAME_LEN];
|
||||
sprintf(linkfilename, "%s.lnk", filename);
|
||||
write_to_spiffs((char *)linkfilename, (uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN); //
|
||||
write_to_spiffs((char *)linkfilename, (uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN);
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -510,8 +520,8 @@ int rdv40_spiffs_make_symlink(char *linkdest, char *filename, RDV40SpiFFSSafetyL
|
|||
// preexistance, avoiding a link being created if filename exists, or avoiding a file being created if
|
||||
// symlink exists with same name
|
||||
int rdv40_spiffs_read_as_filetype(char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level) {
|
||||
RDV40_SPIFFS_SAFE_FUNCTION( //
|
||||
RDV40SpiFFSFileType filetype = filetype_in_spiffs((char *)filename); //
|
||||
RDV40_SPIFFS_SAFE_FUNCTION(
|
||||
RDV40SpiFFSFileType filetype = filetype_in_spiffs((char *)filename);
|
||||
switch (filetype) {
|
||||
case RDV40_SPIFFS_FILETYPE_REAL:
|
||||
rdv40_spiffs_read((char *)filename, (uint8_t *)dst, size, level);
|
||||
|
@ -523,7 +533,7 @@ int rdv40_spiffs_read_as_filetype(char *filename, uint8_t *dst, uint32_t size, R
|
|||
case RDV40_SPIFFS_FILETYPE_UNKNOWN:
|
||||
default:
|
||||
;
|
||||
} //
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -552,7 +562,7 @@ void rdv40_spiffs_safe_print_fsinfo(void) {
|
|||
Dbprintf(" Max Path Length............" _YELLOW_("%d")" chars", fsinfo.maxPathLength);
|
||||
DbpString("");
|
||||
Dbprintf(" filesystem size used available use% mounted");
|
||||
Dbprintf(" spiffs %6d B %6d B %6d B"_YELLOW_("%2d%")" /"
|
||||
Dbprintf(" spiffs %6d B %6d B %6d B " _YELLOW_("%2d%")" /"
|
||||
, fsinfo.totalBytes
|
||||
, fsinfo.usedBytes
|
||||
, fsinfo.freeBytes
|
||||
|
@ -601,6 +611,37 @@ void rdv40_spiffs_safe_print_tree(uint8_t banner) {
|
|||
rdv40_spiffs_lazy_mount_rollback(changed);
|
||||
}
|
||||
|
||||
void rdv40_spiffs_safe_wipe(void) {
|
||||
|
||||
int changed = rdv40_spiffs_lazy_mount();
|
||||
|
||||
spiffs_DIR d;
|
||||
struct spiffs_dirent e;
|
||||
struct spiffs_dirent *pe = &e;
|
||||
SPIFFS_opendir(&fs, "/", &d);
|
||||
|
||||
while ((pe = SPIFFS_readdir(&d, pe))) {
|
||||
|
||||
if (rdv40_spiffs_is_symlink((const char *)pe->name)) {
|
||||
|
||||
char linkdest[SPIFFS_OBJ_NAME_LEN];
|
||||
read_from_spiffs((char *)pe->name, (uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN);
|
||||
|
||||
remove_from_spiffs(linkdest);
|
||||
Dbprintf(".lnk removed %s", pe->name);
|
||||
|
||||
remove_from_spiffs((char *)pe->name);
|
||||
Dbprintf("removed %s", linkdest);
|
||||
|
||||
} else {
|
||||
remove_from_spiffs((char *)pe->name);
|
||||
Dbprintf("removed %s", pe->name);
|
||||
}
|
||||
}
|
||||
|
||||
SPIFFS_closedir(&d);
|
||||
rdv40_spiffs_lazy_mount_rollback(changed);
|
||||
}
|
||||
|
||||
// Selftest function
|
||||
void test_spiffs(void) {
|
||||
|
|
|
@ -58,6 +58,8 @@ int rdv40_spiffs_stat(char *filename, uint32_t *buf, RDV40SpiFFSSafetyLevel leve
|
|||
uint32_t size_in_spiffs(const char *filename);
|
||||
int exists_in_spiffs(const char *filename);
|
||||
|
||||
void rdv40_spiffs_safe_wipe(void);
|
||||
|
||||
#define SPIFFS_OK 0
|
||||
#define SPIFFS_ERR_NOT_MOUNTED -10000
|
||||
#define SPIFFS_ERR_FULL -10001
|
||||
|
|
|
@ -58,8 +58,6 @@ typedef uint8_t u8_t;
|
|||
#define SPIFFS_API_DBGF(str) SPIFFS_API_DBG(str,NULL)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Defines spiffs debug print formatters
|
||||
// some general signed number
|
||||
#ifndef _SPIPRIi
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
void ReadThinFilm(void) {
|
||||
|
||||
clear_trace();
|
||||
|
||||
set_tracing(true);
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
@ -60,15 +59,19 @@ static uint16_t ReadReaderField(void) {
|
|||
}
|
||||
|
||||
static void CodeThinfilmAsTag(const uint8_t *cmd, uint16_t len) {
|
||||
ToSendReset();
|
||||
|
||||
tosend_reset();
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
for (uint16_t i = 0; i < len; i++) {
|
||||
uint8_t b = cmd[i];
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
ToSend[++ToSendMax] = (b & 0x80) ? SEC_D : SEC_E;
|
||||
ts->buf[++ts->max] = (b & 0x80) ? SEC_D : SEC_E;
|
||||
b <<= 1;
|
||||
}
|
||||
}
|
||||
ToSendMax++;
|
||||
ts->max++;
|
||||
}
|
||||
|
||||
static int EmSendCmdThinfilmRaw(uint8_t *resp, uint16_t respLen) {
|
||||
|
@ -122,7 +125,7 @@ void SimulateThinFilm(uint8_t *data, size_t len) {
|
|||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
// Set up the synchronous serial port
|
||||
FpgaSetupSsc();
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
|
||||
|
||||
// connect Demodulated Signal to ADC:
|
||||
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
|
||||
|
@ -132,6 +135,8 @@ void SimulateThinFilm(uint8_t *data, size_t len) {
|
|||
|
||||
uint16_t hf_baseline = ReadReaderField();
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
// Start the timer
|
||||
StartCountSspClk();
|
||||
|
||||
|
@ -147,7 +152,8 @@ void SimulateThinFilm(uint8_t *data, size_t len) {
|
|||
if (hf_av < hf_baseline)
|
||||
hf_baseline = hf_av;
|
||||
if (hf_av > hf_baseline + 10) {
|
||||
EmSendCmdThinfilmRaw(ToSend, ToSendMax);
|
||||
|
||||
EmSendCmdThinfilmRaw(ts->buf, ts->max);
|
||||
if (!reader_detected) {
|
||||
LED_B_ON();
|
||||
//Dbprintf("Reader detected, start beaming data");
|
||||
|
|
|
@ -13,6 +13,31 @@
|
|||
#include "proxmark3_arm.h"
|
||||
#include "dbprint.h"
|
||||
|
||||
|
||||
// timer counts in 666ns increments (32/48MHz), rounding applies
|
||||
// WARNING: timer can't measure more than 43ms (666ns * 0xFFFF)
|
||||
void SpinDelayUsPrecision(int us) {
|
||||
int ticks = ((MCK / 1000000) * us + 16) >> 5;
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
|
||||
// 48 MHz / 32 gives 1.5 Mhz
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(5); // Channel Mode Register
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xFFFF; // Channel Period Register
|
||||
|
||||
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
|
||||
for (;;) {
|
||||
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
if (now == (uint16_t)(start + ticks))
|
||||
return;
|
||||
|
||||
WDT_HIT();
|
||||
}
|
||||
}
|
||||
|
||||
// timer counts in 21.3us increments (1024/48MHz), rounding applies
|
||||
// WARNING: timer can't measure more than 1.39s (21.3us * 0xffff)
|
||||
void SpinDelayUs(int us) {
|
||||
|
@ -131,7 +156,7 @@ void StartCountSspClk(void) {
|
|||
| AT91C_TC_WAVE // Waveform Mode
|
||||
| AT91C_TC_AEEVT_SET // Set TIOA1 on external event
|
||||
| AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare
|
||||
AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04
|
||||
AT91C_BASE_TC1->TC_RC = 0x01; // RC Compare value = 0x01, pulse width to TC0
|
||||
|
||||
// use TC0 to count TIOA1 pulses
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0
|
||||
|
@ -153,11 +178,25 @@ void StartCountSspClk(void) {
|
|||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC1
|
||||
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC2
|
||||
|
||||
//
|
||||
// synchronize the counter with the ssp_frame signal.
|
||||
// Note: FPGA must be in any iso14443 mode, otherwise the frame signal would not be present
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame)
|
||||
// Note: FPGA must be in a FPGA mode with SSC transfer, otherwise SSC_FRAME and SSC_CLK signals would not be present
|
||||
//
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame)
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 1st ssp_clk after start of frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 2nd ssp_clk after start of frame
|
||||
if ((AT91C_BASE_SSC->SSC_RFMR & SSC_FRAME_MODE_BITS_IN_WORD(32)) == SSC_FRAME_MODE_BITS_IN_WORD(16)) { // 16bit frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 3rd ssp_clk after start of frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 4th ssp_clk after start of frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 5th ssp_clk after start of frame
|
||||
while (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK); // wait for ssp_clk to go low;
|
||||
while (!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK)); // wait for ssp_clk to go high; 6th ssp_clk after start of frame
|
||||
}
|
||||
|
||||
// note: up to now two ssp_clk rising edges have passed since the rising edge of ssp_frame
|
||||
// it is now safe to assert a sync signal. This sets all timers to 0 on next active clock edge
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
void SpinDelay(int ms);
|
||||
void SpinDelayUs(int us);
|
||||
void SpinDelayUsPrecision(int us); // precision 0.6us , running for 43ms before
|
||||
|
||||
void StartTickCount(void);
|
||||
uint32_t RAMFUNC GetTickCount(void);
|
||||
|
|
|
@ -51,25 +51,32 @@ static size_t us_rxfifo_high = 0;
|
|||
static void usart_fill_rxfifo(void) {
|
||||
uint16_t rxfifo_free ;
|
||||
if (pUS1->US_RNCR == 0) { // One buffer got filled, backup buffer being used
|
||||
|
||||
if (us_rxfifo_low > us_rxfifo_high)
|
||||
rxfifo_free = us_rxfifo_low - us_rxfifo_high;
|
||||
else
|
||||
rxfifo_free = sizeof(us_rxfifo) - us_rxfifo_high + us_rxfifo_low;
|
||||
|
||||
uint16_t available = USART_BUFFLEN - usart_cur_inbuf_off;
|
||||
|
||||
if (available <= rxfifo_free) {
|
||||
|
||||
for (uint16_t i = 0; i < available; i++) {
|
||||
us_rxfifo[us_rxfifo_high++] = usart_cur_inbuf[usart_cur_inbuf_off + i];
|
||||
if (us_rxfifo_high == sizeof(us_rxfifo))
|
||||
us_rxfifo_high = 0;
|
||||
}
|
||||
|
||||
// Give next buffer
|
||||
pUS1->US_RNPR = (uint32_t)usart_cur_inbuf;
|
||||
pUS1->US_RNCR = USART_BUFFLEN;
|
||||
|
||||
// Swap current buff
|
||||
if (usart_cur_inbuf == us_inbuf1)
|
||||
usart_cur_inbuf = us_inbuf2;
|
||||
else
|
||||
usart_cur_inbuf = us_inbuf1;
|
||||
|
||||
usart_cur_inbuf_off = 0;
|
||||
} else {
|
||||
// Take only what we have room for
|
||||
|
@ -83,12 +90,16 @@ static void usart_fill_rxfifo(void) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (pUS1->US_RCR < USART_BUFFLEN - usart_cur_inbuf_off) { // Current buffer partially filled
|
||||
|
||||
if (us_rxfifo_low > us_rxfifo_high)
|
||||
rxfifo_free = us_rxfifo_low - us_rxfifo_high;
|
||||
else
|
||||
rxfifo_free = sizeof(us_rxfifo) - us_rxfifo_high + us_rxfifo_low;
|
||||
|
||||
uint16_t available = USART_BUFFLEN - pUS1->US_RCR - usart_cur_inbuf_off;
|
||||
|
||||
if (available > rxfifo_free)
|
||||
available = rxfifo_free;
|
||||
for (uint16_t i = 0; i < available; i++) {
|
||||
|
@ -150,7 +161,7 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
|||
}
|
||||
|
||||
// transfer from device to client
|
||||
inline int usart_writebuffer_sync(uint8_t *data, size_t len) {
|
||||
int usart_writebuffer_sync(uint8_t *data, size_t len) {
|
||||
|
||||
// Wait for current PDC bank to be free
|
||||
// (and check next bank too, in case there will be a usart_writebuffer_async)
|
||||
|
|
|
@ -4,9 +4,6 @@
|
|||
#include "common.h"
|
||||
#include "usart_defs.h"
|
||||
|
||||
#define USART_BUFFLEN 512
|
||||
#define USART_FIFOLEN (2*USART_BUFFLEN)
|
||||
|
||||
// Higher baudrates are pointless, only increasing overflow risk
|
||||
|
||||
extern uint32_t g_usart_baudrate;
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
#endif
|
||||
|
||||
#ifndef REV64
|
||||
#define REV64(x) (REV32(x) + (REV32((x) >> 32) << 32))
|
||||
#define REV64(x) (REV32(x) + ((uint64_t)(REV32((x) >> 32) << 32)))
|
||||
#endif
|
||||
|
||||
#ifndef BIT32
|
||||
|
|
|
@ -25,8 +25,8 @@ VERSIONSRC = version.c
|
|||
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
|
||||
APP_CFLAGS = -I. -ffunction-sections -fdata-sections
|
||||
|
||||
# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc
|
||||
APP_CFLAGS += -fno-stack-protector -fno-pie
|
||||
# stack-protect , no-pie reduces size on Gentoo Hardened 8.2 gcc, no-common makes sure uninitalized vars doesn't end up in COMMON area
|
||||
APP_CFLAGS += -fno-stack-protector -fno-pie -fno-common
|
||||
|
||||
|
||||
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
|
||||
|
|
|
@ -238,19 +238,23 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdhfmfhard.c
|
||||
${PM3_ROOT}/client/src/cmdhfmfp.c
|
||||
${PM3_ROOT}/client/src/cmdhfmfu.c
|
||||
${PM3_ROOT}/client/src/cmdhfst.c
|
||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||
${PM3_ROOT}/client/src/cmdhw.c
|
||||
${PM3_ROOT}/client/src/cmdlf.c
|
||||
${PM3_ROOT}/client/src/cmdlfawid.c
|
||||
${PM3_ROOT}/client/src/cmdlfcotag.c
|
||||
${PM3_ROOT}/client/src/cmdlfdestron.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
||||
${PM3_ROOT}/client/src/cmdlffdx.c
|
||||
${PM3_ROOT}/client/src/cmdlffdxb.c
|
||||
${PM3_ROOT}/client/src/cmdlfgallagher.c
|
||||
${PM3_ROOT}/client/src/cmdlfguard.c
|
||||
${PM3_ROOT}/client/src/cmdlfhid.c
|
||||
${PM3_ROOT}/client/src/cmdlfhitag.c
|
||||
${PM3_ROOT}/client/src/cmdlfidteck.c
|
||||
${PM3_ROOT}/client/src/cmdlfindala.c
|
||||
${PM3_ROOT}/client/src/cmdlfio.c
|
||||
${PM3_ROOT}/client/src/cmdlfjablotron.c
|
||||
|
@ -267,7 +271,6 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdlfsecurakey.c
|
||||
${PM3_ROOT}/client/src/cmdlft55xx.c
|
||||
${PM3_ROOT}/client/src/cmdlfti.c
|
||||
${PM3_ROOT}/client/src/cmdlfverichip.c
|
||||
${PM3_ROOT}/client/src/cmdlfviking.c
|
||||
${PM3_ROOT}/client/src/cmdlfvisa2000.c
|
||||
${PM3_ROOT}/client/src/cmdmain.c
|
||||
|
@ -311,7 +314,7 @@ set(X86_CPUS x86 x86_64 i686)
|
|||
message(STATUS "CMAKE_SYSTEM_PROCESSOR := ${CMAKE_SYSTEM_PROCESSOR}")
|
||||
|
||||
if (APPLE)
|
||||
message("Apple device detected.")
|
||||
message(STATUS "Apple device detected.")
|
||||
set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC})
|
||||
set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit")
|
||||
endif (APPLE)
|
||||
|
@ -377,79 +380,79 @@ if (WHEREAMI_FOUND)
|
|||
set(ADDITIONAL_LNK ${WHEREAMI_LIBRARIES} ${ADDITIONAL_LNK})
|
||||
endif (WHEREAMI_FOUND)
|
||||
|
||||
message("===================================================================")
|
||||
message(STATUS "===================================================================")
|
||||
if (SKIPQT EQUAL 1)
|
||||
message("GUI support: skipped")
|
||||
message(STATUS "GUI support: skipped")
|
||||
else (SKIPQT EQUAL 1)
|
||||
if (Qt5_FOUND)
|
||||
message("GUI support: QT5 found, enabled")
|
||||
message(STATUS "GUI support: QT5 found, enabled")
|
||||
else (Qt5_FOUND)
|
||||
message("GUI support: QT5 not found, disabled")
|
||||
message(STATUS "GUI support: QT5 not found, disabled")
|
||||
endif (Qt5_FOUND)
|
||||
endif (SKIPQT EQUAL 1)
|
||||
|
||||
if (SKIPBT EQUAL 1)
|
||||
message("native BT support: skipped")
|
||||
message(STATUS "native BT support: skipped")
|
||||
else (SKIPBT EQUAL 1)
|
||||
if (BLUEZ_FOUND)
|
||||
message("native BT support: Bluez found, enabled")
|
||||
message(STATUS "native BT support: Bluez found, enabled")
|
||||
else (BLUEZ_FOUND)
|
||||
message("native BT support: Bluez not found, disabled")
|
||||
message(STATUS "native BT support: Bluez not found, disabled")
|
||||
endif (BLUEZ_FOUND)
|
||||
endif(SKIPBT EQUAL 1)
|
||||
|
||||
if (EMBED_BZIP2)
|
||||
message("Bzip2 library: embedded")
|
||||
message(STATUS "Bzip2 library: embedded")
|
||||
else (EMBED_BZIP2)
|
||||
message("Bzip2 library: system library found")
|
||||
message(STATUS "Bzip2 library: system library found")
|
||||
endif (EMBED_BZIP2)
|
||||
|
||||
if (SKIPJANSSONSYSTEM EQUAL 1)
|
||||
message("Jansson library: local library forced")
|
||||
message(STATUS "Jansson library: local library forced")
|
||||
else (SKIPJANSSONSYSTEM EQUAL 1)
|
||||
if (JANSSON_FOUND)
|
||||
message("Jansson library: system library found")
|
||||
message(STATUS "Jansson library: system library found")
|
||||
else (JANSSON_FOUND)
|
||||
message("Jansson library: system library not found, using local library")
|
||||
message(STATUS "Jansson library: system library not found, using local library")
|
||||
endif (JANSSON_FOUND)
|
||||
endif (SKIPJANSSONSYSTEM EQUAL 1)
|
||||
|
||||
if (SKIPPYTHON EQUAL 1)
|
||||
message("Python3 library: skipped")
|
||||
message(STATUS "Python3 library: skipped")
|
||||
else (SKIPPYTHON EQUAL 1)
|
||||
if (PYTHON3EMBED_FOUND)
|
||||
message("Python3 library: Python3 embed found, enabled")
|
||||
message(STATUS "Python3 library: Python3 embed found, enabled")
|
||||
elseif (PYTHON_FOUND)
|
||||
message("Python3 library: Python3 found, enabled")
|
||||
message(STATUS "Python3 library: Python3 found, enabled")
|
||||
else (PYTHON3EMBED_FOUND)
|
||||
message("Python3 library: Python3 not found, disabled")
|
||||
message(STATUS "Python3 library: Python3 not found, disabled")
|
||||
endif (PYTHON3EMBED_FOUND)
|
||||
endif(SKIPPYTHON EQUAL 1)
|
||||
|
||||
if (SKIPREADLINE EQUAL 1)
|
||||
message("Readline library: skipped")
|
||||
message(STATUS "Readline library: skipped")
|
||||
else (SKIPREADLINE EQUAL 1)
|
||||
if (READLINE_FOUND)
|
||||
if (EMBED_READLINE)
|
||||
message("Readline library: embedded")
|
||||
message(STATUS "Readline library: embedded")
|
||||
else (EMBED_READLINE)
|
||||
message("Readline library: system library found")
|
||||
message(STATUS "Readline library: system library found")
|
||||
endif (EMBED_READLINE)
|
||||
else (READLINE_FOUND)
|
||||
message("Readline library: Readline not found, disabled")
|
||||
message(STATUS "Readline library: Readline not found, disabled")
|
||||
endif (READLINE_FOUND)
|
||||
endif(SKIPREADLINE EQUAL 1)
|
||||
|
||||
if (SKIPWHEREAMISYSTEM EQUAL 1)
|
||||
message("Whereami library: local library forced")
|
||||
message(STATUS "Whereami library: local library forced")
|
||||
else (SKIPWHEREAMISYSTEM EQUAL 1)
|
||||
if (WHEREAMI_FOUND)
|
||||
message("Whereami library: system library found")
|
||||
message(STATUS "Whereami library: system library found")
|
||||
else (WHEREAMI_FOUND)
|
||||
message("Whereami library: system library not found, using local library")
|
||||
message(STATUS "Whereami library: system library not found, using local library")
|
||||
endif (WHEREAMI_FOUND)
|
||||
endif (SKIPWHEREAMISYSTEM EQUAL 1)
|
||||
message("===================================================================")
|
||||
message(STATUS "===================================================================")
|
||||
|
||||
add_executable(proxmark3
|
||||
${PM3_ROOT}/client/src/proxmark3.c
|
||||
|
|
|
@ -309,6 +309,7 @@ ifeq ($(QT_FOUND),1)
|
|||
endif
|
||||
endif
|
||||
|
||||
LDFLAGS ?= $(DEFLDFLAGS)
|
||||
PM3LDFLAGS = $(LDFLAGS)
|
||||
ifeq ($(platform),Darwin)
|
||||
PM3LDFLAGS += -framework Foundation -framework AppKit
|
||||
|
@ -326,9 +327,9 @@ ifeq ($(SKIPQT),1)
|
|||
else
|
||||
ifeq ($(QT_FOUND),1)
|
||||
ifeq ($(QT5_FOUND),1)
|
||||
$(info GUI support: QT5 found, enabled)
|
||||
$(info GUI support: QT5 found, enabled ($(shell QT_SELECT=5 qmake -v 2>/dev/null|grep -o 'Qt version.*')))
|
||||
else
|
||||
$(info GUI support: QT4 found, enabled)
|
||||
$(info GUI support: QT4 found, enabled ($(shell QT_SELECT=4 qmake -v 2>/dev/null|grep -o 'Qt version.*')))
|
||||
endif
|
||||
else
|
||||
$(info GUI support: QT not found, disabled)
|
||||
|
@ -432,19 +433,23 @@ SRCS = aidsearch.c \
|
|||
cmdhfmfhard.c \
|
||||
cmdhfmfu.c \
|
||||
cmdhfmfp.c \
|
||||
cmdhfst.c \
|
||||
cmdhfthinfilm.c \
|
||||
cmdhftopaz.c \
|
||||
cmdhfwaveshare.c \
|
||||
cmdhw.c \
|
||||
cmdlf.c \
|
||||
cmdlfawid.c \
|
||||
cmdlfcotag.c \
|
||||
cmdlfdestron.c \
|
||||
cmdlfem4x.c \
|
||||
cmdlfem4x50.c \
|
||||
cmdlffdx.c \
|
||||
cmdlffdxb.c \
|
||||
cmdlfguard.c \
|
||||
cmdlfgallagher.c \
|
||||
cmdlfhid.c \
|
||||
cmdlfhitag.c \
|
||||
cmdlfidteck.c \
|
||||
cmdlfindala.c \
|
||||
cmdlfio.c \
|
||||
cmdlfjablotron.c \
|
||||
|
|
|
@ -117,19 +117,23 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/cmdhfmfhard.c
|
||||
${PM3_ROOT}/client/src/cmdhfmfp.c
|
||||
${PM3_ROOT}/client/src/cmdhfmfu.c
|
||||
${PM3_ROOT}/client/src/cmdhfst.c
|
||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||
${PM3_ROOT}/client/src/cmdhw.c
|
||||
${PM3_ROOT}/client/src/cmdlf.c
|
||||
${PM3_ROOT}/client/src/cmdlfawid.c
|
||||
${PM3_ROOT}/client/src/cmdlfcotag.c
|
||||
${PM3_ROOT}/client/src/cmdlfdestron.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
||||
${PM3_ROOT}/client/src/cmdlffdx.c
|
||||
${PM3_ROOT}/client/src/cmdlffdxb.c
|
||||
${PM3_ROOT}/client/src/cmdlfgallagher.c
|
||||
${PM3_ROOT}/client/src/cmdlfguard.c
|
||||
${PM3_ROOT}/client/src/cmdlfhid.c
|
||||
${PM3_ROOT}/client/src/cmdlfhitag.c
|
||||
${PM3_ROOT}/client/src/cmdlfidteck.c
|
||||
${PM3_ROOT}/client/src/cmdlfindala.c
|
||||
${PM3_ROOT}/client/src/cmdlfio.c
|
||||
${PM3_ROOT}/client/src/cmdlfjablotron.c
|
||||
|
|
|
@ -86,7 +86,7 @@ jint Console(JNIEnv *env, jobject instance, jstring cmd_) {
|
|||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
char *cmd = (char *) ((*env)->GetStringUTFChars(env, cmd_, 0));
|
||||
char *cmd = (char *)((*env)->GetStringUTFChars(env, cmd_, 0));
|
||||
int ret = CommandReceived(cmd);
|
||||
if (ret == 99) {
|
||||
// exit / quit
|
||||
|
@ -102,7 +102,7 @@ jint Console(JNIEnv *env, jobject instance, jstring cmd_) {
|
|||
* Is client running!
|
||||
* */
|
||||
jboolean IsClientRunning(JNIEnv *env, jobject instance) {
|
||||
return (jboolean) ((jboolean) conn.run);
|
||||
return (jboolean)((jboolean) conn.run);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -114,7 +114,7 @@ jboolean TestPm3(JNIEnv *env, jobject instance) {
|
|||
return false;
|
||||
}
|
||||
bool ret = (TestProxmark() == PM3_SUCCESS);
|
||||
return (jboolean) (ret);
|
||||
return (jboolean)(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env -S pm3 -s
|
||||
|
||||
mem load f mfc_default_keys m
|
||||
mem load f t55xx_default_pwds t
|
||||
mem load f iclass_default_keys i
|
||||
mem load -f mfc_default_keys --mfc
|
||||
mem load -f t55xx_default_pwds --t55xx
|
||||
mem load -f iclass_default_keys --iclass
|
||||
lf t55xx deviceconfig z p
|
||||
|
|
28
client/cmdscripts/test_psk_clone.cmd
Normal file
28
client/cmdscripts/test_psk_clone.cmd
Normal file
|
@ -0,0 +1,28 @@
|
|||
clear
|
||||
|
||||
rem Test of Motorola clone & read
|
||||
lf t55xx wipe
|
||||
lf motorola clone a0000000a0002021
|
||||
lf motorola read
|
||||
lf search
|
||||
|
||||
rem Test of Nexwatch clone & read
|
||||
lf t55xx wipe
|
||||
lf nexwatch clone c 1337 m 1 n
|
||||
lf nexwatch read
|
||||
lf search
|
||||
|
||||
rem Test of keri clone & read
|
||||
lf t55xx wipe
|
||||
lf keri clone --id 1337
|
||||
lf keri read
|
||||
lf search
|
||||
|
||||
rem Test of Indala clone & read
|
||||
lf t55xx wipe
|
||||
lf indala clone --fc 7 --cn 1337
|
||||
lf indala read
|
||||
lf search
|
||||
|
||||
rem done, just wiping your tag.
|
||||
lf t55xx wipe
|
|
@ -1927,10 +1927,8 @@ struct arg_file *arg_filen(
|
|||
#include <stdlib.h>
|
||||
#include <limits.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "argtable3.h"
|
||||
|
||||
|
||||
static void arg_int_resetfn(struct arg_int *parent) {
|
||||
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
|
||||
parent->count = 0;
|
||||
|
@ -2226,6 +2224,263 @@ struct arg_int *arg_intn(
|
|||
ARG_TRACE(("arg_intn() returns %p\n", result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// uint64_t support
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
static uint64_t strtollu0X(const char *str,
|
||||
const char * *endptr,
|
||||
char X,
|
||||
int base) {
|
||||
uint64_t val; /* stores result */
|
||||
int s = 1; /* sign is +1 or -1 */
|
||||
const char *ptr = str; /* ptr to current position in str */
|
||||
|
||||
/* skip leading whitespace */
|
||||
while (ISSPACE(*ptr))
|
||||
ptr++;
|
||||
// printf("1) %s\n",ptr);
|
||||
|
||||
/* scan optional sign character */
|
||||
switch (*ptr) {
|
||||
case '+':
|
||||
ptr++;
|
||||
s = 1;
|
||||
break;
|
||||
case '-':
|
||||
ptr++;
|
||||
s = -1;
|
||||
break;
|
||||
default:
|
||||
s = 1;
|
||||
break;
|
||||
}
|
||||
// printf("2) %s\n",ptr);
|
||||
|
||||
/* '0X' prefix */
|
||||
if ((*ptr++) != '0') {
|
||||
/* printf("failed to detect '0'\n"); */
|
||||
*endptr = str;
|
||||
return 0;
|
||||
}
|
||||
// printf("3) %s\n",ptr);
|
||||
if (toupper(*ptr++) != toupper(X)) {
|
||||
/* printf("failed to detect '%c'\n",X); */
|
||||
*endptr = str;
|
||||
return 0;
|
||||
}
|
||||
// printf("4) %s\n",ptr);
|
||||
|
||||
/* attempt conversion on remainder of string using strtol() */
|
||||
val = strtoull(ptr, (char * *)endptr, base);
|
||||
|
||||
if (*endptr == ptr) {
|
||||
/* conversion failed */
|
||||
*endptr = str;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* success */
|
||||
return s * val;
|
||||
}
|
||||
|
||||
|
||||
static void arg_u64_resetfn(struct arg_u64 *parent) {
|
||||
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
|
||||
parent->count = 0;
|
||||
}
|
||||
|
||||
static int arg_u64_scanfn(struct arg_u64 *parent, const char *argval) {
|
||||
int errorcode = 0;
|
||||
if (parent->count == parent->hdr.maxcount) {
|
||||
/* maximum number of arguments exceeded */
|
||||
errorcode = EMAXCOUNT;
|
||||
} else if (!argval) {
|
||||
/* a valid argument with no argument value was given. */
|
||||
/* This happens when an optional argument value was invoked. */
|
||||
/* leave parent arguiment value unaltered but still count the argument. */
|
||||
parent->count++;
|
||||
} else {
|
||||
uint64_t val;
|
||||
const char *end;
|
||||
|
||||
/* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
|
||||
val = strtollu0X(argval, &end, 'X', 16);
|
||||
if (end == argval) {
|
||||
/* hex failed, attempt octal conversion (eg +0o123) */
|
||||
val = strtollu0X(argval, &end, 'O', 8);
|
||||
if (end == argval) {
|
||||
/* octal failed, attempt binary conversion (eg +0B101) */
|
||||
val = strtollu0X(argval, &end, 'B', 2);
|
||||
if (end == argval) {
|
||||
/* binary failed, attempt decimal conversion with no prefix (eg 1234) */
|
||||
val = strtoull(argval, (char * *)&end, 10);
|
||||
if (end == argval) {
|
||||
/* all supported number formats failed */
|
||||
return EBADINT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Safety check for integer overflow. WARNING: this check */
|
||||
/* achieves nothing on machines where size(int)==size(long). */
|
||||
if (val > ULLONG_MAX)
|
||||
#ifdef __STDC_WANT_SECURE_LIB__
|
||||
errorcode = EOVERFLOW_;
|
||||
#else
|
||||
errorcode = EOVERFLOW;
|
||||
#endif
|
||||
|
||||
/* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
|
||||
/* We need to be mindful of integer overflows when using such big numbers. */
|
||||
if (detectsuffix(end, "KB")) { /* kilobytes */
|
||||
if (val > (ULLONG_MAX / 1024))
|
||||
#ifdef __STDC_WANT_SECURE_LIB__
|
||||
errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
|
||||
#else
|
||||
errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
|
||||
#endif
|
||||
else
|
||||
val *= 1024; /* 1KB = 1024 */
|
||||
} else if (detectsuffix(end, "MB")) { /* megabytes */
|
||||
if (val > (ULLONG_MAX / 1048576))
|
||||
#ifdef __STDC_WANT_SECURE_LIB__
|
||||
errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
|
||||
#else
|
||||
errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
|
||||
#endif
|
||||
else
|
||||
val *= 1048576; /* 1MB = 1024*1024 */
|
||||
} else if (detectsuffix(end, "GB")) { /* gigabytes */
|
||||
if (val > (ULLONG_MAX / 1073741824))
|
||||
#ifdef __STDC_WANT_SECURE_LIB__
|
||||
errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
|
||||
#else
|
||||
errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
|
||||
#endif
|
||||
else
|
||||
val *= 1073741824; /* 1GB = 1024*1024*1024 */
|
||||
} else if (!detectsuffix(end, ""))
|
||||
errorcode = EBADINT; /* invalid suffix detected */
|
||||
|
||||
/* if success then store result in parent->uval[] array */
|
||||
if (errorcode == 0)
|
||||
parent->uval[parent->count++] = val;
|
||||
}
|
||||
|
||||
/* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
|
||||
return errorcode;
|
||||
}
|
||||
|
||||
static int arg_u64_checkfn(struct arg_u64 *parent) {
|
||||
int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
|
||||
/*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
|
||||
return errorcode;
|
||||
}
|
||||
|
||||
static void arg_u64_errorfn(
|
||||
struct arg_u64 *parent,
|
||||
FILE *fp,
|
||||
int errorcode,
|
||||
const char *argval,
|
||||
const char *progname) {
|
||||
const char *shortopts = parent->hdr.shortopts;
|
||||
const char *longopts = parent->hdr.longopts;
|
||||
const char *datatype = parent->hdr.datatype;
|
||||
|
||||
/* make argval NULL safe */
|
||||
argval = argval ? argval : "";
|
||||
|
||||
fprintf(fp, "%s: ", progname);
|
||||
switch (errorcode) {
|
||||
case EMINCOUNT:
|
||||
fputs("missing option ", fp);
|
||||
arg_print_option(fp, shortopts, longopts, datatype, "\n");
|
||||
break;
|
||||
|
||||
case EMAXCOUNT:
|
||||
fputs("excess option ", fp);
|
||||
arg_print_option(fp, shortopts, longopts, argval, "\n");
|
||||
break;
|
||||
|
||||
case EBADINT:
|
||||
fprintf(fp, "invalid argument \"%s\" to option ", argval);
|
||||
arg_print_option(fp, shortopts, longopts, datatype, "\n");
|
||||
break;
|
||||
|
||||
#ifdef __STDC_WANT_SECURE_LIB__
|
||||
case EOVERFLOW_:
|
||||
#else
|
||||
case EOVERFLOW:
|
||||
#endif
|
||||
fputs("integer overflow at option ", fp);
|
||||
arg_print_option(fp, shortopts, longopts, datatype, " ");
|
||||
fprintf(fp, "(%s is too large)\n", argval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct arg_u64 *arg_u64_0(
|
||||
const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
const char *glossary) {
|
||||
return arg_u64_n(shortopts, longopts, datatype, 0, 1, glossary);
|
||||
}
|
||||
|
||||
struct arg_u64 *arg_u64_1(
|
||||
const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
const char *glossary) {
|
||||
return arg_u64_n(shortopts, longopts, datatype, 1, 1, glossary);
|
||||
}
|
||||
|
||||
struct arg_u64 *arg_u64_n(
|
||||
const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
int mincount,
|
||||
int maxcount,
|
||||
const char *glossary) {
|
||||
size_t nbytes;
|
||||
struct arg_u64 *result;
|
||||
|
||||
/* foolproof things by ensuring maxcount is not less than mincount */
|
||||
maxcount = (maxcount < mincount) ? mincount : maxcount;
|
||||
|
||||
nbytes = sizeof(struct arg_u64) /* storage for struct arg_u64 */
|
||||
+ maxcount * sizeof(uint64_t); /* storage for uval[maxcount] array */
|
||||
|
||||
result = (struct arg_u64 *)malloc(nbytes);
|
||||
if (result) {
|
||||
/* init the arg_hdr struct */
|
||||
result->hdr.flag = ARG_HASVALUE;
|
||||
result->hdr.shortopts = shortopts;
|
||||
result->hdr.longopts = longopts;
|
||||
result->hdr.datatype = datatype ? datatype : "<u64>";
|
||||
result->hdr.glossary = glossary;
|
||||
result->hdr.mincount = mincount;
|
||||
result->hdr.maxcount = maxcount;
|
||||
result->hdr.parent = result;
|
||||
result->hdr.resetfn = (arg_resetfn *)arg_u64_resetfn;
|
||||
result->hdr.scanfn = (arg_scanfn *)arg_u64_scanfn;
|
||||
result->hdr.checkfn = (arg_checkfn *)arg_u64_checkfn;
|
||||
result->hdr.errorfn = (arg_errorfn *)arg_u64_errorfn;
|
||||
|
||||
/* store the uval[maxcount] array immediately after the arg_int struct */
|
||||
result->uval = (uint64_t *)(result + 1);
|
||||
result->count = 0;
|
||||
}
|
||||
|
||||
ARG_TRACE(("arg_u64_n() returns %p\n", result));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* This file is part of the argtable3 library.
|
||||
*
|
||||
|
@ -4020,7 +4275,10 @@ static void arg_parse_untagged(int argc,
|
|||
/* register an error for each unused argv[] entry */
|
||||
while (optind < argc) {
|
||||
/*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/
|
||||
arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]);
|
||||
if (argv[optind][0] != '\x00') {
|
||||
arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind]);
|
||||
}
|
||||
optind++;
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -4195,7 +4453,8 @@ static void arg_cat_option(char *dest,
|
|||
#endif
|
||||
|
||||
if (datatype) {
|
||||
arg_cat(&dest, "=", &ndest);
|
||||
// arg_cat(&dest, "=", &ndest);
|
||||
arg_cat(&dest, " ", &ndest);
|
||||
if (optvalue) {
|
||||
arg_cat(&dest, "[", &ndest);
|
||||
arg_cat(&dest, datatype, &ndest);
|
||||
|
@ -4270,10 +4529,15 @@ static void arg_cat_optionv(char *dest,
|
|||
}
|
||||
|
||||
if (datatype) {
|
||||
if (longopts)
|
||||
/* if (longopts)
|
||||
arg_cat(&dest, "=", &ndest);
|
||||
else if (shortopts)
|
||||
arg_cat(&dest, " ", &ndest);
|
||||
*/
|
||||
if (longopts)
|
||||
arg_cat(&dest, " ", &ndest);
|
||||
else if (shortopts)
|
||||
arg_cat(&dest, " ", &ndest);
|
||||
|
||||
if (optvalue) {
|
||||
arg_cat(&dest, "[", &ndest);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include <stdio.h> /* FILE */
|
||||
#include <time.h> /* struct tm */
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
@ -110,6 +111,12 @@ struct arg_int {
|
|||
int *ival; /* Array of parsed argument values */
|
||||
};
|
||||
|
||||
struct arg_u64 {
|
||||
struct arg_hdr hdr; /* The mandatory argtable header struct */
|
||||
int count; /* Number of matching command line args */
|
||||
uint64_t *uval; /* Array of parsed argument values */
|
||||
};
|
||||
|
||||
struct arg_dbl {
|
||||
struct arg_hdr hdr; /* The mandatory argtable header struct */
|
||||
int count; /* Number of matching command line args */
|
||||
|
@ -176,32 +183,29 @@ struct arg_lit *arg_litn(const char *shortopts,
|
|||
int maxcount,
|
||||
const char *glossary);
|
||||
|
||||
struct arg_key *arg_key0(const char *keyword,
|
||||
int flags,
|
||||
struct arg_key *arg_key0(const char *keyword, int flags, const char *glossary);
|
||||
struct arg_key *arg_key1(const char *keyword, int flags, const char *glossary);
|
||||
struct arg_key *arg_keyn(const char *keyword, int flags, int mincount, int maxcount, const char *glossary);
|
||||
|
||||
struct arg_int *arg_int0(const char *shortopts, const char *longopts, const char *datatype, const char *glossary);
|
||||
struct arg_int *arg_int1(const char *shortopts, const char *longopts, const char *datatype, const char *glossary);
|
||||
struct arg_int *arg_intn(const char *shortopts, const char *longopts, const char *datatype, int mincount, int maxcount, const char *glossary);
|
||||
|
||||
struct arg_u64 *arg_u64_0(const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
const char *glossary);
|
||||
struct arg_key *arg_key1(const char *keyword,
|
||||
int flags,
|
||||
struct arg_u64 *arg_u64_1(const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
const char *glossary);
|
||||
struct arg_key *arg_keyn(const char *keyword,
|
||||
int flags,
|
||||
struct arg_u64 *arg_u64_n(const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
int mincount,
|
||||
int maxcount,
|
||||
const char *glossary);
|
||||
|
||||
struct arg_int *arg_int0(const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
const char *glossary);
|
||||
struct arg_int *arg_int1(const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
const char *glossary);
|
||||
struct arg_int *arg_intn(const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
int mincount,
|
||||
int maxcount,
|
||||
const char *glossary);
|
||||
|
||||
struct arg_dbl *arg_dbl0(const char *shortopts,
|
||||
const char *longopts,
|
||||
|
|
|
@ -11,10 +11,25 @@
|
|||
#include "cliparser.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <util.h> // Get color constants
|
||||
#include <ui.h> // get PrintAndLogEx
|
||||
|
||||
#ifndef ARRAYLEN
|
||||
# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
|
||||
#endif
|
||||
|
||||
// Custom Colors
|
||||
// To default the color return s
|
||||
#define _SectionTagColor_(s) _GREEN_(s)
|
||||
#define _ExampleColor_(s) _YELLOW_(s)
|
||||
#define _CommandColor_(s) _RED_(s)
|
||||
#define _DescriptionColor_(s) _CYAN_(s)
|
||||
#define _ArgColor_(s) s
|
||||
#define _ArgHelpColor_(s) s
|
||||
// End Custom Colors
|
||||
// Option width set to 30 to allow option descriptions to align. approx line 74
|
||||
// Example width set to 50 to allow help descriptions to align. approx line 93
|
||||
|
||||
int CLIParserInit(CLIParserContext **ctx, const char *vprogramName, const char *vprogramHint, const char *vprogramHelp) {
|
||||
*ctx = malloc(sizeof(CLIParserContext));
|
||||
if (!*ctx) {
|
||||
|
@ -40,7 +55,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
|||
/* verify the argtable[] entries were allocated sucessfully */
|
||||
if (arg_nullcheck(ctx->argtable) != 0) {
|
||||
/* NULL entries were detected, some allocations must have failed */
|
||||
printf("ERROR: Insufficient memory\n");
|
||||
PrintAndLogEx(ERR, "ERROR: Insufficient memory\n");
|
||||
fflush(stdout);
|
||||
return 2;
|
||||
}
|
||||
|
@ -49,14 +64,50 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
|||
|
||||
/* special case: '--help' takes precedence over error reporting */
|
||||
if ((argc < 2 && !allowEmptyExec) || ((struct arg_lit *)(ctx->argtable)[0])->count > 0) { // help must be the first record
|
||||
printf("Usage: %s", ctx->programName);
|
||||
arg_print_syntaxv(stdout, ctx->argtable, "\n");
|
||||
if (ctx->programHint)
|
||||
printf("%s\n\n", ctx->programHint);
|
||||
arg_print_glossary(stdout, ctx->argtable, " %-20s %s\n");
|
||||
printf("\n");
|
||||
if (ctx->programHelp)
|
||||
printf("%s \n", ctx->programHelp);
|
||||
PrintAndLogEx(NORMAL, "\n"_DescriptionColor_("%s"), ctx->programHint);
|
||||
|
||||
PrintAndLogEx(NORMAL, "\n"_SectionTagColor_("usage:"));
|
||||
PrintAndLogEx(NORMAL, " "_CommandColor_("%s")NOLF, ctx->programName);
|
||||
arg_print_syntax(stdout, ctx->argtable, "\n\n");
|
||||
|
||||
PrintAndLogEx(NORMAL, _SectionTagColor_("options:"));
|
||||
|
||||
arg_print_glossary(stdout, ctx->argtable, " "_ArgColor_("%-30s")" "_ArgHelpColor_("%s")"\n");
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
if (ctx->programHelp) {
|
||||
PrintAndLogEx(NORMAL, _SectionTagColor_("examples/notes:"));
|
||||
char *buf = NULL;
|
||||
int idx = 0;
|
||||
buf = realloc(buf, strlen(ctx->programHelp) + 1); // more then enough as we are splitting
|
||||
|
||||
char *p2; // pointer to split example from comment.
|
||||
int egWidth = 30;
|
||||
for (int i = 0; i <= strlen(ctx->programHelp); i++) { // <= so to get string terminator.
|
||||
buf[idx++] = ctx->programHelp[i];
|
||||
if ((ctx->programHelp[i] == '\n') || (ctx->programHelp[i] == 0x00)) {
|
||||
buf[idx - 1] = 0x00;
|
||||
p2 = strstr(buf, "->"); // See if the example has a comment.
|
||||
if (p2 != NULL) {
|
||||
*(p2 - 1) = 0x00;
|
||||
|
||||
if (strlen(buf) > 28)
|
||||
egWidth = strlen(buf) + 5;
|
||||
else
|
||||
egWidth = 30;
|
||||
|
||||
PrintAndLogEx(NORMAL, " "_ExampleColor_("%-*s")" %s", egWidth, buf, p2);
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " "_ExampleColor_("%-*s"), egWidth, buf);
|
||||
}
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
free(buf);
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
return 1;
|
||||
|
@ -66,7 +117,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
|||
if (nerrors > 0) {
|
||||
/* Display the error details contained in the arg_end struct.*/
|
||||
arg_print_errors(stdout, ((struct arg_end *)(ctx->argtable)[vargtableLen - 1]), ctx->programName);
|
||||
printf("Try '%s --help' for more information.\n", ctx->programName);
|
||||
PrintAndLogEx(WARNING, "Try '%s --help' for more information.\n", ctx->programName);
|
||||
fflush(stdout);
|
||||
return 3;
|
||||
}
|
||||
|
@ -74,6 +125,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
enum ParserState {
|
||||
PS_FIRST,
|
||||
PS_ARGUMENT,
|
||||
|
@ -152,7 +204,7 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
|||
*datalen = 0;
|
||||
|
||||
int ibuf = 0;
|
||||
uint8_t tmp_buf[256] = {0};
|
||||
uint8_t tmp_buf[512] = {0};
|
||||
int res = CLIParamStrToBuf(argstr, tmp_buf, maxdatalen * 2, &ibuf); // *2 because here HEX
|
||||
if (res) {
|
||||
printf("Parameter error: buffer overflow.\n");
|
||||
|
@ -186,7 +238,7 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
|||
if (!argstr->count)
|
||||
return 0;
|
||||
|
||||
uint8_t tmp_buf[256] = {0};
|
||||
uint8_t tmp_buf[512] = {0};
|
||||
int ibuf = 0;
|
||||
|
||||
for (int i = 0; i < argstr->count; i++) {
|
||||
|
@ -199,12 +251,13 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
|||
if (!ibuf)
|
||||
return 0;
|
||||
|
||||
if (ibuf > maxdatalen) {
|
||||
if (ibuf + 1 > maxdatalen) {
|
||||
printf("Parameter error: string too long, expect max %i chars\n", maxdatalen - 1);
|
||||
fflush(stdout);
|
||||
return 2;
|
||||
}
|
||||
|
||||
memcpy(data, tmp_buf, ibuf);
|
||||
memcpy(data, tmp_buf, ibuf + 1);
|
||||
*datalen = ibuf;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -14,25 +14,42 @@
|
|||
#include <stdlib.h>
|
||||
#include "util.h"
|
||||
|
||||
#define arg_param_begin arg_lit0("hH", "help", "This help")
|
||||
#define arg_param_begin arg_lit0("h", "help", "This help")
|
||||
#define arg_param_end arg_end(20)
|
||||
|
||||
#define arg_getsize(a) (sizeof(a) / sizeof(a[0]))
|
||||
#define arg_get_lit(ctx, n) (((struct arg_lit*)((ctx)->argtable)[n])->count)
|
||||
#define arg_get_int_count(ctx, n)(((struct arg_int*)((ctx)->argtable)[n])->count)
|
||||
#define arg_get_int(ctx, n) (((struct arg_int*)((ctx)->argtable)[n])->ival[0])
|
||||
#define arg_get_int_def(ctx, n, def)(arg_get_int_count((ctx), n) ? (arg_get_int((ctx), n)) : (def))
|
||||
#define arg_get_str(ctx, n) ((struct arg_str*)((ctx)->argtable)[n])
|
||||
#define arg_get_str_len(ctx, n) (strlen(((struct arg_str*)((ctx)->argtable)[n])->sval[0]))
|
||||
#define arg_get_lit(ctx, n) (((struct arg_lit*)((ctx)->argtable)[(n)])->count)
|
||||
|
||||
#define arg_get_int_count(ctx, n) (((struct arg_int*)((ctx)->argtable)[(n)])->count)
|
||||
#define arg_get_int(ctx, n) (((struct arg_int*)((ctx)->argtable)[(n)])->ival[0])
|
||||
#define arg_get_int_def(ctx, n, def)(arg_get_int_count((ctx), (n)) ? (arg_get_int((ctx), (n))) : (def))
|
||||
|
||||
#define arg_get_dbl_count(ctx, n) (((struct arg_dbl*)((ctx)->argtable)[(n)])->count)
|
||||
#define arg_get_dbl(ctx, n) (((struct arg_dbl*)((ctx)->argtable)[(n)])->dval[0])
|
||||
#define arg_get_dbl_def(ctx, n, def)(arg_get_dbl_count((ctx), (n)) ? (arg_get_dbl((ctx), (n))) : (def))
|
||||
|
||||
#define arg_get_u32(ctx, n) (uint32_t)(((struct arg_u64*)((ctx)->argtable)[(n)])->uval[0])
|
||||
#define arg_get_u32_def(ctx, n, def) (arg_get_u64_count((ctx), (n)) ? (arg_get_u32((ctx), (n))) : (uint32_t)(def))
|
||||
|
||||
#define arg_get_u64_count(ctx, n) (((struct arg_u64*)((ctx)->argtable)[(n)])->count)
|
||||
#define arg_get_u64(ctx, n) (((struct arg_u64*)((ctx)->argtable)[(n)])->uval[0])
|
||||
#define arg_get_u64_def(ctx, n, def) (arg_get_u64_count((ctx), (n)) ? (arg_get_u64((ctx), (n))) : (uint64_t)(def))
|
||||
|
||||
#define arg_get_str(ctx, n) ((struct arg_str*)((ctx)->argtable)[(n)])
|
||||
#define arg_get_str_len(ctx, n) (strlen(((struct arg_str*)((ctx)->argtable)[(n)])->sval[0]))
|
||||
|
||||
#define arg_strx1(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 1, 250, (glossary)))
|
||||
#define arg_strx0(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 0, 250, (glossary)))
|
||||
|
||||
#define CLIParserFree(ctx) if ((ctx)) {arg_freetable(ctx->argtable, ctx->argtableLen); free((ctx)); (ctx)=NULL;}
|
||||
#define CLIExecWithReturn(ctx, cmd, atbl, ifempty) if (CLIParserParseString(ctx, cmd, atbl, arg_getsize(atbl), ifempty)) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||
#define CLIGetHexBLessWithReturn(ctx, paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||
#define CLIGetHexWithReturn(ctx, paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), datalen)) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||
#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), datalen)) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||
#define CLIParserFree(ctx) if ((ctx)) {arg_freetable((ctx)->argtable, (ctx)->argtableLen); free((ctx)); (ctx)=NULL;}
|
||||
|
||||
#define CLIExecWithReturn(ctx, cmd, atbl, ifempty) if (CLIParserParseString((ctx), (cmd), (atbl), arg_getsize((atbl)), (ifempty))) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||
|
||||
#define CLIGetHexBLessWithReturn(ctx, paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)) - (delta), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||
|
||||
#define CLIGetHexWithReturn(ctx, paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||
|
||||
#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;}
|
||||
|
||||
typedef struct {
|
||||
void **argtable;
|
||||
|
|
|
@ -7,7 +7,8 @@ set_property(TARGET pm3rrg_rdv4_hardnested_nosimd PROPERTY POSITION_INDEPENDENT_
|
|||
|
||||
target_include_directories(pm3rrg_rdv4_hardnested_nosimd PRIVATE
|
||||
../../common
|
||||
../../include)
|
||||
../../include
|
||||
../src)
|
||||
|
||||
## CPU-specific code
|
||||
## These are mostly for x86-based architectures, which is not useful for many Android devices.
|
||||
|
@ -34,7 +35,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS)
|
|||
|
||||
target_include_directories(pm3rrg_rdv4_hardnested_mmx PRIVATE
|
||||
../../common
|
||||
../../include)
|
||||
../../include
|
||||
../src)
|
||||
|
||||
## x86 / SSE2
|
||||
add_library(pm3rrg_rdv4_hardnested_sse2 OBJECT
|
||||
|
@ -48,7 +50,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS)
|
|||
|
||||
target_include_directories(pm3rrg_rdv4_hardnested_sse2 PRIVATE
|
||||
../../common
|
||||
../../include)
|
||||
../../include
|
||||
../src)
|
||||
|
||||
## x86 / AVX
|
||||
add_library(pm3rrg_rdv4_hardnested_avx OBJECT
|
||||
|
@ -62,7 +65,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS)
|
|||
|
||||
target_include_directories(pm3rrg_rdv4_hardnested_avx PRIVATE
|
||||
../../common
|
||||
../../include)
|
||||
../../include
|
||||
../src)
|
||||
|
||||
## x86 / AVX2
|
||||
add_library(pm3rrg_rdv4_hardnested_avx2 OBJECT
|
||||
|
@ -76,7 +80,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS)
|
|||
|
||||
target_include_directories(pm3rrg_rdv4_hardnested_avx2 PRIVATE
|
||||
../../common
|
||||
../../include)
|
||||
../../include
|
||||
../src)
|
||||
|
||||
## x86 / AVX512
|
||||
add_library(pm3rrg_rdv4_hardnested_avx512 OBJECT
|
||||
|
@ -90,7 +95,8 @@ if ("${CMAKE_SYSTEM_PROCESSOR}" IN_LIST X86_CPUS)
|
|||
|
||||
target_include_directories(pm3rrg_rdv4_hardnested_avx512 PRIVATE
|
||||
../../common
|
||||
../../include)
|
||||
../../include
|
||||
../src)
|
||||
|
||||
set(SIMD_TARGETS
|
||||
$<TARGET_OBJECTS:pm3rrg_rdv4_hardnested_mmx>
|
||||
|
|
|
@ -59,7 +59,7 @@ THE SOFTWARE.
|
|||
#include <string.h>
|
||||
#include "crapto1/crapto1.h"
|
||||
#include "parity.h"
|
||||
//#include "util.h"
|
||||
#include "ui.h" // PrintAndLogEx
|
||||
//#include "common.h"
|
||||
|
||||
// bitslice type
|
||||
|
@ -238,18 +238,18 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel
|
|||
// bitslice all the even states
|
||||
bitslice_t **restrict bitsliced_even_states = (bitslice_t **)malloc(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof(bitslice_t *));
|
||||
if (bitsliced_even_states == NULL) {
|
||||
printf("Out of memory error in brute_force. Aborting...");
|
||||
PrintAndLogEx(WARNING, "Out of memory error in brute_force. Aborting...");
|
||||
exit(4);
|
||||
}
|
||||
bitslice_value_t *restrict bitsliced_even_feedback = malloc_bitslice(((p->len[EVEN_STATE] - 1) / MAX_BITSLICES + 1) * sizeof(bitslice_value_t));
|
||||
if (bitsliced_even_feedback == NULL) {
|
||||
printf("Out of memory error in brute_force. Aborting...");
|
||||
PrintAndLogEx(WARNING, "Out of memory error in brute_force. Aborting...");
|
||||
exit(4);
|
||||
}
|
||||
for (uint32_t *restrict p_even = p->states[EVEN_STATE]; p_even < p_even_end; p_even += MAX_BITSLICES) {
|
||||
bitslice_t *restrict lstate_p = malloc_bitslice(STATE_SIZE / 2 * sizeof(bitslice_t));
|
||||
if (lstate_p == NULL) {
|
||||
printf("Out of memory error in brute_force. Aborting... \n");
|
||||
PrintAndLogEx(WARNING, "Out of memory error in brute_force. Aborting... \n");
|
||||
exit(4);
|
||||
}
|
||||
memset(lstate_p, 0x00, STATE_SIZE / 2 * sizeof(bitslice_t)); // zero even bits
|
||||
|
@ -265,8 +265,8 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel
|
|||
#ifdef DEBUG_KEY_ELIMINATION
|
||||
if (known_target_key != -1 && e == test_state[EVEN_STATE]) {
|
||||
bucket_contains_test_key[bitsliced_blocks] = true;
|
||||
// printf("bucket %d contains test key even state\n", bitsliced_blocks);
|
||||
// printf("in slice %d\n", slice_idx);
|
||||
// PrintAndLogEx(INFO, "bucket %d contains test key even state", bitsliced_blocks);
|
||||
// PrintAndLogEx(INFO, "in slice %d", slice_idx);
|
||||
}
|
||||
#endif
|
||||
for (uint32_t bit_idx = 0; bit_idx < STATE_SIZE / 2; bit_idx++, e >>= 1) {
|
||||
|
@ -336,8 +336,8 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel
|
|||
|
||||
#ifdef DEBUG_KEY_ELIMINATION
|
||||
// if (known_target_key != -1 && bucket_contains_test_key[block_idx] && *p_odd == test_state[ODD_STATE]) {
|
||||
// printf("Now testing known target key.\n");
|
||||
// printf("block_idx = %d/%d\n", block_idx, bitsliced_blocks);
|
||||
// PrintAndLogEx(INFO, "Now testing known target key.");
|
||||
// PrintAndLogEx(INFO, "block_idx = %d/%d", block_idx, bitsliced_blocks);
|
||||
// }
|
||||
#endif
|
||||
// add the even state bits
|
||||
|
@ -444,8 +444,8 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel
|
|||
#endif
|
||||
#ifdef DEBUG_KEY_ELIMINATION
|
||||
if (known_target_key != -1 && bucket_contains_test_key[block_idx] && *p_odd == test_state[ODD_STATE]) {
|
||||
printf("Known target key eliminated in brute_force.\n");
|
||||
printf("block_idx = %d/%d, nonce = %d/%d\n", block_idx, bitsliced_blocks, tests, nonces_to_bruteforce);
|
||||
PrintAndLogEx(INFO, "Known target key eliminated in brute_force.");
|
||||
PrintAndLogEx(INFO, "block_idx = %d/%d, nonce = %d/%d", block_idx, bitsliced_blocks, tests, nonces_to_bruteforce);
|
||||
}
|
||||
#endif
|
||||
goto stop_tests;
|
||||
|
@ -495,15 +495,15 @@ uint64_t CRACK_STATES_BITSLICED(uint32_t cuid, uint8_t *best_first_bytes, statel
|
|||
}
|
||||
#ifdef DEBUG_KEY_ELIMINATION
|
||||
if (known_target_key != -1 && *p_even_test == test_state[EVEN_STATE] && *p_odd == test_state[ODD_STATE]) {
|
||||
printf("Known target key eliminated in brute_force verification.\n");
|
||||
printf("block_idx = %d/%d\n", block_idx, bitsliced_blocks);
|
||||
PrintAndLogEx(INFO, "Known target key eliminated in brute_force verification.");
|
||||
PrintAndLogEx(INFO, "block_idx = %d/%d", block_idx, bitsliced_blocks);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#ifdef DEBUG_KEY_ELIMINATION
|
||||
if (known_target_key != -1 && *p_even_test == test_state[EVEN_STATE] && *p_odd == test_state[ODD_STATE]) {
|
||||
printf("Known target key eliminated in brute_force (results_bit == 0).\n");
|
||||
printf("block_idx = %d/%d\n", block_idx, bitsliced_blocks);
|
||||
PrintAndLogEx(INFO, "Known target key eliminated in brute_force (results_bit == 0).");
|
||||
PrintAndLogEx(INFO, "block_idx = %d/%d", block_idx, bitsliced_blocks);
|
||||
}
|
||||
#endif
|
||||
results64 >>= 1;
|
||||
|
@ -533,7 +533,7 @@ out:
|
|||
|
||||
#if defined (DEBUG_BRUTE_FORCE)
|
||||
for (uint32_t i = 0; i < MAX_ELIMINATION_STEP; i++) {
|
||||
printf("Eliminated after %2u test_bytes: %5.2f%%\n", i + 1, (float)keys_eliminated[i] / bucket_states_tested * 100);
|
||||
PrintAndLogEx(INFO, "Eliminated after %2u test_bytes: %5.2f%%", i + 1, (float)keys_eliminated[i] / bucket_states_tested * 100);
|
||||
}
|
||||
#endif
|
||||
return key;
|
||||
|
|
|
@ -740,8 +740,12 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) {
|
|||
|
||||
case 'b':
|
||||
if (root && !json_is_boolean(root)) {
|
||||
set_error(s, "<validation>", json_error_wrong_type, "Expected true or false, got %s",
|
||||
type_name(root));
|
||||
set_error(s,
|
||||
"<validation>",
|
||||
json_error_wrong_type,
|
||||
"Expected true or false, got %s",
|
||||
type_name(root)
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -167,8 +167,9 @@ int reveng_main(int argc, char *argv[]) {
|
|||
pkchop(&model.spoly);
|
||||
width = plen(model.spoly);
|
||||
rflags |= R_HAVEP;
|
||||
if (c == 'P')
|
||||
if (c == 'P') {
|
||||
prcp(&model.spoly);
|
||||
}
|
||||
mnovel(&model);
|
||||
break;
|
||||
case 'l': /* l little-endian input and output */
|
||||
|
@ -332,6 +333,7 @@ ipqx:
|
|||
mbynum(&model, --args);
|
||||
ufound(&model);
|
||||
} while (args);
|
||||
mfree(&model);
|
||||
break;
|
||||
case 'd': /* d dump CRC model */
|
||||
/* maybe we don't want to do this:
|
||||
|
@ -387,6 +389,10 @@ ipqx:
|
|||
apolys = calloc(args * sizeof(poly_t), sizeof(char));
|
||||
if (!apolys) {
|
||||
uerror("cannot allocate memory for argument list");
|
||||
pfree(&model.spoly);
|
||||
pfree(&model.init);
|
||||
pfree(&model.xorout);
|
||||
mfree(&model);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -421,17 +427,21 @@ ipqx:
|
|||
continue;
|
||||
if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout))
|
||||
continue;
|
||||
|
||||
apoly = pclone(pset.xorout);
|
||||
if (pset.flags & P_REFOUT)
|
||||
if (pset.flags & P_REFOUT) {
|
||||
prev(&apoly);
|
||||
}
|
||||
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
|
||||
if (ptst(crc)) {
|
||||
pfree(&crc);
|
||||
break;
|
||||
} else
|
||||
} else {
|
||||
pfree(&crc);
|
||||
}
|
||||
}
|
||||
pfree(&apoly);
|
||||
if (qptr == pptr) {
|
||||
/* the selected model solved all arguments */
|
||||
|
@ -444,14 +454,19 @@ ipqx:
|
|||
/* toggle refIn/refOut and reflect arguments */
|
||||
if (~rflags & R_HAVERI) {
|
||||
model.flags ^= P_REFIN | P_REFOUT;
|
||||
for (qptr = apolys; qptr < pptr; ++qptr)
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
prevch(qptr, ibperhx);
|
||||
}
|
||||
}
|
||||
} while (~rflags & R_HAVERI && ++pass < 2);
|
||||
}
|
||||
|
||||
if (uflags & C_RESULT) {
|
||||
for (qptr = apolys; qptr < pptr; ++qptr)
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
pfree(qptr);
|
||||
}
|
||||
free(apolys);
|
||||
mfree(&model);
|
||||
return 1;
|
||||
//exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
@ -467,8 +482,10 @@ ipqx:
|
|||
pass = 0;
|
||||
do {
|
||||
mptr = candmods = reveng(&model, qpoly, rflags, args, apolys);
|
||||
if (mptr && plen(mptr->spoly))
|
||||
if (mptr && plen(mptr->spoly)) {
|
||||
uflags |= C_RESULT;
|
||||
}
|
||||
|
||||
while (mptr && plen(mptr->spoly)) {
|
||||
/* results were printed by the callback
|
||||
* string = mtostr(mptr);
|
||||
|
@ -478,26 +495,31 @@ ipqx:
|
|||
mfree(mptr++);
|
||||
}
|
||||
free(candmods);
|
||||
|
||||
if (~rflags & R_HAVERI) {
|
||||
model.flags ^= P_REFIN | P_REFOUT;
|
||||
for (qptr = apolys; qptr < pptr; ++qptr)
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
prevch(qptr, ibperhx);
|
||||
}
|
||||
}
|
||||
} while (~rflags & R_HAVERI && ++pass < 2);
|
||||
for (qptr = apolys; qptr < pptr; ++qptr)
|
||||
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
pfree(qptr);
|
||||
}
|
||||
|
||||
free(apolys);
|
||||
|
||||
if (~uflags & C_RESULT)
|
||||
uerror("no models found");
|
||||
|
||||
break;
|
||||
default: /* no mode specified */
|
||||
fprintf(stderr, "%s: no mode switch specified. Use %s -h for help.\n", myname, myname);
|
||||
return 0;
|
||||
//exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 1;
|
||||
//exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -57,6 +57,9 @@ f1d83f964314 # RKF RejskortDanmark KeyB
|
|||
#
|
||||
4b0b20107ccb # TNP3xxx
|
||||
#
|
||||
# Access control system
|
||||
605F5E5D5C5B
|
||||
#
|
||||
# more Keys from mfc_default_keys.lua
|
||||
000000000001
|
||||
000000000002
|
||||
|
@ -1115,3 +1118,88 @@ fe04ecfe5577
|
|||
C1E51C63B8F5 # RATB key
|
||||
1DB710648A65
|
||||
18F34C92A56E # E-GO card key
|
||||
#
|
||||
# Library Card MFP - SL1
|
||||
4a832584637d
|
||||
ca679d6291b0
|
||||
30d9690fc5bc
|
||||
5296c26109d4
|
||||
e77952748484
|
||||
91c2376005a1
|
||||
30b7680b2bc9
|
||||
e2a9e88bfe16
|
||||
43b04995d234
|
||||
aade86b1f9c1
|
||||
5ea088c824c9
|
||||
c67beb41ffbf
|
||||
5ea088c824c9
|
||||
c67beb41ffbf
|
||||
b84d52971107
|
||||
52b0d3f6116e
|
||||
#
|
||||
# Data from https://pastebin.com/cLSQQ9xN
|
||||
ca3a24669d45
|
||||
4087c6a75a96
|
||||
160a91d29a9c
|
||||
b7bf0c13066e
|
||||
403f09848b87
|
||||
d73438698eea
|
||||
5f31f6fcd3a0
|
||||
a0974382c4c5
|
||||
a82045a10949
|
||||
#
|
||||
# Data from https://pastebin.com/2iV8h93h
|
||||
#
|
||||
# funnivarium
|
||||
# forum ankara
|
||||
#
|
||||
2602FFFFFFFF
|
||||
#
|
||||
# macera adasi
|
||||
# ankara kentpark
|
||||
# INACTIVE
|
||||
#
|
||||
0A4600FF00FF
|
||||
DFF293979FA7
|
||||
4D6F62692E45
|
||||
4118D7EF0902
|
||||
#
|
||||
# petrol ofisi
|
||||
# positive card
|
||||
# ode-gec
|
||||
#
|
||||
0406080A0C0E
|
||||
#
|
||||
# konya elkart
|
||||
#
|
||||
988ACDECDFB0
|
||||
120D00FFFFFF
|
||||
#
|
||||
# bowlingo
|
||||
# serdivan avym
|
||||
#
|
||||
4AE23A562A80
|
||||
#
|
||||
# kart54
|
||||
#
|
||||
2AFFD6F88B97
|
||||
A9F3F289B70C
|
||||
DB6819558A25
|
||||
6130DFA578A0
|
||||
B16B2E573235
|
||||
42EF7BF572AB
|
||||
274E6101FC5E
|
||||
#
|
||||
# crazy park
|
||||
# kizilay avm
|
||||
#
|
||||
00DD300F4F10
|
||||
#
|
||||
# kartsistem B
|
||||
#
|
||||
FEE2A3FBC5B6
|
||||
#
|
||||
# toru ent
|
||||
# taurus avm
|
||||
#
|
||||
005078565703
|
||||
|
|
|
@ -42,3 +42,5 @@ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
|||
100f0e0d0c0b0a090807060504030201
|
||||
404142434445464748494a4b4c4d4e4f
|
||||
303132333435363738393a3b3c3d3e3f
|
||||
9CABF398358405AE2F0E2B3D31C99A8A # Default key
|
||||
605F5E5D5C5B5A59605F5E5D5C5B5A59 # access control
|
|
@ -27,4 +27,4 @@ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
|
|||
100f0e0d0c0b0a090807060504030201
|
||||
404142434445464748494a4b4c4d4e4f
|
||||
303132333435363738393a3b3c3d3e3f
|
||||
|
||||
605F5E5D5C5B5A59605F5E5D5C5B5A59
|
||||
|
|
|
@ -11,7 +11,7 @@ show_usage()
|
|||
{
|
||||
echo
|
||||
echo "Usage:"
|
||||
echo "${0##/} input_eml_without_extension output.pm3scr"
|
||||
echo "${0##/} input_eml_without_extension output.cmd"
|
||||
exit
|
||||
}
|
||||
|
||||
|
@ -32,4 +32,4 @@ rm $2
|
|||
echo "hf mf eclr" >> $2
|
||||
echo "hf mf eload" $1 >> $2
|
||||
echo "hf mf ekeyprn" >> $2
|
||||
echo "hf mf sim" `cat $1.eml | (read -n 8 uid; echo $uid)` >> $2
|
||||
echo "hf mf sim u" `cat $1.eml | (read -n 8 uid; echo $uid)` >> $2
|
|
@ -93,8 +93,10 @@ Command = {
|
|||
o.data = data
|
||||
return o
|
||||
end,
|
||||
parse = function (packet)
|
||||
local count, cmd, arg1, arg2, arg3, data = bin.unpack('LLLLH511', packet)
|
||||
parse = function(packet)
|
||||
local count, cmd, arg1, arg2, arg3, data = bin.unpack('LLLL', packet)
|
||||
local length = #packet - count + 1
|
||||
count, data = bin.unpack('H'..length, packet, count)
|
||||
return Command:new{cmd = cmd, arg1 = arg1, arg2 = arg2, arg3 = arg3, data = data}
|
||||
end
|
||||
}
|
||||
|
@ -121,26 +123,28 @@ end
|
|||
-- @param command - the usb packet to send
|
||||
-- @param ignoreresponse - if set to true, we don't read the device answer packet
|
||||
-- which is usually recipe for fail. If not sent, the host will wait 2s for a
|
||||
-- response of type CMD_ACK
|
||||
-- response of type CMD_ACK or like NG use the CMD as ack..
|
||||
-- @return packet,nil if successful
|
||||
-- nil, errormessage if unsuccessful
|
||||
function Command:sendMIX( ignore_response, timeout )
|
||||
function Command:sendMIX( ignore_response, timeout, use_cmd_ack)
|
||||
if timeout == nil then timeout = TIMEOUT end
|
||||
local data = self.data
|
||||
local cmd = self.cmd
|
||||
local arg1, arg2, arg3 = self.arg1, self.arg2, self.arg3
|
||||
|
||||
local err, msg = core.SendCommandMIX(cmd, arg1, arg2, arg3, data)
|
||||
if err == nil then return err, msg end
|
||||
|
||||
if ignore_response then return true, nil end
|
||||
|
||||
if timeout == nil then timeout = TIMEOUT end
|
||||
local ack = _commands.CMD_ACK
|
||||
if use_cmd_ack then
|
||||
ack = cmd
|
||||
end
|
||||
|
||||
local response, msg = core.WaitForResponseTimeout(_commands.CMD_ACK, timeout)
|
||||
local response, msg = core.WaitForResponseTimeout(ack, timeout)
|
||||
if response == nil then
|
||||
return nil, 'Error, waiting for response timed out :: '..msg
|
||||
end
|
||||
|
||||
-- lets digest
|
||||
data = nil
|
||||
cmd = nil
|
||||
|
@ -157,15 +161,13 @@ function Command:sendMIX( ignore_response, timeout )
|
|||
return packed, nil;
|
||||
end
|
||||
function Command:sendNG( ignore_response, timeout )
|
||||
if timeout == nil then timeout = TIMEOUT end
|
||||
local data = self.data
|
||||
local cmd = self.cmd
|
||||
local err, msg = core.SendCommandNG(cmd, data)
|
||||
if err == nil then return nil, msg end
|
||||
|
||||
if ignore_response then return true, nil end
|
||||
|
||||
if timeout == nil then timeout = TIMEOUT end
|
||||
|
||||
local response, msg = core.WaitForResponseTimeout(cmd, timeout)
|
||||
if response == nil then
|
||||
return nil, 'Error, waiting for response timed out :: '..msg
|
||||
|
|
|
@ -15,17 +15,18 @@ local cmds = require('commands')
|
|||
local utils = require('utils')
|
||||
|
||||
-- Shouldn't take longer than 2.5 seconds
|
||||
local TIMEOUT = 2500
|
||||
local TIMEOUT = 2000
|
||||
|
||||
local ISO14B_COMMAND = {
|
||||
ISO14B_CONNECT = 1,
|
||||
ISO14B_DISCONNECT = 2,
|
||||
ISO14B_APDU = 4,
|
||||
ISO14B_RAW = 8,
|
||||
ISO14B_CONNECT = 0x1,
|
||||
ISO14B_DISCONNECT = 0x2,
|
||||
ISO14B_APDU = 0x4,
|
||||
ISO14B_RAW = 0x8,
|
||||
ISO14B_REQUEST_TRIGGER = 0x10,
|
||||
ISO14B_APPEND_CRC = 0x20,
|
||||
ISO14B_SELECT_STD = 0x40,
|
||||
ISO14B_SELECT_SR = 0x80,
|
||||
ISO14B_SET_TIMEOUT = 0x100,
|
||||
}
|
||||
|
||||
local function parse14443b(data)
|
||||
|
@ -74,9 +75,11 @@ local function read14443b(disconnect)
|
|||
arg1 = flags
|
||||
}
|
||||
|
||||
local result, err = command:sendMIX()
|
||||
info = nil
|
||||
|
||||
local result, err = command:sendMIX(false, TIMEOUT, true)
|
||||
if result then
|
||||
local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',result)
|
||||
local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL', result)
|
||||
if arg0 == 0 then
|
||||
data = string.sub(result, count)
|
||||
info, err = parse14443b(data)
|
||||
|
@ -88,12 +91,10 @@ local function read14443b(disconnect)
|
|||
end
|
||||
|
||||
if err then
|
||||
print(err)
|
||||
return nil, err
|
||||
end
|
||||
return info
|
||||
return info, nil
|
||||
end
|
||||
|
||||
---
|
||||
-- Waits for a mifare card to be placed within the vicinity of the reader.
|
||||
-- @return if successful: an table containing card info
|
||||
|
@ -102,12 +103,11 @@ local function waitFor14443b()
|
|||
print('Waiting for card... press Enter to quit')
|
||||
while not core.kbd_enter_pressed() do
|
||||
res, err = read14443b(false)
|
||||
if res then return res end
|
||||
if res then return res, err end
|
||||
-- err means that there was no response from card
|
||||
end
|
||||
return nil, 'Aborted by user'
|
||||
end
|
||||
|
||||
---
|
||||
-- turns on the HF field.
|
||||
local function connect14443b()
|
||||
|
|
|
@ -9,11 +9,11 @@ desc = [[
|
|||
This script calculates many checksums (CRC) over the provided hex input.
|
||||
]]
|
||||
example = [[
|
||||
script run e -b 010203040506070809
|
||||
script run e -b 010203040506070809 -w 16
|
||||
script run data_hex_crc -b 010203040506070809
|
||||
script run data_hex_crc -b 010203040506070809 -w 16
|
||||
]]
|
||||
usage = [[
|
||||
script run e [-b <hex bytes] [-w <width>]
|
||||
script run data_hex_crc [-b <hex bytes] [-w <width>]
|
||||
]]
|
||||
arguments = [[
|
||||
-b data in hex
|
|
@ -8,10 +8,10 @@ desc = [[
|
|||
This script tries to decode Mifare Classic Access bytes
|
||||
]]
|
||||
example = [[
|
||||
1. script run mifare_access -a 7F0F0869
|
||||
1. script run data_mf_accessdecode -a 7F0F0869
|
||||
]]
|
||||
usage = [[
|
||||
script run mifare_access [-h] [-a <access bytes>]
|
||||
script run data_mf_accessdecode [-h] [-a <access bytes>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
|
@ -12,10 +12,10 @@ This script takes a dumpfile from 'hf mf dump' and converts it to a format that
|
|||
by the emulator
|
||||
]]
|
||||
example = [[
|
||||
script run dumptoemul -i dumpdata-foobar.bin
|
||||
script run data_mf_bin2eml -i dumpdata-foobar.bin
|
||||
]]
|
||||
usage = [[
|
||||
script run dumptoemul [-i <file>] [-o <file>]
|
||||
script run data_mf_bin2eml [-i <file>] [-o <file>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h This help
|
|
@ -13,10 +13,10 @@ This script takes a dumpfile and produces a html based dump, which is a
|
|||
bit more easily analyzed.
|
||||
]]
|
||||
example = [[
|
||||
script run htmldump -o mifarecard_foo.html
|
||||
script run data_mf_bin2html -o mifarecard_foo.html
|
||||
]]
|
||||
usage = [[
|
||||
script run htmldump [-i <file>] [-o <file>]
|
||||
script run data_mf_bin2html [-i <file>] [-o <file>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h This help
|
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