Merge pull request #5 from RfidResearchGroup/master

Update from upstream.
This commit is contained in:
DXL 2020-10-13 14:06:07 +08:00 committed by GitHub
commit 29d17dbe84
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
479 changed files with 802627 additions and 300629 deletions

View 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
View file

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

@ -0,0 +1 @@
leak:libfontconfig.so

View file

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

View file

@ -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' {} \;

View file

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

View file

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

View file

@ -3,9 +3,9 @@
| Releases | Linux & OSX CI | Windows CI | Coverity |
| ------------------- |:-------------------:| -------------------:| -------------------:|
| [![Latest release](https://img.shields.io/github/v/release/rfidresearchgroup/proxmark3)](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [![Build status](https://api.travis-ci.org/RfidResearchGroup/proxmark3.svg?branch=master)](https://travis-ci.org/RfidResearchGroup/proxmark3) | [![Build status](https://ci.appveyor.com/api/projects/status/b4gwrhq3nc876cuu/branch/master?svg=true)](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [![Coverity Status](https://scan.coverity.com/projects/19334/badge.svg)](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)|
| Releases | Linux & OSX CI | Windows CI | Coverity | Contributors |
| ------------------- |:-------------------:| -------------------:| -------------------:| -------------------:|
| [![Latest release](https://img.shields.io/github/v/release/rfidresearchgroup/proxmark3)](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [![Build status](https://api.travis-ci.com/RfidResearchGroup/proxmark3.svg?branch=master)](https://travis-ci.com/RfidResearchGroup/proxmark3) | [![Build status](https://ci.appveyor.com/api/projects/status/b4gwrhq3nc876cuu/branch/master?svg=true)](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [![Coverity Status](https://scan.coverity.com/projects/19334/badge.svg)](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)| ![GitHub contributors](https://img.shields.io/github/contributors/rfidresearchgroup/proxmark3) |
@ -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/)
_no discord or slack channel_
- [Proxmark3 community discord server](https://discord.gg/zjxc8ZB)
_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

View file

@ -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
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
}
Write-Host "[ OK ]" -ForegroundColor Green
}
$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
}
$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 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
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 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 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
$JobTime=[System.Environment]::TickCount
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
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
break
}
if ([System.Environment]::TickCount-$JobTime -gt 1000000) {
Write-host "Exit by timeout" -ForegroundColor Yellow
break
}
}
Remove-Job -Force $Job
}
cd C:\ProxSpace\
C:\ProxSpace\msys2\ps\setup.cmd
ExecUpdate "update1" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2"
ExecUpdate "update2" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2"
Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$CloneTime) / 1000) sec" -Category Information
Write-Host "Update " -NoNewLine
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) {
if ($PSjob.State -eq 'Completed') {
Write-Host "$Text" -NoNewLine
Write-Host "[ OK ]" -ForegroundColor Green
break
}
if ($PSjob.State -eq 'Failed') {
Write-Host "$Text" -NoNewLine
Write-Host "[ Failed ]" -ForegroundColor Red
break
}
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
}
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
}
Write-Host "[ OK ]" -ForegroundColor Green
}
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"
$pmfolder = Split-Path $env:appveyor_build_folder -Leaf
Function ExecMinGWCmd($Cmd) {
cd $env:proxspace_path
./runme64.bat -c "cd $pmfolder && $Cmd"
}
Function ExecCheck($Name) {
$testspass = ($LASTEXITCODE -eq 0)
$global:TestsPassed=$testspass
$env:MSYS_HOME="C:\ProxSpace\msys2"
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."
}
}
$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
ExecMinGWCmd "make clean;make V=1"
$env:MSYSTEM="MINGW32"
if(!(Test-Path "$env:proxspace_home_path\$pmfolder\client\proxmark3.exe")){
$env:MINGW_PREFIX="/mingw32"
throw "Main file proxmark3.exe not exists."
$env:SHELL="/bin/bash"
}
$env:MSYSTEM_CHOST="i686-w64-mingw32"
ExecMinGWCmd 'make check'
cd C:\ProxSpace\pm3
Write-Host "---------- make ----------" -ForegroundColor Yellow
ExecCheck "PS make Tests"
Write-Host "---------- PS btaddon ----------" -ForegroundColor Yellow
$TestTime=[System.Environment]::TickCount
#make
ExecMinGWCmd 'make clean;make V=1 PLATFORM_EXTRAS=BTADDON'
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."
}
cd c:\ProxSpace\pm3
bash -c -i 'make check'
$testspass = ($LASTEXITCODE -eq 0)
ExecMinGWCmd 'make check'
$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
} 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
throw "Tests error."
}
ExecCheck "PS BTaddon Tests"
Write-Host "---------- btaddon ----------" -ForegroundColor Yellow
Write-Host "---------- PS make clean ----------" -ForegroundColor Yellow
ExecMinGWCmd 'make clean'
Write-Host "---------- PS cmake ----------" -ForegroundColor Yellow
$TestTime=[System.Environment]::TickCount
bash -c -i 'pwd;make clean;make PLATFORM_EXTRAS=BTADDON'
cd c:\ProxSpace\pm3
bash -c -i 'make check'
$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
}
ExecMinGWCmd 'mkdir -p client/build; cd client/build; cmake -G""MSYS Makefiles"" ..; make VERBOSE=1;'
Write-Host "---------- make clean ----------" -ForegroundColor Yellow
bash -c -i 'make clean'
Write-Host "---------- cmake ----------" -ForegroundColor Yellow
$TestTime=[System.Environment]::TickCount
Write-Host "---------- PS cmake tests ----------" -ForegroundColor Yellow
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 './tools/pm3_tests.sh --clientbin client/build/proxmark3.exe client'
Write-Host "---------- cmake tests ----------" -ForegroundColor Yellow
cd c:\ProxSpace\pm3
bash -c -i './tools/pm3_tests.sh --clientbin client/build/proxmark3.exe client'
ExecCheck "PS cmake Tests"
$testspass = ($LASTEXITCODE -eq 0)
$global:TestsPassed=(($global:TestsPassed) -and ($testspass))
Receive-Job -Wait -Name WSLInstall -ErrorAction SilentlyContinue
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
}
Receive-Job -Wait -Job $WSLjob
test_script:
- ps: >-
@ -273,4 +345,4 @@ on_success:
on_failure:
- ps: Write-Host "Build error." -ForegroundColor Red
on_finish:
- ps: # $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
- ps: # $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

View file

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

View file

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

View file

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

View file

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

View file

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

View 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();
}

View file

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

View file

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

View 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 ]=-");
}

View file

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

View file

@ -575,4 +575,5 @@ void RunMod(void) {
}
}
}
LEDsoff();
}

View file

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

View file

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

View file

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

View file

@ -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,22 +806,35 @@ 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: {
uint32_t high, low;
int res = lf_hid_watch(0, &high, &low);
reply_ng(CMD_LF_HID_WATCH, res, NULL, 0);
reply_ng(CMD_LF_HID_WATCH, res, NULL, 0);
break;
}
case CMD_LF_HID_SIMULATE: {
@ -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;
}

View file

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

View file

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

View file

@ -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) {
// 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;
}
@ -124,11 +124,10 @@ static uint8_t bits2byte(uint8_t *bits, int length) {
}
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]);
@ -141,27 +140,26 @@ static void msb2lsb_word(uint8_t *word) {
}
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];
}
@ -169,7 +167,7 @@ static void save_word(int pos, uint8_t bits[EM4X50_TAG_WORD]) {
static void wait_timer(int timer, uint32_t period) {
// do nothing for <period> using timer <timer>
if (timer == FPGA_TIMER_0) {
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
@ -184,23 +182,21 @@ 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);
// Connect the A/D to the peak-detected low-frequency path.
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Steal this pin from the SSP (SPI communication channel with fpga) and
// use it to control the modulation
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
@ -208,7 +204,7 @@ static void em4x50_setup_read(void) {
// Disable modulation at default, which means enable the field
LOW(GPIO_SSC_DOUT);
// Enable Peripheral Clock for
// TIMER_CLOCK0, used to measure exact timing before answering
// TIMER_CLOCK1, used to capture edges of the tag frames
@ -221,17 +217,17 @@ static void em4x50_setup_read(void) {
// TC0: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
// TC1: Capture mode, default timer source = MCK/2 (TIMER_CLOCK1), no triggers
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK;
// Enable and reset counters
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
// synchronized startup procedure
while (AT91C_BASE_TC0->TC_CV > 0) {}; // wait until TC1 returned to zero
// Watchdog hit
WDT_HIT();
}
@ -239,21 +235,21 @@ static void em4x50_setup_read(void) {
// functions for "reader" use case
static bool get_signalproperties(void) {
// calculate signal properties (mean amplitudes) from measured data:
// 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow
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++) {
// about 2 samples per bit period
wait_timer(0, T0 * EM4X50_T_TAG_HALF_PERIOD);
@ -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
@ -273,39 +268,36 @@ 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;
}
sample_max_sum += sample_max[i];
}
sample_max_mean = sample_max_sum / no_periods;
// 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;
}
static int get_next_bit(void) {
// returns bit value (or EM4X50_BIT_OTHER -> no bit pattern) by evaluating
// a single sample within a bit period (given there is no LIW, ACK or NAK)
// This function is not used for decoding, it is only used for identifying
// 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);
@ -315,47 +307,58 @@ static int get_next_bit(void) {
return EM4X50_BIT_0;
else if (sample < gLow)
return EM4X50_BIT_1;
return EM4X50_BIT_OTHER;
}
static uint32_t get_pulse_length(void) {
// iterates pulse length (low -> high -> low)
uint8_t sample = 0;
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
while (sample > gLow)
// Dbprintf( _CYAN_("4x50 get_pulse_length A") );
int32_t timeout = (T0 * 3 * EM4X50_T_TAG_FULL_PERIOD);
// iterates pulse length (low -> high -> low)
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
while (sample > gLow && (timeout--)) {
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) {
// send single bit according to EM4x50 application note and datasheet
// reset clock for the next bit
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
@ -370,13 +373,13 @@ static void em4x50_send_bit(int bit) {
// half of bit period
HIGH(GPIO_SSC_DOUT);
while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_HALF_PERIOD);
// disable modulation for second half of bit period
LOW(GPIO_SSC_DOUT);
while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD);
} else {
// bit = "1" means disable modulation for full bit period
LOW(GPIO_SSC_DOUT);
while (AT91C_BASE_TC0->TC_CV < T0 * EM4X50_T_TAG_FULL_PERIOD);
@ -386,20 +389,20 @@ static void em4x50_send_bit(int bit) {
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);
}
static void em4x50_send_byte_with_parity(uint8_t byte) {
// send byte followed by its (equal) parity bit
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;
}
@ -408,12 +411,12 @@ static void em4x50_send_byte_with_parity(uint8_t byte) {
}
static void em4x50_send_word(const uint8_t bytes[4]) {
// send 32 bit word with parity bits according to EM4x50 datasheet
for (int i = 0; i < 4; i++)
em4x50_send_byte_with_parity(bytes[i]);
// send column parities
em4x50_send_byte(bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3]);
@ -422,70 +425,66 @@ static void em4x50_send_word(const uint8_t bytes[4]) {
}
static bool find_single_listen_window(void) {
// find single listen window
int cnt_pulses = 0;
while (cnt_pulses < EM4X50_T_WAITING_FOR_SNGLLIW) {
// identification of listen window is done via evaluation of
// pulse lengths
if (check_pulse_length(get_pulse_length(), 3 * EM4X50_T_TAG_FULL_PERIOD)) {
if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) {
// listen window found
return true;
}
} else {
cnt_pulses++;
}
cnt_pulses++;
}
return false;
}
static bool find_double_listen_window(bool bcommand) {
// find two successive listen windows that indicate the beginning of
// data transmission
// double listen window to be detected within 1600 pulses -> worst case
// reason: first detectable double listen window after 34 words
// -> 34 words + 34 single listen windows -> about 1600 pulses
int cnt_pulses = 0;
while (cnt_pulses < EM4X50_T_WAITING_FOR_DBLLIW) {
// identification of listen window is done via evaluation of
// pulse lengths
if (check_pulse_length(get_pulse_length(), 3 * EM4X50_T_TAG_FULL_PERIOD)) {
if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) {
// first listen window found
if (bcommand) {
// data transmission from card has to be stopped, because
// a commamd shall be issued
// unfortunately the posititon in listen window (where
// command request has to be sent) has gone, so if a
// second window follows - sync on this to issue a command
// skip the next bit...
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_FULL_PERIOD);
// ...and check if the following bit does make sense
// (if not it is the correct position within the second
// listen window)
if (get_next_bit() == EM4X50_BIT_OTHER) {
// send RM for request mode
em4x50_send_bit(0);
em4x50_send_bit(0);
@ -503,51 +502,46 @@ static bool find_double_listen_window(bool bcommand) {
return true;
}
}
} else {
cnt_pulses++;
}
}
return false;
}
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) {
// 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);
}
static bool check_ack(bool bliw) {
// returns true if signal structue corresponds to ACK, anything else is
// counted as NAK (-> false)
// Only relevant for pasword writing function:
// If <bliw> is true then within the single listen window right after the
// ack signal a RM request has to be sent.
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
while (AT91C_BASE_TC0->TC_CV < T0 * 4 * EM4X50_T_TAG_FULL_PERIOD) {
if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) {
// The received signal is either ACK or NAK.
if (check_pulse_length(get_pulse_length(), 2 * EM4X50_T_TAG_FULL_PERIOD)) {
// Now the signal must be ACK.
if (!bliw) {
@ -555,17 +549,17 @@ static bool check_ack(bool bliw) {
return true;
} else {
// send RM request after ack signal
// wait for 2 bits (remaining "bit" of ACK signal + first
// "bit" of listen window)
wait_timer(FPGA_TIMER_0, T0 * 2 * EM4X50_T_TAG_FULL_PERIOD);
// check for listen window (if first bit cannot be inerpreted
// as a valid bit it must belong to a listen window)
if (get_next_bit() == EM4X50_BIT_OTHER) {
// send RM for request mode
em4x50_send_bit(0);
em4x50_send_bit(0);
@ -574,7 +568,7 @@ static bool check_ack(bool bliw) {
}
}
} else {
// It's NAK -> stop searching
break;
}
@ -589,7 +583,7 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) {
// decodes one word by evaluating pulse lengths and previous bit;
// word must have 45 bits in total:
// 32 data bits + 4 row parity bits + 8 column parity bits + 1 stop bit
bool bbitchange = false;
int i = 0;
uint32_t pl = 0;
@ -608,7 +602,7 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) {
bbitchange = true;
} else {
// pulse length = 2.5
bits[0] = 0;
bits[1] = 1;
@ -618,35 +612,35 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) {
// identify remaining bits based on pulse lengths
// between two listen windows only pulse lengths of 1, 1.5 and 2 are possible
while (true) {
i++;
pl = get_pulse_length();
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)) {
// pulse length = 1.5 -> decision on bit change
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
bbitchange = false;
} 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)) {
@ -663,7 +657,7 @@ static int get_word_from_bitstream(uint8_t bits[EM4X50_TAG_WORD]) {
// pulse length of 3 indicates listen window -> clear last
// bit (= 0) and return
return --i;
}
}
}
@ -676,8 +670,8 @@ 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);
@ -688,12 +682,12 @@ static bool login(uint8_t password[4]) {
// check if ACK is returned
if (check_ack(false))
return true;
} else {
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
}
return false;
}
@ -704,18 +698,18 @@ static bool login(uint8_t password[4]) {
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);
if (check_ack(false))
return true;
} else {
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
}
return false;
@ -726,10 +720,10 @@ static bool reset(void) {
//==============================================================================
static bool standard_read(int *now) {
// reads data that tag transmits when exposed to reader field
// (standard read mode); number of read words is saved in <now>
int fwr = *now;
uint8_t bits[EM4X50_TAG_WORD] = {0};
@ -742,23 +736,23 @@ static bool standard_read(int *now) {
// number of detected words
*now -= fwr;
return true;
} else {
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("didn't find a listen window");
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("didn't find a listen window");
}
return false;
}
static bool selective_read(uint8_t addresses[4]) {
// reads from "first word read" (fwr = addresses[3]) to "last word read"
// (lwr = addresses[2])
// result is verified by "standard read mode"
int fwr = addresses[3]; // first word read
int lwr = addresses[2]; // last word read
int now = fwr; // number of words
@ -773,26 +767,26 @@ static bool selective_read(uint8_t addresses[4]) {
// look for ACK sequence
if (check_ack(false))
// save and verify via standard read mode (compare number of words)
if (standard_read(&now))
if (now == (lwr - fwr + 1))
return true;
} else {
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
}
return false;
}
void em4x50_info(em4x50_data_t *etd) {
// collects as much information as possible via selective read mode
// if no password is given -> try with standard password "0x00000000"
// otherwise continue without login
bool bsuccess = false, blogin = false;
uint8_t status = 0;
uint8_t addresses[] = {0x00, 0x00, 0x21, 0x00}; // fwr = 0, lwr = 33
@ -810,28 +804,28 @@ void em4x50_info(em4x50_data_t *etd) {
blogin = login(etd->password);
} else {
// if no password is given, try to login with "0x00000000"
blogin = login(password);
}
bsuccess = selective_read(addresses);
}
status = (bsuccess << 1) + blogin;
lf_finalize();
reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238);
}
void em4x50_read(em4x50_data_t *etd) {
// reads in two different ways:
// - using "selective read mode" -> bidirectional communication
// - using "standard read mode" -> unidirectional communication (read
// data that tag transmits "voluntarily")
bool bsuccess = false, blogin = false;
int now = 0;
uint8_t status = 0;
@ -839,32 +833,32 @@ void em4x50_read(em4x50_data_t *etd) {
init_tag();
em4x50_setup_read();
// set gHigh and gLow
if (get_signalproperties() && find_em4x50_tag()) {
if (etd->addr_given) {
// selective read mode
// try to login with given password
if (etd->pwd_given)
blogin = login(etd->password);
// only one word has to be read -> first word read = last word read
addresses[2] = addresses[3] = etd->address;
bsuccess = selective_read(addresses);
} else {
// standard read mode
bsuccess = standard_read(&now);
}
}
status = (now << 2) + (bsuccess << 1) + blogin;
lf_finalize();
reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238);
}
@ -876,7 +870,7 @@ void em4x50_read(em4x50_data_t *etd) {
static bool write(uint8_t word[4], uint8_t address) {
// writes <word> to specified <address>
if (request_receive_mode()) {
// send write command
@ -902,8 +896,8 @@ static bool write(uint8_t word[4], uint8_t address) {
}
} else {
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
}
return false;
@ -912,7 +906,7 @@ static bool write(uint8_t word[4], uint8_t address) {
static bool write_password(uint8_t password[4], uint8_t new_password[4]) {
// changes password from <password> to <new_password>
if (request_receive_mode()) {
// send write password command
@ -941,36 +935,36 @@ static bool write_password(uint8_t password[4], uint8_t new_password[4]) {
}
} else {
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
if (DBGLEVEL >= DBG_DEBUG)
Dbprintf("error in command request");
}
return false;
}
void em4x50_write(em4x50_data_t *etd) {
// write operation process for EM4x50 tag,
// single word is written to given address, verified by selective read operation
bool bsuccess = false, blogin = false;
uint8_t status = 0;
uint8_t word[4] = {0x00, 0x00, 0x00, 0x00};
uint8_t addresses[4] = {0x00, 0x00, 0x00, 0x00};
init_tag();
em4x50_setup_read();
// set gHigh and gLow
if (get_signalproperties() && find_em4x50_tag()) {
// reorder word according to datasheet
msb2lsb_word(etd->word);
// if password is given try to login first
if (etd->pwd_given)
blogin = login(etd->password);
// write word to given address
if (write(etd->word, etd->address)) {
@ -991,7 +985,7 @@ void em4x50_write(em4x50_data_t *etd) {
word[2] = tag.sectors[etd->address][2];
word[3] = tag.sectors[etd->address][3];
msb2lsb_word(word);
bsuccess = true;
for (int i = 0; i < 4; i++)
bsuccess &= (word[i] == etd->word[i]) ? true : false;
@ -1002,20 +996,20 @@ void em4x50_write(em4x50_data_t *etd) {
}
status = (bsuccess << 1) + blogin;
lf_finalize();
reply_ng(CMD_ACK, status, (uint8_t *)tag.sectors, 238);
}
void em4x50_write_password(em4x50_data_t *etd) {
// sinmple change of password
bool bsuccess = false;
init_tag();
em4x50_setup_read();
// set gHigh and gLow
if (get_signalproperties() && find_em4x50_tag()) {
@ -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);
}

View file

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

View file

@ -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,
sizeof(apdu_select_binary_cardaccess),
response_apdu);
int rapdu_length = EPA_APDU((uint8_t *)apdu_select_binary_cardaccess,
sizeof(apdu_select_binary_cardaccess),
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;
}

View file

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

View file

@ -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
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
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();
}

View file

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

View file

@ -41,18 +41,18 @@ 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);
uint8_t *mem = BigBuf_malloc(*len);
uint32_t trigger_cnt = 0;
uint32_t trigger_cnt = 0;
uint16_t r = 0, interval = 0;
bool pressed = false;
@ -77,7 +77,7 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) {
// 180 (0xB4) arbitary value to see if a strong RF field is near.
if (r > 180) {
if (++trigger_cnt > triggersToSkip) {
break;
}
@ -97,9 +97,9 @@ 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) {
if (DBGLEVEL >= DBG_INFO) {
Dbprintf("Trigger kicked in (%d >= 180)", r);
Dbprintf("Collected %u samples", *len);
}
@ -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;

View file

@ -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,18 +1017,18 @@ void SniffHitag2(void) {
WDT_HIT();
/*
// only every 1000th times, in order to save time when collecting samples.
if (checked == 1000) {
if (data_available()) {
checked = -1;
break;
} else {
checked = 0;
}
}
++checked;
*/
/*
// only every 1000th times, in order to save time when collecting samples.
if (checked == 1000) {
if (data_available()) {
checked = -1;
break;
} else {
checked = 0;
}
}
++checked;
*/
// Receive frame, watch for at most T0*EOF periods
@ -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;
}
}
// 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;
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) {
}
}
// 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;
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);

View file

@ -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;
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
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();
set_tracing(true);
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;

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

@ -148,7 +148,7 @@ bool lf_get_reader_modulation(void) {
}
void lf_wait_periods(size_t periods) {
// wait detect gap
// wait detect gap
lf_count_edge_periods_ex(periods, true, false);
}
@ -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,40 +238,40 @@ void lf_finalize(void) {
}
size_t lf_detect_field_drop(size_t max) {
/*
size_t periods = 0;
// int16_t checked = 0;
/*
size_t periods = 0;
// int16_t checked = 0;
while (BUTTON_PRESS() == false) {
while (BUTTON_PRESS() == false) {
// // only every 1000th times, in order to save time when collecting samples.
// if (checked == 4000) {
// if (data_available()) {
// checked = -1;
// break;
// } else {
// checked = 0;
// // only every 1000th times, in order to save time when collecting samples.
// if (checked == 4000) {
// if (data_available()) {
// checked = -1;
// break;
// } else {
// checked = 0;
// }
// }
// }
// ++checked;
// ++checked;
WDT_HIT();
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
periods++;
volatile uint8_t adc_val = AT91C_BASE_SSC->SSC_RHR;
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
periods++;
volatile uint8_t adc_val = AT91C_BASE_SSC->SSC_RHR;
if (g_logging) logSampleSimple(adc_val);
if (g_logging) logSampleSimple(adc_val);
if (adc_val == 0) {
rising_edge = false;
return periods;
if (adc_val == 0) {
rising_edge = false;
return periods;
}
if (periods == max) return 0;
}
if (periods == max) return 0;
}
}
*/
*/
return 0;
}

View file

@ -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
@ -1245,7 +1255,7 @@ int lf_hid_watch(int findone, uint32_t *high, uint32_t *low) {
while (BUTTON_PRESS() == false) {
WDT_HIT();
// cancel w usb command.
if (interval == 4000) {
if (data_available()) {
@ -1262,7 +1272,7 @@ int lf_hid_watch(int findone, uint32_t *high, uint32_t *low) {
// FSK demodulator
// 50 * 128 * 2 - big enough to catch 2 sequences of largest format
size = MIN(12800, BigBuf_max_traceLen());
int idx = HIDdemodFSK(dest, &size, &hi2, &hi, &lo, &dummyIdx);
if (idx < 0) continue;
@ -1354,7 +1364,7 @@ int lf_awid_watch(int findone, uint32_t *high, uint32_t *low) {
while (BUTTON_PRESS() == false) {
WDT_HIT();
// cancel w usb command.
if (interval == 4000) {
if (data_available()) {
@ -1535,7 +1545,7 @@ int lf_io_watch(int findone, uint32_t *high, uint32_t *low) {
while (BUTTON_PRESS() == false) {
WDT_HIT();
// cancel w usb command.
if (interval == 4000) {
if (data_available()) {
@ -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);
}
LEDsoff();
}
void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) {
StartTicks();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0);
LED_A_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
ON(740) OFF(2035)
ON(3330) OFF(2035)
ON(740) OFF(2035)
ON(1000)
// 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(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);
case 0: {
doCotagAcquisition();
reply_ng(CMD_LF_COTAG_READ, PM3_SUCCESS, NULL, 0);
break;
case 1:
doCotagAcquisitionManchester();
}
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:
}
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();
}

View file

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

View file

@ -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) {
@ -171,7 +171,7 @@ void logSample(uint8_t sample, uint8_t decimation, uint8_t bits_per_sample, bool
// keep track of total gather samples regardless how many was discarded.
if (samples.counter-- == 0) return;
if (bits_per_sample == 0) bits_per_sample = 1;
if (bits_per_sample == 0) bits_per_sample = 1;
if (bits_per_sample > 8) bits_per_sample = 8;
if (decimation == 0) decimation = 1;
@ -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,20 +301,22 @@ 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_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) {
if (cancel_after > 0) {
cancel_counter++;
if (cancel_after == cancel_counter)
break;
if (trigger_hit == false) {
if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) {
if (cancel_after > 0) {
cancel_counter++;
if (cancel_after == cancel_counter)
break;
}
continue;
}
continue;
}
trigger_threshold = 0;
trigger_hit = true;
if (samples_to_skip > 0) {
samples_to_skip--;
@ -323,19 +328,20 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
if (samples.total_saved >= sample_size) break;
}
}
if (checked == -1 && verbose) {
Dbprintf("lf sampling aborted");
}
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);
}
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);
}
/**
@ -414,14 +428,14 @@ void doT55x7Acquisition(size_t sample_size) {
bool lowFound = false;
uint16_t checker = 0;
if (DBGLEVEL >= DBG_DEBUG) {
Dbprintf("doT55x7Acquisition - after init");
print_stack_usage();
}
while (skipCnt < 1000 && (i < bufsize)) {
if (BUTTON_PRESS())
break;
@ -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();
}
while ((i < bufsize) && (noise_counter < (COTAG_T1 << 1))) {
bool firsthigh = false, firstlow = false;
uint16_t i = 0, noise_counter = 0;
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;
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;
}
uint16_t i = 0;
uint16_t period = 0;
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;
}

View file

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

View file

@ -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);
@ -1644,7 +1663,7 @@ OUT:
bar |= ((uint16_t)(found[m] & 1) << j++);
}
uint8_t *tmp = BigBuf_malloc(480 + 10);
uint8_t *tmp = BigBuf_malloc(480 + 10);
memcpy(tmp, k_sector, sectorcnt * sizeof(sector_t));
num_to_bytes(foo, 8, tmp + 480);
tmp[488] = bar & 0xFF;
@ -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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View 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]);
}
}

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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) {
@ -117,47 +142,61 @@ uint32_t RAMFUNC GetCountUS(void) {
void StartCountSspClk(void) {
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1) | (1 << AT91C_ID_TC2); // Enable Clock to all timers
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_TIOA1 // XC0 Clock = TIOA1
| AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none
| AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0
| AT91C_TCB_TC1XC1S_NONE // XC1 Clock = none
| AT91C_TCB_TC2XC2S_TIOA0; // XC2 Clock = TIOA0
// configure TC1 to create a short pulse on TIOA1 when a rising edge on TIOB1 (= ssp_clk from FPGA) occurs:
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // disable TC1
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz
| AT91C_TC_CPCSTOP // Stop clock on RC compare
| AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event
| AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16)
| AT91C_TC_ENETRG // Enable external trigger event
| AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare
| 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_TC_CPCSTOP // Stop clock on RC compare
| AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event
| AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16)
| AT91C_TC_ENETRG // Enable external trigger event
| AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare
| 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 = 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
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_XC0 // TC0 clock = XC0 clock = TIOA1
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP // just count
| AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare
| AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP // just count
| AT91C_TC_ACPA_CLEAR // Clear TIOA0 on RA Compare
| AT91C_TC_ACPC_SET; // Set TIOA0 on RC Compare
AT91C_BASE_TC0->TC_RA = 1; // RA Compare value = 1; pulse width to TC2
AT91C_BASE_TC0->TC_RC = 0; // RC Compare value = 0; increment TC2 on overflow
// use TC2 to count TIOA0 pulses (giving us a 32bit counter (TC0/TC2) clocked by ssp_clk)
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS; // disable TC2
AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_XC2 // TC2 clock = XC2 clock = TIOA0
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP; // just count
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_WAVESEL_UP; // just count
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // enable and reset TC0
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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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
@ -207,4 +211,4 @@ target_link_libraries(pm3rrg_rdv4
pm3rrg_rdv4_reveng
pm3rrg_rdv4_whereami
android
log)
log)

View file

@ -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);
}
/*
@ -141,18 +141,18 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
}
jclass clz_test = (*jniEnv)->FindClass(jniEnv, "cn/rrg/devices/Proxmark3RRGRdv4");
JNINativeMethod methods[] = {
{"startExecute", "(Ljava/lang/String;)I", (void *) Console},
{"stopExecute", "()V", (void *) ClosePm3},
{"isExecuting", "()Z", (void *) IsClientRunning}
{"startExecute", "(Ljava/lang/String;)I", (void *) Console},
{"stopExecute", "()V", (void *) ClosePm3},
{"isExecuting", "()Z", (void *) IsClientRunning}
};
JNINativeMethod methods1[] = {
{"testPm3", "()Z", (void *) TestPm3},
{"closePm3", "()V", ClosePm3}
{"testPm3", "()Z", (void *) TestPm3},
{"closePm3", "()V", ClosePm3}
};
if ((*jniEnv)->RegisterNatives(jniEnv, clazz, methods, sizeof(methods) / sizeof(methods[0])) !=
JNI_OK) {
JNI_OK) {
return -1;
}
@ -164,4 +164,4 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
(*jniEnv)->DeleteLocalRef(jniEnv, clazz);
(*jniEnv)->DeleteLocalRef(jniEnv, clz_test);
return JNI_VERSION_1_4;
}
}

View file

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

View 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

View file

@ -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,8 +4529,13 @@ static void arg_cat_optionv(char *dest,
}
if (datatype) {
/* if (longopts)
arg_cat(&dest, "=", &ndest);
else if (shortopts)
arg_cat(&dest, " ", &ndest);
*/
if (longopts)
arg_cat(&dest, "=", &ndest);
arg_cat(&dest, " ", &ndest);
else if (shortopts)
arg_cat(&dest, " ", &ndest);

View file

@ -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,
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_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_u64 *arg_u64_1(const char *shortopts,
const char *longopts,
const char *datatype,
const char *glossary);
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,

View file

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

View file

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

View file

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

View file

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

View file

@ -174,7 +174,7 @@ crack_states_thread(void *x) {
char progress_text[80];
char keystr[19];
sprintf(keystr, "%012" PRIx64 " ", key);
sprintf(progress_text, "Brute force phase completed. Key found: " _YELLOW_("%s"), keystr);
sprintf(progress_text, "Brute force phase completed. Key found: " _YELLOW_("%s"), keystr);
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0);
break;
} else if (keys_found) {

View file

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

View file

@ -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,16 +427,20 @@ 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) {
@ -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

View file

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

View file

@ -42,3 +42,5 @@ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
100f0e0d0c0b0a090807060504030201
404142434445464748494a4b4c4d4e4f
303132333435363738393a3b3c3d3e3f
9CABF398358405AE2F0E2B3D31C99A8A # Default key
605F5E5D5C5B5A59605F5E5D5C5B5A59 # access control

View file

@ -27,4 +27,4 @@ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
100f0e0d0c0b0a090807060504030201
404142434445464748494a4b4c4d4e4f
303132333435363738393a3b3c3d3e3f
605F5E5D5C5B5A59605F5E5D5C5B5A59

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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