mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
Merge branch 'master' into bruteforce-smart-mode
This commit is contained in:
commit
8e0e8e2240
1273 changed files with 74746 additions and 17013 deletions
17
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
17
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
|
@ -9,7 +9,6 @@ assignees: doegox, iceman1001
|
|||
|
||||
# Checklist
|
||||
|
||||
- [ ] CHANGELOG.md: add title: `## [releasename][YYYY-MM-DD]`
|
||||
- [ ] `make style`
|
||||
- [ ] `make miscchecks`
|
||||
- [ ] `make clean; make client CC=clang CXX=clang++ LD=clang++` on recent Debian or Ubuntu
|
||||
|
@ -44,14 +43,24 @@ Run `tools/release_tests.sh` on:
|
|||
|
||||
# creating release
|
||||
|
||||
- [ ] `make release RELEASE_NAME="ice awesome"`
|
||||
- last line of output, gives you next command to run.
|
||||
- [ ] CHANGELOG.md: add title: `## [myreleasename][YYYY-MM-DD]`
|
||||
- [ ] `make release RELEASE_NAME="myreleasename"`
|
||||
- last line of output gives you next command to run.
|
||||
- Sample: `git push && git push origin v4.12345`
|
||||
- [ ] CHANGELOG.md: edit title to add version info: `## [releasename.4.12345][YYYY-MM-DD]`
|
||||
- [ ] CHANGELOG.md: edit title to add version info: `## [myreleasename.4.12345][YYYY-MM-DD]`
|
||||
|
||||
## Step Github releases
|
||||
|
||||
- [ ] Go to Github releases, create release based on the new created tag and publish
|
||||
- Choose a tag: v4.12345
|
||||
- Target: master
|
||||
- Set as the latest release
|
||||
- Title: `proxmark3-v4.12345`
|
||||
- Description:
|
||||
```
|
||||
Release v4.12345
|
||||
Nickname "myreleasename"
|
||||
```
|
||||
|
||||
## Step Homebrew updates
|
||||
|
||||
|
|
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
|
@ -41,7 +41,7 @@ jobs:
|
|||
run: sudo apt-get update
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
|
@ -70,7 +70,7 @@ jobs:
|
|||
env:
|
||||
V: 1
|
||||
PLATFORM_EXTRAS: BTADDON
|
||||
run: make
|
||||
run: make -j$((`nproc` + 1))
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
|
|
16
.github/workflows/macos.yml
vendored
16
.github/workflows/macos.yml
vendored
|
@ -35,7 +35,7 @@ jobs:
|
|||
run: brew tap RfidResearchGroup/proxmark3
|
||||
|
||||
- name: Install dependencies
|
||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
|
||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl gd
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Python dependencies
|
||||
|
@ -50,14 +50,12 @@ jobs:
|
|||
- name: Build
|
||||
env:
|
||||
V: 1
|
||||
run: make
|
||||
run: make -j$((`sysctl -n hw.ncpu` + 1))
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
macos-make-btaddon:
|
||||
if: always()
|
||||
needs: [macos-make]
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
|
@ -77,7 +75,7 @@ jobs:
|
|||
run: brew tap RfidResearchGroup/proxmark3
|
||||
|
||||
- name: Install dependencies
|
||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
|
||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl gd
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Python dependencies
|
||||
|
@ -93,14 +91,12 @@ jobs:
|
|||
env:
|
||||
V: 1
|
||||
PLATFORM_EXTRAS: BTADDON
|
||||
run: make
|
||||
run: make -j$((`sysctl -n hw.ncpu` + 1))
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
macos-cmake:
|
||||
if: always()
|
||||
needs: [macos-make, macos-make-btaddon]
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
|
@ -120,7 +116,7 @@ jobs:
|
|||
run: brew tap RfidResearchGroup/proxmark3
|
||||
|
||||
- name: Install dependencies
|
||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl
|
||||
run: brew install readline coreutils qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc openssl gd
|
||||
continue-on-error: true
|
||||
|
||||
- name: Install Python dependencies
|
||||
|
@ -144,7 +140,7 @@ jobs:
|
|||
- name: Build
|
||||
env:
|
||||
VERBOSE: 1
|
||||
run: make
|
||||
run: make -j$((`sysctl -n hw.ncpu` + 1))
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Test
|
||||
|
|
16
.github/workflows/ubuntu.yml
vendored
16
.github/workflows/ubuntu.yml
vendored
|
@ -26,7 +26,7 @@ jobs:
|
|||
run: sudo apt-get update
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev libgd-dev
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
|
@ -41,14 +41,12 @@ jobs:
|
|||
- name: Build
|
||||
env:
|
||||
V: 1
|
||||
run: make
|
||||
run: make -j$((`nproc` + 1))
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
ubuntu-make-btaddon:
|
||||
if: always()
|
||||
needs: [ubuntu-make]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
@ -58,7 +56,7 @@ jobs:
|
|||
run: sudo apt-get update
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev libgd-dev
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
|
@ -74,14 +72,12 @@ jobs:
|
|||
env:
|
||||
V: 1
|
||||
PLATFORM_EXTRAS: BTADDON
|
||||
run: make
|
||||
run: make -j$((`nproc` + 1))
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
ubuntu-cmake:
|
||||
if: always()
|
||||
needs: [ubuntu-make, ubuntu-make-btaddon]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
@ -91,7 +87,7 @@ jobs:
|
|||
run: sudo apt-get update
|
||||
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev
|
||||
run: sudo apt-get install -yqq make autoconf build-essential ca-certificates pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev qtbase5-dev libbz2-dev liblz4-dev libbluetooth-dev libpython3-dev python3 python3-dev libpython3-all-dev liblua5.2-dev liblua5.2-0 lua5.2 sed libssl-dev libgd-dev
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
|
@ -115,7 +111,7 @@ jobs:
|
|||
- name: Build
|
||||
env:
|
||||
VERBOSE: 1
|
||||
run: make
|
||||
run: make -j$((`nproc` + 1))
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Test
|
||||
|
|
5
.github/workflows/uniq.yaml
vendored
5
.github/workflows/uniq.yaml
vendored
|
@ -18,6 +18,5 @@ jobs:
|
|||
- name: check unique keys in dic files
|
||||
shell: bash
|
||||
run: |
|
||||
find . -type f -name "*.dic" | xargs -I {} sh -c "echo {} && cat {} | grep -v '#' | sort | uniq -i -d -c | sort -n -r "
|
||||
if [[ $(find . -type f -name "*.dic" | xargs -I {} sh -c "echo {} && cat {} | grep -v '#' | sort | uniq -i -d -c | sort -n -r " | grep -v "./" | wc -l) -gt 0 ]]; then exit 1; fi
|
||||
|
||||
find . -type f -name "*.dic" | xargs -I {} sh -c "echo {} && cat {} | sed 's/ *#.*//;/^$/d' | sort | uniq -i -d -c | sort -n -r "
|
||||
if [[ $(find . -type f -name "*.dic" | xargs -I {} sh -c "echo {} && cat {} | sed 's/ *#.*//;/^$/d' | sort | uniq -i -d -c | sort -n -r " | grep -v '^\./' | wc -l) -gt 0 ]]; then exit 1; fi
|
||||
|
|
14
.github/workflows/windows.yml
vendored
14
.github/workflows/windows.yml
vendored
|
@ -54,7 +54,7 @@ jobs:
|
|||
run: make clean
|
||||
|
||||
- name: Build
|
||||
run: make V=1
|
||||
run: make -j $([System.Environment]::ProcessorCount + 1) V=1
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
@ -63,7 +63,7 @@ jobs:
|
|||
run: make clean
|
||||
|
||||
- name: Build btaddon
|
||||
run: make V=1 PLATFORM_EXTRAS=BTADDON
|
||||
run: make -j $([System.Environment]::ProcessorCount + 1) V=1 PLATFORM_EXTRAS=BTADDON
|
||||
|
||||
- name: Test btaddon
|
||||
run: make check
|
||||
|
@ -84,7 +84,7 @@ jobs:
|
|||
working-directory: client/build/
|
||||
|
||||
- name: Build cmake
|
||||
run: make VERBOSE=1
|
||||
run: make -j $([System.Environment]::ProcessorCount + 1) VERBOSE=1
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Test cmake
|
||||
|
@ -110,6 +110,7 @@ jobs:
|
|||
gcc-arm-none-eabi
|
||||
libnewlib-dev
|
||||
libbz2-dev
|
||||
liblz4-dev
|
||||
qtbase5-dev
|
||||
cmake
|
||||
libpython3-dev
|
||||
|
@ -118,6 +119,7 @@ jobs:
|
|||
python3-dev
|
||||
libpython3-all-dev
|
||||
libssl-dev
|
||||
libgd-dev
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
|
@ -140,7 +142,7 @@ jobs:
|
|||
run: make clean
|
||||
|
||||
- name: Build
|
||||
run: make V=1
|
||||
run: make -j$((`nproc` + 1)) V=1
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
@ -149,7 +151,7 @@ jobs:
|
|||
run: make clean
|
||||
|
||||
- name: Build btaddon
|
||||
run: make V=1 PLATFORM_EXTRAS=BTADDON
|
||||
run: make -j$((`nproc` + 1)) V=1 PLATFORM_EXTRAS=BTADDON
|
||||
|
||||
- name: Test btaddon
|
||||
run: make check
|
||||
|
@ -170,7 +172,7 @@ jobs:
|
|||
working-directory: client/build/
|
||||
|
||||
- name: Build cmake
|
||||
run: make VERBOSE=1
|
||||
run: make -j$((`nproc` + 1)) VERBOSE=1
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Test cmake
|
||||
|
|
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -68,6 +68,7 @@ luac
|
|||
tools/fpga_compress/fpga_compress
|
||||
tools/mfkey/mfkey32
|
||||
tools/mfkey/mfkey64
|
||||
tools/mfkey/staticnested
|
||||
tools/nonce2key/nonce2key
|
||||
tools/cryptorf/cm
|
||||
tools/cryptorf/sm
|
||||
|
@ -79,18 +80,9 @@ tools/jtag_openocd/openocd_configuration
|
|||
tools/mfd_aes_brute/mfd_aes_brute
|
||||
tools/mfd_aes_brute/mfd_multi_brute
|
||||
tools/mfd_aes_brute/brute_key
|
||||
!tools/lena.bmp
|
||||
|
||||
fpga/*
|
||||
!fpga/tests
|
||||
!fpga/fpga_lf.bit
|
||||
!fpga/fpga_hf.bit
|
||||
!fpga/*.v
|
||||
!fpga/Makefile
|
||||
!fpga/fpga.ucf
|
||||
!fpga/xst_lf.scr
|
||||
!fpga/xst_hf.scr
|
||||
!fpga/go.bat
|
||||
!fpga/sim.tcl
|
||||
fpga/__build*
|
||||
|
||||
# offcial dumps folder
|
||||
dumps/*
|
||||
|
|
|
@ -6,7 +6,7 @@ Copyright (C) 2005-2007 Jonathan Westhues
|
|||
|
||||
Since then, each contribution is under the copyright of its respective author.
|
||||
|
||||
A few releases were done by the Proxmark community between 2007 and March 2009 before using version control.
|
||||
A few releases were done by the Proxmark3 community between 2007 and March 2009 before using version control.
|
||||
The last release which served as basis for version control, under SVN then migrated to Git, was the `20090306_ela` release by Edouard Lafargue. See the first commit of this repository.
|
||||
|
||||
Therefore, only the following copyright notices are left untouched in the corresponding files:
|
||||
|
|
205
CHANGELOG.md
205
CHANGELOG.md
|
@ -1,8 +1,191 @@
|
|||
# Change Log
|
||||
Change Log
|
||||
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]
|
||||
- Changed `prefs set client.debug` - now also toggles the client side APDU logging (@iceman1001)
|
||||
- Changed `hf 14b sriwrbl` - now supports --force to override block checks. Thanks @gentilkiwi for the idea! (@iceman1001)
|
||||
- Changed `hf 14b sriwrbl` - now tries to verify the write (@iceman1001)
|
||||
- Changed `hf 14b apdu` - now supports tearoff (@iceman1001)
|
||||
- Fixed `hf 14b raw` - fixed a potential write out of bounds. (@iceman1001)
|
||||
- Fixed `hf 14b` commands got some serious overhaul and love. Better return values and packet handling (@iceman1001)
|
||||
- Changed `hf waveshare` - image is automatically scaled and cropped to match panel size (@socram8888)
|
||||
- Changed `hf waveshare` - image loading and processing is now done using [GDlib](https://github.com/libgd/libgd) (@socram8888)
|
||||
- Added trace of sniffed SEOS traffic between reader and card (@iceman1001)
|
||||
- Change `hf seos list` - print crc and annotate better (@iceman1001)
|
||||
- Added troubleshooting entry - ARM architecture error (@francis2054)
|
||||
- Fixed `lf pyramid sim` - wrong parameter handling (@iceman1001)
|
||||
- Fixed bootloader - Ignore jitters when pressing the button (@wh201906)
|
||||
|
||||
## [Steamboat Willie.4.17768][2024-01-03]
|
||||
- Changed `mem spiffs dump -t` - now supports downloading direct into trace buffer (@hazardousvoltage)
|
||||
- Changed `hf search` - added hints for all HF protocols we search for (@iceman1001)
|
||||
- Changed `hf search` - added hint for iClass (@bettse)
|
||||
- Changed `hf 14a apdu` - It now uses the FWI and SGFI values from the ATS to determine an appropriate timeout (@nvx)
|
||||
- Added a thread to check when device comes online again. It will connect and update prompt (@iceman1001)
|
||||
- Changed CLI offline prompt - replaces the old prompt when offline is detected (@iceman100)
|
||||
- Changed `hf mf info` - it now uses found keys to try identify Gen2 cards (@iceman1001)
|
||||
- Changed `hf 14a info` - disabled debug logging while performing the magic tests (@iceman1001)
|
||||
- Changed `hf 14a info` - magic detection to better detect different GDM/USCUID configurations and improved Gen2/CUID detection when default keys are used (@nvx)
|
||||
- Changed `hf_cardhopper` - standalone mode to allow running over the internal Proxmark3 USB-CDC serial port (@nvx)
|
||||
- Fixed CLI prompt - Update connection type prompt after running `hw connect` (@wh201906)
|
||||
- Changed `uart_receive()` - Check if TCP connection is lost (@wh201906)
|
||||
- Change `data detectclock` - now tries all clocks if called w/o any params (@iceman1001)
|
||||
- Changed `lf search -1u` - improved the autocorrelation detection for unknown signals (@iceman1001)
|
||||
- Fixed `hf emrtd dump` stack smashing on device side (@iceman1001)
|
||||
- Changed `dbprint` on device side to use max 200 chars strings. (@iceman1001)
|
||||
- Fixed bootloader to correctly clear bss segment on start. Fixes USB serial number sometimes not working in the bootloader (@nvx)
|
||||
- Changed `notes on downgrade attacks` - reworked the original text follow repo style (@iceman1001)
|
||||
- Added `hf mf info` command and static encrypted nonce detection (@merlokk)
|
||||
- Added Saflok KDF - generate MFC keys (@h1kari)
|
||||
- Changed `lf fdx demod` - now raw bytes shows all data (@iceman1001)
|
||||
- Changed `data num` - now can print reversed and inverse (@iceman1001)
|
||||
- Fixed `hf mf sim -ix` never returning console (@datatags)
|
||||
- Added standalone mode `hf_unisniff` combining 14a/14b/15 sniffing with extra flash save options (@hazardousvoltage)
|
||||
- Added encryption and other SL3 functions for Mifare Plus - more to come (@team-orangeBlue)
|
||||
- Fixed the corrupted data in real-time sampling (@wh201906)
|
||||
- Added a slider in the plot window for navigation (@wh201906)
|
||||
- Fixed client build bug with Python 3.12 (@wh201906)
|
||||
- Fixed `ExchangeAPDUSC()` in `cmdsmartcard.c` to prevent client crash (@wh201906)
|
||||
- Added real-time LF sampling support (@wh201906)
|
||||
- Changed `hf 14a info` - now reads and prints QL88 sigantures (@iceman1001)
|
||||
- Fixed `hf iclass dump` truncating AA2 blocks and improve reliability (@nvx)
|
||||
- Added some info about UMC in "doc/magic_cards_notes.md" (@temskiy)
|
||||
- Added `hw bootloader` to reboot to the bootloader mode (@wh201906)
|
||||
|
||||
## [Faraday.4.17511][2023-11-13]
|
||||
- Fixed Python support of `experimental_client_with_swig` (@doegox)
|
||||
- Use proxmark3 as a generic smartcard reader with other software with `smart relay` (@gm3197)
|
||||
- Added `tools\mfkeys\staticnested` - program to recover static nested keys (@iceman1001)
|
||||
- Added `pm3_gen_dictionary.py` - python script to extract and save all keys from MFC dump files. (@iceman1001)
|
||||
- Changed `hf mfu info` - now detect MIFARE Ultralight AES (@iceman1001)
|
||||
- Changed `hf mf autopwn` - now supports multiple user supplied keys (@iceman1001)
|
||||
- Added `hf mf gchpwd` command for change Gen4 GTU card access password (@merlokk)
|
||||
- Added `--ms` option in `hw status` to specify the timeout of connection speed test (@wh201906)
|
||||
- Added `hf mf ginfo` command for get info about Gen4 GTU configuration (@merlokk)
|
||||
- Added support for loading Flipper PICOPASS dump files (@iceman1001)
|
||||
- Fixed unknown chip identification (@jmichelp)
|
||||
- Fixed `nfc decode` - now properly handles MFU dump files (@iceman1001)
|
||||
- Added support for loading Flipper MCT/MFU dump files (@iceman1001)
|
||||
- Changed `data bmap` - now default `-m` is 8 (@iceman1001)
|
||||
- Added support for NTAG424 cards. (@dankar)
|
||||
- Additional fixes to configcard code for keyroll mode based on nfc-iclass output (@Antiklesys)
|
||||
- Changed lf sampling - improved the performance (@yah01)
|
||||
- Added `bind` option for network connections to specify the outbound address and port (@wh201906)
|
||||
- Changed `lf em 4x05 dump` - now supports the `--ns` nosave parameter (@iceman1001)
|
||||
- Fixed some wrong synchronization waits in usb_write() to increase the communication speed (@wh201906)
|
||||
- Added new command `data bmap` - breaks down a hexvalue to a binary template (@iceman1001)
|
||||
- Changed aid_desfire.json - added entreis from the Metrodroid project (@iceman1001)
|
||||
- Changed mad.json - added entries from the Metrodroid project (@iceman1001)
|
||||
- Changed `hf iclass dump` - now allow no save of dumped data (@iceman1001)
|
||||
- Changed `hf iclass calcnewkey` - Added calculations for old key elite and new key non elite (@Antiklesys)
|
||||
- Changed the CLI prompt to show tcp/udp if used (@iceman1001)
|
||||
- Changed `hw ping` - now shows transfer time (@doegox)
|
||||
- Added `hf mf encodehid` - writes HID legacy credential to a empty MFC (@iceman1001)
|
||||
- Added `hf iclass sam` - Added support for HID SAM Picopass communications (@iceman1001)
|
||||
- Add support for quoted arguments in the CLI, allowing spaces in them which
|
||||
are removed automatically (@jmichelp)
|
||||
- Added UDP support on Windows (@wh201906)
|
||||
- Added client communication timeout to preferences (@iceman1001)
|
||||
- Added IPv6 support (@wh201906)
|
||||
- Fixed `lf hid clone --bin` - now correctly handles sentinel bits (@iceman1001)
|
||||
- Experimental UDP support in linux (@iceman1001, @wh201906)
|
||||
- Changed CI scripts to speed up the builds (@wh201906)
|
||||
- Changed the timeout of local TCP connections (@wh201906)
|
||||
- Finalized implementation of configcard generation for keyroll when cardhelper is not present (@Antiklesys)
|
||||
- Added documentation for compiling on iOS (@The-SamminAter)
|
||||
- Fixed `hf iclass wrbl` - pagemap bit map for secured is now handled better (@iceman1001)
|
||||
- Changed `hf iclass view/decrypt` to detect SIO lengths better and show if legacy credentials are encrypted (@nvx)
|
||||
- Changed the json file formats for mfc, 14b, 15, legic, cryptorf, ndef (@iceman1001)
|
||||
- Deprecated the EML file format when saving dump files. (@iceman1001)
|
||||
- Added `sim014.bin` - new sim module firmware v4.42 with improved ISO7816 Protocol T0 support (@gentilkiwi)
|
||||
- Added datasheet for sim module (@iceman1001)
|
||||
- Changed `smart raw --timeout` - allows for a custom timeout (@iceman1001)
|
||||
- Changed `lf t55 detectp1` - now also accepts 0xE039 Silicon Craft Tech as valid card (@iceman1001)
|
||||
- Fixed `utils.lua` library function "convertdectohex" wasn't working (@iceman1001)
|
||||
- Added `hf iclass creditepurse` command to allow crediting the epurse debit value (@nvx)
|
||||
- Modified `hf iclass configcard` to only support online mode (@Antiklesys)
|
||||
- Modified `hf iclass configcard` command to generate config cards without a cardhelper module by porting the contents of blocks 6 & 7 from nfc-iclass (@Antiklesys)
|
||||
- Fixed `hf iclass info` command showing incorrectly in offline mode (@Antiklesys)
|
||||
- The "doc/magic_cards_notes.md" file has been rebuilt, filled up, and so on. (@team-orangeBlue)
|
||||
|
||||
## [Raccoon.4.17140][2023-09-09]
|
||||
- Changed text and adjust pm3_test case for mf_aes_brute (@doegox)
|
||||
- Fix CPPChecker warnings (@doegox)
|
||||
- Fix TubmleWeed docker setup (@doegox)
|
||||
- Added default keys (@ernestask) (@craftbyte)
|
||||
- Fixed MFU authentication to send PACK correctly (@shallax)
|
||||
- Fixed list output when line has 16 bytes (@piru)
|
||||
- Changed AIDlist w new entries (@kormax)
|
||||
- Swapped to OE1 for Shallow modulation on RDV4. Thanks to @gentilkiwi for testing (@d18c7db)
|
||||
- Changed iClass SIO and Legacy credential detection to be more reliable (@nvx)
|
||||
- Add hf_cardhopper standalone mode for long-distance relay attacks (@startrekdude)
|
||||
- Added `hf iclass esetblk` - set iClass emulator memory block data (@nvx)
|
||||
- Added cryptorf regressiontests (@iceman1001)
|
||||
- Fixed `cryptorf/sma_multi` - local state used in multithread (@iceman1001)
|
||||
- Changed `fpga_compress` - better deallocation of memory and closing of file handles (@iceman1001)
|
||||
- Changed `hf search` - less swaps of fpga images on device side (@iceman1001)
|
||||
- Changed `mkversion.sh` - now regenerates version_pm3.c (and consequently the binaries) only when needed (@doegox)
|
||||
- Added `data atr` - a command to lookup ATR (@iceman1001)
|
||||
- Fixed bug in ATR lookup fct, thanks @DidierA (@iceman1001)
|
||||
- Updated ATR list (@iceman1001)
|
||||
- Changed `mem load -m` - now correctly erase all allocated flash memory (@iceman1001)
|
||||
- Fixed emulator quick dump to handle MFC Ev1 extra sectors (@iceman100)
|
||||
- Removed some empty dump files (@iceman1001)
|
||||
- Added a fct to choose fpga mode (@iceman1001)
|
||||
- Changed `hf mf eload/gsave` - fast uploading to emulator memory (@iceman1001)
|
||||
- Added empty dump files with keys for easy simulation (@iceman1001)
|
||||
- Added `hf 15 view` - view ISO15693 dump files (@iceman1001)
|
||||
- Fixed `hf iclass config` - now loops correct in keyroll generation (@iceman1001)
|
||||
- Added `hf iclass sam` - skeleton command (@iceman1001)
|
||||
- Changed `lf cotag demo` - a new decoder (@iceman1001)
|
||||
- Changed `hf legic view/eview/info` - now in verbose mode will print raw hex dump (@iceman1001)
|
||||
- Added new test for cotag demod using data commands in pm3_test.sh (@iceman1001)
|
||||
- Added new sample trace file for cotag w fc/272. Thanks s1acky! (@iceman1001)
|
||||
- Fixed `hf legic eload` - now it doesn't crash client (@doegox)
|
||||
- Changed `lf hitag *` - rework client side (@doegox)
|
||||
- Changed data commands to handle ask/nrz clocks above 256 (@iceman1001)
|
||||
- Added `data envelope` - almost acts like data askedgedetect (@iceman1001)
|
||||
- Added `data cthreshold` - acts like an inverted dirtythreshold command. Remove center values (@iceman1001)
|
||||
- Added `hf mfp list` - interprets MIFARE Plus commands in traces (@DidierA)
|
||||
- Changed `hf legic sim` - loop and return codes on deviceside updated to DEFINES (@iceman1001)
|
||||
- Changed `hf legic einfo` - now accepts the three different cardsizes as params (@iceman1001)
|
||||
- Fixed `lf cotag reader -1` - now doesn't fail (@iceman1001)
|
||||
- Added support for LZ4 compressed hardnested tables (@doegox)
|
||||
- Changed `emv reader -v` - now tries to print found transactions logs (@iceman1001)
|
||||
- Added ISO4217 currency lookup (@iceman1001)
|
||||
- Fixed bad free in loadfilebinarykey fct. Thanks to @gentilkiwi
|
||||
- Changed `emv reader -v` - now can decode track1/2 data if found (@iceman1001)
|
||||
- Added `emv reader` - act as a EMV reader (@iceman1001)
|
||||
- Added support for Apple Wallet NFC Passes with the Value Added Services protocol implementation (@gm3197)
|
||||
- Fixed compiling liblua on iOS (@The-SamminAter)
|
||||
- Changed `hf_mf_luxeo_dump.lua` - now have list of keys to iterate (@iceman1001)
|
||||
- Fixed the timeout of TCP connections (@wh201906)
|
||||
- Added `hw timeout` - make the connection timeout configurable (@wh201906)
|
||||
|
||||
## [Seven.4.16717][2023-06-25]
|
||||
- Change `hf 14a info` - now identifes QL88 tags (@iceman1001)
|
||||
- Added support for compiling on iOS (@The-SamminAter)
|
||||
- Fixed viewing MFC dump - border char is now white (@iceman1001)
|
||||
- Changed `data diff` - to print filenames in header if it fits (@iceman1001)
|
||||
- Changed viewing MFC dump files - it now colors ACL + GPB bytes (@iceman1001)
|
||||
- Added `hf mf supercard --furui` - now supports key recovery from Furui detection card. Thanks foxushka! (@iceman1001)
|
||||
- Added `hf topaz dump --ns` - now supports nosave param (@iceman1001)
|
||||
- Changed `hf topaz rdbl` - unified output (@iceman1001)
|
||||
- Fixed `hf topaz wrbl` - now supports tear off and write_nonerase command (@iceman1001)
|
||||
- Fixed `hf mf` commands (@iceman1001)
|
||||
- Fixed `hf mfp` commands (@iceman1001)
|
||||
- Added more default keys (@iceman1001) Thanks anon!
|
||||
- Fixed `pm3-flash-all` shell script now correctly identify the if running on outdated bootloader (@iceman1001)
|
||||
- Fixed `hf 15693/iclass sniff` trace timings (@nvx)
|
||||
- Fixed LegicCash segment handling in `hf_legic.lua` script (@jmichelp)
|
||||
- Fixed `trace list` - now handles marking of crc bytes w color a bit better (@iceman1001)
|
||||
- Changed `hf mfu pwdgen -r` - now generates pwd/pack for Philips Sonicare, thanks @ckuenzi, @atc1441 (@iceman1001)
|
||||
- Changed `hf mfu info` - now detects Philips Sonicare devices (@iceman1001)
|
||||
- Fixed truncated FPGA upload due to incorrect integer size variable (@d18c7db)
|
||||
- Changed `usart btfactory` - handles the new BT board with version "BT SPP V3.0" (@iceman1001)
|
||||
- Changed `hf mf eview --sk` - now can extract keys and save to file (@iceman1001)
|
||||
- Changed `hf mf view --sk` - now can extract keys and save to file (@iceman1001)
|
||||
- Changed `hf mf sim` - reduce 6ms threshold to 4ms for reset to idle #1974 (@net147)
|
||||
- Rebuilt the Spartan-2 `fpga_*.bit` files to include the `hi_iso14443a.v` update (@d18c7db)
|
||||
- Added minor orphaned change from `hi_iso14443a.v` in `fpga-xc3s100e` to `hi_iso14443a.v` in `fpga-xc2s30` (@d18c7db)
|
||||
|
@ -22,7 +205,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Changed `hf mf supercard` - Support editing UID and recovery of keys from second generation card (@AloneLiberty)
|
||||
- Added iClass credit key to default iClass key table and reorganized key order (@GuruSteve)
|
||||
- Changed `hf mf value` - ability to use transfer on different block (@AloneLiberty)
|
||||
- Change `hf mf dump --ns` - dump command now supports `no save` of MFC card memory (@iceman1001)
|
||||
- Changed `hf mf dump --ns` - dump command now supports `no save` of MFC card memory (@iceman1001)
|
||||
- Added `hf mf gdmsetcfg` - Supprt Gen4 GDM write configuration block (@iceman1001)
|
||||
- Added `hf mf gdmcfg` - Support Gen4 GDM read configuration block (@iceman1001)
|
||||
- Changed magic note to include a section about GDM tags (@iceman1001)
|
||||
|
@ -62,11 +245,13 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Added `hf legic info` command for other sources (@0xdeb)
|
||||
- Added `hf legic einfo` - views emulator menory (@0xdeb)
|
||||
- Changed `hf legic view` - now also print the decoded info of the dump file (@0xdeb)
|
||||
- Now `script run hf_mf_ultimatecard.lua -u` supports 10bytes UID (@alejandro12120)
|
||||
- Update documentation for installation on macOS with MacPorts (@linuxgemini)
|
||||
- Changed `script run hf_mf_ultimatecard.lua -u` to support 10bytes UID (@alejandro12120)
|
||||
- Updated documentation for installation on macOS with MacPorts (@linuxgemini)
|
||||
- Added possible Paxton id to hitag2 tag info output
|
||||
- Changed `hf mf sim` - reduce 50ms threshold to 6ms for reset to idle #1974 (@net147)
|
||||
- Update `amiibo_tools.lua` with new identifiers and create a python script `update_amiibo_tools_lua.py` to automate the process in the future. (@CorySolovewicz)
|
||||
- Added `lf paradox sim --fc --cn` - Simulates Paradox fob from facility code and card number (jerji)
|
||||
|
||||
|
||||
## [Nitride.4.16191][2023-01-29]
|
||||
- Changed `build_all_firmwares.sh` to fit GENERIC 256kb firmware images (@doegox)
|
||||
|
@ -83,11 +268,11 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Changed `hf mfu info` - now also does a simple OTP fingerprinting (@iceman1001)
|
||||
- Changed `hf mf wrbl` - now checks for strict readonly ACL's in the data to write (@iceman1001)
|
||||
- Changed `hf mf view` - verbose printing if strict readonly ACL's exists in dump file (@iceman1001)
|
||||
- Add command `piv authsign` to get a buffer signed by the selected key (@jmichelp)
|
||||
- Add command `piv scan` which tries to read all known containers on PIV (@jmichelp)
|
||||
- Add support for PIV commands, over wired and contactless interfaces (@jmichelp)
|
||||
- Add `--shallow` option to `hf iclass` reader commands to do shallow (ASK) reader modulation instead of OOK (@nvx)
|
||||
- Improved NXP SLI/SLIX series tag identification (@nvx)
|
||||
- Added command `piv authsign` to get a buffer signed by the selected key (@jmichelp)
|
||||
- Added command `piv scan` which tries to read all known containers on PIV (@jmichelp)
|
||||
- Added support for PIV commands, over wired and contactless interfaces (@jmichelp)
|
||||
- Added `--shallow` option to `hf iclass` reader commands to do shallow (ASK) reader modulation instead of OOK (@nvx)
|
||||
- Change and improved NXP SLI/SLIX series tag identification (@nvx)
|
||||
- Fixed buffer overflow in "lf em 4x05 sniff" (@HeinrichsH)
|
||||
- Fixed potential NULL array printing (@jmichelp)
|
||||
- Added PIV aid to resource file (@jmichelp)
|
||||
|
@ -216,6 +401,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Added new standalone mode `lf_em4100rsww` (@zabszk)
|
||||
- Fixed `hf 15 slixdisable` wrong pass id (@r1ddl3rz)
|
||||
- Added `script run hf_mf_hid_sim.lua` (@micsen)
|
||||
- Added flashmem support in `HF_14BSNIFF` standalone mode (@wh201906)
|
||||
- Changed `HF_14ASNIFF` standalone mode - now supports Proxmark3 without flashmem (@wh201906)
|
||||
|
||||
## [Frostbit.4.14831][2022-01-11]
|
||||
- Changed Wiegand format lookup - now case-insensitive (@iceman1001)
|
||||
|
|
25
Makefile
25
Makefile
|
@ -29,17 +29,17 @@ ifneq (,$(DESTDIR))
|
|||
endif
|
||||
endif
|
||||
|
||||
all clean install uninstall check: %: client/% bootrom/% armsrc/% recovery/% mfkey/% nonce2key/% mf_nonce_brute/% mfd_aes_brute/% fpga_compress/%
|
||||
all clean install uninstall check: %: client/% bootrom/% armsrc/% recovery/% mfkey/% nonce2key/% mf_nonce_brute/% mfd_aes_brute/% fpga_compress/% cryptorf/%
|
||||
# hitag2crack toolsuite is not yet integrated in "all", it must be called explicitly: "make hitag2crack"
|
||||
#all clean install uninstall check: %: hitag2crack/%
|
||||
|
||||
INSTALLTOOLS=pm3_eml2lower.sh pm3_eml2upper.sh pm3_mfdread.py pm3_mfd2eml.py pm3_eml2mfd.py pm3_amii_bin2eml.pl pm3_reblay-emulating.py pm3_reblay-reading.py
|
||||
INSTALLSIMFW=sim011.bin sim011.sha512.txt sim013.bin sim013.sha512.txt
|
||||
INSTALLSIMFW=sim011.bin sim011.sha512.txt sim013.bin sim013.sha512.txt sim014.bin sim014.sha512.txt
|
||||
INSTALLSCRIPTS=pm3 pm3-flash pm3-flash-all pm3-flash-bootrom pm3-flash-fullimage
|
||||
INSTALLSHARES=tools/jtag_openocd traces
|
||||
INSTALLDOCS=doc/*.md doc/md
|
||||
|
||||
install: all common/install
|
||||
install: common/install
|
||||
|
||||
common/install:
|
||||
$(info [@] Installing common resources to $(MYDESTDIR)$(PREFIX)...)
|
||||
|
@ -109,6 +109,9 @@ endif
|
|||
$(Q)-$(INSTALLSUDO) $(RMDIR_SOFT) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLSHARERELPATH)
|
||||
|
||||
# tests
|
||||
cryptorf/check: FORCE
|
||||
$(info [*] CHECK $(patsubst %/check,%,$@))
|
||||
$(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@)
|
||||
mfkey/check: FORCE
|
||||
$(info [*] CHECK $(patsubst %/check,%,$@))
|
||||
$(Q)$(BASH) tools/pm3_tests.sh $(CHECKARGS) $(patsubst %/check,%,$@)
|
||||
|
@ -145,6 +148,9 @@ common/check: FORCE
|
|||
check: common/check
|
||||
$(info [*] ALL CHECKS DONE)
|
||||
|
||||
cryptorf/%: FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C tools/cryptorf $(patsubst cryptorf/%,%,$@) DESTDIR=$(MYDESTDIR)
|
||||
mfkey/%: FORCE
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C tools/mfkey $(patsubst mfkey/%,%,$@) DESTDIR=$(MYDESTDIR)
|
||||
|
@ -170,7 +176,7 @@ client/%: FORCE cleanifplatformchanged
|
|||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C client $(patsubst client/%,%,$@) DESTDIR=$(MYDESTDIR)
|
||||
recovery/all: bootrom/all armsrc/all
|
||||
recovery/install: bootrom/all armsrc/all
|
||||
recovery/install: bootrom/install armsrc/install
|
||||
recovery/%: FORCE cleanifplatformchanged
|
||||
$(info [*] MAKE $@)
|
||||
$(Q)$(MAKE) --no-print-directory -C recovery $(patsubst recovery/%,%,$@) DESTDIR=$(MYDESTDIR)
|
||||
|
@ -196,6 +202,7 @@ help:
|
|||
@echo "+ recovery - Make bootrom and fullimage files for JTAG flashing"
|
||||
@echo
|
||||
@echo "+ client - Make only the OS-specific host client"
|
||||
@echo "+ cryptorf - Make tools/cryptorf"
|
||||
@echo "+ mfkey - Make tools/mfkey"
|
||||
@echo "+ nonce2key - Make tools/nonce2key"
|
||||
@echo "+ mf_nonce_brute - Make tools/mf_nonce_brute"
|
||||
|
@ -232,6 +239,8 @@ fullimage/uninstall: armsrc/uninstall
|
|||
|
||||
recovery: recovery/all
|
||||
|
||||
cryptorf: cryptorf/all
|
||||
|
||||
mfkey: mfkey/all
|
||||
|
||||
nonce2key: nonce2key/all
|
||||
|
@ -318,10 +327,10 @@ style:
|
|||
# Make sure python3 is installed
|
||||
@command -v python3 >/dev/null || ( echo "Please install 'python3' package first" ; exit 1 )
|
||||
# Update commands.json, patch port in case it was run under Windows
|
||||
[ -x client/proxmark3 ] && client/proxmark3 --fulltext | sed 's#com[0-9]#/dev/ttyacm0#'|python3 client/pyscripts/pm3_help2json.py - doc/commands.json
|
||||
[ -x client/proxmark3 ] && client/proxmark3 --fulltext | sed 's#com[0-9]#/dev/ttyACM0#'|python3 client/pyscripts/pm3_help2json.py - doc/commands.json
|
||||
|
||||
# Update the readline autocomplete autogenerated code
|
||||
[ -x client/proxmark3 ] && client/proxmark3 --fulltext | python3 client/pyscripts/pm3_help2list.py - client/src/pm3line_vocabulory.h
|
||||
[ -x client/proxmark3 ] && client/proxmark3 --fulltext | python3 client/pyscripts/pm3_help2list.py - client/src/pm3line_vocabulary.h
|
||||
|
||||
|
||||
# Detecting weird codepages and tabs.
|
||||
|
@ -370,10 +379,10 @@ release:
|
|||
# - Tagging temporarily...
|
||||
@git tag -a -m "Release $(VERSION) - $(RELEASE_NAME)" $(VERSION)
|
||||
# - Changing default version information based on new tag
|
||||
@$(SH) tools/mkversion.sh > common/default_version_pm3.c.tmp && $(MV) common/default_version_pm3.c.tmp common/default_version_pm3.c
|
||||
@$(SH) tools/mkversion.sh --force common/default_version_pm3.c
|
||||
# - Removing mkversion calls
|
||||
@sed -i 's#^.*\.\./tools/mkversion.sh.*|| #\t$$(Q)#' client/Makefile bootrom/Makefile armsrc/Makefile
|
||||
@sed -i '/COMMAND/s/sh .*|| //' client/CMakeLists.txt
|
||||
@sed -i '/COMMAND/s/sh .*|| //' client/CMakeLists.txt client/experimental_lib/CMakeLists.txt
|
||||
# - Deleting tag...
|
||||
@git tag -d $(VERSION)
|
||||
# - Amending commit...
|
||||
|
|
|
@ -75,7 +75,15 @@ else
|
|||
endif
|
||||
|
||||
ifeq ($(platform),Darwin)
|
||||
ifeq ($(shell uname -p),arm64)
|
||||
# The platform is iOS
|
||||
USE_BREW ?= 0
|
||||
# iOS refuses to compile unless this is set
|
||||
export IPHONEOS_DEPLOYMENT_TARGET=11.0
|
||||
else
|
||||
# M* macOS devices return arm
|
||||
USE_BREW ?= 1
|
||||
endif
|
||||
USE_MACPORTS ?= 0
|
||||
AR= /usr/bin/ar rcs
|
||||
RANLIB= /usr/bin/ranlib
|
||||
|
@ -132,6 +140,10 @@ ifeq ($(shell expr $(CC_VERSION) \>= 10), 1)
|
|||
endif
|
||||
endif
|
||||
ifeq ($(platform),Darwin)
|
||||
ifeq ($(shell uname -p),arm64)
|
||||
# iOS will refuse to compile without the minimum target of iOS 11.0
|
||||
DEFCFLAGS += -mios-version-min=11.0
|
||||
endif
|
||||
# their readline has strict-prototype issues
|
||||
DEFCFLAGS += -Wno-strict-prototypes
|
||||
# some warnings about braced initializers on structs we want to ignore
|
||||
|
@ -158,6 +170,8 @@ GCCEXTRACFLAGS += -Wold-style-declaration -Wno-error=old-style-declaration
|
|||
GCCEXTRACFLAGS += -Woverride-init
|
||||
GCCEXTRACFLAGS += -Wshift-negative-value
|
||||
GCCEXTRACFLAGS += -Wunused-but-set-parameter -Wno-error=unused-but-set-parameter
|
||||
# enable gcc static analysis
|
||||
GCCEXTRACFLAGS += -fanalyzer
|
||||
ifeq ($(GCCEXTRA),1)
|
||||
DEFCFLAGS += $(GCCEXTRACFLAGS) $(EXTRACFLAGS)
|
||||
endif
|
||||
|
|
|
@ -6,6 +6,7 @@ PLATFORM=PM3RDV4
|
|||
# If you want more than one PLATFORM_EXTRAS option, separate them by spaces:
|
||||
#PLATFORM_EXTRAS=BTADDON
|
||||
#PLATFORM_EXTRAS=FLASH
|
||||
#PLATFORM_EXTRAS=SMARTCARD
|
||||
#PLATFORM_EXTRAS=BTADDON FLASH
|
||||
#STANDALONE=LF_SAMYRUN
|
||||
|
||||
|
|
50
README.md
50
README.md
|
@ -1,4 +1,4 @@
|
|||
# Iceman Fork - Proxmark3 a RFID / NFC project.
|
||||
# Iceman Fork - Proxmark3
|
||||
|
||||
The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the vast majority of RFID tags on a global scale. Originally built by Jonathan Westhues, the device is now the goto tool for RFID Analysis for the enthusiast. Iceman repository is considered to be the pinnacle of features and functionality, enabling a huge range of extremely useful and convenient commands and LUA scripts to automate chip identification, penetration testing, and programming
|
||||
|
||||
|
@ -10,24 +10,25 @@ The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the
|
|||
|
||||
| Actions OSX CI | Actions Ubuntu CI | Actions Windows CI |
|
||||
|:--------------:|:------------------:|:------------------:|
|
||||
|  |  | [](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/windows.yml) |
|
||||
|
||||
| [](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/macos.yml) | [](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/ubuntu.yml) | [](https://github.com/RfidResearchGroup/proxmark3/actions/workflows/windows.yml) |
|
||||
|
||||
# Table of Contents
|
||||
1. [PROXMARK3 INSTALLATION AND OVERVIEW](#proxmark3-installation-and-overview)
|
||||
2. [Notes / helpful documents](#notes--helpful-documents)
|
||||
3. [How to build?](#how-to-build)
|
||||
1. [Proxmark3 RDV4](#proxmark3-rdv4)
|
||||
2. [Generic Proxmark3 platforms](#generic-proxmark3-platforms)
|
||||
4. [What has changed?](#what-has-changed)
|
||||
5. [Development](#development)
|
||||
6. [Supported operative systems](#supported-operative-systems)
|
||||
7. [Precompiled binaries](#precompiled-binaries)
|
||||
8. [Proxmark3 GUI](#proxmark3-gui)
|
||||
9. [Official channels](#official-channels)
|
||||
10. [Maintainers](#maintainers)
|
||||
11. [Citation](#citation)
|
||||
12. [Copyright and licensing terms](#copyright-and-licensing-terms)
|
||||
- [Iceman Fork - Proxmark3](#iceman-fork---proxmark3)
|
||||
- [Table of Contents](#table-of-contents)
|
||||
- [PROXMARK3 INSTALLATION AND OVERVIEW](#proxmark3-installation-and-overview)
|
||||
- [Notes / helpful documents](#notes--helpful-documents)
|
||||
- [How to build?](#how-to-build)
|
||||
- [Proxmark3 RDV4](#proxmark3-rdv4)
|
||||
- [Generic Proxmark3 platforms](#generic-proxmark3-platforms)
|
||||
- [What has changed?](#what-has-changed)
|
||||
- [Development](#development)
|
||||
- [Supported operative systems](#supported-operative-systems)
|
||||
- [Precompiled binaries](#precompiled-binaries)
|
||||
- [Proxmark3 GUI](#proxmark3-gui)
|
||||
- [Official channels](#official-channels)
|
||||
- [Maintainers](#maintainers)
|
||||
- [Citation](#citation)
|
||||
- [Copyright and licensing terms](#copyright-and-licensing-terms)
|
||||
|
||||
# PROXMARK3 INSTALLATION AND OVERVIEW
|
||||
|
||||
|
@ -35,11 +36,12 @@ The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the
|
|||
| :------------------: | :------------------: |
|
||||
| [Linux - Setup and Build](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) | [Compilation Instructions](/doc/md/Use_of_Proxmark/0_Compilation-Instructions.md)|
|
||||
| [Linux - Important notes on ModemManager](/doc/md/Installation_Instructions/ModemManager-Must-Be-Discarded.md) | [Validating Proxmark3 Client Functionality](/doc/md/Use_of_Proxmark/1_Validation.md)|
|
||||
| [Mac OS X - Homebrew & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/Mac-OS-X-Homebrew-Installation-Instructions.md) | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|
||||
| [Mac OS X - MacPorts](/doc/md/Installation_Instructions/Mac-OS-X-MacPorts-Installation-Instructions.md) | [Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|
||||
| [Mac OS X - Setup and Build](/doc/md/Installation_Instructions/Mac-OS-X-Compile-From-Source-Instructions.md) ||
|
||||
| [macOS - Homebrew & Upgrading HomeBrew Tap Formula](/doc/md/Installation_Instructions/macOS-Homebrew-Installation-Instructions.md) | [First Use and Verification](/doc/md/Use_of_Proxmark/2_Configuration-and-Verification.md)|
|
||||
| [macOS - MacPorts](/doc/md/Installation_Instructions/macOS-MacPorts-Installation-Instructions.md) | [Commands & Features](/doc/md/Use_of_Proxmark/3_Commands-and-Features.md)|
|
||||
| [macOS - Setup and Build](/doc/md/Installation_Instructions/macOS-Compile-From-Source-Instructions.md) ||
|
||||
| [Windows - Setup and Build](/doc/md/Installation_Instructions/Windows-Installation-Instructions.md) ||
|
||||
| [Termux / Android - Setup and Build](/doc/termux_notes.md) ||
|
||||
| [iOS - Setup and Build](/doc/md/Installation_Instructions/iOS-Installation-Instructions.md)
|
||||
| [Blue Shark Manual](/doc/bt_manual_v10.md) | [Command Cheat Sheet](/doc/cheatsheet.md)|
|
||||
| [Advanced Compilation Parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md) | [More Cheat Sheets](https://github.com/RfidResearchGroup/proxmark3/wiki/More-cheat-sheets)|
|
||||
| [Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md) | [Complete Client Command Set](/doc/commands.md) |
|
||||
|
@ -58,7 +60,7 @@ The Proxmark3 is the swiss-army tool of RFID, allowing for interactions with the
|
|||
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)|[Notes on Magic UID 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)|[Notes on clocks](/doc/clocks.md)|[Notes on MIFARE DESFire](/doc/desfire.md)|
|
||||
|[Notes on CIPURSE](/doc/cipurse.md)|[Notes on NDEF type4a](/doc/ndef_type4a.md)||
|
||||
|[Notes on CIPURSE](/doc/cipurse.md)|[Notes on NDEF type4a](/doc/ndef_type4a.md)|[Notes on downgrade attacks](/doc/hid_downgrade.md)|
|
||||
|
||||
# How to build?
|
||||
|
||||
|
@ -77,6 +79,7 @@ We define generic Proxmark3 platforms as following devices.
|
|||
- Ryscorp green PCB version
|
||||
- Radiowar black PCB version
|
||||
- numerous Chinese adapted versions of the RDV3 easy (kkmoon, PiSwords etc)
|
||||
- Proxmark3 SE (Second edition) (BLE enabled)
|
||||
|
||||
**Not supported**
|
||||
- ⚠ Proxmark Evolution (EVO)
|
||||
|
@ -96,8 +99,6 @@ We define generic Proxmark3 platforms as following devices.
|
|||
- **Note**: unknown device hw
|
||||
- ⚠ Proxmark3 Ultimate
|
||||
- **Note**: unknown device hw
|
||||
- ⚠ Proxmark3 SE
|
||||
- **Note**: unknown device hw
|
||||
|
||||
When it comes to these new unknown models we are depending on the community to report in if this repo works and what they did to make it work.
|
||||
|
||||
|
@ -184,7 +185,8 @@ This repo compiles nicely on
|
|||
- Windows/MinGW environment
|
||||
- Ubuntu, ParrotOS, Gentoo, Pentoo, Kali, NetHunter, Arch Linux, Fedora, Debian, Raspbian
|
||||
- Android / Termux
|
||||
- Mac OS X / Homebrew (or MacPorts, experimental) / Apple Silicon M1
|
||||
- macOS / Homebrew (or MacPorts, experimental) / Apple Silicon M1
|
||||
- iOS (Jailbroken, rootful)
|
||||
- Docker container
|
||||
- [ 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/)
|
||||
|
|
|
@ -69,8 +69,6 @@ static dmabuf8_t dma_8 = {
|
|||
.buf = NULL
|
||||
};
|
||||
|
||||
|
||||
|
||||
// trace related variables
|
||||
static uint32_t trace_len = 0;
|
||||
static bool tracing = true;
|
||||
|
@ -99,6 +97,11 @@ uint8_t *BigBuf_get_EM_addr(void) {
|
|||
|
||||
return emulator_memory;
|
||||
}
|
||||
|
||||
uint32_t BigBuf_get_hi(void) {
|
||||
return s_bigbuf_hi;
|
||||
}
|
||||
|
||||
/*
|
||||
uint32_t BigBuf_get_EM_size(void) {
|
||||
return CARD_MEMORY_SIZE;
|
||||
|
@ -129,7 +132,7 @@ void BigBuf_Clear_keep_EM(void) {
|
|||
// 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 (s_bigbuf_hi < chunksize)
|
||||
if (s_bigbuf_hi < (chunksize + 3))
|
||||
return NULL; // no memory left
|
||||
|
||||
chunksize = (chunksize + 3) & 0xfffc; // round to next multiple of 4
|
||||
|
@ -142,7 +145,7 @@ uint8_t *BigBuf_malloc(uint16_t chunksize) {
|
|||
uint8_t *BigBuf_calloc(uint16_t chunksize) {
|
||||
uint8_t *mem = BigBuf_malloc(chunksize);
|
||||
if (mem != NULL) {
|
||||
memset(mem, 0x00, chunksize);
|
||||
memset(mem, 0x00, ((chunksize + 3) & 0xfffc)); // round to next multiple of 4
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
@ -233,7 +236,7 @@ uint32_t BigBuf_get_traceLen(void) {
|
|||
by 'hf list -t raw', alternatively 'hf list -t <proto>' for protocol-specific
|
||||
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 reader2tag) {
|
||||
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, const uint8_t *parity, bool reader2tag) {
|
||||
if (tracing == false) {
|
||||
return false;
|
||||
}
|
||||
|
@ -290,7 +293,7 @@ bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_
|
|||
}
|
||||
|
||||
// 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) {
|
||||
bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, const uint8_t *parity, bool reader2tag) {
|
||||
uint32_t duration = ts_end - ts_start;
|
||||
duration /= 32;
|
||||
ts_end = ts_start + duration;
|
||||
|
@ -306,24 +309,31 @@ bool RAMFUNC LogTraceBits(const uint8_t *btBytes, uint16_t bitLen, uint32_t time
|
|||
}
|
||||
|
||||
// Emulator memory
|
||||
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length) {
|
||||
uint8_t emlSet(const uint8_t *data, uint32_t offset, uint32_t length) {
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
if (offset + length < CARD_MEMORY_SIZE) {
|
||||
if (offset + length <= CARD_MEMORY_SIZE) {
|
||||
memcpy(mem + offset, data, length);
|
||||
return 0;
|
||||
}
|
||||
Dbprintf("Error, trying to set memory outside of bounds! %d > %d", (offset + length), CARD_MEMORY_SIZE);
|
||||
Dbprintf("Error, trying to set memory outside of bounds! " _RED_("%d") " > %d", (offset + length), CARD_MEMORY_SIZE);
|
||||
return 1;
|
||||
}
|
||||
uint8_t emlGet(uint8_t *out, uint32_t offset, uint32_t length) {
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
if (offset + length <= CARD_MEMORY_SIZE) {
|
||||
memcpy(out, mem + offset, length);
|
||||
return 0;
|
||||
}
|
||||
Dbprintf("Error, trying to read memory outside of bounds! " _RED_("%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)
|
||||
if (toSend.buf == NULL) {
|
||||
toSend.buf = BigBuf_malloc(TOSEND_BUFFER_SIZE);
|
||||
|
||||
}
|
||||
return &toSend;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ uint8_t *BigBuf_get_addr(void);
|
|||
uint32_t BigBuf_get_size(void);
|
||||
uint8_t *BigBuf_get_EM_addr(void);
|
||||
uint16_t BigBuf_max_traceLen(void);
|
||||
uint32_t BigBuf_get_hi(void);
|
||||
|
||||
void BigBuf_initialize(void);
|
||||
void BigBuf_Clear(void);
|
||||
void BigBuf_Clear_ext(bool verbose);
|
||||
|
@ -51,11 +53,12 @@ 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 reader2tag);
|
||||
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, const uint8_t *parity, bool reader2tag);
|
||||
bool RAMFUNC LogTraceBits(const uint8_t *btBytes, uint16_t bitLen, uint32_t timestamp_start, uint32_t timestamp_end, bool reader2tag);
|
||||
bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, uint8_t *parity, bool reader2tag);
|
||||
bool LogTrace_ISO15693(const uint8_t *bytes, uint16_t len, uint32_t ts_start, uint32_t ts_end, const uint8_t *parity, bool reader2tag);
|
||||
|
||||
uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length);
|
||||
uint8_t emlSet(const uint8_t *data, uint32_t offset, uint32_t length);
|
||||
uint8_t emlGet(uint8_t *out, uint32_t offset, uint32_t length);
|
||||
|
||||
typedef struct {
|
||||
int max;
|
||||
|
|
|
@ -53,7 +53,7 @@ void LCDFill(unsigned char xs, unsigned char ys, unsigned char width, unsigned c
|
|||
}
|
||||
}
|
||||
|
||||
void LCDString(char *lcd_string, const char *font_style, unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor) {
|
||||
void LCDString(const char *lcd_string, const char *font_style, unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor) {
|
||||
unsigned int i;
|
||||
unsigned char mask = 0, px, py, xme, yme, offset;
|
||||
const char *data;
|
||||
|
|
|
@ -130,7 +130,7 @@ void LCDInit(void);
|
|||
void LCDReset(void);
|
||||
void LCDSetXY(unsigned char x, unsigned char y);
|
||||
void LCDSetPixel(unsigned char x, unsigned char y, unsigned char color);
|
||||
void LCDString(char *lcd_string, const char *font_style, unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor);
|
||||
void LCDString(const char *lcd_string, const char *font_style, unsigned char x, unsigned char y, unsigned char fcolor, unsigned char bcolor);
|
||||
void LCDFill(unsigned char xs, unsigned char ys, unsigned char width, unsigned char height, unsigned char color);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,13 +37,13 @@ APP_CFLAGS = $(PLATFORM_DEFS) \
|
|||
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c
|
||||
SRC_HF = hfops.c
|
||||
SRC_ISO15693 = iso15693.c iso15693tools.c
|
||||
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c
|
||||
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c sam_mfc.c sam_seos.c
|
||||
#UNUSED: mifaresniff.c
|
||||
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_cipherutils.c optimized_ikeys.c optimized_elite.c optimized_cipher.c
|
||||
SRC_ICLASS = iclass.c optimized_cipherutils.c optimized_ikeys.c optimized_elite.c optimized_cipher.c sam_picopass.c
|
||||
SRC_LEGIC = legicrf.c legicrfsim.c legic_prng.c
|
||||
SRC_NFCBARCODE = thinfilm.c
|
||||
|
||||
|
@ -103,9 +103,6 @@ endif
|
|||
# Generic standalone Mode injection of source code
|
||||
include Standalone/Makefile.inc
|
||||
|
||||
#the FPGA bitstream files. Note: order matters!
|
||||
FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit fpga_felica.bit fpga_hf_15.bit
|
||||
|
||||
#the lz4 source files required for decompressing the fpga config at run time
|
||||
SRC_LZ4 = lz4.c
|
||||
#additional defines required to compile lz4
|
||||
|
@ -184,10 +181,10 @@ showinfo:
|
|||
|
||||
.DELETE_ON_ERROR:
|
||||
|
||||
# version_pm3.c should be remade on every time fullimage.stage1.elf should be remade
|
||||
# version_pm3.c should be checked on every time fullimage.stage1.elf should be remade
|
||||
version_pm3.c: default_version_pm3.c $(OBJDIR)/fpga_version_info.o $(OBJDIR)/fpga_all.o $(THUMBOBJ) $(ARMOBJ) .FORCE
|
||||
$(info [-] GEN $@)
|
||||
$(Q)$(SH) ../tools/mkversion.sh > $@ || $(CP) $< $@
|
||||
$(info [-] CHECK $@)
|
||||
$(Q)$(SH) ../tools/mkversion.sh $@ || $(CP) $< $@
|
||||
|
||||
fpga_version_info.c: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
|
||||
$(info [-] GEN $@)
|
||||
|
|
|
@ -86,6 +86,9 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| HF_BOG | 14a sniff with ULC/ULEV1/NTAG auth |
|
||||
| (RDV4 only) | storing in flashmem - Bogito |
|
||||
+----------------------------------------------------------+
|
||||
| HF_CARDHOPPER | Relay 14a protocols over long distances|
|
||||
| (RDV4 only) | (w/ IP backbone) - Sam Haskins |
|
||||
+----------------------------------------------------------+
|
||||
| HF_COLIN | Mifare ultra fast sniff/sim/clone |
|
||||
| (RDV4 only) | - Colin Brigato |
|
||||
+----------------------------------------------------------+
|
||||
|
@ -119,6 +122,9 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| HF_TMUDFORD | Read and emulate 15 tags |
|
||||
| | - Tim Mudford |
|
||||
+----------------------------------------------------------+
|
||||
| HF_UNISNIFF | Sniff 14a/14b/15 (optionally to flash) |
|
||||
| | - hazardousvoltage |
|
||||
+----------------------------------------------------------+
|
||||
| HF_YOUNG | Mifare sniff/simulation |
|
||||
| | - Craig Young |
|
||||
+----------------------------------------------------------+
|
||||
|
@ -130,9 +136,9 @@ endef
|
|||
|
||||
STANDALONE_MODES := LF_SKELETON
|
||||
STANDALONE_MODES += LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RSWW LF_EM4100RWC LF_HIDBRUTE LF_HIDFCBRUTE LF_ICEHID LF_MULTIHID LF_NEDAP_SIM LF_NEXID LF_PROXBRUTE LF_PROX2BRUTE LF_SAMYRUN LF_THAREXDE
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_YOUNG
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_14BSNIFF HF_15SNIFF HF_AVEFUL HF_BOG HF_CARDHOPPER HF_COLIN HF_CRAFTBYTE HF_ICECLASS HF_LEGIC HF_LEGICSIM HF_MATTYRUN HF_MFCSIM HF_MSDSAL HF_REBLAY HF_TCPRST HF_TMUDFORD HF_UNISNIFF HF_YOUNG
|
||||
STANDALONE_MODES += DANKARMULTI
|
||||
STANDALONE_MODES_REQ_BT := HF_REBLAY
|
||||
STANDALONE_MODES_REQ_BT := HF_CARDHOPPER HF_REBLAY
|
||||
STANDALONE_MODES_REQ_SMARTCARD :=
|
||||
STANDALONE_MODES_REQ_FLASH := LF_HIDFCBRUTE LF_ICEHID LF_NEXID LF_THAREXDE HF_BOG HF_COLIN HF_ICECLASS HF_LEGICSIM HF_MFCSIM
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
|
||||
|
|
|
@ -97,6 +97,10 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_BOG,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_bog.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_CARDHOPPER
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_CARDHOPPER,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_cardhopper.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_COLIN
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_COLIN,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = vtsend.c hf_colin.c frozen.c nprintf.c
|
||||
|
@ -141,6 +145,10 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_TMUDFORD,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_tmudford.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_UNISNIFF
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_UNISNIFF,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_unisniff.c
|
||||
endif
|
||||
# WITH_STANDALONE_HF_YOUNG
|
||||
ifneq (,$(findstring WITH_STANDALONE_HF_YOUNG,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_young.c
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
* 1. mem spiffs dump -s hf_14asniff.trace -d hf_14asniff.trace
|
||||
* Copies trace data file from flash to your PC.
|
||||
*
|
||||
* 2. trace load hf_14asniff.trace
|
||||
* 2. trace load -f hf_14asniff.trace
|
||||
* Loads trace data from a file into PC-side buffers.
|
||||
*
|
||||
* 3. For ISO14a: trace list -t 14a -1
|
||||
|
@ -55,6 +55,7 @@
|
|||
* the lab connected to PM3 client before taking it into the field.
|
||||
*
|
||||
* To delete the trace data from flash:
|
||||
* mem spiffs remove -f hf_14asniff.trace
|
||||
*
|
||||
* Caveats / notes:
|
||||
* - Trace buffer will be cleared on starting stand-alone mode. Data in flash
|
||||
|
|
15
armsrc/Standalone/hf_14bsniff.c
Executable file → Normal file
15
armsrc/Standalone/hf_14bsniff.c
Executable file → Normal file
|
@ -14,9 +14,24 @@
|
|||
* - LED3: sniffed reader command, turns off when finished sniffing tag command
|
||||
* - LED4: unmounting/sync'ing flash (normally < 100ms)
|
||||
*
|
||||
* To retrieve trace data from flash:
|
||||
*
|
||||
* 1. mem spiffs dump -s hf_14bsniff.trace -d hf_14bsniff.trace
|
||||
* Copies trace data file from flash to your PC.
|
||||
*
|
||||
* 2. trace load -f hf_14bsniff.trace
|
||||
* Loads trace data from a file into PC-side buffers.
|
||||
*
|
||||
* 3. For ISO14a: trace list -t 14b -1
|
||||
*
|
||||
* Lists trace data from buffer without requesting it from PM3.
|
||||
*
|
||||
* This module emits debug strings during normal operation -- so try it out in
|
||||
* the lab connected to PM3 client before taking it into the field.
|
||||
*
|
||||
* To delete the trace data from flash:
|
||||
* mem spiffs remove -f hf_14bsniff.trace
|
||||
*
|
||||
* Caveats / notes:
|
||||
* - Trace buffer will be cleared on starting stand-alone mode.
|
||||
* - This module will terminate if the trace buffer is full.
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
* 1. mem spiffs dump -s hf_15693sniff.trace -d hf_15693sniff.trace
|
||||
* Copies trace data file from flash to your PC.
|
||||
*
|
||||
* 2. trace load hf_15693sniff.trace
|
||||
* 2. trace load -f hf_15693sniff.trace
|
||||
* Loads trace data from a file into PC-side buffers.
|
||||
*
|
||||
* 3. For ISO15693: trace list -t 15 -1
|
||||
|
@ -54,6 +54,7 @@
|
|||
* the lab connected to PM3 client before taking it into the field.
|
||||
*
|
||||
* To delete the trace data from flash:
|
||||
* mem spiffs remove -f hf_15693sniff.trace
|
||||
*
|
||||
* Caveats / notes:
|
||||
* - Trace buffer will be cleared on starting stand-alone mode. Data in flash
|
||||
|
|
|
@ -250,7 +250,7 @@ void RunMod(void) {
|
|||
} else if (state == STATE_EMUL) {
|
||||
uint16_t flags = FLAG_7B_UID_IN_DATA;
|
||||
|
||||
Dbprintf("Starting simulation, press pm3-button to stop and go back to search state.");
|
||||
Dbprintf("Starting simulation, press " _GREEN_("pm3 button") " to stop and go back to search state.");
|
||||
SimulateIso14443aTag(7, flags, card.uid, 0);
|
||||
|
||||
// Go back to search state if user presses pm3-button
|
||||
|
|
437
armsrc/Standalone/hf_cardhopper.c
Normal file
437
armsrc/Standalone/hf_cardhopper.c
Normal file
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
* hf_cardhopper standalone mode by Sam Haskins
|
||||
*
|
||||
* A component of our (me + Trevor Stevado) research on long-range relay
|
||||
* attacks against 14a-based protocols (as presented at DEF CON '31).
|
||||
* Works with a CardHopper (recommended) or BlueShark add-on.
|
||||
*
|
||||
* If you're reading this, you're clearly a very interesting person---
|
||||
* do reach out if you get any fun results? [ sam AT loudmouth DOT io ]
|
||||
* Good luck, and may the odds be ever in your favour!
|
||||
*
|
||||
* The companion Android app is available on our gitlab: gitlab.com/loudmouth-security
|
||||
*
|
||||
* For more information, see: https://media.defcon.org/DEF%20CON%2031/DEF%20CON%2031%20presentations/Trevor%20Stevado%20Sam%20Haskins%20-%20Unlocking%20Doors%20from%20Half%20a%20Continent%20Away.pdf
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "appmain.h"
|
||||
#include "BigBuf.h"
|
||||
#include "dbprint.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "iso14443a.h"
|
||||
#include "protocols.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "standalone.h"
|
||||
#include "ticks.h"
|
||||
#include "util.h"
|
||||
#include "usart.h"
|
||||
#include "cmd.h"
|
||||
#include "usb_cdc.h"
|
||||
|
||||
#ifdef CARDHOPPER_USB
|
||||
#define cardhopper_write usb_write
|
||||
#define cardhopper_read usb_read_ng
|
||||
#define cardhopper_data_available usb_poll_validate_length
|
||||
#else
|
||||
#define cardhopper_write usart_writebuffer_sync
|
||||
#define cardhopper_read usart_read_ng
|
||||
#define cardhopper_data_available usart_rxdata_available
|
||||
#endif
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" HF - Long-range relay 14a over serial<->IP - a.k.a. CardHopper (Sam Haskins)");
|
||||
}
|
||||
|
||||
|
||||
typedef struct PACKED {
|
||||
uint8_t len;
|
||||
uint8_t dat[255];
|
||||
} packet_t;
|
||||
|
||||
// Magic numbers
|
||||
static const uint8_t magicREAD[4] = "READ";
|
||||
static const uint8_t magicCARD[4] = "CARD";
|
||||
static const uint8_t magicEND [4] = "\xff" "END";
|
||||
static const uint8_t magicRSRT[7] = "RESTART";
|
||||
static const uint8_t magicERR [4] = "\xff" "ERR";
|
||||
static uint8_t magicACK [1] = "\xfe"; // is constant, but must be passed to API that doesn't like that
|
||||
|
||||
// Forward declarations
|
||||
static void become_reader(void);
|
||||
static void select_card(void);
|
||||
|
||||
static void become_card(void);
|
||||
static void prepare_emulation(uint8_t *, uint16_t *, uint8_t *, packet_t *);
|
||||
static void cook_ats(packet_t *, uint8_t, uint8_t);
|
||||
static bool try_use_canned_response(const uint8_t *, int, tag_response_info_t *);
|
||||
static void reply_with_packet(packet_t *);
|
||||
|
||||
static void read_packet(packet_t *);
|
||||
static void write_packet(packet_t *);
|
||||
|
||||
static bool GetIso14443aCommandFromReaderInterruptible(uint8_t *, uint8_t *, int *);
|
||||
|
||||
|
||||
void RunMod(void) {
|
||||
// Ensure debug logs don't polute stream
|
||||
#ifdef CARDHOPPER_USB
|
||||
g_reply_via_usb = false;
|
||||
#else
|
||||
g_reply_via_fpc = false;
|
||||
#endif
|
||||
|
||||
StandAloneMode();
|
||||
DbpString(_CYAN_("[@]") " CardHopper has started - waiting for mode");
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
// Indicate we are alive and in CardHopper
|
||||
LEDsoff();
|
||||
LED_A_ON();
|
||||
LED_D_ON();
|
||||
|
||||
while (1) {
|
||||
WDT_HIT();
|
||||
|
||||
packet_t modeRx = { 0 };
|
||||
read_packet(&modeRx);
|
||||
|
||||
if (memcmp(magicREAD, modeRx.dat, sizeof(magicREAD)) == 0) {
|
||||
DbpString(_CYAN_("[@]") " I am a READER. I talk to a CARD.");
|
||||
become_reader();
|
||||
} else if (memcmp(magicCARD, modeRx.dat, sizeof(magicCARD)) == 0) {
|
||||
DbpString(_CYAN_("[@]") " I am a CARD. I talk to a READER.");
|
||||
become_card();
|
||||
} else if (memcmp(magicEND, modeRx.dat, sizeof(magicEND)) == 0) {
|
||||
break;
|
||||
} else {
|
||||
DbpString(_YELLOW_("[!]") " unknown mode!");
|
||||
Dbhexdump(modeRx.len, modeRx.dat, true);
|
||||
}
|
||||
}
|
||||
|
||||
DbpString(_CYAN_("[@]") " exiting ...");
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
|
||||
static void become_reader(void) {
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
select_card(); // also sends UID, ATS
|
||||
|
||||
DbpString(_CYAN_("[@]") " entering reader main loop ...");
|
||||
packet_t packet = { 0 };
|
||||
packet_t *rx = &packet;
|
||||
packet_t *tx = &packet;
|
||||
uint8_t toCard[256] = { 0 };
|
||||
uint8_t parity[MAX_PARITY_SIZE] = { 0 };
|
||||
|
||||
while (1) {
|
||||
WDT_HIT();
|
||||
|
||||
read_packet(rx);
|
||||
if (memcmp(magicRSRT, rx->dat, sizeof(magicRSRT)) == 0) break;
|
||||
|
||||
memcpy(toCard, rx->dat, rx->len);
|
||||
AddCrc14A(toCard, rx->len);
|
||||
ReaderTransmit(toCard, rx->len + 2, NULL);
|
||||
|
||||
tx->len = ReaderReceive(tx->dat, parity);
|
||||
if (tx->len == 0) {
|
||||
tx->len = sizeof(magicERR);
|
||||
memcpy(tx->dat, magicERR, sizeof(magicERR));
|
||||
} else tx->len -= 2; // cut off the CRC
|
||||
|
||||
write_packet(tx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void select_card(void) {
|
||||
iso14a_card_select_t card = { 0 };
|
||||
while (1) {
|
||||
WDT_HIT();
|
||||
|
||||
int ret = iso14443a_select_card(NULL, &card, NULL, true, 0, false);
|
||||
if (ret && ret != 1)
|
||||
Dbprintf(_RED_("[!]") " Error selecting card: %d", ret);
|
||||
if (ret == 1) break;
|
||||
|
||||
SpinDelay(20);
|
||||
}
|
||||
|
||||
DbpString(_CYAN_("[@]") " UID:");
|
||||
Dbhexdump(card.uidlen, card.uid, false);
|
||||
DbpString(_CYAN_("[@]") " ATS:");
|
||||
Dbhexdump(card.ats_len - 2 /* no CRC */, card.ats, false);
|
||||
|
||||
packet_t tx = { 0 };
|
||||
tx.len = card.uidlen;
|
||||
memcpy(tx.dat, card.uid, tx.len);
|
||||
write_packet(&tx);
|
||||
|
||||
tx.len = card.ats_len - 2;
|
||||
memcpy(tx.dat, card.ats, tx.len);
|
||||
write_packet(&tx);
|
||||
}
|
||||
|
||||
|
||||
static void become_card(void) {
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
|
||||
|
||||
uint8_t tagType;
|
||||
uint16_t flags;
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = { 0 };
|
||||
packet_t ats = { 0 };
|
||||
prepare_emulation(&tagType, &flags, data, &ats);
|
||||
|
||||
tag_response_info_t *canned;
|
||||
uint32_t cuid;
|
||||
uint32_t counters[3] = { 0 };
|
||||
uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd };
|
||||
uint8_t pages;
|
||||
SimulateIso14443aInit(tagType, flags, data, &canned, &cuid, counters, tearings, &pages);
|
||||
|
||||
DbpString(_CYAN_("[@]") " Setup done - entering emulation loop");
|
||||
int fromReaderLen;
|
||||
uint8_t fromReaderDat[256] = { 0 };
|
||||
uint8_t parity[MAX_PARITY_SIZE] = { 0 };
|
||||
packet_t packet = { 0 };
|
||||
packet_t *tx = &packet;
|
||||
packet_t *rx = &packet;
|
||||
|
||||
while (1) {
|
||||
WDT_HIT();
|
||||
|
||||
if (!GetIso14443aCommandFromReaderInterruptible(fromReaderDat, parity, &fromReaderLen)) {
|
||||
if (cardhopper_data_available()) {
|
||||
read_packet(rx);
|
||||
if (memcmp(magicRSRT, rx->dat, sizeof(magicRSRT)) == 0) {
|
||||
DbpString(_CYAN_("[@]") " Breaking from reader loop");
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Option 1: Use a canned response
|
||||
if (try_use_canned_response(fromReaderDat, fromReaderLen, canned)) continue;
|
||||
|
||||
// Option 2: Reply with our cooked ATS
|
||||
if (fromReaderDat[0] == ISO14443A_CMD_RATS && fromReaderLen == 4) {
|
||||
reply_with_packet(&ats);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Option 3: Relay the message
|
||||
tx->len = fromReaderLen - 2; // cut off the crc
|
||||
memcpy(tx->dat, fromReaderDat, tx->len);
|
||||
write_packet(tx);
|
||||
|
||||
read_packet(rx);
|
||||
reply_with_packet(rx);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void prepare_emulation(uint8_t *tagType, uint16_t *flags, uint8_t *data, packet_t *ats) {
|
||||
packet_t tagTypeRx = { 0 };
|
||||
read_packet(&tagTypeRx);
|
||||
packet_t timeModeRx = { 0 };
|
||||
read_packet(&timeModeRx);
|
||||
packet_t uidRx = { 0 };
|
||||
read_packet(&uidRx);
|
||||
read_packet(ats);
|
||||
|
||||
*tagType = tagTypeRx.dat[0];
|
||||
Dbprintf(_CYAN_("[@]") " Using tag type: %hhu", *tagType);
|
||||
|
||||
DbpString(_CYAN_("[@]") " Time control parameters:");
|
||||
Dbhexdump(timeModeRx.len, timeModeRx.dat, false);
|
||||
uint8_t fwi = timeModeRx.dat[0] & 0x0f;
|
||||
uint8_t sfgi = timeModeRx.dat[1] & 0x0f;
|
||||
Dbprintf(_CYAN_("[@]") " Parsed as fwi = %hhu, sfgi = %hhu", fwi, sfgi);
|
||||
|
||||
if (fwi == 0xf) {
|
||||
DbpString(_YELLOW_("[!]") " Refusing to use 15 as FWI - will use 14");
|
||||
fwi = 0xe;
|
||||
}
|
||||
if (sfgi == 0xf) {
|
||||
DbpString(_YELLOW_("[!]") " Refusing to use 15 as SFGI - will use 14");
|
||||
sfgi = 0xe;
|
||||
}
|
||||
|
||||
memcpy(data, uidRx.dat, uidRx.len);
|
||||
*flags = (uidRx.len == 10 ? FLAG_10B_UID_IN_DATA : (uidRx.len == 7 ? FLAG_7B_UID_IN_DATA : FLAG_4B_UID_IN_DATA));
|
||||
DbpString(_CYAN_("[@]") " UID:");
|
||||
Dbhexdump(uidRx.len, data, false);
|
||||
Dbprintf(_CYAN_("[@]") " Flags: %hu", *flags);
|
||||
|
||||
DbpString(_CYAN_("[@]") " Original ATS:");
|
||||
Dbhexdump(ats->len, ats->dat, false);
|
||||
cook_ats(ats, fwi, sfgi);
|
||||
DbpString(_CYAN_("[@]") " Cooked ATS:");
|
||||
Dbhexdump(ats->len, ats->dat, false);
|
||||
}
|
||||
|
||||
|
||||
static void cook_ats(packet_t *ats, uint8_t fwi, uint8_t sfgi) {
|
||||
if (ats->len != ats->dat[0]) {
|
||||
DbpString(_RED_("[!]") " Malformed ATS - unable to cook; things may go wrong!");
|
||||
return;
|
||||
}
|
||||
|
||||
// If the ATS is too short (unusual), pad it to length with hopefully-sensible data
|
||||
// Might be better for the phone side to do this tbh
|
||||
if (ats->len == 1) {
|
||||
ats->len = 4;
|
||||
ats->dat[0] = 0x04;
|
||||
ats->dat[1] = 0x78;
|
||||
ats->dat[2] = 0x77;
|
||||
// ats->dat[3] = 0x80;
|
||||
} else if (ats->len == 2) {
|
||||
ats->len = 4;
|
||||
ats->dat[0] = 0x04;
|
||||
ats->dat[2] = 0x77;
|
||||
// ats->dat[3] = 0x80;
|
||||
} else if (ats->len == 3) {
|
||||
ats->len = 4;
|
||||
ats->dat[0] = 0x04;
|
||||
// ats->dat[3] = 0x80;
|
||||
}
|
||||
|
||||
// Set the SFGI as well as the FWI - needed for some older readers (firmware revs?)
|
||||
uint8_t cookedTB0 = (fwi << 4) | sfgi;
|
||||
ats->dat[3] = cookedTB0;
|
||||
}
|
||||
|
||||
|
||||
static bool try_use_canned_response(const uint8_t *dat, int len, tag_response_info_t *canned) {
|
||||
if ((dat[0] == ISO14443A_CMD_REQA || dat[0] == ISO14443A_CMD_WUPA) && len == 1) {
|
||||
EmSendPrecompiledCmd(canned + RESP_INDEX_ATQA);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (dat[1] == 0x20 && len == 2) {
|
||||
if (dat[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) {
|
||||
EmSendPrecompiledCmd(canned + RESP_INDEX_UIDC1);
|
||||
return true;
|
||||
} else if (dat[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) {
|
||||
EmSendPrecompiledCmd(canned + RESP_INDEX_UIDC2);
|
||||
return true;
|
||||
} else if (dat[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3) {
|
||||
EmSendPrecompiledCmd(canned + RESP_INDEX_UIDC3);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (dat[1] == 0x70 && len == 9) {
|
||||
if (dat[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT) {
|
||||
EmSendPrecompiledCmd(canned + RESP_INDEX_SAKC1);
|
||||
return true;
|
||||
} else if (dat[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2) {
|
||||
EmSendPrecompiledCmd(canned + RESP_INDEX_SAKC2);
|
||||
return true;
|
||||
} else if (dat[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_3) {
|
||||
EmSendPrecompiledCmd(canned + RESP_INDEX_SAKC3);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (dat[0] == ISO14443A_CMD_PPS) {
|
||||
EmSendPrecompiledCmd(canned + RESP_INDEX_PPS);
|
||||
return true;
|
||||
}
|
||||
|
||||
// No response is expected to these 14a commands
|
||||
if ((dat[0] == 0xf2 && len == 4) || dat[0] == 0xfa) return true;
|
||||
if (dat[0] == ISO14443A_CMD_HALT && len == 4) return true;
|
||||
|
||||
// Ignore Apple ECP2 polling
|
||||
if (dat[0] == 0x6a) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static uint8_t g_responseBuffer [512 ] = { 0 };
|
||||
static uint8_t g_modulationBuffer[1024] = { 0 };
|
||||
|
||||
static void reply_with_packet(packet_t *packet) {
|
||||
tag_response_info_t response = { 0 };
|
||||
response.response = g_responseBuffer;
|
||||
response.modulation = g_modulationBuffer;
|
||||
|
||||
memcpy(response.response, packet->dat, packet->len);
|
||||
AddCrc14A(response.response, packet->len);
|
||||
response.response_n = packet->len + 2;
|
||||
|
||||
prepare_tag_modulation(&response, sizeof(g_modulationBuffer));
|
||||
EmSendPrecompiledCmd(&response);
|
||||
}
|
||||
|
||||
|
||||
static void read_packet(packet_t *packet) {
|
||||
while (!cardhopper_data_available()) {
|
||||
WDT_HIT();
|
||||
SpinDelayUs(100);
|
||||
}
|
||||
|
||||
cardhopper_read((uint8_t *) &packet->len, 1);
|
||||
|
||||
uint32_t dataReceived = 0;
|
||||
while (dataReceived != packet->len) {
|
||||
while (!cardhopper_data_available()) WDT_HIT();
|
||||
|
||||
dataReceived += cardhopper_read(packet->dat + dataReceived, packet->len - dataReceived);
|
||||
}
|
||||
cardhopper_write(magicACK, sizeof(magicACK));
|
||||
}
|
||||
|
||||
|
||||
static void write_packet(packet_t *packet) {
|
||||
cardhopper_write((uint8_t *) packet, packet->len + 1);
|
||||
}
|
||||
|
||||
|
||||
static bool GetIso14443aCommandFromReaderInterruptible(uint8_t *received, uint8_t *par, int *len) {
|
||||
LED_D_OFF();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN);
|
||||
|
||||
Uart14aInit(received, par);
|
||||
|
||||
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
(void)b;
|
||||
|
||||
uint8_t flip = 0;
|
||||
uint16_t checker = 4000;
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
if (flip == 3) {
|
||||
if (cardhopper_data_available())
|
||||
return false;
|
||||
|
||||
flip = 0;
|
||||
}
|
||||
|
||||
if (checker-- == 0) {
|
||||
flip++;
|
||||
checker = 4000;
|
||||
}
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
if (MillerDecoding(b, 0)) {
|
||||
*len = GetUart14a()->len;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -293,7 +293,7 @@ static void ReadLastTagFromFlash(void) {
|
|||
rdv40_spiffs_read_as_filetype((char *)HFCOLIN_LASTTAG_SYMLINK, (uint8_t *)mem, len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
||||
// copy 64blocks (16bytes) starting w block0, to emulator mem.
|
||||
emlSetMem(mem, 0, 64);
|
||||
emlSetMem_xt(mem, 0, 64, 16);
|
||||
|
||||
DbprintfEx(FLAG_NEWLINE, "[OK] Last tag recovered from FLASHMEM set to emulator");
|
||||
cjSetCursLeft();
|
||||
|
@ -650,7 +650,7 @@ failtag:
|
|||
for (uint8_t t = 0; t < 2; t++) {
|
||||
memcpy(mblock + t * 10, foundKey[t][sectorNo], 6);
|
||||
}
|
||||
emlSetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
|
||||
emlSetMem_xt(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1, 16);
|
||||
}
|
||||
cjSetCursLeft();
|
||||
|
||||
|
@ -821,24 +821,24 @@ int e_MifareECardLoad(uint32_t numofsectors, uint8_t keytype) {
|
|||
}
|
||||
|
||||
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(s); blockNo++) {
|
||||
if (isOK && mifare_classic_readblock(pcs, colin_cjcuid, FirstBlockOfSector(s) + blockNo, dataoutbuf)) {
|
||||
if (isOK && mifare_classic_readblock(pcs, FirstBlockOfSector(s) + blockNo, dataoutbuf)) {
|
||||
isOK = false;
|
||||
break;
|
||||
};
|
||||
if (isOK) {
|
||||
if (blockNo < NumBlocksPerSector(s) - 1) {
|
||||
emlSetMem(dataoutbuf, FirstBlockOfSector(s) + blockNo, 1);
|
||||
emlSetMem_xt(dataoutbuf, FirstBlockOfSector(s) + blockNo, 1, 16);
|
||||
} else {
|
||||
// sector trailer, keep the keys, set only the AC
|
||||
emlGetMem(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1);
|
||||
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
|
||||
emlSetMem(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1);
|
||||
emlSetMem_xt(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int res = mifare_classic_halt(pcs, colin_cjcuid);
|
||||
int res = mifare_classic_halt(pcs);
|
||||
(void)res;
|
||||
|
||||
crypto1_deinit(pcs);
|
||||
|
@ -986,7 +986,7 @@ int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *data
|
|||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_halt(NULL, colin_cjcuid)) {
|
||||
if (mifare_classic_halt(NULL)) {
|
||||
DbprintfEx(FLAG_NEWLINE, "Halt error");
|
||||
break;
|
||||
};
|
||||
|
@ -1006,7 +1006,7 @@ int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *data
|
|||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_halt(NULL, colin_cjcuid)) {
|
||||
if (mifare_classic_halt(NULL)) {
|
||||
DbprintfEx(FLAG_NEWLINE, "Halt error");
|
||||
break;
|
||||
};
|
||||
|
@ -1043,7 +1043,7 @@ int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *data
|
|||
};
|
||||
|
||||
if (workFlags & 0x04) {
|
||||
if (mifare_classic_halt(NULL, colin_cjcuid)) {
|
||||
if (mifare_classic_halt(NULL)) {
|
||||
cjSetCursFRight();
|
||||
|
||||
DbprintfEx(FLAG_NEWLINE, "Halt error");
|
||||
|
|
|
@ -91,7 +91,7 @@ void RunMod(void) {
|
|||
continue;
|
||||
}
|
||||
|
||||
Dbprintf("Starting simulation, press pm3-button to stop and go back to search state.");
|
||||
Dbprintf("Starting simulation, press " _GREEN_("pm3 button") " to stop and go back to search state.");
|
||||
if (card.sak == 0x08 && card.atqa[0] == 0x04 && card.atqa[1] == 0) {
|
||||
DbpString("Mifare Classic 1k");
|
||||
SimulateIso14443aTag(1, flags, card.uid, 0);
|
||||
|
|
|
@ -69,7 +69,6 @@
|
|||
#define HF_ICALSSS_READSIM_TEMP_MOD_BIN "iceclass-temp-mod.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"
|
||||
|
@ -117,10 +116,6 @@ 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_t *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,
|
||||
|
|
|
@ -68,8 +68,10 @@ static bool fill_eml_from_file(char *dumpfile) {
|
|||
}
|
||||
//read and load dump file
|
||||
BigBuf_Clear();
|
||||
if (g_dbglevel >= DBG_INFO)
|
||||
Dbprintf(_YELLOW_("Found dump file %s. Uploading to emulator memory..."), dumpfile);
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf("Found dump file... `" _YELLOW_("%s") "`", dumpfile);
|
||||
Dbprintf("Uploading to emulator memory...");
|
||||
}
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
rdv40_spiffs_read_as_filetype(dumpfile, emCARD, size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
return true;
|
||||
|
|
|
@ -109,7 +109,7 @@ static int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_
|
|||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_halt(NULL, mattyrun_cuid)) {
|
||||
if (mifare_classic_halt(NULL)) {
|
||||
DbprintfEx(FLAG_NEWLINE, "Halt error");
|
||||
break;
|
||||
};
|
||||
|
@ -129,7 +129,7 @@ static int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_
|
|||
break;
|
||||
};
|
||||
|
||||
if (mifare_classic_halt(NULL, mattyrun_cuid)) {
|
||||
if (mifare_classic_halt(NULL)) {
|
||||
DbprintfEx(FLAG_NEWLINE, "Halt error");
|
||||
break;
|
||||
};
|
||||
|
@ -165,7 +165,7 @@ static int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_
|
|||
};
|
||||
|
||||
if (workFlags & 0x04) {
|
||||
if (mifare_classic_halt(NULL, mattyrun_cuid)) {
|
||||
if (mifare_classic_halt(NULL)) {
|
||||
DbprintfEx(FLAG_NEWLINE, "Halt error");
|
||||
break;
|
||||
};
|
||||
|
@ -267,23 +267,23 @@ static int saMifareECardLoad(uint32_t numofsectors, uint8_t keytype) {
|
|||
|
||||
// failure to read one block, skips to next sector.
|
||||
for (uint8_t blockNo = 0; blockNo < NumBlocksPerSector(s); blockNo++) {
|
||||
if (mifare_classic_readblock(pcs, mattyrun_cuid, FirstBlockOfSector(s) + blockNo, dataoutbuf)) {
|
||||
if (mifare_classic_readblock(pcs, FirstBlockOfSector(s) + blockNo, dataoutbuf)) {
|
||||
retval = PM3_ESOFT;
|
||||
break;
|
||||
};
|
||||
|
||||
if (blockNo < NumBlocksPerSector(s) - 1) {
|
||||
emlSetMem(dataoutbuf, FirstBlockOfSector(s) + blockNo, 1);
|
||||
emlSetMem_xt(dataoutbuf, FirstBlockOfSector(s) + blockNo, 1, 16);
|
||||
} else {
|
||||
// sector trailer, keep the keys, set only the AC
|
||||
emlGetMem(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1);
|
||||
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
|
||||
emlSetMem(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1);
|
||||
emlSetMem_xt(dataoutbuf2, FirstBlockOfSector(s) + blockNo, 1, 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int res = mifare_classic_halt(pcs, mattyrun_cuid);
|
||||
int res = mifare_classic_halt(pcs);
|
||||
(void)res;
|
||||
|
||||
out:
|
||||
|
@ -505,7 +505,7 @@ void RunMod(void) {
|
|||
memcpy(mblock + t * 10, foundKey[t][sectorNo], 6);
|
||||
}
|
||||
}
|
||||
emlSetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
|
||||
emlSetMem_xt(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1, 16);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,7 +71,8 @@ static bool fill_eml_from_file(char *dumpfile) {
|
|||
|
||||
//read and load dump file
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf(_YELLOW_("Found dump file %s. Uploading to emulator memory..."), dumpfile);
|
||||
Dbprintf("Found dump file... `" _YELLOW_("%s") "`", dumpfile);
|
||||
Dbprintf("Uploading to emulator memory...");
|
||||
}
|
||||
|
||||
emlClearMem();
|
||||
|
|
|
@ -28,19 +28,20 @@
|
|||
#include "iso14443a.h"
|
||||
#include "protocols.h"
|
||||
#include "cmd.h"
|
||||
#include "commonutil.h"
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" HF - Reading Visa cards & Emulating a Visa MSD Transaction(ISO14443) - (Salvador Mendoza)");
|
||||
DbpString(" HF - Reading VISA cards & Emulating a VISA MSD Transaction(ISO14443) - (Salvador Mendoza)");
|
||||
}
|
||||
|
||||
/* This standalone implements two different modes: reading and emulating.
|
||||
*
|
||||
* The initial mode is reading with LED A as guide.
|
||||
* In this mode, the Proxmark expects a Visa Card,
|
||||
* In this mode, the Proxmark3 expects a Visa Card,
|
||||
* and will act as card reader. Trying to find track 2.
|
||||
*
|
||||
* If the Proxmark found a track 2, it will change to emulation mode (LED C) automatically.
|
||||
* During this mode the Proxmark will behave as card, emulating a Visa MSD transaction
|
||||
* If the Proxmark3 found a track 2, it will change to emulation mode (LED C) automatically.
|
||||
* During this mode the Proxmark3 will behave as card, emulating a Visa MSD transaction
|
||||
* using the pre-saved track2 from the previous reading.
|
||||
*
|
||||
* It is possible to jump from mode to another by simply pressing the button.
|
||||
|
@ -132,9 +133,15 @@ static uint8_t treatPDOL(const uint8_t *apdu) {
|
|||
|
||||
void RunMod(void) {
|
||||
StandAloneMode();
|
||||
DbpString(_YELLOW_(">>") "Reading Visa cards & Emulating a Visa MSD Transaction a.k.a. MSDSal Started " _YELLOW_("<<"));
|
||||
DbpString("");
|
||||
DbpString(_YELLOW_(">>>") " Reading VISA cards & Emulating a VISA MSD Transaction a.k.a. MSDSal Started " _YELLOW_("<<<"));
|
||||
DbpString("");
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||
// also sets HIGH pointer of BigBuf enabling us to malloc w/o fiddling w the reserved emulator memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
//For reading process
|
||||
iso14a_card_select_t card_a_info;
|
||||
|
||||
|
@ -146,10 +153,32 @@ void RunMod(void) {
|
|||
0x59, 0x2e, 0x53, 0x59, 0x53, 0x2e, 0x44, 0x44,
|
||||
0x46, 0x30, 0x31, 0x00
|
||||
};
|
||||
uint8_t visa[13] = {
|
||||
0x00, 0xA4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00,
|
||||
0x00, 0x03, 0x10, 0x10, 0x00
|
||||
|
||||
uint8_t visa[] = { 0x00, 0xA4, 0x04, 0x00, 0x07, 0xa0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10, 0x00 };
|
||||
|
||||
|
||||
/*
|
||||
uint8_t select_aid_hdr[5] = { 0x00, 0xA4, 0x04, 0x00, 0x00 };
|
||||
static const char* aid_list [] = {
|
||||
"A00000000305076010", // VISA ELO Credit
|
||||
"A0000000031010", // VISA Debit/Credit (Classic)
|
||||
"A000000003101001", // VISA Credit
|
||||
"A000000003101002", // VISA Debit
|
||||
"A0000000032010", // VISA Electron
|
||||
"A0000000032020", // VISA
|
||||
"A0000000033010", // VISA Interlink
|
||||
"A0000000034010", // VISA Specific
|
||||
"A0000000035010", // VISA Specific
|
||||
"A0000000036010", // Domestic Visa Cash Stored Value
|
||||
"A0000000036020", // International Visa Cash Stored Value
|
||||
"A0000000038002", // VISA Auth, VisaRemAuthen EMV-CAP (DPA)
|
||||
"A0000000038010", // VISA Plus
|
||||
"A0000000039010", // VISA Loyalty
|
||||
"A000000003999910", // VISA Proprietary ATM
|
||||
"A000000098", // Visa USA Debit Card
|
||||
"A0000000980848", // Visa USA Debit Cardv
|
||||
};
|
||||
*/
|
||||
|
||||
uint8_t processing [8] = {0x80, 0xA8, 0x00, 0x00, 0x02, 0x83, 0x00, 0x00};
|
||||
uint8_t sfi[5] = {0x00, 0xb2, 0x01, 0x0c, 0x00};
|
||||
|
@ -161,48 +190,49 @@ void RunMod(void) {
|
|||
|
||||
bool existpdol;
|
||||
|
||||
|
||||
// - MSD token card format -
|
||||
//
|
||||
//Card number: 4412 3456 0578 1234
|
||||
//Expiration date: 17/11
|
||||
//Service code: 201
|
||||
//Discretionary data: 0000030000991
|
||||
//char token[19] = {0x44,0x12,0x34,0x56,0x05,0x78,0x12,0x34,0xd1,0x71,0x12,0x01,0x00,0x00,0x03,0x00,0x00,0x99,0x1f};
|
||||
// Card number.............. 4412 3456 0578 1234
|
||||
// Expiration date.......... 17/11
|
||||
// Service code............. 201
|
||||
// Discretionary data....... 0000030000991
|
||||
// Pin verification value... 0000
|
||||
// CVV / iCvv............... 030
|
||||
// Trailing................. 000991
|
||||
|
||||
// 44 12 34 56 05 78 12 34 D 1711 2 01 00 00 03 00 00 99 1
|
||||
// char token[19] = {0x44,0x12,0x34,0x56,0x05,0x78,0x12,0x34,0xd1,0x71,0x12,0x01,0x00,0x00,0x03,0x00,0x00,0x99,0x1f};
|
||||
//
|
||||
// It is possible to initialize directly the emulation mode, having "token" with data and set "chktoken" = true ;)
|
||||
//
|
||||
char token[19] = {0x00};
|
||||
bool chktoken = false;
|
||||
|
||||
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
|
||||
// Such a response is less time critical, so we can prepare them on the fly
|
||||
#define DYNAMIC_RESPONSE_BUFFER_SIZE 64
|
||||
#define DYNAMIC_MODULATION_BUFFER_SIZE 512
|
||||
|
||||
// UID 4 bytes(could be 7 bytes if needed it)
|
||||
uint8_t flags = FLAG_4B_UID_IN_DATA;
|
||||
// in case there is a read command received we shouldn't break
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
|
||||
uint8_t visauid[7] = {0x01, 0x02, 0x03, 0x04};
|
||||
uint8_t visauid[7] = {0xE9, 0x66, 0x5D, 0x20};
|
||||
memcpy(data, visauid, 4);
|
||||
|
||||
// to initialize the emulation
|
||||
uint8_t tagType = 11; // 11 = ISO/IEC 14443-4 - javacard (JCOP)
|
||||
tag_response_info_t *responses;
|
||||
|
||||
uint32_t cuid = 0;
|
||||
uint32_t counters[3] = { 0x00, 0x00, 0x00 };
|
||||
uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd };
|
||||
uint8_t pages = 0;
|
||||
|
||||
// command buffers
|
||||
uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 };
|
||||
uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 };
|
||||
|
||||
|
||||
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
|
||||
// Such a response is less time critical, so we can prepare them on the fly
|
||||
#define DYNAMIC_RESPONSE_BUFFER_SIZE 64
|
||||
#define DYNAMIC_MODULATION_BUFFER_SIZE 512
|
||||
|
||||
uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE] = {0};
|
||||
uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE] = {0};
|
||||
|
||||
// to know the transaction status
|
||||
uint8_t prevCmd = 0;
|
||||
|
||||
|
@ -223,11 +253,11 @@ void RunMod(void) {
|
|||
// Checking if the user wants to go directly to emulation mode using a hardcoded track 2
|
||||
if (chktoken == true && token[0] != 0x00) {
|
||||
state = STATE_EMU;
|
||||
DbpString(_YELLOW_("[ ") "Initialized emulation mode" _YELLOW_(" ]"));
|
||||
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader...");
|
||||
DbpString("Initialized [ " _BLUE_("emulation mode") " ]");
|
||||
DbpString("Waiting for a card reader...");
|
||||
} else {
|
||||
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]"));
|
||||
DbpString("\n"_YELLOW_("!!") "Waiting for a Visa card...");
|
||||
DbpString("Initialized [ " _YELLOW_("reading mode") " ]");
|
||||
DbpString("Waiting for a VISA card...");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
@ -240,20 +270,20 @@ void RunMod(void) {
|
|||
int button_pressed = BUTTON_HELD(1000);
|
||||
|
||||
|
||||
if (button_pressed == BUTTON_HOLD)
|
||||
if (button_pressed == BUTTON_HOLD) {
|
||||
break;
|
||||
else if (button_pressed == BUTTON_SINGLE_CLICK) {
|
||||
} else if (button_pressed == BUTTON_SINGLE_CLICK) {
|
||||
// pressing one time change between reading & emulation
|
||||
if (state == STATE_READ) {
|
||||
if (chktoken == true && token[0] != 0x00) {
|
||||
// only change to emulation if it saved a track 2 in memory
|
||||
state = STATE_EMU;
|
||||
DbpString(_YELLOW_("[ ") "In emulation mode" _YELLOW_(" ]"));
|
||||
DbpString("[ " _BLUE_("Emulation mode") " ]");
|
||||
} else
|
||||
DbpString(_YELLOW_("!!") "Nothing in memory to emulate");
|
||||
DbpString(_YELLOW_("Nothing in memory to emulate"));
|
||||
} else {
|
||||
state = STATE_READ;
|
||||
DbpString(_YELLOW_("[ ") "In reading mode" _YELLOW_(" ]"));
|
||||
DbpString("[ " _YELLOW_("Reading mode") " ]");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,35 +291,40 @@ void RunMod(void) {
|
|||
|
||||
if (state == STATE_READ) {
|
||||
LED_A_ON();
|
||||
if (chktoken)
|
||||
if (chktoken) {
|
||||
LED_C_ON();
|
||||
}
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
|
||||
if (iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) {
|
||||
|
||||
DbpString(_YELLOW_("+") "Found ISO 14443 Type A!");
|
||||
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
chktoken = false;
|
||||
LED_C_OFF();
|
||||
LED_B_ON();
|
||||
|
||||
// add loop visa
|
||||
// for (int i = 0; i < ARRAYLEN(AIDlist); i ++) {
|
||||
// hexstr_to_byte_array("a0da02631a440a44000000a012ad10a00e800200048108", sam_apdu, &sam_len);
|
||||
uint8_t apdulen = iso14_apdu(apdus[i], (uint16_t) apduslen[i], false, apdubuffer, NULL);
|
||||
|
||||
if (apdulen > 0) {
|
||||
DbpString(_YELLOW_("[ ") "Proxmark command" _YELLOW_(" ]"));
|
||||
DbpString("[ " _YELLOW_("Proxmark command") " ]");
|
||||
Dbhexdump(apduslen[i], apdus[i], false);
|
||||
DbpString(_GREEN_("[ ") "Card answer" _GREEN_(" ]"));
|
||||
DbpString("[ " _GREEN_("Card answer") " ]");
|
||||
Dbhexdump(apdulen - 2, apdubuffer, false);
|
||||
DbpString("----");
|
||||
DbpString("-------------------------------");
|
||||
|
||||
for (uint8_t u = 0; u < apdulen; u++) {
|
||||
if (i == 1) {
|
||||
|
||||
// check for PDOL
|
||||
if (apdubuffer[u] == 0x9F && apdubuffer[u + 1] == 0x38) {
|
||||
for (uint8_t e = 0; e <= apdubuffer[u + 2]; e++)
|
||||
|
||||
for (uint8_t e = 0; e <= apdubuffer[u + 2]; e++) {
|
||||
pdol[e] = apdubuffer[u + e + 2];
|
||||
}
|
||||
|
||||
// generate a challenge
|
||||
plen = treatPDOL(pdol);
|
||||
|
@ -309,25 +344,27 @@ void RunMod(void) {
|
|||
}
|
||||
|
||||
if (i == 1) {
|
||||
DbpString(_GREEN_("[ ") "Challenge generated" _GREEN_(" ]"));
|
||||
DbpString("[ "_GREEN_("Challenge generated") " ]");
|
||||
Dbhexdump(plen, existpdol ? ppdol : processing, false);
|
||||
}
|
||||
} else {
|
||||
DbpString(_YELLOW_("!!") "Error reading the card");
|
||||
DbpString(_RED_("Error reading the card"));
|
||||
}
|
||||
LED_B_OFF();
|
||||
}
|
||||
|
||||
if (chktoken) {
|
||||
DbpString(_RED_("[ ") "Track 2" _RED_(" ]"));
|
||||
DbpString("[ " _GREEN_("Track 2") " ]");
|
||||
Dbhexdump(19, (uint8_t *)token, false);
|
||||
DbpString(_YELLOW_("!!") "Card number");
|
||||
DbpString("[ " _GREEN_("Card Number") " ]");
|
||||
Dbhexdump(8, (uint8_t *)token, false);
|
||||
DbpString("---");
|
||||
DbpString("-------------------------------");
|
||||
DbpString("");
|
||||
DbpString("");
|
||||
LED_C_ON();
|
||||
state = STATE_EMU;
|
||||
DbpString(_YELLOW_("[ ") "Initialized emulation mode" _YELLOW_(" ]"));
|
||||
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader...");
|
||||
DbpString("Initialized [ " _BLUE_("emulation mode") " ]");
|
||||
DbpString("Waiting for a card reader...");
|
||||
}
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
@ -340,14 +377,15 @@ void RunMod(void) {
|
|||
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) {
|
||||
// tag type: 11 = ISO/IEC 14443-4 - javacard (JCOP)
|
||||
if (SimulateIso14443aInit(11, flags, data, &responses, &cuid, NULL, NULL, NULL) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
DbpString(_YELLOW_("!!") "Error initializing the emulation process!");
|
||||
DbpString(_RED_("Error initializing the emulation process!"));
|
||||
SpinDelay(500);
|
||||
state = STATE_READ;
|
||||
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]"));
|
||||
DbpString("\n" _YELLOW_("!!") "Waiting for a Visa card...");
|
||||
DbpString("Initialized [ "_YELLOW_("reading mode") " ]");
|
||||
DbpString("Waiting for a VISA card...");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -366,11 +404,12 @@ void RunMod(void) {
|
|||
for (;;) {
|
||||
LED_B_OFF();
|
||||
// clean receive command buffer
|
||||
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) {
|
||||
DbpString(_YELLOW_("!!") "Emulator stopped");
|
||||
if (GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len) == false) {
|
||||
DbpString("Emulator stopped");
|
||||
retval = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
tag_response_info_t *p_response = NULL;
|
||||
LED_B_ON();
|
||||
|
||||
|
@ -387,53 +426,49 @@ void RunMod(void) {
|
|||
|
||||
// received a HALT
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) {
|
||||
//DbpString(_YELLOW_("+") "Received a HALT");
|
||||
p_response = NULL;
|
||||
|
||||
// received a WAKEUP
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) {
|
||||
//DbpString(_YELLOW_("+") "WAKEUP Received");
|
||||
prevCmd = 0;
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
|
||||
// received request for UID (cascade 1)
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) {
|
||||
//DbpString(_YELLOW_("+") "Request for UID C1");
|
||||
p_response = &responses[RESP_INDEX_UIDC1];
|
||||
|
||||
// received a SELECT (cascade 1)
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) {
|
||||
//DbpString(_YELLOW_("+") "Request for SELECT S1");
|
||||
p_response = &responses[RESP_INDEX_SAKC1];
|
||||
|
||||
// received a RATS request
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) {
|
||||
DbpString(_YELLOW_("+") "Request for RATS");
|
||||
prevCmd = 0;
|
||||
//p_response = &responses[RESP_INDEX_RATS];
|
||||
|
||||
static uint8_t rRATS[] = { 0x13, 0x78, 0x80, 0x72, 0x02, 0x80, 0x31, 0x80, 0x66, 0xb1, 0x84, 0x0c, 0x01, 0x6e, 0x01, 0x83, 0x00, 0x90, 0x00 };
|
||||
|
||||
memcpy(&dynamic_response_info.response[0], rRATS, sizeof(rRATS));
|
||||
dynamic_response_info.response_n = sizeof(rRATS);
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
|
||||
} else {
|
||||
DbpString(_YELLOW_("[ ") "Card reader command" _YELLOW_(" ]"));
|
||||
if (g_dbglevel == DBG_DEBUG) {
|
||||
DbpString("[ "_YELLOW_("Card reader command") " ]");
|
||||
Dbhexdump(len, receivedCmd, false);
|
||||
}
|
||||
|
||||
// emulate a Visa MSD(Magnetic stripe data) card
|
||||
// emulate a Visa MSD (Magnetic stripe data) card
|
||||
if (receivedCmd[0] == 0x02 || receivedCmd[0] == 0x03) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
|
||||
// depending on card reader commands, the Proxmark will answer to fool the reader
|
||||
// respond with PPSE
|
||||
if (receivedCmd[2] == 0xA4 && receivedCmd[6] == 0x32 && prevCmd == 0) {
|
||||
// need to adapt lengths..
|
||||
uint8_t ppsea[39] = {
|
||||
// 0x23 = 35, skip two first bytes then the message - SW 2 is 35 = 0x23
|
||||
0x6F, 0x23, 0x84, 0x0E, 0x32, 0x50, 0x41, 0x59,
|
||||
0x2E, 0x53, 0x59, 0x53, 0x2E, 0x44, 0x44, 0x46,
|
||||
0x30, 0x31, 0xA5, 0x11, 0xBF, 0x0C, 0x0E, 0x61,
|
||||
0x0C, 0x4F, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03,
|
||||
0x10, 0x10, 0x87, 0x01, 0x01, 0x90, 0x00
|
||||
0x0C, 0x4F,
|
||||
// len aid0 aid1 aid2...
|
||||
0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10,
|
||||
0x87, 0x01, 0x01, 0x90, 0x00
|
||||
};
|
||||
memcpy(&dynamic_response_info.response[1], ppsea, sizeof(ppsea));
|
||||
dynamic_response_info.response_n = sizeof(ppsea) + 1;
|
||||
|
@ -442,10 +477,14 @@ void RunMod(void) {
|
|||
// respond Visa AID
|
||||
} else if (receivedCmd[2] == 0xA4 && receivedCmd[10] == 0x03 && receivedCmd[11] == 0x10 && prevCmd == 1) {
|
||||
uint8_t visauid_long[34] = {
|
||||
0x6F, 0x1E, 0x84, 0x07, 0xA0, 0x00, 0x00, 0x00,
|
||||
0x03, 0x10, 0x10, 0xA5, 0x13, 0x50, 0x0B, 0x56,
|
||||
0x49, 0x53, 0x41, 0x20, 0x43, 0x52, 0x45, 0x44,
|
||||
0x49, 0x54, 0x9F, 0x38, 0x03, 0x9F, 0x66, 0x02,
|
||||
// 0x1E = 30, skip two first bytes then the message - SW 2 is 30 = 0x1E
|
||||
0x6F, 0x1E, 0x84,
|
||||
// len aid0 aid1 aid2....
|
||||
0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x10, 0x10,
|
||||
0xA5, 0x13, 0x50,
|
||||
// len V I S A C R E D I T
|
||||
0x0B, 0x56, 0x49, 0x53, 0x41, 0x20, 0x43, 0x52, 0x45, 0x44, 0x49, 0x54,
|
||||
0x9F, 0x38, 0x03, 0x9F, 0x66, 0x02,
|
||||
0x90, 0x00
|
||||
};
|
||||
memcpy(&dynamic_response_info.response[1], visauid_long, sizeof(visauid_long));
|
||||
|
@ -461,18 +500,21 @@ void RunMod(void) {
|
|||
|
||||
// SFI
|
||||
} else if (receivedCmd[1] == 0x00 && receivedCmd[2] == 0xB2 && prevCmd == 3) {
|
||||
uint8_t last[4] = {0x70, 0x15, 0x57, 0x13};
|
||||
uint8_t statusapdu[2] = {0x90, 0x00};
|
||||
uint8_t card[25];
|
||||
memcpy(&card[0], last, sizeof(last));
|
||||
uint8_t card[25] = {
|
||||
0x70, 0x15, 0x57, 0x13, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x90, 0x00
|
||||
};
|
||||
// add token array == Track 2 found before
|
||||
memcpy(&card[4], token, sizeof(token));
|
||||
memcpy(&card[23], statusapdu, sizeof(statusapdu));
|
||||
|
||||
memcpy(&dynamic_response_info.response[1], card, sizeof(card));
|
||||
dynamic_response_info.response_n = sizeof(card) + 1;
|
||||
prevCmd++;
|
||||
|
||||
} else {
|
||||
uint8_t finished[2] = {0x6f, 0x00};
|
||||
uint8_t finished[2] = {0x6F, 0x00};
|
||||
memcpy(&dynamic_response_info.response[1], finished, sizeof(finished));
|
||||
dynamic_response_info.response_n = sizeof(finished) + 1;
|
||||
if (prevCmd == 5) {
|
||||
|
@ -480,7 +522,7 @@ void RunMod(void) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
DbpString(_YELLOW_("!!") "Received unknown command!");
|
||||
DbpString(_RED_("Received unknown command!"));
|
||||
if (prevCmd < 4) {
|
||||
memcpy(dynamic_response_info.response, receivedCmd, len);
|
||||
dynamic_response_info.response_n = len;
|
||||
|
@ -491,7 +533,7 @@ void RunMod(void) {
|
|||
}
|
||||
|
||||
if (dynamic_response_info.response_n > 0) {
|
||||
DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]"));
|
||||
DbpString("[ " _GREEN_("Proxmark3 answer") " ]");
|
||||
Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false);
|
||||
DbpString("----");
|
||||
|
||||
|
@ -501,7 +543,7 @@ void RunMod(void) {
|
|||
|
||||
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
|
||||
SpinDelay(500);
|
||||
DbpString(_YELLOW_("!!") "Error preparing Proxmark to answer!");
|
||||
DbpString(_RED_("Error preparing Proxmark to answer!"));
|
||||
continue;
|
||||
}
|
||||
p_response = &dynamic_response_info;
|
||||
|
@ -511,13 +553,15 @@ void RunMod(void) {
|
|||
EmSendPrecompiledCmd(p_response);
|
||||
}
|
||||
}
|
||||
switch_off();
|
||||
|
||||
switch_off();
|
||||
set_tracing(false);
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, retval, NULL, 0);
|
||||
}
|
||||
}
|
||||
DbpString(_YELLOW_("[=]") "exiting");
|
||||
DbpString("Exit standalone mode!");
|
||||
DbpString("");
|
||||
SpinErr(15, 200, 3);
|
||||
LEDsoff();
|
||||
}
|
||||
|
|
|
@ -46,14 +46,14 @@ void ModInfo(void) {
|
|||
* standalone.
|
||||
*
|
||||
* For the reading mode:
|
||||
* - Set up and run the other end first, to where the Proxmark will send the data.
|
||||
* - Set up and run the other end first, to where the Proxmark3 will send the data.
|
||||
* - After the card is detected, Proxmark3 will send a package. The first byte will be the package
|
||||
* length, then, the card data. Use the first length byte to read the whole package.
|
||||
* - Proxmark3 will expect a raw APDU from the other end, then it will be sent to the card.
|
||||
* - The answer of the card will be sent back to the connection, repeating the cycle.
|
||||
*
|
||||
* For the emulation mode:
|
||||
* - Set up and run the other end first, from where the Proxmark will receive the data.
|
||||
* - Set up and run the other end first, from where the Proxmark3 will receive the data.
|
||||
* - When the Proxmark3 detected the terminal, it will send the command to the connection.
|
||||
* - The first byte will be the package length, then, the terminal command. Use the first
|
||||
* length byte to read the whole package.
|
||||
|
@ -73,29 +73,25 @@ void ModInfo(void) {
|
|||
|
||||
void RunMod() {
|
||||
StandAloneMode();
|
||||
Dbprintf(_YELLOW_(">>") "Relaying ISO/14443A data over Bluetooth a.k.a. reblay Started<<");
|
||||
DbpString("");
|
||||
Dbprintf(_YELLOW_(">>> ") " Relaying ISO/14443A data over Bluetooth a.k.a. reblay Started " _YELLOW_("<<<"));
|
||||
DbpString("");
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
|
||||
// Such a response is less time critical, so we can prepare them on the fly
|
||||
#define DYNAMIC_RESPONSE_BUFFER_SIZE 512
|
||||
#define DYNAMIC_MODULATION_BUFFER_SIZE 1024
|
||||
|
||||
uint8_t flags = FLAG_4B_UID_IN_DATA; //UID 4 bytes(could be 7 bytes if needed it)
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; // in case there is a read command received we shouldn't break
|
||||
|
||||
uint8_t visauid[7] = {0x01, 0x02, 0x03, 0x04};
|
||||
// UID 4 bytes(could be 7 bytes if needed it)
|
||||
uint8_t flags = FLAG_4B_UID_IN_DATA;
|
||||
// in case there is a read command received we shouldn't break
|
||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
|
||||
uint8_t visauid[7] = {0xE9, 0x66, 0x5D, 0x20};
|
||||
memcpy(data, visauid, 4);
|
||||
|
||||
// to initialize the emulation
|
||||
uint8_t tagType = 4; // 4 = ISO/IEC 14443-4 - javacard (JCOP)
|
||||
tag_response_info_t *responses;
|
||||
|
||||
uint32_t cuid = 0;
|
||||
uint32_t counters[3] = { 0x00, 0x00, 0x00 };
|
||||
uint8_t tearings[3] = { 0xbd, 0xbd, 0xbd };
|
||||
uint8_t pages = 0;
|
||||
|
||||
|
||||
// For received Bluetooth package
|
||||
uint8_t rpacket[MAX_FRAME_SIZE] = { 0x00 };
|
||||
|
@ -126,6 +122,12 @@ void RunMod() {
|
|||
uint8_t receivedCmd[MAX_FRAME_SIZE] = { 0x00 };
|
||||
uint8_t receivedCmdPar[MAX_PARITY_SIZE] = { 0x00 };
|
||||
|
||||
|
||||
// Allocate 512 bytes for the dynamic modulation, created when the reader queries for it
|
||||
// Such a response is less time critical, so we can prepare them on the fly
|
||||
#define DYNAMIC_RESPONSE_BUFFER_SIZE 512
|
||||
#define DYNAMIC_MODULATION_BUFFER_SIZE 1024
|
||||
|
||||
uint8_t dynamic_response_buffer[DYNAMIC_RESPONSE_BUFFER_SIZE] = {0};
|
||||
uint8_t dynamic_modulation_buffer[DYNAMIC_MODULATION_BUFFER_SIZE] = {0};
|
||||
|
||||
|
@ -143,9 +145,9 @@ void RunMod() {
|
|||
uint8_t state = STATE_READ;
|
||||
|
||||
if (state == STATE_READ) {
|
||||
DbpString(_YELLOW_("[ ") "In reading mode" _YELLOW_(" ]"));
|
||||
DbpString("Initialized [ " _YELLOW_("reading mode") " ]");
|
||||
} else {
|
||||
DbpString(_YELLOW_("[ ") "In emulation mode" _YELLOW_(" ]"));
|
||||
DbpString("Initialized [ " _BLUE_("emulation mode") " ]");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
@ -162,10 +164,10 @@ void RunMod() {
|
|||
else if (button_pressed == BUTTON_SINGLE_CLICK) { // Pressing one time change between reading & emulation
|
||||
if (state == STATE_READ) {
|
||||
state = STATE_EMU;
|
||||
DbpString(_YELLOW_("[ ") "In emulation mode" _YELLOW_(" ]"));
|
||||
DbpString("[ " _BLUE_("Emulation mode") " ]");
|
||||
} else {
|
||||
state = STATE_READ;
|
||||
DbpString(_YELLOW_("[ ") "In reading mode" _YELLOW_(" ]"));
|
||||
DbpString("[ " _YELLOW_("Reading mode") " ]");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,6 +180,7 @@ void RunMod() {
|
|||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
|
||||
if (iso14443a_select_card(NULL, &card_a_info, NULL, true, 0, false)) {
|
||||
|
||||
LED_B_ON();
|
||||
|
||||
// Get data to send a ping with UID + ATQA + SAK
|
||||
|
@ -208,7 +211,9 @@ void RunMod() {
|
|||
Dbhexdump(uidlen + 4, rdata, false);
|
||||
|
||||
DbpString(_YELLOW_("[ ") "Sending ping" _YELLOW_(" ]"));
|
||||
|
||||
if (usart_writebuffer_sync(rdata, uidlen + 4) == PM3_SUCCESS) {
|
||||
|
||||
DbpString(_YELLOW_("[ ") "Sent!" _YELLOW_(" ]"));
|
||||
|
||||
for (;;) {
|
||||
|
@ -261,26 +266,31 @@ void RunMod() {
|
|||
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
if (SimulateIso14443aInit(tagType, flags, data, &responses, &cuid, counters, tearings, &pages) == false) {
|
||||
// 4 = ISO/IEC 14443-4 - javacard (JCOP)
|
||||
if (SimulateIso14443aInit(4, flags, data, &responses, &cuid, NULL, NULL, NULL) == false) {
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, PM3_EINIT, NULL, 0);
|
||||
DbpString(_YELLOW_("!!") "Error initializing the emulation process!");
|
||||
DbpString(_RED_("Error initializing the emulation process!"));
|
||||
SpinDelay(500);
|
||||
state = STATE_READ;
|
||||
DbpString(_YELLOW_("[ ") "Initialized reading mode" _YELLOW_(" ]"));
|
||||
DbpString("Initialized [ "_YELLOW_("reading mode") " ]");
|
||||
continue;
|
||||
}
|
||||
|
||||
// We need to listen to the high-frequency, peak-detected path.
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
|
||||
|
||||
int len = 0; // Command length
|
||||
int retval = PM3_SUCCESS; // Check emulation status
|
||||
// Command length
|
||||
int len = 0;
|
||||
// Check emulation status
|
||||
int retval = PM3_SUCCESS;
|
||||
|
||||
uint8_t resp = 0; // Bluetooth response
|
||||
// Bluetooth response
|
||||
uint8_t resp = 0;
|
||||
lenpacket = 0;
|
||||
|
||||
uint8_t prevcmd = 0x00; // Keep track of last terminal type command
|
||||
// Keep track of last terminal type command
|
||||
uint8_t prevcmd = 0x00;
|
||||
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
@ -288,11 +298,12 @@ void RunMod() {
|
|||
for (;;) {
|
||||
LED_B_OFF();
|
||||
// Clean receive command buffer
|
||||
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) {
|
||||
DbpString(_YELLOW_("!!") "Emulator stopped");
|
||||
if (GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len) == false) {
|
||||
DbpString("Emulator stopped");
|
||||
retval = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
tag_response_info_t *p_response = NULL;
|
||||
LED_B_ON();
|
||||
|
||||
|
@ -314,46 +325,42 @@ void RunMod() {
|
|||
}
|
||||
}
|
||||
if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST
|
||||
// DbpString(_YELLOW_("+") "REQUEST Received");
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_HALT && len == 4) { // Received a HALT
|
||||
// DbpString(_YELLOW_("+") "Received a HALT");
|
||||
p_response = NULL;
|
||||
resp = 0;
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
|
||||
// DbpString(_YELLOW_("+") "WAKEUP Received");
|
||||
p_response = &responses[RESP_INDEX_ATQA];
|
||||
resp = 0;
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
|
||||
// DbpString(_YELLOW_("+") "Request for UID C1");
|
||||
p_response = &responses[RESP_INDEX_UIDC1];
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
|
||||
// DbpString(_YELLOW_("+") "Request for SELECT S1");
|
||||
p_response = &responses[RESP_INDEX_SAKC1];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_RATS && len == 4) { // Received a RATS request
|
||||
// DbpString(_YELLOW_("+") "Request for RATS");
|
||||
p_response = &responses[RESP_INDEX_RATS];
|
||||
resp = 1;
|
||||
} else if (receivedCmd[0] == 0xf2 && len == 4) { // ACKed - Time extension
|
||||
DbpString(_YELLOW_("!!") "Reader accepted time extension!");
|
||||
DbpString(_YELLOW_("!!") " Reader accepted time extension!");
|
||||
p_response = NULL;
|
||||
} else if ((receivedCmd[0] == 0xb2 || receivedCmd[0] == 0xb3) && len == 3) { //NACK - Request more time WTX
|
||||
DbpString(_YELLOW_("!!") "NACK - time extension request?");
|
||||
DbpString(_YELLOW_("!!") " NACK - time extension request?");
|
||||
if (resp == 2 && lenpacket == 0) {
|
||||
DbpString(_YELLOW_("!!") "Requesting more time - WTX");
|
||||
DbpString(_YELLOW_("!!") " Requesting more time - WTX");
|
||||
dynamic_response_info.response_n = 2;
|
||||
dynamic_response_info.response[0] = 0xf2;
|
||||
dynamic_response_info.response[1] = 0x0b; // Requesting the maximum amount of time
|
||||
} else if (lenpacket == 0) {
|
||||
DbpString(_YELLOW_("!!") "NACK - ACK - Resend last command!"); // To burn some time as well
|
||||
DbpString(_YELLOW_("!!") " NACK - ACK - Resend last command!"); // To burn some time as well
|
||||
dynamic_response_info.response[0] = 0xa3;
|
||||
dynamic_response_info.response_n = 1;
|
||||
} else {
|
||||
DbpString(_YELLOW_("!!") "Avoiding request - Bluetooth data already in memory!!");
|
||||
DbpString(_YELLOW_("!!") " Avoiding request - Bluetooth data already in memory!!");
|
||||
}
|
||||
} else {
|
||||
DbpString(_GREEN_("[ ") "Card reader command" _GREEN_(" ]"));
|
||||
if (g_dbglevel == DBG_DEBUG) {
|
||||
DbpString("[ "_YELLOW_("Card reader command") " ]");
|
||||
Dbhexdump(len - 2, &receivedCmd[1], false);
|
||||
}
|
||||
|
||||
if ((receivedCmd[0] == 0x02 || receivedCmd[0] == 0x03) && len > 3) { // Process reader commands
|
||||
|
||||
|
@ -379,16 +386,17 @@ void RunMod() {
|
|||
|
||||
} else {
|
||||
if (lenpacket == 0) {
|
||||
DbpString(_YELLOW_("!!") "Received unknown command!");
|
||||
DbpString(_RED_("Received unknown command!"));
|
||||
memcpy(dynamic_response_info.response, receivedCmd, len);
|
||||
dynamic_response_info.response_n = len;
|
||||
} else {
|
||||
DbpString(_YELLOW_("!!") "Avoiding unknown command - Bluetooth data already in memory!!");
|
||||
DbpString(_YELLOW_("!!") " Avoiding unknown command - Bluetooth data already in memory !!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (dynamic_response_info.response_n > 0) {
|
||||
DbpString(_GREEN_("[ ") "Proxmark3 answer" _GREEN_(" ]"));
|
||||
DbpString("[ " _GREEN_("Proxmark3 answer") " ]");
|
||||
Dbhexdump(dynamic_response_info.response_n, dynamic_response_info.response, false);
|
||||
DbpString("----");
|
||||
if (lenpacket > 0) {
|
||||
|
@ -402,7 +410,7 @@ void RunMod() {
|
|||
if (prepare_tag_modulation(&dynamic_response_info, DYNAMIC_MODULATION_BUFFER_SIZE) == false) {
|
||||
Dbprintf(_YELLOW_("[ ") "Buffer size: %d "_YELLOW_(" ]"), dynamic_response_info.response_n);
|
||||
SpinDelay(500);
|
||||
DbpString(_YELLOW_("!!") "Error preparing Proxmark to answer!");
|
||||
DbpString(_RED_("Error preparing Proxmark to answer!"));
|
||||
continue;
|
||||
}
|
||||
p_response = &dynamic_response_info;
|
||||
|
@ -412,13 +420,15 @@ void RunMod() {
|
|||
EmSendPrecompiledCmd(p_response);
|
||||
}
|
||||
}
|
||||
switch_off();
|
||||
|
||||
switch_off();
|
||||
set_tracing(false);
|
||||
BigBuf_free_keep_EM();
|
||||
reply_ng(CMD_HF_MIFARE_SIMULATE, retval, NULL, 0);
|
||||
}
|
||||
}
|
||||
DbpString(_YELLOW_("[=]") "exiting");
|
||||
DbpString("Exit standalone mode!");
|
||||
DbpString("");
|
||||
SpinErr(15, 200, 3);
|
||||
LEDsoff();
|
||||
}
|
||||
|
|
|
@ -36,19 +36,19 @@ void ModInfo(void) {
|
|||
/* This standalone implements four different modes: reading, simulating, dumping, & emulating.
|
||||
*
|
||||
* The initial mode is reading with LEDs A & D.
|
||||
* In this mode, the Proxmark is looking for an ST25TA card like those used by the IKEA Rothult,
|
||||
* In this mode, the Proxmark3 is looking for an ST25TA card like those used by the IKEA Rothult,
|
||||
* it will act as reader, and store the UID for simulation.
|
||||
*
|
||||
* If the Proxmark gets an ST25TA UID, it will change to simulation mode (LEDs A & C) automatically.
|
||||
* During this mode the Proxmark will pretend to be the IKEA Rothult ST25TA master key, upon presentation
|
||||
* to an IKEA Rothult the Proxmark will steal the 16 byte Read Protection key used to authenticate to the card.
|
||||
* If the Proxmark3 gets an ST25TA UID, it will change to simulation mode (LEDs A & C) automatically.
|
||||
* During this mode the Proxmark3 will pretend to be the IKEA Rothult ST25TA master key, upon presentation
|
||||
* to an IKEA Rothult the Proxmark3 will steal the 16 byte Read Protection key used to authenticate to the card.
|
||||
*
|
||||
* Once it gets the key, it will switch to dump mode (LEDs C & D) automatically. During this mode the Proxmark
|
||||
* Once it gets the key, it will switch to dump mode (LEDs C & D) automatically. During this mode the Proxmark3
|
||||
* will act as a reader once again, but now we know the Read Protection key to authenticate to the card to dump
|
||||
* it's contents so we can achieve full emulation.
|
||||
*
|
||||
* Once it dumps the contents of the card, it will switch to emulation mode (LED C) automatically.
|
||||
* During this mode the Proxmark should function as the original ST25TA IKEA Rothult Master Key
|
||||
* During this mode the Proxmark3 should function as the original ST25TA IKEA Rothult Master Key
|
||||
*
|
||||
* Keep pressing the button down will quit the standalone cycle.
|
||||
*
|
||||
|
|
|
@ -74,7 +74,7 @@ void RunMod(void) {
|
|||
}
|
||||
} else if (state == STATE_EMUL) {
|
||||
Iso15693InitTag();
|
||||
Dbprintf("Starting simulation, press pm3-button to stop and go back to search state.");
|
||||
Dbprintf("Starting simulation, press " _GREEN_("pm3 button") " to stop and go back to search state.");
|
||||
// default block size is 4
|
||||
SimTagIso15693(card.uid, 4);
|
||||
|
||||
|
|
340
armsrc/Standalone/hf_unisniff.c
Normal file
340
armsrc/Standalone/hf_unisniff.c
Normal file
|
@ -0,0 +1,340 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// HF_UNISNIFF: Integrated 14a/14b/15 sniffer
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
* 'hf_unisniff' integrates existing sniffer functionality for 14a/14b/15a into
|
||||
* one standalone module. It can sniff to the RAM trace buffer, or if you have
|
||||
* a PM3 with Flash it will (optionally) save traces to SPIFFS.
|
||||
*
|
||||
* You can select which protocol will be sniffed with compile-time flags, or at
|
||||
* runtime via button presses or a config file in SPIFFS. You can also choose
|
||||
* whether it will append to the trace file for each sniffing session
|
||||
* or create new ones.
|
||||
*
|
||||
* If the protocol to sniff is configured at compile time or in config file:
|
||||
* Once the module is launched, it will begin sniffing immediately.
|
||||
*
|
||||
* If configured for runtime selection:
|
||||
* Flashing LED(s) indicate selected sniffer protocol: A=14a, B=14b, A+B=15
|
||||
* Short press cycles through options. Long press begins sniffing.
|
||||
*
|
||||
* Short-pressing the button again will stop sniffing, with the sniffed data in
|
||||
* the trace buffer. If you have Flash, and have not set the 'save=none'
|
||||
* option in the config file, trace data will be saved to SPIFFS. The default
|
||||
* is to create a new file for each sniffing session, but you may configure it
|
||||
* to append instead.
|
||||
*
|
||||
* Once the data is saved, standalone mode will exit.
|
||||
*
|
||||
* LEDs:
|
||||
* - LED1: sniffing
|
||||
* - LED2: sniffed tag command, turns off when finished sniffing reader command
|
||||
* - LED3: sniffed reader command, turns off when finished sniffing tag command
|
||||
* - LED4: unmounting/sync'ing flash (normally < 100ms)
|
||||
*
|
||||
* Config file: 'hf_unisniff.conf' is a plain text file, one option per line.
|
||||
* Settings here will override the compile-time options.
|
||||
*
|
||||
* Currently available options:
|
||||
* save = [new|append|none]
|
||||
* new = create a new file with a numbered name for each session.
|
||||
* append = append to existing file, create if not existing.
|
||||
* none = do not save to SPIFFS, leave in trace buffer only.
|
||||
*
|
||||
* protocol = [14a|14b|15|user]
|
||||
* which protocol to sniff. If you choose a protocol it will go directly
|
||||
* to work. If you choose 'user' you may select the protocol at the start
|
||||
* of each session.
|
||||
*
|
||||
* To retrieve trace data from flash:
|
||||
*
|
||||
* 1. mem spiffs dump -s hf_unisniff_[protocol]_[number].trace -d hf_unisniff.trace
|
||||
* Copies trace data file from flash to your PC.
|
||||
*
|
||||
* 2. trace load -f hf_unisniff.trace
|
||||
* Loads trace data from a file into PC-side buffers.
|
||||
*
|
||||
* 3. For ISO14a: trace list -t [protocol] -1
|
||||
* For MIFARE Classic: trace list -t mf -1
|
||||
*
|
||||
* Lists trace data from buffer without requesting it from PM3.
|
||||
*
|
||||
* This module emits debug strings during normal operation -- so try it out in
|
||||
* the lab connected to PM3 client before taking it into the field.
|
||||
*
|
||||
* To delete the trace data from flash:
|
||||
* mem spiffs remove -f [filename]
|
||||
*
|
||||
* Caveats / notes:
|
||||
* - Trace buffer will be cleared on starting stand-alone mode. Data in flash
|
||||
* will remain unless explicitly deleted.
|
||||
* - This module will terminate if the trace buffer is full (and save data to
|
||||
* flash).
|
||||
* - Like normal sniffing mode, timestamps overflow after 5 min 16 sec.
|
||||
* However, the trace buffer is sequential, so will be in the correct order.
|
||||
*
|
||||
* Mostly this is based on existing code, i.e. the hf_1*sniff modules and dankarmulti.
|
||||
* I find it handy to have multiprotocol sniffing on the go, and prefer separate trace
|
||||
* files rather than appends, so here it is.
|
||||
*
|
||||
* If you really like navigating menus with one button and some LEDs, it also works
|
||||
* with dankarmulti :)
|
||||
*
|
||||
* Enjoy!
|
||||
*/
|
||||
|
||||
#include "standalone.h" // standalone definitions
|
||||
#include "proxmark3_arm.h"
|
||||
#include "iso14443a.h"
|
||||
#include "iso14443b.h"
|
||||
#include "iso15693.h"
|
||||
#include "iso15.h"
|
||||
#include "util.h"
|
||||
#include "commonutil.h"
|
||||
#include "spiffs.h"
|
||||
#include "appmain.h"
|
||||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
#include "BigBuf.h"
|
||||
#include "string.h"
|
||||
|
||||
#undef HF_UNISNIFF_VERBOSE_DEBUG
|
||||
#define HF_UNISNIFF_PROTOCOL "14a"
|
||||
#define HF_UNISNIFF_LOGFILE "hf_unisniff"
|
||||
#define HF_UNISNIFF_LOGEXT ".trace"
|
||||
#define HF_UNISNIFF_CONFIG "hf_unisniff.conf"
|
||||
#define HF_UNISNIFF_CONFIG_SIZE 128
|
||||
|
||||
#define HF_UNISNIFF_PROTOCOLS {"14a","14b","15", "user"} // The logic requires USER be last.
|
||||
#define HF_UNISNIFF_NUM_PROTOCOLS 4
|
||||
#define HF_UNISNIFF_PROTO_14a 0
|
||||
#define HF_UNISNIFF_PROTO_14b 1
|
||||
#define HF_UNISNIFF_PROTO_15 2
|
||||
#define HF_UNISNIFF_PROTO_USER HF_UNISNIFF_NUM_PROTOCOLS-1
|
||||
|
||||
#define HF_UNISNIFF_SAVE_MODE HF_UNISNIFF_SAVE_MODE_NEW // Default, override in .conf
|
||||
#define HF_UNISNIFF_SAVE_MODE_NEW 0
|
||||
#define HF_UNISNIFF_SAVE_MODE_APPEND 1
|
||||
#define HF_UNISNIFF_SAVE_MODE_NONE 2
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
static void UniSniff_DownloadTraceInstructions(char *filename) {
|
||||
Dbprintf("");
|
||||
Dbprintf("To get the trace from flash and display it:");
|
||||
Dbprintf("1. mem spiffs dump -s %s -d hf_unisniff.trace", filename);
|
||||
Dbprintf("2. trace load -f hf_unisniff.trace");
|
||||
Dbprintf("3. trace list -t [protocol] -1");
|
||||
}
|
||||
#endif
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" HF UNISNIFF, multimode HF sniffer with optional flashmem & runtime select (hazardousvoltage)");
|
||||
Dbprintf(" Compile-time default protocol: %s", HF_UNISNIFF_PROTOCOL);
|
||||
#ifdef WITH_FLASH
|
||||
DbpString(" WITH_FLASH support.");
|
||||
#endif
|
||||
}
|
||||
|
||||
void RunMod(void) {
|
||||
char *protocols[] = HF_UNISNIFF_PROTOCOLS;
|
||||
uint8_t sniff_protocol, default_sniff_protocol;
|
||||
StandAloneMode();
|
||||
|
||||
Dbprintf(_YELLOW_("HF UNISNIFF started"));
|
||||
for (sniff_protocol = 0; sniff_protocol < HF_UNISNIFF_NUM_PROTOCOLS; sniff_protocol++) {
|
||||
if (!strcmp(protocols[sniff_protocol], HF_UNISNIFF_PROTOCOL)) break;
|
||||
}
|
||||
default_sniff_protocol = sniff_protocol;
|
||||
#ifdef HF_UNISNIFF_VERBOSE_DEBUG
|
||||
Dbprintf("Compile-time configured protocol: %d", sniff_protocol);
|
||||
#endif
|
||||
#ifdef WITH_FLASH
|
||||
uint8_t save_mode = HF_UNISNIFF_SAVE_MODE;
|
||||
rdv40_spiffs_lazy_mount();
|
||||
// Allocate memory now for buffer for filename to save to. Who knows what'll be
|
||||
// available after filling the trace buffer.
|
||||
char *filename = (char *)BigBuf_malloc(64);
|
||||
if (filename == NULL) {
|
||||
Dbprintf("failed to allocate memory");
|
||||
return;
|
||||
}
|
||||
// Read the config file. Size is limited to defined value so as not to consume
|
||||
// stupid amounts of stack
|
||||
if (exists_in_spiffs(HF_UNISNIFF_CONFIG)) {
|
||||
char config_buffer_array[HF_UNISNIFF_CONFIG_SIZE];
|
||||
char *config_buffer = &config_buffer_array[0];
|
||||
uint32_t config_size = size_in_spiffs(HF_UNISNIFF_CONFIG);
|
||||
if (config_size > HF_UNISNIFF_CONFIG_SIZE) config_size = HF_UNISNIFF_CONFIG_SIZE;
|
||||
rdv40_spiffs_read_as_filetype(HF_UNISNIFF_CONFIG, (uint8_t *)config_buffer,
|
||||
config_size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
// This parser is terrible but I think fairly memory efficient? Maybe better to use JSON?
|
||||
char *x = config_buffer;
|
||||
char *y = x;
|
||||
// strip out all the whitespace and Windows line-endings
|
||||
do {
|
||||
while (*y == 0x20 || *y == 0x09 || *y == 0x0D) {
|
||||
++y;
|
||||
}
|
||||
} while ((*x++ = c_tolower(*y++)));
|
||||
char *token = strchr(config_buffer, '\n');
|
||||
while (token != NULL) {
|
||||
*token++ = '\0';
|
||||
char *tag = strtok(config_buffer, "=");
|
||||
char *value = strtok(NULL, "\n");
|
||||
if (tag != NULL && value != NULL) {
|
||||
if (!strcmp(tag, "protocol")) {
|
||||
// If we got a selection here, override compile-time selection
|
||||
uint8_t conf_protocol;
|
||||
for (conf_protocol = 0; conf_protocol < HF_UNISNIFF_NUM_PROTOCOLS; conf_protocol++) {
|
||||
if (!strcmp(protocols[conf_protocol], value)) {
|
||||
sniff_protocol = conf_protocol;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef HF_UNISNIFF_VERBOSE_DEBUG
|
||||
Dbprintf("Run-time configured protocol: %d", conf_protocol);
|
||||
#endif
|
||||
} else if (!strcmp(tag, "save")) {
|
||||
if (!strcmp(value, "append")) save_mode = HF_UNISNIFF_SAVE_MODE_APPEND;
|
||||
else if (!strcmp(value, "none")) save_mode = HF_UNISNIFF_SAVE_MODE_NONE;
|
||||
else save_mode = HF_UNISNIFF_SAVE_MODE_NEW;
|
||||
#ifdef HF_UNISNIFF_VERBOSE_DEBUG
|
||||
Dbprintf("Run-time configured save_mode: %d", save_mode);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
config_buffer = token;
|
||||
token = strchr(config_buffer, '\n');
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
if (sniff_protocol >= HF_UNISNIFF_PROTO_USER) {
|
||||
Dbprintf("[!] Protocol undefined, going to prompt loop");
|
||||
sniff_protocol = default_sniff_protocol; // Default to compile-time setting.
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
if (data_available()) {
|
||||
BigBuf_free();
|
||||
return;
|
||||
}
|
||||
if (GetTickCount() & 0x80)
|
||||
LED(sniff_protocol + 1, 0);
|
||||
else
|
||||
LEDsoff();
|
||||
|
||||
// Was our button held down or pressed?
|
||||
int button_pressed = BUTTON_HELD(1000);
|
||||
if (button_pressed == BUTTON_SINGLE_CLICK) {
|
||||
sniff_protocol++;
|
||||
if (sniff_protocol >= HF_UNISNIFF_PROTO_USER) sniff_protocol = 0;
|
||||
SpinDelay(100);
|
||||
Dbprintf("Selected protocol: '%s'", protocols[sniff_protocol]);
|
||||
} else if (button_pressed == BUTTON_HOLD) {
|
||||
Dbprintf("Executing protocol %s", protocols[sniff_protocol]);
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
LED(15, 0);
|
||||
SpinDelay(100);
|
||||
LEDsoff();
|
||||
SpinDelay(100);
|
||||
}
|
||||
WAIT_BUTTON_RELEASED();
|
||||
SpinDelay(300);
|
||||
LEDsoff();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (sniff_protocol) {
|
||||
case HF_UNISNIFF_PROTO_14a:
|
||||
SniffIso14443a(0);
|
||||
break;
|
||||
case HF_UNISNIFF_PROTO_14b:
|
||||
SniffIso14443b();
|
||||
break;
|
||||
case HF_UNISNIFF_PROTO_15:
|
||||
SniffIso15693(0, NULL, false);
|
||||
break;
|
||||
default:
|
||||
Dbprintf("No protocol selected, exiting.");
|
||||
BigBuf_free();
|
||||
LEDsoff();
|
||||
return;
|
||||
}
|
||||
|
||||
Dbprintf("Stopped sniffing");
|
||||
SpinDelay(200);
|
||||
|
||||
uint32_t trace_len = BigBuf_get_traceLen();
|
||||
#ifndef WITH_FLASH
|
||||
// Keep stuff in BigBuf for USB/BT dumping
|
||||
if (trace_len > 0)
|
||||
Dbprintf("[!] Trace length (bytes) = %u", trace_len);
|
||||
#else
|
||||
// Write stuff to spiffs logfile
|
||||
if (trace_len == 0) {
|
||||
Dbprintf("[!] Trace buffer is empty, nothing to write!");
|
||||
} else if (save_mode == HF_UNISNIFF_SAVE_MODE_NONE) {
|
||||
Dbprintf("[!] Trace save to flash disabled in config!");
|
||||
} else {
|
||||
Dbprintf("[!] Trace length (bytes) = %u", trace_len);
|
||||
|
||||
uint8_t *trace_buffer = BigBuf_get_addr();
|
||||
|
||||
sprintf(filename, "%s_%s%s", HF_UNISNIFF_LOGFILE, protocols[sniff_protocol], HF_UNISNIFF_LOGEXT);
|
||||
if (save_mode == HF_UNISNIFF_SAVE_MODE_NEW) {
|
||||
uint16_t file_index = 0;
|
||||
while (exists_in_spiffs(filename)) {
|
||||
if (file_index++ == 1000) break;
|
||||
sprintf(filename, "%s_%s-%03d%s", HF_UNISNIFF_LOGFILE, protocols[sniff_protocol],
|
||||
file_index, HF_UNISNIFF_LOGEXT);
|
||||
}
|
||||
if (file_index > 999) {
|
||||
Dbprintf("[!] Too many files! Trace not saved. Clean up your SPIFFS.");
|
||||
} else {
|
||||
rdv40_spiffs_write(filename, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
Dbprintf("[!] Wrote trace to %s", filename);
|
||||
}
|
||||
} else if (save_mode == HF_UNISNIFF_SAVE_MODE_APPEND) {
|
||||
if (!exists_in_spiffs(filename)) {
|
||||
rdv40_spiffs_write(filename, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
Dbprintf("[!] Wrote trace to %s", filename);
|
||||
} else {
|
||||
rdv40_spiffs_append(filename, trace_buffer, trace_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
Dbprintf("[!] Appended trace to %s", filename);
|
||||
}
|
||||
}
|
||||
UniSniff_DownloadTraceInstructions(filename);
|
||||
}
|
||||
|
||||
LED_D_ON();
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
LED_D_OFF();
|
||||
|
||||
SpinErr(LED_A, 200, 5);
|
||||
SpinDelay(100);
|
||||
BigBuf_free();
|
||||
#endif
|
||||
|
||||
Dbprintf("-=[ exit ]=-");
|
||||
LEDsoff();
|
||||
|
||||
return;
|
||||
}
|
199
armsrc/appmain.c
199
armsrc/appmain.c
|
@ -60,7 +60,11 @@
|
|||
#include "ticks.h"
|
||||
#include "commonutil.h"
|
||||
#include "crc16.h"
|
||||
|
||||
#include "protocols.h"
|
||||
#include "mifareutil.h"
|
||||
#include "sam_picopass.h"
|
||||
#include "sam_seos.h"
|
||||
#include "sam_mfc.h"
|
||||
|
||||
#ifdef WITH_LCD
|
||||
#include "LCD_disabled.h"
|
||||
|
@ -365,11 +369,10 @@ static void print_debug_level(void) {
|
|||
|
||||
// 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) {
|
||||
static void printConnSpeed(uint32_t wait) {
|
||||
DbpString(_CYAN_("Transfer Speed"));
|
||||
Dbprintf(" Sending packets to client...");
|
||||
|
||||
#define CONN_SPEED_TEST_MIN_TIME 500 // in milliseconds
|
||||
uint8_t *test_data = BigBuf_get_addr();
|
||||
uint32_t start_time = GetTickCount();
|
||||
uint32_t delta_time = 0;
|
||||
|
@ -377,7 +380,7 @@ static void printConnSpeed(void) {
|
|||
|
||||
LED_B_ON();
|
||||
|
||||
while (delta_time < CONN_SPEED_TEST_MIN_TIME) {
|
||||
while (delta_time < wait) {
|
||||
reply_ng(CMD_DOWNLOADED_BIGBUF, PM3_SUCCESS, test_data, PM3_CMD_DATA_SIZE);
|
||||
bytes_transferred += PM3_CMD_DATA_SIZE;
|
||||
delta_time = GetTickCountDelta(start_time);
|
||||
|
@ -386,13 +389,15 @@ static void printConnSpeed(void) {
|
|||
|
||||
Dbprintf(" Time elapsed................... %dms", delta_time);
|
||||
Dbprintf(" Bytes transferred.............. %d", bytes_transferred);
|
||||
Dbprintf(" Transfer Speed PM3 -> Client... " _YELLOW_("%d") " bytes/s", 1000 * bytes_transferred / delta_time);
|
||||
if (delta_time) {
|
||||
Dbprintf(" Transfer Speed PM3 -> Client... " _YELLOW_("%llu") " bytes/s", 1000 * (uint64_t)bytes_transferred / delta_time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints runtime information about the PM3.
|
||||
**/
|
||||
static void SendStatus(void) {
|
||||
static void SendStatus(uint32_t wait) {
|
||||
BigBuf_print_status();
|
||||
Fpga_print_status();
|
||||
#ifdef WITH_FLASH
|
||||
|
@ -408,7 +413,7 @@ static void SendStatus(void) {
|
|||
#ifdef WITH_ISO14443a
|
||||
printHf14aConfig(); // HF 14a config
|
||||
#endif
|
||||
printConnSpeed();
|
||||
printConnSpeed(wait);
|
||||
DbpString(_CYAN_("Various"));
|
||||
|
||||
print_stack_usage();
|
||||
|
@ -427,7 +432,7 @@ static void SendStatus(void) {
|
|||
delta_time = GetTickCountDelta(start_time);
|
||||
if ((delta_time < SLCK_CHECK_MS - 1) || (delta_time > SLCK_CHECK_MS + 1)) {
|
||||
// error > 2% with SLCK_CHECK_MS=50
|
||||
Dbprintf(_RED_(" Slow Clock speed change detected, TIA needed"));
|
||||
Dbprintf(_RED_(" Slow Clock speed change detected, run `hw tia`"));
|
||||
Dbprintf(_YELLOW_(" Slow Clock actual speed seems closer to %d kHz"),
|
||||
(16 * MAINCK / 1000) / mainf * delta_time / SLCK_CHECK_MS);
|
||||
}
|
||||
|
@ -782,9 +787,19 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
g_reply_via_usb = false;
|
||||
break;
|
||||
}
|
||||
case CMD_SET_FPGAMODE: {
|
||||
uint8_t mode = packet->data.asBytes[0];
|
||||
if (mode >= FPGA_BITSTREAM_LF && mode <= FPGA_BITSTREAM_HF_15) {
|
||||
FpgaDownloadAndGo(mode);
|
||||
reply_ng(CMD_SET_FPGAMODE, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
reply_ng(CMD_SET_FPGAMODE, PM3_EINVARG, NULL, 0);
|
||||
break;
|
||||
}
|
||||
// emulator
|
||||
case CMD_SET_DBGMODE: {
|
||||
g_dbglevel = packet->data.asBytes[0];
|
||||
if (packet->length == 1 || packet->data.asBytes[1] != 0)
|
||||
print_debug_level();
|
||||
reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
|
@ -837,13 +852,13 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_LF_ACQ_RAW_ADC: {
|
||||
struct p {
|
||||
uint32_t samples : 31;
|
||||
bool verbose : 1;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
lf_sample_payload_t *payload = (lf_sample_payload_t *)packet->data.asBytes;
|
||||
if (payload->realtime) {
|
||||
ReadLF_realtime(true);
|
||||
} else {
|
||||
uint32_t bits = SampleLF(payload->verbose, payload->samples, true);
|
||||
reply_ng(CMD_LF_ACQ_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_LF_MOD_THEN_ACQ_RAW_ADC: {
|
||||
|
@ -866,14 +881,13 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_LF_SNIFF_RAW_ADC: {
|
||||
struct p {
|
||||
uint32_t samples : 31;
|
||||
bool verbose : 1;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
|
||||
lf_sample_payload_t *payload = (lf_sample_payload_t *)packet->data.asBytes;
|
||||
if (payload->realtime) {
|
||||
ReadLF_realtime(false);
|
||||
} else {
|
||||
uint32_t bits = SniffLF(payload->verbose, payload->samples, true);
|
||||
reply_ng(CMD_LF_SNIFF_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_LF_HID_WATCH: {
|
||||
|
@ -1143,27 +1157,27 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
|
||||
#ifdef WITH_EM4x50
|
||||
case CMD_LF_EM4X50_INFO: {
|
||||
em4x50_info((em4x50_data_t *)packet->data.asBytes, true);
|
||||
em4x50_info((const em4x50_data_t *)packet->data.asBytes, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X50_WRITE: {
|
||||
em4x50_write((em4x50_data_t *)packet->data.asBytes, true);
|
||||
em4x50_write((const em4x50_data_t *)packet->data.asBytes, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X50_WRITEPWD: {
|
||||
em4x50_writepwd((em4x50_data_t *)packet->data.asBytes, true);
|
||||
em4x50_writepwd((const em4x50_data_t *)packet->data.asBytes, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X50_READ: {
|
||||
em4x50_read((em4x50_data_t *)packet->data.asBytes, true);
|
||||
em4x50_read((const em4x50_data_t *)packet->data.asBytes, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X50_BRUTE: {
|
||||
em4x50_brute((em4x50_data_t *)packet->data.asBytes, true);
|
||||
em4x50_brute((const em4x50_data_t *)packet->data.asBytes, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X50_LOGIN: {
|
||||
em4x50_login((uint32_t *)packet->data.asBytes, true);
|
||||
em4x50_login((const uint32_t *)packet->data.asBytes, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X50_SIM: {
|
||||
|
@ -1173,7 +1187,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
// destroy the Emulator Memory.
|
||||
//-----------------------------------------------------------------------------
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
em4x50_sim((uint32_t *)packet->data.asBytes, true);
|
||||
em4x50_sim((const uint32_t *)packet->data.asBytes, true);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X50_READER: {
|
||||
|
@ -1197,7 +1211,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
// destroy the Emulator Memory.
|
||||
//-----------------------------------------------------------------------------
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
em4x50_chk((uint8_t *)packet->data.asBytes, true);
|
||||
em4x50_chk((const char *)packet->data.asBytes, true);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -1277,7 +1291,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint8_t data[];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
EmlSetMemIso15693(payload->count, payload->data, payload->offset);
|
||||
emlSet(payload->data, payload->offset, payload->count);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_SIMULATE: {
|
||||
|
@ -1415,7 +1429,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint8_t blockno;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
ReadSTBlock(payload->blockno);
|
||||
read_14b_st_block(payload->blockno);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO14443B_SNIFF: {
|
||||
|
@ -1556,7 +1570,9 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
case CMD_HF_MIFARE_READBL: {
|
||||
mf_readblock_t *payload = (mf_readblock_t *)packet->data.asBytes;
|
||||
MifareReadBlock(payload->blockno, payload->keytype, payload->key);
|
||||
uint8_t outbuf[16];
|
||||
int16_t retval = mifare_cmd_readblocks(MIFARE_AUTH_KEYA + (payload->keytype & 1), payload->key, ISO14443A_CMD_READBLOCK, payload->blockno, 1, outbuf);
|
||||
reply_ng(CMD_HF_MIFARE_READBL, retval, outbuf, sizeof(outbuf));
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFAREU_READBL: {
|
||||
|
@ -1580,7 +1596,19 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_WRITEBL: {
|
||||
MifareWriteBlock(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
|
||||
uint8_t block_no = packet->oldarg[0];
|
||||
uint8_t key_type = packet->oldarg[1];
|
||||
uint8_t *key = packet->data.asBytes;
|
||||
uint8_t *block_data = packet->data.asBytes + 10;
|
||||
|
||||
int16_t retval = mifare_cmd_writeblocks(MIFARE_AUTH_KEYA + (key_type & 1), key, ISO14443A_CMD_WRITEBLOCK, block_no, 1, block_data);
|
||||
|
||||
// convert ng style retval to old status
|
||||
if (retval >= 0) {
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
reply_mix(CMD_ACK, retval, 0, 0, 0, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_VALUE: {
|
||||
|
@ -1659,6 +1687,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
case CMD_HF_MIFARE_EML_MEMCLR: {
|
||||
MifareEMemClr();
|
||||
reply_ng(CMD_HF_MIFARE_EML_MEMCLR, PM3_SUCCESS, NULL, 0);
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_EML_MEMSET: {
|
||||
|
@ -1669,7 +1698,14 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint8_t data[];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
MifareEMemSet(payload->blockno, payload->blockcnt, payload->blockwidth, payload->data);
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
// backwards compat... default bytewidth
|
||||
if (payload->blockwidth == 0)
|
||||
payload->blockwidth = 16;
|
||||
|
||||
emlSetMem_xt(payload->data, payload->blockno, payload->blockcnt, payload->blockwidth);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_EML_MEMGET: {
|
||||
|
@ -1696,8 +1732,15 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_CIDENT: {
|
||||
bool is_mfc = packet->data.asBytes[0];
|
||||
MifareCIdent(is_mfc);
|
||||
|
||||
|
||||
struct p {
|
||||
uint8_t is_mfc;
|
||||
uint8_t keytype;
|
||||
uint8_t key[6];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
MifareCIdent(payload->is_mfc, payload->keytype, payload->key);
|
||||
break;
|
||||
}
|
||||
// Gen 3 magic cards
|
||||
|
@ -1740,7 +1783,9 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint8_t key[6];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
MifareReadConfigBlockGDM(payload->key);
|
||||
uint8_t outbuf[16];
|
||||
int16_t retval = mifare_cmd_readblocks(MIFARE_MAGIC_GDM_AUTH_KEY, payload->key, MIFARE_MAGIC_GDM_READ_CFG, 0, 1, outbuf);
|
||||
reply_ng(CMD_HF_MIFARE_G4_GDM_CONFIG, retval, outbuf, sizeof(outbuf));
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_G4_GDM_WRCFG: {
|
||||
|
@ -1748,18 +1793,20 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint8_t data[16];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
MifareWriteConfigBlockGDM(payload->data);
|
||||
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
|
||||
int16_t retval = mifare_cmd_writeblocks(MIFARE_MAGIC_GDM_AUTH_KEY, key, MIFARE_MAGIC_GDM_WRITE_CFG, 0, 1, payload->data);
|
||||
reply_ng(CMD_HF_MIFARE_G4_GDM_WRCFG, retval, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_G4_GDM_WRBL: {
|
||||
struct p {
|
||||
uint8_t blockno;
|
||||
uint8_t keytype;
|
||||
uint8_t key[6];
|
||||
uint8_t data[16]; // data to be written
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
MifareWriteBlockGDM(payload->blockno, payload->keytype, payload->key, payload->data);
|
||||
int16_t retval = mifare_cmd_writeblocks(MIFARE_MAGIC_GDM_AUTH_KEY, payload->key, MIFARE_MAGIC_GDM_WRITEBLOCK, payload->blockno, 1, payload->data);
|
||||
reply_ng(CMD_HF_MIFARE_G4_GDM_WRBL, retval, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_PERSONALIZE_UID: {
|
||||
|
@ -1826,6 +1873,17 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
MifareHasStaticNonce();
|
||||
break;
|
||||
}
|
||||
case CMD_HF_MIFARE_STATIC_ENCRYPTED_NONCE: {
|
||||
struct p {
|
||||
uint8_t block_no;
|
||||
uint8_t key_type;
|
||||
uint8_t key[6];
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
|
||||
MifareHasStaticEncryptedNonce(payload->block_no, payload->key_type, payload->key);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_NFCBARCODE
|
||||
|
@ -1904,6 +1962,10 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
iClass_Restore((iclass_restore_req_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_CREDIT_EPURSE: {
|
||||
iclass_credit_epurse((iclass_credit_epurse_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_HFSNIFF
|
||||
|
@ -1998,6 +2060,21 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
fwdata = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_HF_SAM_PICOPASS: {
|
||||
sam_picopass_get_pacs();
|
||||
break;
|
||||
}
|
||||
case CMD_HF_SAM_SEOS: {
|
||||
// sam_seos_get_pacs();
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_HF_SAM_MFC: {
|
||||
// sam_mfc_get_pacs();
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WITH_FPC_USART
|
||||
|
@ -2014,11 +2091,16 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint32_t waittime;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) &packet->data.asBytes;
|
||||
|
||||
uint16_t available;
|
||||
uint16_t pre_available = 0;
|
||||
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
|
||||
uint32_t wait = payload->waittime;
|
||||
|
||||
StartTicks();
|
||||
|
||||
uint32_t ti = GetTickCount();
|
||||
|
||||
while (true) {
|
||||
WaitMS(50);
|
||||
available = usart_rxdata_available();
|
||||
|
@ -2039,6 +2121,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
} else {
|
||||
reply_ng(CMD_USART_RX, PM3_ENODATA, NULL, 0);
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
BigBuf_free();
|
||||
LED_B_OFF();
|
||||
break;
|
||||
|
@ -2051,11 +2135,16 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
} PACKED;
|
||||
struct p *payload = (struct p *) &packet->data.asBytes;
|
||||
usart_writebuffer_sync(payload->data, packet->length - sizeof(payload));
|
||||
|
||||
uint16_t available;
|
||||
uint16_t pre_available = 0;
|
||||
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
|
||||
uint32_t wait = payload->waittime;
|
||||
|
||||
StartTicks();
|
||||
|
||||
uint32_t ti = GetTickCount();
|
||||
|
||||
while (true) {
|
||||
WaitMS(50);
|
||||
available = usart_rxdata_available();
|
||||
|
@ -2070,12 +2159,15 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
if (GetTickCountDelta(ti) > wait)
|
||||
break;
|
||||
}
|
||||
|
||||
if (available > 0) {
|
||||
uint16_t len = usart_read_ng(dest, available);
|
||||
reply_ng(CMD_USART_TXRX, PM3_SUCCESS, dest, len);
|
||||
} else {
|
||||
reply_ng(CMD_USART_TXRX, PM3_ENODATA, NULL, 0);
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
BigBuf_free();
|
||||
LED_B_OFF();
|
||||
break;
|
||||
|
@ -2112,8 +2204,9 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
case 2:
|
||||
if (button_status == BUTTON_SINGLE_CLICK)
|
||||
if (button_status == BUTTON_SINGLE_CLICK) {
|
||||
reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_EOPABORTED, NULL, 0);
|
||||
}
|
||||
uint16_t volt = MeasureAntennaTuningHfData();
|
||||
reply_ng(CMD_MEASURE_ANTENNA_TUNING_HF, PM3_SUCCESS, (uint8_t *)&volt, sizeof(volt));
|
||||
break;
|
||||
|
@ -2140,8 +2233,9 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
reply_ng(CMD_MEASURE_ANTENNA_TUNING_LF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
case 2:
|
||||
if (button_status == BUTTON_SINGLE_CLICK)
|
||||
if (button_status == BUTTON_SINGLE_CLICK) {
|
||||
reply_ng(CMD_MEASURE_ANTENNA_TUNING_LF, PM3_EOPABORTED, NULL, 0);
|
||||
}
|
||||
|
||||
uint32_t volt = MeasureAntennaTuningLfData();
|
||||
reply_ng(CMD_MEASURE_ANTENNA_TUNING_LF, PM3_SUCCESS, (uint8_t *)&volt, sizeof(volt));
|
||||
|
@ -2465,6 +2559,9 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
Flash_WriteEnable();
|
||||
Flash_Erase4k(3, 0xC);
|
||||
} else if (payload->startidx == DEFAULT_MF_KEYS_OFFSET) {
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
Flash_Erase4k(3, 0x8);
|
||||
Flash_CheckBusy(BUSY_TIMEOUT);
|
||||
Flash_WriteEnable();
|
||||
Flash_Erase4k(3, 0x9);
|
||||
|
@ -2587,7 +2684,10 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_STATUS: {
|
||||
SendStatus();
|
||||
if (packet->length == 4)
|
||||
SendStatus(packet->data.asDwords[0]);
|
||||
else
|
||||
SendStatus(CONN_SPEED_TEST_MIN_TIME_DEFAULT);
|
||||
break;
|
||||
}
|
||||
case CMD_TIA: {
|
||||
|
@ -2669,6 +2769,7 @@ void __attribute__((noreturn)) AppMain(void) {
|
|||
SpinDelay(100);
|
||||
BigBuf_initialize();
|
||||
|
||||
// Add stack canary
|
||||
for (uint32_t *p = _stack_start; p + 0x200 < _stack_end ; ++p) {
|
||||
*p = 0xdeadbeef;
|
||||
}
|
||||
|
@ -2718,9 +2819,6 @@ void __attribute__((noreturn)) AppMain(void) {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_FPC_USART
|
||||
usart_init(USART_BAUD_RATE, USART_PARITY);
|
||||
#endif
|
||||
|
||||
#ifdef WITH_FLASH
|
||||
// If flash is not present, BUSY_TIMEOUT kicks in, let's do it after USB
|
||||
|
@ -2733,20 +2831,27 @@ void __attribute__((noreturn)) AppMain(void) {
|
|||
rdv40_spiffs_check();
|
||||
#endif
|
||||
|
||||
#ifdef WITH_FPC_USART
|
||||
usart_init(USART_BAUD_RATE, USART_PARITY);
|
||||
#endif
|
||||
|
||||
allow_send_wtx = true;
|
||||
|
||||
// This is made as late as possible to ensure enumeration without timeout
|
||||
// against device such as http://www.hobbytronics.co.uk/usb-host-board-v2
|
||||
// In other words, keep the interval between usb_enable() and the main loop as short as possible.
|
||||
// (AT91F_CDC_Enumerate() will be called in the main loop)
|
||||
usb_disable();
|
||||
usb_enable();
|
||||
allow_send_wtx = true;
|
||||
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
if (*_stack_start != 0xdeadbeef) {
|
||||
Dbprintf("Stack overflow detected! Please increase stack size, currently %d bytes", (uint32_t)_stack_end - (uint32_t)_stack_start);
|
||||
Dbprintf("Unplug your device now.");
|
||||
Dbprintf("DEBUG: increase stack size, currently " _YELLOW_("%d") " bytes", (uint32_t)_stack_end - (uint32_t)_stack_start);
|
||||
Dbprintf("Stack overflow detected");
|
||||
Dbprintf("--> Unplug your device now! <--");
|
||||
hf_field_off();
|
||||
while (1);
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@ int tearoff_hook(void);
|
|||
// ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV
|
||||
#define MAX_ADC_LF_VOLTAGE 140800
|
||||
|
||||
// Default connection speed test timeout, used in hw status
|
||||
#define CONN_SPEED_TEST_MIN_TIME_DEFAULT 500 // in milliseconds
|
||||
|
||||
extern int ToSendMax;
|
||||
extern uint8_t ToSend[];
|
||||
|
||||
|
|
19
armsrc/cmd.c
19
armsrc/cmd.c
|
@ -18,6 +18,7 @@
|
|||
#include "usart.h"
|
||||
#include "crc16.h"
|
||||
#include "string.h"
|
||||
#include "BigBuf.h"
|
||||
|
||||
// Flags to tell where to add CRC on sent replies
|
||||
bool g_reply_with_crc_on_usb = false;
|
||||
|
@ -26,11 +27,11 @@ bool g_reply_with_crc_on_fpc = true;
|
|||
bool g_reply_via_fpc = false;
|
||||
bool g_reply_via_usb = false;
|
||||
|
||||
int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len) {
|
||||
int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len) {
|
||||
PacketResponseOLD txcmd = {CMD_UNKNOWN, {0, 0, 0}, {{0}}};
|
||||
|
||||
// for (size_t i = 0; i < sizeof(PacketResponseOLD); i++)
|
||||
// ((uint8_t *)&txcmd)[i] = 0x00;
|
||||
for (size_t i = 0; i < sizeof(PacketResponseOLD); i++)
|
||||
((uint8_t *)&txcmd)[i] = 0x00;
|
||||
|
||||
// Compose the outgoing command frame
|
||||
txcmd.cmd = cmd;
|
||||
|
@ -42,7 +43,7 @@ int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *d
|
|||
if (data && len) {
|
||||
len = MIN(len, PM3_CMD_DATA_SIZE);
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
txcmd.d.asBytes[i] = ((uint8_t *)data)[i];
|
||||
txcmd.d.asBytes[i] = ((const uint8_t *)data)[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -135,7 +136,7 @@ int reply_ng(uint16_t cmd, int16_t status, const uint8_t *data, size_t len) {
|
|||
return reply_ng_internal(cmd, status, data, len, true);
|
||||
}
|
||||
|
||||
int reply_mix(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len) {
|
||||
int reply_mix(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len) {
|
||||
int16_t status = PM3_SUCCESS;
|
||||
uint64_t arg[3] = {arg0, arg1, arg2};
|
||||
if (len > PM3_CMD_DATA_SIZE - sizeof(arg)) {
|
||||
|
@ -147,7 +148,8 @@ int reply_mix(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *d
|
|||
if (len && data)
|
||||
memcpy(cmddata + sizeof(arg), data, (int)len);
|
||||
|
||||
return reply_ng_internal((cmd & 0xFFFF), status, cmddata, len + sizeof(arg), false);
|
||||
int res = reply_ng_internal((cmd & 0xFFFF), status, cmddata, len + sizeof(arg), false);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int receive_ng_internal(PacketCommandNG *rx, uint32_t read_ng(uint8_t *data, size_t len), bool usb, bool fpc) {
|
||||
|
@ -178,9 +180,10 @@ static int receive_ng_internal(PacketCommandNG *rx, uint32_t read_ng(uint8_t *da
|
|||
memcpy(rx->data.asBytes, rx_raw.data, length);
|
||||
rx->length = length;
|
||||
} else {
|
||||
uint64_t arg[3];
|
||||
if (length < sizeof(arg))
|
||||
uint64_t arg[3] = {0};
|
||||
if (length < sizeof(arg)) {
|
||||
return PM3_EIO;
|
||||
}
|
||||
|
||||
memcpy(arg, rx_raw.data, sizeof(arg));
|
||||
rx->oldarg[0] = arg[0];
|
||||
|
|
|
@ -27,9 +27,9 @@ extern bool g_reply_with_crc_on_fpc;
|
|||
extern bool g_reply_via_fpc;
|
||||
extern bool g_reply_via_usb;
|
||||
|
||||
int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
|
||||
int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len);
|
||||
int reply_ng(uint16_t cmd, int16_t status, const uint8_t *data, size_t len);
|
||||
int reply_mix(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
|
||||
int reply_mix(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len);
|
||||
int receive_ng(PacketCommandNG *rx);
|
||||
|
||||
#endif // _PROXMARK_CMD_H_
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "printf.h"
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
#define DEBUG_MAX_MSG_SIZE 200
|
||||
//=============================================================================
|
||||
// Debug print functions, to go out over USB, to the usual PC-side client.
|
||||
//=============================================================================
|
||||
|
@ -31,7 +31,7 @@ void DbpStringEx(uint32_t flags, const char *src, size_t srclen) {
|
|||
#if DEBUG
|
||||
struct {
|
||||
uint16_t flag;
|
||||
uint8_t buf[PM3_CMD_DATA_SIZE - sizeof(uint16_t)];
|
||||
uint8_t buf[DEBUG_MAX_MSG_SIZE];
|
||||
} PACKED data;
|
||||
data.flag = flags;
|
||||
uint16_t len = MIN(srclen, sizeof(data.buf));
|
||||
|
@ -49,7 +49,7 @@ void DbpString(const char *str) {
|
|||
void DbprintfEx(uint32_t flags, const char *fmt, ...) {
|
||||
#if DEBUG
|
||||
// should probably limit size here; oh well, let's just use a big buffer
|
||||
char s[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
char s[DEBUG_MAX_MSG_SIZE] = {0x00};
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
kvsprintf(fmt, s, 10, ap);
|
||||
|
@ -62,7 +62,7 @@ void DbprintfEx(uint32_t flags, const char *fmt, ...) {
|
|||
void Dbprintf(const char *fmt, ...) {
|
||||
#if DEBUG
|
||||
// should probably limit size here; oh well, let's just use a big buffer
|
||||
char output_string[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
char output_string[DEBUG_MAX_MSG_SIZE] = {0x00};
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
@ -74,13 +74,13 @@ void Dbprintf(const char *fmt, ...) {
|
|||
}
|
||||
|
||||
// prints HEX & ASCII
|
||||
void Dbhexdump(int len, uint8_t *d, bool bAsci) {
|
||||
void Dbhexdump(int len, const uint8_t *d, bool bAsci) {
|
||||
#if DEBUG
|
||||
char ascii[9];
|
||||
char ascii[17];
|
||||
|
||||
while (len > 0) {
|
||||
|
||||
int l = (len > 8) ? 8 : len;
|
||||
int l = (len > 16) ? 16 : len;
|
||||
|
||||
memcpy(ascii, d, l);
|
||||
ascii[l] = 0;
|
||||
|
@ -97,33 +97,41 @@ void Dbhexdump(int len, uint8_t *d, bool bAsci) {
|
|||
else
|
||||
Dbprintf("%*D", l, d, " ");
|
||||
|
||||
len -= 8;
|
||||
d += 8;
|
||||
len -= 16;
|
||||
d += 16;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void print_result(const char *name, uint8_t *buf, size_t len) {
|
||||
void print_result(const char *name, const uint8_t *d, size_t n) {
|
||||
|
||||
uint8_t *p = buf;
|
||||
uint16_t tmp = len & 0xFFF0;
|
||||
const uint8_t *p = d;
|
||||
uint16_t tmp = n & 0xFFF0;
|
||||
|
||||
for (; p - buf < tmp; p += 16) {
|
||||
for (; p - d < tmp; p += 16) {
|
||||
Dbprintf("[%s: %02d/%02d] %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
|
||||
name,
|
||||
p - buf,
|
||||
len,
|
||||
p - d,
|
||||
n,
|
||||
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]
|
||||
);
|
||||
}
|
||||
if (len % 16 != 0) {
|
||||
|
||||
if (n % 16 != 0) {
|
||||
char s[46] = {0};
|
||||
char *sp = s;
|
||||
for (; p - buf < len; p++) {
|
||||
for (; p - d < n; p++) {
|
||||
sprintf(sp, "%02x ", p[0]);
|
||||
sp += 3;
|
||||
}
|
||||
Dbprintf("[%s: %02d/%02d] %s", name, p - buf, len, s);
|
||||
Dbprintf("[%s: %02d/%02d] %s", name, p - d, n, s);
|
||||
}
|
||||
}
|
||||
|
||||
// Prints message and hexdump
|
||||
void print_dbg(char *msg, uint8_t *d, uint16_t n) {
|
||||
if (g_dbglevel == DBG_DEBUG) {
|
||||
print_result(msg, d, n);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,40 +22,13 @@
|
|||
#include "common.h"
|
||||
#include "ansi.h"
|
||||
|
||||
#define Dbprintf_usb(...) {\
|
||||
bool tmpfpc = g_reply_via_fpc;\
|
||||
bool tmpusb = g_reply_via_usb;\
|
||||
g_reply_via_fpc = false;\
|
||||
g_reply_via_usb = true;\
|
||||
Dbprintf(__VA_ARGS__);\
|
||||
g_reply_via_fpc = tmpfpc;\
|
||||
g_reply_via_usb = tmpusb;}
|
||||
|
||||
#define Dbprintf_fpc(...) {\
|
||||
bool tmpfpc = g_reply_via_fpc;\
|
||||
bool tmpusb = g_reply_via_usb;\
|
||||
g_reply_via_fpc = true;\
|
||||
g_reply_via_usb = false;\
|
||||
Dbprintf(__VA_ARGS__);\
|
||||
g_reply_via_fpc = tmpfpc;\
|
||||
g_reply_via_usb = tmpusb;}
|
||||
|
||||
#define Dbprintf_all(...) {\
|
||||
bool tmpfpc = g_reply_via_fpc;\
|
||||
bool tmpusb = g_reply_via_usb;\
|
||||
g_reply_via_fpc = true;\
|
||||
g_reply_via_usb = true;\
|
||||
Dbprintf(__VA_ARGS__);\
|
||||
g_reply_via_fpc = tmpfpc;\
|
||||
g_reply_via_usb = tmpusb;}
|
||||
|
||||
|
||||
void DbpString(const char *str);
|
||||
void DbpStringEx(uint32_t flags, const char *src, size_t srclen);
|
||||
void Dbprintf(const char *fmt, ...);
|
||||
void DbprintfEx(uint32_t flags, const char *fmt, ...);
|
||||
void Dbhexdump(int len, uint8_t *d, bool bAsci);
|
||||
void print_result(const char *name, uint8_t *buf, size_t len);
|
||||
void Dbhexdump(int len, const uint8_t *d, bool bAsci);
|
||||
void print_result(const char *name, const uint8_t *buf, size_t len);
|
||||
void print_dbg(char *msg, uint8_t *d, uint16_t n);
|
||||
//void PrintToSendBuffer(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -634,7 +634,7 @@ static int login(uint32_t password) {
|
|||
}
|
||||
|
||||
// searching for password using chosen bruteforce algorithm
|
||||
static bool brute(em4x50_data_t *etd, uint32_t *pwd) {
|
||||
static bool brute(const em4x50_data_t *etd, uint32_t *pwd) {
|
||||
|
||||
generator_context_t ctx;
|
||||
bool pwd_found = false;
|
||||
|
@ -698,7 +698,7 @@ static bool brute(em4x50_data_t *etd, uint32_t *pwd) {
|
|||
}
|
||||
|
||||
// login into EM4x50
|
||||
void em4x50_login(uint32_t *password, bool ledcontrol) {
|
||||
void em4x50_login(const uint32_t *password, bool ledcontrol) {
|
||||
em4x50_setup_read();
|
||||
|
||||
int status = PM3_EFAILED;
|
||||
|
@ -717,7 +717,7 @@ void em4x50_login(uint32_t *password, bool ledcontrol) {
|
|||
}
|
||||
|
||||
// invoke password search
|
||||
void em4x50_brute(em4x50_data_t *etd, bool ledcontrol) {
|
||||
void em4x50_brute(const em4x50_data_t *etd, bool ledcontrol) {
|
||||
em4x50_setup_read();
|
||||
|
||||
bool bsuccess = false;
|
||||
|
@ -737,7 +737,7 @@ void em4x50_brute(em4x50_data_t *etd, bool ledcontrol) {
|
|||
}
|
||||
|
||||
// check passwords from dictionary content in flash memory
|
||||
void em4x50_chk(uint8_t *filename, bool ledcontrol) {
|
||||
void em4x50_chk(const char *filename, bool ledcontrol) {
|
||||
int status = PM3_EFAILED;
|
||||
uint32_t pwd = 0x0;
|
||||
|
||||
|
@ -747,11 +747,11 @@ void em4x50_chk(uint8_t *filename, bool ledcontrol) {
|
|||
|
||||
int changed = rdv40_spiffs_lazy_mount();
|
||||
uint16_t pwd_count = 0;
|
||||
uint32_t size = size_in_spiffs((char *)filename);
|
||||
uint32_t size = size_in_spiffs(filename);
|
||||
pwd_count = size / 4;
|
||||
uint8_t *pwds = BigBuf_malloc(size);
|
||||
|
||||
rdv40_spiffs_read_as_filetype((char *)filename, pwds, size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
rdv40_spiffs_read_as_filetype(filename, pwds, size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
||||
if (changed)
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
|
@ -877,7 +877,7 @@ static int selective_read(uint32_t addresses, uint32_t *words) {
|
|||
}
|
||||
|
||||
// reads by using "selective read mode" -> bidirectional communication
|
||||
void em4x50_read(em4x50_data_t *etd, bool ledcontrol) {
|
||||
void em4x50_read(const em4x50_data_t *etd, bool ledcontrol) {
|
||||
int status = PM3_EFAILED;
|
||||
uint32_t words[EM4X50_NO_WORDS] = {0x0};
|
||||
|
||||
|
@ -910,7 +910,7 @@ void em4x50_read(em4x50_data_t *etd, bool ledcontrol) {
|
|||
}
|
||||
|
||||
// collects as much information as possible via selective read mode
|
||||
void em4x50_info(em4x50_data_t *etd, bool ledcontrol) {
|
||||
void em4x50_info(const em4x50_data_t *etd, bool ledcontrol) {
|
||||
int status = PM3_EFAILED;
|
||||
uint32_t words[EM4X50_NO_WORDS] = {0x0};
|
||||
|
||||
|
@ -1057,7 +1057,7 @@ static int write_password(uint32_t password, uint32_t new_password) {
|
|||
// write operation process for EM4x50 tag,
|
||||
// single word is written to given address, verified by selective read operation
|
||||
// wrong password -> return with PM3_EFAILED
|
||||
void em4x50_write(em4x50_data_t *etd, bool ledcontrol) {
|
||||
void em4x50_write(const em4x50_data_t *etd, bool ledcontrol) {
|
||||
int status = PM3_EFAILED;
|
||||
uint32_t words[EM4X50_NO_WORDS] = {0x0};
|
||||
|
||||
|
@ -1117,7 +1117,7 @@ void em4x50_write(em4x50_data_t *etd, bool ledcontrol) {
|
|||
}
|
||||
|
||||
// simple change of password
|
||||
void em4x50_writepwd(em4x50_data_t *etd, bool ledcontrol) {
|
||||
void em4x50_writepwd(const em4x50_data_t *etd, bool ledcontrol) {
|
||||
int status = PM3_EFAILED;
|
||||
|
||||
em4x50_setup_read();
|
||||
|
@ -1362,7 +1362,7 @@ static bool em4x50_sim_read_word(uint32_t *word) {
|
|||
}
|
||||
|
||||
// check if reader requests receive mode (rm) by sending two zeros
|
||||
static int check_rm_request(uint32_t *tag, bool ledcontrol) {
|
||||
static int check_rm_request(const uint32_t *tag, bool ledcontrol) {
|
||||
|
||||
// look for first zero
|
||||
int bit = em4x50_sim_read_bit();
|
||||
|
@ -1391,7 +1391,7 @@ static int check_rm_request(uint32_t *tag, bool ledcontrol) {
|
|||
}
|
||||
|
||||
// send single listen window in simulation mode
|
||||
static int em4x50_sim_send_listen_window(uint32_t *tag, bool ledcontrol) {
|
||||
static int em4x50_sim_send_listen_window(const uint32_t *tag, bool ledcontrol) {
|
||||
|
||||
SHORT_COIL();
|
||||
wait_cycles(EM4X50_T_TAG_HALF_PERIOD);
|
||||
|
@ -1464,7 +1464,7 @@ static void em4x50_sim_send_nak(void) {
|
|||
}
|
||||
|
||||
// standard read mode process (simulation mode)
|
||||
static int em4x50_sim_handle_standard_read_command(uint32_t *tag, bool ledcontrol) {
|
||||
static int em4x50_sim_handle_standard_read_command(const uint32_t *tag, bool ledcontrol) {
|
||||
|
||||
// extract control data
|
||||
int fwr = reflect32(tag[EM4X50_CONTROL]) & 0xFF; // first word read
|
||||
|
@ -1504,7 +1504,7 @@ static int em4x50_sim_handle_standard_read_command(uint32_t *tag, bool ledcontro
|
|||
}
|
||||
|
||||
// selective read mode process (simulation mode)
|
||||
static int em4x50_sim_handle_selective_read_command(uint32_t *tag, bool ledcontrol) {
|
||||
static int em4x50_sim_handle_selective_read_command(const uint32_t *tag, bool ledcontrol) {
|
||||
|
||||
// read password
|
||||
uint32_t address = 0;
|
||||
|
@ -1559,7 +1559,7 @@ static int em4x50_sim_handle_selective_read_command(uint32_t *tag, bool ledcontr
|
|||
}
|
||||
|
||||
// login process (simulation mode)
|
||||
static int em4x50_sim_handle_login_command(uint32_t *tag, bool ledcontrol) {
|
||||
static int em4x50_sim_handle_login_command(const uint32_t *tag, bool ledcontrol) {
|
||||
|
||||
// read password
|
||||
uint32_t password = 0;
|
||||
|
@ -1585,7 +1585,7 @@ static int em4x50_sim_handle_login_command(uint32_t *tag, bool ledcontrol) {
|
|||
}
|
||||
|
||||
// reset process (simulation mode)
|
||||
static int em4x50_sim_handle_reset_command(uint32_t *tag, bool ledcontrol) {
|
||||
static int em4x50_sim_handle_reset_command(const uint32_t *tag, bool ledcontrol) {
|
||||
|
||||
// processing pause time (corresponds to a "1" bit)
|
||||
em4x50_sim_send_bit(1);
|
||||
|
@ -1810,7 +1810,7 @@ void em4x50_handle_commands(int *command, uint32_t *tag, bool ledcontrol) {
|
|||
// simulate uploaded data in emulator memory
|
||||
// LED C -> reader command has been detected
|
||||
// LED D -> operations that require authentication are possible
|
||||
void em4x50_sim(uint32_t *password, bool ledcontrol) {
|
||||
void em4x50_sim(const uint32_t *password, bool ledcontrol) {
|
||||
|
||||
int command = PM3_ENODATA;
|
||||
|
||||
|
|
|
@ -21,20 +21,21 @@
|
|||
|
||||
#include "../include/em4x50.h"
|
||||
|
||||
// used by standalone mode
|
||||
void em4x50_setup_read(void);
|
||||
int standard_read(int *now, uint32_t *words);
|
||||
|
||||
void em4x50_setup_sim(void);
|
||||
void em4x50_handle_commands(int *command, uint32_t *tag, bool ledcontrol);
|
||||
|
||||
void em4x50_info(em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_write(em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_writepwd(em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_read(em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_brute(em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_login(uint32_t *password, bool ledcontrol);
|
||||
void em4x50_sim(uint32_t *password, bool ledcontrol);
|
||||
// dispatch functions (appmain.c)
|
||||
void em4x50_info(const em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_write(const em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_writepwd(const em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_read(const em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_brute(const em4x50_data_t *etd, bool ledcontrol);
|
||||
void em4x50_login(const uint32_t *password, bool ledcontrol);
|
||||
void em4x50_sim(const uint32_t *password, bool ledcontrol);
|
||||
void em4x50_reader(bool ledcontrol);
|
||||
void em4x50_chk(uint8_t *filename, bool ledcontrol);
|
||||
void em4x50_chk(const char *filename, bool ledcontrol);
|
||||
|
||||
#endif /* EM4X50_H */
|
||||
|
|
|
@ -310,6 +310,7 @@ static bool check_ack(void) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: define and use structs for rnd, frnd, response
|
||||
static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *response) {
|
||||
|
||||
if (find_listen_window(true)) {
|
||||
|
@ -350,8 +351,10 @@ static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *respon
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
static int set_byte(uint8_t *target, int value) {
|
||||
int c = value > 0xFF;
|
||||
// Sets one (reflected) byte and returns carry bit
|
||||
// (1 if `value` parameter was greater than 0xFF)
|
||||
static int set_byte(uint8_t *target, uint16_t value) {
|
||||
int c = value > 0xFF ? 1 : 0; // be explicit about carry bit values
|
||||
*target = reflect8(value);
|
||||
return c;
|
||||
}
|
||||
|
@ -373,8 +376,8 @@ static int bruteforce(const uint8_t address, const uint8_t *rnd, const uint8_t *
|
|||
uint16_t rev_k = reflect16(k);
|
||||
switch (address) {
|
||||
case 9:
|
||||
c = set_byte(&temp_rnd[0], rev_rnd[0] + (rev_k & 0xFF));
|
||||
c = set_byte(&temp_rnd[1], rev_rnd[1] + c + ((rev_k >> 8) & 0xFF));
|
||||
c = set_byte(&temp_rnd[0], rev_rnd[0] + ((rev_k) & 0xFFu));
|
||||
c = set_byte(&temp_rnd[1], rev_rnd[1] + c + ((rev_k >> 8) & 0xFFu));
|
||||
c = set_byte(&temp_rnd[2], rev_rnd[2] + c);
|
||||
c = set_byte(&temp_rnd[3], rev_rnd[3] + c);
|
||||
c = set_byte(&temp_rnd[4], rev_rnd[4] + c);
|
||||
|
@ -383,16 +386,16 @@ static int bruteforce(const uint8_t address, const uint8_t *rnd, const uint8_t *
|
|||
break;
|
||||
|
||||
case 8:
|
||||
c = set_byte(&temp_rnd[2], rev_rnd[2] + (rev_k & 0xFF));
|
||||
c = set_byte(&temp_rnd[3], rev_rnd[3] + c + ((rev_k >> 8) & 0xFF));
|
||||
c = set_byte(&temp_rnd[2], rev_rnd[2] + ((rev_k) & 0xFFu));
|
||||
c = set_byte(&temp_rnd[3], rev_rnd[3] + c + ((rev_k >> 8) & 0xFFu));
|
||||
c = set_byte(&temp_rnd[4], rev_rnd[4] + c);
|
||||
c = set_byte(&temp_rnd[5], rev_rnd[5] + c);
|
||||
set_byte(&temp_rnd[6], rev_rnd[6] + c);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
c = set_byte(&temp_rnd[4], rev_rnd[4] + (rev_k & 0xFF));
|
||||
c = set_byte(&temp_rnd[5], rev_rnd[5] + c + ((rev_k >> 8) & 0xFF));
|
||||
c = set_byte(&temp_rnd[4], rev_rnd[4] + ((rev_k) & 0xFFu));
|
||||
c = set_byte(&temp_rnd[5], rev_rnd[5] + c + ((rev_k >> 8) & 0xFFu));
|
||||
set_byte(&temp_rnd[6], rev_rnd[6] + c);
|
||||
break;
|
||||
|
||||
|
@ -707,7 +710,7 @@ static int em4x70_receive(uint8_t *bits, size_t length) {
|
|||
return bit_pos;
|
||||
}
|
||||
|
||||
void em4x70_info(em4x70_data_t *etd, bool ledcontrol) {
|
||||
void em4x70_info(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
|
||||
|
@ -728,7 +731,7 @@ void em4x70_info(em4x70_data_t *etd, bool ledcontrol) {
|
|||
reply_ng(CMD_LF_EM4X70_INFO, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
||||
void em4x70_write(em4x70_data_t *etd, bool ledcontrol) {
|
||||
void em4x70_write(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
|
||||
|
@ -758,7 +761,7 @@ void em4x70_write(em4x70_data_t *etd, bool ledcontrol) {
|
|||
reply_ng(CMD_LF_EM4X70_WRITE, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
||||
void em4x70_unlock(em4x70_data_t *etd, bool ledcontrol) {
|
||||
void em4x70_unlock(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
|
||||
|
@ -791,7 +794,7 @@ void em4x70_unlock(em4x70_data_t *etd, bool ledcontrol) {
|
|||
reply_ng(CMD_LF_EM4X70_UNLOCK, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
||||
void em4x70_auth(em4x70_data_t *etd, bool ledcontrol) {
|
||||
void em4x70_auth(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
uint8_t response[3] = {0};
|
||||
|
@ -813,7 +816,7 @@ void em4x70_auth(em4x70_data_t *etd, bool ledcontrol) {
|
|||
reply_ng(CMD_LF_EM4X70_AUTH, status, response, sizeof(response));
|
||||
}
|
||||
|
||||
void em4x70_brute(em4x70_data_t *etd, bool ledcontrol) {
|
||||
void em4x70_brute(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
uint8_t status = 0;
|
||||
uint8_t response[2] = {0};
|
||||
|
||||
|
@ -834,7 +837,7 @@ void em4x70_brute(em4x70_data_t *etd, bool ledcontrol) {
|
|||
reply_ng(CMD_LF_EM4X70_BRUTE, status, response, sizeof(response));
|
||||
}
|
||||
|
||||
void em4x70_write_pin(em4x70_data_t *etd, bool ledcontrol) {
|
||||
void em4x70_write_pin(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
|
||||
|
@ -850,7 +853,7 @@ void em4x70_write_pin(em4x70_data_t *etd, bool ledcontrol) {
|
|||
if (em4x70_read_id()) {
|
||||
|
||||
// Write new PIN
|
||||
if ((write(etd->pin & 0xFFFF, EM4X70_PIN_WORD_UPPER) == PM3_SUCCESS) &&
|
||||
if ((write((etd->pin) & 0xFFFF, EM4X70_PIN_WORD_UPPER) == PM3_SUCCESS) &&
|
||||
(write((etd->pin >> 16) & 0xFFFF, EM4X70_PIN_WORD_LOWER) == PM3_SUCCESS)) {
|
||||
|
||||
// Now Try to authenticate using the new PIN
|
||||
|
@ -874,7 +877,7 @@ void em4x70_write_pin(em4x70_data_t *etd, bool ledcontrol) {
|
|||
reply_ng(CMD_LF_EM4X70_WRITEPIN, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
||||
void em4x70_write_key(em4x70_data_t *etd, bool ledcontrol) {
|
||||
void em4x70_write_key(const em4x70_data_t *etd, bool ledcontrol) {
|
||||
|
||||
uint8_t status = 0;
|
||||
|
||||
|
|
|
@ -30,12 +30,12 @@ typedef enum {
|
|||
FALLING_EDGE
|
||||
} edge_detection_t;
|
||||
|
||||
void em4x70_info(em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_write(em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_brute(em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_unlock(em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_auth(em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_write_pin(em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_write_key(em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_info(const em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_write(const em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_brute(const em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_unlock(const em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_auth(const em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_write_pin(const em4x70_data_t *etd, bool ledcontrol);
|
||||
void em4x70_write_key(const em4x70_data_t *etd, bool ledcontrol);
|
||||
|
||||
#endif /* EM4x70_H */
|
||||
|
|
40
armsrc/epa.c
40
armsrc/epa.c
|
@ -37,6 +37,24 @@
|
|||
static const uint8_t pps[] = {0xD0, 0x11, 0x00, 0x52, 0xA6};
|
||||
#endif
|
||||
|
||||
// this struct is used by EPA_Parse_CardAccess and contains info about the
|
||||
// PACE protocol supported by the chip
|
||||
typedef struct {
|
||||
uint8_t oid[10];
|
||||
uint8_t version;
|
||||
uint8_t parameter_id;
|
||||
} pace_version_info_t;
|
||||
|
||||
// general functions
|
||||
static void EPA_Finish(void);
|
||||
static size_t EPA_Parse_CardAccess(const uint8_t *data, size_t length, pace_version_info_t *pace_info);
|
||||
static int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length);
|
||||
static int EPA_Setup(void);
|
||||
|
||||
// PACE related functions
|
||||
static int EPA_PACE_MSE_Set_AT(const pace_version_info_t pace_version_info, uint8_t password);
|
||||
static int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce);
|
||||
|
||||
// APDUs for communication with German Identification Card
|
||||
|
||||
// General Authenticate (request encrypted nonce) WITHOUT the Le at the end
|
||||
|
@ -137,7 +155,7 @@ static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t re
|
|||
#endif
|
||||
case 'b':
|
||||
#ifdef WITH_ISO14443b
|
||||
return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL);
|
||||
return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL, NULL);
|
||||
#else
|
||||
(void) apdu;
|
||||
(void) length;
|
||||
|
@ -153,7 +171,7 @@ static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t re
|
|||
//-----------------------------------------------------------------------------
|
||||
// Closes the communication channel and turns off the field
|
||||
//-----------------------------------------------------------------------------
|
||||
void EPA_Finish(void) {
|
||||
static void EPA_Finish(void) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
iso_type = 0;
|
||||
|
@ -172,7 +190,7 @@ 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) {
|
||||
static size_t EPA_Parse_CardAccess(const uint8_t *data, size_t length, pace_version_info_t *pace_info) {
|
||||
|
||||
size_t index = 0;
|
||||
|
||||
|
@ -243,7 +261,7 @@ size_t EPA_Parse_CardAccess(uint8_t *data, size_t length, pace_version_info_t *p
|
|||
// Returns -1 on failure or the length of the data on success
|
||||
// TODO: for the moment this sends only 1 APDU regardless of the requested length
|
||||
//-----------------------------------------------------------------------------
|
||||
int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) {
|
||||
static int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length) {
|
||||
// the response APDU of the card
|
||||
// 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)
|
||||
|
@ -300,7 +318,7 @@ static void EPA_PACE_Collect_Nonce_Abort(uint32_t cmd, uint8_t step, int func_re
|
|||
//-----------------------------------------------------------------------------
|
||||
// Acquire one encrypted PACE nonce
|
||||
//-----------------------------------------------------------------------------
|
||||
void EPA_PACE_Collect_Nonce(PacketCommandNG *c) {
|
||||
void EPA_PACE_Collect_Nonce(const PacketCommandNG *c) {
|
||||
/*
|
||||
* ack layout:
|
||||
* arg:
|
||||
|
@ -354,7 +372,7 @@ void EPA_PACE_Collect_Nonce(PacketCommandNG *c) {
|
|||
struct p {
|
||||
uint32_t m;
|
||||
} PACKED;
|
||||
struct p *packet = (struct p *)c->data.asBytes;
|
||||
const struct p *packet = (const struct p *)c->data.asBytes;
|
||||
|
||||
func_return = EPA_PACE_Get_Nonce(packet->m, nonce);
|
||||
// check if the command succeeded
|
||||
|
@ -377,7 +395,7 @@ void EPA_PACE_Collect_Nonce(PacketCommandNG *c) {
|
|||
// Returns the actual size of the nonce on success or a less-than-zero error
|
||||
// code on failure.
|
||||
//-----------------------------------------------------------------------------
|
||||
int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) {
|
||||
static 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];
|
||||
|
@ -416,7 +434,7 @@ int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce) {
|
|||
// Initializes the PACE protocol by performing the "MSE: Set AT" step
|
||||
// Returns 0 on success or a non-zero error code on failure
|
||||
//-----------------------------------------------------------------------------
|
||||
int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password) {
|
||||
static int EPA_PACE_MSE_Set_AT(const pace_version_info_t pace_version_info, uint8_t password) {
|
||||
// create the MSE: Set AT APDU
|
||||
uint8_t apdu[23];
|
||||
|
||||
|
@ -479,7 +497,7 @@ int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password)
|
|||
//-----------------------------------------------------------------------------
|
||||
// Perform the PACE protocol by replaying given APDUs
|
||||
//-----------------------------------------------------------------------------
|
||||
void EPA_PACE_Replay(PacketCommandNG *c) {
|
||||
void EPA_PACE_Replay(const PacketCommandNG *c) {
|
||||
|
||||
uint32_t timings[ARRAYLEN(apdu_lengths_replay)] = {0};
|
||||
|
||||
|
@ -547,7 +565,7 @@ void EPA_PACE_Replay(PacketCommandNG *c) {
|
|||
// Set up a communication channel (Card Select, PPS)
|
||||
// Returns 0 on success or a non-zero error code on failure
|
||||
//-----------------------------------------------------------------------------
|
||||
int EPA_Setup(void) {
|
||||
static int EPA_Setup(void) {
|
||||
|
||||
#ifdef WITH_ISO14443a
|
||||
{
|
||||
|
@ -593,7 +611,7 @@ int EPA_Setup(void) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
void EPA_PACE_Simulate(PacketCommandNG *c) {
|
||||
void EPA_PACE_Simulate(const PacketCommandNG *c) {
|
||||
|
||||
//---------Initializing---------
|
||||
|
||||
|
|
24
armsrc/epa.h
24
armsrc/epa.h
|
@ -22,26 +22,8 @@
|
|||
#include "common.h"
|
||||
#include "pm3_cmd.h"
|
||||
|
||||
// this struct is used by EPA_Parse_CardAccess and contains info about the
|
||||
// PACE protocol supported by the chip
|
||||
typedef struct {
|
||||
uint8_t oid[10];
|
||||
uint8_t version;
|
||||
uint8_t parameter_id;
|
||||
} pace_version_info_t;
|
||||
|
||||
// general functions
|
||||
void EPA_Finish(void);
|
||||
size_t EPA_Parse_CardAccess(uint8_t *data, size_t length, pace_version_info_t *pace_info);
|
||||
int EPA_Read_CardAccess(uint8_t *buffer, size_t max_length);
|
||||
int EPA_Setup(void);
|
||||
|
||||
// PACE related functions
|
||||
int EPA_PACE_MSE_Set_AT(pace_version_info_t pace_version_info, uint8_t password);
|
||||
int EPA_PACE_Get_Nonce(uint8_t requested_length, uint8_t *nonce);
|
||||
|
||||
void EPA_PACE_Collect_Nonce(PacketCommandNG *c);
|
||||
void EPA_PACE_Replay(PacketCommandNG *c);
|
||||
void EPA_PACE_Simulate(PacketCommandNG *c);
|
||||
void EPA_PACE_Collect_Nonce(const PacketCommandNG *c);
|
||||
void EPA_PACE_Replay(const PacketCommandNG *c);
|
||||
void EPA_PACE_Simulate(const PacketCommandNG *c);
|
||||
|
||||
#endif /* __EPA_H */
|
||||
|
|
|
@ -49,7 +49,7 @@ static uint32_t felica_lasttime_prox2air_start;
|
|||
|
||||
static void iso18092_setup(uint8_t fpga_minor_mode);
|
||||
static uint8_t felica_select_card(felica_card_select_t *card);
|
||||
static void TransmitFor18092_AsReader(uint8_t *frame, uint16_t len, uint32_t *timing, uint8_t power, uint8_t highspeed);
|
||||
static void TransmitFor18092_AsReader(const uint8_t *frame, uint16_t len, const uint32_t *NYI_timing_NYI, uint8_t power, uint8_t highspeed);
|
||||
static bool WaitForFelicaReply(uint16_t maxbytes);
|
||||
|
||||
static void iso18092_set_timeout(uint32_t timeout) {
|
||||
|
@ -350,7 +350,12 @@ static void BuildFliteRdblk(const uint8_t *idm, uint8_t blocknum, const uint16_t
|
|||
AddCrc(frameSpace + 2, c - 2);
|
||||
}
|
||||
|
||||
static void TransmitFor18092_AsReader(uint8_t *frame, uint16_t len, uint32_t *timing, uint8_t power, uint8_t highspeed) {
|
||||
static void TransmitFor18092_AsReader(const uint8_t *frame, uint16_t len, const uint32_t *NYI_timing_NYI, uint8_t power, uint8_t highspeed) {
|
||||
if (NYI_timing_NYI != NULL) {
|
||||
Dbprintf("Error: TransmitFor18092_AsReader does not check or set parameter NYI_timing_NYI");
|
||||
return;
|
||||
}
|
||||
|
||||
uint16_t flags = FPGA_MAJOR_MODE_HF_ISO18092;
|
||||
if (power)
|
||||
flags |= FPGA_HF_ISO18092_FLAG_READER;
|
||||
|
@ -512,12 +517,12 @@ static void felica_reset_frame_mode(void) {
|
|||
// arg0 FeliCa flags
|
||||
// arg1 len of commandbytes
|
||||
// d.asBytes command bytes to send
|
||||
void felica_sendraw(PacketCommandNG *c) {
|
||||
void felica_sendraw(const PacketCommandNG *c) {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("FeliCa_sendraw Enter");
|
||||
|
||||
felica_command_t param = c->oldarg[0];
|
||||
size_t len = c->oldarg[1] & 0xffff;
|
||||
uint8_t *cmd = c->data.asBytes;
|
||||
const uint8_t *cmd = c->data.asBytes;
|
||||
uint32_t arg0;
|
||||
|
||||
felica_card_select_t card;
|
||||
|
@ -675,7 +680,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
|
|||
#define R_READBLK_LEN 0x21
|
||||
//simulate NFC Tag3 card - for now only poll response works
|
||||
// second half (4 bytes) of NDEF2 goes into nfcid2_0, first into nfcid2_1
|
||||
void felica_sim_lite(uint8_t *uid) {
|
||||
void felica_sim_lite(const uint8_t *uid) {
|
||||
|
||||
// prepare our 3 responses...
|
||||
uint8_t resp_poll0[R_POLL0_LEN] = { 0xb2, 0x4d, 0x12, FELICA_POLL_ACK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, 0xb3, 0x7f};
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
#include "common.h"
|
||||
#include "cmd.h"
|
||||
|
||||
void felica_sendraw(PacketCommandNG *c);
|
||||
void felica_sendraw(const PacketCommandNG *c);
|
||||
void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip);
|
||||
void felica_sim_lite(uint8_t *uid);
|
||||
void felica_sim_lite(const uint8_t *uid);
|
||||
void felica_dump_lite_s(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -162,8 +162,7 @@ void FpgaSetupSsc(uint16_t fpga_mode) {
|
|||
|
||||
// 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync
|
||||
// pulse, no output sync
|
||||
if (((fpga_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_READER ||
|
||||
(fpga_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_FSK_READER) &&
|
||||
if (((fpga_mode & FPGA_MAJOR_MODE_MASK) == FPGA_MAJOR_MODE_HF_READER) &&
|
||||
(FpgaGetCurrent() == FPGA_BITSTREAM_HF || FpgaGetCurrent() == FPGA_BITSTREAM_HF_15)) {
|
||||
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
|
||||
} else {
|
||||
|
@ -393,7 +392,7 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3
|
|||
while (numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH) {
|
||||
char current_name = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
|
||||
numbytes++;
|
||||
uint16_t current_length = 0;
|
||||
uint32_t current_length = 0;
|
||||
if (current_name < 'a' || current_name > 'e') {
|
||||
/* Strange section name, abort */
|
||||
break;
|
||||
|
@ -404,16 +403,22 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3
|
|||
/* Four byte length field */
|
||||
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 24;
|
||||
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 16;
|
||||
numbytes += 2;
|
||||
default: /* Fall through, two byte length field */
|
||||
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 8;
|
||||
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 0;
|
||||
numbytes += 4;
|
||||
if (current_length > 300 * 1024) {
|
||||
/* section e should never exceed about 300KB, if the length is too big limit it but still send the bitstream just in case */
|
||||
current_length = 300 * 1024;
|
||||
}
|
||||
break;
|
||||
default: /* Two byte length field */
|
||||
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 8;
|
||||
current_length += get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer) << 0;
|
||||
numbytes += 2;
|
||||
if (current_length > 64) {
|
||||
/* if text field is too long, keep it but truncate it */
|
||||
current_length = 64;
|
||||
}
|
||||
|
||||
if (current_name != 'e' && current_length > 255) {
|
||||
/* Maybe a parse error */
|
||||
break;
|
||||
}
|
||||
|
||||
if (current_name == section_name) {
|
||||
|
@ -423,7 +428,7 @@ static int bitparse_find_section(int bitstream_version, char section_name, uint3
|
|||
break;
|
||||
}
|
||||
|
||||
for (uint16_t i = 0; i < current_length && numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH; i++) {
|
||||
for (uint32_t i = 0; i < current_length && numbytes < MAX_FPGA_BIT_STREAM_HEADER_SEARCH; i++) {
|
||||
get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
|
||||
numbytes++;
|
||||
}
|
||||
|
@ -488,7 +493,7 @@ void FpgaDownloadAndGo(int bitstream_version) {
|
|||
#endif
|
||||
|
||||
// Send waiting time extension request as this will take a while
|
||||
send_wtx(1500);
|
||||
send_wtx(FPGA_LOAD_WAIT_TIME);
|
||||
|
||||
bool verbose = (g_dbglevel > 3);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Jonathan Westhues, April 2006
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
|
@ -25,83 +24,117 @@
|
|||
#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
|
||||
#define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN;
|
||||
|
||||
// definitions for multiple FPGA config files support
|
||||
#define FPGA_BITSTREAM_LF 1
|
||||
#define FPGA_BITSTREAM_HF 2
|
||||
#define FPGA_BITSTREAM_HF_FELICA 3
|
||||
#define FPGA_BITSTREAM_HF_15 4
|
||||
|
||||
/*
|
||||
Communication between ARM / FPGA is done inside armsrc/fpgaloader.c (function FpgaSendCommand)
|
||||
Send 16 bit command / data pair to FPGA
|
||||
The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
|
||||
where
|
||||
C is 4bit command
|
||||
D is 12bit data
|
||||
Communication between ARM / FPGA is done inside armsrc/fpgaloader.c see: function FpgaSendCommand()
|
||||
Send 16 bit command / data pair to FPGA with the bit format:
|
||||
|
||||
+------ frame layout circa 2020 ------------------+
|
||||
| 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
|
||||
+-------------------------------------------------+
|
||||
| C C C C M M M M P P P P P P P P | C = FPGA_CMD_SET_CONFREG, M = FPGA_MAJOR_MODE_*, P = FPGA_LF_* or FPGA_HF_* parameter
|
||||
| C C C C D D D D D D D D | C = FPGA_CMD_SET_DIVISOR, D = divisor
|
||||
| C C C C T T T T T T T T | C = FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, T = threshold
|
||||
| C C C C E | C = FPGA_CMD_TRACE_ENABLE, E=0 off, E=1 on
|
||||
+-------------------------------------------------+
|
||||
|
||||
+------ frame layout current ---------------------+
|
||||
| 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 |
|
||||
+-------------------------------------------------+
|
||||
| C C C C M M M P P P P P P | C = FPGA_CMD_SET_CONFREG, M = FPGA_MAJOR_MODE_*, P = FPGA_LF_* or FPGA_HF_* parameter
|
||||
| C C C C D D D D D D D D | C = FPGA_CMD_SET_DIVISOR, D = divisor
|
||||
| C C C C T T T T T T T T | C = FPGA_CMD_SET_EDGE_DETECT_THRESHOLD, T = threshold
|
||||
| C C C C E | C = FPGA_CMD_TRACE_ENABLE, E=0 off, E=1 on
|
||||
+-------------------------------------------------+
|
||||
|
||||
shift_reg receive this 16bit frame
|
||||
|
||||
LF command
|
||||
----------
|
||||
shift_reg[15:12] == 4bit command
|
||||
LF has three commands (FPGA_CMD_SET_CONFREG, FPGA_CMD_SET_DIVISOR, FPGA_CMD_SET_EDGE_DETECT_THRESHOLD)
|
||||
Current commands uses only 2bits. We have room for up to 4bits of commands total (7).
|
||||
|
||||
LF data
|
||||
-------
|
||||
shift_reg[11:0] == 12bit data
|
||||
lf data is divided into MAJOR MODES and configuration values.
|
||||
|
||||
The major modes uses 3bits (0,1,2,3,7 | 000, 001, 010, 011, 111)
|
||||
000 FPGA_MAJOR_MODE_LF_READER = Act as LF reader (modulate)
|
||||
001 FPGA_MAJOR_MODE_LF_EDGE_DETECT = Simulate LF
|
||||
010 FPGA_MAJOR_MODE_LF_PASSTHRU = Passthrough mode, CROSS_LO line connected to SSP_DIN. SSP_DOUT logic level controls if we modulate / listening
|
||||
011 FPGA_MAJOR_MODE_LF_ADC = refactor hitag2, clear ADC sampling
|
||||
111 FPGA_MAJOR_MODE_OFF = turn off sampling.
|
||||
|
||||
Each one of this major modes can have options. Currently these two major modes uses options.
|
||||
- FPGA_MAJOR_MODE_LF_READER
|
||||
- FPGA_MAJOR_MODE_LF_EDGE_DETECT
|
||||
|
||||
FPGA_MAJOR_MODE_LF_READER
|
||||
-------------------------------------
|
||||
lf_field = 1bit (FPGA_LF_ADC_READER_FIELD)
|
||||
|
||||
You can send FPGA_CMD_SET_DIVISOR to set with FREQUENCY the fpga should sample at
|
||||
divisor = 8bits shift_reg[7:0]
|
||||
|
||||
FPGA_MAJOR_MODE_LF_EDGE_DETECT
|
||||
------------------------------------------
|
||||
lf_ed_toggle_mode = 1bits
|
||||
lf_ed_threshold = 8bits threshold defaults to 127
|
||||
|
||||
You can send FPGA_CMD_SET_EDGE_DETECT_THRESHOLD to set a custom threshold
|
||||
lf_ed_threshold = 8bits threshold value.
|
||||
|
||||
conf_word 12bits
|
||||
conf_word[7:5] = 3bit major mode.
|
||||
conf_word[0] = 1bit lf_field
|
||||
conf_word[1] = 1bit lf_ed_toggle_mode
|
||||
conf_word[7:0] = 8bit divisor
|
||||
conf_word[7:0] = 8bit threshold
|
||||
|
||||
-----+--------- frame layout --------------------
|
||||
bit | 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
|
||||
-----+-------------------------------------------
|
||||
cmd | x x x x
|
||||
major| x x x
|
||||
opt | x x
|
||||
divi | x x x x x x x x
|
||||
thres| x x x x x x x x
|
||||
-----+-------------------------------------------
|
||||
*/
|
||||
|
||||
// Definitions for the FPGA commands.
|
||||
// BOTH HF / LF
|
||||
#define FPGA_CMD_SET_CONFREG (1<<12) // C
|
||||
|
||||
// LF
|
||||
#define FPGA_CMD_SET_DIVISOR (2<<12) // C
|
||||
#define FPGA_CMD_SET_USER_BYTE1 (3<<12) // C
|
||||
|
||||
// HF
|
||||
#define FPGA_CMD_TRACE_ENABLE (2<<12) // C
|
||||
|
||||
// Definitions for the FPGA configuration word.
|
||||
// Defining commands, modes and options. This must be aligned to the definitions in fpga/define.v
|
||||
#define FPGA_MAJOR_MODE_MASK 0x01C0
|
||||
#define FPGA_MINOR_MODE_MASK 0x003F
|
||||
|
||||
// LF
|
||||
// Definitions for the FPGA commands.
|
||||
#define FPGA_CMD_SET_CONFREG (1<<12)
|
||||
#define FPGA_CMD_SET_DIVISOR (2<<12)
|
||||
#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD (3<<12)
|
||||
#define FPGA_CMD_TRACE_ENABLE (2<<12)
|
||||
|
||||
// Major modes
|
||||
#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 (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
|
||||
#define FPGA_MAJOR_MODE_HF_FSK_READER (6<<6) // D
|
||||
|
||||
// BOTH HF / LF
|
||||
#define FPGA_MAJOR_MODE_OFF (7<<6) // D
|
||||
|
||||
#define FPGA_MAJOR_MODE_HF_READER (0<<6)
|
||||
#define FPGA_MAJOR_MODE_HF_SIMULATOR (1<<6)
|
||||
#define FPGA_MAJOR_MODE_HF_ISO14443A (2<<6)
|
||||
#define FPGA_MAJOR_MODE_HF_SNIFF (3<<6)
|
||||
#define FPGA_MAJOR_MODE_HF_ISO18092 (4<<6)
|
||||
#define FPGA_MAJOR_MODE_HF_GET_TRACE (5<<6)
|
||||
#define FPGA_MAJOR_MODE_OFF (7<<6)
|
||||
|
||||
// Options for LF_READER
|
||||
#define FPGA_LF_ADC_READER_FIELD 0x1
|
||||
#define FPGA_LF_ADC_READER_FIELD ( 1 )
|
||||
|
||||
// Options for LF_EDGE_DETECT
|
||||
#define FPGA_CMD_SET_EDGE_DETECT_THRESHOLD FPGA_CMD_SET_USER_BYTE1
|
||||
#define FPGA_LF_EDGE_DETECT_READER_FIELD 0x1
|
||||
#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE 0x2
|
||||
#define FPGA_LF_EDGE_DETECT_READER_FIELD ( 1 )
|
||||
#define FPGA_LF_EDGE_DETECT_TOGGLE_MODE ( 2 )
|
||||
|
||||
// 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 generic HF reader
|
||||
#define FPGA_HF_READER_MODE_RECEIVE_IQ ( 0 )
|
||||
#define FPGA_HF_READER_MODE_RECEIVE_AMPLITUDE ( 1 )
|
||||
#define FPGA_HF_READER_MODE_RECEIVE_PHASE ( 2 )
|
||||
#define FPGA_HF_READER_MODE_SEND_FULL_MOD ( 3 )
|
||||
#define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD ( 4 )
|
||||
#define FPGA_HF_READER_MODE_SNIFF_IQ ( 5 )
|
||||
#define FPGA_HF_READER_MODE_SNIFF_AMPLITUDE ( 6 )
|
||||
#define FPGA_HF_READER_MODE_SNIFF_PHASE ( 7 )
|
||||
#define FPGA_HF_READER_MODE_SEND_JAM ( 8 )
|
||||
#define FPGA_HF_READER_MODE_SEND_SHALLOW_MOD_RDV4 ( 9 )
|
||||
|
||||
#define FPGA_HF_READER_SUBCARRIER_848_KHZ (0<<4)
|
||||
#define FPGA_HF_READER_SUBCARRIER_424_KHZ (1<<4)
|
||||
|
@ -109,24 +142,23 @@ thres| x x x x x x x x
|
|||
#define FPGA_HF_READER_2SUBCARRIERS_424_484_KHZ (3<<4)
|
||||
|
||||
// Options for the HF simulated tag, how to modulate
|
||||
#define FPGA_HF_SIMULATOR_NO_MODULATION 0x0 // 0000
|
||||
#define FPGA_HF_SIMULATOR_MODULATE_BPSK 0x1 // 0001
|
||||
#define FPGA_HF_SIMULATOR_MODULATE_212K 0x2 // 0010
|
||||
#define FPGA_HF_SIMULATOR_MODULATE_424K 0x4 // 0100
|
||||
#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT 0x5 // 0101
|
||||
// no 848K
|
||||
#define FPGA_HF_SIMULATOR_NO_MODULATION ( 0 )
|
||||
#define FPGA_HF_SIMULATOR_MODULATE_BPSK ( 1 )
|
||||
#define FPGA_HF_SIMULATOR_MODULATE_212K ( 2 )
|
||||
#define FPGA_HF_SIMULATOR_MODULATE_424K ( 4 )
|
||||
#define FPGA_HF_SIMULATOR_MODULATE_424K_8BIT ( 5 )
|
||||
|
||||
// Options for ISO14443A
|
||||
#define FPGA_HF_ISO14443A_SNIFFER 0x0
|
||||
#define FPGA_HF_ISO14443A_TAGSIM_LISTEN 0x1
|
||||
#define FPGA_HF_ISO14443A_TAGSIM_MOD 0x2
|
||||
#define FPGA_HF_ISO14443A_READER_LISTEN 0x3
|
||||
#define FPGA_HF_ISO14443A_READER_MOD 0x4
|
||||
#define FPGA_HF_ISO14443A_SNIFFER ( 0 )
|
||||
#define FPGA_HF_ISO14443A_TAGSIM_LISTEN ( 1 )
|
||||
#define FPGA_HF_ISO14443A_TAGSIM_MOD ( 2 )
|
||||
#define FPGA_HF_ISO14443A_READER_LISTEN ( 3 )
|
||||
#define FPGA_HF_ISO14443A_READER_MOD ( 4 )
|
||||
|
||||
//options for Felica.
|
||||
#define FPGA_HF_ISO18092_FLAG_NOMOD 0x1 // 0001 disable modulation module
|
||||
#define FPGA_HF_ISO18092_FLAG_424K 0x2 // 0010 should enable 414k mode (untested). No autodetect
|
||||
#define FPGA_HF_ISO18092_FLAG_READER 0x4 // 0100 enables antenna power, to act as a reader instead of tag
|
||||
// Options for ISO18092 / Felica
|
||||
#define FPGA_HF_ISO18092_FLAG_NOMOD ( 1 ) // 0001 disable modulation module
|
||||
#define FPGA_HF_ISO18092_FLAG_424K ( 2 ) // 0010 should enable 414k mode (untested). No autodetect
|
||||
#define FPGA_HF_ISO18092_FLAG_READER ( 4 ) // 0100 enables antenna power, to act as a reader instead of tag
|
||||
|
||||
void FpgaSendCommand(uint16_t cmd, uint16_t v);
|
||||
void FpgaWriteConfWord(uint16_t v);
|
||||
|
|
|
@ -200,7 +200,7 @@ static uint32_t HfEncodeTkm(const uint8_t *uid, uint8_t modulation, uint8_t *dat
|
|||
return len;
|
||||
}
|
||||
|
||||
int HfSimulateTkm(uint8_t *uid, uint8_t modulation, uint32_t timeout) {
|
||||
int HfSimulateTkm(const uint8_t *uid, uint8_t modulation, uint32_t timeout) {
|
||||
// free eventually allocated BigBuf memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
|
|
|
@ -22,6 +22,6 @@
|
|||
#include "common.h"
|
||||
|
||||
int HfReadADC(uint32_t samplesCount, bool ledcontrol);
|
||||
int HfSimulateTkm(uint8_t *uid, uint8_t modulation, uint32_t timeout);
|
||||
int HfSimulateTkm(const uint8_t *uid, uint8_t modulation, uint32_t timeout);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -281,7 +281,7 @@ static void hitag2_handle_reader_command(uint8_t *rx, const size_t rxlen, uint8_
|
|||
}
|
||||
break;
|
||||
|
||||
// Received RWD authentication challenge and respnse
|
||||
// Received RWD authentication challenge and response
|
||||
case 64: {
|
||||
// Store the authentication attempt
|
||||
if (auth_table_len < (AUTH_TABLE_LENGTH - 8)) {
|
||||
|
@ -891,7 +891,7 @@ static bool hitag2_test_auth_attempts(uint8_t *rx, const size_t rxlen, uint8_t *
|
|||
if (bCrypto) {
|
||||
Dbprintf("auth: %02x%02x%02x%02x%02x%02x%02x%02x Failed, removed entry!", NrAr[0], NrAr[1], NrAr[2], NrAr[3], NrAr[4], NrAr[5], NrAr[6], NrAr[7]);
|
||||
|
||||
// Removing failed entry from authentiations table
|
||||
// Removing failed entry from authentications table
|
||||
memcpy(auth_table + auth_table_pos, auth_table + auth_table_pos + 8, 8);
|
||||
auth_table_len -= 8;
|
||||
|
||||
|
@ -979,7 +979,7 @@ static bool hitag2_read_uid(uint8_t *rx, const size_t rxlen, uint8_t *tx, size_t
|
|||
return true;
|
||||
}
|
||||
|
||||
void EloadHitag(uint8_t *data, uint16_t len) {
|
||||
void EloadHitag(const uint8_t *data, uint16_t len) {
|
||||
memcpy(tag.sectors, data, sizeof(tag.sectors));
|
||||
}
|
||||
|
||||
|
@ -1532,7 +1532,7 @@ void SimulateHitag2(bool ledcontrol) {
|
|||
// reply_ng(CMD_LF_HITAG_SIMULATE, (checked == -1) ? PM3_EOPABORTED : PM3_SUCCESS, (uint8_t *)tag.sectors, tag_size);
|
||||
}
|
||||
|
||||
void ReaderHitag(hitag_function htf, hitag_data *htd, bool ledcontrol) {
|
||||
void ReaderHitag(hitag_function htf, const hitag_data *htd, bool ledcontrol) {
|
||||
|
||||
uint32_t command_start = 0, command_duration = 0;
|
||||
uint32_t response_start = 0, response_duration = 0;
|
||||
|
@ -1928,7 +1928,7 @@ out:
|
|||
reply_mix(CMD_ACK, bSuccessful, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void WriterHitag(hitag_function htf, hitag_data *htd, int page, bool ledcontrol) {
|
||||
void WriterHitag(hitag_function htf, const hitag_data *htd, int page, bool ledcontrol) {
|
||||
|
||||
uint32_t command_start = 0;
|
||||
uint32_t command_duration = 0;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
void SniffHitag2(bool ledcontrol);
|
||||
void SimulateHitag2(bool ledcontrol);
|
||||
void ReaderHitag(hitag_function htf, hitag_data *htd, bool ledcontrol);
|
||||
void WriterHitag(hitag_function htf, hitag_data *htd, int page, bool ledcontrol);
|
||||
void EloadHitag(uint8_t *data, uint16_t len);
|
||||
void ReaderHitag(hitag_function htf, const hitag_data *htd, bool ledcontrol);
|
||||
void WriterHitag(hitag_function htf, const hitag_data *htd, int page, bool ledcontrol);
|
||||
void EloadHitag(const uint8_t *data, uint16_t len);
|
||||
#endif
|
||||
|
|
|
@ -339,7 +339,7 @@ bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar,
|
|||
// decrypt response
|
||||
hitag2crack_xor(response, e_response, keybits + 10, 32);
|
||||
// convert to hexstring
|
||||
binarraytohex(responsestr, response, 32);
|
||||
binarray_2_hex(responsestr, response, 32);
|
||||
return true;
|
||||
} else {
|
||||
UserMessage("hitag2crack_read_page:\r\n hitag2crack_send_e_cmd returned ERROR_RESPONSE\r\n");
|
||||
|
@ -424,7 +424,7 @@ bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, b
|
|||
}
|
||||
|
||||
// convert response to hexstring
|
||||
binarraytohex(responsestr, tmp + 5, 32);
|
||||
binarray_2_hex(responsestr, tmp + 5, 32);
|
||||
return true;
|
||||
} else {
|
||||
#ifdef RFIDLER_DEBUG
|
||||
|
@ -506,8 +506,8 @@ bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex) {
|
|||
binulong = hextoulong(hex);
|
||||
|
||||
ulongtobinarray(bin, hitag2_crypt(binulong, 32), 32);
|
||||
binarraytobinstring(binstr, bin, 32);
|
||||
binarraytohex(binhex, bin, 32);
|
||||
binarray_2_binstr(binstr, bin, 32);
|
||||
binarray_2_hex(binhex, bin, 32);
|
||||
// UserMessage("ar = %s\r\n", binstr);
|
||||
// UserMessage("arhex = %s\r\n", binhex);
|
||||
|
||||
|
@ -532,7 +532,7 @@ bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *e_binstr) {
|
|||
binulong = binarraytoulong(e_bin, len);
|
||||
|
||||
ulongtobinarray(bin, hitag2_crypt(binulong, len), len);
|
||||
binarraytobinstring(binstr, bin, len);
|
||||
binarray_2_binstr(binstr, bin, len);
|
||||
strcpy(response, binstr);
|
||||
return true;
|
||||
}
|
||||
|
@ -569,7 +569,7 @@ bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex) {
|
|||
uint8_t *spaceptr = NULL;
|
||||
|
||||
/*
|
||||
keybits = malloc(2080);
|
||||
keybits = calloc(2080, sizeof(uint8_t));
|
||||
if (!keybits) {
|
||||
UserMessage("cannot malloc keybits\r\n");
|
||||
return false;
|
||||
|
@ -646,7 +646,7 @@ bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex) {
|
|||
}
|
||||
|
||||
for (i = 0; i < 2048; i += 256) {
|
||||
binarraytohex(keybitshex, keybits + i, 256);
|
||||
binarray_2_hex(keybitshex, keybits + i, 256);
|
||||
UserMessage("%s\r\n", keybitshex);
|
||||
}
|
||||
|
||||
|
|
|
@ -635,7 +635,7 @@ static void hitagS_handle_reader_command(uint8_t *rx, const size_t rxlen,
|
|||
/*
|
||||
* Emulates a Hitag S Tag with the given data from the .hts file
|
||||
*/
|
||||
void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data, bool ledcontrol) {
|
||||
void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol) {
|
||||
|
||||
StopTicks();
|
||||
|
||||
|
@ -1052,7 +1052,7 @@ static size_t concatbits(uint8_t *dstbuf, size_t dstbufskip, const uint8_t *srcb
|
|||
return dstbufskip + srcbuflen;
|
||||
}
|
||||
|
||||
static int selectHitagS(hitag_function htf, hitag_data *htd, uint8_t *tx, size_t sizeoftx, uint8_t *rx, size_t sizeofrx, int t_wait, bool ledcontrol) {
|
||||
static int selectHitagS(hitag_function htf, const hitag_data *htd, uint8_t *tx, size_t sizeoftx, uint8_t *rx, size_t sizeofrx, int t_wait, bool ledcontrol) {
|
||||
StopTicks();
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
@ -1263,7 +1263,7 @@ static int selectHitagS(hitag_function htf, hitag_data *htd, uint8_t *tx, size_t
|
|||
* If the key was given the password will be decrypted.
|
||||
* Reads every page of a hitag S transpoder.
|
||||
*/
|
||||
void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
|
||||
void ReadHitagS(hitag_function htf, const hitag_data *htd, bool ledcontrol) {
|
||||
|
||||
uint8_t rx[HITAG_FRAME_LEN];
|
||||
size_t rxlen = 0;
|
||||
|
@ -1356,7 +1356,7 @@ void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol) {
|
|||
* Authenticates to the Tag with the given Key or Challenge.
|
||||
* Writes the given 32Bit data into page_
|
||||
*/
|
||||
void WritePageHitagS(hitag_function htf, hitag_data *htd, int page, bool ledcontrol) {
|
||||
void WritePageHitagS(hitag_function htf, const hitag_data *htd, int page, bool ledcontrol) {
|
||||
|
||||
bool bSuccessful = false;
|
||||
//check for valid input
|
||||
|
@ -1443,7 +1443,7 @@ write_end:
|
|||
* is not received correctly due to Antenna problems. This function
|
||||
* detects these challenges.
|
||||
*/
|
||||
void Hitag_check_challenges(uint8_t *data, uint32_t datalen, bool ledcontrol) {
|
||||
void Hitag_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol) {
|
||||
//check for valid input
|
||||
if (datalen < 8) {
|
||||
Dbprintf("Error, need chals");
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
|
||||
#include "hitag.h"
|
||||
|
||||
void SimulateHitagSTag(bool tag_mem_supplied, uint8_t *data, bool ledcontrol);
|
||||
void ReadHitagS(hitag_function htf, hitag_data *htd, bool ledcontrol);
|
||||
void WritePageHitagS(hitag_function htf, hitag_data *htd, int page, bool ledcontrol);
|
||||
void Hitag_check_challenges(uint8_t *data, uint32_t datalen, bool ledcontrol);
|
||||
void SimulateHitagSTag(bool tag_mem_supplied, const uint8_t *data, bool ledcontrol);
|
||||
void ReadHitagS(hitag_function htf, const hitag_data *htd, bool ledcontrol);
|
||||
void WritePageHitagS(hitag_function htf, const hitag_data *htd, int page, bool ledcontrol);
|
||||
void Hitag_check_challenges(const uint8_t *data, uint32_t datalen, bool ledcontrol);
|
||||
#endif
|
||||
|
|
326
armsrc/i2c.c
326
armsrc/i2c.c
|
@ -1,4 +1,4 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// //-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
|
@ -53,9 +53,6 @@ static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
|
|||
#define I2C_DELAY_2CLK I2CSpinDelayClk(2)
|
||||
#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x))
|
||||
|
||||
// The SIM module v4 supports up to 384 bytes for the length.
|
||||
#define ISO7816_MAX_FRAME 270
|
||||
|
||||
// try i2c bus recovery at 100kHz = 5us high, 5us low
|
||||
void I2C_recovery(void) {
|
||||
|
||||
|
@ -168,15 +165,15 @@ static bool WaitSCL_H_delay(uint32_t delay) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// 5000 * 3.07us = 15350us. 15.35ms
|
||||
// 15000 * 3.07us = 46050us. 46.05ms
|
||||
// 5000 * 3.07us = 15350 us = 15.35 ms
|
||||
// 15000 * 3.07us = 46050 us = 46.05 ms
|
||||
static bool WaitSCL_H(void) {
|
||||
return WaitSCL_H_delay(5000);
|
||||
}
|
||||
|
||||
static bool WaitSCL_L_delay(uint32_t delay) {
|
||||
while (delay--) {
|
||||
if (!SCL_read) {
|
||||
if (SCL_read == false) {
|
||||
return true;
|
||||
}
|
||||
I2C_DELAY_1CLK;
|
||||
|
@ -194,7 +191,7 @@ static bool WaitSCL_L(void) {
|
|||
// It timeout reading response from card
|
||||
// Which ever comes first
|
||||
static bool WaitSCL_L_timeout(void) {
|
||||
volatile uint32_t delay = 200;
|
||||
volatile uint32_t delay = 1200;
|
||||
while (delay--) {
|
||||
// exit on SCL LOW
|
||||
if (SCL_read == false)
|
||||
|
@ -212,32 +209,41 @@ static bool I2C_Start(void) {
|
|||
SDA_H;
|
||||
I2C_DELAY_1CLK;
|
||||
SCL_H;
|
||||
if (!WaitSCL_H())
|
||||
if (WaitSCL_H() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_DELAY_2CLK;
|
||||
|
||||
if (!SCL_read)
|
||||
if (SCL_read == false) {
|
||||
return false;
|
||||
if (!SDA_read)
|
||||
}
|
||||
|
||||
if (SDA_read == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SDA_L;
|
||||
I2C_DELAY_2CLK;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool I2C_WaitForSim(void) {
|
||||
static bool I2C_WaitForSim(uint32_t wait) {
|
||||
|
||||
// wait for data from card
|
||||
if (!WaitSCL_L_timeout())
|
||||
if (WaitSCL_L_timeout() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 8051 speaks with smart card.
|
||||
// 1000*50*3.07 = 153.5ms
|
||||
// 1000*110*3.07 = 337.7ms
|
||||
// 1000*110*3.07 = 337.7ms (337700)
|
||||
// 4 560 000 * 3.07 = 13999,2ms (13999200)
|
||||
// 1byte transfer == 1ms with max frame being 256bytes
|
||||
return WaitSCL_H_delay(1000 * 110);
|
||||
|
||||
// fct WaitSCL_H_delay uses a I2C_DELAY_1CLK in the loop with "wait" as number of iterations.
|
||||
// I2C_DELAY_1CLK == I2CSpinDelayClk(1) = 3.07us
|
||||
return WaitSCL_H_delay(wait);
|
||||
}
|
||||
|
||||
// send i2c STOP
|
||||
|
@ -248,7 +254,11 @@ static void I2C_Stop(void) {
|
|||
I2C_DELAY_2CLK;
|
||||
SCL_H;
|
||||
I2C_DELAY_2CLK;
|
||||
if (!WaitSCL_H()) return;
|
||||
|
||||
if (WaitSCL_H() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDA_H;
|
||||
I2C_DELAY_2CLK;
|
||||
I2C_DELAY_2CLK;
|
||||
|
@ -264,7 +274,11 @@ static void I2C_Ack(void) {
|
|||
I2C_DELAY_2CLK;
|
||||
SCL_H;
|
||||
I2C_DELAY_2CLK;
|
||||
if (!WaitSCL_H()) return;
|
||||
|
||||
if (WaitSCL_H() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
SCL_L;
|
||||
I2C_DELAY_2CLK;
|
||||
}
|
||||
|
@ -277,7 +291,11 @@ static void I2C_NoAck(void) {
|
|||
I2C_DELAY_2CLK;
|
||||
SCL_H;
|
||||
I2C_DELAY_2CLK;
|
||||
if (!WaitSCL_H()) return;
|
||||
|
||||
if (WaitSCL_H() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
SCL_L;
|
||||
I2C_DELAY_2CLK;
|
||||
}
|
||||
|
@ -288,8 +306,10 @@ static bool I2C_WaitAck(void) {
|
|||
SDA_H;
|
||||
I2C_DELAY_1CLK;
|
||||
SCL_H;
|
||||
if (!WaitSCL_H())
|
||||
|
||||
if (WaitSCL_H() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_DELAY_2CLK;
|
||||
I2C_DELAY_2CLK;
|
||||
|
@ -302,6 +322,7 @@ static bool I2C_WaitAck(void) {
|
|||
}
|
||||
|
||||
static void I2C_SendByte(uint8_t data) {
|
||||
|
||||
uint8_t bits = 8;
|
||||
|
||||
while (bits--) {
|
||||
|
@ -319,8 +340,9 @@ static void I2C_SendByte(uint8_t data) {
|
|||
I2C_DELAY_1CLK;
|
||||
|
||||
SCL_H;
|
||||
if (!WaitSCL_H())
|
||||
if (WaitSCL_H() == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
I2C_DELAY_2CLK;
|
||||
}
|
||||
|
@ -332,111 +354,131 @@ static int16_t I2C_ReadByte(void) {
|
|||
|
||||
SDA_H;
|
||||
while (bits--) {
|
||||
|
||||
b <<= 1;
|
||||
SCL_L;
|
||||
if (!WaitSCL_L()) return -2;
|
||||
if (WaitSCL_L() == false) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
I2C_DELAY_1CLK;
|
||||
|
||||
SCL_H;
|
||||
if (!WaitSCL_H()) return -1;
|
||||
if (WaitSCL_H() == false) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
I2C_DELAY_1CLK;
|
||||
if (SDA_read)
|
||||
if (SDA_read) {
|
||||
b |= 0x01;
|
||||
}
|
||||
}
|
||||
SCL_L;
|
||||
return b;
|
||||
}
|
||||
|
||||
// Sends one byte ( command to be written, SlaveDevice address)
|
||||
// Sends one byte (command to be written, SlaveDevice address)
|
||||
bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) {
|
||||
bool bBreak = true;
|
||||
bool _break = true;
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
if (I2C_Start() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
I2C_SendByte(device_cmd);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
bBreak = false;
|
||||
_break = false;
|
||||
} while (false);
|
||||
|
||||
I2C_Stop();
|
||||
if (bBreak) {
|
||||
|
||||
if (_break) {
|
||||
|
||||
if (g_dbglevel > 3) DbpString(I2C_ERROR);
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Sends 1 byte data (Data to be written, command to be written , SlaveDevice address ).
|
||||
// Sends 1 byte data (data to be written, command to be written , SlaveDevice address)
|
||||
bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) {
|
||||
bool bBreak = true;
|
||||
bool _break = true;
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
if (I2C_Start() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
I2C_SendByte(device_cmd);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
I2C_SendByte(data);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
bBreak = false;
|
||||
_break = false;
|
||||
} while (false);
|
||||
|
||||
I2C_Stop();
|
||||
if (bBreak) {
|
||||
if (_break) {
|
||||
if (g_dbglevel > 3) DbpString(I2C_ERROR);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//Sends array of data (Array, length, command to be written , SlaveDevice address ).
|
||||
// Sends array of data (array, length, command to be written , SlaveDevice address)
|
||||
// len = uint16 because we need to write up to 256 bytes
|
||||
bool I2C_BufferWrite(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) {
|
||||
bool bBreak = true;
|
||||
bool I2C_BufferWrite(const uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) {
|
||||
bool _break = true;
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
if (I2C_Start() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
I2C_SendByte(device_cmd);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (len) {
|
||||
|
||||
I2C_SendByte(*data);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false)
|
||||
break;
|
||||
|
||||
len--;
|
||||
data++;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
bBreak = false;
|
||||
if (len == 0) {
|
||||
_break = false;
|
||||
}
|
||||
|
||||
} while (false);
|
||||
|
||||
I2C_Stop();
|
||||
if (bBreak) {
|
||||
if (_break) {
|
||||
if (g_dbglevel > 3) DbpString(I2C_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
@ -447,132 +489,157 @@ bool I2C_BufferWrite(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t de
|
|||
// len = uint16 because we need to read up to 256bytes
|
||||
int16_t I2C_BufferRead(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address) {
|
||||
|
||||
if (!data || len == 0)
|
||||
// sanity check
|
||||
if (data == NULL || len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// uint8_t *pd = data;
|
||||
|
||||
// extra wait 500us (514us measured)
|
||||
// 200us (xx measured)
|
||||
WaitUS(600);
|
||||
|
||||
bool bBreak = true;
|
||||
uint16_t readcount = 0;
|
||||
uint16_t recv_len = 0;
|
||||
bool _break = true;
|
||||
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
if (I2C_Start() == false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0xB0 / 0xC0 == i2c write
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
I2C_SendByte(device_cmd);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 0xB1 / 0xC1 == i2c read
|
||||
I2C_Start();
|
||||
I2C_SendByte(device_address | 1);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
bBreak = false;
|
||||
_break = false;
|
||||
} while (false);
|
||||
|
||||
if (bBreak) {
|
||||
if (_break) {
|
||||
I2C_Stop();
|
||||
if (g_dbglevel > 3) DbpString(I2C_ERROR);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t readcount = 0;
|
||||
uint16_t recv_len = 0;
|
||||
|
||||
while (len) {
|
||||
|
||||
int16_t tmp = I2C_ReadByte();
|
||||
if (tmp < 0)
|
||||
if (tmp < 0) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
*data = (uint8_t)tmp & 0xFF;
|
||||
|
||||
len--;
|
||||
|
||||
// Starting firmware v4 the length is encoded on the first two bytes.
|
||||
// This only applies if command is I2C_DEVICE_CMD_READ.
|
||||
if (device_cmd == I2C_DEVICE_CMD_READ) {
|
||||
switch (readcount) {
|
||||
case 0:
|
||||
case 0: {
|
||||
// Length (MSB)
|
||||
recv_len = (*data) << 8;
|
||||
break;
|
||||
case 1:
|
||||
}
|
||||
case 1: {
|
||||
// Length (LSB)
|
||||
recv_len += *data;
|
||||
|
||||
// old packages..
|
||||
if (recv_len > 0x0200) {
|
||||
// [0] = len
|
||||
// [1] = data
|
||||
recv_len >>= 8;
|
||||
data++;
|
||||
}
|
||||
|
||||
// Adjust len if needed
|
||||
if (len > recv_len) {
|
||||
len = recv_len;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
// Data byte received
|
||||
data++;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Length is encoded on 1 byte
|
||||
if ((readcount == 0) && (len > *data)) {
|
||||
len = *data;
|
||||
} else {
|
||||
data++;
|
||||
}
|
||||
}
|
||||
|
||||
readcount++;
|
||||
|
||||
// acknowledgements. After last byte send NACK.
|
||||
if (len == 0)
|
||||
if (len == 0) {
|
||||
I2C_NoAck();
|
||||
else
|
||||
} else {
|
||||
I2C_Ack();
|
||||
}
|
||||
}
|
||||
|
||||
I2C_Stop();
|
||||
|
||||
// Dbprintf("rec len... %u readcount... %u", recv_len, readcount);
|
||||
// Dbhexdump(readcount, pd, false);
|
||||
|
||||
if (readcount < 2) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return bytecount - bytes encoding length
|
||||
return readcount - (device_cmd == I2C_DEVICE_CMD_READ ? 2 : 1);
|
||||
return readcount - 2;
|
||||
}
|
||||
|
||||
int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
|
||||
//START, 0xB0, 0x00, 0x00, START, 0xB1, xx, yy, zz, ......, STOP
|
||||
bool bBreak = true;
|
||||
bool _break = true;
|
||||
uint8_t readcount = 0;
|
||||
|
||||
// sending
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
if (I2C_Start() == false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 0xB0 / 0xC0 i2c write
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false)
|
||||
break;
|
||||
|
||||
I2C_SendByte(msb);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
I2C_SendByte(lsb);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 0xB1 / 0xC1 i2c read
|
||||
I2C_Start();
|
||||
I2C_SendByte(device_address | 1);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
bBreak = false;
|
||||
_break = false;
|
||||
} while (false);
|
||||
|
||||
if (bBreak) {
|
||||
if (_break) {
|
||||
I2C_Stop();
|
||||
if (g_dbglevel > 3) DbpString(I2C_ERROR);
|
||||
return 0;
|
||||
|
@ -582,8 +649,9 @@ int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t
|
|||
while (len) {
|
||||
|
||||
int16_t tmp = I2C_ReadByte();
|
||||
if (tmp < 0)
|
||||
if (tmp < 0) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
*data = (uint8_t)tmp & 0xFF;
|
||||
|
||||
|
@ -602,42 +670,49 @@ int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t
|
|||
return readcount;
|
||||
}
|
||||
|
||||
bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
|
||||
bool I2C_WriteFW(const uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
|
||||
//START, 0xB0, 0x00, 0x00, xx, yy, zz, ......, STOP
|
||||
bool bBreak = true;
|
||||
bool _break = true;
|
||||
|
||||
do {
|
||||
if (!I2C_Start())
|
||||
if (I2C_Start() == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0xB0 == i2c write
|
||||
I2C_SendByte(device_address & 0xFE);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
I2C_SendByte(msb);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
I2C_SendByte(lsb);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (len) {
|
||||
I2C_SendByte(*data);
|
||||
if (!I2C_WaitAck())
|
||||
if (I2C_WaitAck() == false) {
|
||||
break;
|
||||
|
||||
}
|
||||
len--;
|
||||
data++;
|
||||
}
|
||||
|
||||
if (len == 0)
|
||||
bBreak = false;
|
||||
if (len == 0) {
|
||||
_break = false;
|
||||
}
|
||||
|
||||
} while (false);
|
||||
|
||||
I2C_Stop();
|
||||
if (bBreak) {
|
||||
|
||||
if (_break) {
|
||||
if (g_dbglevel > 3) DbpString(I2C_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
@ -646,37 +721,40 @@ bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t d
|
|||
|
||||
void I2C_print_status(void) {
|
||||
DbpString(_CYAN_("Smart card module (ISO 7816)"));
|
||||
uint8_t maj, min;
|
||||
if (I2C_get_version(&maj, &min) == PM3_SUCCESS) {
|
||||
Dbprintf(" version................. " _YELLOW_("v%x.%02d"), maj, min);
|
||||
if (maj < 4) {
|
||||
DbpString(" " _RED_("Outdated firmware.") " Please upgrade to v4.x or above.");
|
||||
}
|
||||
|
||||
uint8_t major, minor;
|
||||
if (I2C_get_version(&major, &minor) == PM3_SUCCESS) {
|
||||
|
||||
Dbprintf(" version................. v%d.%02d ( %s )"
|
||||
, major
|
||||
, minor
|
||||
, ((major == 4) && (minor == 42)) ? _GREEN_("ok") : _RED_("Outdated")
|
||||
);
|
||||
} else {
|
||||
DbpString(" version................. " _RED_("FAILED"));
|
||||
DbpString(" version................. ( " _RED_("fail") " )");
|
||||
}
|
||||
}
|
||||
|
||||
int I2C_get_version(uint8_t *maj, uint8_t *min) {
|
||||
int I2C_get_version(uint8_t *major, uint8_t *minor) {
|
||||
uint8_t resp[] = {0, 0, 0, 0};
|
||||
I2C_Reset_EnterMainProgram();
|
||||
uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN);
|
||||
if (len > 0) {
|
||||
*maj = resp[0];
|
||||
*min = resp[1];
|
||||
if (len > 1) {
|
||||
*major = resp[0];
|
||||
*minor = resp[1];
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return PM3_EDEVNOTSUPP;
|
||||
}
|
||||
|
||||
// Will read response from smart card module, retries 3 times to get the data.
|
||||
bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen) {
|
||||
bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen, uint32_t wait) {
|
||||
|
||||
uint8_t i = 5;
|
||||
uint8_t i = 10;
|
||||
int16_t len = 0;
|
||||
while (i--) {
|
||||
|
||||
I2C_WaitForSim();
|
||||
I2C_WaitForSim(wait);
|
||||
|
||||
len = I2C_BufferRead(dest, *destlen, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
|
||||
|
||||
|
@ -691,9 +769,9 @@ bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen) {
|
|||
}
|
||||
}
|
||||
|
||||
// after three
|
||||
if (len <= 1)
|
||||
if (len < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
*destlen = len;
|
||||
return true;
|
||||
|
@ -701,8 +779,10 @@ bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen) {
|
|||
|
||||
bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
|
||||
|
||||
if (card_ptr == NULL)
|
||||
if (card_ptr == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
card_ptr->atr_len = 0;
|
||||
memset(card_ptr->atr, 0, sizeof(card_ptr->atr));
|
||||
|
@ -711,15 +791,17 @@ bool GetATR(smart_card_atr_t *card_ptr, bool verbose) {
|
|||
// 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.
|
||||
// wait for sim card to answer.
|
||||
// 1byte = 1ms , max frame 256bytes. Should wait 256ms atleast just in case.
|
||||
if (I2C_WaitForSim() == false)
|
||||
if (I2C_WaitForSim(SIM_WAIT_DELAY) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// read bytes from module
|
||||
uint16_t len = sizeof(card_ptr->atr);
|
||||
if (sc_rx_bytes(card_ptr->atr, &len) == false)
|
||||
if (sc_rx_bytes(card_ptr->atr, &len, SIM_WAIT_DELAY) == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (len > sizeof(card_ptr->atr)) {
|
||||
len = sizeof(card_ptr->atr);
|
||||
|
@ -772,7 +854,7 @@ void SmartCardAtr(void) {
|
|||
// StopTicks();
|
||||
}
|
||||
|
||||
void SmartCardRaw(smart_card_raw_t *p) {
|
||||
void SmartCardRaw(const smart_card_raw_t *p) {
|
||||
LED_D_ON();
|
||||
|
||||
uint16_t len = 0;
|
||||
|
@ -803,16 +885,22 @@ void SmartCardRaw(smart_card_raw_t *p) {
|
|||
}
|
||||
}
|
||||
|
||||
if ((flags & SC_RAW) || (flags & SC_RAW_T0)) {
|
||||
if (((flags & SC_RAW) == SC_RAW) || ((flags & SC_RAW_T0) == SC_RAW_T0)) {
|
||||
|
||||
uint32_t wait = SIM_WAIT_DELAY;
|
||||
if ((flags & SC_WAIT) == SC_WAIT) {
|
||||
wait = (uint32_t)((p->wait_delay * 1000) / 3.07);
|
||||
}
|
||||
|
||||
LogTrace(p->data, p->len, 0, 0, NULL, true);
|
||||
|
||||
bool res = I2C_BufferWrite(
|
||||
p->data,
|
||||
p->len,
|
||||
((flags & SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND),
|
||||
(((flags & SC_RAW_T0) == SC_RAW_T0) ? I2C_DEVICE_CMD_SEND_T0 : I2C_DEVICE_CMD_SEND),
|
||||
I2C_DEVICE_ADDRESS_MAIN
|
||||
);
|
||||
|
||||
if (res == false && g_dbglevel > 3) {
|
||||
DbpString(I2C_ERROR);
|
||||
reply_ng(CMD_SMART_RAW, PM3_ESOFT, NULL, 0);
|
||||
|
@ -821,7 +909,7 @@ void SmartCardRaw(smart_card_raw_t *p) {
|
|||
|
||||
// read bytes from module
|
||||
len = ISO7816_MAX_FRAME;
|
||||
res = sc_rx_bytes(resp, &len);
|
||||
res = sc_rx_bytes(resp, &len, wait);
|
||||
if (res) {
|
||||
LogTrace(resp, len, 0, 0, NULL, false);
|
||||
} else {
|
||||
|
|
17
armsrc/i2c.h
17
armsrc/i2c.h
|
@ -30,6 +30,15 @@
|
|||
#define I2C_DEVICE_CMD_GETVERSION 0x06
|
||||
#define I2C_DEVICE_CMD_SEND_T0 0x07
|
||||
|
||||
// The SIM module v4 supports up to 384 bytes for the length.
|
||||
#define ISO7816_MAX_FRAME 270
|
||||
|
||||
// 8051 speaks with smart card.
|
||||
// 1000*50*3.07 = 153.5ms
|
||||
// 1 byte transfer == 1ms with max frame being 256 bytes
|
||||
#define SIM_WAIT_DELAY 88000 // about 270ms delay // 109773 -- about 337.7ms delay
|
||||
|
||||
|
||||
void I2C_recovery(void);
|
||||
void I2C_init(bool has_ticks);
|
||||
void I2C_Reset(void);
|
||||
|
@ -41,20 +50,20 @@ void I2C_Reset_EnterBootloader(void);
|
|||
bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address);
|
||||
|
||||
bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address);
|
||||
bool I2C_BufferWrite(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address);
|
||||
bool I2C_BufferWrite(const uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address);
|
||||
int16_t I2C_BufferRead(uint8_t *data, uint16_t len, uint8_t device_cmd, uint8_t device_address);
|
||||
|
||||
// for firmware
|
||||
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 I2C_WriteFW(const uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address);
|
||||
|
||||
bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen);
|
||||
bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen, uint32_t wait);
|
||||
//
|
||||
bool GetATR(smart_card_atr_t *card_ptr, bool verbose);
|
||||
|
||||
// generice functions
|
||||
void SmartCardAtr(void);
|
||||
void SmartCardRaw(smart_card_raw_t *p);
|
||||
void SmartCardRaw(const smart_card_raw_t *p);
|
||||
void SmartCardUpgrade(uint64_t arg0);
|
||||
void SmartCardSetBaud(uint64_t arg0);
|
||||
void SmartCardSetClock(uint64_t arg0);
|
||||
|
|
206
armsrc/iclass.c
206
armsrc/iclass.c
|
@ -36,9 +36,10 @@
|
|||
#include "protocols.h"
|
||||
#include "ticks.h"
|
||||
#include "iso15693.h"
|
||||
#include "iclass_cmd.h" /* iclass_card_select_t struct */
|
||||
#include "iclass_cmd.h" // iclass_card_select_t struct
|
||||
#include "i2c.h" // i2c defines (SIM module access)
|
||||
|
||||
static uint8_t get_pagemap(const picopass_hdr_t *hdr) {
|
||||
uint8_t get_pagemap(const picopass_hdr_t *hdr) {
|
||||
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
||||
}
|
||||
|
||||
|
@ -52,23 +53,6 @@ static uint8_t get_pagemap(const picopass_hdr_t *hdr) {
|
|||
#define ICLASS_16KS_SIZE 0x100 * 8
|
||||
#endif
|
||||
|
||||
// iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after
|
||||
// the reader command. This is measured from end of reader EOF to first modulation of the tag's SOF which starts with a 56,64us unmodulated period.
|
||||
// 330us = 140 ssp_clk cycles @ 423,75kHz when simulating.
|
||||
// 56,64us = 24 ssp_clk_cycles
|
||||
#define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 26) // (140 - 24)
|
||||
|
||||
// times in ssp_clk_cycles @ 3,3625MHz when acting as reader
|
||||
#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER
|
||||
|
||||
// times in samples @ 212kHz when acting as reader
|
||||
#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us
|
||||
#define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms
|
||||
#define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us
|
||||
|
||||
#define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
|
||||
|
||||
/*
|
||||
* CARD TO READER
|
||||
* in ISO15693-2 mode - Manchester
|
||||
|
@ -1245,7 +1229,7 @@ send:
|
|||
}
|
||||
|
||||
// THE READER CODE
|
||||
static void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod) {
|
||||
void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod) {
|
||||
CodeIso15693AsReader(frame, len);
|
||||
tosend_t *ts = get_tosend();
|
||||
TransmitTo15693Tag(ts->buf, ts->max, start_time, shallow_mod);
|
||||
|
@ -1270,6 +1254,12 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t *
|
|||
if (res == PM3_SUCCESS && expected_size == resp_len) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Timed out waiting for the tag to reply, but perhaps the tag did hear the command and is attempting to reply
|
||||
// So wait long enough for the tag to encode it's reply plus required frame delays on each side before retrying
|
||||
// And then double it, because in practice it seems to make it much more likely to succeed
|
||||
// Response time calculation from expected_size lifted from GetIso15693AnswerFromTag
|
||||
*start_time = *eof_time + ((DELAY_ICLASS_VICC_TO_VCD_READER + DELAY_ISO15693_VCD_TO_VICC_READER + (expected_size * 8 * 8 * 16)) * 2);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -1755,7 +1745,7 @@ void iClass_Dump(uint8_t *msg) {
|
|||
} PACKED response;
|
||||
|
||||
response.isOK = dumpsuccess;
|
||||
response.block_cnt = i;
|
||||
response.block_cnt = i - cmd->start_block;
|
||||
response.bb_offset = dataout - BigBuf_get_addr();
|
||||
reply_ng(CMD_HF_ICLASS_DUMP, PM3_SUCCESS, (uint8_t *)&response, sizeof(response));
|
||||
}
|
||||
|
@ -1784,7 +1774,6 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac,
|
|||
return false;
|
||||
}
|
||||
|
||||
uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
if (blockno == 2) {
|
||||
// check response. e-purse update swaps first and second half
|
||||
if (memcmp(data + 4, resp, 4) || memcmp(data, resp + 4, 4)) {
|
||||
|
@ -1792,6 +1781,7 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac,
|
|||
}
|
||||
} else if (blockno == 3 || blockno == 4) {
|
||||
// check response. Key updates always return 0xffffffffffffffff
|
||||
uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
if (memcmp(all_ff, resp, 8)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1821,7 +1811,7 @@ void iClass_WriteBlock(uint8_t *msg) {
|
|||
// select tag.
|
||||
uint32_t eof_time = 0;
|
||||
picopass_hdr_t hdr = {0};
|
||||
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time, shallow_mod);
|
||||
bool res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time, shallow_mod);
|
||||
if (res == false) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -1881,8 +1871,9 @@ void iClass_WriteBlock(uint8_t *msg) {
|
|||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
res = false;
|
||||
switch_off();
|
||||
if (payload->req.send_reply)
|
||||
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t));
|
||||
if (payload->req.send_reply) {
|
||||
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(bool));
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
|
||||
|
@ -1901,16 +1892,16 @@ void iClass_WriteBlock(uint8_t *msg) {
|
|||
}
|
||||
|
||||
// verify write
|
||||
uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
if (payload->req.blockno == 2) {
|
||||
if ((pagemap != PICOPASS_NON_SECURE_PAGEMODE) && (payload->req.blockno == 2)) {
|
||||
// check response. e-purse update swaps first and second half
|
||||
if (memcmp(payload->data + 4, resp, 4) || memcmp(payload->data, resp + 4, 4)) {
|
||||
res = false;
|
||||
goto out;
|
||||
}
|
||||
} else if (payload->req.blockno == 3 || payload->req.blockno == 4) {
|
||||
} else if ((pagemap != PICOPASS_NON_SECURE_PAGEMODE) && (payload->req.blockno == 3 || payload->req.blockno == 4)) {
|
||||
// check response. Key updates always return 0xffffffffffffffff
|
||||
if (memcmp(all_ff, resp, 8)) {
|
||||
uint8_t all_ff[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
if (memcmp(all_ff, resp, sizeof(all_ff))) {
|
||||
res = false;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1925,8 +1916,163 @@ void iClass_WriteBlock(uint8_t *msg) {
|
|||
out:
|
||||
switch_off();
|
||||
|
||||
if (payload->req.send_reply) {
|
||||
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(bool));
|
||||
}
|
||||
}
|
||||
|
||||
void iclass_credit_epurse(iclass_credit_epurse_t *payload) {
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
bool shallow_mod = payload->req.shallow_mod;
|
||||
|
||||
Iso15693InitReader();
|
||||
|
||||
// select tag.
|
||||
uint32_t eof_time = 0;
|
||||
picopass_hdr_t hdr = {0};
|
||||
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time, shallow_mod);
|
||||
if (res == false) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
uint8_t mac[4] = {0};
|
||||
|
||||
// authenticate
|
||||
if (payload->req.do_auth) {
|
||||
|
||||
res = authenticate_iclass_tag(&payload->req, &hdr, &start_time, &eof_time, mac);
|
||||
if (res == false) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
uint8_t cmd_read[] = {ICLASS_CMD_READ_OR_IDENTIFY, payload->req.blockno, 0x00, 0x00};
|
||||
AddCrc(cmd_read + 1, 1);
|
||||
|
||||
uint8_t epurse[10];
|
||||
res = iclass_send_cmd_with_retries(cmd_read, sizeof(cmd_read), epurse, sizeof(epurse), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, shallow_mod);
|
||||
if (!res) {
|
||||
switch_off();
|
||||
if (payload->req.send_reply) {
|
||||
reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_ETIMEOUT, (uint8_t *)&res, sizeof(uint8_t));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t write[14] = { 0x80 | ICLASS_CMD_UPDATE, payload->req.blockno };
|
||||
uint8_t write_len = 14;
|
||||
|
||||
uint8_t epurse_offset = 0;
|
||||
const uint8_t empty_epurse[] = {0xff, 0xff, 0xff, 0xff};
|
||||
if (memcmp(epurse, empty_epurse, 4) == 0) {
|
||||
// epurse data in stage 2
|
||||
epurse_offset = 4;
|
||||
}
|
||||
|
||||
memcpy(epurse + epurse_offset, payload->epurse, 4);
|
||||
|
||||
// blank out debiting value as per the first step of the crediting procedure
|
||||
epurse[epurse_offset + 0] = 0xFF;
|
||||
epurse[epurse_offset + 1] = 0xFF;
|
||||
|
||||
// initial epurse write for credit
|
||||
memcpy(write + 2, epurse, 8);
|
||||
|
||||
doMAC_N(write + 1, 9, payload->req.use_credit_key ? hdr.key_c : hdr.key_d, mac);
|
||||
memcpy(write + 10, mac, sizeof(mac));
|
||||
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
uint8_t resp[10] = {0};
|
||||
|
||||
uint8_t tries = 3;
|
||||
while (tries-- > 0) {
|
||||
|
||||
iclass_send_as_reader(write, write_len, &start_time, &eof_time, shallow_mod);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
res = false;
|
||||
switch_off();
|
||||
if (payload->req.send_reply)
|
||||
reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t));
|
||||
reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t));
|
||||
return;
|
||||
} else {
|
||||
|
||||
uint16_t resp_len = 0;
|
||||
int res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_UPDATE, &eof_time, false, true, &resp_len);
|
||||
if (res2 == PM3_SUCCESS && resp_len == 10) {
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tries == 0) {
|
||||
res = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// check response. e-purse update swaps first and second half
|
||||
if (memcmp(write + 2 + 4, resp, 4) || memcmp(write + 2, resp + 4, 4)) {
|
||||
res = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// new epurse write
|
||||
// epurse offset is now flipped after the first write
|
||||
epurse_offset ^= 4;
|
||||
memcpy(resp + epurse_offset, payload->epurse, 4);
|
||||
memcpy(write + 2, resp, 8);
|
||||
|
||||
doMAC_N(write + 1, 9, payload->req.use_credit_key ? hdr.key_c : hdr.key_d, mac);
|
||||
memcpy(write + 10, mac, sizeof(mac));
|
||||
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
tries = 3;
|
||||
while (tries-- > 0) {
|
||||
|
||||
iclass_send_as_reader(write, write_len, &start_time, &eof_time, shallow_mod);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||
res = false;
|
||||
switch_off();
|
||||
if (payload->req.send_reply)
|
||||
reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t));
|
||||
return;
|
||||
} else {
|
||||
|
||||
uint16_t resp_len = 0;
|
||||
int res2 = GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_UPDATE, &eof_time, false, true, &resp_len);
|
||||
if (res2 == PM3_SUCCESS && resp_len == 10) {
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (tries == 0) {
|
||||
res = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// check response. e-purse update swaps first and second half
|
||||
if (memcmp(write + 2 + 4, resp, 4) || memcmp(write + 2, resp + 4, 4)) {
|
||||
res = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
switch_off();
|
||||
|
||||
if (payload->req.send_reply)
|
||||
reply_ng(CMD_HF_ICLASS_CREDIT_EPURSE, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t));
|
||||
}
|
||||
|
||||
void iClass_Restore(iclass_restore_req_t *msg) {
|
||||
|
|
|
@ -21,10 +21,28 @@
|
|||
#include "common.h"
|
||||
#include "iclass_cmd.h"
|
||||
|
||||
// iCLASS has a slightly different timing compared to ISO15693. According to the picopass data sheet the tag response is expected 330us after
|
||||
// the reader command. This is measured from end of reader EOF to first modulation of the tag's SOF which starts with a 56,64us unmodulated period.
|
||||
// 330us = 140 ssp_clk cycles @ 423,75kHz when simulating.
|
||||
// 56,64us = 24 ssp_clk_cycles
|
||||
#define DELAY_ICLASS_VCD_TO_VICC_SIM (140 - 26) // (140 - 24)
|
||||
|
||||
// times in ssp_clk_cycles @ 3,3625MHz when acting as reader
|
||||
#define DELAY_ICLASS_VICC_TO_VCD_READER DELAY_ISO15693_VICC_TO_VCD_READER
|
||||
|
||||
|
||||
// times in samples @ 212kHz when acting as reader
|
||||
#define ICLASS_READER_TIMEOUT_ACTALL 330 // 1558us, nominal 330us + 7slots*160us = 1450us
|
||||
#define ICLASS_READER_TIMEOUT_UPDATE 3390 // 16000us, nominal 4-15ms
|
||||
#define ICLASS_READER_TIMEOUT_OTHERS 80 // 380us, nominal 330us
|
||||
|
||||
#define AddCrc(data, len) compute_crc(CRC_ICLASS, (data), (len), (data)+(len), (data)+(len)+1)
|
||||
|
||||
void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
|
||||
void ReaderIClass(uint8_t flags);
|
||||
|
||||
void iClass_WriteBlock(uint8_t *msg);
|
||||
void iclass_credit_epurse(iclass_credit_epurse_t *payload);
|
||||
void iClass_Dump(uint8_t *msg);
|
||||
|
||||
void iClass_Restore(iclass_restore_req_t *msg);
|
||||
|
@ -42,4 +60,7 @@ bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, ui
|
|||
|
||||
bool select_iclass_tag(picopass_hdr_t *hdr, bool use_credit_key, uint32_t *eof_time, bool shallow_mod);
|
||||
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr_t *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out);
|
||||
|
||||
uint8_t get_pagemap(const picopass_hdr_t *hdr);
|
||||
void iclass_send_as_reader(uint8_t *frame, int len, uint32_t *start_time, uint32_t *end_time, bool shallow_mod);
|
||||
#endif
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -121,7 +121,7 @@ typedef enum {
|
|||
#endif
|
||||
|
||||
void printHf14aConfig(void);
|
||||
void setHf14aConfig(hf14a_config *hc);
|
||||
void setHf14aConfig(const hf14a_config *hc);
|
||||
hf14a_config *getHf14aConfig(void);
|
||||
void iso14a_set_timeout(uint32_t timeout);
|
||||
uint32_t iso14a_get_timeout(void);
|
||||
|
@ -151,7 +151,7 @@ uint16_t ReaderReceive(uint8_t *receivedAnswer, uint8_t *par);
|
|||
void iso14443a_setup(uint8_t fpga_minor_mode);
|
||||
int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, uint8_t *res);
|
||||
int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
|
||||
int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats, bool use_ecp, bool use_magsafe);
|
||||
int iso14443a_select_cardEx(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats, iso14a_polling_parameters_t *polling_parameters);
|
||||
int iso14443a_fast_select_card(uint8_t *uid_ptr, uint8_t num_cascades);
|
||||
void iso14a_set_trigger(bool enable);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -35,15 +35,13 @@
|
|||
#endif
|
||||
|
||||
void iso14443b_setup(void);
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res);
|
||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, int * responselen);
|
||||
|
||||
int iso14443b_select_card(iso14b_card_select_t *card);
|
||||
int iso14443b_select_card_srx(iso14b_card_select_t *card);
|
||||
int iso14443b_select_xrx_card(iso14b_card_select_t *card);
|
||||
|
||||
void SimulateIso14443bTag(uint8_t *pupi);
|
||||
void SimulateIso14443bTag(const uint8_t *pupi);
|
||||
void AcquireRawAdcSamplesIso14443b(uint32_t parameter);
|
||||
void ReadSTBlock(uint8_t blocknr);
|
||||
void read_14b_st_block(uint8_t blocknr);
|
||||
void SniffIso14443b(void);
|
||||
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
|
||||
void SendRawCommand14443B_Ex(iso14b_raw_cmd_t *p);
|
||||
|
|
|
@ -294,7 +294,12 @@ void CodeIso15693AsTag(const uint8_t *cmd, size_t len) {
|
|||
// Transmit the command (to the tag) that was placed in cmd[].
|
||||
void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time, bool shallow_mod) {
|
||||
|
||||
#ifdef RDV4
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | (shallow_mod ? FPGA_HF_READER_MODE_SEND_SHALLOW_MOD_RDV4 : FPGA_HF_READER_MODE_SEND_FULL_MOD));
|
||||
#else
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | (shallow_mod ? FPGA_HF_READER_MODE_SEND_SHALLOW_MOD : FPGA_HF_READER_MODE_SEND_FULL_MOD));
|
||||
#endif
|
||||
|
||||
|
||||
if (*start_time < DELAY_ARM_TO_TAG) {
|
||||
*start_time = DELAY_ARM_TO_TAG;
|
||||
|
@ -1055,7 +1060,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo
|
|||
|
||||
if (dtf->len > dtf->max_len) {
|
||||
ret = PM3_EOVFLOW;
|
||||
Dbprintf("overflow (%d > %d", dtf->len, dtf->max_len);
|
||||
Dbprintf("overflow (%d > %d)", dtf->len, dtf->max_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1078,7 +1083,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo
|
|||
|
||||
if (dt->len > dt->max_len) {
|
||||
ret = PM3_EOVFLOW;
|
||||
Dbprintf("overflow (%d > %d", dt->len, dt->max_len);
|
||||
Dbprintf("overflow (%d > %d)", dt->len, dt->max_len);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1736,14 +1741,19 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
// no need to try decoding reader data if the tag is sending
|
||||
if (!tag_is_active) {
|
||||
|
||||
if (Handle15693SampleFromReader((sniffdata & 0x02) >> 1, &dreader)) {
|
||||
int extra_8s = 1;
|
||||
if (Handle15693SampleFromReader((sniffdata & 0x02) >> 1, &dreader) ||
|
||||
(++extra_8s && Handle15693SampleFromReader(sniffdata & 0x01, &dreader))) {
|
||||
|
||||
uint32_t eof_time = dma_start_time + (samples * 16) + 8 - DELAY_READER_TO_ARM_SNIFF; // end of EOF
|
||||
if (dreader.byteCount > 0) {
|
||||
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
|
||||
// not sure where the extra +8's on the EOF time comes from though, if someone knows update this comment
|
||||
uint32_t eof_time = dma_start_time + (samples * 16) + (extra_8s * 8) - DELAY_READER_TO_ARM_SNIFF; // end of EOF
|
||||
uint32_t sof_time = eof_time
|
||||
- dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers
|
||||
- 32 * 16 // time for SOF transfer
|
||||
- 16 * 16; // time for EOF transfer
|
||||
- dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 1024 : 16384) // time for byte transfers
|
||||
- 256 // time for SOF transfer (1024/fc / 4)
|
||||
- 128; // time for EOF transfer (512/fc / 4)
|
||||
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
|
||||
LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true);
|
||||
|
||||
if (!iclass) { // Those flags don't exist in iClass
|
||||
|
@ -1751,52 +1761,38 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
expect_fast_answer = dreader.output[0] & ISO15_REQ_DATARATE_HIGH;
|
||||
}
|
||||
}
|
||||
|
||||
// And ready to receive another command.
|
||||
//DecodeReaderReset(&dreader); // already reseted
|
||||
DecodeTagReset(&dtag);
|
||||
DecodeTagFSKReset(&dtagfsk);
|
||||
reader_is_active = false;
|
||||
expect_tag_answer = true;
|
||||
} else if (Handle15693SampleFromReader(sniffdata & 0x01, &dreader)) {
|
||||
|
||||
uint32_t eof_time = dma_start_time + (samples * 16) + 16 - DELAY_READER_TO_ARM_SNIFF; // end of EOF
|
||||
if (dreader.byteCount > 0) {
|
||||
uint32_t sof_time = eof_time
|
||||
- dreader.byteCount * (dreader.Coding == CODING_1_OUT_OF_4 ? 128 * 16 : 2048 * 16) // time for byte transfers
|
||||
- 32 * 16 // time for SOF transfer
|
||||
- 16 * 16; // time for EOF transfer
|
||||
LogTrace_ISO15693(dreader.output, dreader.byteCount, (sof_time * 4), (eof_time * 4), NULL, true);
|
||||
if (!iclass) { // Those flags don't exist in iClass
|
||||
expect_fsk_answer = dreader.output[0] & ISO15_REQ_SUBCARRIER_TWO;
|
||||
expect_fast_answer = dreader.output[0] & ISO15_REQ_DATARATE_HIGH;
|
||||
}
|
||||
}
|
||||
// And ready to receive another command
|
||||
//DecodeReaderReset(&dreader); // already reseted
|
||||
DecodeTagReset(&dtag);
|
||||
DecodeTagFSKReset(&dtagfsk);
|
||||
reader_is_active = false;
|
||||
expect_tag_answer = true;
|
||||
} else {
|
||||
reader_is_active = (dreader.state >= STATE_READER_RECEIVE_DATA_1_OUT_OF_4);
|
||||
}
|
||||
}
|
||||
|
||||
if (!reader_is_active && expect_tag_answer) { // no need to try decoding tag data if the reader is currently sending or no answer expected yet
|
||||
// no need to try decoding tag data if the reader is currently sending or no answer expected yet
|
||||
if (!reader_is_active && expect_tag_answer) {
|
||||
|
||||
if (!expect_fsk_answer) {
|
||||
// single subcarrier tag response
|
||||
if (Handle15693SamplesFromTag((sniffdata >> 4) << 2, &dtag, expect_fast_answer)) {
|
||||
|
||||
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
|
||||
uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF
|
||||
if (dtag.lastBit == SOF_PART2) {
|
||||
eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS)
|
||||
}
|
||||
uint32_t sof_time = eof_time
|
||||
- dtag.len * 8 * 8 * 16 // time for byte transfers
|
||||
- (32 * 16) // time for SOF transfer
|
||||
- (dtag.lastBit != SOF_PART2 ? (32 * 16) : 0); // time for EOF transfer
|
||||
- dtag.len * 1024 // time for byte transfers (4096/fc / 4)
|
||||
- 512 // time for SOF transfer (2048/fc / 4)
|
||||
- (dtag.lastBit != SOF_PART2 ? 512 : 0); // time for EOF transfer (2048/fc / 4)
|
||||
|
||||
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
|
||||
LogTrace_ISO15693(dtag.output, dtag.len, (sof_time * 4), (eof_time * 4), NULL, false);
|
||||
|
||||
// And ready to receive another response.
|
||||
DecodeTagReset(&dtag);
|
||||
DecodeTagFSKReset(&dtagfsk);
|
||||
|
@ -1807,26 +1803,23 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
tag_is_active = (dtag.state >= STATE_TAG_RECEIVING_DATA);
|
||||
}
|
||||
} else {
|
||||
// dual subcarrier tag response
|
||||
if (FREQ_IS_0((sniffdata >> 2) & 0x3)) // tolerate 1 00
|
||||
sniffdata = sniffdata_prev;
|
||||
|
||||
if (Handle15693FSKSamplesFromTag((sniffdata >> 2) & 0x3, &dtagfsk, expect_fast_answer)) {
|
||||
expect_fsk_answer = false;
|
||||
} else {
|
||||
tag_is_active = (dtagfsk.state >= STATE_FSK_RECEIVING_DATA_484);
|
||||
}
|
||||
if (!expect_fsk_answer) {
|
||||
// FSK answer no more expected: switch back to ASK
|
||||
if (dtagfsk.len > 0) {
|
||||
// sof/eof_times are in ssp_clk, which is 13.56MHz / 4
|
||||
uint32_t eof_time = dma_start_time + (samples * 16) - DELAY_TAG_TO_ARM_SNIFF; // end of EOF
|
||||
if (dtagfsk.lastBit == SOF) {
|
||||
eof_time -= (8 * 16); // needed 8 additional samples to confirm single SOF (iCLASS)
|
||||
}
|
||||
uint32_t sof_time = eof_time
|
||||
- dtagfsk.len * 8 * 8 * 16 // time for byte transfers
|
||||
- (32 * 16) // time for SOF transfer
|
||||
- (dtagfsk.lastBit != SOF ? (32 * 16) : 0); // time for EOF transfer
|
||||
- dtagfsk.len * 1016 // time for byte transfers (4064/fc / 4) - FSK is slightly different
|
||||
- 512 // time for SOF transfer (2048/fc / 4)
|
||||
- (dtagfsk.lastBit != SOF ? 512 : 0); // time for EOF transfer (2048/fc / 4)
|
||||
|
||||
// sof/eof_times * 4 here to bring from ssp_clk freq to RF carrier freq
|
||||
LogTrace_ISO15693(dtagfsk.output, dtagfsk.len, (sof_time * 4), (eof_time * 4), NULL, false);
|
||||
}
|
||||
|
||||
|
@ -1834,6 +1827,10 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
DecodeReaderReset(&dreader);
|
||||
expect_tag_answer = false;
|
||||
tag_is_active = false;
|
||||
// FSK answer no more expected: switch back to ASK
|
||||
expect_fsk_answer = false;
|
||||
} else {
|
||||
tag_is_active = (dtagfsk.state >= STATE_FSK_RECEIVING_DATA_484);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1843,20 +1840,20 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
|||
switch_off();
|
||||
|
||||
DbpString("");
|
||||
if (g_dbglevel > DBG_ERROR) {
|
||||
DbpString(_CYAN_("Sniff statistics"));
|
||||
DbpString("=================================");
|
||||
Dbprintf(" DecodeTag State........%d", dtag.state);
|
||||
Dbprintf(" DecodeTag byteCnt......%d", dtag.len);
|
||||
Dbprintf(" DecodeTag posCount.....%d", dtag.posCount);
|
||||
Dbprintf(" DecodeTagFSK State.....%d", dtagfsk.state);
|
||||
Dbprintf(" DecodeTagFSK byteCnt...%d", dtagfsk.len);
|
||||
Dbprintf(" DecodeTagFSK count.....%d", dtagfsk.count);
|
||||
Dbprintf(" DecodeReader State.....%d", dreader.state);
|
||||
Dbprintf(" DecodeReader byteCnt...%d", dreader.byteCount);
|
||||
Dbprintf(" DecodeReader posCount..%d", dreader.posCount);
|
||||
Dbprintf(" Trace length..........." _YELLOW_("%d"), BigBuf_get_traceLen());
|
||||
DbpString("");
|
||||
|
||||
Dbprintf("DecodeTag State........ %d", dtag.state);
|
||||
Dbprintf("DecodeTag byteCnt...... %d", dtag.len);
|
||||
Dbprintf("DecodeTag posCount..... %d", dtag.posCount);
|
||||
Dbprintf("DecodeTagFSK State..... %d", dtagfsk.state);
|
||||
Dbprintf("DecodeTagFSK byteCnt... %d", dtagfsk.len);
|
||||
Dbprintf("DecodeTagFSK count..... %d", dtagfsk.count);
|
||||
Dbprintf("DecodeReader State..... %d", dreader.state);
|
||||
Dbprintf("DecodeReader byteCnt... %d", dreader.byteCount);
|
||||
Dbprintf("DecodeReader posCount.. %d", dreader.posCount);
|
||||
}
|
||||
Dbprintf("Trace length........... " _YELLOW_("%d"), BigBuf_get_traceLen());
|
||||
}
|
||||
|
||||
// Initialize Proxmark3 as ISO15693 reader
|
||||
|
@ -2127,7 +2124,6 @@ void Iso15693InitTag(void) {
|
|||
StartCountSspClk();
|
||||
}
|
||||
|
||||
|
||||
void EmlClearIso15693(void) {
|
||||
// Resetting the bitstream also frees the BigBuf memory, so we do this here to prevent
|
||||
// an inconvenient reset in the future by Iso15693InitTag
|
||||
|
@ -2136,16 +2132,6 @@ void EmlClearIso15693(void) {
|
|||
reply_ng(CMD_HF_ISO15693_EML_CLEAR, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
|
||||
void EmlSetMemIso15693(uint8_t count, uint8_t *data, uint32_t offset) {
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
memcpy(emCARD + offset, data, count);
|
||||
}
|
||||
|
||||
void EmlGetMemIso15693(uint8_t count, uint8_t *output, uint32_t offset) {
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
memcpy(output, emCARD + offset, count);
|
||||
}
|
||||
|
||||
// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
|
||||
// all demodulation performed in arm rather than host. - greg
|
||||
void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
||||
|
@ -2304,8 +2290,11 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
|||
}
|
||||
// Block data
|
||||
if (block_size * (block_idx + j + 1) <= CARD_MEMORY_SIZE) {
|
||||
EmlGetMemIso15693(block_size, resp_readblock + (work_offset + security_offset),
|
||||
block_size * (block_idx + j));
|
||||
emlGet(
|
||||
resp_readblock + (work_offset + security_offset),
|
||||
block_size * (block_idx + j),
|
||||
block_size
|
||||
);
|
||||
} else {
|
||||
memset(resp_readblock + work_offset + security_offset, 0, block_size);
|
||||
}
|
||||
|
@ -2342,7 +2331,7 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
|||
uint8_t *data = cmd + 3 + address_offset + multi_offset;
|
||||
|
||||
// write data
|
||||
EmlSetMemIso15693(block_count * block_size, data, block_idx * block_size);
|
||||
emlSet(data, (block_idx * block_size), (block_count * block_size));
|
||||
|
||||
// Build WRITE_(MULTI_)BLOCK response
|
||||
int response_length = 3;
|
||||
|
@ -2672,7 +2661,7 @@ void SetTag15693Uid(const uint8_t *uid) {
|
|||
switch_off();
|
||||
}
|
||||
|
||||
static void init_password_15693_Slix(uint8_t *buffer, uint8_t *pwd, const uint8_t *rnd) {
|
||||
static void init_password_15693_Slix(uint8_t *buffer, const uint8_t *pwd, const uint8_t *rnd) {
|
||||
memcpy(buffer, pwd, 4);
|
||||
if (rnd) {
|
||||
buffer[0] ^= rnd[0];
|
||||
|
@ -2700,7 +2689,7 @@ static bool get_rnd_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t
|
|||
return true;
|
||||
}
|
||||
|
||||
static uint32_t disable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, uint8_t *password) {
|
||||
static uint32_t disable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, const uint8_t *password) {
|
||||
|
||||
uint8_t rnd[2];
|
||||
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
|
||||
|
@ -2722,7 +2711,7 @@ static uint32_t disable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_ti
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t set_pass_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, uint8_t *password, uint8_t *uid) {
|
||||
static uint32_t set_pass_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, const uint8_t *password, uint8_t *uid) {
|
||||
|
||||
|
||||
uint8_t rnd[2];
|
||||
|
@ -2749,7 +2738,7 @@ static uint32_t set_pass_15693_Slix(uint32_t start_time, uint32_t *eof_time, uin
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t set_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *password) {
|
||||
static uint32_t set_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, const uint8_t *password) {
|
||||
uint8_t rnd[2];
|
||||
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
|
||||
return PM3_ETIMEOUT;
|
||||
|
@ -2770,7 +2759,7 @@ static uint32_t set_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time,
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t disable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *password, bool usepwd) {
|
||||
static uint32_t disable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time, const uint8_t *password, bool usepwd) {
|
||||
|
||||
uint8_t uid[8];
|
||||
get_uid_slix(start_time, eof_time, uid);
|
||||
|
@ -2804,7 +2793,7 @@ static uint32_t disable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time,
|
|||
}
|
||||
|
||||
|
||||
static uint32_t enable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *password, bool usepwd) {
|
||||
static uint32_t enable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time, const uint8_t *password, bool usepwd) {
|
||||
|
||||
uint8_t uid[8];
|
||||
get_uid_slix(start_time, eof_time, uid);
|
||||
|
@ -2836,7 +2825,7 @@ static uint32_t enable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time, u
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pwd_id, uint8_t *password, uint8_t *uid) {
|
||||
static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pwd_id, const uint8_t *password, uint8_t *uid) {
|
||||
|
||||
uint8_t new_pwd_cmd[] = { (ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS), ISO15693_WRITE_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, pwd_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
|
@ -2857,7 +2846,7 @@ static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_tim
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t pass_protect_EASAFI_15693_Slix(uint32_t start_time, uint32_t *eof_time, bool set_option_flag, uint8_t *password) {
|
||||
static uint32_t pass_protect_EASAFI_15693_Slix(uint32_t start_time, uint32_t *eof_time, bool set_option_flag, const uint8_t *password) {
|
||||
|
||||
uint8_t flags;
|
||||
|
||||
|
@ -2896,7 +2885,7 @@ static uint32_t pass_protect_EASAFI_15693_Slix(uint32_t start_time, uint32_t *eo
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t write_afi_15693(uint32_t start_time, uint32_t *eof_time, uint8_t *password, bool usepwd, uint8_t *uid, bool use_uid, uint8_t afi) {
|
||||
static uint32_t write_afi_15693(uint32_t start_time, uint32_t *eof_time, const uint8_t *password, bool usepwd, uint8_t *uid, bool use_uid, uint8_t afi) {
|
||||
|
||||
if (!use_uid) {
|
||||
int res_getuid = get_uid_slix(start_time, eof_time, uid);
|
||||
|
@ -2933,7 +2922,7 @@ static uint32_t write_afi_15693(uint32_t start_time, uint32_t *eof_time, uint8_t
|
|||
}
|
||||
|
||||
/*
|
||||
static uint32_t enable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, uint8_t *password) {
|
||||
static uint32_t enable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, const uint8_t *password) {
|
||||
uint8_t rnd[2];
|
||||
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
|
||||
return PM3_ETIMEOUT;
|
||||
|
@ -2954,7 +2943,7 @@ static uint32_t enable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_tim
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, uint8_t *password) {
|
||||
static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t pass_id, const uint8_t *password) {
|
||||
uint8_t rnd[2];
|
||||
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
|
||||
return PM3_ETIMEOUT;
|
||||
|
@ -2977,7 +2966,7 @@ static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_tim
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t destroy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, uint8_t *password) {
|
||||
static uint32_t destroy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t *uid, const uint8_t *password) {
|
||||
|
||||
uint8_t rnd[2];
|
||||
if (get_rnd_15693_Slix(start_time, eof_time, rnd) == false) {
|
||||
|
@ -3001,7 +2990,7 @@ static uint32_t destroy_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint
|
|||
|
||||
*/
|
||||
|
||||
void WritePasswordSlixIso15693(uint8_t *old_password, uint8_t *new_password, uint8_t pwd_id) {
|
||||
void WritePasswordSlixIso15693(const uint8_t *old_password, const uint8_t *new_password, uint8_t pwd_id) {
|
||||
LED_D_ON();
|
||||
Iso15693InitReader();
|
||||
StartCountSspClk();
|
||||
|
@ -3026,7 +3015,7 @@ void WritePasswordSlixIso15693(uint8_t *old_password, uint8_t *new_password, uin
|
|||
|
||||
}
|
||||
|
||||
void DisablePrivacySlixIso15693(uint8_t *password) {
|
||||
void DisablePrivacySlixIso15693(const uint8_t *password) {
|
||||
LED_D_ON();
|
||||
Iso15693InitReader();
|
||||
StartCountSspClk();
|
||||
|
@ -3041,7 +3030,7 @@ void DisablePrivacySlixIso15693(uint8_t *password) {
|
|||
switch_off();
|
||||
}
|
||||
|
||||
void EnablePrivacySlixIso15693(uint8_t *password) {
|
||||
void EnablePrivacySlixIso15693(const uint8_t *password) {
|
||||
LED_D_ON();
|
||||
Iso15693InitReader();
|
||||
StartCountSspClk();
|
||||
|
@ -3057,7 +3046,7 @@ void EnablePrivacySlixIso15693(uint8_t *password) {
|
|||
}
|
||||
|
||||
|
||||
void DisableEAS_AFISlixIso15693(uint8_t *password, bool usepwd) {
|
||||
void DisableEAS_AFISlixIso15693(const uint8_t *password, bool usepwd) {
|
||||
LED_D_ON();
|
||||
Iso15693InitReader();
|
||||
StartCountSspClk();
|
||||
|
@ -3075,7 +3064,7 @@ void DisableEAS_AFISlixIso15693(uint8_t *password, bool usepwd) {
|
|||
switch_off();
|
||||
}
|
||||
|
||||
void EnableEAS_AFISlixIso15693(uint8_t *password, bool usepwd) {
|
||||
void EnableEAS_AFISlixIso15693(const uint8_t *password, bool usepwd) {
|
||||
LED_D_ON();
|
||||
Iso15693InitReader();
|
||||
StartCountSspClk();
|
||||
|
@ -3090,7 +3079,7 @@ void EnableEAS_AFISlixIso15693(uint8_t *password, bool usepwd) {
|
|||
switch_off();
|
||||
}
|
||||
|
||||
void PassProtextEASSlixIso15693(uint8_t *password) {
|
||||
void PassProtextEASSlixIso15693(const uint8_t *password) {
|
||||
LED_D_ON();
|
||||
Iso15693InitReader();
|
||||
StartCountSspClk();
|
||||
|
@ -3099,7 +3088,7 @@ void PassProtextEASSlixIso15693(uint8_t *password) {
|
|||
reply_ng(CMD_HF_ISO15693_SLIX_PASS_PROTECT_EAS, res, NULL, 0);
|
||||
switch_off();
|
||||
}
|
||||
void PassProtectAFISlixIso15693(uint8_t *password) {
|
||||
void PassProtectAFISlixIso15693(const uint8_t *password) {
|
||||
LED_D_ON();
|
||||
Iso15693InitReader();
|
||||
StartCountSspClk();
|
||||
|
@ -3109,7 +3098,7 @@ void PassProtectAFISlixIso15693(uint8_t *password) {
|
|||
switch_off();
|
||||
}
|
||||
|
||||
void WriteAFIIso15693(uint8_t *password, bool use_pwd, uint8_t *uid, bool use_uid, uint8_t afi) {
|
||||
void WriteAFIIso15693(const uint8_t *password, bool use_pwd, uint8_t *uid, bool use_uid, uint8_t afi) {
|
||||
LED_D_ON();
|
||||
Iso15693InitReader();
|
||||
StartCountSspClk();
|
||||
|
|
|
@ -47,8 +47,6 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo
|
|||
void AcquireRawAdcSamplesIso15693(void);
|
||||
void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader
|
||||
void EmlClearIso15693(void);
|
||||
void EmlSetMemIso15693(uint8_t count, uint8_t *data, uint32_t offset);
|
||||
void EmlGetMemIso15693(uint8_t count, uint8_t *output, uint32_t offset);
|
||||
void SimTagIso15693(uint8_t *uid, uint8_t block_size); // simulate an ISO15693 tag
|
||||
void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag
|
||||
void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI
|
||||
|
@ -62,12 +60,12 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui
|
|||
|
||||
void SetTag15693Uid(const uint8_t *uid);
|
||||
|
||||
void WritePasswordSlixIso15693(uint8_t *old_password, uint8_t *new_password, uint8_t pwd_id);
|
||||
void DisablePrivacySlixIso15693(uint8_t *password);
|
||||
void EnablePrivacySlixIso15693(uint8_t *password);
|
||||
void DisableEAS_AFISlixIso15693(uint8_t *password, bool usepwd);
|
||||
void EnableEAS_AFISlixIso15693(uint8_t *password, bool usepwd);
|
||||
void PassProtextEASSlixIso15693(uint8_t *password);
|
||||
void PassProtectAFISlixIso15693(uint8_t *password);
|
||||
void WriteAFIIso15693(uint8_t *password, bool usepwd, uint8_t *uid, bool use_uid, uint8_t afi);
|
||||
void WritePasswordSlixIso15693(const uint8_t *old_password, const uint8_t *new_password, uint8_t pwd_id);
|
||||
void DisablePrivacySlixIso15693(const uint8_t *password);
|
||||
void EnablePrivacySlixIso15693(const uint8_t *password);
|
||||
void DisableEAS_AFISlixIso15693(const uint8_t *password, bool usepwd);
|
||||
void EnableEAS_AFISlixIso15693(const uint8_t *password, bool usepwd);
|
||||
void PassProtextEASSlixIso15693(const uint8_t *password);
|
||||
void PassProtectAFISlixIso15693(const uint8_t *password);
|
||||
void WriteAFIIso15693(const uint8_t *password, bool usepwd, uint8_t *uid, bool use_uid, uint8_t afi);
|
||||
#endif
|
||||
|
|
|
@ -528,7 +528,7 @@ OUT:
|
|||
StopTicks();
|
||||
}
|
||||
|
||||
void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data) {
|
||||
void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, const uint8_t *data) {
|
||||
// configure ARM and FPGA
|
||||
init_reader();
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
void LegicRfInfo(void);
|
||||
int LegicRfReaderEx(uint16_t offset, uint16_t len, uint8_t iv);
|
||||
void LegicRfReader(uint16_t offset, uint16_t len, uint8_t iv);
|
||||
void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, uint8_t *data);
|
||||
void LegicRfWriter(uint16_t offset, uint16_t len, uint8_t iv, const uint8_t *data);
|
||||
|
||||
legic_card_select_t *getLegicCardInfo(void);
|
||||
#endif /* __LEGICRF_H */
|
||||
|
|
|
@ -91,18 +91,18 @@ static bool wait_for(bool value, const uint32_t timeout) {
|
|||
// - A bit length >80.2us is a 1
|
||||
// - A bit length <80.2us is a 0
|
||||
// - A bit length >148.6us is a code violation
|
||||
static int8_t rx_bit(void) {
|
||||
static int32_t rx_bit(void) {
|
||||
// backup ts for threshold calculation
|
||||
uint32_t bit_start = last_frame_end;
|
||||
|
||||
// wait for pause to end
|
||||
if (!wait_for(RWD_PULSE, bit_start + RWD_TIME_1 * 3 / 2)) {
|
||||
return -1;
|
||||
if (wait_for(RWD_PULSE, bit_start + RWD_TIME_1 * 3 / 2) == false) {
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
|
||||
// wait for next pause
|
||||
if (!wait_for(RWD_PAUSE, bit_start + RWD_TIME_1 * 3 / 2)) {
|
||||
return -1;
|
||||
if (wait_for(RWD_PAUSE, bit_start + RWD_TIME_1 * 3 / 2) == false) {
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
|
||||
// update bit and frame end
|
||||
|
@ -110,7 +110,7 @@ static int8_t rx_bit(void) {
|
|||
|
||||
// check for code violation (bit to short)
|
||||
if (last_frame_end - bit_start < RWD_TIME_PAUSE) {
|
||||
return -1;
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
|
||||
// apply threshold (average of RWD_TIME_0 and )
|
||||
|
@ -215,7 +215,6 @@ static void tx_ack(void) {
|
|||
// - receive the frame
|
||||
// - detect end of frame (last pause)
|
||||
static int32_t rx_frame(uint8_t *len) {
|
||||
int32_t frame = 0;
|
||||
|
||||
// add 2 SSP clock cycles (1 for tx and 1 for rx pipeline delay)
|
||||
// those will be subtracted at the end of the rx phase
|
||||
|
@ -235,23 +234,24 @@ static int32_t rx_frame(uint8_t *len) {
|
|||
|
||||
// check for code violation
|
||||
if (i > RWD_CMD_TIMEOUT) {
|
||||
return -1;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
// backup ts for trace log
|
||||
uint32_t last_frame_start = last_frame_end;
|
||||
int32_t frame = 0;
|
||||
|
||||
// receive frame
|
||||
for (*len = 0; true; ++(*len)) {
|
||||
// receive next bit
|
||||
LED_B_ON();
|
||||
int8_t bit = rx_bit();
|
||||
int32_t bit = rx_bit();
|
||||
LED_B_OFF();
|
||||
|
||||
// check for code violation and to short / long frame
|
||||
if ((bit < 0) && ((*len < RWD_MIN_FRAME_LEN) || (*len > RWD_MAX_FRAME_LEN))) {
|
||||
return -1;
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
|
||||
// check for code violation caused by end of frame
|
||||
|
@ -353,7 +353,7 @@ static int32_t setup_phase(legic_card_select_t *p_card) {
|
|||
// wait for iv
|
||||
int32_t iv = rx_frame(&len);
|
||||
if ((len != 7) || (iv < 0)) {
|
||||
return -1;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
// configure prng
|
||||
|
@ -375,19 +375,19 @@ static int32_t setup_phase(legic_card_select_t *p_card) {
|
|||
// wait for ack
|
||||
int32_t ack = rx_frame(&len);
|
||||
if ((len != 6) || (ack < 0)) {
|
||||
return -1;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
// validate data
|
||||
switch (p_card->tagtype) {
|
||||
case 0:
|
||||
if (ack != 0x19) return -1;
|
||||
if (ack != 0x19) return PM3_ERFTRANS;
|
||||
break;
|
||||
case 1:
|
||||
if (ack != 0x39) return -1;
|
||||
if (ack != 0x39) return PM3_ERFTRANS;
|
||||
break;
|
||||
case 2:
|
||||
if (ack != 0x39) return -1;
|
||||
if (ack != 0x39) return PM3_ERFTRANS;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -399,7 +399,7 @@ static int32_t setup_phase(legic_card_select_t *p_card) {
|
|||
// the gap by one period.
|
||||
last_frame_end += TAG_BIT_PERIOD;
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static uint8_t calc_crc4(uint16_t cmd, uint8_t cmd_sz, uint8_t value) {
|
||||
|
@ -414,7 +414,7 @@ static int32_t connected_phase(legic_card_select_t *p_card) {
|
|||
// wait for command
|
||||
int32_t cmd = rx_frame(&len);
|
||||
if (cmd < 0) {
|
||||
return -1;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
// check if command is LEGIC_READ
|
||||
|
@ -425,8 +425,7 @@ static int32_t connected_phase(legic_card_select_t *p_card) {
|
|||
|
||||
// transmit data
|
||||
tx_frame((crc << 8) | byte, 12);
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// check if command is LEGIC_WRITE
|
||||
|
@ -441,7 +440,7 @@ static int32_t connected_phase(legic_card_select_t *p_card) {
|
|||
uint8_t calc_crc = calc_crc4(addr << 1, p_card->cmdsize, byte);
|
||||
if (calc_crc != crc) {
|
||||
Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc);
|
||||
return -1;
|
||||
return PM3_ECRC;
|
||||
}
|
||||
|
||||
// store data
|
||||
|
@ -449,11 +448,10 @@ static int32_t connected_phase(legic_card_select_t *p_card) {
|
|||
|
||||
// transmit ack
|
||||
tx_ack();
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
return -1;
|
||||
return PM3_ERFTRANS;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -466,26 +464,26 @@ void LegicRfSimulate(uint8_t tagtype, bool send_reply) {
|
|||
// configure ARM and FPGA
|
||||
init_tag();
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
int res = init_card(tagtype, &card);
|
||||
// verify command line input
|
||||
if (init_card(tagtype, &card) != PM3_SUCCESS) {
|
||||
if (res != PM3_SUCCESS) {
|
||||
DbpString("Unknown tagtype to simulate");
|
||||
res = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
uint16_t counter = 0;
|
||||
LED_A_ON();
|
||||
|
||||
Dbprintf("Legic Prime, simulating uid: %02X%02X%02X%02X", legic_mem[0], legic_mem[1], legic_mem[2], legic_mem[3]);
|
||||
Dbprintf("Legic Prime, simulating MCD... " _YELLOW_("%02X") " MSN... " _YELLOW_("%02X%02X%02X"), legic_mem[0], legic_mem[1], legic_mem[2], legic_mem[3]);
|
||||
|
||||
uint16_t counter = 0;
|
||||
while (BUTTON_PRESS() == false) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (counter >= 2000) {
|
||||
if (data_available()) {
|
||||
res = PM3_EOPABORTED;
|
||||
break;
|
||||
goto OUT;
|
||||
}
|
||||
counter = 0;
|
||||
}
|
||||
|
@ -497,12 +495,12 @@ void LegicRfSimulate(uint8_t tagtype, bool send_reply) {
|
|||
}
|
||||
|
||||
// wait for connection, restart on error
|
||||
if (setup_phase(&card)) {
|
||||
if (setup_phase(&card) != PM3_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// connection is established, process commands until one fails
|
||||
while (connected_phase(&card) == false) {
|
||||
while (connected_phase(&card) == PM3_SUCCESS) {
|
||||
WDT_HIT();
|
||||
}
|
||||
}
|
||||
|
@ -510,17 +508,19 @@ void LegicRfSimulate(uint8_t tagtype, bool send_reply) {
|
|||
OUT:
|
||||
|
||||
if (g_dbglevel >= DBG_ERROR) {
|
||||
Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen());
|
||||
Dbprintf("Emulator stopped. Trace length... " _YELLOW_("%d"), BigBuf_get_traceLen());
|
||||
}
|
||||
|
||||
if (res == PM3_EOPABORTED)
|
||||
DbpString("aborted by user");
|
||||
if (res == PM3_EOPABORTED) {
|
||||
DbpString("Aborted by user");
|
||||
}
|
||||
|
||||
switch_off();
|
||||
StopTicks();
|
||||
|
||||
if (send_reply)
|
||||
if (send_reply) {
|
||||
reply_ng(CMD_HF_LEGIC_SIMULATE, res, NULL, 0);
|
||||
}
|
||||
|
||||
BigBuf_free_keep_EM();
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
Notes about EM4xxx timings.
|
||||
|
||||
The timing values differs between cards, we got EM410x, EM43x5, EM445x etc.
|
||||
We are trying to unify and enable the Proxmark to easily detect and select correct timings automatic.
|
||||
We are trying to unify and enable the Proxmark3 to easily detect and select correct timings automatic.
|
||||
The measures from datasheets doesn't always match correct the hardware features of RDV4 antenans and we still wanted to let other devices with other custom antennas
|
||||
still benefit from this repo. This is why its configurable and we use to set these dynamic settings in device external flash memory.
|
||||
|
||||
|
@ -287,7 +287,7 @@ void printT55xxConfig(void) {
|
|||
DbpString("");
|
||||
}
|
||||
|
||||
void setT55xxConfig(uint8_t arg0, t55xx_configurations_t *c) {
|
||||
void setT55xxConfig(uint8_t arg0, const t55xx_configurations_t *c) {
|
||||
for (uint8_t i = 0; i < 4; i++) {
|
||||
if (c->m[i].start_gap != 0)
|
||||
T55xx_Timing.m[i].start_gap = c->m[i].start_gap;
|
||||
|
@ -391,6 +391,8 @@ void loadT55xxConfig(void) {
|
|||
if (isok == T55XX_CONFIG_LEN) {
|
||||
if (g_dbglevel > 1) DbpString("T55XX Config load success");
|
||||
}
|
||||
|
||||
BigBuf_free();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1009,7 +1011,7 @@ void CmdHIDsimTAG(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool
|
|||
// prepare a waveform pattern in the buffer based on the ID given then
|
||||
// simulate a FSK tag until the button is pressed
|
||||
// arg1 contains fcHigh and fcLow, arg2 contains STT marker and clock
|
||||
void CmdFSKsimTAGEx(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen, uint8_t *bits, bool ledcontrol, int numcycles) {
|
||||
void CmdFSKsimTAGEx(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen, const uint8_t *bits, bool ledcontrol, int numcycles) {
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
||||
|
@ -1045,7 +1047,7 @@ void CmdFSKsimTAGEx(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t cl
|
|||
// prepare a waveform pattern in the buffer based on the ID given then
|
||||
// simulate a FSK tag until the button is pressed
|
||||
// arg1 contains fcHigh and fcLow, arg2 contains STT marker and clock
|
||||
void CmdFSKsimTAG(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen, uint8_t *bits, bool ledcontrol) {
|
||||
void CmdFSKsimTAG(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen, const uint8_t *bits, bool ledcontrol) {
|
||||
CmdFSKsimTAGEx(fchigh, fclow, separator, clk, bitslen, bits, ledcontrol, -1);
|
||||
reply_ng(CMD_LF_FSK_SIMULATE, PM3_EOPABORTED, NULL, 0);
|
||||
}
|
||||
|
@ -1866,9 +1868,9 @@ void T55xxResetRead(uint8_t flags, bool ledcontrol) {
|
|||
if (ledcontrol) LED_A_OFF();
|
||||
}
|
||||
|
||||
void T55xxDangerousRawTest(uint8_t *data, bool ledcontrol) {
|
||||
void T55xxDangerousRawTest(const uint8_t *data, bool ledcontrol) {
|
||||
// supports only default downlink mode
|
||||
t55xx_test_block_t *c = (t55xx_test_block_t *)data;
|
||||
const t55xx_test_block_t *c = (const t55xx_test_block_t *)data;
|
||||
|
||||
uint8_t start_wait = 4;
|
||||
uint8_t bs[128 / 8];
|
||||
|
@ -2320,7 +2322,7 @@ void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, boo
|
|||
}
|
||||
|
||||
// clone viking tag to T55xx
|
||||
void CopyVikingtoT55xx(uint8_t *blocks, bool q5, bool em, bool ledcontrol) {
|
||||
void CopyVikingtoT55xx(const uint8_t *blocks, bool q5, bool em, bool ledcontrol) {
|
||||
|
||||
uint32_t data[] = {T55x7_BITRATE_RF_32 | T55x7_MODULATION_MANCHESTER | (2 << T55x7_MAXBLOCK_SHIFT), 0, 0};
|
||||
if (q5) {
|
||||
|
|
|
@ -38,9 +38,9 @@ void CmdHIDsimTAGEx(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, boo
|
|||
void CmdHIDsimTAG(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool ledcontrol);
|
||||
|
||||
void CmdFSKsimTAGEx(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen,
|
||||
uint8_t *bits, bool ledcontrol, int numcycles);
|
||||
const uint8_t *bits, bool ledcontrol, int numcycles);
|
||||
void CmdFSKsimTAG(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t clk, uint16_t bitslen,
|
||||
uint8_t *bits, bool ledcontrol);
|
||||
const uint8_t *bits, bool ledcontrol);
|
||||
void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size,
|
||||
const uint8_t *bits, bool ledcontrol);
|
||||
void CmdPSKsimTAG(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size,
|
||||
|
@ -54,7 +54,7 @@ int lf_em410x_watch(int findone, uint32_t *high, uint64_t *low, bool ledcontrol)
|
|||
int lf_io_watch(int findone, uint32_t *high, uint32_t *low, bool ledcontrol);
|
||||
|
||||
void CopyHIDtoT55x7(uint32_t hi2, uint32_t hi, uint32_t lo, uint8_t longFMT, bool q5, bool em, bool ledcontrol); // Clone an HID card to T5557/T5567
|
||||
void CopyVikingtoT55xx(uint8_t *blocks, bool q5, bool em, bool ledcontrol);
|
||||
void CopyVikingtoT55xx(const uint8_t *blocks, bool q5, bool em, bool ledcontrol);
|
||||
|
||||
int copy_em410x_to_t55xx(uint8_t card, uint8_t clock, uint32_t id_hi, uint32_t id_lo, bool ledcontrol);
|
||||
|
||||
|
@ -66,7 +66,7 @@ void T55xxReadBlock(uint8_t page, bool pwd_mode, bool brute_mem, uint8_t block,
|
|||
uint8_t downlink_mode, bool ledcontrol);
|
||||
void T55xxWakeUp(uint32_t pwd, uint8_t flags, bool ledcontrol);
|
||||
void T55xx_ChkPwds(uint8_t flags, bool ledcontrol);
|
||||
void T55xxDangerousRawTest(uint8_t *data, bool ledcontrol);
|
||||
void T55xxDangerousRawTest(const uint8_t *data, bool ledcontrol);
|
||||
|
||||
void turn_read_lf_on(uint32_t delay);
|
||||
void turn_read_lf_off(uint32_t delay);
|
||||
|
@ -78,7 +78,7 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd, bo
|
|||
void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd, bool ledcontrol);
|
||||
|
||||
void Cotag(uint32_t arg0, bool ledcontrol);
|
||||
void setT55xxConfig(uint8_t arg0, t55xx_configurations_t *c);
|
||||
void setT55xxConfig(uint8_t arg0, const t55xx_configurations_t *c);
|
||||
t55xx_configurations_t *getT55xxConfig(void);
|
||||
void printT55xxConfig(void);
|
||||
void loadT55xxConfig(void);
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "lfdemod.h"
|
||||
#include "string.h" // memset
|
||||
#include "appmain.h" // print stack
|
||||
#include "usb_cdc.h" // real-time sampling
|
||||
|
||||
/*
|
||||
Default LF config is set to:
|
||||
|
@ -94,7 +95,7 @@ void setDefaultSamplingConfig(void) {
|
|||
* @brief setSamplingConfig
|
||||
* @param sc
|
||||
*/
|
||||
void setSamplingConfig(sample_config *sc) {
|
||||
void setSamplingConfig(const sample_config *sc) {
|
||||
|
||||
// decimation (1-8) how many bits of adc sample value to save
|
||||
if (sc->decimation > 0 && sc->decimation < 9)
|
||||
|
@ -128,20 +129,6 @@ sample_config *getSamplingConfig(void) {
|
|||
return &config;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pushes bit onto the stream
|
||||
* @param stream
|
||||
* @param bit
|
||||
*/
|
||||
static void pushBit(BitstreamOut_t *stream, uint8_t bit) {
|
||||
int bytepos = stream->position >> 3; // divide by 8
|
||||
int bitpos = stream->position & 7;
|
||||
*(stream->buffer + bytepos) &= ~(1 << (7 - bitpos));
|
||||
*(stream->buffer + bytepos) |= (bit > 0) << (7 - bitpos);
|
||||
stream->position++;
|
||||
stream->numbits++;
|
||||
}
|
||||
|
||||
void initSampleBuffer(uint32_t *sample_size) {
|
||||
initSampleBufferEx(sample_size, false);
|
||||
}
|
||||
|
@ -233,13 +220,20 @@ void logSample(uint8_t sample, uint8_t decimation, uint8_t bits_per_sample, bool
|
|||
data.numbits = samples.total_saved << 3;
|
||||
|
||||
} else {
|
||||
pushBit(&data, sample & 0x80);
|
||||
if (bits_per_sample > 1) pushBit(&data, sample & 0x40);
|
||||
if (bits_per_sample > 2) pushBit(&data, sample & 0x20);
|
||||
if (bits_per_sample > 3) pushBit(&data, sample & 0x10);
|
||||
if (bits_per_sample > 4) pushBit(&data, sample & 0x08);
|
||||
if (bits_per_sample > 5) pushBit(&data, sample & 0x04);
|
||||
if (bits_per_sample > 6) pushBit(&data, sample & 0x02);
|
||||
// truncate trailing data
|
||||
sample >>= 8 - bits_per_sample;
|
||||
sample <<= 8 - bits_per_sample;
|
||||
|
||||
uint8_t bits_offset = data.numbits & 0x7;
|
||||
uint8_t bits_cap = 8 - bits_offset;
|
||||
|
||||
// write the current byte
|
||||
data.buffer[data.numbits >> 3] |= sample >> bits_offset;
|
||||
uint32_t numbits = data.numbits + bits_cap;
|
||||
|
||||
// write the remaining bits to the next byte
|
||||
data.buffer[numbits >> 3] |= sample << (bits_cap);
|
||||
data.numbits += bits_per_sample;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,7 +306,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
|||
|
||||
// only every 4000th times, in order to save time when collecting samples.
|
||||
// interruptible only when logging not yet triggered
|
||||
if ((checked >= 4000) && trigger_hit == false) {
|
||||
if (trigger_hit == false && (checked >= 4000)) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
|
@ -331,7 +325,7 @@ 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;
|
||||
|
||||
// Test point 8 (TP8) can be used to trigger oscilloscope
|
||||
// (RDV4) Test point 8 (TP8) can be used to trigger oscilloscope
|
||||
if (ledcontrol) LED_D_OFF();
|
||||
|
||||
// threshold either high or low values 128 = center 0. if trigger = 178
|
||||
|
@ -344,9 +338,8 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
|||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
trigger_hit = true;
|
||||
}
|
||||
|
||||
if (samples_to_skip > 0) {
|
||||
samples_to_skip--;
|
||||
|
@ -377,6 +370,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
|||
}
|
||||
return data.numbits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Does sample acquisition, ignoring the config values set in the sample_config.
|
||||
* This method is typically used by tag-specific readers who just wants to read the samples
|
||||
|
@ -431,6 +425,123 @@ uint32_t SampleLF(bool verbose, uint32_t sample_size, bool ledcontrol) {
|
|||
BigBuf_Clear_ext(false);
|
||||
return ReadLF(true, verbose, sample_size, ledcontrol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do LF sampling and send samples to the USB
|
||||
*
|
||||
* Uses parameters in config. Only bits_per_sample = 8 is working now
|
||||
*
|
||||
* @param reader_field - true for reading tags, false for sniffing
|
||||
* @return sampling result
|
||||
**/
|
||||
int ReadLF_realtime(bool reader_field) {
|
||||
// parameters from config and constants
|
||||
const uint8_t bits_per_sample = config.bits_per_sample;
|
||||
const int16_t trigger_threshold = config.trigger_threshold;
|
||||
int32_t samples_to_skip = config.samples_to_skip;
|
||||
const uint8_t decimation = config.decimation;
|
||||
|
||||
const int8_t size_threshold_table[9] = {0, 64, 64, 60, 64, 60, 60, 56, 64};
|
||||
const int8_t size_threshold = size_threshold_table[bits_per_sample];
|
||||
|
||||
// DoAcquisition() start
|
||||
uint8_t last_byte = 0;
|
||||
uint8_t curr_byte = 0;
|
||||
int return_value = PM3_SUCCESS;
|
||||
|
||||
uint32_t sample_buffer_len = AT91C_USB_EP_IN_SIZE;
|
||||
initSampleBuffer(&sample_buffer_len);
|
||||
if (sample_buffer_len != AT91C_USB_EP_IN_SIZE) {
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
bool trigger_hit = false;
|
||||
int16_t checked = 0;
|
||||
|
||||
return_value = async_usb_write_start();
|
||||
if (return_value != PM3_SUCCESS) {
|
||||
return return_value;
|
||||
}
|
||||
|
||||
BigBuf_Clear_ext(false);
|
||||
LFSetupFPGAForADC(config.divisor, reader_field);
|
||||
|
||||
while (BUTTON_PRESS() == false) {
|
||||
// only every 4000th times, in order to save time when collecting samples.
|
||||
// interruptible only when logging not yet triggered
|
||||
if (trigger_hit == false && (checked >= 4000)) {
|
||||
if (data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
|
||||
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;
|
||||
|
||||
// (RDV4) Test point 8 (TP8) can be used to trigger oscilloscope
|
||||
LED_D_OFF();
|
||||
|
||||
// threshold either high or low values 128 = center 0. if trigger = 178
|
||||
if (trigger_hit == false) {
|
||||
if ((trigger_threshold > 0) && (sample < (trigger_threshold + 128)) && (sample > (128 - trigger_threshold))) {
|
||||
continue;
|
||||
}
|
||||
trigger_hit = true;
|
||||
}
|
||||
|
||||
if (samples_to_skip > 0) {
|
||||
samples_to_skip--;
|
||||
continue;
|
||||
}
|
||||
|
||||
logSample(sample, decimation, bits_per_sample, false);
|
||||
|
||||
// Write to USB FIFO if byte changed
|
||||
curr_byte = data.numbits >> 3;
|
||||
if (curr_byte > last_byte) {
|
||||
async_usb_write_pushByte(data.buffer[last_byte]);
|
||||
}
|
||||
last_byte = curr_byte;
|
||||
|
||||
if (samples.total_saved == size_threshold) {
|
||||
// Request USB transmission and change FIFO bank
|
||||
if (async_usb_write_requestWrite() == false) {
|
||||
return_value = PM3_EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
// Reset sample
|
||||
last_byte = 0;
|
||||
data.numbits = 0;
|
||||
samples.counter = size_threshold;
|
||||
samples.total_saved = 0;
|
||||
|
||||
} else if (samples.total_saved == 1) {
|
||||
// Check if there is any data from client
|
||||
if (data_available_fast()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LED_D_OFF();
|
||||
return_value = async_usb_write_stop();
|
||||
|
||||
// DoAcquisition() end
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
return return_value;
|
||||
}
|
||||
/**
|
||||
* Initializes the FPGA for sniffer-mode (field off), and acquires the samples.
|
||||
* @return number of bits sampled
|
||||
|
|
|
@ -51,6 +51,16 @@ void doT55x7Acquisition(size_t sample_size, bool ledcontrol);
|
|||
**/
|
||||
uint32_t SampleLF(bool verbose, uint32_t sample_size, bool ledcontrol);
|
||||
|
||||
/**
|
||||
* Do LF sampling and send samples to the USB
|
||||
*
|
||||
* Uses parameters in config. Only bits_per_sample = 8 is working now
|
||||
*
|
||||
* @param reader_field - true for reading tags, false for sniffing
|
||||
* @return sampling result
|
||||
**/
|
||||
int ReadLF_realtime(bool reader_field);
|
||||
|
||||
/**
|
||||
* Initializes the FPGA for sniff-mode (field off), and acquires the samples.
|
||||
* @return number of bits sampled
|
||||
|
@ -110,7 +120,7 @@ void LFSetupFPGAForADC(int divisor, bool reader_field);
|
|||
* @brief setSamplingConfig
|
||||
* @param sc
|
||||
*/
|
||||
void setSamplingConfig(sample_config *sc);
|
||||
void setSamplingConfig(const sample_config *sc);
|
||||
void setDefaultSamplingConfig(void);
|
||||
sample_config *getSamplingConfig(void);
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ static void zx8211_setup_read(void) {
|
|||
WDT_HIT();
|
||||
}
|
||||
|
||||
static void zx_send(uint8_t *cmd, uint8_t clen) {
|
||||
static void zx_send(const uint8_t *cmd, uint8_t clen) {
|
||||
|
||||
if (clen == 0)
|
||||
return;
|
||||
|
@ -153,7 +153,7 @@ static void zx_get(bool ledcontrol) {
|
|||
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
(void)sample;
|
||||
|
||||
// Test point 8 (TP8) can be used to trigger oscilloscope
|
||||
// (RDV4) Test point 8 (TP8) can be used to trigger oscilloscope
|
||||
if (ledcontrol) LED_D_OFF();
|
||||
|
||||
}
|
||||
|
|
1161
armsrc/mifarecmd.c
1161
armsrc/mifarecmd.c
File diff suppressed because it is too large
Load diff
|
@ -19,19 +19,18 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
void MifareReadBlock(uint8_t blockNo, uint8_t keyType, uint8_t *datain);
|
||||
int16_t mifare_cmd_readblocks(uint8_t key_auth_cmd, uint8_t *key, uint8_t read_cmd, uint8_t block_no, uint8_t count, uint8_t *block_data);
|
||||
int16_t mifare_cmd_writeblocks(uint8_t key_auth_cmd, uint8_t *key, uint8_t write_cmd, uint8_t block_no, uint8_t count, uint8_t *block_data);
|
||||
void MifareReadSector(uint8_t sector_no, uint8_t key_type, uint8_t *key);
|
||||
void MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
|
||||
|
||||
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
|
||||
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 MifareValue(uint8_t arg0, uint8_t arg1, uint8_t arg2, 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);
|
||||
|
||||
void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, bool calibrate, uint8_t *key);
|
||||
void MifareStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8_t targetKeyType, uint8_t *key);
|
||||
|
||||
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
|
||||
|
@ -41,7 +40,6 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da
|
|||
void MifareChkKeys_file(uint8_t *fn);
|
||||
|
||||
void MifareEMemClr(void);
|
||||
void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain);
|
||||
void MifareEMemGet(uint8_t blockno, uint8_t blockcnt);
|
||||
int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype);
|
||||
int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype);
|
||||
|
@ -49,8 +47,9 @@ int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype);
|
|||
// MFC GEN1a /1b
|
||||
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(bool is_mfc); // is "magic chinese" card?
|
||||
void MifareCIdent(bool is_mfc, uint8_t keytype, uint8_t *key); // is "magic chinese" card?
|
||||
void MifareHasStaticNonce(void); // Has the tag a static nonce?
|
||||
void MifareHasStaticEncryptedNonce(uint8_t block_no, uint8_t key_type, uint8_t *key); // Has the tag a static encrypted nonce?
|
||||
|
||||
// MFC GEN3
|
||||
int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len);
|
||||
|
@ -58,11 +57,6 @@ void MifareGen3UID(uint8_t uidlen, uint8_t *uid); // Gen 3 magic card set UID wi
|
|||
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
|
||||
|
||||
// MFC GEN4 GDM
|
||||
void MifareReadConfigBlockGDM(uint8_t *key);
|
||||
void MifareWriteConfigBlockGDM(uint8_t *datain);
|
||||
void MifareWriteBlockGDM(uint8_t blockno, uint8_t keytype, uint8_t *key, uint8_t *datain);
|
||||
|
||||
// MFC GEN4 GTU
|
||||
void MifareG4ReadBlk(uint8_t blockno, uint8_t *pwd, uint8_t workFlags);
|
||||
void MifareG4WriteBlk(uint8_t blockno, uint8_t *pwd, uint8_t *data, uint8_t workFlags);
|
||||
|
|
|
@ -46,6 +46,15 @@
|
|||
#include "dbprint.h"
|
||||
#include "ticks.h"
|
||||
|
||||
static bool IsKeyBReadable(uint8_t blockNo) {
|
||||
uint8_t sector_trailer[16];
|
||||
emlGetMem(sector_trailer, SectorTrailer(blockNo), 1);
|
||||
uint8_t AC = ((sector_trailer[7] >> 5) & 0x04)
|
||||
| ((sector_trailer[8] >> 2) & 0x02)
|
||||
| ((sector_trailer[8] >> 7) & 0x01);
|
||||
return (AC == 0x00 || AC == 0x01 || AC == 0x02);
|
||||
}
|
||||
|
||||
static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
|
||||
uint8_t sector_trailer[16];
|
||||
emlGetMem(sector_trailer, blockNo, 1);
|
||||
|
@ -514,7 +523,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
uint8_t rAUTH_NT_keystream[4];
|
||||
uint32_t nonce = 0;
|
||||
|
||||
tUart14a *uart = GetUart14a();
|
||||
const tUart14a *uart = GetUart14a();
|
||||
|
||||
// free eventually allocated BigBuf memory but keep Emulator Memory
|
||||
BigBuf_free_keep_EM();
|
||||
|
@ -872,8 +881,8 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
if (MifareBlockToSector(receivedCmd_dec[1]) != cardAUTHSC) {
|
||||
blockNo = receivedCmd_dec[1];
|
||||
if (MifareBlockToSector(blockNo) != cardAUTHSC) {
|
||||
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
|
||||
FpgaDisableTracing();
|
||||
|
||||
|
@ -881,6 +890,18 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
Dbprintf("[MFEMUL_WORK] Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking", receivedCmd_dec[0], receivedCmd_dec[1], cardAUTHSC);
|
||||
break;
|
||||
}
|
||||
|
||||
// Compliance of MIFARE Classic EV1 1K Datasheet footnote of Table 8
|
||||
// If access bits show that key B is Readable, any subsequent memory access will be refused.
|
||||
|
||||
if (cardAUTHKEY == AUTHKEYB && IsKeyBReadable(blockNo)) {
|
||||
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
|
||||
FpgaDisableTracing();
|
||||
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
Dbprintf("[MFEMUL_WORK] Access denied: Reader tried to access memory on authentication with key B while key B is readable in sector (0x%02x)", cardAUTHSC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// case MFEMUL_WORK => CMD READ block
|
||||
|
@ -1251,7 +1272,7 @@ void Mifare1ksim(uint16_t flags, uint8_t exitAfterNReads, uint8_t *datain, uint1
|
|||
memcpy(receivedCmd_dec, response, 16); // don't change anything
|
||||
}
|
||||
}
|
||||
emlSetMem(receivedCmd_dec, cardWRBL, 1);
|
||||
emlSetMem_xt(receivedCmd_dec, cardWRBL, 1, 16);
|
||||
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK?
|
||||
FpgaDisableTracing();
|
||||
|
||||
|
|
|
@ -116,7 +116,9 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
|
|||
|
||||
uint16_t len = ReaderReceive(answer, par);
|
||||
|
||||
if (answer_parity) *answer_parity = par[0];
|
||||
if (answer_parity) {
|
||||
*answer_parity = par[0];
|
||||
}
|
||||
|
||||
if (pcs && (crypted == CRYPT_ALL)) {
|
||||
if (len == 1) {
|
||||
|
@ -127,10 +129,11 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
|
|||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(answer[0], 3)) << 3;
|
||||
answer[0] = res;
|
||||
} else {
|
||||
for (pos = 0; pos < len; pos++)
|
||||
for (pos = 0; pos < len; pos++) {
|
||||
answer[pos] = crypto1_byte(pcs, 0x00, 0) ^ answer[pos];
|
||||
}
|
||||
}
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -139,9 +142,9 @@ int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo,
|
|||
return mifare_classic_authex(pcs, uid, blockNo, keyType, ui64Key, isNested, NULL, NULL);
|
||||
}
|
||||
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing) {
|
||||
return mifare_classic_authex_2(pcs, uid, blockNo, keyType, ui64Key, isNested, ntptr, timing, false);
|
||||
return mifare_classic_authex_cmd(pcs, uid, blockNo, (keyType & 1) ? MIFARE_AUTH_KEYB : MIFARE_AUTH_KEYA, ui64Key, isNested, ntptr, NULL, timing);
|
||||
}
|
||||
int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, bool is_gdm) {
|
||||
int mifare_classic_authex_cmd(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t cmd, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *ntencptr, uint32_t *timing) {
|
||||
|
||||
// "random" reader nonce:
|
||||
uint8_t nr[4];
|
||||
|
@ -150,13 +153,14 @@ int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t bloc
|
|||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
|
||||
|
||||
// Transmit MIFARE_CLASSIC_AUTH 0x60, 0x61 or GDM 0x80
|
||||
uint8_t cmdbyte = (is_gdm) ? MIFARE_MAGIC_GDM_AUTH_KEY : MIFARE_AUTH_KEYA + (keyType & 0x01);
|
||||
int len = mifare_sendcmd_short(pcs, isNested, cmdbyte, blockNo, receivedAnswer, receivedAnswerPar, timing);
|
||||
// Transmit MIFARE_CLASSIC_AUTH, 0x60 for key A, 0x61 for key B, or 0x80 for GDM backdoor
|
||||
int len = mifare_sendcmd_short(pcs, isNested, cmd, blockNo, receivedAnswer, receivedAnswerPar, timing);
|
||||
if (len != 4) return 1;
|
||||
|
||||
// Save the tag nonce (nt)
|
||||
uint32_t nt = bytes_to_num(receivedAnswer, 4);
|
||||
if (ntencptr)
|
||||
*ntencptr = nt;
|
||||
|
||||
// ----------------------------- crypto1 create
|
||||
if (isNested)
|
||||
|
@ -207,8 +211,8 @@ int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t bloc
|
|||
uint32_t save_timeout = iso14a_get_timeout();
|
||||
|
||||
// set timeout for authentication response
|
||||
if (save_timeout > 103)
|
||||
iso14a_set_timeout(103);
|
||||
if (save_timeout > 106)
|
||||
iso14a_set_timeout(106);
|
||||
|
||||
// Receive 4 byte tag answer
|
||||
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
|
||||
|
@ -229,21 +233,25 @@ int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t bloc
|
|||
return 0;
|
||||
}
|
||||
|
||||
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
|
||||
return mifare_classic_readblock_ex(pcs, uid, blockNo, blockData, ISO14443A_CMD_READBLOCK);
|
||||
int mifare_classic_readblock(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData) {
|
||||
return mifare_classic_readblock_ex(pcs, blockNo, blockData, ISO14443A_CMD_READBLOCK);
|
||||
}
|
||||
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte) {
|
||||
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte) {
|
||||
|
||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
|
||||
|
||||
uint16_t len = mifare_sendcmd_short(pcs, 1, iso_byte, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
if (len == 1) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error %02x", receivedAnswer[0]);
|
||||
if (g_dbglevel >= DBG_ERROR) {
|
||||
Dbprintf("Block " _YELLOW_("%3d") " Cmd 0x%02x Cmd Error %02x", blockNo, iso_byte, receivedAnswer[0]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (len != 18) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("wrong response len %d (expected 18)", len);
|
||||
if (g_dbglevel >= DBG_ERROR) {
|
||||
Dbprintf("Block " _YELLOW_("%3d") " Cmd 0x%02x Wrong response len, expected 18 got " _RED_("%d"), blockNo, iso_byte, len);
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@ -415,32 +423,29 @@ int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData) {
|
|||
return res;
|
||||
}
|
||||
|
||||
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData) {
|
||||
return mifare_classic_writeblock_ex(pcs, uid, blockNo, blockData, false);
|
||||
int mifare_classic_writeblock(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData) {
|
||||
return mifare_classic_writeblock_ex(pcs, blockNo, blockData, ISO14443A_CMD_WRITEBLOCK);
|
||||
}
|
||||
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm) {
|
||||
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData, uint8_t cmd) {
|
||||
|
||||
// variables
|
||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
|
||||
|
||||
// command MIFARE_MAGIC_GDM_WRITEBLOCK
|
||||
uint16_t len;
|
||||
if (is_gdm) {
|
||||
len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
} else {
|
||||
len = mifare_sendcmd_short(pcs, 1, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
}
|
||||
// cmd is ISO14443A_CMD_WRITEBLOCK for normal tags, but could also be
|
||||
// MIFARE_MAGIC_GDM_WRITEBLOCK or MIFARE_MAGIC_GDM_WRITE_CFG for certain magic tags
|
||||
uint16_t len = mifare_sendcmd_short(pcs, 1, cmd, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return 1;
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
uint8_t d_block[18], d_block_enc[18];
|
||||
memcpy(d_block, blockData, 16);
|
||||
AddCrc14A(d_block, 16);
|
||||
|
||||
if (pcs) {
|
||||
// enough for 18 Bytes to send
|
||||
uint8_t par[3] = {0x00, 0x00, 0x00};
|
||||
// crypto
|
||||
|
@ -450,6 +455,9 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
|
|||
}
|
||||
|
||||
ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);
|
||||
} else {
|
||||
ReaderTransmit(d_block, sizeof(d_block), NULL);
|
||||
}
|
||||
|
||||
// tearoff occurred
|
||||
if (tearoff_hook() == PM3_ETEAROFF) {
|
||||
|
@ -459,67 +467,24 @@ int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t
|
|||
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
|
||||
|
||||
uint8_t res = 0;
|
||||
if (pcs) {
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
|
||||
|
||||
if ((len != 1) || (res != 0x0A)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData) {
|
||||
|
||||
// variables
|
||||
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE] = {0x00};
|
||||
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE] = {0x00};
|
||||
|
||||
uint16_t len = mifare_sendcmd_short(pcs, 1, MIFARE_MAGIC_GDM_WRITE_CFG, 0, receivedAnswer, receivedAnswerPar, NULL);
|
||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t d_block[18], d_block_enc[18];
|
||||
memcpy(d_block, blockData, 16);
|
||||
AddCrc14A(d_block, 16);
|
||||
|
||||
// enough for 18 Bytes to send
|
||||
uint8_t par[3] = {0x00, 0x00, 0x00};
|
||||
// crypto
|
||||
for (uint32_t pos = 0; pos < 18; pos++) {
|
||||
d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ d_block[pos];
|
||||
par[pos >> 3] |= (((filter(pcs->odd) ^ oddparity8(d_block[pos])) & 0x01) << (7 - (pos & 0x0007)));
|
||||
}
|
||||
|
||||
ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par, NULL);
|
||||
|
||||
// tearoff occurred
|
||||
if (tearoff_hook() == PM3_ETEAROFF) {
|
||||
return PM3_ETEAROFF;
|
||||
} else {
|
||||
// Receive the response
|
||||
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
|
||||
|
||||
uint8_t res = 0;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 0)) << 0;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 1)) << 1;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 2)) << 2;
|
||||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
|
||||
res = receivedAnswer[0];
|
||||
}
|
||||
|
||||
if ((len != 1) || (res != 0x0A)) {
|
||||
return 2;
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd send data2 Error: %02x", res);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action) {
|
||||
int mifare_classic_value(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData, uint8_t action) {
|
||||
// variables
|
||||
uint16_t len = 0;
|
||||
uint32_t pos = 0;
|
||||
|
@ -540,8 +505,8 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
|
|||
len = mifare_sendcmd_short(pcs, 1, command, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return 1;
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
memcpy(d_block, blockData, 4);
|
||||
|
@ -566,12 +531,12 @@ int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo
|
|||
res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], 3)) << 3;
|
||||
|
||||
if ((len != 1) || (res != 0x0A)) {
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Cmd send data2 Error: %02x", res);
|
||||
return 2;
|
||||
if (g_dbglevel >= DBG_INFO) Dbprintf("Cmd send data2 Error: %02x", res);
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
|
||||
|
@ -585,9 +550,10 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
|
|||
len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_WRITEBLOCK, blockNo, receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len);
|
||||
return 1;
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
memcpy(d_block, blockData, 16);
|
||||
|
@ -599,11 +565,12 @@ int mifare_ultra_writeblock_compat(uint8_t blockNo, uint8_t *blockData) {
|
|||
len = ReaderReceive(receivedAnswer, receivedAnswerPar);
|
||||
|
||||
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf("Cmd Send Data Error: %02x %d", receivedAnswer[0], len);
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) {
|
||||
|
@ -618,13 +585,15 @@ int mifare_ultra_writeblock(uint8_t blockNo, uint8_t *blockData) {
|
|||
len = mifare_sendcmd(MIFARE_ULC_WRITE, block, sizeof(block), receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if (receivedAnswer[0] != 0x0A) { // 0x0a - ACK
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf("Cmd Send Error: %02x %d", receivedAnswer[0], len);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
int mifare_classic_halt_ex(struct Crypto1State *pcs) {
|
||||
|
||||
int mifare_classic_halt(struct Crypto1State *pcs) {
|
||||
uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00};
|
||||
uint16_t len = mifare_sendcmd_short(pcs, (pcs == NULL) ? CRYPT_NONE : CRYPT_ALL, ISO14443A_CMD_HALT, 0x00, receivedAnswer, NULL, NULL);
|
||||
if (len != 0) {
|
||||
|
@ -633,19 +602,9 @@ int mifare_classic_halt_ex(struct Crypto1State *pcs) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) {
|
||||
return mifare_classic_halt_ex(pcs);
|
||||
}
|
||||
|
||||
int mifare_ultra_halt(void) {
|
||||
uint16_t len = 0;
|
||||
uint8_t receivedAnswer[4] = {0x00, 0x00, 0x00, 0x00};
|
||||
len = mifare_sendcmd_short(NULL, CRYPT_NONE, ISO14443A_CMD_HALT, 0x00, receivedAnswer, NULL, NULL);
|
||||
if (len != 0) {
|
||||
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("halt warning. response len: %x", len);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
return mifare_classic_halt(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
@ -660,32 +619,28 @@ uint8_t FirstBlockOfSector(uint8_t sectorNo) {
|
|||
return sectorNo * 4;
|
||||
else
|
||||
return 32 * 4 + (sectorNo - 32) * 16;
|
||||
|
||||
}
|
||||
|
||||
// work with emulator memory
|
||||
void emlSetMem(uint8_t *data, int blockNum, int blocksCount) {
|
||||
emlSetMem_xt(data, blockNum, blocksCount, 16);
|
||||
}
|
||||
|
||||
void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth) {
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
memcpy(emCARD + blockNum * blockBtWidth, data, blocksCount * blockBtWidth);
|
||||
void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int block_width) {
|
||||
uint32_t offset = blockNum * block_width;
|
||||
uint32_t len = blocksCount * block_width;
|
||||
emlSet(data, offset, len);
|
||||
}
|
||||
|
||||
void emlGetMem(uint8_t *data, int blockNum, int blocksCount) {
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
memcpy(data, emCARD + blockNum * 16, blocksCount * 16);
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
memcpy(data, mem + blockNum * 16, blocksCount * 16);
|
||||
}
|
||||
|
||||
void emlGetMemBt(uint8_t *data, int offset, int byteCount) {
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
memcpy(data, emCARD + offset, byteCount);
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
memcpy(data, mem + offset, byteCount);
|
||||
}
|
||||
|
||||
int emlCheckValBl(int blockNum) {
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
uint8_t *data = emCARD + blockNum * 16;
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
uint8_t *data = mem + blockNum * 16;
|
||||
|
||||
if ((data[0] != (data[4] ^ 0xff)) || (data[0] != data[8]) ||
|
||||
(data[1] != (data[5] ^ 0xff)) || (data[1] != data[9]) ||
|
||||
|
@ -699,8 +654,8 @@ int emlCheckValBl(int blockNum) {
|
|||
}
|
||||
|
||||
int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) {
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
uint8_t *data = emCARD + blockNum * 16;
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
uint8_t *data = mem + blockNum * 16;
|
||||
|
||||
if (emlCheckValBl(blockNum))
|
||||
return 1;
|
||||
|
@ -711,8 +666,8 @@ int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum) {
|
|||
}
|
||||
|
||||
int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) {
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
uint8_t *data = emCARD + blockNum * 16;
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
uint8_t *data = mem + blockNum * 16;
|
||||
|
||||
memcpy(data + 0, &blReg, 4);
|
||||
memcpy(data + 8, &blReg, 4);
|
||||
|
@ -723,41 +678,43 @@ int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum) {
|
|||
data[13] = blBlock ^ 0xff;
|
||||
data[14] = blBlock;
|
||||
data[15] = blBlock ^ 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t emlGetKey(int sectorNum, int keyType) {
|
||||
uint8_t key[6] = {0x00};
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
memcpy(key, emCARD + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6);
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
memcpy(key, mem + 16 * (FirstBlockOfSector(sectorNum) + NumBlocksPerSector(sectorNum) - 1) + keyType * 10, 6);
|
||||
return bytes_to_num(key, 6);
|
||||
}
|
||||
|
||||
void emlClearMem(void) {
|
||||
const uint8_t trailer[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x80, 0x69, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
const uint8_t uid[] = {0xe6, 0x84, 0x87, 0xf3, 0x16, 0x88, 0x04, 0x00, 0x46, 0x8e, 0x45, 0x55, 0x4d, 0x70, 0x41, 0x04};
|
||||
uint8_t *emCARD = BigBuf_get_EM_addr();
|
||||
memset(emCARD, 0, CARD_MEMORY_SIZE);
|
||||
uint8_t *mem = BigBuf_get_EM_addr();
|
||||
memset(mem, 0, CARD_MEMORY_SIZE);
|
||||
|
||||
// fill sectors trailer data
|
||||
for (uint16_t b = 3; b < MIFARE_4K_MAXBLOCK; ((b < MIFARE_2K_MAXBLOCK - 4) ? (b += 4) : (b += 16)))
|
||||
emlSetMem((uint8_t *)trailer, b, 1);
|
||||
for (uint16_t b = 3; b < MIFARE_4K_MAXBLOCK; ((b < MIFARE_2K_MAXBLOCK - 4) ? (b += 4) : (b += 16))) {
|
||||
emlSetMem_xt((uint8_t *)trailer, b, 1, 16);
|
||||
}
|
||||
|
||||
// uid
|
||||
emlSetMem((uint8_t *)uid, 0, 1);
|
||||
emlSetMem_xt((uint8_t *)uid, 0, 1, 16);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t SectorTrailer(uint8_t blockNo) {
|
||||
if (blockNo <= MIFARE_2K_MAXBLOCK) {
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("Sector Trailer for block %d : %d", blockNo, (blockNo | 0x03));
|
||||
}
|
||||
return (blockNo | 0x03);
|
||||
} else {
|
||||
if (g_dbglevel >= DBG_EXTENDED)
|
||||
Dbprintf("Sector Trailer for block %d : %d", blockNo, (blockNo | 0x0f));
|
||||
return (blockNo | 0x0f);
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("Sector Trailer for block %d : %d", blockNo, (blockNo | 0x0F));
|
||||
}
|
||||
return (blockNo | 0x0F);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -804,9 +761,10 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData) {
|
|||
|
||||
len = mifare_sendcmd_special(NULL, 1, 0x02, data, receivedAnswer, receivedAnswerPar, NULL);
|
||||
if (len == 1) {
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_INFO) {
|
||||
Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
|
||||
return 1;
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
if (len == 12) {
|
||||
|
@ -817,9 +775,9 @@ int mifare_desfire_des_auth1(uint32_t uid, uint8_t *blockData) {
|
|||
receivedAnswer[10], receivedAnswer[11]);
|
||||
}
|
||||
memcpy(blockData, receivedAnswer, 12);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return 1;
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
|
||||
|
@ -834,9 +792,10 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
|
|||
len = mifare_sendcmd_special2(NULL, 1, 0x03, data, receivedAnswer, receivedAnswerPar, NULL);
|
||||
|
||||
if ((receivedAnswer[0] == 0x03) && (receivedAnswer[1] == 0xae)) {
|
||||
if (g_dbglevel >= DBG_ERROR)
|
||||
if (g_dbglevel >= DBG_ERROR) {
|
||||
Dbprintf("Auth Error: %02x %02x", receivedAnswer[0], receivedAnswer[1]);
|
||||
return 1;
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
if (len == 12) {
|
||||
|
@ -847,7 +806,7 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData) {
|
|||
receivedAnswer[10], receivedAnswer[11]);
|
||||
}
|
||||
memcpy(blockData, receivedAnswer, 12);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return 1;
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@
|
|||
#define MIFARE_2K_MAXSECTOR 32
|
||||
#define MIFARE_4K_MAXSECTOR 40
|
||||
|
||||
#define MIFARE_BLOCK_SIZE 16
|
||||
|
||||
//mifare emulator states
|
||||
#define MFEMUL_NOFIELD 0
|
||||
#define MFEMUL_IDLE 1
|
||||
|
@ -72,17 +74,15 @@ uint16_t mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t
|
|||
// mifare classic
|
||||
int mifare_classic_auth(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested);
|
||||
int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing);
|
||||
int mifare_classic_authex_2(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t keyType, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *timing, bool is_gdm);
|
||||
int mifare_classic_authex_cmd(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t cmd, uint64_t ui64Key, uint8_t isNested, uint32_t *ntptr, uint32_t *ntencptr, uint32_t *timing);
|
||||
|
||||
int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
|
||||
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte);
|
||||
int mifare_classic_readblock(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData);
|
||||
int mifare_classic_readblock_ex(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData, uint8_t iso_byte);
|
||||
|
||||
int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid);
|
||||
int mifare_classic_halt_ex(struct Crypto1State *pcs);
|
||||
int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData);
|
||||
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, bool is_gdm);
|
||||
int mifare_classic_value(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData, uint8_t action);
|
||||
int mifare_classic_write_cfg_block_gdm(struct Crypto1State *pcs, uint32_t uid, uint8_t *blockData);
|
||||
int mifare_classic_halt(struct Crypto1State *pcs);
|
||||
int mifare_classic_writeblock(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData);
|
||||
int mifare_classic_writeblock_ex(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData, uint8_t cmd);
|
||||
int mifare_classic_value(struct Crypto1State *pcs, uint8_t blockNo, uint8_t *blockData, uint8_t action);
|
||||
|
||||
// Ultralight/NTAG...
|
||||
int mifare_ul_ev1_auth(uint8_t *keybytes, uint8_t *pack);
|
||||
|
@ -115,8 +115,7 @@ uint8_t SectorTrailer(uint8_t blockNo);
|
|||
|
||||
// emulator functions
|
||||
void emlClearMem(void);
|
||||
void emlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidth);
|
||||
void emlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int block_width);
|
||||
void emlGetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
void emlGetMemBt(uint8_t *data, int offset, int byteCount);
|
||||
uint64_t emlGetKey(int sectorNum, int keyType);
|
||||
|
|
|
@ -115,12 +115,12 @@ static void init_opt_select_LUT(void) {
|
|||
print_result("", opt_select_LUT, 256);
|
||||
}
|
||||
***********************************************************************************/
|
||||
|
||||
/*
|
||||
#define opt__select(x,y,r) (4 & (((r & (r << 2)) >> 5) ^ ((r & ~(r << 2)) >> 4) ^ ( (r | r << 2) >> 3)))\
|
||||
|(2 & (((r | r << 2) >> 6) ^ ( (r | r << 2) >> 1) ^ (r >> 5) ^ r ^ ((x^y) << 1)))\
|
||||
|(1 & (((r & ~(r << 2)) >> 4) ^ ((r & (r << 2)) >> 3) ^ r ^ x))
|
||||
|
||||
/*
|
||||
|
||||
* Some background on the expression above can be found here...
|
||||
uint8_t xopt__select(bool x, bool y, uint8_t r)
|
||||
{
|
||||
|
@ -201,7 +201,9 @@ static void opt_suc(const uint8_t *k, State_t *s, const uint8_t *in, uint8_t len
|
|||
}
|
||||
//For tag MAC, an additional 32 zeroes
|
||||
if (add32Zeroes) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
opt_successor(k, s, 0);
|
||||
opt_successor(k, s, 0);
|
||||
opt_successor(k, s, 0);
|
||||
opt_successor(k, s, 0);
|
||||
}
|
||||
|
|
|
@ -114,7 +114,7 @@ uint64_t x_bytes_to_num(uint8_t *src, size_t len) {
|
|||
return num;
|
||||
}
|
||||
|
||||
uint8_t reversebytes(uint8_t b) {
|
||||
uint8_t reversebyte(uint8_t b) {
|
||||
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4;
|
||||
b = (b & 0xCC) >> 2 | (b & 0x33) << 2;
|
||||
b = (b & 0xAA) >> 1 | (b & 0x55) << 1;
|
||||
|
@ -124,14 +124,14 @@ uint8_t reversebytes(uint8_t b) {
|
|||
void reverse_arraybytes(uint8_t *arr, size_t len) {
|
||||
size_t i;
|
||||
for (i = 0; i < len ; i++) {
|
||||
arr[i] = reversebytes(arr[i]);
|
||||
arr[i] = reversebyte(arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void reverse_arraycopy(uint8_t *arr, uint8_t *dest, size_t len) {
|
||||
size_t i;
|
||||
for (i = 0; i < len ; i++) {
|
||||
dest[i] = reversebytes(arr[i]);
|
||||
dest[i] = reversebyte(arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ int bitsLeft(BitstreamIn_t *stream);
|
|||
void push6bits(BitstreamOut_t *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);
|
||||
uint8_t reversebyte(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
|
||||
|
|
23
armsrc/sam_mfc.c
Normal file
23
armsrc/sam_mfc.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Routines to support MFC <-> SAM communication
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "sam_mfc.h"
|
||||
#include "sam_seos.h"
|
||||
#include "iclass.h"
|
||||
|
||||
#include "proxmark3_arm.h"
|
||||
#include "cmd.h"
|
21
armsrc/sam_mfc.h
Normal file
21
armsrc/sam_mfc.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __SAM_MFC_H
|
||||
#define __SAM_MFC_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#endif
|
447
armsrc/sam_picopass.c
Normal file
447
armsrc/sam_picopass.c
Normal file
|
@ -0,0 +1,447 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Routines to support Picopass <-> SAM communication
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "sam_picopass.h"
|
||||
#include "iclass.h"
|
||||
#include "crc16.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "BigBuf.h"
|
||||
#include "cmd.h"
|
||||
#include "commonutil.h"
|
||||
#include "ticks.h"
|
||||
#include "dbprint.h"
|
||||
#include "i2c.h"
|
||||
#include "iso15693.h"
|
||||
#include "protocols.h"
|
||||
#include "optimized_cipher.h"
|
||||
#include "fpgaloader.h"
|
||||
|
||||
static int sam_rxtx(const uint8_t *data, uint16_t n, uint8_t *resp, uint16_t *resplen) {
|
||||
|
||||
StartTicks();
|
||||
|
||||
bool res = I2C_BufferWrite(data, n, I2C_DEVICE_CMD_SEND_T0, I2C_DEVICE_ADDRESS_MAIN);
|
||||
if (res == false) {
|
||||
DbpString("failed to send to SIM CARD");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*resplen = ISO7816_MAX_FRAME;
|
||||
|
||||
res = sc_rx_bytes(resp, resplen, SIM_WAIT_DELAY);
|
||||
if (res == false) {
|
||||
DbpString("failed to receive from SIM CARD");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (*resplen < 2) {
|
||||
DbpString("received too few bytes from SIM CARD");
|
||||
res = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
uint16_t more_len = 0;
|
||||
|
||||
if (resp[*resplen - 2] == 0x61 || resp[*resplen - 2] == 0x9F) {
|
||||
more_len = resp[*resplen - 1];
|
||||
} else {
|
||||
// we done, return
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Don't discard data we already received except the SW code.
|
||||
// If we only received 1 byte, this is the echo of INS, we discard it.
|
||||
*resplen -= 2;
|
||||
if (*resplen == 1) {
|
||||
*resplen = 0;
|
||||
}
|
||||
|
||||
uint8_t cmd_getresp[] = {0x00, ISO7816_GET_RESPONSE, 0x00, 0x00, more_len};
|
||||
|
||||
res = I2C_BufferWrite(cmd_getresp, sizeof(cmd_getresp), I2C_DEVICE_CMD_SEND_T0, I2C_DEVICE_ADDRESS_MAIN);
|
||||
if (res == false) {
|
||||
DbpString("failed to send to SIM CARD 2");
|
||||
goto out;
|
||||
}
|
||||
|
||||
more_len = 255 - *resplen;
|
||||
|
||||
res = sc_rx_bytes(resp + *resplen, &more_len, SIM_WAIT_DELAY);
|
||||
if (res == false) {
|
||||
DbpString("failed to receive from SIM CARD 2");
|
||||
goto out;
|
||||
}
|
||||
|
||||
*resplen += more_len;
|
||||
|
||||
out:
|
||||
StopTicks();
|
||||
return res;
|
||||
}
|
||||
|
||||
// using HID SAM to authenticate w PICOPASS
|
||||
int sam_picopass_get_pacs(void) {
|
||||
|
||||
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
|
||||
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 };
|
||||
static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 };
|
||||
uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t read_aia[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64};
|
||||
uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
|
||||
|
||||
picopass_hdr_t hdr = {0};
|
||||
// Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used
|
||||
// bit 7: parity.
|
||||
// if (use_credit_key)
|
||||
// read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
|
||||
|
||||
BigBuf_free_keep_EM();
|
||||
|
||||
clear_trace();
|
||||
|
||||
I2C_Reset_EnterMainProgram();
|
||||
StopTicks();
|
||||
|
||||
uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
|
||||
bool shallow_mod = false;
|
||||
uint16_t resp_len = 0;
|
||||
int res;
|
||||
uint32_t eof_time = 0;
|
||||
|
||||
// wakeup
|
||||
Iso15693InitReader();
|
||||
|
||||
uint32_t start_time = GetCountSspClk();
|
||||
iclass_send_as_reader(act_all, 1, &start_time, &eof_time, shallow_mod);
|
||||
|
||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_ACTALL, &eof_time, false, true, &resp_len);
|
||||
if (res != PM3_SUCCESS) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// send Identify
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(identify, 1, &start_time, &eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC
|
||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// copy the Anti-collision CSN to our select-packet
|
||||
memcpy(&select[1], resp, 8);
|
||||
|
||||
// select the card
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(select, sizeof(select), &start_time, &eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here, 8 byte CSN and 2 byte CRC
|
||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// store CSN
|
||||
memcpy(hdr.csn, resp, sizeof(hdr.csn));
|
||||
|
||||
// card selected, now read config (block1) (only 8 bytes no CRC)
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time, &eof_time, shallow_mod);
|
||||
|
||||
// expect a 8-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// store CONFIG
|
||||
memcpy((uint8_t *)&hdr.conf, resp, sizeof(hdr.conf));
|
||||
|
||||
uint8_t pagemap = get_pagemap(&hdr);
|
||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
||||
res = PM3_EWRONGANSWER;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// read App Issuer Area block 5
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, &eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// store AIA
|
||||
memcpy(hdr.app_issuer_area, resp, sizeof(hdr.app_issuer_area));
|
||||
|
||||
// card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod);
|
||||
|
||||
// expect a 8-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
||||
if (res != PM3_SUCCESS || resp_len != 8) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// store EPURSE
|
||||
memcpy(hdr.epurse, resp, sizeof(hdr.epurse));
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// SAM comms
|
||||
// -----------------------------------------------------------------------------
|
||||
size_t sam_len = 0;
|
||||
uint8_t *sam_apdu = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// first
|
||||
// a0 da 02 63 1a 44 0a 44 00 00 00 a0 12 ad 10 a0 0e 80 02 00 04 81 08 9b fc a4 00 fb ff 12 e0
|
||||
hexstr_to_byte_array("a0da02631a440a44000000a012ad10a00e800200048108", sam_apdu, &sam_len);
|
||||
memcpy(sam_apdu + sam_len, hdr.csn, sizeof(hdr.csn));
|
||||
sam_len += sizeof(hdr.csn);
|
||||
|
||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("-- 1", resp, resp_len);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// second
|
||||
// a0 da 02 63 0d 44 0a 44 00 00 00 a0 05 a1 03 80 01 04
|
||||
hexstr_to_byte_array("a0da02630d440a44000000a005a103800104", sam_apdu, &sam_len);
|
||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("-- 2", resp, resp_len);
|
||||
|
||||
// TAG response
|
||||
// -- 0c 05 de64 // read block 5
|
||||
// Tag|c00a140a000000a110a10e8004 0c05de64 8102 0004 820201f4
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// third AIA block 5
|
||||
// a0da02631c140a00000000bd14a012a010800a ffffff0006fffffff88e 81020000
|
||||
// picopass legacy is fixed. wants AIA and crc. ff ff ff ff ff ff ff ff ea f5
|
||||
// picpoasss SE ff ff ff 00 06 ff ff ff f8 8e
|
||||
hexstr_to_byte_array("a0da02631c140a00000000bd14a012a010800affffff0006fffffff88e81020000", sam_apdu, &sam_len);
|
||||
memcpy(sam_apdu + 19, hdr.app_issuer_area, sizeof(hdr.app_issuer_area));
|
||||
AddCrc(sam_apdu + 19, 8);
|
||||
|
||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("-- 3", resp, resp_len);
|
||||
|
||||
// 88 02 -- readcheck (block2 epurse, start of auth)
|
||||
// Tag|c00a140a000000a10ea10c8002 8802 8102 0004 820201f4 9000
|
||||
// 61 16 f5 0a140a000000a10ea10c 8002 8802 8102 0004 820201f4 9000
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// forth EPURSE
|
||||
// a0da02631a140a00000000bd12a010a00e8008 ffffffffedffffff 81020000
|
||||
hexstr_to_byte_array("a0da02631a140a00000000bd12a010a00e8008ffffffffedffffff81020000", sam_apdu, &sam_len);
|
||||
memcpy(sam_apdu + 19, hdr.epurse, sizeof(hdr.epurse));
|
||||
|
||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("-- 4", resp, resp_len);
|
||||
|
||||
uint8_t nr_mac[9] = {0};
|
||||
memcpy(nr_mac, resp + 11, sizeof(nr_mac));
|
||||
// resp here hold the whole NR/MAC
|
||||
// 05 9bcd475e965ee20e // CHECK (w key)
|
||||
print_dbg("NR/MAC", nr_mac, sizeof(nr_mac));
|
||||
|
||||
// c00a140a000000a115a1138009 059bcd475e965ee20e 8102 0004 820201f4 9000
|
||||
|
||||
// pre calc ourself?
|
||||
// uint8_t cc_nr[] = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0};
|
||||
uint8_t div_key[8] = {0};
|
||||
static uint8_t legacy_aa1_key[] = {0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78};
|
||||
iclass_calc_div_key(hdr.csn, legacy_aa1_key, div_key, false);
|
||||
|
||||
uint8_t mac[4] = {0};
|
||||
if (g_dbglevel == DBG_DEBUG) {
|
||||
uint8_t wb[16] = {0};
|
||||
memcpy(wb, hdr.epurse, sizeof(hdr.epurse));
|
||||
memcpy(wb + sizeof(hdr.epurse), nr_mac + 1, 4);
|
||||
print_dbg("cc_nr...", wb, sizeof(wb));
|
||||
doMAC_N(wb, sizeof(wb), div_key, mac);
|
||||
print_dbg("Calc MAC...", mac, sizeof(mac));
|
||||
}
|
||||
|
||||
// start ssp clock again...
|
||||
StartCountSspClk();
|
||||
|
||||
// NOW we auth against tag
|
||||
uint8_t cmd_check[9] = { ICLASS_CMD_CHECK };
|
||||
memcpy(cmd_check + 1, nr_mac + 1, 8);
|
||||
|
||||
start_time = GetCountSspClk();
|
||||
iclass_send_as_reader(cmd_check, sizeof(cmd_check), &start_time, &eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
||||
if (res != PM3_SUCCESS || resp_len != 4) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
// store MAC
|
||||
memcpy(mac, resp, sizeof(mac));
|
||||
print_dbg("Got MAC", mac, sizeof(mac));
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// fifth send received MAC
|
||||
// A0DA026316140A00000000BD0EA00CA00A8004 311E32E9 81020000
|
||||
hexstr_to_byte_array("A0DA026316140A00000000BD0EA00CA00A8004311E32E981020000", sam_apdu, &sam_len);
|
||||
memcpy(sam_apdu + 19, mac, sizeof(mac));
|
||||
|
||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("-- 5", resp, resp_len);
|
||||
|
||||
uint8_t tmp_p1[4] = {0};
|
||||
uint8_t tmp_p2[4] = {0};
|
||||
|
||||
// c161c10000a11aa118800e8702 ffffffff88ffffff 0a914eb981020004820236b09000
|
||||
|
||||
memcpy(tmp_p1, resp + 13, sizeof(tmp_p1));
|
||||
memcpy(tmp_p2, resp + 13 + 4, sizeof(tmp_p2));
|
||||
// -----------------------------------------------------------------------------
|
||||
// sixth send fake epurse update
|
||||
// A0DA02631C140A00000000BD14A012A010800A 88FFFFFFFFFFFFFF9DE1 81020000
|
||||
hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A88FFFFFFFFFFFFFF9DE181020000", sam_apdu, &sam_len);
|
||||
|
||||
memcpy(sam_apdu + 19, tmp_p2, sizeof(tmp_p1));
|
||||
memcpy(sam_apdu + 19 + 4, tmp_p1, sizeof(tmp_p1));
|
||||
AddCrc(sam_apdu + 19, 8);
|
||||
|
||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("-- 6", resp, resp_len);
|
||||
// c1 61 c1 00 00 a1 10 a1 0e 80 04 0c 06 45 56 81 02 00 04 82 02 01 f4 90 00
|
||||
|
||||
// read block 6
|
||||
StartCountSspClk();
|
||||
start_time = GetCountSspClk();
|
||||
iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("Block 6 from Picopass", resp, resp_len);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// eight send block 6 config to SAM
|
||||
// A0DA02631C140A00000000BD14A012A010800A 030303030003E0174323 81020000
|
||||
hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A030303030003E017432381020000", sam_apdu, &sam_len);
|
||||
memcpy(sam_apdu + 19, resp, resp_len);
|
||||
|
||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("-- 7", resp, resp_len);
|
||||
|
||||
// c161c10000a110a10e8004 0606455681020004820201f49000
|
||||
|
||||
// read the credential blocks
|
||||
StartCountSspClk();
|
||||
start_time = GetCountSspClk();
|
||||
iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod);
|
||||
|
||||
// expect a 10-byte response here
|
||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
||||
if (res != PM3_SUCCESS) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("Block 6-9 from Picopass", resp, resp_len);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// nine send credential blocks to SAM
|
||||
// A0DA026334140A00000000BD2CA02AA0288022 030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C 81020000
|
||||
hexstr_to_byte_array("A0DA026334140A00000000BD2CA02AA0288022030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C81020000", sam_apdu, &sam_len);
|
||||
memcpy(sam_apdu + 19, resp, resp_len);
|
||||
|
||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
print_dbg("-- 8", resp, resp_len);
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// TEN ask for PACS data
|
||||
// A0DA02630C440A00000000BD04A0028200
|
||||
hexstr_to_byte_array("A0DA02630C440A00000000BD04A0028200", sam_apdu, &sam_len);
|
||||
memcpy(sam_apdu + 19, resp, resp_len);
|
||||
|
||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
||||
res = PM3_ECARDEXCHANGE;
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_dbg("-- 9 response", resp, resp_len);
|
||||
if (memcmp(resp, "\xc1\x64\x00\x00\x00\xbd\x17\x8a\x15", 9) == 0) {
|
||||
res = PM3_ENOPACS;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// c164000000bd098a07 030506951f9a00 9000
|
||||
uint8_t *pacs = BigBuf_calloc(resp[8]);
|
||||
memcpy(pacs, resp + 9, resp[8]);
|
||||
|
||||
print_dbg("-- 10 PACS data", pacs, resp[8]);
|
||||
|
||||
reply_ng(CMD_HF_SAM_PICOPASS, PM3_SUCCESS, pacs, resp[8]);
|
||||
res = PM3_SUCCESS;
|
||||
goto off;
|
||||
|
||||
out:
|
||||
reply_ng(CMD_HF_SAM_PICOPASS, res, NULL, 0);
|
||||
|
||||
off:
|
||||
switch_off();
|
||||
BigBuf_free();
|
||||
return res;
|
||||
}
|
||||
|
||||
// HID SAM <-> MFC
|
||||
// HID SAM <-> SEOS
|
23
armsrc/sam_picopass.h
Normal file
23
armsrc/sam_picopass.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __SAM_PICOPASS_H
|
||||
#define __SAM_PICOPASS_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int sam_picopass_get_pacs(void);
|
||||
|
||||
#endif
|
22
armsrc/sam_seos.c
Normal file
22
armsrc/sam_seos.c
Normal file
|
@ -0,0 +1,22 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Routines to support SEOS <-> SAM communication
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "sam_seos.h"
|
||||
#include "iclass.h"
|
||||
|
||||
#include "proxmark3_arm.h"
|
||||
#include "cmd.h"
|
21
armsrc/sam_seos.h
Normal file
21
armsrc/sam_seos.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// See LICENSE.txt for the text of the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef __SAM_SEOS_H
|
||||
#define __SAM_SEOS_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#endif
|
|
@ -196,17 +196,19 @@ int rdv40_spiffs_check(void) {
|
|||
|
||||
///// Base RDV40_SPIFFS_SAFETY_NORMAL operations////////////////////////////////
|
||||
|
||||
void write_to_spiffs(const char *filename, uint8_t *src, uint32_t size) {
|
||||
void write_to_spiffs(const char *filename, const uint8_t *src, uint32_t size) {
|
||||
spiffs_file fd = SPIFFS_open(&fs, filename, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
|
||||
if (SPIFFS_write(&fs, fd, src, size) < 0) {
|
||||
// Note: SPIFFS_write() doesn't declare third parameter as const (but should)
|
||||
if (SPIFFS_write(&fs, fd, (void *)src, size) < 0) {
|
||||
Dbprintf("wr errno %i\n", SPIFFS_errno(&fs));
|
||||
}
|
||||
SPIFFS_close(&fs, fd);
|
||||
}
|
||||
|
||||
void append_to_spiffs(const char *filename, uint8_t *src, uint32_t size) {
|
||||
void append_to_spiffs(const char *filename, const uint8_t *src, uint32_t size) {
|
||||
spiffs_file fd = SPIFFS_open(&fs, filename, SPIFFS_APPEND | SPIFFS_RDWR, 0);
|
||||
if (SPIFFS_write(&fs, fd, src, size) < 0) {
|
||||
// Note: SPIFFS_write() doesn't declare third parameter as const (but should)
|
||||
if (SPIFFS_write(&fs, fd, (void *)src, size) < 0) {
|
||||
Dbprintf("errno %i\n", SPIFFS_errno(&fs));
|
||||
}
|
||||
SPIFFS_close(&fs, fd);
|
||||
|
@ -310,10 +312,10 @@ static int is_valid_filename(const char *filename) {
|
|||
}
|
||||
*/
|
||||
static void copy_in_spiffs(const char *src, const char *dst) {
|
||||
uint32_t size = size_in_spiffs((char *)src);
|
||||
uint32_t size = size_in_spiffs(src);
|
||||
uint8_t *mem = BigBuf_malloc(size);
|
||||
read_from_spiffs((char *)src, (uint8_t *)mem, size);
|
||||
write_to_spiffs((char *)dst, (uint8_t *)mem, size);
|
||||
read_from_spiffs(src, (uint8_t *)mem, size);
|
||||
write_to_spiffs(dst, (uint8_t *)mem, size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -434,7 +436,7 @@ int rdv40_spiffs_lazy_mount_rollback(int changed) {
|
|||
// TODO : forbid writing to a filename which already exists as lnk !
|
||||
// TODO : forbid writing to a filename.lnk which already exists without lnk !
|
||||
// Note: Writing in SPIFFS_WRITE_CHUNK_SIZE (8192) byte chucks helps to ensure "free space" has been erased by GC (Garbage collection)
|
||||
int rdv40_spiffs_write(const char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) {
|
||||
int rdv40_spiffs_write(const char *filename, const uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) {
|
||||
RDV40_SPIFFS_SAFE_FUNCTION(
|
||||
uint32_t idx;
|
||||
if (size <= SPIFFS_WRITE_CHUNK_SIZE) {
|
||||
|
@ -457,7 +459,7 @@ int rdv40_spiffs_write(const char *filename, uint8_t *src, uint32_t size, RDV40S
|
|||
)
|
||||
}
|
||||
|
||||
int rdv40_spiffs_append(const char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) {
|
||||
int rdv40_spiffs_append(const char *filename, const uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level) {
|
||||
RDV40_SPIFFS_SAFE_FUNCTION(
|
||||
uint32_t idx;
|
||||
// Append any SPIFFS_WRITE_CHUNK_SIZE byte chunks
|
||||
|
@ -480,26 +482,26 @@ int rdv40_spiffs_read(const char *filename, uint8_t *dst, uint32_t size, RDV40Sp
|
|||
|
||||
// TODO : forbid writing to a filename which already exists as lnk !
|
||||
// TODO : forbid writing to a filename.lnk which already exists without lnk !
|
||||
int rdv40_spiffs_rename(char *old_filename, char *new_filename, RDV40SpiFFSSafetyLevel level) {
|
||||
int rdv40_spiffs_rename(const char *old_filename, const char *new_filename, RDV40SpiFFSSafetyLevel level) {
|
||||
RDV40_SPIFFS_SAFE_FUNCTION( //
|
||||
rename_in_spiffs(old_filename, new_filename); //
|
||||
)
|
||||
}
|
||||
int rdv40_spiffs_remove(char *filename, RDV40SpiFFSSafetyLevel level) {
|
||||
int rdv40_spiffs_remove(const char *filename, RDV40SpiFFSSafetyLevel level) {
|
||||
RDV40_SPIFFS_SAFE_FUNCTION( //
|
||||
remove_from_spiffs(filename); //
|
||||
)
|
||||
}
|
||||
|
||||
int rdv40_spiffs_copy(char *src, char *dst, RDV40SpiFFSSafetyLevel level) {
|
||||
int rdv40_spiffs_copy(const char *src_filename, const char *dst_filename, RDV40SpiFFSSafetyLevel level) {
|
||||
RDV40_SPIFFS_SAFE_FUNCTION( //
|
||||
copy_in_spiffs(src, dst); //
|
||||
copy_in_spiffs(src_filename, dst_filename); //
|
||||
)
|
||||
}
|
||||
|
||||
int rdv40_spiffs_stat(char *filename, uint32_t *buf, RDV40SpiFFSSafetyLevel level) {
|
||||
int rdv40_spiffs_stat(const char *filename, uint32_t *size_in_bytes, RDV40SpiFFSSafetyLevel level) {
|
||||
RDV40_SPIFFS_SAFE_FUNCTION( //
|
||||
*buf = size_in_spiffs(filename); //
|
||||
*size_in_bytes = size_in_spiffs(filename); //
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -530,7 +532,7 @@ int rdv40_spiffs_is_symlink(const char *s) {
|
|||
// symlink ?")
|
||||
// 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) {
|
||||
int rdv40_spiffs_read_as_symlink(const char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level) {
|
||||
|
||||
RDV40_SPIFFS_SAFE_FUNCTION(
|
||||
char linkdest[SPIFFS_OBJ_NAME_LEN];
|
||||
|
@ -538,7 +540,7 @@ int rdv40_spiffs_read_as_symlink(char *filename, uint8_t *dst, uint32_t size, RD
|
|||
sprintf(linkfilename, "%s.lnk", filename);
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
Dbprintf("Linkk real filename is " _YELLOW_("%s"), linkfilename);
|
||||
Dbprintf("Link real filename is " _YELLOW_("%s"), linkfilename);
|
||||
|
||||
read_from_spiffs((char *)linkfilename, (uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN);
|
||||
|
||||
|
@ -561,11 +563,11 @@ int rdv40_spiffs_read_as_symlink(char *filename, uint8_t *dst, uint32_t size, RD
|
|||
// which you can then read back with :
|
||||
// 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) {
|
||||
int rdv40_spiffs_make_symlink(const char *linkdest, const char *filename, RDV40SpiFFSSafetyLevel level) {
|
||||
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(linkfilename, (const uint8_t *)linkdest, SPIFFS_OBJ_NAME_LEN);
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -575,15 +577,15 @@ int rdv40_spiffs_make_symlink(char *linkdest, char *filename, RDV40SpiFFSSafetyL
|
|||
// Still, this case won't happen when the write(s) functions will check for both symlink and real file
|
||||
// preexistence, 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) {
|
||||
int rdv40_spiffs_read_as_filetype(const char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level) {
|
||||
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);
|
||||
rdv40_spiffs_read(filename, dst, size, level);
|
||||
break;
|
||||
case RDV40_SPIFFS_FILETYPE_SYMLINK:
|
||||
rdv40_spiffs_read_as_symlink(filename, (uint8_t *)dst, size, level);
|
||||
rdv40_spiffs_read_as_symlink(filename, dst, size, level);
|
||||
break;
|
||||
case RDV40_SPIFFS_FILETYPE_BOTH:
|
||||
case RDV40_SPIFFS_FILETYPE_UNKNOWN:
|
||||
|
|
|
@ -46,18 +46,18 @@ typedef struct rdv40_spiffs_fsinfo {
|
|||
uint32_t usedPercent, freePercent;
|
||||
} rdv40_spiffs_fsinfo;
|
||||
|
||||
int rdv40_spiffs_read_as_filetype(char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_read_as_filetype(const char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level);
|
||||
|
||||
int rdv40_spiffs_check(void);
|
||||
int rdv40_spiffs_lazy_unmount(void);
|
||||
int rdv40_spiffs_lazy_mount(void);
|
||||
int rdv40_spiffs_lazy_mount_rollback(int changed);
|
||||
int rdv40_spiffs_write(const char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_write(const char *filename, const uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_read(const char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_rename(char *old_filename, char *new_filename, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_remove(char *filename, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_read_as_symlink(char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level);
|
||||
void write_to_spiffs(const char *filename, uint8_t *src, uint32_t size);
|
||||
int rdv40_spiffs_rename(const char *old_filename, const char *new_filename, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_remove(const char *filename, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_read_as_symlink(const char *filename, uint8_t *dst, uint32_t size, RDV40SpiFFSSafetyLevel level);
|
||||
void write_to_spiffs(const char *filename, const uint8_t *src, uint32_t size);
|
||||
void read_from_spiffs(const char *filename, uint8_t *dst, uint32_t size);
|
||||
void test_spiffs(void);
|
||||
void rdv40_spiffs_safe_print_tree(void);
|
||||
|
@ -65,11 +65,11 @@ int rdv40_spiffs_unmount(void);
|
|||
int rdv40_spiffs_mount(void);
|
||||
int rdv40_spiffs_is_symlink(const char *s);
|
||||
void rdv40_spiffs_safe_print_fsinfo(void);
|
||||
int rdv40_spiffs_make_symlink(char *linkdest, char *filename, RDV40SpiFFSSafetyLevel level);
|
||||
void append_to_spiffs(const char *filename, uint8_t *src, uint32_t size);
|
||||
int rdv40_spiffs_copy(char *src, char *dst, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_append(const char *filename, uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_stat(char *filename, uint32_t *buf, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_make_symlink(const char *linkdest, const char *filename, RDV40SpiFFSSafetyLevel level);
|
||||
void append_to_spiffs(const char *filename, const uint8_t *src, uint32_t size);
|
||||
int rdv40_spiffs_copy(const char *src_filename, const char *dst_filename, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_append(const char *filename, const uint8_t *src, uint32_t size, RDV40SpiFFSSafetyLevel level);
|
||||
int rdv40_spiffs_stat(const char *filename, uint32_t *size_in_bytes, RDV40SpiFFSSafetyLevel level);
|
||||
uint32_t size_in_spiffs(const char *filename);
|
||||
int exists_in_spiffs(const char *filename);
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ static int EmSendCmdThinfilmRaw(const uint8_t *resp, uint16_t respLen) {
|
|||
}
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
b = (uint8_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
(void)b;
|
||||
}
|
||||
if (BUTTON_PRESS()) break;
|
||||
|
@ -121,13 +121,12 @@ static int EmSendCmdThinfilmRaw(const uint8_t *resp, uint16_t respLen) {
|
|||
}
|
||||
|
||||
void SimulateThinFilm(uint8_t *data, size_t len) {
|
||||
Dbprintf("Simulate %i-bit Thinfilm tag", len * 8);
|
||||
Dbhexdump(len, data, true);
|
||||
int16_t status = PM3_SUCCESS;
|
||||
CodeThinfilmAsTag(data, len);
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
|
||||
|
||||
Dbprintf("Simulate " _YELLOW_("%i-bit Thinfilm") " tag", len * 8);
|
||||
Dbhexdump(len, data, true);
|
||||
|
||||
// Set up the synchronous serial port
|
||||
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER);
|
||||
|
||||
|
@ -136,29 +135,38 @@ void SimulateThinFilm(uint8_t *data, size_t len) {
|
|||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);
|
||||
SpinDelay(100);
|
||||
// Start the timer
|
||||
StartCountSspClk();
|
||||
|
||||
uint16_t hf_baseline = ReadReaderField();
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
int16_t status = PM3_SUCCESS;
|
||||
CodeThinfilmAsTag(data, len);
|
||||
|
||||
// Start the timer
|
||||
StartCountSspClk();
|
||||
tosend_t *ts = get_tosend();
|
||||
|
||||
bool reader_detected = false;
|
||||
LED_A_ON();
|
||||
for (;;) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
status = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t hf_av = ReadReaderField();
|
||||
if (hf_av < hf_baseline)
|
||||
|
||||
if (hf_av < hf_baseline) {
|
||||
hf_baseline = hf_av;
|
||||
}
|
||||
|
||||
if (hf_av > hf_baseline + 10) {
|
||||
|
||||
EmSendCmdThinfilmRaw(ts->buf, ts->max);
|
||||
if (!reader_detected) {
|
||||
|
||||
if (reader_detected == false) {
|
||||
LED_B_ON();
|
||||
//Dbprintf("Reader detected, start beaming data");
|
||||
reader_detected = true;
|
||||
|
@ -166,7 +174,7 @@ void SimulateThinFilm(uint8_t *data, size_t len) {
|
|||
} else {
|
||||
if (reader_detected) {
|
||||
LED_B_OFF();
|
||||
//Dbprintf("Reader gone, stop beaming data");
|
||||
// Dbprintf("Reader gone, stop beaming data");
|
||||
reader_detected = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,34 @@
|
|||
#include "usart.h"
|
||||
#include "proxmark3_arm.h"
|
||||
|
||||
#define Dbprintf_usb(...) {\
|
||||
bool tmpfpc = g_reply_via_fpc;\
|
||||
bool tmpusb = g_reply_via_usb;\
|
||||
g_reply_via_fpc = false;\
|
||||
g_reply_via_usb = true;\
|
||||
Dbprintf(__VA_ARGS__);\
|
||||
g_reply_via_fpc = tmpfpc;\
|
||||
g_reply_via_usb = tmpusb;}
|
||||
|
||||
#define Dbprintf_fpc(...) {\
|
||||
bool tmpfpc = g_reply_via_fpc;\
|
||||
bool tmpusb = g_reply_via_usb;\
|
||||
g_reply_via_fpc = true;\
|
||||
g_reply_via_usb = false;\
|
||||
Dbprintf(__VA_ARGS__);\
|
||||
g_reply_via_fpc = tmpfpc;\
|
||||
g_reply_via_usb = tmpusb;}
|
||||
|
||||
#define Dbprintf_all(...) {\
|
||||
bool tmpfpc = g_reply_via_fpc;\
|
||||
bool tmpusb = g_reply_via_usb;\
|
||||
g_reply_via_fpc = true;\
|
||||
g_reply_via_usb = true;\
|
||||
Dbprintf(__VA_ARGS__);\
|
||||
g_reply_via_fpc = tmpfpc;\
|
||||
g_reply_via_usb = tmpusb;}
|
||||
|
||||
|
||||
static volatile AT91PS_USART pUS1 = AT91C_BASE_US1;
|
||||
static volatile AT91PS_PIO pPIO = AT91C_BASE_PIOA;
|
||||
static volatile AT91PS_PDC pPDC = AT91C_BASE_PDC_US1;
|
||||
|
@ -46,8 +74,8 @@ void usart_close(void) {
|
|||
}
|
||||
*/
|
||||
|
||||
static uint8_t us_inbuf1[USART_BUFFLEN];
|
||||
static uint8_t us_inbuf2[USART_BUFFLEN];
|
||||
static uint8_t us_in_a[USART_BUFFLEN];
|
||||
static uint8_t us_in_b[USART_BUFFLEN];
|
||||
static uint8_t *usart_cur_inbuf = NULL;
|
||||
static uint16_t usart_cur_inbuf_off = 0;
|
||||
static uint8_t us_rxfifo[USART_FIFOLEN];
|
||||
|
@ -56,7 +84,9 @@ static size_t us_rxfifo_high = 0;
|
|||
|
||||
|
||||
static void usart_fill_rxfifo(void) {
|
||||
uint16_t rxfifo_free ;
|
||||
|
||||
uint16_t rxfifo_free = 0;
|
||||
|
||||
if (pUS1->US_RNCR == 0) { // One buffer got filled, backup buffer being used
|
||||
|
||||
if (us_rxfifo_low > us_rxfifo_high)
|
||||
|
@ -79,20 +109,23 @@ static void usart_fill_rxfifo(void) {
|
|||
pUS1->US_RNCR = USART_BUFFLEN;
|
||||
|
||||
// Swap current buff
|
||||
if (usart_cur_inbuf == us_inbuf1)
|
||||
usart_cur_inbuf = us_inbuf2;
|
||||
if (usart_cur_inbuf == us_in_a)
|
||||
usart_cur_inbuf = us_in_b;
|
||||
else
|
||||
usart_cur_inbuf = us_inbuf1;
|
||||
usart_cur_inbuf = us_in_a;
|
||||
|
||||
usart_cur_inbuf_off = 0;
|
||||
} else {
|
||||
// Take only what we have room for
|
||||
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))
|
||||
|
||||
if (us_rxfifo_high == sizeof(us_rxfifo)) {
|
||||
us_rxfifo_high = 0;
|
||||
}
|
||||
}
|
||||
usart_cur_inbuf_off += available;
|
||||
return;
|
||||
}
|
||||
|
@ -101,19 +134,21 @@ static void usart_fill_rxfifo(void) {
|
|||
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;
|
||||
rxfifo_free = (us_rxfifo_low - us_rxfifo_high);
|
||||
else
|
||||
rxfifo_free = sizeof(us_rxfifo) - us_rxfifo_high + us_rxfifo_low;
|
||||
rxfifo_free = (sizeof(us_rxfifo) - us_rxfifo_high + us_rxfifo_low);
|
||||
|
||||
uint16_t available = USART_BUFFLEN - pUS1->US_RCR - usart_cur_inbuf_off;
|
||||
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++) {
|
||||
us_rxfifo[us_rxfifo_high++] = usart_cur_inbuf[usart_cur_inbuf_off + i];
|
||||
if (us_rxfifo_high == sizeof(us_rxfifo))
|
||||
if (us_rxfifo_high == sizeof(us_rxfifo)) {
|
||||
us_rxfifo_high = 0;
|
||||
}
|
||||
}
|
||||
usart_cur_inbuf_off += available;
|
||||
}
|
||||
}
|
||||
|
@ -121,9 +156,9 @@ static void usart_fill_rxfifo(void) {
|
|||
uint16_t usart_rxdata_available(void) {
|
||||
usart_fill_rxfifo();
|
||||
if (us_rxfifo_low <= us_rxfifo_high)
|
||||
return us_rxfifo_high - us_rxfifo_low;
|
||||
return (us_rxfifo_high - us_rxfifo_low);
|
||||
else
|
||||
return sizeof(us_rxfifo) - us_rxfifo_low + us_rxfifo_high;
|
||||
return (sizeof(us_rxfifo) - us_rxfifo_low + us_rxfifo_high);
|
||||
}
|
||||
|
||||
uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
||||
|
@ -143,9 +178,10 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
|||
uint32_t maxtry = 10 * (3000000 / USART_BAUD_RATE) + tryconstant;
|
||||
|
||||
while (len) {
|
||||
uint32_t available = usart_rxdata_available();
|
||||
|
||||
uint32_t available = usart_rxdata_available();
|
||||
uint32_t packetSize = MIN(available, len);
|
||||
|
||||
if (available > 0) {
|
||||
// Dbprintf_usb("Dbg USART ask %d bytes, available %d bytes, packetsize %d bytes", len, available, packetSize);
|
||||
// highest_observed_try = MAX(highest_observed_try, try);
|
||||
|
@ -153,8 +189,9 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
|||
}
|
||||
len -= packetSize;
|
||||
while (packetSize--) {
|
||||
if (us_rxfifo_low == sizeof(us_rxfifo))
|
||||
if (us_rxfifo_low == sizeof(us_rxfifo)) {
|
||||
us_rxfifo_low = 0;
|
||||
}
|
||||
data[bytes_rcv++] = us_rxfifo[us_rxfifo_low++];
|
||||
}
|
||||
if (try++ == maxtry) {
|
||||
|
@ -183,10 +220,13 @@ int usart_writebuffer_sync(uint8_t *data, size_t len) {
|
|||
|
||||
void usart_init(uint32_t baudrate, uint8_t parity) {
|
||||
|
||||
if (baudrate != 0)
|
||||
if (baudrate != 0) {
|
||||
g_usart_baudrate = baudrate;
|
||||
if ((parity == 'N') || (parity == 'O') || (parity == 'E'))
|
||||
}
|
||||
|
||||
if ((parity == 'N') || (parity == 'O') || (parity == 'E')) {
|
||||
g_usart_parity = parity;
|
||||
}
|
||||
|
||||
// For a nice detailed sample, interrupt driven but still relevant.
|
||||
// See https://www.sparkfun.com/datasheets/DevTools/SAM7/at91sam7%20serial%20communications.pdf
|
||||
|
@ -262,11 +302,11 @@ void usart_init(uint32_t baudrate, uint8_t parity) {
|
|||
pUS1->US_TCR = 0;
|
||||
pUS1->US_TNPR = (uint32_t)0;
|
||||
pUS1->US_TNCR = 0;
|
||||
pUS1->US_RPR = (uint32_t)us_inbuf1;
|
||||
pUS1->US_RPR = (uint32_t)us_in_a;
|
||||
pUS1->US_RCR = USART_BUFFLEN;
|
||||
usart_cur_inbuf = us_inbuf1;
|
||||
usart_cur_inbuf = us_in_a;
|
||||
usart_cur_inbuf_off = 0;
|
||||
pUS1->US_RNPR = (uint32_t)us_inbuf2;
|
||||
pUS1->US_RNPR = (uint32_t)us_in_b;
|
||||
pUS1->US_RNCR = USART_BUFFLEN;
|
||||
|
||||
// Initialize our fifo
|
||||
|
|
|
@ -268,8 +268,9 @@ int BUTTON_HELD(int ms) {
|
|||
int ticks = (48000 * (ms ? ms : 1000)) >> 10;
|
||||
|
||||
// If we're not even pressed, forget about it!
|
||||
if (BUTTON_PRESS() == false)
|
||||
if (BUTTON_PRESS() == false) {
|
||||
return BUTTON_NO_CLICK;
|
||||
}
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
|
@ -284,12 +285,14 @@ int BUTTON_HELD(int ms) {
|
|||
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
|
||||
// As soon as our button let go, we didn't hold long enough
|
||||
if (BUTTON_PRESS() == false)
|
||||
if (BUTTON_PRESS() == false) {
|
||||
return BUTTON_SINGLE_CLICK;
|
||||
}
|
||||
|
||||
// Have we waited the full second?
|
||||
else if (now == (uint16_t)(start + ticks))
|
||||
else if (now == (uint16_t)(start + ticks)) {
|
||||
return BUTTON_HOLD;
|
||||
}
|
||||
|
||||
WDT_HIT();
|
||||
}
|
||||
|
@ -298,6 +301,8 @@ int BUTTON_HELD(int ms) {
|
|||
return BUTTON_ERROR;
|
||||
}
|
||||
|
||||
// This function returns false if no data is available or
|
||||
// the USB connection is invalid.
|
||||
bool data_available(void) {
|
||||
#ifdef WITH_FPC_USART_HOST
|
||||
return usb_poll_validate_length() || (usart_rxdata_available() > 0);
|
||||
|
@ -305,3 +310,14 @@ bool data_available(void) {
|
|||
return usb_poll_validate_length();
|
||||
#endif
|
||||
}
|
||||
|
||||
// This function doesn't check if the USB connection is valid.
|
||||
// In most of the cases, you should use data_available() unless
|
||||
// the timing is critical.
|
||||
bool data_available_fast(void) {
|
||||
#ifdef WITH_FPC_USART_HOST
|
||||
return usb_available_length() || (usart_rxdata_available() > 0);
|
||||
#else
|
||||
return usb_available_length();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -101,5 +101,6 @@ void SpinUp(uint32_t speed);
|
|||
int BUTTON_CLICKED(int ms);
|
||||
int BUTTON_HELD(int ms);
|
||||
bool data_available(void);
|
||||
bool data_available_fast(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -53,10 +53,10 @@ INSTALLFW = $(OBJDIR)/bootrom.elf
|
|||
|
||||
OBJS = $(OBJDIR)/bootrom.s19
|
||||
|
||||
# version_pm3.c should be remade on every compilation
|
||||
# version_pm3.c should be checked on every compilation
|
||||
version_pm3.c: default_version_pm3.c .FORCE
|
||||
$(info [=] GEN $@)
|
||||
$(Q)$(SH) ../tools/mkversion.sh > $@ || $(PERL) ../tools/mkversion.pl > $@ || $(CP) $< $@
|
||||
$(info [=] CHECK $@)
|
||||
$(Q)$(SH) ../tools/mkversion.sh $@ || $(CP) $< $@
|
||||
|
||||
all: showinfo $(OBJS)
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
common_area_t g_common_area __attribute__((section(".commonarea")));
|
||||
uint32_t start_addr, end_addr;
|
||||
bool bootrom_unlocked;
|
||||
extern uint32_t _bootrom_start[], _bootrom_end[], _flash_start[], _flash_end[], _osimage_entry[];
|
||||
extern uint32_t _bootrom_start[], _bootrom_end[], _flash_start[], _flash_end[], _osimage_entry[], __bss_start__[], __bss_end__[];
|
||||
|
||||
static int reply_old(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len) {
|
||||
PacketResponseOLD txcmd;
|
||||
|
@ -212,6 +212,12 @@ static void UsbPacketReceived(uint8_t *packet) {
|
|||
reply_old(CMD_ACK, arg0, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
// delay_loop(1) = 3.07us
|
||||
static volatile uint32_t c;
|
||||
static void __attribute__((optimize("O0"))) delay_loop(uint32_t delay) {
|
||||
for (c = delay * 2; c; c--) {};
|
||||
}
|
||||
|
||||
static void flash_mode(void) {
|
||||
start_addr = 0;
|
||||
end_addr = 0;
|
||||
|
@ -234,7 +240,7 @@ static void flash_mode(void) {
|
|||
usb_enable();
|
||||
|
||||
// wait for reset to be complete?
|
||||
for (volatile size_t i = 0; i < 0x100000; i++) {};
|
||||
delay_loop(100000);
|
||||
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
@ -246,10 +252,17 @@ static void flash_mode(void) {
|
|||
}
|
||||
}
|
||||
|
||||
if (g_common_area.flags.button_pressed && BUTTON_PRESS() == false) {
|
||||
bool button_state = BUTTON_PRESS();
|
||||
// ~10ms, prevent jitter
|
||||
delay_loop(3333);
|
||||
if (button_state != BUTTON_PRESS()) {
|
||||
// in jitter state, ignore
|
||||
continue;
|
||||
}
|
||||
if (g_common_area.flags.button_pressed && button_state == false) {
|
||||
g_common_area.flags.button_pressed = 0;
|
||||
}
|
||||
if (!g_common_area.flags.button_pressed && BUTTON_PRESS()) {
|
||||
if (!g_common_area.flags.button_pressed && button_state) {
|
||||
/* Perform a reset to leave flash mode */
|
||||
g_common_area.flags.button_pressed = 1;
|
||||
usb_disable();
|
||||
|
@ -262,6 +275,10 @@ static void flash_mode(void) {
|
|||
|
||||
void BootROM(void);
|
||||
void BootROM(void) {
|
||||
/* Set up (that is: clear) BSS. */
|
||||
uint32_t *bss_dst = __bss_start__;
|
||||
while (bss_dst < __bss_end__) *bss_dst++ = 0;
|
||||
|
||||
//------------
|
||||
// First set up all the I/O pins; GPIOs configured directly, other ones
|
||||
// just need to be assigned to the appropriate peripheral.
|
||||
|
|
|
@ -96,11 +96,13 @@ if (CMAKE_TOOLCHAIN_FILE)
|
|||
endif (ANDROID)
|
||||
set(EMBED_READLINE ON)
|
||||
set(EMBED_BZIP2 ON)
|
||||
set(EMBED_LZ4 ON)
|
||||
set(EMBED_GD ON)
|
||||
endif (CMAKE_TOOLCHAIN_FILE)
|
||||
|
||||
if (EMBED_READLINE OR EMBED_BZIP2)
|
||||
if (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4 OR EMBED_GD)
|
||||
include(ExternalProject)
|
||||
endif (EMBED_READLINE OR EMBED_BZIP2)
|
||||
endif (EMBED_READLINE OR EMBED_BZIP2 OR EMBED_LZ4 OR EMBED_GD)
|
||||
|
||||
if (NOT SKIPREADLINE EQUAL 1)
|
||||
if (APPLE)
|
||||
|
@ -162,6 +164,7 @@ if (NOT SKIPJANSSONSYSTEM EQUAL 1)
|
|||
endif (NOT SKIPJANSSONSYSTEM EQUAL 1)
|
||||
|
||||
if(EMBED_BZIP2)
|
||||
cmake_policy(SET CMP0114 NEW)
|
||||
set(BZIP2_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/bzip2/src/bzip2)
|
||||
# Specify SOURCE_DIR will cause some errors
|
||||
ExternalProject_Add(bzip2
|
||||
|
@ -183,6 +186,55 @@ else(EMBED_BZIP2)
|
|||
find_package (BZip2 REQUIRED)
|
||||
endif(EMBED_BZIP2)
|
||||
|
||||
if(EMBED_LZ4)
|
||||
cmake_policy(SET CMP0114 NEW)
|
||||
set(LZ4_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/lz4/src/lz4)
|
||||
# Specify SOURCE_DIR will cause some errors
|
||||
ExternalProject_Add(lz4
|
||||
GIT_REPOSITORY https://android.googlesource.com/platform/external/lz4
|
||||
GIT_TAG platform-tools-30.0.2
|
||||
PREFIX deps/lz4
|
||||
# SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/lz4
|
||||
CONFIGURE_COMMAND mkdir -p ${LZ4_BUILD_DIR} && git archive --format tar HEAD | tar -C ${LZ4_BUILD_DIR} -x
|
||||
BUILD_IN_SOURCE ON
|
||||
BUILD_COMMAND make -C ${LZ4_BUILD_DIR}/lib -j4 CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} liblz4.a
|
||||
INSTALL_COMMAND ""
|
||||
LOG_DOWNLOAD ON
|
||||
)
|
||||
ExternalProject_Add_StepTargets(lz4 configure build install)
|
||||
set(LZ4_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR}/deps/lz4/src/lz4/lib)
|
||||
set(LZ4_LIBRARIES ${CMAKE_CURRENT_BINARY_DIR}/deps/lz4/src/lz4/lib/liblz4.a)
|
||||
set(LZ4_FOUND ON)
|
||||
else(EMBED_LZ4)
|
||||
find_path(LZ4_INCLUDE_DIRS lz4frame.h)
|
||||
find_library(LZ4_LIBRARIES lz4)
|
||||
endif(EMBED_LZ4)
|
||||
|
||||
if (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
|
||||
set(LZ4_FOUND ON)
|
||||
endif (LZ4_INCLUDE_DIRS AND LZ4_LIBRARIES)
|
||||
|
||||
if (NOT SKIPGD EQUAL 1)
|
||||
if (EMBED_GD)
|
||||
cmake_policy(SET CMP0114 NEW)
|
||||
set(GD_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}/deps/gd)
|
||||
# Specify SOURCE_DIR will cause some errors
|
||||
ExternalProject_Add(gd
|
||||
URL https://github.com/libgd/libgd/releases/download/gd-2.3.3/libgd-2.3.3.tar.gz
|
||||
URL_HASH SHA256=dd3f1f0bb016edcc0b2d082e8229c822ad1d02223511997c80461481759b1ed2
|
||||
PREFIX deps/gd
|
||||
CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DBUILD_STATIC_LIBS=ON -DENABLE_CPP=0 -DCMAKE_INSTALL_PREFIX=.
|
||||
PATCH_COMMAND cat ${CMAKE_CURRENT_SOURCE_DIR}/deps/gd-static.patch | patch -p1
|
||||
)
|
||||
ExternalProject_Add_StepTargets(gd configure build install)
|
||||
set(GD_INCLUDE_DIRS ${GD_BUILD_DIR}/src/gd-build/include)
|
||||
set(GD_LIBRARIES ${GD_BUILD_DIR}/src/gd-build/lib/libgd.a)
|
||||
set(GD_FOUND ON)
|
||||
else (EMBED_GD)
|
||||
pkg_search_module(GD QUIET gdlib)
|
||||
endif (EMBED_GD)
|
||||
endif (NOT SKIPGD EQUAL 1)
|
||||
|
||||
if (NOT SKIPWHEREAMISYSTEM EQUAL 1)
|
||||
find_path(WHEREAMI_INCLUDE_DIRS whereami.h)
|
||||
find_library(WHEREAMI_LIBRARIES whereami)
|
||||
|
@ -249,6 +301,7 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/mifare/mifare4.c
|
||||
${PM3_ROOT}/client/src/mifare/mifaredefault.c
|
||||
${PM3_ROOT}/client/src/mifare/mifarehost.c
|
||||
${PM3_ROOT}/client/src/mifare/gen4.c
|
||||
${PM3_ROOT}/client/src/nfc/ndef.c
|
||||
${PM3_ROOT}/client/src/mifare/lrpcrypto.c
|
||||
${PM3_ROOT}/client/src/mifare/desfirecrypto.c
|
||||
|
@ -256,6 +309,8 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/mifare/desfirecore.c
|
||||
${PM3_ROOT}/client/src/mifare/desfiretest.c
|
||||
${PM3_ROOT}/client/src/mifare/gallaghercore.c
|
||||
${PM3_ROOT}/client/src/uart/ringbuffer.c
|
||||
${PM3_ROOT}/client/src/uart/uart_common.c
|
||||
${PM3_ROOT}/client/src/uart/uart_posix.c
|
||||
${PM3_ROOT}/client/src/uart/uart_win32.c
|
||||
${PM3_ROOT}/client/src/ui/overlays.ui
|
||||
|
@ -298,7 +353,7 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdhftexkom.c
|
||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||
${PM3_ROOT}/client/src/cmdhfvas.c
|
||||
${PM3_ROOT}/client/src/cmdhfxerox.c
|
||||
${PM3_ROOT}/client/src/cmdhw.c
|
||||
${PM3_ROOT}/client/src/cmdlf.c
|
||||
|
@ -348,6 +403,7 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/fileutils.c
|
||||
${PM3_ROOT}/client/src/flash.c
|
||||
${PM3_ROOT}/client/src/graph.c
|
||||
${PM3_ROOT}/client/src/iso4217.c
|
||||
${PM3_ROOT}/client/src/jansson_path.c
|
||||
${PM3_ROOT}/client/src/preferences.c
|
||||
${PM3_ROOT}/client/src/pm3.c
|
||||
|
@ -365,7 +421,7 @@ set (TARGET_SOURCES
|
|||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_BINARY_DIR}/version_pm3.c
|
||||
COMMAND sh ${PM3_ROOT}/tools/mkversion.sh > ${CMAKE_BINARY_DIR}/version_pm3.c || ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c
|
||||
COMMAND sh ${PM3_ROOT}/tools/mkversion.sh ${CMAKE_BINARY_DIR}/version_pm3.c || ${CMAKE_COMMAND} -E copy ${PM3_ROOT}/common/default_version_pm3.c ${CMAKE_BINARY_DIR}/version_pm3.c
|
||||
DEPENDS ${PM3_ROOT}/common/default_version_pm3.c
|
||||
)
|
||||
|
||||
|
@ -380,7 +436,23 @@ message(STATUS "CMAKE_SYSTEM_PROCESSOR := ${CMAKE_SYSTEM_PROCESSOR}")
|
|||
if (APPLE)
|
||||
message(STATUS "Apple device detected.")
|
||||
set(ADDITIONAL_SRC ${PM3_ROOT}/client/src/util_darwin.h ${PM3_ROOT}/client/src/util_darwin.m ${ADDITIONAL_SRC})
|
||||
|
||||
find_library(UIKIT_LIBRARY UIKit)
|
||||
if (NOT UIKIT_LIBRARY)
|
||||
message(STATUS "UIKit.framework NOT found!")
|
||||
else()
|
||||
message(STATUS "UIKit.framework found! ${UIKIT_LIBRARY}")
|
||||
set(ADDITIONAL_LNK "-framework Foundation" "-framework UIKit")
|
||||
endif()
|
||||
|
||||
find_library(APPKIT_LIBRARY AppKit)
|
||||
if (NOT APPKIT_LIBRARY)
|
||||
message(STATUS "AppKit.framework NOT found!")
|
||||
else()
|
||||
message(STATUS "AppKit.framework found! ${APPKIT_LIBRARY}")
|
||||
set(ADDITIONAL_LNK "-framework Foundation" "-framework AppKit")
|
||||
endif()
|
||||
|
||||
endif (APPLE)
|
||||
|
||||
if ((NOT SKIPQT EQUAL 1) AND (Qt5_FOUND))
|
||||
|
@ -439,6 +511,22 @@ if (BZIP2_FOUND)
|
|||
set(ADDITIONAL_LNK ${BZIP2_LIBRARIES} ${ADDITIONAL_LNK})
|
||||
endif (BZIP2_FOUND)
|
||||
|
||||
if (LZ4_FOUND)
|
||||
set(ADDITIONAL_DIRS ${LZ4_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
|
||||
set(ADDITIONAL_LNK ${LZ4_LIBRARIES} ${ADDITIONAL_LNK})
|
||||
endif (LZ4_FOUND)
|
||||
|
||||
if (NOT SKIPGD EQUAL 1 AND GD_FOUND)
|
||||
set(ADDITIONAL_DIRS ${GD_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
|
||||
set(ADDITIONAL_LNK ${GD_LIBRARIES} ${ADDITIONAL_LNK})
|
||||
set(ADDITIONAL_LNKDIRS ${GD_LIBRARY_DIRS} ${ADDITIONAL_LNKDIRS})
|
||||
set(TARGET_SOURCES
|
||||
${PM3_ROOT}/client/src/imgutils.c
|
||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||
${TARGET_SOURCES})
|
||||
add_definitions("-DHAVE_GD")
|
||||
endif (NOT SKIPGD EQUAL 1 AND GD_FOUND)
|
||||
|
||||
if (WHEREAMI_FOUND)
|
||||
set(ADDITIONAL_DIRS ${WHEREAMI_INCLUDE_DIRS} ${ADDITIONAL_DIRS})
|
||||
set(ADDITIONAL_LNK ${WHEREAMI_LIBRARIES} ${ADDITIONAL_LNK})
|
||||
|
@ -471,11 +559,37 @@ else (SKIPBT EQUAL 1)
|
|||
endif (BLUEZ_FOUND)
|
||||
endif(SKIPBT EQUAL 1)
|
||||
|
||||
if (EMBED_BZIP2)
|
||||
if (BZIP2_FOUND)
|
||||
if (EMBED_BZIP2)
|
||||
message(STATUS "Bzip2 library: embedded")
|
||||
else (EMBED_BZIP2)
|
||||
else (EMBED_BZIP2)
|
||||
message(STATUS "Bzip2 library: system library found")
|
||||
endif (EMBED_BZIP2)
|
||||
endif (EMBED_BZIP2)
|
||||
else (BZIP2_FOUND)
|
||||
message(SEND_ERROR "Bzip2 library: Bzip2 not found")
|
||||
endif (BZIP2_FOUND)
|
||||
|
||||
if (LZ4_FOUND)
|
||||
if (EMBED_LZ4)
|
||||
message(STATUS "LZ4 library: embedded")
|
||||
else (EMBED_LZ4)
|
||||
message(STATUS "LZ4 library: system library found")
|
||||
endif (EMBED_LZ4)
|
||||
else (LZ4_FOUND)
|
||||
message(SEND_ERROR "LZ4 library: LZ4 not found")
|
||||
endif (LZ4_FOUND)
|
||||
|
||||
if (SKIPGD EQUAL 1)
|
||||
message(STATUS "GD library: skipped")
|
||||
elseif (GD_FOUND)
|
||||
if (EMBED_GD)
|
||||
message(STATUS "GD library: embedded")
|
||||
else (EMBED_GD)
|
||||
message(STATUS "GD library: system library found")
|
||||
endif (EMBED_GD)
|
||||
else (SKIPGD EQUAL 1)
|
||||
message(STATUS "GD library: GD not found, disabled")
|
||||
endif (SKIPGD EQUAL 1)
|
||||
|
||||
if (SKIPJANSSONSYSTEM EQUAL 1)
|
||||
message(STATUS "Jansson library: local library forced")
|
||||
|
@ -575,6 +689,9 @@ endif (EMBED_READLINE)
|
|||
if (EMBED_BZIP2)
|
||||
add_dependencies(proxmark3 bzip2)
|
||||
endif (EMBED_BZIP2)
|
||||
if (EMBED_LZ4)
|
||||
add_dependencies(proxmark3 lz4)
|
||||
endif (EMBED_LZ4)
|
||||
|
||||
if (MINGW)
|
||||
# Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z)
|
||||
|
@ -586,20 +703,20 @@ if (MINGW)
|
|||
set(CMAKE_C_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "-mno-ms-bitfields -fexec-charset=cp850 ${CMAKE_CXX_FLAGS}")
|
||||
|
||||
# GCC 10 has issues with false positives on stringop-overflow,
|
||||
# let's disable them for now (cf https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92955, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335)
|
||||
# beware these flags didn't exist for GCC < 7
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
# link Winsock2
|
||||
set(ADDITIONAL_LNK ws2_32 ${ADDITIONAL_LNK})
|
||||
endif (MINGW)
|
||||
|
||||
# GCC 10 has issues with false positives on stringop-overflow,
|
||||
# let's disable them for now (cf https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92955, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335)
|
||||
# beware these flags didn't exist for GCC < 7
|
||||
if(CMAKE_COMPILER_IS_GNUCXX)
|
||||
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
|
||||
if (GCC_VERSION VERSION_GREATER 10.0 OR GCC_VERSION VERSION_EQUAL 10.0)
|
||||
set(CMAKE_C_FLAGS "-Wno-stringop-overflow -Wno-error=stringop-overflow ${CMAKE_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "-Wno-stringop-overflow -Wno-error=stringop-overflow ${CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
# link Winsock2
|
||||
set(ADDITIONAL_LNK ws2_32 ${ADDITIONAL_LNK})
|
||||
endif (MINGW)
|
||||
endif(CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
||||
target_include_directories(proxmark3 PRIVATE
|
||||
${PM3_ROOT}/common
|
||||
|
@ -648,14 +765,14 @@ endif (NOT SKIPPTHREAD EQUAL 1)
|
|||
if (NOT SKIPPYTHON EQUAL 1)
|
||||
# OSX have a hard time compiling python3 dependency with older cmake.
|
||||
if (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
||||
if (NOT CMAKE_VERSION VERSION_LESS 3.13)
|
||||
target_link_directories(proxmark3 PRIVATE ${ADDITIONAL_LNKDIRS})
|
||||
elseif (APPLE)
|
||||
if (CMAKE_VERSION VERSION_LESS 3.13)
|
||||
message( SEND_ERROR "Your CMAKE version is too old for Apple platform, please update to a version >=3.13" )
|
||||
endif (NOT CMAKE_VERSION VERSION_LESS 3.13)
|
||||
endif (CMAKE_VERSION VERSION_LESS 3.13)
|
||||
endif (PYTHON3EMBED_FOUND OR PYTHON3_FOUND)
|
||||
endif (NOT SKIPPYTHON EQUAL 1)
|
||||
|
||||
target_link_directories(proxmark3 PRIVATE ${ADDITIONAL_LNKDIRS})
|
||||
|
||||
install(TARGETS proxmark3 DESTINATION "bin")
|
||||
install(DIRECTORY cmdscripts lualibs luascripts pyscripts resources dictionaries DESTINATION "share/proxmark3")
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue