mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 22:03:42 -07:00
commit
d8984626db
273 changed files with 29981 additions and 9303 deletions
14
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
14
.github/ISSUE_TEMPLATE/checklist-for-release.md
vendored
|
@ -22,14 +22,14 @@ assignees: doegox, iceman1001
|
|||
# OS compilation and tests
|
||||
|
||||
```bash
|
||||
make clean && make -j PLATFORM=PM3OTHER && tools/pm3test.sh
|
||||
make clean && make -j PLATFORM=PM3RDV4 && tools/pm3test.sh
|
||||
make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && tools/pm3test.sh
|
||||
make install; pushd /tmp; proxmark3 -c 'data load em4x05.pm3;lf search 1'; popd; make uninstall
|
||||
make clean && make -j PLATFORM=PM3OTHER && tools/pm3_tests.sh
|
||||
make clean && make -j PLATFORM=PM3RDV4 && tools/pm3_tests.sh
|
||||
make clean && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && tools/pm3_tests.sh
|
||||
make install; pushd /tmp; proxmark3 -c 'data load -f em4x05.pm3;lf search 1'; popd; make uninstall
|
||||
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3OTHER && PM3BIN=./proxmark3 ../../tools/pm3test.sh client )
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 && PM3BIN=./proxmark3 ../../tools/pm3test.sh client )
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && PM3BIN=./proxmark3 ../../tools/pm3test.sh client )
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3OTHER && PM3BIN=./proxmark3 ../../tools/pm3_tests.sh client )
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 && PM3BIN=./proxmark3 ../../tools/pm3_tests.sh client )
|
||||
( cd client; rm -rf build; mkdir build;cd build;cmake .. && make -j PLATFORM=PM3RDV4 PLATFORM_EXTRAS=BTADDON && PM3BIN=./proxmark3 ../../tools/pm3_tests.sh client )
|
||||
```
|
||||
|
||||
- [ ] RPI Zero
|
||||
|
|
133
.github/workflows/macos.yml
vendored
Normal file
133
.github/workflows/macos.yml
vendored
Normal file
|
@ -0,0 +1,133 @@
|
|||
name: MacOS Build and Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
macos-make:
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set Git http.postBuffer to something high
|
||||
run: git config --global http.postBuffer 524288000
|
||||
|
||||
- name: Handle homebrew quirks
|
||||
run: rm -rf /usr/local/bin/2to3
|
||||
|
||||
- name: Update brew repos
|
||||
run: brew update
|
||||
continue-on-error: true
|
||||
|
||||
- name: Tap RfidResearchGroup/proxmark3
|
||||
run: brew tap RfidResearchGroup/proxmark3
|
||||
|
||||
- name: Install dependencies
|
||||
run: brew install readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
V: 1
|
||||
run: make
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
macos-make-btaddon:
|
||||
if: always()
|
||||
needs: [macos-make]
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set Git http.postBuffer to something high
|
||||
run: git config --global http.postBuffer 524288000
|
||||
|
||||
- name: Handle homebrew quirks
|
||||
run: rm -rf /usr/local/bin/2to3
|
||||
|
||||
- name: Update brew repos
|
||||
run: brew update
|
||||
continue-on-error: true
|
||||
|
||||
- name: Tap RfidResearchGroup/proxmark3
|
||||
run: brew tap RfidResearchGroup/proxmark3
|
||||
|
||||
- name: Install dependencies
|
||||
run: brew install readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
V: 1
|
||||
PLATFORM_EXTRAS: BTADDON
|
||||
run: make
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
macos-cmake:
|
||||
if: always()
|
||||
needs: [macos-make, macos-make-btaddon]
|
||||
runs-on: macos-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Set Git http.postBuffer to something high
|
||||
run: git config --global http.postBuffer 524288000
|
||||
|
||||
- name: Handle homebrew quirks
|
||||
run: rm -rf /usr/local/bin/2to3
|
||||
|
||||
- name: Update brew repos
|
||||
run: brew update
|
||||
continue-on-error: true
|
||||
|
||||
- name: Tap RfidResearchGroup/proxmark3
|
||||
run: brew tap RfidResearchGroup/proxmark3
|
||||
|
||||
- name: Install dependencies
|
||||
run: brew install readline qt5 RfidResearchGroup/proxmark3/arm-none-eabi-gcc
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
|
||||
- name: Prepare Build Folders
|
||||
run: mkdir -p client/build
|
||||
|
||||
- name: Initiate cmake environment
|
||||
run: cmake ..
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
VERBOSE: 1
|
||||
run: make
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
CHECKARGS: "--clientbin ./client/build/proxmark3"
|
||||
run: make client/check
|
106
.github/workflows/ubuntu.yml
vendored
Normal file
106
.github/workflows/ubuntu.yml
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
name: Ubuntu Build and Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
ubuntu-make:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Update apt repos
|
||||
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-dbg liblua5.2-0 lua5.2 sed
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools
|
||||
python3 -m pip install ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
V: 1
|
||||
run: make
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
ubuntu-make-btaddon:
|
||||
if: always()
|
||||
needs: [ubuntu-make]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Update apt repos
|
||||
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-dbg liblua5.2-0 lua5.2 sed
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools
|
||||
python3 -m pip install ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
V: 1
|
||||
PLATFORM_EXTRAS: BTADDON
|
||||
run: make
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
ubuntu-cmake:
|
||||
if: always()
|
||||
needs: [ubuntu-make, ubuntu-make-btaddon]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: Update apt repos
|
||||
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-dbg liblua5.2-0 lua5.2 sed
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools
|
||||
python3 -m pip install ansicolors sslcrypto
|
||||
if [ -f requirements.txt ]; then python3 -m pip install -r requirements.txt; fi
|
||||
|
||||
- name: Prepare Build Folders
|
||||
run: mkdir -p client/build
|
||||
|
||||
- name: Initiate cmake environment
|
||||
run: cmake ..
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Build
|
||||
env:
|
||||
VERBOSE: 1
|
||||
run: make
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
CHECKARGS: "--clientbin ./client/build/proxmark3"
|
||||
run: make client/check
|
152
.github/workflows/windows.yml
vendored
Normal file
152
.github/workflows/windows.yml
vendored
Normal file
|
@ -0,0 +1,152 @@
|
|||
name: Windows Build and Test
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
proxspace:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: pwsh
|
||||
env:
|
||||
PATH: C:/ProxSpace/msys2/mingw64/bin;C:/ProxSpace/msys2/usr/local/bin;C:/ProxSpace/msys2/usr/bin;C:/ProxSpace/msys2/bin
|
||||
MSYSTEM: MINGW64
|
||||
|
||||
steps:
|
||||
- name: ProxSpace download
|
||||
run: Invoke-WebRequest "https://github.com/Gator96100/ProxSpace/archive/master.zip" -outfile "C:\proxspace.zip" -Passthru
|
||||
|
||||
- name: ProxSpace extract
|
||||
run: Expand-Archive -LiteralPath "C:\proxspace.zip" -DestinationPath "C:\"
|
||||
|
||||
- name: ProxSpace delete zip
|
||||
run: Remove-Item "C:\proxspace.zip"
|
||||
|
||||
- name: ProxSpace rename folder
|
||||
run: Get-ChildItem -Path "C:\ProxSpace-*" | Rename-Item -NewName (Split-Path C:\ProxSpace -Leaf)
|
||||
|
||||
- name: ProxSpace version
|
||||
run: |
|
||||
$psversion = (Select-String -Pattern 'PSVERSION=' -SimpleMatch -Path "C:\ProxSpace\msys2\ps\09-proxspace_setup.post").Line.Split("""")[1]
|
||||
Write-Host "ProxSpace version: $psversion"
|
||||
|
||||
- name: ProxSpace initial startup
|
||||
working-directory: C:\ProxSpace
|
||||
run: ./runme64.bat -c "exit"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Build
|
||||
run: make V=1
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Build btaddon
|
||||
run: make V=1 PLATFORM_EXTRAS=BTADDON
|
||||
|
||||
- name: Test btaddon
|
||||
run: make check
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Prepare cmake build folders
|
||||
run: mkdir -p client/build
|
||||
|
||||
- name: Initiate cmake environment
|
||||
run: cmake -G"MSYS Makefiles" ..
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Build cmake
|
||||
run: make VERBOSE=1
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Test cmake
|
||||
run: make client/check CHECKARGS="--clientbin ./client/build/proxmark3"
|
||||
|
||||
wsl:
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: wsl-bash {0}
|
||||
|
||||
steps:
|
||||
- name: WSL setup
|
||||
uses: Vampire/setup-wsl@v1
|
||||
with:
|
||||
distribution: Ubuntu-20.04
|
||||
update: "true"
|
||||
additional-packages: git
|
||||
ca-certificates
|
||||
build-essential
|
||||
pkg-config
|
||||
libreadline-dev
|
||||
gcc-arm-none-eabi
|
||||
libnewlib-dev
|
||||
libbz2-dev
|
||||
qtbase5-dev
|
||||
cmake
|
||||
libpython3-dev
|
||||
python3
|
||||
python3-pip
|
||||
python3-dev
|
||||
libpython3-all-dev
|
||||
|
||||
- name: Install Python dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
python3 -m pip install setuptools
|
||||
python3 -m pip install ansicolors sslcrypto
|
||||
|
||||
- name: WSL QT fix
|
||||
run: sudo strip --remove-section=.note.ABI-tag /usr/lib/x86_64-linux-gnu/libQt5Core.so.5
|
||||
|
||||
- name: Set git to use LF
|
||||
shell: bash
|
||||
run: |
|
||||
git config --global core.autocrlf false
|
||||
git config --global core.eol lf
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Build
|
||||
run: make V=1
|
||||
|
||||
- name: Test
|
||||
run: make check
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Build btaddon
|
||||
run: make V=1 PLATFORM_EXTRAS=BTADDON
|
||||
|
||||
- name: Test btaddon
|
||||
run: make check
|
||||
|
||||
- name: make clean
|
||||
run: make clean
|
||||
|
||||
- name: Prepare cmake build folders
|
||||
run: mkdir -p client/build
|
||||
|
||||
- name: Initiate cmake environment
|
||||
run: cmake ..
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Build cmake
|
||||
run: make VERBOSE=1
|
||||
working-directory: client/build/
|
||||
|
||||
- name: Test cmake
|
||||
run: make client/check CHECKARGS="--clientbin ./client/build/proxmark3"
|
13
.gitignore
vendored
13
.gitignore
vendored
|
@ -33,6 +33,7 @@ version.c
|
|||
*.json.bak
|
||||
*.pyc
|
||||
*.bmp
|
||||
originalitysig.csv
|
||||
|
||||
# new build file for add-ons.
|
||||
Makefile.platform
|
||||
|
@ -71,6 +72,7 @@ tools/cryptorf/cm
|
|||
tools/cryptorf/sm
|
||||
tools/cryptorf/sma
|
||||
tools/cryptorf/sma_multi
|
||||
tools/mf_nonce_brute/mf_nonce_brute
|
||||
|
||||
fpga/*
|
||||
!fpga/tests
|
||||
|
@ -93,18 +95,21 @@ client/traces/*
|
|||
client/dumps/*
|
||||
*.ice
|
||||
*.new
|
||||
tools/mf_nonce_brute/mf_nonce_brute
|
||||
tools/andrew/*
|
||||
tools/jtag_openocd/openocd_configuration
|
||||
ppls patches/*
|
||||
*- Copy.*
|
||||
/EF_*
|
||||
|
||||
client/lualibs/mfc_default_keys.lua
|
||||
client/lualibs/pm3_cmd.lua
|
||||
# recompiled
|
||||
fpga_version_info.c
|
||||
|
||||
# log / history
|
||||
.proxmark3/*
|
||||
|
||||
# .tmp files are created during compilation
|
||||
*.tmp
|
||||
|
||||
# VSCode files
|
||||
!.vscode/templates/*.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/tasks.json
|
||||
|
|
10
.vscode/extensions.json
vendored
Normal file
10
.vscode/extensions.json
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
// See https://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"ms-vscode.cpptools",
|
||||
"austin.code-gnu-global",
|
||||
"marus25.cortex-debug",
|
||||
"augustocdias.tasks-shell-input"
|
||||
]
|
||||
}
|
145
.vscode/setup.sh
vendored
Executable file
145
.vscode/setup.sh
vendored
Executable file
|
@ -0,0 +1,145 @@
|
|||
#!/bin/bash
|
||||
###############################
|
||||
# Linux #
|
||||
# Uncomment to override #
|
||||
###############################
|
||||
#export SerialPort="/dev/ttyACM0"
|
||||
#export DebuggerPath="/usr/bin/gdb"
|
||||
#export JLinkServerPath="/opt/SEGGER/JLink/JLinkGDBServerCLExe"
|
||||
|
||||
###############################
|
||||
# WSL #
|
||||
# Uncomment to override #
|
||||
###############################
|
||||
#export SerialPort="/dev/ttyS4"
|
||||
#export DebuggerPath="/usr/bin/gdb"
|
||||
#export JLinkServerPath="/mnt/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe"
|
||||
|
||||
###############################
|
||||
# ProxSpace #
|
||||
# Uncomment to override #
|
||||
###############################
|
||||
#export SerialPort="COM5"
|
||||
#export JLinkServerPath="C:/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe"
|
||||
|
||||
#Debugging on 256KB systems is not recommended
|
||||
#This option does not override PLATFORM_SIZE
|
||||
export DeviceMem="512"
|
||||
|
||||
|
||||
VSCODEPATH=$(dirname "$0")
|
||||
|
||||
function print_config {
|
||||
echo "Updating with following configuration:"
|
||||
echo "SerialPort: $SerialPort"
|
||||
echo "DebuggerPath: $DebuggerPath"
|
||||
echo "JLinkServerPath: $JLinkServerPath"
|
||||
}
|
||||
|
||||
function setup_serial_port {
|
||||
if [ -z "$SerialPort" ]; then
|
||||
pm3list=$($VSCODEPATH/../pm3 --list 2>/dev/null)
|
||||
#Use first port listed
|
||||
export SerialPort=$(echo $pm3list | head -n 1 | cut -c 4-)
|
||||
if [ -z "$SerialPort" ]; then
|
||||
echo >&2 "[!!] No serial port found, please set SerialPort manually"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function setup_gdb_linux {
|
||||
if [ -z "$DebuggerPath" ]; then
|
||||
export DebuggerPath="/usr/bin/gdb"
|
||||
fi
|
||||
if [ ! -x "$DebuggerPath" ]; then
|
||||
echo >&2 "[!!] gdb not found, please set DebuggerPath manually"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function setup_jlink_linux {
|
||||
if [ -z "$JLinkServerPath" ]; then
|
||||
export JLinkServerPath="/opt/SEGGER/JLink/JLinkGDBServerCLExe"
|
||||
fi
|
||||
if [ ! -x "$JLinkServerPath" ]; then
|
||||
echo >&2 "[!!] JLinkGDBServerCLExe not found, please set JLinkServerPath manually"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function setup_jlink_wsl {
|
||||
if [ -z "$JLinkServerPath" ]; then
|
||||
export JLinkServerPath="/mnt/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe"
|
||||
fi
|
||||
if [ ! -x "$JLinkServerPath" ]; then
|
||||
echo >&2 "[!!] JLinkGDBServerCL.exe not found, please set JLinkServerPath manually"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function setup_jlink_ps {
|
||||
if [ -z "$JLinkServerPath" ]; then
|
||||
export JLinkServerPath="c:/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe"
|
||||
fi
|
||||
jlinkpath=$(cygpath "$JLinkServerPath")
|
||||
if [ ! -x "$jlinkpath" ]; then
|
||||
echo >&2 "[!!] JLinkGDBServerCL.exe not found, please set JLinkServerPath manually"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function setup_wsl {
|
||||
setup_serial_port
|
||||
setup_gdb_linux
|
||||
setup_jlink_wsl
|
||||
print_config
|
||||
envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_wsl.json" > "$VSCODEPATH/launch.json"
|
||||
}
|
||||
|
||||
function setup_linux {
|
||||
setup_serial_port
|
||||
setup_gdb_linux
|
||||
setup_jlink_linux
|
||||
print_config
|
||||
envsubst '${SerialPort} ${DebuggerPath} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_linux.json" > "$VSCODEPATH/launch.json"
|
||||
}
|
||||
|
||||
function setup_ps {
|
||||
setup_serial_port
|
||||
setup_jlink_ps
|
||||
export DebuggerPath="Using ProxSpace gbd"
|
||||
print_config
|
||||
envsubst '${SerialPort} ${JLinkServerPath} ${DeviceMem}' <"$VSCODEPATH/templates/launch_ps.json" > "$VSCODEPATH/launch.json"
|
||||
}
|
||||
|
||||
if [ -f "$VSCODEPATH/launch.json" ]; then
|
||||
read -p "Existing configuration found, do you want to override it? " -n 1 -r
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
rm "$VSCODEPATH/launch.json.bak" 2> /dev/null
|
||||
mv "$VSCODEPATH/launch.json" "$VSCODEPATH/launch.json.bak" 2> /dev/null
|
||||
else
|
||||
echo >&2 "[!!] user abort"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
HOSTOS=$(uname | awk '{print toupper($0)}')
|
||||
if [ "$HOSTOS" = "LINUX" ]; then
|
||||
if uname -a|grep -q Microsoft; then
|
||||
setup_wsl
|
||||
else
|
||||
setup_linux
|
||||
fi
|
||||
elif [ "$HOSTOS" = "DARWIN" ]; then
|
||||
echo >&2 "[!!] MacOS not supported, sorry!"
|
||||
exit 1
|
||||
elif [[ "$HOSTOS" =~ MINGW(32|64)_NT* ]]; then
|
||||
setup_ps
|
||||
else
|
||||
echo >&2 "[!!] Host OS not recognized, abort: $HOSTOS"
|
||||
exit 1
|
||||
fi
|
101
.vscode/tasks.json
vendored
101
.vscode/tasks.json
vendored
|
@ -2,23 +2,20 @@
|
|||
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||
// for the documentation about the tasks.json format
|
||||
"version": "2.0.0",
|
||||
"windows": {
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {
|
||||
"PATH": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin",
|
||||
"MSYSTEM": "MINGW64"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tasks": [
|
||||
{
|
||||
"label": "all: Make & run",
|
||||
"type": "shell",
|
||||
"command": "make -j && ./pm3",
|
||||
"windows": {
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../..",
|
||||
"shell": {
|
||||
"executable": "${workspaceFolder}/../../runme64.bat",
|
||||
"args": [
|
||||
"-c \"cd ${workspaceFolderBasename} &&"
|
||||
],
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
|
@ -31,18 +28,6 @@
|
|||
"label": "choose: Make",
|
||||
"type": "shell",
|
||||
"command": "make ${input:componentType} -j",
|
||||
"windows": {
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../..",
|
||||
"shell": {
|
||||
"executable": "${workspaceFolder}/../../runme64.bat",
|
||||
"args": [
|
||||
"-c \"cd ${workspaceFolderBasename} &&"
|
||||
],
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
|
@ -52,18 +37,6 @@
|
|||
"label": "client: Debug: make",
|
||||
"type": "shell",
|
||||
"command": "make client -j DEBUG=1",
|
||||
"windows": {
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../..",
|
||||
"shell": {
|
||||
"executable": "${workspaceFolder}/../../runme64.bat",
|
||||
"args": [
|
||||
"-c \"cd ${workspaceFolderBasename} &&"
|
||||
],
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
|
@ -73,18 +46,6 @@
|
|||
"label": "client: Debug: clean & make",
|
||||
"type": "shell",
|
||||
"command": "make client/clean && make client -j DEBUG=1",
|
||||
"windows": {
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../..",
|
||||
"shell": {
|
||||
"executable": "${workspaceFolder}/../../runme64.bat",
|
||||
"args": [
|
||||
"-c \"cd ${workspaceFolderBasename} &&"
|
||||
],
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
|
@ -94,55 +55,27 @@
|
|||
"label": "fullimage: Make & Flash",
|
||||
"type": "shell",
|
||||
"command": "make fullimage && ./pm3-flash-fullimage",
|
||||
"windows": {
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../..",
|
||||
"shell": {
|
||||
"executable": "${workspaceFolder}/../../runme64.bat",
|
||||
"args": [
|
||||
"-c \"cd ${workspaceFolderBasename} &&"
|
||||
],
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "BOOTROM: Make & Flash",
|
||||
"type": "shell",
|
||||
"command": "make bootrom && ./pm3-flash-bootrom",
|
||||
"windows": {
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../..",
|
||||
"shell": {
|
||||
"executable": "${workspaceFolder}/../../runme64.bat",
|
||||
"args": [
|
||||
"-c \"cd ${workspaceFolderBasename} &&"
|
||||
],
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
{
|
||||
"label": "Run client",
|
||||
"type": "shell",
|
||||
"command": "./pm3",
|
||||
"windows": {
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}/../..",
|
||||
"shell": {
|
||||
"executable": "${workspaceFolder}/../../runme64.bat",
|
||||
"args": [
|
||||
"-c \"cd ${workspaceFolderBasename} &&"
|
||||
],
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
"problemMatcher": []
|
||||
},{
|
||||
"label": "fullimage: clean & make debug",
|
||||
"type": "shell",
|
||||
"command": "make armsrc/clean && make armsrc/all DEBUG_ARM=1",
|
||||
"problemMatcher": [
|
||||
"$gcc"
|
||||
],
|
||||
"group": "build",
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
|
|
|
@ -5,34 +5,11 @@
|
|||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "(gdb) Attach",
|
||||
"type": "cppdbg",
|
||||
"request": "attach",
|
||||
"program": "${cwd}/client/proxmark3",
|
||||
//"processId": "${command:pickProcess}",
|
||||
"processId": "${input:ProcessID}",
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"windows": {
|
||||
"processId": "${input:ProcessIDWindows}",
|
||||
"miDebuggerPath": "${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe",
|
||||
"externalConsole": true,//for ProxSpace externalConsole=true is required, because the internal cosole stops updating after a while
|
||||
"environment": [{
|
||||
"name": "PATH","value": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin"
|
||||
}]
|
||||
}
|
||||
},{
|
||||
"name": "(gdb) Build & Launch",
|
||||
"name": "Client: (gdb) Build & Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${cwd}/client/proxmark3",
|
||||
"args": ["/dev/ttyACM0"],
|
||||
"args": ["${SerialPort}"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
|
@ -46,15 +23,36 @@
|
|||
}
|
||||
],
|
||||
"preLaunchTask": "client: Debug: clean & make",
|
||||
"miDebuggerPath": "/usr/bin/gdb",
|
||||
"windows": {
|
||||
"args": ["COM5"],
|
||||
"miDebuggerPath": "${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe",
|
||||
"externalConsole": true,//for ProxSpace externalConsole=true is required, because the internal cosole stops updating after a while
|
||||
"environment": [{
|
||||
"name": "PATH","value": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin"
|
||||
}]
|
||||
"miDebuggerPath": "${DebuggerPath}"
|
||||
},{
|
||||
"name": "Client: (gdb) Attach",
|
||||
"type": "cppdbg",
|
||||
"request": "attach",
|
||||
"program": "${cwd}/client/proxmark3",
|
||||
//"processId": "${command:pickProcess}",
|
||||
"processId": "${input:ProcessID}",
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},{
|
||||
"name": "Firmware: (J-Link) Build & Launch",
|
||||
"type": "cortex-debug",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "fullimage: clean & make debug",
|
||||
"executable": "${workspaceRoot}/armsrc/obj/fullimage.elf",
|
||||
"serverpath": "${JLinkServerPath}",
|
||||
"servertype": "jlink",
|
||||
"device": "AT91SAM7S${DeviceMem}",
|
||||
"interface": "jtag",
|
||||
"serialNumber": "", //If you have more than one J-Link probe, add the serial number here.
|
||||
"runToMain": false,
|
||||
"armToolchainPath": "/usr/bin/"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
|
@ -67,14 +65,6 @@
|
|||
"command": "pgrep -n proxmark3",
|
||||
}
|
||||
|
||||
},{
|
||||
"id": "ProcessIDWindows",
|
||||
"type": "command",
|
||||
"command": "shellCommand.execute",
|
||||
"args": {
|
||||
"command": "${workspaceFolder}/../../runme64.bat -c \"cat /proc/$(pgrep -n proxmark3)/winpid\"",
|
||||
}
|
||||
|
||||
}
|
||||
]
|
||||
}
|
49
.vscode/templates/launch_ps.json
vendored
Normal file
49
.vscode/templates/launch_ps.json
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"options": {
|
||||
"cwd": "${workspaceFolder}",
|
||||
"env": {
|
||||
"PATH": "${workspaceFolder}/../../msys2/mingw64/bin;${workspaceFolder}/../../msys2/usr/local/bin;${workspaceFolder}/../../msys2/usr/bin;${workspaceFolder}/../../msys2/bin",
|
||||
"MSYSTEM": "MINGW64"
|
||||
}
|
||||
},
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Client: (gdb) Build & Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"program": "${cwd}/client/proxmark3",
|
||||
"args": ["${SerialPort}"],
|
||||
"stopAtEntry": false,
|
||||
"externalConsole": true,//for ProxSpace externalConsole=true is required, because the internal cosole stops updating after a while
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "client: Debug: clean & make",
|
||||
"miDebuggerPath": "${workspaceFolder}/../../msys2/mingw64/bin/gdb.exe"
|
||||
},{
|
||||
"name": "Firmware: (J-Link) Build & Launch",
|
||||
"type": "cortex-debug",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "fullimage: clean & make debug",
|
||||
"executable": "${workspaceRoot}/armsrc/obj/fullimage.elf",
|
||||
"serverpath": "${JLinkServerPath}",
|
||||
"servertype": "jlink",
|
||||
"device": "AT91SAM7S${DeviceMem}",
|
||||
"interface": "jtag",
|
||||
"serialNumber": "", //If you have more than one J-Link probe, add the serial number here.
|
||||
"runToMain": false,
|
||||
"armToolchainPath": "${workspaceFolder}/../../msys2/mingw64/bin"
|
||||
}
|
||||
]
|
||||
}
|
70
.vscode/templates/launch_wsl.json
vendored
Normal file
70
.vscode/templates/launch_wsl.json
vendored
Normal file
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Client: (gdb) Build & Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
"program": "${cwd}/client/proxmark3",
|
||||
"args": ["${SerialPort}"],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
],
|
||||
"preLaunchTask": "client: Debug: clean & make",
|
||||
"miDebuggerPath": "${DebuggerPath}"
|
||||
},{
|
||||
"name": "Client: (gdb) Attach",
|
||||
"type": "cppdbg",
|
||||
"request": "attach",
|
||||
"program": "${cwd}/client/proxmark3",
|
||||
//"processId": "${command:pickProcess}",
|
||||
"processId": "${input:ProcessID}",
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},{
|
||||
"name": "Firmware: (J-Link) Build & Launch",
|
||||
"type": "cortex-debug",
|
||||
"request": "launch",
|
||||
"cwd": "${workspaceRoot}",
|
||||
"preLaunchTask": "fullimage: clean & make debug",
|
||||
"executable": "${workspaceRoot}/armsrc/obj/fullimage.elf",
|
||||
"serverpath": "${JLinkServerPath}",
|
||||
"servertype": "jlink",
|
||||
"device": "AT91SAM7S${DeviceMem}",
|
||||
"interface": "jtag",
|
||||
"serialNumber": "", //If you have more than one J-Link probe, add the serial number here.
|
||||
"runToMain": false,
|
||||
"armToolchainPath": "/usr/bin/"
|
||||
}
|
||||
],
|
||||
"inputs": [
|
||||
{
|
||||
// Using Extension "Tasks Shell Input" https://marketplace.visualstudio.com/items?itemName=augustocdias.tasks-shell-input
|
||||
"id": "ProcessID",
|
||||
"type": "command",
|
||||
"command": "shellCommand.execute",
|
||||
"args": {
|
||||
"command": "pgrep -n proxmark3",
|
||||
}
|
||||
|
||||
}
|
||||
]
|
||||
}
|
76
CHANGELOG.md
76
CHANGELOG.md
|
@ -3,29 +3,67 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Added a script to dump originality signatures from MFU EV1s and NTAGs (@aveao)
|
||||
- Added parsing of EF_CardAccess to display PACE algorithm, version and parameter in `hf emrtd info` (@aveao)
|
||||
- Change, numerous commands more uses cliparser (@tcprst, @iceman1001)
|
||||
- Added more originality public keys (@anon)
|
||||
- Added `hf 14a info` - now also verify MFC Ev1 signatures (@iceman1001)
|
||||
- Added `LF_THAREXDE` standalone mode which simulates and reads EM4x50 cards (@tharexde)
|
||||
- Added `hf jooki` commands (@iceman1001)
|
||||
- Changed `lf hid clone` - also accepts binary wiegand (@iceman1001)
|
||||
- Changed `wiegand encode` - format param is now optional, w/o it will try encode all formats (@iceman1001)
|
||||
- Fix cppchecker warnings (@iceman1001)
|
||||
- Added `trace list -t mf` - now can use external dictionary keys file (@McEloff)
|
||||
- Fix `lf gallagher read` - now correctly decodes card data
|
||||
- Add support to `lf gallagher clone` and `lf gallagher sim` for writing specific card region, facility, card & issue numbers (@DarkMatterMatt)
|
||||
- Added support for older vid/pid detection (@Gator96100)
|
||||
- Added `hf mfdes bruteaid` - proper bruteforce of DESFire AID when no reading of files is possible (@craftbyte)
|
||||
- Added support for bidirectional communication for `lf em 4x50 sim` (@tharexde)
|
||||
- Change `PLATFORM=PM3OTHER` to `PLATFORM=PM3GENERIC` (@iceman1001)
|
||||
- Added `tools/hitag2crack/crack5opencl`, an optimized version of `crack5gpu` (@matrix)
|
||||
- Fixed Makefile to account for changes when running on Apple Silicon (@tcprst)
|
||||
- Added support for debugging ARM with JTAG & VSCode (@Gator96100)
|
||||
- Added MFUL "Gen1b" suport to `hf_mfu_setuid.lua` (@iceman1001)
|
||||
- Added possibility to get bargraph in `lf tune` and `hf tune` (@iceman1001, @doegox)
|
||||
- Added `hf emrtd` ePassport dumping and parsing (@aveao)
|
||||
- Added `aidsearch` to `hf 14b info` (@iceman1001)
|
||||
- Added `ICE_STATE_DUMP_SIM` - standalone mode for dumping/simming one iClass tag (@iconicsec)
|
||||
- Added `lf em 4x50 eview` - show uploaded EM4x50 data in emul memory (@tharexde)
|
||||
- Fix `data rawdemod` parsing for psk2 and user defined clock (@cyberpunk-re)
|
||||
- Added `hf iclass encode` - encode a wiegand binary to a encrypted credential (@iceman1001)
|
||||
- Changed `recoverpk.py` - now tests more ECDSA curves (@doegox)
|
||||
- Added `hf 14a apdufuzz`- a naive apdu cla/ins/p1p2/len fuzzer (@iceman1001)
|
||||
- Improved `hf 14a apdufuzz/apdufind` to find hidden APDUs (@ikarus23)
|
||||
- Fix mixed up INC/DEC in MIFARE protocol defs (@vortixdev)
|
||||
- Added `lf em 4x70 info` - new support for ID48 transponders (@cmolson)
|
||||
- Fix multiple coverity scan issues (@iceman1001)
|
||||
- Added a SIO item (@iceman1001)
|
||||
- Fix `lf hid brute` - param (@iceman1001)
|
||||
- Changed `lf em` layouts (@iceman1001)
|
||||
- Change many commands to cliparser (@iceman1001, @tcprst, ...)
|
||||
- Fix issue #844 - `lf t55xx config` => recompute block0 (@cyberpunk-re)
|
||||
- EM4x50: changed cli parameter from w (word) to d (data) (@tharexde)
|
||||
- EM4x50: new function 4x50 login: authenticate against tag (@tharexde)
|
||||
- EM4x50: new function 4x50 brute: guess password within a given password range (@tharexde)
|
||||
- EM4x50: new function 4x50 chk: try passwords from dictionary (without option -> T55xx default dictionary or -f user dictionary) (@tharexde)
|
||||
- EM4x50: new function 4x50 reader: read data from tag (configured data -> standard read mode), incl. option -@ (@tharexde)
|
||||
- EM4x50: new function 4x50 sim: simulate dump from file or emulator/flash (@tharexde)
|
||||
- EM4x50: new function 4x50 restore: restore dump file (bin, eml, json) onto tag (@tharexde)
|
||||
- EM4x50: new function 4x50 esave: dump em4x50 content in emulator memory to file (bin + eml + json) (@tharexde)
|
||||
- EM4x50: new function 4x50 eload: upload em4x50 file content (bin, eml, json) to emulator memory (@tharexde)
|
||||
- EM4x50: added LED signals (@tharexde)
|
||||
- EM4x50: added json format for 4x50 dump (@tharexde)
|
||||
- EM4x50: relocated write requests in function 4x50 wipe from device to client (@tharexde)
|
||||
- EM4x50: renamed 4x50_write_password to 4x50 writepwd (@tharexde)
|
||||
- EM4x50: all hex input parameters now have to be given in lsb format (output is still msb + lsb) (@tharexde)
|
||||
- EM4x50: changed cli parameter from a (address) to b (block) (@tharexde)
|
||||
- EM4x50: switched to cliparser for all functions (@tharexde)
|
||||
- EM4x50: stabilized and accelerated tag detection (@tharexde)
|
||||
- EM4x50: removed global tag structure on device side (@tharexde)
|
||||
- Change `lf em 4x50` - changed cli parameter from w (word) to d (data) (@tharexde)
|
||||
- Added `lf em 4x50 login` - authenticate against tag (@tharexde)
|
||||
- Added `lf em 4x50 brute` - guess password within a given password range (@tharexde)
|
||||
- Added `lf em 4x50 chk` - try passwords from dictionary (without option -> T55xx default dictionary or -f user dictionary) (@tharexde)
|
||||
- Added `lf em 4x50 reader` - read data from tag (configured data -> standard read mode), incl. option -@ (@tharexde)
|
||||
- Added `lf em 4x50 sim` - simulate dump from file or emulator/flash (@tharexde)
|
||||
- Added `lf em 4x50 restore` - restore dump file (bin, eml, json) onto tag (@tharexde)
|
||||
- Added `lf em 4x50 esave` - dump em4x50 content in emulator memory to file (bin + eml + json) (@tharexde)
|
||||
- Added `lf em 4x50 eload` - upload em4x50 file content (bin, eml, json) to emulator memory (@tharexde)
|
||||
- Changed EM4x50 - added LED signals (@tharexde)
|
||||
- Change `lf em 4x50 dump` - now support json format (@tharexde)
|
||||
- Change `lf em 4x50 wipe` - relocated write requests from device to client (@tharexde)
|
||||
- Renamed `lf em 4x50 write_passwordd` -> `writepwd` (@tharexde)
|
||||
- Change `lf em 4x50` - all hex input parameters now have to be given in lsb format (output is still msb + lsb) (@tharexde)
|
||||
- Change `lf em 4x50` - changed cli parameter from a (address) to b (block) (@tharexde)
|
||||
- Change `lf em 4x50` - now supports cliparser (@tharexde)
|
||||
- Change EM4x50 - stabilized and accelerated tag detection (@tharexde)
|
||||
- Change EM4x50 - removed global tag structure on device side (@tharexde)
|
||||
- Fix `hf 15 sim` - Added basic response to GET_SYSTEM_INFO and READBLOCK requests in order to fix iso15693 tag sim (@cyberpunk-re)
|
||||
- Added `mf mfu sim t 7 n <numreads>` - MFU emulation now supports automatic exit after <num> blocks read. (@cyberpunk-re)
|
||||
- Added T55xx Guide to assist in learning how to use the T55xx chip (@mwalker33)
|
||||
- Fix 'hf iclass wrbl' - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001)
|
||||
- Fix `hf iclass wrbl` - dealing with tags in unsecured vs secured pagemode now is correct (@iceman1001)
|
||||
- Change many commands to cliparser (@iceman1001, @tcprst, @mwalker33,...)
|
||||
- ...
|
||||
- Change `hf iclass chk/lookup/loclass` speedups (@iceman1001)
|
||||
|
|
4
Makefile
4
Makefile
|
@ -46,7 +46,7 @@ ifneq (,$(INSTALLTOOLS))
|
|||
endif
|
||||
ifneq (,$(INSTALLSIMFW))
|
||||
$(Q)$(MKDIR) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
|
||||
$(Q)$(CP) $(foreach fw,$(INSTALLSIMFW),tools/simmodule/$(fw)) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
|
||||
$(Q)$(CP) $(foreach fw,$(INSTALLSIMFW),client/resources/$(fw)) $(DESTDIR)$(PREFIX)$(PATHSEP)$(INSTALLFWRELPATH)
|
||||
endif
|
||||
ifeq ($(platform),Linux)
|
||||
$(Q)$(MKDIR) $(DESTDIR)$(UDEV_PREFIX)
|
||||
|
@ -169,7 +169,7 @@ help:
|
|||
@echo "+ fpga_compress - Make tools/fpga_compress"
|
||||
@echo
|
||||
@echo "+ style - Apply some automated source code formatting rules"
|
||||
@echo "+ cliparser - Generate cliparser TODO
|
||||
@echo "+ cliparser - Generate cliparser TODO"
|
||||
@echo "+ check - Run offline tests. Set CHECKARGS to pass arguments to the test script"
|
||||
@echo "+ .../check - Run offline tests against specific target. See above."
|
||||
@echo "+ miscchecks - Detect various encoding issues in source code"
|
||||
|
|
|
@ -57,6 +57,11 @@ else
|
|||
RANLIB= ranlib
|
||||
endif
|
||||
|
||||
# For detection of Apple Silicon
|
||||
ifeq ($(platform),Darwin)
|
||||
BREW_PREFIX = $(shell brew --prefix)
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG),1)
|
||||
DEFCXXFLAGS = -g -O0 -pipe
|
||||
DEFCFLAGS = -g -O0 -fstrict-aliasing -pipe
|
||||
|
@ -66,6 +71,11 @@ else
|
|||
DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe
|
||||
DEFLDFLAGS =
|
||||
endif
|
||||
|
||||
ifeq ($(DEBUG_ARM),1)
|
||||
APP_CFLAGS += -g
|
||||
SKIP_COMPRESSION=1
|
||||
endif
|
||||
# Next ones are activated only if SANITIZE=1
|
||||
ifeq ($(SANITIZE),1)
|
||||
DEFCFLAGS += -g -fsanitize=address -fno-omit-frame-pointer
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# Run 'make PLATFORM=' to get an exhaustive list of possible parameters for this file.
|
||||
|
||||
PLATFORM=PM3RDV4
|
||||
#PLATFORM=PM3OTHER
|
||||
#PLATFORM=PM3GENERIC
|
||||
# If you want more than one PLATFORM_EXTRAS option, separate them by spaces:
|
||||
#PLATFORM_EXTRAS=BTADDON
|
||||
#STANDALONE=HF_MSDSAL
|
||||
|
|
109
README.md
109
README.md
|
@ -1,15 +1,18 @@
|
|||
# RRG / Iceman repo - Proxmark3
|
||||
# RRG / Iceman - Proxmark3
|
||||
|
||||
|
||||
| Releases | Coverity | Contributors |
|
||||
| ------------------- | -------------------:| -------------------:|
|
||||
| [](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)|  |
|
||||
|
||||
|
||||
| Actions OSX CI | Actions Ubuntu CI | Windows CI |
|
||||
| ------------------- | -------------------:| -------------------:|
|
||||
|  |  | [](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) |
|
||||
|
||||
|
||||
|
||||
|
||||
| Releases | Linux & OSX CI | Windows CI | Coverity | Contributors |
|
||||
| ------------------- |:-------------------:| -------------------:| -------------------:| -------------------:|
|
||||
| [](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [](https://travis-ci.com/RfidResearchGroup/proxmark3) | [](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)|  |
|
||||
|
||||
|
||||
|
||||
# PROXMARK INSTALLATION AND OVERVIEW
|
||||
# PROXMARK3 INSTALLATION AND OVERVIEW
|
||||
|
||||
| FAQ's & Updates | Installation | Use of the Proxmark |
|
||||
| ------------------- |:-------------------:| -------------------:|
|
||||
|
@ -36,10 +39,25 @@
|
|||
|[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)||
|
||||
|
||||
## Build for non-RDV4 Proxmark3 platforms
|
||||
|
||||
In order to build this repo for other Proxmark3 platforms we urge you to read [Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)
|
||||
## Build for Proxmark3 RDV4
|
||||
See the instruction links in the tables above to build, flash and run for your Proxmark3 RDV4 device.
|
||||
|
||||
## Build for generic Proxmark3 platforms
|
||||
In order to build this repo for generic Proxmark3 platforms we urge you to read [Advanced compilation parameters](/doc/md/Use_of_Proxmark/4_Advanced-compilation-parameters.md)
|
||||
|
||||
With generic Proxmark3 platforms we mean:
|
||||
- RDV1
|
||||
- RDV2
|
||||
- RDV3 easy
|
||||
- Proxmark Evolution (needs extra care)
|
||||
- Radiowar black PCB version
|
||||
- Ryscorp green PCB version
|
||||
- Ryscorp Pm3Pro
|
||||
- VX
|
||||
- numerous Chinese adapted versions of the RDV3 easy (kkmoon, pisworks etc)
|
||||
|
||||
> ⚠ **Note**: About flash memory size of other Proxmark3 platforms. You need to keep a eye on how large your ARM chip built-in flash memory is. With 512kb you are fine but if its 256kb you need to compile this repo with even less functionality. When running the `./pm3-flash-all` you can see which size your device have if you have the bootloader from this repo installed. Otherwise you will find the size reported in the start message when running the Proxmark3 client `./pm3`.
|
||||
|
||||
## What has changed?
|
||||
|
||||
|
@ -49,7 +67,9 @@ On the hardware side:
|
|||
* added smart card module
|
||||
* added FPC connector
|
||||
|
||||
On the software side: quite a lot, see the [Changelog file](CHANGELOG.md).
|
||||
On the software side:
|
||||
|
||||
quite a lot, see the [Changelog file](CHANGELOG.md) which we try to keep updated.
|
||||
|
||||
## Development
|
||||
|
||||
|
@ -57,13 +77,13 @@ On the software side: quite a lot, see the [Changelog file](CHANGELOG.md).
|
|||
|
||||
This repo compiles nicely on
|
||||
- Proxspace v3.x
|
||||
- [latest release v3.7.1](https://github.com/Gator96100/ProxSpace/releases)
|
||||
- [latest release v3.8](https://github.com/Gator96100/ProxSpace/releases)
|
||||
- Windows/mingw environment with Qt5.6.1 & GCC 4.9
|
||||
- Ubuntu 16.04 -> 20.04
|
||||
- ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian
|
||||
- Rasbian
|
||||
- Android / Termux
|
||||
- Mac OS X / Homebrew
|
||||
- Mac OS X / Homebrew / Apple Silicon
|
||||
- WSL1 (Windows subsystem linux) on Windows 10
|
||||
- Docker container
|
||||
- [ RRG / Iceman repo based ubuntu 18.04 container ](https://hub.docker.com/r/secopsconsult/proxmark3)
|
||||
|
@ -72,26 +92,22 @@ This repo compiles nicely on
|
|||
Hardware to run client on
|
||||
- PC
|
||||
- Android
|
||||
- Raspberry Pi & Raspberry Pi Zero
|
||||
- Raspberry Pi, Raspberry Pi Zero
|
||||
- Nvidia Jetson Nano
|
||||
|
||||
## Precompiled binaries
|
||||
We don't maintain any precompiled binaries in this repo. There is community effort over at the Proxmark3 forum where @gator96100 has set up a google drive with many mingw binaries which is up-to-date. We link to these files here as to make it easier for users.
|
||||
If you are having troubles with these files, contact the package maintainer @gator96100 and read the [sticky thread at forum](http://www.proxmark.org/forum/viewtopic.php?pid=24763#p24763) where known issues has been documented.
|
||||
We don't maintain any precompiled binaries in this repo. There is community effort over at the Proxmark3 forum where [@gator96100](https://github.com/gator96100) has set up a AWS bucket with precompiled Proxspace (Mingw) binaries which is recompiled every night and with that also up-to-date. We link to these files here as to make it easier for users.
|
||||
|
||||
_If you use his pre-compiled Proxspace binaries do consider buy him a coffee for his efforts. Remember nothing says thank you as good as a donation._
|
||||
|
||||
Ref:
|
||||
For Proxmark3 RDV4
|
||||
- [Precompiled builds for RDV40 dedicated x86](https://drive.google.com/open?id=13zUs-aiQkYaSl5KWrBtuW5IWCoHJPsue)
|
||||
- [Precompiled builds for RDV40 dedicated x64](https://drive.google.com/open?id=1SyPB8t5Vo8O0Lh7PjNm3Kv-mO4BNbxjX)
|
||||
If you are having troubles with these files, contact the package maintainer [@gator96100](https://github.com/gator96100) and read the [homepage of his proxmark builds](https://www.proxmarkbuilds.org/) or read the [sticky thread at forum](http://www.proxmark.org/forum/viewtopic.php?pid=24763#p24763) where known issues has been documented with regards to the precompiled builds.
|
||||
|
||||
For Proxmark3 RDV4 with blueshark addon
|
||||
- [Precompiled builds for RDV40 dedicated with Bluetooth addon x86](https://drive.google.com/open?id=1TqWYctkRvkLshQ1ZRBHPLDzYHR-asuMO)
|
||||
- [Precompiled builds for RDV40 dedicated with Bluetooth addon x64](https://drive.google.com/open?id=17ful7u2QyYmMQzQzc5fAf8nJvyoDJfSL)
|
||||
### Proxmark3 RDV4 devices
|
||||
- [Precompiled builds for RDV40 dedicated x64](https://www.proxmarkbuilds.org/#rdv40-64/)
|
||||
- [Precompiled builds for RDV40 dedicated with Bluetooth addon x64](https://www.proxmarkbuilds.org/#rdv40_bt-64/)
|
||||
|
||||
Generice Proxmark3 devices (non RDV4), for Proxmark3 Easy, RDV1, RDV2, RDV3, etc etc
|
||||
- [Precompiled builds for RRG / Iceman repository x86](https://drive.google.com/open?id=1PI3Xr1mussPBPnYGu4ZjWzGPARK4N7JR)
|
||||
- [Precompiled builds for RRG / Iceman repository x64](https://drive.google.com/open?id=1uX9RtYGinuFrpHybu4xq_BE3HrobI20e)
|
||||
### Generic Proxmark3 devices
|
||||
- [Precompiled builds for RRG / Iceman repository x64](https://www.proxmarkbuilds.org/#rrg_other-64/)
|
||||
|
||||
|
||||
## Roadmap
|
||||
|
@ -103,28 +119,40 @@ We usually merge your contributions fast since we do like the idea of getting a
|
|||
|
||||
## Issues & Troubleshooting
|
||||
Please search the [issues](https://github.com/rfidresearchgroup/proxmark3/issues) page here and see if your issue is listed in the first instance.
|
||||
Read the [Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md) guide to weed out most known problems.
|
||||
Read the [Troubleshooting guide](/doc/md/Installation_Instructions/Troubleshooting.md) to weed out most known problems.
|
||||
|
||||
Next place to visit is the [Proxmark Forum](http://www.proxmark.org/forum/index.php). Learn to search it well and finally Google / duckduckgo is your friend :) You will find many blogposts, youtube videos, tweets, reddit
|
||||
Next place to visit is the [Proxmark3 Forum](http://www.proxmark.org/forum/index.php). Learn to search it well and finally Google / duckduckgo is your friend :)
|
||||
You will find many blogposts, youtube videos, tweets, reddit
|
||||
|
||||
### Offical channels
|
||||
- [RFID Hacking community discord server](https://discord.gg/QfPvGFRQxH)
|
||||
- [Proxmark3 IRC channel](http://webchat.freenode.net/?channels=#proxmark3)
|
||||
- [Proxmark3 sub reddit](https://www.reddit.com/r/proxmark3/)
|
||||
- [Twitter](https://twitter.com/proxmark3/)
|
||||
- [Proxmark3 community discord server](https://discord.gg/zjxc8ZB)
|
||||
- [Proxmark3 Twitter](https://twitter.com/proxmark3/)
|
||||
- [Proxmark3 forum](http://www.proxmark.org/forum/index.php)
|
||||
- _no slack channel_
|
||||
|
||||
_no slack channel_
|
||||
|
||||
Iceman has quite a few videos on his [youtube channel](https://www.youtube.com/c/ChrisHerrmann1001)
|
||||
### Youtube channels
|
||||
Iceman has quite a few videos on his channel and Quentyn has risen up the last year with good informative videos. We suggest you check them out and smash that subscribe buttons!
|
||||
|
||||
- [Iceman channel](https://www.youtube.com/c/ChrisHerrmann1001)
|
||||
- [Quentyn Taylor](https://www.youtube.com/channel/UCL91C3IZDv3wfj2ABhdRIrw)
|
||||
- [Hacker warehouse channel](https://www.youtube.com/channel/UCimS6P854cQ23j6c_xst7EQ)
|
||||
|
||||
_if you think of some more good youtube channels to be on this list, let us know!_
|
||||
|
||||
## Cheat sheet
|
||||
|
||||
Thanks to Alex Dibs, you can enjoy a [command cheat sheet](/doc/cheatsheet.md)
|
||||
You can enjoy a [command cheat sheet](/doc/cheatsheet.md) and we are trying to keep it updated.
|
||||
[Thanks to Alex Dib!](https://github.com/scund00r)
|
||||
|
||||
## Maintainers ( package, distro )
|
||||
|
||||
To all distro, package maintainers, we tried to make your life easier. `make install` is now available and if you want to know more.
|
||||
- [Maintainers](/doc/md/Development/Maintainers.md)
|
||||
To all distro, package maintainers, we tried to make your life easier.
|
||||
|
||||
`make install` is now available and if you want to know more.
|
||||
- [Notes for maintainers](/doc/md/Development/Maintainers.md)
|
||||
|
||||
## Why didn't you base it on official Proxmark3 Master?
|
||||
|
||||
|
@ -132,14 +160,9 @@ The separation from official Proxmark3 repo gives us a lot of freedom to create
|
|||
|
||||
## Proxmark3 GUI
|
||||
|
||||
The official PM3-GUI from Gaucho will not work.
|
||||
The new [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) will work more or less. Change is needed in order to show helptext when client isn't connected to a device. We don't know how active the maintainers.
|
||||
The official PM3-GUI from Gaucho will not work. Not to mention is quite old and not maintained any longer.
|
||||
|
||||
## The end
|
||||
|
||||
- July 2018 [@herrmann1001](https://mobile.twitter.com/herrmann1001)
|
||||
- updated Feb 2019 [@5w0rdfish](https://mobile.twitter.com/5w0rdFish)
|
||||
- updated 2019 [@doegox](https://mobile.twitter.com/doegox)
|
||||
The new [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) will work more or less. Change is needed in order to show helptext when client isn't connected to a device. We don't know how active the maintainers are. There has been brought to our attention that there is quite a few Chinese Windows GUI available. Usually you find them on alibaba / taobao ads but we have no idea which fw/client they are compatible with. Proceed with caution if you decide to go down that road.
|
||||
|
||||
# Donations
|
||||
|
||||
|
|
|
@ -64,8 +64,12 @@ clone_script:
|
|||
WSLExec "WSL update..." "sudo apt-get update 1>/dev/null"
|
||||
WSLExec "WSL upgrade..." "sudo apt-get upgrade -y 1>/dev/null"
|
||||
WSLExec "WSL cleanup..." "sudo apt-get auto-remove -y 1>/dev/null"
|
||||
WSLExec "WSL install..." "sudo apt-get -y install --reinstall --no-install-recommends git ca-certificates build-essential pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev qtbase5-dev cmake 1>/dev/null"
|
||||
WSLExec "WSL install..." "sudo apt-get -y install --reinstall --no-install-recommends git ca-certificates build-essential pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev qtbase5-dev cmake libpython3-dev python3 python3-pip python3-dev libpython3-all-dev 1>/dev/null"
|
||||
WSLExec "WSL QT fix..." "sudo strip --remove-section=.note.ABI-tag /usr/lib/x86_64-linux-gnu/libQt5Core.so.5"
|
||||
WSLExec "WSL install python dependencies..." "sudo python3 -m pip install --upgrade pip 1>/dev/null"
|
||||
WSLExec "WSL install pip..." "sudo python3 -m pip install setuptools 1>/dev/null"
|
||||
WSLExec "WSL install pip continue..." "sudo python3 -m pip install ansicolors sslcrypto 1>/dev/null"
|
||||
|
||||
Add-AppveyorMessage -Message "WSL setup took $(([System.Environment]::TickCount-$WSLInstallTime) / 1000) sec" -Category Information
|
||||
New-Item -ItemType "file" -Path "C:\WSL-Finished.txt" -Force | Out-Null
|
||||
}
|
||||
|
|
|
@ -217,8 +217,12 @@ $(OBJDIR)/fullimage.data.o: $(OBJDIR)/fullimage.data.bin.z
|
|||
$(Q)$(OBJCOPY) -O elf32-littlearm -I binary -B arm --rename-section .data=compressed_data $^ $@
|
||||
|
||||
$(OBJDIR)/fullimage.elf: $(OBJDIR)/fullimage.nodata.o $(OBJDIR)/fullimage.data.o
|
||||
ifeq (,$(findstring WITH_NO_COMPRESSION,$(APP_CFLAGS)))
|
||||
$(info [=] LD $@)
|
||||
$(Q)$(CC) $(CROSS_LDFLAGS) -Wl,-T,ldscript,-e,_osimage_entry,-Map,$(patsubst %.elf,%.map,$@) -o $@ $^
|
||||
else
|
||||
$(Q)$(CP) $(OBJDIR)/fullimage.stage1.elf $@
|
||||
endif
|
||||
|
||||
tarbin: $(OBJS)
|
||||
$(info TAR $@)
|
||||
|
|
|
@ -35,6 +35,9 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
| LF_SAMYRUN | HID26 read/clone/sim |
|
||||
| | - Samy Kamkar |
|
||||
+----------------------------------------------------------+
|
||||
| LF_THAREXDE | Simulate/read EM4x50 tags |
|
||||
| (RDV4 only) | storing in flashmem |
|
||||
+----------------------------------------------------------+
|
||||
| HF_14ASNIFF | 14a sniff to flashmem |
|
||||
| (RDV4 only) | |
|
||||
+----------------------------------------------------------+
|
||||
|
@ -67,10 +70,10 @@ define KNOWN_STANDALONE_DEFINITIONS
|
|||
+----------------------------------------------------------+
|
||||
endef
|
||||
|
||||
STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN
|
||||
STANDALONE_MODES := LF_SKELETON LF_EM4100EMUL LF_EM4100RSWB LF_EM4100RWC LF_HIDBRUTE LF_ICEHID LF_PROXBRUTE LF_SAMYRUN LF_THAREXDE
|
||||
STANDALONE_MODES += HF_14ASNIFF HF_AVEFUL HF_BOG HF_COLIN HF_ICECLASS HF_LEGIC HF_MATTYRUN HF_MSDSAL HF_TCPRST HF_YOUNG
|
||||
STANDALONE_MODES_REQ_SMARTCARD :=
|
||||
STANDALONE_MODES_REQ_FLASH := LF_ICEHID HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS
|
||||
STANDALONE_MODES_REQ_FLASH := LF_ICEHID LF_THAREXDE HF_14ASNIFF HF_BOG HF_COLIN HF_ICECLASS
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES)),)
|
||||
STANDALONE_PLATFORM_DEFS += -DWITH_STANDALONE_$(STANDALONE)
|
||||
ifneq ($(filter $(STANDALONE),$(STANDALONE_MODES_REQ_SMARTCARD)),)
|
||||
|
|
|
@ -73,3 +73,7 @@ endif
|
|||
ifneq (,$(findstring WITH_STANDALONE_HF_ICECLASS,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = hf_iceclass.c
|
||||
endif
|
||||
# WITH_STANDALONE_LF_THAREXDE
|
||||
ifneq (,$(findstring WITH_STANDALONE_LF_THAREXDE,$(APP_CFLAGS)))
|
||||
SRC_STANDALONE = lf_tharexde.c
|
||||
endif
|
||||
|
|
|
@ -68,11 +68,11 @@ uint16_t get_ev1_version(iso14a_card_select_t card, uint8_t *version) {
|
|||
return mifare_sendcmd(MIFARE_ULEV1_VERSION, NULL, 0, version, NULL, NULL);
|
||||
}
|
||||
|
||||
uint16_t get_ev1_signature(iso14a_card_select_t card, uint8_t *response) {
|
||||
uint16_t get_ev1_signature(iso14a_card_select_t card, uint8_t *signature) {
|
||||
uint8_t cmd[4] = {MIFARE_ULEV1_READSIG, 0x00, 0x00, 0x00};
|
||||
AddCrc14A(cmd, 2);
|
||||
ReaderTransmit(cmd, sizeof(cmd), NULL);
|
||||
return ReaderReceive(response, NULL);
|
||||
return ReaderReceive(signature, NULL);
|
||||
}
|
||||
|
||||
uint16_t get_ev1_counter(iso14a_card_select_t card, uint8_t counter, uint8_t *response) {
|
||||
|
@ -114,7 +114,6 @@ int get_block_count(iso14a_card_select_t card, uint8_t version[], uint16_t versi
|
|||
else if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0E", 7) == 0) { block_count = MAX_ULEV1b_BLOCKS; }
|
||||
else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { block_count = MAX_ULEV1b_BLOCKS; }
|
||||
else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { block_count = MAX_ULEV1b_BLOCKS; } // Mikron JSC Russia EV1 41 pages tag
|
||||
else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { block_count = MAX_UL_BLOCKS; }
|
||||
else if (version[2] == 0x03) { block_count = MAX_ULEV1a_BLOCKS; }
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +190,7 @@ void RunMod(void) {
|
|||
read_successful = false;
|
||||
break;
|
||||
}
|
||||
// We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on hf_mfu_dumptoemulator
|
||||
// We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on data_mfu_bin2eml
|
||||
// When converting a bin, it's almost all 0 other than one 0x0F byte, and functionality seems to be unaffected if that byte is set to 0x00.
|
||||
emlSetMem_xt(dataout, 14 + i, 1, 4);
|
||||
Dbhexdump(4, dataout, 0);
|
||||
|
|
|
@ -37,15 +37,19 @@
|
|||
#define ICE_STATE_ATTACK 2
|
||||
#define ICE_STATE_READER 3
|
||||
#define ICE_STATE_CONFIGCARD 4
|
||||
#define ICE_STATE_DUMP_SIM 5
|
||||
|
||||
#define HF_ICLASS_NUM_MODES 6
|
||||
|
||||
// ====================================================
|
||||
// Select which standalone function to be active.
|
||||
// 4 possiblities. Uncomment the one you wanna use.
|
||||
// 5 possiblities. Uncomment the one you wanna use.
|
||||
|
||||
#define ICE_USE ICE_STATE_FULLSIM
|
||||
//#define ICE_USE ICE_STATE_ATTACK
|
||||
//#define ICE_USE ICE_STATE_READER
|
||||
//#define ICE_USE ICE_STATE_CONFIGCARD
|
||||
//#define ICE_USE ICE_STATE_DUMP_SIM
|
||||
|
||||
// ====================================================
|
||||
|
||||
|
@ -53,6 +57,8 @@
|
|||
#define NUM_CSNS 9
|
||||
#define MAC_RESPONSES_SIZE (16 * NUM_CSNS)
|
||||
#define HF_ICLASS_FULLSIM_ORIG_BIN "iceclass-orig.bin"
|
||||
#define HF_ICALSSS_READSIM_TEMP_BIN "iceclass-temp.bin"
|
||||
#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"
|
||||
|
@ -141,20 +147,33 @@ static void download_instructions(uint8_t t) {
|
|||
DbpString("2. " _YELLOW_("mem spiffs dump h"));
|
||||
break;
|
||||
}
|
||||
case ICE_STATE_DUMP_SIM: {
|
||||
DbpString("The found tag will be dumped to " HF_ICALSSS_READSIM_TEMP_BIN);
|
||||
DbpString("1. " _YELLOW_("mem spiffs tree"));
|
||||
DbpString("2. " _YELLOW_("mem spiffs dump h"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save to flash if file doesn't exist.
|
||||
// Write over file if size of flash file is less than new datalen
|
||||
static void save_to_flash(uint8_t *data, uint16_t datalen) {
|
||||
static void save_to_flash(uint8_t *data, uint16_t datalen, char *filename) {
|
||||
|
||||
rdv40_spiffs_lazy_mount();
|
||||
|
||||
char fn[SPIFFS_OBJ_NAME_LEN];
|
||||
|
||||
if (filename == NULL) {
|
||||
sprintf(fn, "iclass-%02X%02X%02X%02X%02X%02X%02X%02X.bin",
|
||||
data[0], data[1], data[2], data[3],
|
||||
data[4], data[5], data[6], data[7]
|
||||
);
|
||||
} else {
|
||||
int fnlen = MIN(strlen(filename), SPIFFS_OBJ_NAME_LEN);
|
||||
// if the given name len longer than buffer allows, cut it down to size
|
||||
memcpy(fn, filename, fnlen);
|
||||
}
|
||||
|
||||
int res;
|
||||
if (exists_in_spiffs(fn) == false) {
|
||||
|
@ -400,13 +419,180 @@ static int reader_dump_mode(void) {
|
|||
}
|
||||
}
|
||||
switch_off();
|
||||
save_to_flash(card_data, (start_block + dumped) * 8);
|
||||
save_to_flash(card_data, (start_block + dumped) * 8, NULL);
|
||||
Dbprintf("%u bytes saved", (start_block + dumped) * 8);
|
||||
}
|
||||
DbpString("-=[ exiting " _CYAN_("`read & dump`") " mode ]=-");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int dump_sim_mode(void) {
|
||||
|
||||
DbpString("this mode has no tracelog");
|
||||
if (have_aa2())
|
||||
DbpString("dumping of " _YELLOW_("AA2 enabled"));
|
||||
|
||||
for (;;) {
|
||||
|
||||
BigBuf_free();
|
||||
|
||||
uint8_t *card_data = BigBuf_malloc(ICLASS_16KS_SIZE);
|
||||
memset(card_data, 0xFF, ICLASS_16KS_SIZE);
|
||||
|
||||
if (BUTTON_PRESS()) {
|
||||
DbpString("button pressed");
|
||||
break;
|
||||
}
|
||||
|
||||
// setup authenticate AA1
|
||||
iclass_auth_req_t auth = {
|
||||
.use_raw = false,
|
||||
.use_elite = false,
|
||||
.use_credit_key = false,
|
||||
.do_auth = true,
|
||||
.send_reply = false,
|
||||
};
|
||||
memcpy(auth.key, legacy_aa1_key, sizeof(auth.key));
|
||||
|
||||
Iso15693InitReader();
|
||||
set_tracing(false);
|
||||
|
||||
|
||||
picopass_hdr *hdr = (picopass_hdr *)card_data;
|
||||
|
||||
// select tag.
|
||||
uint32_t eof_time = 0;
|
||||
bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
|
||||
if (res == false) {
|
||||
switch_off();
|
||||
continue;
|
||||
}
|
||||
|
||||
// sanity check of CSN.
|
||||
if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) {
|
||||
switch_off();
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
// get 3 config bits
|
||||
uint8_t type = (hdr->conf.chip_config & 0x10) >> 2;
|
||||
type |= (hdr->conf.mem_config & 0x80) >> 6;
|
||||
type |= (hdr->conf.mem_config & 0x20) >> 5;
|
||||
|
||||
Dbprintf(_GREEN_("%s") ", dumping...", card_types[type]);
|
||||
|
||||
uint8_t pagemap = get_pagemap(hdr);
|
||||
uint8_t app1_limit, app2_limit, start_block;
|
||||
|
||||
// tags configured for NON SECURE PAGE, acts different
|
||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
||||
app1_limit = card_app2_limit[type];
|
||||
app2_limit = 0;
|
||||
start_block = 3;
|
||||
} else {
|
||||
|
||||
app1_limit = hdr->conf.app_limit;
|
||||
app2_limit = card_app2_limit[type];
|
||||
start_block = 5;
|
||||
|
||||
res = authenticate_iclass_tag(&auth, hdr, &start_time, &eof_time, NULL);
|
||||
if (res == false) {
|
||||
switch_off();
|
||||
Dbprintf(_RED_("failed AA1 auth") ", skipping ");
|
||||
continue;
|
||||
}
|
||||
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
}
|
||||
|
||||
uint16_t dumped = 0;
|
||||
|
||||
// main read loop
|
||||
for (uint16_t i = start_block; i <= app1_limit; i++) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
|
||||
dumped++;
|
||||
}
|
||||
}
|
||||
|
||||
if (pagemap != PICOPASS_NON_SECURE_PAGEMODE && have_aa2()) {
|
||||
|
||||
// authenticate AA2
|
||||
auth.use_raw = false;
|
||||
auth.use_credit_key = true;
|
||||
memcpy(auth.key, aa2_key, sizeof(auth.key));
|
||||
|
||||
res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time);
|
||||
if (res) {
|
||||
|
||||
// sanity check of CSN.
|
||||
if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) {
|
||||
switch_off();
|
||||
continue;
|
||||
}
|
||||
|
||||
res = authenticate_iclass_tag(&auth, hdr, &start_time, &eof_time, NULL);
|
||||
if (res) {
|
||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||
|
||||
for (uint16_t i = app1_limit + 1; i <= app2_limit; i++) {
|
||||
if (iclass_read_block(i, card_data + (8 * i), &start_time, &eof_time)) {
|
||||
dumped++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DbpString(_RED_("failed AA2 auth"));
|
||||
}
|
||||
} else {
|
||||
DbpString(_RED_("failed selecting AA2"));
|
||||
|
||||
// sanity check of CSN.
|
||||
if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) {
|
||||
switch_off();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
switch_off();
|
||||
char *temp_file = HF_ICALSSS_READSIM_TEMP_BIN;
|
||||
save_to_flash(card_data, (start_block + dumped) * 8, temp_file);
|
||||
Dbprintf("%u bytes saved", (start_block + dumped) * 8);
|
||||
|
||||
if (((start_block + dumped) * 8) > 0) {
|
||||
break; //switch to sim mode
|
||||
}
|
||||
}
|
||||
|
||||
rdv40_spiffs_lazy_mount();
|
||||
|
||||
SpinOff(0);
|
||||
uint8_t *emul = BigBuf_get_EM_addr();
|
||||
uint32_t fsize = size_in_spiffs(HF_ICALSSS_READSIM_TEMP_BIN);
|
||||
int res = rdv40_spiffs_read_as_filetype(HF_ICALSSS_READSIM_TEMP_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
if (res == SPIFFS_OK) {
|
||||
Dbprintf("loaded " _GREEN_(HF_ICALSSS_READSIM_TEMP_BIN) " (%u bytes)", fsize);
|
||||
}
|
||||
|
||||
Dbprintf("simming " _GREEN_(HF_ICALSSS_READSIM_TEMP_BIN));
|
||||
iclass_simulate(ICLASS_SIM_MODE_FULL, 0, false, NULL, NULL, NULL);
|
||||
|
||||
LED_B_ON();
|
||||
rdv40_spiffs_lazy_mount();
|
||||
res = rdv40_spiffs_write(HF_ICALSSS_READSIM_TEMP_BIN, emul, fsize, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
rdv40_spiffs_lazy_unmount();
|
||||
LED_B_OFF();
|
||||
if (res == SPIFFS_OK) {
|
||||
Dbprintf("wrote emulator memory to " _GREEN_(HF_ICALSSS_READSIM_TEMP_MOD_BIN));
|
||||
} else {
|
||||
Dbprintf(_RED_("error") " writing "HF_ICALSSS_READSIM_TEMP_MOD_BIN" to flash ( %d )", res);
|
||||
}
|
||||
|
||||
DbpString("-=[ exiting " _CYAN_("`dump & sim`") " mode ]=-");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int config_sim_mode(void) {
|
||||
|
||||
uint8_t *emul = BigBuf_get_EM_addr();
|
||||
|
@ -436,7 +622,7 @@ void RunMod(void) {
|
|||
|
||||
uint8_t mode = ICE_USE;
|
||||
uint8_t *bb = BigBuf_get_EM_addr();
|
||||
if (bb[0] > 0 && bb[0] < 5) {
|
||||
if (bb[0] > 0 && bb[0] < HF_ICLASS_NUM_MODES) {
|
||||
mode = bb[0];
|
||||
}
|
||||
|
||||
|
@ -512,6 +698,16 @@ void RunMod(void) {
|
|||
if (mode == ICE_STATE_CONFIGCARD)
|
||||
config_sim_mode();
|
||||
|
||||
mode = ICE_STATE_NONE;
|
||||
break;
|
||||
}
|
||||
case ICE_STATE_DUMP_SIM: {
|
||||
DbpString("-=[ enter " _CYAN_("`dump & sim`") " mode, read 1 card and sim it ]=-");
|
||||
res = dump_sim_mode();
|
||||
if (res == PM3_SUCCESS) {
|
||||
download_instructions(mode);
|
||||
}
|
||||
|
||||
mode = ICE_STATE_NONE;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -248,11 +248,9 @@ void RunMod(void) {
|
|||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
|
||||
if (memcmp("\x02\xa2\xb0\x00\x00\x1d\x51\x69", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
memcpy(dynamic_response_info.response + 1, ndef, 31);
|
||||
dynamic_response_info.response_n = 32;
|
||||
} else if (memcmp("\x02\x00\x20\x00\x01\x00\x6e\xa9", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x63;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
|
@ -260,14 +258,12 @@ void RunMod(void) {
|
|||
memcpy(verify_pwd + 5, receivedCmd + 6, 16);
|
||||
DbpString("Reader sent password: ");
|
||||
Dbhexdump(16, verify_pwd + 5, 0);
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
gotkey = true;
|
||||
state = STATE_DUMP;
|
||||
} else {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
|
@ -321,7 +317,7 @@ void RunMod(void) {
|
|||
LED_B_ON();
|
||||
uint8_t apdulen = iso14_apdu(apdus[i], (uint16_t) apdusLen[i], false, apdubuffer, NULL);
|
||||
|
||||
if (apdulen > 0) {
|
||||
if (apdulen > 2) {
|
||||
DbpString(_YELLOW_("[ ") "Proxmark command" _YELLOW_(" ]"));
|
||||
Dbhexdump(apdusLen[i], apdus[i], false);
|
||||
DbpString(_GREEN_("[ ") "Card answer" _GREEN_(" ]"));
|
||||
|
@ -429,11 +425,9 @@ void RunMod(void) {
|
|||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
|
||||
if (memcmp("\x02\xa2\xb0\x00\x00\x1d\x51\x69", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
memcpy(dynamic_response_info.response + 1, ndef, 31);
|
||||
dynamic_response_info.response_n = 32;
|
||||
} else if (memcmp("\x02\x00\x20\x00\x01\x00\x6e\xa9", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x63;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
|
@ -441,12 +435,10 @@ void RunMod(void) {
|
|||
memcpy(verify_pwd + 5, receivedCmd + 6, 16);
|
||||
DbpString("Reader sent password: ");
|
||||
Dbhexdump(16, verify_pwd + 5, 0);
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
} else {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
|
|
|
@ -21,19 +21,19 @@
|
|||
#include "commonutil.h"
|
||||
|
||||
#define MAX_IND 16 // 4 LEDs - 2^4 combinations
|
||||
#define CLOCK 64 //for 125kHz
|
||||
#define LF_CLOCK 64 // for 125kHz
|
||||
|
||||
// low & high - array for storage IDs. Its length must be equal.
|
||||
// Predefined IDs must be stored in low[].
|
||||
static uint64_t low[] = {0x565A1140BE, 0x365A398149, 0x5555555555, 0xFFFFFFFFFF};
|
||||
static uint8_t *bba, slots_count;
|
||||
static uint8_t slots_count;
|
||||
static int buflen;
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" LF EM4100 simulator standalone mode");
|
||||
}
|
||||
|
||||
static uint64_t ReversQuads(uint64_t bits) {
|
||||
static uint64_t rev_quads(uint64_t bits) {
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
result += ((bits >> (60 - 4 * i)) & 0xf) << (4 * i);
|
||||
|
@ -41,32 +41,40 @@ static uint64_t ReversQuads(uint64_t bits) {
|
|||
return result >> 24;
|
||||
}
|
||||
|
||||
static void FillBuff(uint8_t bit) {
|
||||
memset(bba + buflen, bit, CLOCK / 2);
|
||||
buflen += (CLOCK / 2);
|
||||
memset(bba + buflen, bit ^ 1, CLOCK / 2);
|
||||
buflen += (CLOCK / 2);
|
||||
static void fill_buff(uint8_t bit) {
|
||||
uint8_t *bba = BigBuf_get_addr();
|
||||
memset(bba + buflen, bit, LF_CLOCK / 2);
|
||||
buflen += (LF_CLOCK / 2);
|
||||
memset(bba + buflen, bit ^ 1, LF_CLOCK / 2);
|
||||
buflen += (LF_CLOCK / 2);
|
||||
}
|
||||
|
||||
static void ConstructEM410xEmulBuf(uint64_t id) {
|
||||
static void construct_EM410x_emul(uint64_t id) {
|
||||
|
||||
int i, j, binary[4], parity[4];
|
||||
int i, j;
|
||||
int binary[4] = {0, 0, 0, 0};
|
||||
int parity[4] = {0, 0, 0, 0};
|
||||
buflen = 0;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
FillBuff(1);
|
||||
parity[0] = parity[1] = parity[2] = parity[3] = 0;
|
||||
fill_buff(1);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
for (j = 3; j >= 0; j--, id /= 2)
|
||||
binary[j] = id % 2;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
FillBuff(binary[j]);
|
||||
FillBuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
fill_buff(binary[j]);
|
||||
|
||||
fill_buff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
for (j = 0; j < 4; j++)
|
||||
parity[j] ^= binary[j];
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
FillBuff(parity[j]);
|
||||
FillBuff(0);
|
||||
fill_buff(parity[j]);
|
||||
|
||||
fill_buff(0);
|
||||
}
|
||||
|
||||
static void LED_Slot(int i) {
|
||||
|
@ -85,14 +93,14 @@ void RunMod(void) {
|
|||
|
||||
int selected = 0; //selected slot after start
|
||||
slots_count = ARRAYLEN(low);
|
||||
bba = BigBuf_get_addr();
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
if (data_available()) break;
|
||||
|
||||
SpinDelay(100);
|
||||
SpinUp(100);
|
||||
LED_Slot(selected);
|
||||
ConstructEM410xEmulBuf(ReversQuads(low[selected]));
|
||||
construct_EM410x_emul(rev_quads(low[selected]));
|
||||
SimulateTagLowFrequency(buflen, 0, true);
|
||||
selected = (selected + 1) % slots_count;
|
||||
}
|
||||
|
|
|
@ -53,8 +53,8 @@
|
|||
#include "flashmem.h"
|
||||
#endif
|
||||
|
||||
#define LF_CLOCK 64 //for 125kHz
|
||||
#define LF_RWSB_T55XX_TYPE 1 //Tag type: 0 - T5555, 1-T55x7
|
||||
#define LF_CLOCK 64 // for 125kHz
|
||||
#define LF_RWSB_T55XX_TYPE 1 // Tag type: 0 - T5555, 1-T55x7
|
||||
|
||||
#define LF_RWSB_UNKNOWN_RESULT 0
|
||||
#define LF_RWSB_BRUTE_STOPED 1
|
||||
|
@ -76,14 +76,13 @@ static int bruteforceSpeed[] = {10, 12, 14, 16};
|
|||
// In high[] must be nulls
|
||||
static uint64_t low[] = {0, 0, 0, 0};
|
||||
static uint32_t high[] = {0, 0, 0, 0};
|
||||
static uint8_t *bba;
|
||||
static int buflen;
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(" LF EM4100 read/sim/write/brute mode");
|
||||
}
|
||||
|
||||
static uint64_t ReversQuads(uint64_t bits) {
|
||||
static uint64_t rev_quads(uint64_t bits) {
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
result += ((bits >> (60 - 4 * i)) & 0xf) << (4 * i);
|
||||
|
@ -91,33 +90,39 @@ static uint64_t ReversQuads(uint64_t bits) {
|
|||
return result >> 24;
|
||||
}
|
||||
|
||||
static void FillBuff(uint8_t bit) {
|
||||
static void fill_buff(uint8_t bit) {
|
||||
uint8_t *bba = BigBuf_get_addr();
|
||||
memset(bba + buflen, bit, LF_CLOCK / 2);
|
||||
buflen += (LF_CLOCK / 2);
|
||||
memset(bba + buflen, bit ^ 1, LF_CLOCK / 2);
|
||||
buflen += (LF_CLOCK / 2);
|
||||
}
|
||||
|
||||
static void ConstructEM410xEmulBuf(uint64_t id) {
|
||||
bba = BigBuf_get_addr();
|
||||
|
||||
int i, j, binary[4], parity[4];
|
||||
static void construct_EM410x_emul(uint64_t id) {
|
||||
int i, j;
|
||||
int binary[4] = {0, 0, 0, 0};
|
||||
int parity[4] = {0, 0, 0, 0};
|
||||
buflen = 0;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
FillBuff(1);
|
||||
parity[0] = parity[1] = parity[2] = parity[3] = 0;
|
||||
fill_buff(1);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
for (j = 3; j >= 0; j--, id /= 2)
|
||||
binary[j] = id % 2;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
FillBuff(binary[j]);
|
||||
FillBuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
fill_buff(binary[j]);
|
||||
|
||||
fill_buff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
for (j = 0; j < 4; j++)
|
||||
parity[j] ^= binary[j];
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
FillBuff(parity[j]);
|
||||
FillBuff(0);
|
||||
fill_buff(parity[j]);
|
||||
|
||||
fill_buff(0);
|
||||
}
|
||||
|
||||
static void LED_Update(int mode, int slot) {
|
||||
|
@ -188,8 +193,8 @@ static uint64_t PackEmID(uint64_t original, int newCardNum) {
|
|||
buf &= ~(1 << i);
|
||||
}
|
||||
buf |= (newCardNum & 0xFFFF) << 1;
|
||||
buf |= oddparity32((buf >> 1) & 0xFFF) & 1;
|
||||
buf |= (evenparity32((buf >> 13) & 0xFFF) & 1) << 25;
|
||||
buf |= oddparity32((buf >> 1) & 0xFFF);
|
||||
buf |= (evenparity32((buf >> 13) & 0xFFF)) << 25;
|
||||
|
||||
uint32_t cardnumNew = (buf >> 1) & 0xFFFF;
|
||||
uint32_t fcNew = (buf >> 17) & 0xFF;
|
||||
|
@ -197,7 +202,6 @@ static uint64_t PackEmID(uint64_t original, int newCardNum) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
|
||||
static void PrintFcAndCardNum(uint64_t lowData) {
|
||||
// Calculate Facility Code and Card Number from high and low
|
||||
uint32_t fc = (lowData >> 17) & 0xFF;
|
||||
|
@ -222,7 +226,7 @@ static int BruteEMTag(uint64_t originalCard, int slot) {
|
|||
cardnum = cardnum + direction;
|
||||
uint64_t currentCard = PackEmID(originalCard, cardnum);
|
||||
Dbprintf("[=] >> Simulating card id %"PRIx64" <<", currentCard);
|
||||
ConstructEM410xEmulBuf(ReversQuads(currentCard));
|
||||
construct_EM410x_emul(rev_quads(currentCard));
|
||||
SimulateTagLowFrequencyEx(buflen, 0, 1, bruteforceSpeed[bruteforceSpeedCurrent] * 10000);
|
||||
|
||||
int button_pressed = BUTTON_CLICKED(1000);
|
||||
|
@ -267,7 +271,7 @@ static int ExecuteMode(int mode, int slot) {
|
|||
return LF_RWSB_UNKNOWN_RESULT;
|
||||
case LF_RWSB_MODE_SIM:
|
||||
Dbprintf("[=] >> Sim mode started <<");
|
||||
ConstructEM410xEmulBuf(ReversQuads(low[slot]));
|
||||
construct_EM410x_emul(rev_quads(low[slot]));
|
||||
SimulateTagLowFrequency(buflen, 0, 1);
|
||||
return LF_RWSB_UNKNOWN_RESULT;
|
||||
case LF_RWSB_MODE_WRITE:
|
||||
|
@ -310,7 +314,6 @@ void RunMod() {
|
|||
int slot = 0;
|
||||
mode = SwitchMode(mode, slot);
|
||||
|
||||
bba = BigBuf_get_addr();
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
if (data_available()) break;
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
// In high[] must be nulls
|
||||
static uint64_t low[] = {0x565AF781C7, 0x540053E4E2, 0x1234567890, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static uint32_t high[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static uint8_t *bba, slots_count;
|
||||
static uint8_t slots_count;
|
||||
static int buflen;
|
||||
|
||||
void ModInfo(void) {
|
||||
|
@ -56,7 +56,8 @@ static uint64_t rev_quads(uint64_t bits) {
|
|||
return result >> 24;
|
||||
}
|
||||
|
||||
static void fillbuff(uint8_t bit) {
|
||||
static void fill_buff(uint8_t bit) {
|
||||
uint8_t *bba = BigBuf_get_addr();
|
||||
memset(bba + buflen, bit, LF_CLOCK / 2);
|
||||
buflen += (LF_CLOCK / 2);
|
||||
memset(bba + buflen, bit ^ 1, LF_CLOCK / 2);
|
||||
|
@ -66,29 +67,29 @@ static void fillbuff(uint8_t bit) {
|
|||
static void construct_EM410x_emul(uint64_t id) {
|
||||
|
||||
int i, j;
|
||||
int binary[4] = {0};
|
||||
int parity[4] = {0};
|
||||
int binary[4] = {0, 0, 0, 0};
|
||||
int parity[4] = {0, 0, 0, 0};
|
||||
buflen = 0;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
fillbuff(1);
|
||||
fill_buff(1);
|
||||
|
||||
for (i = 0; i < 10; i++) {
|
||||
for (j = 3; j >= 0; j--, id /= 2)
|
||||
binary[j] = id % 2;
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
fillbuff(binary[j]);
|
||||
fill_buff(binary[j]);
|
||||
|
||||
fillbuff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
fill_buff(binary[0] ^ binary[1] ^ binary[2] ^ binary[3]);
|
||||
for (j = 0; j < 4; j++)
|
||||
parity[j] ^= binary[j];
|
||||
}
|
||||
|
||||
for (j = 0; j < 4; j++)
|
||||
fillbuff(parity[j]);
|
||||
fill_buff(parity[j]);
|
||||
|
||||
fillbuff(0);
|
||||
fill_buff(0);
|
||||
}
|
||||
|
||||
static void led_slot(int i) {
|
||||
|
@ -138,7 +139,6 @@ void RunMod(void) {
|
|||
// 3 - write to T5555 tag
|
||||
uint8_t state = 0;
|
||||
slots_count = ARRAYLEN(low);
|
||||
bba = BigBuf_get_addr();
|
||||
led_slot(selected);
|
||||
for (;;) {
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Tharexde, 2020
|
||||
// tharexde, 2021
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
|
@ -8,10 +8,12 @@
|
|||
// main code for EM4x50 simulator and collector aka THAREXDE
|
||||
//-----------------------------------------------------------------------------
|
||||
#include <inttypes.h>
|
||||
#include "ticks.h"
|
||||
#include "standalone.h"
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
#include "BigBuf.h"
|
||||
#include "commonutil.h"
|
||||
#include "fpgaloader.h"
|
||||
#include "util.h"
|
||||
#include "dbprint.h"
|
||||
|
@ -19,68 +21,75 @@
|
|||
#include "../em4x50.h"
|
||||
|
||||
/*
|
||||
* `lf_tharexde` simulates hardcoded words/blocks, reads words of standard read
|
||||
* mode of EM4x50 tags and stores them in internal flash.
|
||||
* `lf_tharexde` simulates EM4x50 dumps uploaded to flash, reads words
|
||||
* transmitted by EM4x50 tags in standard read mode and stores them in
|
||||
* internal flash.
|
||||
* It requires RDV4 hardware (for flash and battery).
|
||||
*
|
||||
* On entering stand-alone mode, this module will start reading/record EM4x50 data.
|
||||
* Every found / collected data will be written/appended to the logfile in flash
|
||||
* as a text string.
|
||||
* On entering stand-alone mode, this module will start simulating EM4x50 data.
|
||||
* Data is read from eml dump file uploaded to flash memory (lf_em4x50_simulate.eml).
|
||||
* If reader sends password different from dump file password, it is saved in
|
||||
* file lf_em4x50_passwords.log in flash memory.
|
||||
*
|
||||
* On switching to read/record mode by pressing pm3 button, module will start
|
||||
* reading EM4x50 data. Each collected data set will be written/appended to the
|
||||
* logfile in flash (lf_em4x50_collect.log) as a text string.
|
||||
*
|
||||
* LEDs:
|
||||
* - LED A: simulating
|
||||
* - LED B: reading / record
|
||||
* - LED C: writing to flash
|
||||
* - LED A blinking: no simulation data or read error
|
||||
* - LED B: reading/recording
|
||||
* - LED D: unmounting/sync'ing flash (normally < 100ms)
|
||||
*
|
||||
* To upload input file (eml format) to flash:
|
||||
* - mem spiffs load f <filename> o lf_em4x50_simulate.eml
|
||||
*
|
||||
* To retrieve password file from flash:
|
||||
* - mem spiffs dump o lf_em4x50_passwords.log f <filename>
|
||||
*
|
||||
* To retrieve log file from flash:
|
||||
*
|
||||
* 1. mem spiffs dump o lf_em4x50collect.log f lf_em4x50collect.log
|
||||
* Copies log file from flash to your client.
|
||||
*
|
||||
* 2. exit the Proxmark3 client
|
||||
*
|
||||
* 3. more lf_tharexdecollect.log
|
||||
* - mem spiffs dump o lf_em4x50_collect.log f <filename>
|
||||
*
|
||||
* This module emits debug strings during normal operation -- so try it out in
|
||||
* the lab connected to PM3 client before taking it into the field.
|
||||
*
|
||||
* To delete the log file from flash:
|
||||
* To delete the input file from flash:
|
||||
* - mem spiffs remove lf_em4x50_simulate.eml
|
||||
*
|
||||
* 1. mem spiffs remove lf_tharexdecollect.log
|
||||
* To delete the log file from flash:
|
||||
* - mem spiffs remove lf_em4x50_passwords.log
|
||||
*
|
||||
* To delete the log file from flash:
|
||||
* - mem spiffs remove lf_em4x50_collect.log
|
||||
*/
|
||||
|
||||
#define STATE_SIM 0
|
||||
#define STATE_READ 1
|
||||
#define STATE_BRUTE 2
|
||||
#define EM4X50_TAG_WORD 45
|
||||
#define EM4X50_PWD_SPEED 27
|
||||
#define LF_EM4X50SIMULATE_INPUTFILE "lf_em4x50simulate.eml"
|
||||
#define LF_EM4X50COLLECT_LOGFILE "lf_em4x50collect.log"
|
||||
#define LF_EM4X50BRUTE_INPUTFILE "lf_em4x50brute.eml"
|
||||
#define LF_EM4X50BRUTE_LOGFILE "lf_em4x50brute.log"
|
||||
#define LF_EM4X50_INPUTFILE_SIM "lf_em4x50_simulate.eml"
|
||||
#define LF_EM4X50_LOGFILE_SIM "lf_em4x50_passwords.log"
|
||||
#define LF_EM4X50_LOGFILE_COLLECT "lf_em4x50_collect.log"
|
||||
#define MAX_NO_PWDS_TO_SAVE 50
|
||||
|
||||
bool input_exists;
|
||||
bool log_exists;
|
||||
uint32_t gPassword;
|
||||
|
||||
static void LoadDataInstructions(const char *inputfile) {
|
||||
Dbprintf("");
|
||||
Dbprintf("To load datafile into flash and display it:");
|
||||
Dbprintf(_YELLOW_("1.") " edit inputfile %s", inputfile);
|
||||
Dbprintf(_YELLOW_("2.") " start proxmark3 client");
|
||||
Dbprintf(_YELLOW_("3.") " mem spiffs load f %s o %s", inputfile, inputfile);
|
||||
Dbprintf(_YELLOW_("4.") " start standalone mode");
|
||||
Dbprintf("To load datafile to flash and display it:");
|
||||
Dbprintf("1. edit input file %s", inputfile);
|
||||
Dbprintf("2. start proxmark3 client");
|
||||
Dbprintf("3. mem spiffs load f <filename> o %s", inputfile);
|
||||
Dbprintf("4. start standalone mode");
|
||||
}
|
||||
|
||||
static void DownloadLogInstructions(const char *logfile) {
|
||||
Dbprintf("");
|
||||
Dbprintf("To get the logfile from flash and display it:");
|
||||
Dbprintf(_YELLOW_("1.") " mem spiffs dump o %s f %s", logfile, logfile);
|
||||
Dbprintf(_YELLOW_("2.") " exit proxmark3 client");
|
||||
Dbprintf(_YELLOW_("3.") " cat %s", logfile);
|
||||
Dbprintf("1. mem spiffs dump o %s f <filename>", logfile);
|
||||
Dbprintf("2. exit proxmark3 client");
|
||||
Dbprintf("3. cat <filename>");
|
||||
}
|
||||
|
||||
static int get_input_data_from_file(uint32_t *words, char *inputfile) {
|
||||
static bool get_input_data_from_file(uint32_t *tag, char *inputfile) {
|
||||
|
||||
size_t now = 0;
|
||||
|
||||
|
@ -94,75 +103,77 @@ static int get_input_data_from_file(uint32_t *words, char *inputfile) {
|
|||
rdv40_spiffs_read_as_filetype(inputfile, mem, size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
||||
now = size / 9;
|
||||
for (int i = 0; i < now; i++)
|
||||
for (int j = 0; j < 4; j++)
|
||||
words[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8);
|
||||
for (int i = 0; i < now; i++) {
|
||||
for (int j = 0; j < 4; j++) {
|
||||
tag[i] |= (hex2int(mem[2 * j + 9 * i]) << 4 | hex2int(mem[2 * j + 1 + 9 * i])) << ((3 - j) * 8);
|
||||
}
|
||||
}
|
||||
|
||||
Dbprintf(_YELLOW_("read data from input file"));
|
||||
Dbprintf(_YELLOW_("read tag data from input file"));
|
||||
} else {
|
||||
Dbprintf(_RED_("no input file %s"), inputfile);
|
||||
}
|
||||
|
||||
BigBuf_free();
|
||||
|
||||
return (now > 0) ? now : 0;
|
||||
return ((now == EM4X50_NO_WORDS) && (tag[EM4X50_DEVICE_SERIAL] != tag[EM4X50_DEVICE_ID]));
|
||||
}
|
||||
|
||||
static void append(const char *filename, uint8_t *entry, size_t entry_len) {
|
||||
|
||||
LED_D_ON();
|
||||
if (log_exists == false) {
|
||||
rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
log_exists = true;
|
||||
} else {
|
||||
if (exists_in_spiffs(filename)) {
|
||||
rdv40_spiffs_append(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
} else {
|
||||
rdv40_spiffs_write(filename, entry, entry_len, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
}
|
||||
}
|
||||
|
||||
static void save_pwds(uint32_t *pwdlist, size_t no_pwd) {
|
||||
uint8_t entry[10] = {0};
|
||||
|
||||
if (no_pwd > 0) {
|
||||
Dbprintf("");
|
||||
for (int i = 0; i < no_pwd; i++) {
|
||||
sprintf((char *)entry, "%08"PRIx32"\n", pwdlist[i]);
|
||||
append(LF_EM4X50_LOGFILE_SIM, entry, strlen((char *)entry));
|
||||
Dbprintf("received password: %08"PRIx32"", pwdlist[i]);
|
||||
}
|
||||
}
|
||||
LED_D_OFF();
|
||||
}
|
||||
|
||||
void ModInfo(void) {
|
||||
DbpString(_YELLOW_(" LF EM4x50 sim/collector/bruteforce mode") " - a.k.a tharexde");
|
||||
DbpString(_YELLOW_(" LF EM4x50 sim/collector mode") " - a.k.a tharexde");
|
||||
}
|
||||
|
||||
void RunMod(void) {
|
||||
|
||||
bool state_change = true;//, password_found = false;
|
||||
int pwd_found = false;
|
||||
uint8_t state = STATE_SIM;
|
||||
// declarations for simulating
|
||||
uint32_t words[33] = {0x0};
|
||||
uint32_t pwd = 0x0;
|
||||
uint32_t passwords[2] = {0x0};
|
||||
size_t now = 0;
|
||||
// declarations for reading
|
||||
int no_words = 0;
|
||||
//uint32_t words[EM4X50_TAG_WORD];
|
||||
uint8_t entry[81];
|
||||
bool state_change = true, read_ok = false;
|
||||
int no_words = 0, command = 0, no_pwd = 0;
|
||||
uint8_t entry[400], state = STATE_SIM;
|
||||
uint32_t tag[EM4X50_NO_WORDS] = {0x0}, pwdlist[MAX_NO_PWDS_TO_SAVE];
|
||||
|
||||
rdv40_spiffs_lazy_mount();
|
||||
|
||||
StandAloneMode();
|
||||
Dbprintf(_YELLOW_("Standalone mode THAREXDE started"));
|
||||
|
||||
for (;;) {
|
||||
|
||||
WDT_HIT();
|
||||
if (data_available()) break;
|
||||
if (data_available()) {
|
||||
break;
|
||||
}
|
||||
|
||||
// press button - toggle between SIM, READ and BRUTE
|
||||
// press button - toggle between SIM and READ
|
||||
// hold button - exit
|
||||
int button_pressed = BUTTON_CLICKED(1000);
|
||||
if (button_pressed == BUTTON_SINGLE_CLICK) {
|
||||
|
||||
SpinUp(100);
|
||||
|
||||
switch (state) {
|
||||
|
||||
case STATE_SIM:
|
||||
// save and display passwords
|
||||
save_pwds(pwdlist, no_pwd);
|
||||
state = STATE_READ;
|
||||
break;
|
||||
case STATE_READ:
|
||||
state = STATE_BRUTE;
|
||||
break;
|
||||
case STATE_BRUTE:
|
||||
state = STATE_SIM;
|
||||
break;
|
||||
default:
|
||||
|
@ -172,8 +183,6 @@ void RunMod(void) {
|
|||
state_change = true;
|
||||
|
||||
} else if (button_pressed == BUTTON_HOLD) {
|
||||
|
||||
SpinDown(100);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -181,170 +190,102 @@ void RunMod(void) {
|
|||
|
||||
if (state_change) {
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_EDGE_DETECT);
|
||||
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, LF_DIVISOR_125);
|
||||
|
||||
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT | GPIO_SSC_CLK;
|
||||
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
|
||||
AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_CLK;
|
||||
|
||||
// initialize simulation mode
|
||||
LEDsoff();
|
||||
LED_A_ON();
|
||||
Dbprintf("");
|
||||
Dbprintf(_YELLOW_("switched to EM4x50 simulating mode"));
|
||||
|
||||
now = get_input_data_from_file(words, LF_EM4X50SIMULATE_INPUTFILE);
|
||||
if (now > 0) {
|
||||
Dbprintf(_YELLOW_("simulating %i blocks"), now);
|
||||
for (int i = 0; i < now; i++)
|
||||
Dbprintf("%2i -> %lx", i + 1, words[i]);
|
||||
|
||||
read_ok = get_input_data_from_file(tag, LF_EM4X50_INPUTFILE_SIM);
|
||||
if (read_ok) {
|
||||
Dbprintf(_YELLOW_("tag data ok"));
|
||||
} else {
|
||||
Dbprintf(_RED_("error in input data"));
|
||||
Dbprintf(_RED_("error in tag data"));
|
||||
LoadDataInstructions(LF_EM4X50_INPUTFILE_SIM);
|
||||
}
|
||||
|
||||
LED_D_OFF();
|
||||
gLogin = false;
|
||||
gPassword = reflect32(tag[0]);
|
||||
gWritePasswordProcess = false;
|
||||
command = EM4X50_COMMAND_STANDARD_READ;
|
||||
no_pwd = 0;
|
||||
memset(pwdlist, 0, sizeof(pwdlist));
|
||||
|
||||
em4x50_setup_sim();
|
||||
state_change = false;
|
||||
}
|
||||
|
||||
em4x50_sim_send_listen_window();
|
||||
for (int i = 0; i < now; i++) {
|
||||
em4x50_sim_send_listen_window();
|
||||
em4x50_sim_send_word(words[i]);
|
||||
// if no data or read error -> blink
|
||||
if (read_ok == false) {
|
||||
LED(LED_A, 200);
|
||||
SpinDelay(200);
|
||||
}
|
||||
|
||||
em4x50_handle_commands(&command, tag);
|
||||
|
||||
// check if new password was found
|
||||
if (gPassword != reflect32(tag[EM4X50_DEVICE_PASSWORD])) {
|
||||
if (no_pwd < MAX_NO_PWDS_TO_SAVE) {
|
||||
pwdlist[no_pwd] = gPassword;
|
||||
no_pwd++;
|
||||
}
|
||||
gPassword = reflect32(tag[EM4X50_DEVICE_PASSWORD]);
|
||||
}
|
||||
|
||||
// if timeout (e.g. no reader field) continue with standard read
|
||||
// mode and reset former authentication
|
||||
if (command == PM3_ETIMEOUT) {
|
||||
command = EM4X50_COMMAND_STANDARD_READ;
|
||||
gLogin = false;
|
||||
LED_D_OFF();
|
||||
}
|
||||
|
||||
} else if (state == STATE_READ) {
|
||||
|
||||
if (state_change) {
|
||||
|
||||
// initialize read mode
|
||||
LEDsoff();
|
||||
LED_B_ON();
|
||||
Dbprintf("");
|
||||
Dbprintf(_YELLOW_("switched to EM4x50 reading mode"));
|
||||
|
||||
memset(entry, 0, sizeof(entry));
|
||||
memset(words, 0, sizeof(words));
|
||||
|
||||
log_exists = exists_in_spiffs(LF_EM4X50COLLECT_LOGFILE);
|
||||
|
||||
em4x50_setup_read();
|
||||
state_change = false;
|
||||
}
|
||||
|
||||
no_words = em4x50_standalone_read(words);
|
||||
no_words = 0;
|
||||
memset(tag, 0, sizeof(tag));
|
||||
standard_read(&no_words, tag);
|
||||
|
||||
if (no_words > 0) {
|
||||
|
||||
memset(entry, 0, sizeof(entry));
|
||||
|
||||
sprintf((char *)entry, "found new EM4x50 tag:");
|
||||
Dbprintf("%s", entry);
|
||||
strcat((char *)entry, "\n");
|
||||
append(LF_EM4X50COLLECT_LOGFILE, entry, strlen((char *)entry));
|
||||
|
||||
sprintf((char *)entry, "found EM4x50 tag:\n");
|
||||
for (int i = 0; i < no_words; i++) {
|
||||
|
||||
sprintf((char *)entry, " %2i -> 0x%08"PRIx32"", i + 1, words[i]);
|
||||
sprintf((char *)entry + strlen((char *)entry), "%08"PRIx32"\n", tag[i]);
|
||||
}
|
||||
Dbprintf("%s", entry);
|
||||
strcat((char *)entry, "\n");
|
||||
append(LF_EM4X50COLLECT_LOGFILE, entry, strlen((char *)entry));
|
||||
sprintf((char *)entry + strlen((char *)entry), "\n");
|
||||
append(LF_EM4X50_LOGFILE_COLLECT, entry, strlen((char *)entry));
|
||||
}
|
||||
}
|
||||
|
||||
} else if (state == STATE_BRUTE) {
|
||||
|
||||
if (state_change) {
|
||||
|
||||
LEDsoff();
|
||||
LED_C_ON();
|
||||
Dbprintf("");
|
||||
Dbprintf(_YELLOW_("switched to EM4x50 brute force mode"));
|
||||
|
||||
log_exists = exists_in_spiffs(LF_EM4X50BRUTE_LOGFILE);
|
||||
now = get_input_data_from_file(passwords, LF_EM4X50BRUTE_INPUTFILE);
|
||||
|
||||
if (now == 2) {
|
||||
|
||||
// print some information
|
||||
int no_iter = passwords[1] - passwords[0] + 1;
|
||||
int dur_s = no_iter / EM4X50_PWD_SPEED;
|
||||
int dur_h = dur_s / 3600;
|
||||
int dur_m = (dur_s - dur_h * 3600) / 60;
|
||||
dur_s -= dur_h * 3600 + dur_m * 60;
|
||||
|
||||
//iterprint = no_iter/10;
|
||||
|
||||
Dbprintf(_YELLOW_("trying %i passwords in range [0x%08x, 0x%08x]"),
|
||||
no_iter, passwords[0], passwords[1]);
|
||||
Dbprintf(_YELLOW_("estimated duration: %ih%im%is"),
|
||||
dur_h, dur_m, dur_s);
|
||||
|
||||
} else {
|
||||
Dbprintf(_RED_("error in input data"));
|
||||
break;
|
||||
}
|
||||
|
||||
state_change = false;
|
||||
}
|
||||
|
||||
pwd_found = em4x50_standalone_brute(passwords[0], passwords[1], &pwd);
|
||||
|
||||
if (pwd_found == PM3_ETIMEOUT) {
|
||||
|
||||
// timeout -> no EM4x50 tag on reader?
|
||||
Dbprintf(_YELLOW_("timeout - no EM4x50 tag detected"));
|
||||
|
||||
} else if (pwd_found == true) {
|
||||
|
||||
// password found -> write to logfile
|
||||
sprintf((char *)entry, "password found: 0x%08"PRIx32, pwd);
|
||||
Dbprintf(_YELLOW_("%s"), entry);
|
||||
strcat((char *)entry, "\n");
|
||||
append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry));
|
||||
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
if (pwd == passwords[1] + 1) {
|
||||
|
||||
// finished without success -> write to logfile
|
||||
sprintf((char *)entry, "no password found");
|
||||
Dbprintf(_YELLOW_("%s"), entry);
|
||||
strcat((char *)entry, "\n");
|
||||
append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry));
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
// stopped -> write to logfile
|
||||
sprintf((char *)entry, "stopped search - last password: 0x%08"PRIx32, pwd);
|
||||
Dbprintf(_YELLOW_("%s"), entry);
|
||||
strcat((char *)entry, "\n");
|
||||
append(LF_EM4X50BRUTE_LOGFILE, entry, strlen((char *)entry));
|
||||
|
||||
// replace start password by last tested password in
|
||||
// inputfile (spiffs) so that brute forcing process will
|
||||
// be continued when envoking brute force mode again
|
||||
sprintf((char *)entry, "%08"PRIx32"\n%08"PRIx32"\n", pwd, passwords[1]);
|
||||
rdv40_spiffs_write(LF_EM4X50BRUTE_INPUTFILE,
|
||||
entry,
|
||||
strlen((char *)entry),
|
||||
RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
// reset timer
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0
|
||||
AT91C_BASE_TC0->TC_RC = 0; // set TIOA (carry bit) on overflow, return to zero
|
||||
AT91C_BASE_TC0->TC_RA = 1; // clear carry bit on next clock cycle
|
||||
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // reset and re-enable timer
|
||||
}
|
||||
|
||||
if (state == STATE_READ) {
|
||||
DownloadLogInstructions(LF_EM4X50COLLECT_LOGFILE);
|
||||
} else if (state == STATE_BRUTE) {
|
||||
LoadDataInstructions(LF_EM4X50BRUTE_INPUTFILE);
|
||||
DownloadLogInstructions(LF_EM4X50BRUTE_LOGFILE);
|
||||
DownloadLogInstructions(LF_EM4X50_LOGFILE_COLLECT);
|
||||
} else {
|
||||
LoadDataInstructions(LF_EM4X50SIMULATE_INPUTFILE);
|
||||
// save and display passwords
|
||||
save_pwds(pwdlist, no_pwd);
|
||||
DownloadLogInstructions(LF_EM4X50_LOGFILE_SIM);
|
||||
}
|
||||
|
||||
LED_D_ON();
|
||||
|
@ -352,8 +293,8 @@ void RunMod(void) {
|
|||
LED_D_OFF();
|
||||
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
LEDsoff();
|
||||
Dbprintf("");
|
||||
Dbprintf(_YELLOW_("[=] Standalone mode THAREXDE stopped"));
|
||||
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
#include "crc16.h"
|
||||
|
||||
#ifdef WITH_LCD
|
||||
#include "LCD.h"
|
||||
#include "LCD_disabled.h"
|
||||
#endif
|
||||
|
||||
#ifdef WITH_SMARTCARD
|
||||
|
@ -257,6 +257,9 @@ void ReadMem(int addr) {
|
|||
/* osimage version information is linked in, cf commonutil.h */
|
||||
/* bootrom version information is pointed to from _bootphase1_version_pointer */
|
||||
extern char *_bootphase1_version_pointer, _flash_start, _flash_end, __data_src_start__;
|
||||
#ifdef WITH_NO_COMPRESSION
|
||||
extern char *_bootrom_end, _bootrom_start, __os_size__;
|
||||
#endif
|
||||
static void SendVersion(void) {
|
||||
char temp[PM3_CMD_DATA_SIZE - 12]; /* Limited data payload in USB packets */
|
||||
char VersionString[PM3_CMD_DATA_SIZE - 12] = { '\0' };
|
||||
|
@ -295,9 +298,11 @@ static void SendVersion(void) {
|
|||
strncat(VersionString, "\n ", sizeof(VersionString) - strlen(VersionString) - 1);
|
||||
}
|
||||
}
|
||||
#ifndef WITH_NO_COMPRESSION
|
||||
// Send Chip ID and used flash memory
|
||||
uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start;
|
||||
uint32_t compressed_data_section_size = common_area.arg1;
|
||||
#endif
|
||||
|
||||
struct p {
|
||||
uint32_t id;
|
||||
|
@ -308,7 +313,11 @@ static void SendVersion(void) {
|
|||
|
||||
struct p payload;
|
||||
payload.id = *(AT91C_DBGU_CIDR);
|
||||
#ifdef WITH_NO_COMPRESSION
|
||||
payload.section_size = (uint32_t)&_bootrom_end - (uint32_t)&_bootrom_start + (uint32_t)&__os_size__;
|
||||
#else
|
||||
payload.section_size = text_and_rodata_section_size + compressed_data_section_size;
|
||||
#endif
|
||||
payload.versionstr_len = strlen(VersionString) + 1;
|
||||
memcpy(payload.versionstr, VersionString, payload.versionstr_len);
|
||||
|
||||
|
@ -1136,7 +1145,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
// destroy the Emulator Memory.
|
||||
//-----------------------------------------------------------------------------
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
em4x50_sim((uint8_t *)packet->data.asBytes);
|
||||
em4x50_sim((uint32_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X50_READER: {
|
||||
|
@ -1170,6 +1179,26 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
em4x70_info((em4x70_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X70_WRITE: {
|
||||
em4x70_write((em4x70_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X70_UNLOCK: {
|
||||
em4x70_unlock((em4x70_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X70_AUTH: {
|
||||
em4x70_auth((em4x70_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X70_WRITEPIN: {
|
||||
em4x70_write_pin((em4x70_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X70_WRITEKEY: {
|
||||
em4x70_write_key((em4x70_data_t *)packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WITH_ISO15693
|
||||
|
@ -1637,10 +1666,6 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
iClass_ReadBlock(packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_AUTH: { //check
|
||||
iClass_Authentication(packet->data.asBytes);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ICLASS_CHKKEYS: {
|
||||
iClass_Authentication_fast(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes);
|
||||
break;
|
||||
|
|
|
@ -242,7 +242,6 @@ void Desfire_session_key_new(const uint8_t rnda[], const uint8_t rndb[], desfire
|
|||
}
|
||||
}
|
||||
|
||||
static void xor(const uint8_t *ivect, uint8_t *data, const size_t len);
|
||||
static size_t key_macing_length(desfirekey_t key);
|
||||
|
||||
// iceman, see memxor inside string.c, dest/src swapped..
|
||||
|
@ -264,20 +263,20 @@ void cmac_generate_subkeys(desfirekey_t key) {
|
|||
|
||||
mifare_cypher_blocks_chained(NULL, key, ivect, l, kbs, MCD_RECEIVE, MCO_ENCYPHER);
|
||||
|
||||
bool xor = false;
|
||||
bool txor = false;
|
||||
|
||||
// Used to compute CMAC on complete blocks
|
||||
memcpy(key->cmac_sk1, l, kbs);
|
||||
xor = l[0] & 0x80;
|
||||
txor = l[0] & 0x80;
|
||||
lsl(key->cmac_sk1, kbs);
|
||||
if (xor)
|
||||
if (txor)
|
||||
key->cmac_sk1[kbs - 1] ^= R;
|
||||
|
||||
// Used to compute CMAC on the last block if non-complete
|
||||
memcpy(key->cmac_sk2, key->cmac_sk1, kbs);
|
||||
xor = key->cmac_sk1[0] & 0x80;
|
||||
txor = key->cmac_sk1[0] & 0x80;
|
||||
lsl(key->cmac_sk2, kbs);
|
||||
if (xor)
|
||||
if (txor)
|
||||
key->cmac_sk2[kbs - 1] ^= R;
|
||||
}
|
||||
|
||||
|
|
1158
armsrc/em4x50.c
1158
armsrc/em4x50.c
File diff suppressed because it is too large
Load diff
|
@ -13,10 +13,11 @@
|
|||
|
||||
#include "../include/em4x50.h"
|
||||
|
||||
int em4x50_standalone_read(uint32_t *words);
|
||||
int em4x50_standalone_brute(uint32_t start, uint32_t stop, uint32_t *pwd);
|
||||
bool em4x50_sim_send_listen_window(void);
|
||||
bool em4x50_sim_send_word(uint32_t word);
|
||||
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);
|
||||
|
||||
void em4x50_info(em4x50_data_t *etd);
|
||||
void em4x50_write(em4x50_data_t *etd);
|
||||
|
@ -24,7 +25,7 @@ void em4x50_writepwd(em4x50_data_t *etd);
|
|||
void em4x50_read(em4x50_data_t *etd);
|
||||
void em4x50_brute(em4x50_data_t *etd);
|
||||
void em4x50_login(uint32_t *password);
|
||||
void em4x50_sim(uint8_t *filename);
|
||||
void em4x50_sim(uint32_t *password);
|
||||
void em4x50_reader(void);
|
||||
void em4x50_chk(uint8_t *filename);
|
||||
|
||||
|
|
722
armsrc/em4x70.c
722
armsrc/em4x70.c
|
@ -21,28 +21,35 @@ static em4x70_tag_t tag = { 0 };
|
|||
// EM4170 requires a parity bit on commands, other variants do not.
|
||||
static bool command_parity = true;
|
||||
|
||||
#define EM4X70_T_TAG_QUARTER_PERIOD 8
|
||||
#define EM4X70_T_TAG_HALF_PERIOD 16
|
||||
#define EM4X70_T_TAG_THREE_QUARTER_PERIOD 24
|
||||
#define EM4X70_T_TAG_FULL_PERIOD 32
|
||||
#define EM4X70_T_TAG_TWA 128 // Write Access Time
|
||||
#define EM4X70_T_TAG_DIV 224 // Divergency Time
|
||||
#define EM4X70_T_TAG_AUTH 4224 // Authentication Time
|
||||
#define EM4X70_T_TAG_WEE 3072 // EEPROM write Time
|
||||
#define EM4X70_T_TAG_TWALB 128 // Write Access Time of Lock Bits
|
||||
// Conversion from Ticks to RF periods
|
||||
// 1 us = 1.5 ticks
|
||||
// 1RF Period = 8us = 12 Ticks
|
||||
#define TICKS_PER_FC 12
|
||||
|
||||
#define EM4X70_T_WAITING_FOR_SNGLLIW 160 // Unsure
|
||||
// Chip timing from datasheet
|
||||
// Converted into Ticks for timing functions
|
||||
#define EM4X70_T_TAG_QUARTER_PERIOD (8 * TICKS_PER_FC)
|
||||
#define EM4X70_T_TAG_HALF_PERIOD (16 * TICKS_PER_FC)
|
||||
#define EM4X70_T_TAG_THREE_QUARTER_PERIOD (24 * TICKS_PER_FC)
|
||||
#define EM4X70_T_TAG_FULL_PERIOD (32 * TICKS_PER_FC) // 1 Bit Period
|
||||
#define EM4X70_T_TAG_TWA (128 * TICKS_PER_FC) // Write Access Time
|
||||
#define EM4X70_T_TAG_DIV (224 * TICKS_PER_FC) // Divergency Time
|
||||
#define EM4X70_T_TAG_AUTH (4224 * TICKS_PER_FC) // Authentication Time
|
||||
#define EM4X70_T_TAG_WEE (3072 * TICKS_PER_FC) // EEPROM write Time
|
||||
#define EM4X70_T_TAG_TWALB (672 * TICKS_PER_FC) // Write Access Time of Lock Bits
|
||||
#define EM4X70_T_TAG_BITMOD (4 * TICKS_PER_FC) // Initial time to stop modulation when sending 0
|
||||
#define EM4X70_T_TAG_TOLERANCE (8 * TICKS_PER_FC) // Tolerance in RF periods for receive/LIW
|
||||
|
||||
#define TICKS_PER_FC 12 // 1 fc = 8us, 1.5us per tick = 12 ticks
|
||||
#define EM4X70_MIN_AMPLITUDE 10 // Minimum difference between a high and low signal
|
||||
|
||||
#define EM4X70_TAG_TOLERANCE 10
|
||||
#define EM4X70_TAG_WORD 48
|
||||
#define EM4X70_T_TAG_TIMEOUT (4 * EM4X70_T_TAG_FULL_PERIOD) // Timeout if we ever get a pulse longer than this
|
||||
#define EM4X70_T_WAITING_FOR_LIW 50 // Pulses to wait for listen window
|
||||
#define EM4X70_T_READ_HEADER_LEN 16 // Read header length (16 bit periods)
|
||||
|
||||
#define EM4X70_COMMAND_RETRIES 5 // Attempts to send/read command
|
||||
#define EM4X70_MAX_RECEIVE_LENGTH 96 // Maximum bits to expect from any command
|
||||
|
||||
/**
|
||||
* These IDs are from the EM4170 datasheet
|
||||
* Some versions of the chip require a fourth
|
||||
* Some versions of the chip require a
|
||||
* (even) parity bit, others do not
|
||||
*/
|
||||
#define EM4X70_COMMAND_ID 0x01
|
||||
|
@ -52,24 +59,28 @@ static bool command_parity = true;
|
|||
#define EM4X70_COMMAND_WRITE 0x05
|
||||
#define EM4X70_COMMAND_UM2 0x07
|
||||
|
||||
static uint8_t gHigh = 0;
|
||||
static uint8_t gLow = 0;
|
||||
// Constants used to determing high/low state of signal
|
||||
#define EM4X70_NOISE_THRESHOLD 13 // May depend on noise in environment
|
||||
#define HIGH_SIGNAL_THRESHOLD (127 + EM4X70_NOISE_THRESHOLD)
|
||||
#define LOW_SIGNAL_THRESHOLD (127 - EM4X70_NOISE_THRESHOLD)
|
||||
|
||||
#define IS_HIGH(sample) (sample>gLow ? true : false)
|
||||
#define IS_LOW(sample) (sample<gHigh ? true : false)
|
||||
#define IS_HIGH(sample) (sample > LOW_SIGNAL_THRESHOLD ? true : false)
|
||||
#define IS_LOW(sample) (sample < HIGH_SIGNAL_THRESHOLD ? true : false)
|
||||
|
||||
// Timing related macros
|
||||
#define IS_TIMEOUT(timeout_ticks) (GetTicks() > timeout_ticks)
|
||||
#define TICKS_ELAPSED(start_ticks) (GetTicks() - start_ticks)
|
||||
|
||||
|
||||
static uint8_t bits2byte(uint8_t *bits, int length);
|
||||
static void bits2bytes(uint8_t *bits, int length, uint8_t *out);
|
||||
static int em4x70_receive(uint8_t *bits);
|
||||
static uint8_t bits2byte(const uint8_t *bits, int length);
|
||||
static void bits2bytes(const uint8_t *bits, int length, uint8_t *out);
|
||||
static int em4x70_receive(uint8_t *bits, size_t length);
|
||||
static bool find_listen_window(bool command);
|
||||
|
||||
static void init_tag(void) {
|
||||
memset(tag.data, 0x00, sizeof(tag.data)/sizeof(tag.data[0]));
|
||||
memset(tag.data, 0x00, sizeof(tag.data) / sizeof(tag.data[0]));
|
||||
}
|
||||
|
||||
static void EM4170_setup_read(void) {
|
||||
static void em4x70_setup_read(void) {
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
|
||||
|
@ -102,208 +113,312 @@ static void EM4170_setup_read(void) {
|
|||
|
||||
static bool get_signalproperties(void) {
|
||||
|
||||
// calculate signal properties (mean amplitudes) from measured data:
|
||||
// 32 amplitudes (maximum values) -> mean amplitude value -> gHigh -> gLow
|
||||
bool signal_found = false;
|
||||
int no_periods = 32, pct = 50, noise = 140; // pct originally 75, found 50 was working better for me
|
||||
uint8_t sample_ref = 127;
|
||||
uint8_t sample_max_mean = 0;
|
||||
uint8_t sample_max[no_periods];
|
||||
uint32_t sample_max_sum = 0;
|
||||
|
||||
memset(sample_max, 0x00, sizeof(sample_max));
|
||||
// Simple check to ensure we see a signal above the noise threshold
|
||||
uint32_t no_periods = 32;
|
||||
|
||||
// wait until signal/noise > 1 (max. 32 periods)
|
||||
for (int i = 0; i < TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD * no_periods; i++) {
|
||||
for (int i = 0; i < EM4X70_T_TAG_FULL_PERIOD * no_periods; i++) {
|
||||
|
||||
// about 2 samples per bit period
|
||||
WaitTicks(TICKS_PER_FC * EM4X70_T_TAG_HALF_PERIOD);
|
||||
WaitTicks(EM4X70_T_TAG_HALF_PERIOD);
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_RHR > noise) {
|
||||
signal_found = true;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (signal_found == false)
|
||||
return false;
|
||||
|
||||
// calculate mean maximum value of 32 periods, each period has a length of
|
||||
// 3 single "full periods" to eliminate the influence of a listen window
|
||||
for (int i = 0; i < no_periods; i++) {
|
||||
|
||||
uint32_t start_ticks = GetTicks();
|
||||
//AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
|
||||
while (GetTicks() - start_ticks < TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD) {
|
||||
|
||||
volatile uint8_t sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
if (sample > sample_max[i])
|
||||
sample_max[i] = sample;
|
||||
|
||||
}
|
||||
|
||||
sample_max_sum += sample_max[i];
|
||||
}
|
||||
|
||||
sample_max_mean = sample_max_sum / no_periods;
|
||||
|
||||
// set global envelope variables
|
||||
gHigh = sample_ref + pct * (sample_max_mean - sample_ref) / 100;
|
||||
gLow = sample_ref - pct * (sample_max_mean - sample_ref) / 100;
|
||||
|
||||
// Basic sanity check
|
||||
if(gHigh - gLow < EM4X70_MIN_AMPLITUDE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Dbprintf("%s: gHigh %d gLow: %d", __func__, gHigh, gLow);
|
||||
if (AT91C_BASE_SSC->SSC_RHR > HIGH_SIGNAL_THRESHOLD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_pulse_length
|
||||
* get_falling_pulse_length
|
||||
*
|
||||
* Times falling edge pulses
|
||||
* Returns time between falling edge pulse in ticks
|
||||
*/
|
||||
static uint32_t get_pulse_length(void) {
|
||||
static uint32_t get_falling_pulse_length(void) {
|
||||
|
||||
uint8_t sample;
|
||||
uint32_t timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD);
|
||||
uint32_t timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT;
|
||||
|
||||
do {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}while (IS_HIGH(sample) && !IS_TIMEOUT(timeout));
|
||||
while (IS_HIGH(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout));
|
||||
|
||||
if (IS_TIMEOUT(timeout))
|
||||
return 0;
|
||||
|
||||
uint32_t start_ticks = GetTicks();
|
||||
timeout = start_ticks + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD);
|
||||
|
||||
do {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}while (IS_LOW(sample) && !IS_TIMEOUT(timeout));
|
||||
while (IS_LOW(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout));
|
||||
|
||||
if (IS_TIMEOUT(timeout))
|
||||
return 0;
|
||||
|
||||
timeout = (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD) + GetTicks();
|
||||
do {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}while (IS_HIGH(sample) && !IS_TIMEOUT(timeout));
|
||||
while (IS_HIGH(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout));
|
||||
|
||||
if (IS_TIMEOUT(timeout))
|
||||
return 0;
|
||||
|
||||
return GetTicks() - start_ticks;
|
||||
return TICKS_ELAPSED(start_ticks);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_pulse_invert_length
|
||||
* get_rising_pulse_length
|
||||
*
|
||||
* Times rising edge pules
|
||||
* TODO: convert to single function with get_pulse_length()
|
||||
* Returns time between rising edge pulse in ticks
|
||||
*/
|
||||
static uint32_t get_pulse_invert_length(void) {
|
||||
static uint32_t get_rising_pulse_length(void) {
|
||||
|
||||
uint8_t sample;
|
||||
uint32_t timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD);
|
||||
uint32_t timeout = GetTicks() + EM4X70_T_TAG_TIMEOUT;
|
||||
|
||||
do {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}while (IS_LOW(sample) && !IS_TIMEOUT(timeout));
|
||||
while (IS_LOW(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout));
|
||||
|
||||
if (IS_TIMEOUT(timeout))
|
||||
return 0;
|
||||
|
||||
uint32_t start_ticks = GetTicks();
|
||||
timeout = start_ticks + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD);
|
||||
|
||||
do {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}while (IS_HIGH(sample) && !IS_TIMEOUT(timeout));
|
||||
while (IS_HIGH(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout));
|
||||
|
||||
if (IS_TIMEOUT(timeout))
|
||||
return 0;
|
||||
|
||||
timeout = GetTicks() + (TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD);
|
||||
do {
|
||||
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}while (IS_LOW(sample) && !IS_TIMEOUT(timeout));
|
||||
while (IS_LOW(AT91C_BASE_SSC->SSC_RHR) && !IS_TIMEOUT(timeout));
|
||||
|
||||
if (IS_TIMEOUT(timeout))
|
||||
return 0;
|
||||
|
||||
return GetTicks() - start_ticks;
|
||||
return TICKS_ELAPSED(start_ticks);
|
||||
|
||||
}
|
||||
|
||||
static bool check_pulse_length(uint32_t pl, int length, int margin) {
|
||||
static uint32_t get_pulse_length(edge_detection_t edge) {
|
||||
|
||||
if (edge == RISING_EDGE)
|
||||
return get_rising_pulse_length();
|
||||
else if (edge == FALLING_EDGE)
|
||||
return get_falling_pulse_length();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool check_pulse_length(uint32_t pl, uint32_t length) {
|
||||
// check if pulse length <pl> corresponds to given length <length>
|
||||
//Dbprintf("%s: pulse length %d vs %d", __func__, pl, length * TICKS_PER_FC);
|
||||
return ((pl >= TICKS_PER_FC * (length - margin)) & (pl <= TICKS_PER_FC * (length + margin)));
|
||||
return ((pl >= (length - EM4X70_T_TAG_TOLERANCE)) && (pl <= (length + EM4X70_T_TAG_TOLERANCE)));
|
||||
}
|
||||
|
||||
static void em4x70_send_bit(int bit) {
|
||||
static void em4x70_send_bit(bool bit) {
|
||||
|
||||
// send single bit according to EM4170 application note and datasheet
|
||||
|
||||
uint32_t start_ticks = GetTicks();
|
||||
|
||||
if (bit == 0) {
|
||||
|
||||
// disable modulation (drop the field) for 4 cycles of carrier
|
||||
// disable modulation (drop the field) n cycles of carrier
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
while (GetTicks() - start_ticks <= TICKS_PER_FC * 4);
|
||||
while (TICKS_ELAPSED(start_ticks) <= EM4X70_T_TAG_BITMOD);
|
||||
|
||||
// enable modulation (activates the field) for remaining first
|
||||
// half of bit period
|
||||
HIGH(GPIO_SSC_DOUT);
|
||||
while (GetTicks() - start_ticks <= TICKS_PER_FC * EM4X70_T_TAG_HALF_PERIOD);
|
||||
while (TICKS_ELAPSED(start_ticks) <= EM4X70_T_TAG_HALF_PERIOD);
|
||||
|
||||
// disable modulation for second half of bit period
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
while (GetTicks() - start_ticks <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD);
|
||||
while (TICKS_ELAPSED(start_ticks) <= EM4X70_T_TAG_FULL_PERIOD);
|
||||
|
||||
} else {
|
||||
|
||||
// bit = "1" means disable modulation for full bit period
|
||||
LOW(GPIO_SSC_DOUT);
|
||||
while (GetTicks() - start_ticks <= TICKS_PER_FC * EM4X70_T_TAG_FULL_PERIOD);
|
||||
while (TICKS_ELAPSED(start_ticks) <= EM4X70_T_TAG_FULL_PERIOD);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* em4x70_send_command
|
||||
* em4x70_send_nibble
|
||||
*
|
||||
* sends 4 bits of data + 1 bit of parity (with_parity)
|
||||
*
|
||||
*/
|
||||
static void em4170_send_command(uint8_t command) {
|
||||
static void em4x70_send_nibble(uint8_t nibble, bool with_parity) {
|
||||
int parity = 0;
|
||||
int msb_bit = 0;
|
||||
|
||||
// Non automotive EM4x70 based tags are 3 bits + 1 parity.
|
||||
// So drop the MSB and send a parity bit instead after the command
|
||||
if(command_parity)
|
||||
if (command_parity)
|
||||
msb_bit = 1;
|
||||
|
||||
for (int i = msb_bit; i < 4; i++) {
|
||||
int bit = (command >> (3 - i)) & 1;
|
||||
int bit = (nibble >> (3 - i)) & 1;
|
||||
em4x70_send_bit(bit);
|
||||
parity ^= bit;
|
||||
}
|
||||
|
||||
if(command_parity)
|
||||
if (with_parity)
|
||||
em4x70_send_bit(parity);
|
||||
|
||||
}
|
||||
|
||||
static void em4x70_send_byte(uint8_t byte) {
|
||||
// Send byte msb first
|
||||
for (int i = 0; i < 8; i++)
|
||||
em4x70_send_bit((byte >> (7 - i)) & 1);
|
||||
}
|
||||
|
||||
static void em4x70_send_word(const uint16_t word) {
|
||||
|
||||
// Split into nibbles
|
||||
uint8_t nibbles[4];
|
||||
uint8_t j = 0;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
uint8_t byte = (word >> (8 * i)) & 0xff;
|
||||
nibbles[j++] = (byte >> 4) & 0xf;
|
||||
nibbles[j++] = byte & 0xf;
|
||||
}
|
||||
|
||||
// send 16 bit word with parity bits according to EM4x70 datasheet
|
||||
// sent as 4 x nibbles (4 bits + parity)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
em4x70_send_nibble(nibbles[i], true);
|
||||
}
|
||||
|
||||
// send column parities (4 bit)
|
||||
em4x70_send_nibble(nibbles[0] ^ nibbles[1] ^ nibbles[2] ^ nibbles[3], false);
|
||||
|
||||
// send final stop bit (always "0")
|
||||
em4x70_send_bit(0);
|
||||
}
|
||||
|
||||
static bool check_ack(void) {
|
||||
// returns true if signal structue corresponds to ACK, anything else is
|
||||
// counted as NAK (-> false)
|
||||
// ACK 64 + 64
|
||||
// NACK 64 + 48
|
||||
if (check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD) &&
|
||||
check_pulse_length(get_pulse_length(FALLING_EDGE), 2 * EM4X70_T_TAG_FULL_PERIOD)) {
|
||||
// ACK
|
||||
return true;
|
||||
}
|
||||
|
||||
// Othewise it was a NACK or Listen Window
|
||||
return false;
|
||||
}
|
||||
|
||||
static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *response) {
|
||||
|
||||
if (find_listen_window(true)) {
|
||||
|
||||
em4x70_send_nibble(EM4X70_COMMAND_AUTH, true);
|
||||
|
||||
// Send 56-bit Random number
|
||||
for (int i = 0; i < 7; i++) {
|
||||
em4x70_send_byte(rnd[i]);
|
||||
}
|
||||
|
||||
// Send 7 x 0's (Diversity bits)
|
||||
for (int i = 0; i < 7; i++) {
|
||||
em4x70_send_bit(0);
|
||||
}
|
||||
|
||||
// Send 28-bit f(RN)
|
||||
|
||||
// Send first 24 bits
|
||||
for (int i = 0; i < 3; i++) {
|
||||
em4x70_send_byte(frnd[i]);
|
||||
}
|
||||
|
||||
// Send last 4 bits (no parity)
|
||||
em4x70_send_nibble((frnd[3] >> 4) & 0xf, false);
|
||||
|
||||
// Receive header, 20-bit g(RN), LIW
|
||||
uint8_t grnd[EM4X70_MAX_RECEIVE_LENGTH] = {0};
|
||||
int num = em4x70_receive(grnd, 20);
|
||||
if (num < 20) {
|
||||
Dbprintf("Auth failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
bits2bytes(grnd, 24, response);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
static int send_pin(const uint32_t pin) {
|
||||
|
||||
// sends pin code for unlocking
|
||||
if (find_listen_window(true)) {
|
||||
|
||||
// send PIN command
|
||||
em4x70_send_nibble(EM4X70_COMMAND_PIN, true);
|
||||
|
||||
// --> Send TAG ID (bytes 4-7)
|
||||
for (int i = 0; i < 4; i++) {
|
||||
em4x70_send_byte(tag.data[7 - i]);
|
||||
}
|
||||
|
||||
// --> Send PIN
|
||||
for (int i = 0; i < 4 ; i++) {
|
||||
em4x70_send_byte((pin >> (i * 8)) & 0xff);
|
||||
}
|
||||
|
||||
// Wait TWALB (write access lock bits)
|
||||
WaitTicks(EM4X70_T_TAG_TWALB);
|
||||
|
||||
// <-- Receive ACK
|
||||
if (check_ack()) {
|
||||
|
||||
// <w> Writes Lock Bits
|
||||
WaitTicks(EM4X70_T_TAG_WEE);
|
||||
// <-- Receive header + ID
|
||||
uint8_t tag_id[EM4X70_MAX_RECEIVE_LENGTH];
|
||||
int num = em4x70_receive(tag_id, 32);
|
||||
if (num < 32) {
|
||||
Dbprintf("Invalid ID Received");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
bits2bytes(tag_id, num, &tag.data[4]);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
static int write(const uint16_t word, const uint8_t address) {
|
||||
|
||||
// writes <word> to specified <address>
|
||||
if (find_listen_window(true)) {
|
||||
|
||||
// send write command
|
||||
em4x70_send_nibble(EM4X70_COMMAND_WRITE, true);
|
||||
|
||||
// send address data with parity bit
|
||||
em4x70_send_nibble(address, true);
|
||||
|
||||
// send data word
|
||||
em4x70_send_word(word);
|
||||
|
||||
// Wait TWA
|
||||
WaitTicks(EM4X70_T_TAG_TWA);
|
||||
|
||||
// look for ACK sequence
|
||||
if (check_ack()) {
|
||||
|
||||
// now EM4x70 needs EM4X70_T_TAG_TWEE (EEPROM write time)
|
||||
// for saving data and should return with ACK
|
||||
WaitTicks(EM4X70_T_TAG_WEE);
|
||||
if (check_ack()) {
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
||||
static bool find_listen_window(bool command) {
|
||||
|
||||
int cnt = 0;
|
||||
while(cnt < EM4X70_T_WAITING_FOR_SNGLLIW) {
|
||||
while (cnt < EM4X70_T_WAITING_FOR_LIW) {
|
||||
/*
|
||||
80 ( 64 + 16 )
|
||||
80 ( 64 + 16 )
|
||||
|
@ -311,49 +426,46 @@ static bool find_listen_window(bool command) {
|
|||
96 ( 64 + 32 )
|
||||
64 ( 32 + 16 +16 )*/
|
||||
|
||||
if (check_pulse_length(get_pulse_invert_length(), 80, EM4X70_TAG_TOLERANCE)) {
|
||||
if (check_pulse_length(get_pulse_invert_length(), 80, EM4X70_TAG_TOLERANCE)) {
|
||||
if (check_pulse_length(get_pulse_length(), 96, EM4X70_TAG_TOLERANCE)) {
|
||||
if (check_pulse_length(get_pulse_length(), 64, EM4X70_TAG_TOLERANCE)) {
|
||||
if(command) {
|
||||
if (check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) &&
|
||||
check_pulse_length(get_pulse_length(RISING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_HALF_PERIOD) &&
|
||||
check_pulse_length(get_pulse_length(FALLING_EDGE), (2 * EM4X70_T_TAG_FULL_PERIOD) + EM4X70_T_TAG_FULL_PERIOD) &&
|
||||
check_pulse_length(get_pulse_length(FALLING_EDGE), EM4X70_T_TAG_FULL_PERIOD + (2 * EM4X70_T_TAG_HALF_PERIOD))) {
|
||||
|
||||
if (command) {
|
||||
/* Here we are after the 64 duration edge.
|
||||
* em4170 says we need to wait about 48 RF clock cycles.
|
||||
* depends on the delay between tag and us
|
||||
*
|
||||
* I've found between 4-5 quarter periods (32-40) works best
|
||||
*/
|
||||
WaitTicks(TICKS_PER_FC * 5 * EM4X70_T_TAG_QUARTER_PERIOD);
|
||||
WaitTicks(4 * EM4X70_T_TAG_QUARTER_PERIOD);
|
||||
// Send RM Command
|
||||
em4x70_send_bit(0);
|
||||
em4x70_send_bit(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cnt++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void bits2bytes(uint8_t *bits, int length, uint8_t *out) {
|
||||
static void bits2bytes(const uint8_t *bits, int length, uint8_t *out) {
|
||||
|
||||
if(length%8 != 0) {
|
||||
if (length % 8 != 0) {
|
||||
Dbprintf("Should have a multiple of 8 bits, was sent %d", length);
|
||||
}
|
||||
|
||||
int num_bytes = length / 8; // We should have a multiple of 8 here
|
||||
|
||||
for(int i=1; i <= num_bytes; i++) {
|
||||
out[num_bytes-i] = bits2byte(bits, 8);
|
||||
bits+=8;
|
||||
//Dbprintf("Read: %02X", out[num_bytes-i]);
|
||||
for (int i = 1; i <= num_bytes; i++) {
|
||||
out[num_bytes - i] = bits2byte(bits, 8);
|
||||
bits += 8;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t bits2byte(uint8_t *bits, int length) {
|
||||
static uint8_t bits2byte(const uint8_t *bits, int length) {
|
||||
|
||||
// converts <length> separate bits into a single "byte"
|
||||
uint8_t byte = 0;
|
||||
|
@ -368,22 +480,28 @@ static uint8_t bits2byte(uint8_t *bits, int length) {
|
|||
return byte;
|
||||
}
|
||||
|
||||
/*static void print_array(uint8_t *bits, int len) {
|
||||
static bool send_command_and_read(uint8_t command, uint8_t *bytes, size_t length) {
|
||||
|
||||
if(len%8 != 0) {
|
||||
Dbprintf("Should have a multiple of 8 bits, was sent %d", len);
|
||||
int retries = EM4X70_COMMAND_RETRIES;
|
||||
while (retries) {
|
||||
retries--;
|
||||
|
||||
if (find_listen_window(true)) {
|
||||
uint8_t bits[EM4X70_MAX_RECEIVE_LENGTH] = {0};
|
||||
size_t out_length_bits = length * 8;
|
||||
em4x70_send_nibble(command, command_parity);
|
||||
int len = em4x70_receive(bits, out_length_bits);
|
||||
if (len < out_length_bits) {
|
||||
Dbprintf("Invalid data received length: %d, expected %d", len, out_length_bits);
|
||||
return false;
|
||||
}
|
||||
|
||||
int num_bytes = len / 8; // We should have a multiple of 8 here
|
||||
|
||||
uint8_t bytes[8];
|
||||
|
||||
for(int i=0;i<num_bytes;i++) {
|
||||
bytes[i] = bits2byte(bits, 8);
|
||||
bits+=8;
|
||||
Dbprintf("Read: %02X", bytes[i]);
|
||||
bits2bytes(bits, len, bytes);
|
||||
return true;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -393,18 +511,8 @@ static uint8_t bits2byte(uint8_t *bits, int length) {
|
|||
*/
|
||||
static bool em4x70_read_id(void) {
|
||||
|
||||
if(find_listen_window(true)) {
|
||||
uint8_t bits[64] = {0};
|
||||
em4170_send_command(EM4X70_COMMAND_ID);
|
||||
int num = em4x70_receive(bits);
|
||||
if(num < 32) {
|
||||
Dbprintf("Invalid ID Received");
|
||||
return false;
|
||||
}
|
||||
bits2bytes(bits, num, &tag.data[4]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return send_command_and_read(EM4X70_COMMAND_ID, &tag.data[4], 4);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -413,18 +521,9 @@ static bool em4x70_read_id(void) {
|
|||
* read user memory 1 (4 bytes including lock bits)
|
||||
*/
|
||||
static bool em4x70_read_um1(void) {
|
||||
if(find_listen_window(true)) {
|
||||
uint8_t bits[64] = {0};
|
||||
em4170_send_command(EM4X70_COMMAND_UM1);
|
||||
int num = em4x70_receive(bits);
|
||||
if(num < 32) {
|
||||
Dbprintf("Invalid UM1 data received");
|
||||
return false;
|
||||
}
|
||||
bits2bytes(bits, num, &tag.data[0]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return send_command_and_read(EM4X70_COMMAND_UM1, &tag.data[0], 4);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -434,34 +533,22 @@ static bool em4x70_read_um1(void) {
|
|||
* read user memory 2 (8 bytes)
|
||||
*/
|
||||
static bool em4x70_read_um2(void) {
|
||||
if(find_listen_window(true)) {
|
||||
uint8_t bits[64] = {0};
|
||||
em4170_send_command(EM4X70_COMMAND_UM2);
|
||||
int num = em4x70_receive(bits);
|
||||
if(num < 64) {
|
||||
Dbprintf("Invalid UM2 data received");
|
||||
return false;
|
||||
}
|
||||
bits2bytes(bits, num, &tag.data[24]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
return send_command_and_read(EM4X70_COMMAND_UM2, &tag.data[24], 8);
|
||||
|
||||
}
|
||||
|
||||
static bool find_EM4X70_Tag(void) {
|
||||
Dbprintf("%s: Start", __func__);
|
||||
static bool find_em4x70_tag(void) {
|
||||
// function is used to check wether a tag on the proxmark is an
|
||||
// EM4170 tag or not -> speed up "lf search" process
|
||||
return find_listen_window(false);
|
||||
}
|
||||
|
||||
static int em4x70_receive(uint8_t *bits) {
|
||||
static int em4x70_receive(uint8_t *bits, size_t length) {
|
||||
|
||||
uint32_t pl;
|
||||
int bit_pos = 0;
|
||||
uint8_t edge = 0;
|
||||
|
||||
|
||||
edge_detection_t edge = RISING_EDGE;
|
||||
bool foundheader = false;
|
||||
|
||||
// Read out the header
|
||||
|
@ -469,60 +556,58 @@ static int em4x70_receive(uint8_t *bits) {
|
|||
// 4 Manchester 0's
|
||||
|
||||
// Skip a few leading 1's as it could be noisy
|
||||
WaitTicks(TICKS_PER_FC * 3 * EM4X70_T_TAG_FULL_PERIOD);
|
||||
WaitTicks(6 * EM4X70_T_TAG_FULL_PERIOD);
|
||||
|
||||
// wait until we get the transition from 1's to 0's which is 1.5 full windows
|
||||
int pulse_count = 0;
|
||||
while(pulse_count < 12){
|
||||
pl = get_pulse_invert_length();
|
||||
pulse_count++;
|
||||
if(check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD, EM4X70_TAG_TOLERANCE)) {
|
||||
for (int i = 0; i < EM4X70_T_READ_HEADER_LEN; i++) {
|
||||
pl = get_pulse_length(edge);
|
||||
if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) {
|
||||
foundheader = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!foundheader) {
|
||||
if (!foundheader) {
|
||||
Dbprintf("Failed to find read header");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Skip next 3 0's, header check consumes the first 0
|
||||
for(int i = 0; i < 3; i++) {
|
||||
get_pulse_invert_length();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
// If pulse length is not 1 bit, then abort early
|
||||
if (!check_pulse_length(get_pulse_length(edge), EM4X70_T_TAG_FULL_PERIOD)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// identify remaining bits based on pulse lengths
|
||||
// between two listen windows only pulse lengths of 1, 1.5 and 2 are possible
|
||||
while (true) {
|
||||
// between listen windows only pulse lengths of 1, 1.5 and 2 are possible
|
||||
while (bit_pos < length) {
|
||||
|
||||
if(edge)
|
||||
pl = get_pulse_length();
|
||||
else
|
||||
pl = get_pulse_invert_length();
|
||||
pl = get_pulse_length(edge);
|
||||
|
||||
if (check_pulse_length(pl, EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) {
|
||||
if (check_pulse_length(pl, EM4X70_T_TAG_FULL_PERIOD)) {
|
||||
|
||||
// pulse length = 1
|
||||
bits[bit_pos++] = edge;
|
||||
// pulse length 1 -> assign bit
|
||||
bits[bit_pos++] = edge == FALLING_EDGE ? 1 : 0;
|
||||
|
||||
} else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) {
|
||||
} else if (check_pulse_length(pl, 3 * EM4X70_T_TAG_HALF_PERIOD)) {
|
||||
|
||||
// pulse length = 1.5 -> flip edge detection
|
||||
if(edge) {
|
||||
// pulse length 1.5 -> 2 bits + flip edge detection
|
||||
if (edge == FALLING_EDGE) {
|
||||
bits[bit_pos++] = 0;
|
||||
bits[bit_pos++] = 0;
|
||||
edge = 0;
|
||||
edge = RISING_EDGE;
|
||||
} else {
|
||||
bits[bit_pos++] = 1;
|
||||
bits[bit_pos++] = 1;
|
||||
edge = 1;
|
||||
edge = FALLING_EDGE;
|
||||
}
|
||||
|
||||
} else if (check_pulse_length(pl, 2 * EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) {
|
||||
} else if (check_pulse_length(pl, 2 * EM4X70_T_TAG_FULL_PERIOD)) {
|
||||
|
||||
// pulse length of 2
|
||||
if(edge) {
|
||||
// pulse length of 2 -> two bits
|
||||
if (edge == FALLING_EDGE) {
|
||||
bits[bit_pos++] = 0;
|
||||
bits[bit_pos++] = 1;
|
||||
} else {
|
||||
|
@ -530,15 +615,13 @@ static int em4x70_receive(uint8_t *bits) {
|
|||
bits[bit_pos++] = 0;
|
||||
}
|
||||
|
||||
} else if ( (edge && check_pulse_length(pl, 3 * EM4X70_T_TAG_FULL_PERIOD, EM4X70_T_TAG_QUARTER_PERIOD)) ||
|
||||
(!edge && check_pulse_length(pl, 80, EM4X70_T_TAG_QUARTER_PERIOD))) {
|
||||
} else {
|
||||
// Listen Window, or invalid bit
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// LIW detected (either invert or normal)
|
||||
return --bit_pos;
|
||||
}
|
||||
}
|
||||
return bit_pos;
|
||||
|
||||
}
|
||||
|
||||
void em4x70_info(em4x70_data_t *etd) {
|
||||
|
@ -549,10 +632,10 @@ void em4x70_info(em4x70_data_t *etd) {
|
|||
command_parity = etd->parity;
|
||||
|
||||
init_tag();
|
||||
EM4170_setup_read();
|
||||
em4x70_setup_read();
|
||||
|
||||
// Find the Tag
|
||||
if (get_signalproperties() && find_EM4X70_Tag()) {
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
// Read ID, UM1 and UM2
|
||||
status = em4x70_read_id() && em4x70_read_um1() && em4x70_read_um2();
|
||||
}
|
||||
|
@ -561,3 +644,166 @@ void em4x70_info(em4x70_data_t *etd) {
|
|||
lf_finalize();
|
||||
reply_ng(CMD_LF_EM4X70_INFO, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
||||
void em4x70_write(em4x70_data_t *etd) {
|
||||
|
||||
uint8_t status = 0;
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
// Find the Tag
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
|
||||
// Write
|
||||
status = write(etd->word, etd->address) == PM3_SUCCESS;
|
||||
|
||||
if (status) {
|
||||
// Read Tag after writing
|
||||
if (em4x70_read_id()) {
|
||||
em4x70_read_um1();
|
||||
em4x70_read_um2();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
lf_finalize();
|
||||
reply_ng(CMD_LF_EM4X70_WRITE, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
||||
void em4x70_unlock(em4x70_data_t *etd) {
|
||||
|
||||
uint8_t status = 0;
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
// Find the Tag
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
|
||||
// Read ID (required for send_pin command)
|
||||
if (em4x70_read_id()) {
|
||||
|
||||
// Send PIN
|
||||
status = send_pin(etd->pin) == PM3_SUCCESS;
|
||||
|
||||
// If the write succeeded, read the rest of the tag
|
||||
if (status) {
|
||||
// Read Tag
|
||||
// ID doesn't change
|
||||
em4x70_read_um1();
|
||||
em4x70_read_um2();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
lf_finalize();
|
||||
reply_ng(CMD_LF_EM4X70_UNLOCK, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
||||
void em4x70_auth(em4x70_data_t *etd) {
|
||||
|
||||
uint8_t status = 0;
|
||||
uint8_t response[3] = {0};
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
// Find the Tag
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
|
||||
// Authenticate and get tag response
|
||||
status = authenticate(etd->rnd, etd->frnd, response) == PM3_SUCCESS;
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
lf_finalize();
|
||||
reply_ng(CMD_LF_EM4X70_AUTH, status, response, sizeof(response));
|
||||
}
|
||||
|
||||
void em4x70_write_pin(em4x70_data_t *etd) {
|
||||
|
||||
uint8_t status = 0;
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
// Find the Tag
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
|
||||
// Read ID (required for send_pin command)
|
||||
if (em4x70_read_id()) {
|
||||
|
||||
// Write new PIN
|
||||
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
|
||||
|
||||
// Send PIN
|
||||
status = send_pin(etd->pin) == PM3_SUCCESS;
|
||||
|
||||
// If the write succeeded, read the rest of the tag
|
||||
if (status) {
|
||||
// Read Tag
|
||||
// ID doesn't change
|
||||
em4x70_read_um1();
|
||||
em4x70_read_um2();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
lf_finalize();
|
||||
reply_ng(CMD_LF_EM4X70_WRITEPIN, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
||||
void em4x70_write_key(em4x70_data_t *etd) {
|
||||
|
||||
uint8_t status = 0;
|
||||
|
||||
command_parity = etd->parity;
|
||||
|
||||
init_tag();
|
||||
em4x70_setup_read();
|
||||
|
||||
// Find the Tag
|
||||
if (get_signalproperties() && find_em4x70_tag()) {
|
||||
|
||||
// Read ID to ensure we can write to card
|
||||
if (em4x70_read_id()) {
|
||||
status = 1;
|
||||
|
||||
// Write each crypto block
|
||||
for (int i = 0; i < 6; i++) {
|
||||
|
||||
uint16_t key_word = (etd->crypt_key[(i * 2) + 1] << 8) + etd->crypt_key[i * 2];
|
||||
// Write each word, abort if any failure occurs
|
||||
if (write(key_word, 9 - i) != PM3_SUCCESS) {
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// TODO: Ideally here we would perform a test authentication
|
||||
// to ensure the new key was written correctly. This is
|
||||
// what the datasheet suggests. We can't do that until
|
||||
// we have the crypto algorithm implemented.
|
||||
}
|
||||
}
|
||||
|
||||
StopTicks();
|
||||
lf_finalize();
|
||||
reply_ng(CMD_LF_EM4X70_WRITEKEY, status, tag.data, sizeof(tag.data));
|
||||
}
|
||||
|
|
|
@ -17,6 +17,16 @@ typedef struct {
|
|||
uint8_t data[32];
|
||||
} em4x70_tag_t;
|
||||
|
||||
typedef enum {
|
||||
RISING_EDGE,
|
||||
FALLING_EDGE
|
||||
} edge_detection_t;
|
||||
|
||||
void em4x70_info(em4x70_data_t *etd);
|
||||
void em4x70_write(em4x70_data_t *etd);
|
||||
void em4x70_unlock(em4x70_data_t *etd);
|
||||
void em4x70_auth(em4x70_data_t *etd);
|
||||
void em4x70_write_pin(em4x70_data_t *etd);
|
||||
void em4x70_write_key(em4x70_data_t *etd);
|
||||
|
||||
#endif /* EM4x70_H */
|
||||
|
|
|
@ -408,9 +408,9 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) {
|
|||
// Tag CSN
|
||||
|
||||
uint8_t *modulated_response = NULL;
|
||||
int modulated_response_size = 0;
|
||||
int modulated_response_size;
|
||||
uint8_t *trace_data = NULL;
|
||||
int trace_data_size = 0;
|
||||
int trace_data_size;
|
||||
|
||||
// Respond SOF -- takes 1 bytes
|
||||
uint8_t *resp_sof = BigBuf_malloc(1);
|
||||
|
@ -498,10 +498,9 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) {
|
|||
|
||||
bool button_pressed = false;
|
||||
uint8_t cmd, options, block;
|
||||
int len = 0;
|
||||
int len, kc_attempt = 0;
|
||||
bool exit_loop = false;
|
||||
bool using_kc = false;
|
||||
int kc_attempt = 0;
|
||||
|
||||
while (exit_loop == false) {
|
||||
WDT_HIT();
|
||||
|
@ -1364,6 +1363,8 @@ static bool select_iclass_tag_ex(picopass_hdr *hdr, bool use_credit_key, uint32_
|
|||
return false;
|
||||
|
||||
memcpy(hdr->epurse, resp, sizeof(hdr->epurse));
|
||||
|
||||
if (status)
|
||||
*status |= FLAG_ICLASS_CC;
|
||||
|
||||
} else {
|
||||
|
@ -1469,16 +1470,9 @@ void ReaderIClass(uint8_t flags) {
|
|||
switch_off();
|
||||
}
|
||||
|
||||
// used with function select_and_auth (cmdhficlass.c)
|
||||
// which needs to authenticate before doing more things like read/write
|
||||
// selects and authenticate to a card, sends back div_key and mac to client.
|
||||
void iClass_Authentication(uint8_t *msg) {
|
||||
}
|
||||
|
||||
bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out) {
|
||||
|
||||
uint8_t cmd_check[9] = { ICLASS_CMD_CHECK };
|
||||
uint8_t div_key[8] = {0};
|
||||
uint8_t mac[4] = {0};
|
||||
uint8_t resp_auth[4] = {0};
|
||||
uint8_t ccnr[12] = {0};
|
||||
|
@ -1495,6 +1489,8 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint
|
|||
memcpy(cmd_check + 1, payload->key, 8);
|
||||
|
||||
} else {
|
||||
|
||||
uint8_t div_key[8] = {0};
|
||||
if (payload->use_raw)
|
||||
memcpy(div_key, payload->key, 8);
|
||||
else
|
||||
|
@ -1792,7 +1788,7 @@ static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac,
|
|||
|
||||
uint8_t resp[10] = {0};
|
||||
uint32_t eof_time = 0, start_time = 0;
|
||||
bool isOK = iclass_send_cmd_with_retries(write, sizeof(write), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_UPDATE, &eof_time);
|
||||
bool isOK = iclass_send_cmd_with_retries(write, write_len, resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_UPDATE, &eof_time);
|
||||
if (isOK == false) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1833,7 +1829,7 @@ void iClass_WriteBlock(uint8_t *msg) {
|
|||
// select tag.
|
||||
uint32_t eof_time = 0;
|
||||
picopass_hdr hdr = {0};
|
||||
bool res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time);
|
||||
uint8_t res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time);
|
||||
if (res == false) {
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include "pm3_cmd.h"
|
||||
|
||||
void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string);
|
||||
void ReaderIClass(uint8_t arg0);
|
||||
void ReaderIClass(uint8_t flags);
|
||||
|
||||
void iClass_WriteBlock(uint8_t *msg);
|
||||
void iClass_Dump(uint8_t *msg);
|
||||
|
@ -29,7 +29,6 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
|
|||
void iclass_simulate(uint8_t sim_type, uint8_t num_csns, bool send_reply, uint8_t *datain, uint8_t *dataout, uint16_t *dataoutlen);
|
||||
|
||||
void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain);
|
||||
void iClass_Authentication(uint8_t *bytes);
|
||||
bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out);
|
||||
|
||||
void iClass_ReadBlock(uint8_t *msg);
|
||||
|
|
|
@ -133,35 +133,30 @@ static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ;
|
|||
|
||||
void printHf14aConfig(void) {
|
||||
DbpString(_CYAN_("HF 14a config"));
|
||||
Dbprintf(" [a] Anticol override....%i %s%s%s",
|
||||
hf14aconfig.forceanticol,
|
||||
(hf14aconfig.forceanticol == 0) ? "( " _GREEN_("No") " ) follow standard " : "",
|
||||
(hf14aconfig.forceanticol == 1) ? "( " _RED_("Yes") " ) always do anticol" : "",
|
||||
(hf14aconfig.forceanticol == 2) ? "( " _RED_("Yes") " ) always skip anticol" : ""
|
||||
Dbprintf(" [a] Anticol override....%s%s%s",
|
||||
(hf14aconfig.forceanticol == 0) ? _GREEN_("std") " : follow standard " : "",
|
||||
(hf14aconfig.forceanticol == 1) ? _RED_("force") " : always do anticol" : "",
|
||||
(hf14aconfig.forceanticol == 2) ? _RED_("skip") " : always skip anticol" : ""
|
||||
);
|
||||
Dbprintf(" [b] BCC override........%i %s%s%s",
|
||||
hf14aconfig.forcebcc,
|
||||
(hf14aconfig.forcebcc == 0) ? "( " _GREEN_("No") " ) follow standard" : "",
|
||||
(hf14aconfig.forcebcc == 1) ? "( " _RED_("Yes") " ) always do CL2" : "",
|
||||
(hf14aconfig.forcebcc == 2) ? "( " _RED_("Yes") " ) always use card BCC" : ""
|
||||
Dbprintf(" [b] BCC override........%s%s%s",
|
||||
(hf14aconfig.forcebcc == 0) ? _GREEN_("std") " : follow standard" : "",
|
||||
(hf14aconfig.forcebcc == 1) ? _RED_("fix") " : fix bad BCC" : "",
|
||||
(hf14aconfig.forcebcc == 2) ? _RED_("ignore") " : ignore bad BCC, always use card BCC" : ""
|
||||
);
|
||||
Dbprintf(" [2] CL2 override........%i %s%s%s",
|
||||
hf14aconfig.forcecl2,
|
||||
(hf14aconfig.forcecl2 == 0) ? "( " _GREEN_("No") " ) follow standard" : "",
|
||||
(hf14aconfig.forcecl2 == 1) ? "( " _RED_("Yes") " ) always do CL2" : "",
|
||||
(hf14aconfig.forcecl2 == 2) ? "( " _RED_("Yes") " ) always skip CL2" : ""
|
||||
Dbprintf(" [2] CL2 override........%s%s%s",
|
||||
(hf14aconfig.forcecl2 == 0) ? _GREEN_("std") " : follow standard" : "",
|
||||
(hf14aconfig.forcecl2 == 1) ? _RED_("force") " : always do CL2" : "",
|
||||
(hf14aconfig.forcecl2 == 2) ? _RED_("skip") " : always skip CL2" : ""
|
||||
);
|
||||
Dbprintf(" [3] CL3 override........%i %s%s%s",
|
||||
hf14aconfig.forcecl3,
|
||||
(hf14aconfig.forcecl3 == 0) ? "( " _GREEN_("No") " ) follow standard" : "",
|
||||
(hf14aconfig.forcecl3 == 1) ? "( " _RED_("Yes") " ) always do CL3" : "",
|
||||
(hf14aconfig.forcecl3 == 2) ? "( " _RED_("Yes") " ) always skip CL3" : ""
|
||||
Dbprintf(" [3] CL3 override........%s%s%s",
|
||||
(hf14aconfig.forcecl3 == 0) ? _GREEN_("std") " : follow standard" : "",
|
||||
(hf14aconfig.forcecl3 == 1) ? _RED_("force") " : always do CL3" : "",
|
||||
(hf14aconfig.forcecl3 == 2) ? _RED_("skip") " : always skip CL3" : ""
|
||||
);
|
||||
Dbprintf(" [r] RATS override.......%i %s%s%s",
|
||||
hf14aconfig.forcerats,
|
||||
(hf14aconfig.forcerats == 0) ? "( " _GREEN_("No") " ) follow standard " : "",
|
||||
(hf14aconfig.forcerats == 1) ? "( " _RED_("Yes") " ) always do RATS" : "",
|
||||
(hf14aconfig.forcerats == 2) ? "( " _RED_("Yes") " ) always skip RATS" : ""
|
||||
Dbprintf(" [r] RATS override.......%s%s%s",
|
||||
(hf14aconfig.forcerats == 0) ? _GREEN_("std") " : follow standard " : "",
|
||||
(hf14aconfig.forcerats == 1) ? _RED_("force") " : always do RATS" : "",
|
||||
(hf14aconfig.forcerats == 2) ? _RED_("skip") " : always skip RATS" : ""
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -921,18 +916,25 @@ bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len) {
|
|||
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
(void)b;
|
||||
|
||||
uint16_t check = 0;
|
||||
|
||||
uint8_t flip = 0;
|
||||
uint16_t checker = 0;
|
||||
for (;;) {
|
||||
if (check == 4000) {
|
||||
// if (BUTTON_PRESS() || data_available())
|
||||
WDT_HIT();
|
||||
if (flip == 3) {
|
||||
if (data_available())
|
||||
return false;
|
||||
|
||||
flip = 0;
|
||||
}
|
||||
|
||||
if (checker >= 3000) {
|
||||
if (BUTTON_PRESS())
|
||||
return false;
|
||||
|
||||
check = 0;
|
||||
WDT_HIT();
|
||||
flip++;
|
||||
checker = 0;
|
||||
}
|
||||
++check;
|
||||
++checker;
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
@ -1340,7 +1342,6 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data, uint8_t
|
|||
LED_A_ON();
|
||||
|
||||
// main loop
|
||||
//for (;;) {
|
||||
bool finished = false;
|
||||
bool button_pushed = BUTTON_PRESS();
|
||||
while (!button_pushed && !finished) {
|
||||
|
|
|
@ -129,7 +129,7 @@ RAMFUNC bool MillerDecoding(uint8_t bit, uint32_t non_real_time);
|
|||
RAMFUNC int ManchesterDecoding(uint8_t bit, uint16_t offset, uint32_t non_real_time);
|
||||
|
||||
void RAMFUNC SniffIso14443a(uint8_t param);
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data, uint8_t numReads);
|
||||
void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data, uint8_t exitAfterNReads);
|
||||
bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_info_t **responses, uint32_t *cuid, uint32_t counters[3], uint8_t tearings[3], uint8_t *pages);
|
||||
bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len);
|
||||
void iso14443a_antifuzz(uint32_t flags);
|
||||
|
|
|
@ -1201,7 +1201,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
|||
|
||||
if (Handle14443bSamplesFromTag(ci, cq)) {
|
||||
|
||||
*eof_time = dma_start_time + (samples) - DELAY_TAG_TO_ARM; // end of EOF
|
||||
*eof_time = GetCountSspClkDelta(dma_start_time) - (DELAY_TAG_TO_ARM * 128); // end of EOF
|
||||
|
||||
if (Demod.len > Demod.max_len) {
|
||||
ret = -2; // overflow
|
||||
|
@ -1209,7 +1209,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
|||
break;
|
||||
}
|
||||
|
||||
if (samples > timeout && Demod.state < DEMOD_PHASE_REF_TRAINING) {
|
||||
if (((GetCountSspClkDelta(dma_start_time) >> 7) > timeout) && Demod.state < DEMOD_PHASE_REF_TRAINING) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
@ -1225,7 +1225,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
|||
- (Demod.len * (8 + 2)) // time for byte transfers
|
||||
- (12) // time for SOF transfer
|
||||
- (12); // time for EOF transfer
|
||||
LogTrace(Demod.output, Demod.len, (sof_time * 4), (*eof_time * 4), NULL, false);
|
||||
LogTrace(Demod.output, Demod.len, sof_time, *eof_time, NULL, false);
|
||||
}
|
||||
return Demod.len;
|
||||
}
|
||||
|
@ -1400,7 +1400,7 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
|||
CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time);
|
||||
|
||||
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER;
|
||||
int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, ISO14443B_READER_TIMEOUT, &eof_time);
|
||||
int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, iso14b_timeout, &eof_time);
|
||||
FpgaDisableTracing();
|
||||
|
||||
uint8_t *data_bytes = (uint8_t *) rxdata;
|
||||
|
|
|
@ -1602,7 +1602,7 @@ void ReaderIso15693(uint32_t parameter) {
|
|||
reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0);
|
||||
} else {
|
||||
|
||||
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||
//start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||
|
||||
// we should do a better check than this
|
||||
if (recvlen >= 12) {
|
||||
|
@ -1686,7 +1686,7 @@ void SimTagIso15693(uint8_t *uid) {
|
|||
enum { NO_FIELD, IDLE, ACTIVATED, SELECTED, HALTED } chip_state = NO_FIELD;
|
||||
|
||||
bool button_pressed = false;
|
||||
int vHf = 0; // in mV
|
||||
int vHf; // in mV
|
||||
|
||||
bool exit_loop = false;
|
||||
while (exit_loop == false) {
|
||||
|
@ -1719,7 +1719,6 @@ void SimTagIso15693(uint8_t *uid) {
|
|||
int cmd_len = GetIso15693CommandFromReader(cmd, sizeof(cmd), &reader_eof_time);
|
||||
if (cmd_len < 0) {
|
||||
button_pressed = true;
|
||||
exit_loop = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1845,9 +1844,8 @@ void BruteforceIso15693Afi(uint32_t speed) {
|
|||
|
||||
int datalen = 5;
|
||||
uint32_t eof_time = 0;
|
||||
uint32_t start_time = GetCountSspClk();
|
||||
int recvlen = SendDataTag(data, datalen, true, speed, recv, sizeof(recv), 0, ISO15693_READER_TIMEOUT, &eof_time);
|
||||
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||
uint32_t start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
|
|
|
@ -154,7 +154,7 @@ t55xx_configurations_t T55xx_Timing = {
|
|||
{ 29 * 8, 17 * 8, 15 * 8, 40 * 8, 15 * 8, 0, 0 }, // Leading 0
|
||||
{ 29 * 8, 17 * 8, 15 * 8, 31 * 8, 15 * 8, 47 * 8, 63 * 8 } // 1 of 4
|
||||
#else
|
||||
// PM3OTHER or like offical repo
|
||||
// PM3GENERIC or like official repo
|
||||
{ 31 * 8, 20 * 8, 18 * 8, 50 * 8, 15 * 8, 0, 0 }, // Default Fixed
|
||||
{ 31 * 8, 20 * 8, 18 * 8, 50 * 8, 15 * 8, 0, 0 }, // Long Leading Ref.
|
||||
{ 31 * 8, 20 * 8, 18 * 8, 40 * 8, 15 * 8, 0, 0 }, // Leading 0
|
||||
|
@ -1009,7 +1009,7 @@ void CmdFSKsimTAGEx(uint8_t fchigh, uint8_t fclow, uint8_t separator, uint8_t cl
|
|||
|
||||
WDT_HIT();
|
||||
|
||||
Dbprintf("Simulating with fcHigh: %d, fcLow: %d, clk: %d, STT: %d, n: %d", fchigh, fclow, clk, separator, n);
|
||||
Dbprintf("FSK simulating with rf/%d, fc high %d, fc low %d, STT %d, n %d", clk, fchigh, fclow, separator, n);
|
||||
|
||||
if (ledcontrol) LED_A_ON();
|
||||
SimulateTagLowFrequencyEx(n, 0, ledcontrol, numcycles);
|
||||
|
@ -1122,10 +1122,10 @@ void CmdASKsimTAG(uint8_t encoding, uint8_t invert, uint8_t separator, uint8_t c
|
|||
|
||||
WDT_HIT();
|
||||
|
||||
Dbprintf("Simulating with clk: %d, invert: %d, encoding: %s (%d), separator: %d, n: %d"
|
||||
Dbprintf("ASK simulating with rf/%d, invert %d, encoding %s (%d), separator %d, n %d"
|
||||
, clk
|
||||
, invert
|
||||
, (encoding == 2) ? "BI" : (encoding == 1) ? "ASK" : "RAW"
|
||||
, (encoding == 2) ? "ASK/BI" : (encoding == 1) ? "ASK/MAN" : "RAW/MAN"
|
||||
, encoding
|
||||
, separator
|
||||
, n
|
||||
|
@ -1176,7 +1176,7 @@ void CmdPSKsimTAG(uint8_t carrier, uint8_t invert, uint8_t clk, uint16_t size, u
|
|||
|
||||
WDT_HIT();
|
||||
|
||||
Dbprintf("Simulating with Carrier: %d, clk: %d, invert: %d, n: %d", carrier, clk, invert, n);
|
||||
Dbprintf("PSK simulating with rf/%d, fc/%d, invert %d, n %d", clk, carrier, invert, n);
|
||||
|
||||
if (ledcontrol) LED_A_ON();
|
||||
SimulateTagLowFrequency(n, 0, ledcontrol);
|
||||
|
@ -1220,7 +1220,7 @@ void CmdNRZsimTAG(uint8_t invert, uint8_t separator, uint8_t clk, uint16_t size,
|
|||
|
||||
WDT_HIT();
|
||||
|
||||
Dbprintf("Simulating with clk: %d, invert: %d, separator: %d, n: %d"
|
||||
Dbprintf("NRZ simulating with rf/%d, invert %d, separator %d, n %d"
|
||||
, clk
|
||||
, invert
|
||||
, separator
|
||||
|
@ -1251,21 +1251,14 @@ int lf_hid_watch(int findone, uint32_t *high, uint32_t *low) {
|
|||
BigBuf_Clear_keep_EM();
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
uint16_t interval = 0;
|
||||
while (BUTTON_PRESS() == false) {
|
||||
for (;;) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
// cancel w usb command.
|
||||
if (interval == 4000) {
|
||||
if (data_available()) {
|
||||
if (data_available() || BUTTON_PRESS()) {
|
||||
res = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
interval = 0;
|
||||
} else {
|
||||
interval++;
|
||||
}
|
||||
|
||||
DoAcquisition_default(-1, false);
|
||||
|
||||
|
@ -1360,21 +1353,14 @@ int lf_awid_watch(int findone, uint32_t *high, uint32_t *low) {
|
|||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
uint16_t interval = 0;
|
||||
while (BUTTON_PRESS() == false) {
|
||||
for (;;) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
// cancel w usb command.
|
||||
if (interval == 4000) {
|
||||
if (data_available()) {
|
||||
if (data_available() || BUTTON_PRESS()) {
|
||||
res = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
interval = 0;
|
||||
} else {
|
||||
interval++;
|
||||
}
|
||||
|
||||
DoAcquisition_default(-1, false);
|
||||
// FSK demodulator
|
||||
|
@ -1465,20 +1451,13 @@ int lf_em410x_watch(int findone, uint32_t *high, uint64_t *low) {
|
|||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
uint16_t interval = 0;
|
||||
while (BUTTON_PRESS() == false) {
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
// cancel w usb command.
|
||||
if (interval == 4000) {
|
||||
if (data_available()) {
|
||||
if (data_available() || BUTTON_PRESS()) {
|
||||
res = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
interval = 0;
|
||||
} else {
|
||||
interval++;
|
||||
}
|
||||
|
||||
DoAcquisition_default(-1, false);
|
||||
|
||||
|
@ -1541,21 +1520,14 @@ int lf_io_watch(int findone, uint32_t *high, uint32_t *low) {
|
|||
LFSetupFPGAForADC(LF_DIVISOR_125, true);
|
||||
|
||||
int res = PM3_SUCCESS;
|
||||
uint16_t interval = 0;
|
||||
while (BUTTON_PRESS() == false) {
|
||||
for (;;) {
|
||||
|
||||
WDT_HIT();
|
||||
|
||||
// cancel w usb command.
|
||||
if (interval == 4000) {
|
||||
if (data_available()) {
|
||||
if (data_available() || BUTTON_PRESS()) {
|
||||
res = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
interval = 0;
|
||||
} else {
|
||||
interval++;
|
||||
}
|
||||
|
||||
DoAcquisition_default(-1, false);
|
||||
|
||||
|
|
|
@ -73,11 +73,11 @@ void printSamples(void) {
|
|||
void setSamplingConfig(sample_config *sc) {
|
||||
|
||||
// decimation (1-8) how many bits of adc sample value to save
|
||||
if (sc->decimation > 0 && sc->decimation < 8)
|
||||
if (sc->decimation > 0 && sc->decimation < 9)
|
||||
config.decimation = sc->decimation;
|
||||
|
||||
// bits per sample (1-8)
|
||||
if (sc->bits_per_sample > 0 && sc->bits_per_sample < 8)
|
||||
if (sc->bits_per_sample > 0 && sc->bits_per_sample < 9)
|
||||
config.bits_per_sample = sc->bits_per_sample;
|
||||
|
||||
//
|
||||
|
|
|
@ -662,9 +662,11 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain) {
|
|||
|
||||
// Return 1 if the nonce is invalid else return 0
|
||||
static int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, uint8_t *parity) {
|
||||
return ((oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1, 16))) & \
|
||||
(oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1, 8))) & \
|
||||
(oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1, 0)))) ? 1 : 0;
|
||||
return (
|
||||
(oddparity8((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity8((NtEnc >> 24) & 0xFF) ^ BIT(Ks1, 16))) && \
|
||||
(oddparity8((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity8((NtEnc >> 16) & 0xFF) ^ BIT(Ks1, 8))) && \
|
||||
(oddparity8((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity8((NtEnc >> 8) & 0xFF) ^ BIT(Ks1, 0)))
|
||||
) ? 1 : 0;
|
||||
}
|
||||
|
||||
void MifareAcquireNonces(uint32_t arg0, uint32_t flags) {
|
||||
|
@ -696,7 +698,7 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) {
|
|||
|
||||
LED_C_ON();
|
||||
|
||||
for (uint16_t i = 0; i <= PM3_CMD_DATA_SIZE - 4; i += 4) {
|
||||
while (num_nonces < PM3_CMD_DATA_SIZE / 4) {
|
||||
|
||||
// Test if the action was cancelled
|
||||
if (BUTTON_PRESS()) {
|
||||
|
@ -746,18 +748,14 @@ void MifareAcquireNonces(uint32_t arg0, uint32_t flags) {
|
|||
continue;
|
||||
}
|
||||
|
||||
num_nonces++;
|
||||
|
||||
// Save the tag nonce (nt)
|
||||
buf[i] = answer[0];
|
||||
buf[i + 1] = answer[1];
|
||||
buf[i + 2] = answer[2];
|
||||
buf[i + 3] = answer[3];
|
||||
memcpy(buf + num_nonces * 4, answer, 4);
|
||||
num_nonces++;
|
||||
}
|
||||
|
||||
LED_C_OFF();
|
||||
LED_B_ON();
|
||||
reply_old(CMD_ACK, isOK, cuid, num_nonces - 1, buf, sizeof(buf));
|
||||
reply_old(CMD_ACK, isOK, cuid, num_nonces, buf, sizeof(buf));
|
||||
LED_B_OFF();
|
||||
|
||||
if (DBGLEVEL >= 3) DbpString("AcquireNonces finished");
|
||||
|
@ -826,7 +824,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
if (!have_uid) { // need a full select cycle to get the uid first
|
||||
iso14a_card_select_t card_info;
|
||||
if (!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (ALL)");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireEncryptedNonces: Can't select card (ALL)");
|
||||
continue;
|
||||
}
|
||||
switch (card_info.uidlen) {
|
||||
|
@ -845,7 +843,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
have_uid = true;
|
||||
} else { // no need for anticollision. We can directly select the card
|
||||
if (!iso14443a_fast_select_card(uid, cascade_levels)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Can't select card (UID)");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireEncryptedNonces: Can't select card (UID)");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -855,7 +853,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
|
||||
uint32_t nt1;
|
||||
if (mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1, NULL)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Auth1 error");
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireEncryptedNonces: Auth1 error");
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -866,7 +864,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
CHK_TIMEOUT();
|
||||
|
||||
if (len != 4) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireNonces: Auth2 error len=%d", len);
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("AcquireEncryptedNonces: Auth2 error len=%d", len);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1015,6 +1013,7 @@ void MifareNested(uint8_t blockNo, uint8_t keyType, uint8_t targetBlockNo, uint8
|
|||
}
|
||||
}
|
||||
|
||||
if (rtr > 1)
|
||||
davg = (davg + (rtr - 1) / 2) / (rtr - 1);
|
||||
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf("rtr=%d isOK=%d min=%d max=%d avg=%d, delta_time=%d", rtr, isOK, dmin, dmax, davg, delta_time);
|
||||
|
@ -2714,8 +2713,8 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) {
|
|||
//
|
||||
// Tear-off attack against MFU.
|
||||
// - Moebius et al
|
||||
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) {
|
||||
uint8_t blockNo = arg0;
|
||||
void MifareU_Otp_Tearoff(uint8_t blno, uint32_t tearoff_time, uint8_t *datain) {
|
||||
uint8_t blockNo = blno;
|
||||
uint8_t data_fullwrite[4] = {0x00};
|
||||
uint8_t data_testwrite[4] = {0x00};
|
||||
memcpy(data_fullwrite, datain, 4);
|
||||
|
|
|
@ -63,6 +63,6 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain);
|
|||
void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain);
|
||||
|
||||
// Tear-off test for MFU
|
||||
void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain);
|
||||
void MifareU_Otp_Tearoff(uint8_t blno, uint32_t tearoff_time, uint8_t *datain);
|
||||
void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time, uint8_t *datain);
|
||||
#endif
|
||||
|
|
|
@ -68,9 +68,12 @@ uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data) {
|
|||
|
||||
// send X byte basic commands
|
||||
int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t *answer, uint8_t *answer_parity, uint32_t *timing) {
|
||||
|
||||
uint8_t dcmd[data_size + 3];
|
||||
dcmd[0] = cmd;
|
||||
if (data_size > 0)
|
||||
memcpy(dcmd + 1, data, data_size);
|
||||
|
||||
AddCrc14A(dcmd, data_size + 1);
|
||||
ReaderTransmit(dcmd, sizeof(dcmd), timing);
|
||||
int len = ReaderReceive(answer, answer_parity);
|
||||
|
|
|
@ -14,14 +14,16 @@
|
|||
|
||||
#include "proxmark3_arm.h"
|
||||
#include "appmain.h"
|
||||
#ifndef WITH_NO_COMPRESSION
|
||||
#include "lz4.h"
|
||||
#endif
|
||||
#include "BigBuf.h"
|
||||
#include "string.h"
|
||||
|
||||
extern struct common_area common_area;
|
||||
extern char __data_src_start__, __data_start__, __data_end__, __bss_start__, __bss_end__;
|
||||
|
||||
|
||||
#ifndef WITH_NO_COMPRESSION
|
||||
static void uncompress_data_section(void) {
|
||||
int avail_in;
|
||||
memcpy(&avail_in, &__data_src_start__, sizeof(int));
|
||||
|
@ -35,6 +37,7 @@ static void uncompress_data_section(void) {
|
|||
// save the size of the compressed data section
|
||||
common_area.arg1 = avail_in;
|
||||
}
|
||||
#endif
|
||||
|
||||
void __attribute__((section(".startos"))) Vector(void);
|
||||
void Vector(void) {
|
||||
|
@ -48,12 +51,20 @@ void Vector(void) {
|
|||
}
|
||||
common_area.flags.osimage_present = 1;
|
||||
|
||||
/* Set up data segment: Copy from flash to ram */
|
||||
#ifdef WITH_NO_COMPRESSION
|
||||
char *data_src = &__data_src_start__;
|
||||
char *data_dst = &__data_start__;
|
||||
char *data_end = &__data_end__;
|
||||
while (data_dst < data_end) *data_dst++ = *data_src++;
|
||||
#else
|
||||
uncompress_data_section();
|
||||
#endif
|
||||
|
||||
/* Set up (that is: clear) BSS. */
|
||||
char *dst = &__bss_start__;
|
||||
char *end = &__bss_end__;
|
||||
while (dst < end) *dst++ = 0;
|
||||
char *bss_dst = &__bss_start__;
|
||||
char *bss_end = &__bss_end__;
|
||||
while (bss_dst < bss_end) *bss_dst++ = 0;
|
||||
|
||||
AppMain();
|
||||
}
|
||||
|
|
|
@ -121,7 +121,7 @@ uint16_t usart_rxdata_available(void) {
|
|||
|
||||
uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
||||
if (len == 0) return 0;
|
||||
uint32_t nbBytesRcv = 0;
|
||||
uint32_t bytes_rcv = 0;
|
||||
uint32_t try = 0;
|
||||
// uint32_t highest_observed_try = 0;
|
||||
// Empirical max try observed: 3000000 / USART_BAUD_RATE
|
||||
|
@ -146,7 +146,7 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
|||
}
|
||||
len -= packetSize;
|
||||
while (packetSize--) {
|
||||
data[nbBytesRcv++] = us_rxfifo[us_rxfifo_low++];
|
||||
data[bytes_rcv++] = us_rxfifo[us_rxfifo_low++];
|
||||
if (us_rxfifo_low == sizeof(us_rxfifo))
|
||||
us_rxfifo_low = 0;
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ uint32_t usart_read_ng(uint8_t *data, size_t len) {
|
|||
}
|
||||
// highest_observed_try = MAX(highest_observed_try, try);
|
||||
// Dbprintf_usb("Dbg USART max observed try %i", highest_observed_try);
|
||||
return nbBytesRcv;
|
||||
return bytes_rcv;
|
||||
}
|
||||
|
||||
// transfer from device to client
|
||||
|
|
|
@ -32,7 +32,7 @@ find_package(PkgConfig)
|
|||
if (NOT SKIPQT EQUAL 1)
|
||||
if(APPLE AND EXISTS /usr/local/opt/qt5)
|
||||
# Homebrew installs Qt5 (up to at least 5.11.0) in
|
||||
# /usr/local/qt5. Ensure that it can be found by CMake
|
||||
# /usr/local/opt/qt5. Ensure that it can be found by CMake
|
||||
# since it is not in the default /usr/local prefix.
|
||||
# Add it to PATHS so that it doesn't override the
|
||||
# CMAKE_PREFIX_PATH environment variable.
|
||||
|
@ -40,6 +40,16 @@ if (NOT SKIPQT EQUAL 1)
|
|||
# e.g. find_package(Qt5Core ${QT_FIND_PACKAGE_OPTIONS})
|
||||
list(APPEND QT_FIND_PACKAGE_OPTIONS PATHS /usr/local/opt/qt5)
|
||||
endif(APPLE AND EXISTS /usr/local/opt/qt5)
|
||||
if(APPLE AND EXISTS /opt/homebrew/opt/qt5)
|
||||
# Homebrew on Apple Silicon installs Qt5 in
|
||||
# /opt/homebrew/opt/qt5. Ensure that it can be found by CMake
|
||||
# since it is not in the default /usr/local prefix.
|
||||
# Add it to PATHS so that it doesn't override the
|
||||
# CMAKE_PREFIX_PATH environment variable.
|
||||
# QT_FIND_PACKAGE_OPTIONS should be passed to find_package,
|
||||
# e.g. find_package(Qt5Core ${QT_FIND_PACKAGE_OPTIONS})
|
||||
list(APPEND QT_FIND_PACKAGE_OPTIONS PATHS /opt/homebrew/opt/qt5)
|
||||
endif(APPLE AND EXISTS /opt/homebrew/opt/qt5)
|
||||
set(QT_PACKAGELIST
|
||||
Qt5Core
|
||||
Qt5Widgets
|
||||
|
@ -77,12 +87,12 @@ endif (EMBED_READLINE OR EMBED_BZIP2)
|
|||
|
||||
if (NOT SKIPREADLINE EQUAL 1)
|
||||
if (APPLE)
|
||||
find_path(READLINE_INCLUDE_DIRS readline/readline.h /usr/local/opt/readline/include /opt/local/include /opt/include /usr/local/include /usr/include NO_DEFAULT_PATH)
|
||||
find_library(READLINE_LIBRARIES readline /usr/local/opt/readline/lib /opt/local/lib /opt/lib /usr/local/lib /usr/lib NO_DEFAULT_PATH)
|
||||
find_path(READLINE_INCLUDE_DIRS readline/readline.h /usr/local/opt/readline/include /opt/local/include /opt/include /usr/local/include /usr/include /opt/homebrew/opt/readline/include NO_DEFAULT_PATH)
|
||||
find_library(READLINE_LIBRARIES readline /usr/local/opt/readline/lib /opt/local/lib /opt/lib /usr/local/lib /usr/lib /opt/homebrew/opt/readline/lib NO_DEFAULT_PATH)
|
||||
endif (APPLE)
|
||||
if (EMBED_READLINE)
|
||||
ExternalProject_Add(ncurses
|
||||
URL http://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.0.tar.gz
|
||||
URL http://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.1.tar.gz
|
||||
PREFIX deps/ncurses
|
||||
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/ncurses
|
||||
CONFIGURE_COMMAND ./configure CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} --host=arm --disable-database --with-fallbacks=ansi-generic,ansi-mini,color_xterm,dtterm,dumb,Eterm,Eterm-256color,Eterm-88color,eterm-color,gnome,gnome-256color,guru,hurd,iTerm.app,konsole,konsole-16color,konsole-256color,konsole-base,konsole-linux,konsole-solaris,konsole-vt100,kterm,kterm-color,linux,linux-16color,linux-basic,mac,mlterm,mlterm-256color,mrxvt,mrxvt-256color,mterm,mterm-ansi,mvterm,nsterm,nsterm-16color,nsterm-256color,pty,putty,putty-256color,putty-vt100,rxvt,rxvt-16color,rxvt-256color,rxvt-88color,rxvt-basic,rxvt-color,screen,screen-16color,screen-256color,simpleterm,st-16color,st-256color,st52,st52-color,stv52,tt,tt52,unknown,vt100,vt102,vte,vte-256color,xterm,xterm-16color,xterm-256color,xterm-88color,xterm-basic,xterm-bold,xterm-color,xterm-utf8,xterm-vt220,xterm-vt52,xterm1,xtermc,xtermm --enable-termcap --without-ada --without-debug --without-dlsym --without-gpm --without-develop --without-tests --without-cxx-binding --with-termlib
|
||||
|
@ -94,7 +104,7 @@ if (NOT SKIPREADLINE EQUAL 1)
|
|||
ExternalProject_Add_StepTargets(ncurses configure build install)
|
||||
|
||||
ExternalProject_Add(readline
|
||||
URL ftp://ftp.gnu.org/gnu/readline/readline-7.0.tar.gz
|
||||
URL ftp://ftp.gnu.org/gnu/readline/readline-8.1.tar.gz
|
||||
PREFIX deps/readline
|
||||
DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/readline
|
||||
CONFIGURE_COMMAND ./configure CC=${CMAKE_C_COMPILER} CXX=${CMAKE_CXX_COMPILER} LD=${CMAKE_C_COMPILER} AR=${CMAKE_AR} RANLIB=${CMAKE_RANLIB} ${CFLAGS_EXTERNAL_LIB} --host=arm --enable-static
|
||||
|
@ -228,9 +238,11 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdhf15.c
|
||||
${PM3_ROOT}/client/src/cmdhfcryptorf.c
|
||||
${PM3_ROOT}/client/src/cmdhfepa.c
|
||||
${PM3_ROOT}/client/src/cmdhfemrtd.c
|
||||
${PM3_ROOT}/client/src/cmdhffelica.c
|
||||
${PM3_ROOT}/client/src/cmdhffido.c
|
||||
${PM3_ROOT}/client/src/cmdhficlass.c
|
||||
${PM3_ROOT}/client/src/cmdhfjooki.c
|
||||
${PM3_ROOT}/client/src/cmdhflegic.c
|
||||
${PM3_ROOT}/client/src/cmdhflist.c
|
||||
${PM3_ROOT}/client/src/cmdhflto.c
|
||||
|
|
|
@ -17,8 +17,7 @@ vpath %.dic dictionaries
|
|||
OBJDIR = obj
|
||||
|
||||
ifeq ($(platform),Darwin)
|
||||
# cf brew info qt: qt not symlinked anymore
|
||||
PKG_CONFIG_ENV := PKG_CONFIG_PATH=/usr/local/opt/qt/lib/pkgconfig
|
||||
PKG_CONFIG_ENV := PKG_CONFIG_PATH=$(BREW_PREFIX)/opt/qt/lib/pkgconfig
|
||||
endif
|
||||
|
||||
###################
|
||||
|
@ -115,21 +114,6 @@ STATICLIBS += $(HARDNESTEDLIB)
|
|||
LDLIBS +=$(HARDNESTEDLIBLD)
|
||||
INCLUDES += $(HARDNESTEDLIBINC)
|
||||
|
||||
## Jansson
|
||||
ifneq ($(SKIPJANSSONSYSTEM),1)
|
||||
JANSSONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags jansson 2>/dev/null)
|
||||
JANSSONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs jansson 2>/dev/null)
|
||||
ifneq ($(JANSSONLDLIBS),)
|
||||
JANSSONLIB =
|
||||
JANSSONLIBLD = $(JANSSONLDLIBS)
|
||||
JANSSONLIBINC = $(JANSSONINCLUDES)
|
||||
JANSSON_FOUND = 1
|
||||
endif
|
||||
endif
|
||||
STATICLIBS += $(JANSSONLIB)
|
||||
LDLIBS += $(JANSSONLIBLD)
|
||||
INCLUDES += $(JANSSONLIBINC)
|
||||
|
||||
## Lua
|
||||
ifneq ($(SKIPLUASYSTEM),1)
|
||||
LUAINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags lua5.2 2>/dev/null)
|
||||
|
@ -145,6 +129,22 @@ STATICLIBS += $(LUALIB)
|
|||
LDLIBS += $(LUALIBLD)
|
||||
INCLUDES += $(LUALIBINC)
|
||||
|
||||
## Jansson
|
||||
# Jansson section needs to be after Lua to avoid interferences on macOS if a locally incompatible Lua was available, see PR 1155
|
||||
ifneq ($(SKIPJANSSONSYSTEM),1)
|
||||
JANSSONINCLUDES = $(shell $(PKG_CONFIG_ENV) pkg-config --cflags jansson 2>/dev/null)
|
||||
JANSSONLDLIBS = $(shell $(PKG_CONFIG_ENV) pkg-config --libs jansson 2>/dev/null)
|
||||
ifneq ($(JANSSONLDLIBS),)
|
||||
JANSSONLIB =
|
||||
JANSSONLIBLD = $(JANSSONLDLIBS)
|
||||
JANSSONLIBINC = $(JANSSONINCLUDES)
|
||||
JANSSON_FOUND = 1
|
||||
endif
|
||||
endif
|
||||
STATICLIBS += $(JANSSONLIB)
|
||||
LDLIBS += $(JANSSONLIBLD)
|
||||
INCLUDES += $(JANSSONLIBINC)
|
||||
|
||||
## mbed TLS
|
||||
# system library cannot be used because it is compiled by default without CMAC support
|
||||
STATICLIBS += $(MBEDTLSLIB)
|
||||
|
@ -278,8 +278,8 @@ CXXINCLUDES += $(QTINCLUDES)
|
|||
## Readline
|
||||
ifneq ($(SKIPREADLINE),1)
|
||||
ifeq ($(platform),Darwin)
|
||||
LDLIBS += -L/usr/local/opt/readline/lib
|
||||
INCLUDES += -I/usr/local/opt/readline/include
|
||||
LDLIBS += -L$(BREW_PREFIX)/opt/readline/lib
|
||||
INCLUDES += -I$(BREW_PREFIX)/opt/readline/include
|
||||
endif
|
||||
LDLIBS += -lreadline
|
||||
READLINE_FOUND = 1
|
||||
|
@ -469,10 +469,12 @@ SRCS = aiddesfire.c \
|
|||
cmdhf15.c \
|
||||
cmdhfcryptorf.c \
|
||||
cmdhfepa.c \
|
||||
cmdhfemrtd.c \
|
||||
cmdhffelica.c \
|
||||
cmdhffido.c \
|
||||
cmdhficlass.c \
|
||||
cmdhflegic.c \
|
||||
cmdhfjooki.c \
|
||||
cmdhflist.c \
|
||||
cmdhflto.c \
|
||||
cmdhfmf.c \
|
||||
|
|
|
@ -106,6 +106,7 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/cmdhf15.c
|
||||
${PM3_ROOT}/client/src/cmdhfcryptorf.c
|
||||
${PM3_ROOT}/client/src/cmdhfepa.c
|
||||
${PM3_ROOT}/client/src/cmdhfemrtd.c
|
||||
${PM3_ROOT}/client/src/cmdhffelica.c
|
||||
${PM3_ROOT}/client/src/cmdhffido.c
|
||||
${PM3_ROOT}/client/src/cmdhficlass.c
|
||||
|
@ -126,9 +127,11 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/cmdlfawid.c
|
||||
${PM3_ROOT}/client/src/cmdlfcotag.c
|
||||
${PM3_ROOT}/client/src/cmdlfdestron.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x.c
|
||||
${PM3_ROOT}/client/src/cmdlfem.c
|
||||
${PM3_ROOT}/client/src/cmdlfem410x.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x05.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x70.c
|
||||
${PM3_ROOT}/client/src/cmdlffdxb.c
|
||||
${PM3_ROOT}/client/src/cmdlfgallagher.c
|
||||
${PM3_ROOT}/client/src/cmdlfguard.c
|
||||
|
|
|
@ -74,13 +74,13 @@ static bool OpenPm3(void) {
|
|||
jint Console(JNIEnv *env, jobject instance, jstring cmd_) {
|
||||
|
||||
if (!conn.run) {
|
||||
if (OpenPm3() && TestProxmark() == PM3_SUCCESS) {
|
||||
if (OpenPm3() && TestProxmark(session.current_device) == PM3_SUCCESS) {
|
||||
LOGD("Connected to device");
|
||||
PrintAndLogEx(SUCCESS, "Connected to device");
|
||||
} else {
|
||||
LOGD("Failed to connect to device");
|
||||
PrintAndLogEx(ERR, "Failed to connect to device");
|
||||
CloseProxmark();
|
||||
CloseProxmark(session.current_device);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,10 +110,10 @@ jboolean IsClientRunning(JNIEnv *env, jobject instance) {
|
|||
* */
|
||||
jboolean TestPm3(JNIEnv *env, jobject instance) {
|
||||
if (open() == false) {
|
||||
CloseProxmark();
|
||||
CloseProxmark(session.current_device);
|
||||
return false;
|
||||
}
|
||||
bool ret = (TestProxmark() == PM3_SUCCESS);
|
||||
bool ret = (TestProxmark(session.current_device) == PM3_SUCCESS);
|
||||
return (jboolean)(ret);
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ jboolean TestPm3(JNIEnv *env, jobject instance) {
|
|||
* stop pm3 client
|
||||
* */
|
||||
void ClosePm3(JNIEnv *env, jobject instance) {
|
||||
CloseProxmark();
|
||||
CloseProxmark(session.current_device);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
mem load -f mfc_default_keys --mfc
|
||||
mem load -f t55xx_default_pwds --t55xx
|
||||
mem load -f iclass_default_keys --iclass
|
||||
lf t55xx deviceconfig z p
|
||||
lf t55xx deviceconfig -z -p
|
||||
|
|
|
@ -14,10 +14,18 @@ add_library(pm3rrg_rdv4_amiibo STATIC
|
|||
if (NOT TARGET pm3rrg_rdv4_mbedtls)
|
||||
include(mbedtls.cmake)
|
||||
endif()
|
||||
|
||||
target_link_libraries(pm3rrg_rdv4_amiibo PRIVATE
|
||||
m
|
||||
pm3rrg_rdv4_mbedtls)
|
||||
target_include_directories(pm3rrg_rdv4_amiibo PRIVATE ../../include ../../common)
|
||||
target_include_directories(pm3rrg_rdv4_amiibo INTERFACE amiitool)
|
||||
|
||||
target_compile_options(pm3rrg_rdv4_amiibo PRIVATE -Wall -Werror -O3)
|
||||
set_property(TARGET pm3rrg_rdv4_amiibo PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_include_directories(pm3rrg_rdv4_amiibo PRIVATE amiitool
|
||||
../../common
|
||||
../../include
|
||||
../src
|
||||
jansson)
|
||||
|
||||
target_include_directories(pm3rrg_rdv4_amiibo INTERFACE amiitool)
|
|
@ -1,5 +1,5 @@
|
|||
MYSRCPATHS =
|
||||
MYINCLUDES = -I. -I.. -I../jansson -I../../../common -I../../../common/mbedtls -I../../../include
|
||||
MYINCLUDES = -I. -I.. -I../../../common -I../../../common/mbedtls -I../../../include -I../../src -I../../../include -I../jansson
|
||||
MYCFLAGS =
|
||||
MYDEFS =
|
||||
MYSRCS = \
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "md.h"
|
||||
#include "aes.h"
|
||||
#include "commonutil.h"
|
||||
#include "../src/fileutils.h"
|
||||
|
||||
#define HMAC_POS_DATA 0x008
|
||||
#define HMAC_POS_TAG 0x1B4
|
||||
|
@ -131,24 +132,29 @@ void nfc3d_amiibo_pack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *plain
|
|||
nfc3d_amiibo_internal_to_tag(cipher, tag);
|
||||
}
|
||||
|
||||
bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys, const char *path) {
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f) {
|
||||
bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys) {
|
||||
|
||||
#define amiboo_key_fn "key_retail.bin"
|
||||
|
||||
uint8_t *dump = NULL;
|
||||
size_t bytes_read = 0;
|
||||
if (loadFile_safe(amiboo_key_fn, "", (void **)&dump, &bytes_read) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(FAILED, "File: " _YELLOW_("%s") ": not found or locked.", amiboo_key_fn);
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t len = fread(amiiboKeys, sizeof(*amiiboKeys), 1, f);
|
||||
fclose(f);
|
||||
|
||||
if (len != sizeof(*amiiboKeys)) {
|
||||
if (bytes_read != sizeof(*amiiboKeys)) {
|
||||
free(dump);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((amiiboKeys->data.magicBytesSize > 16) ||
|
||||
(amiiboKeys->tag.magicBytesSize > 16)) {
|
||||
if ((amiiboKeys->data.magicBytesSize > 16) || (amiiboKeys->tag.magicBytesSize > 16)) {
|
||||
free(dump);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(amiiboKeys, dump, bytes_read);
|
||||
free(dump);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ typedef struct {
|
|||
|
||||
bool nfc3d_amiibo_unpack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *tag, uint8_t *plain);
|
||||
void nfc3d_amiibo_pack(const nfc3d_amiibo_keys *amiiboKeys, const uint8_t *plain, uint8_t *tag);
|
||||
bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys, const char *path);
|
||||
bool nfc3d_amiibo_load_keys(nfc3d_amiibo_keys *amiiboKeys);
|
||||
void nfc3d_amiibo_copy_app_data(const uint8_t *src, uint8_t *dst);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,15 +33,6 @@ void amiitool_usage(void) {
|
|||
);
|
||||
}
|
||||
|
||||
static bool LoadAmiikey(nfc3d_amiibo_keys keys, char *keyfile) {
|
||||
|
||||
if (!nfc3d_amiibo_load_keys(&keys, keyfile)) {
|
||||
PrintAndLogEx(ERR, "Could not load keys from '%s'", keyfile);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
self = argv[0];
|
||||
|
||||
|
|
|
@ -830,7 +830,7 @@ static void arg_date_errorfn(
|
|||
/* make argval NULL safe */
|
||||
argval = argval ? argval : "";
|
||||
|
||||
fprintf(fp, "%s: ", progname);
|
||||
fprintf(fp, "[!] %s: ", progname);
|
||||
switch (errorcode) {
|
||||
case EMINCOUNT:
|
||||
fputs("missing option ", fp);
|
||||
|
@ -846,11 +846,11 @@ static void arg_date_errorfn(
|
|||
struct tm tm;
|
||||
char buff[200];
|
||||
|
||||
fprintf(fp, "illegal timestamp format \"%s\"\n", argval);
|
||||
fprintf(fp, "[!] illegal timestamp format \"%s\"\n", argval);
|
||||
memset(&tm, 0, sizeof(tm));
|
||||
arg_strptime("1999-12-31 23:59:59", "%F %H:%M:%S", &tm);
|
||||
strftime(buff, sizeof(buff), parent->format, &tm);
|
||||
printf("correct format is \"%s\"\n", buff);
|
||||
printf("[+] correct format is \"%s\"\n", buff);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1442,7 +1442,7 @@ static void arg_dbl_errorfn(
|
|||
/* make argval NULL safe */
|
||||
argval = argval ? argval : "";
|
||||
|
||||
fprintf(fp, "%s: ", progname);
|
||||
fprintf(fp, "[!] %s: ", progname);
|
||||
switch (errorcode) {
|
||||
case EMINCOUNT:
|
||||
fputs("missing option ", fp);
|
||||
|
@ -1455,7 +1455,7 @@ static void arg_dbl_errorfn(
|
|||
break;
|
||||
|
||||
case EBADDOUBLE:
|
||||
fprintf(fp, "invalid argument \"%s\" to option ", argval);
|
||||
fprintf(fp, "[!] invalid argument \"%s\" to option ", argval);
|
||||
arg_print_option(fp, shortopts, longopts, datatype, "\n");
|
||||
break;
|
||||
}
|
||||
|
@ -1805,7 +1805,7 @@ static void arg_file_errorfn(
|
|||
/* make argval NULL safe */
|
||||
argval = argval ? argval : "";
|
||||
|
||||
fprintf(fp, "%s: ", progname);
|
||||
fprintf(fp, "[!] %s: ", progname);
|
||||
switch (errorcode) {
|
||||
case EMINCOUNT:
|
||||
fputs("missing option ", fp);
|
||||
|
@ -1818,7 +1818,7 @@ static void arg_file_errorfn(
|
|||
break;
|
||||
|
||||
default:
|
||||
fprintf(fp, "unknown error at \"%s\"\n", argval);
|
||||
fprintf(fp, "[!] unknown error at \"%s\"\n", argval);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2136,7 +2136,7 @@ static void arg_int_errorfn(
|
|||
/* make argval NULL safe */
|
||||
argval = argval ? argval : "";
|
||||
|
||||
fprintf(fp, "%s: ", progname);
|
||||
fprintf(fp, "[!] %s: ", progname);
|
||||
switch (errorcode) {
|
||||
case EMINCOUNT:
|
||||
fputs("missing option ", fp);
|
||||
|
@ -2149,7 +2149,7 @@ static void arg_int_errorfn(
|
|||
break;
|
||||
|
||||
case EBADINT:
|
||||
fprintf(fp, "invalid argument \"%s\" to option ", argval);
|
||||
fprintf(fp, "[!] invalid argument \"%s\" to option ", argval);
|
||||
arg_print_option(fp, shortopts, longopts, datatype, "\n");
|
||||
break;
|
||||
|
||||
|
@ -2394,7 +2394,7 @@ static void arg_u64_errorfn(
|
|||
/* make argval NULL safe */
|
||||
argval = argval ? argval : "";
|
||||
|
||||
fprintf(fp, "%s: ", progname);
|
||||
fprintf(fp, "[!] %s: ", progname);
|
||||
switch (errorcode) {
|
||||
case EMINCOUNT:
|
||||
fputs("missing option ", fp);
|
||||
|
@ -2407,7 +2407,7 @@ static void arg_u64_errorfn(
|
|||
break;
|
||||
|
||||
case EBADINT:
|
||||
fprintf(fp, "invalid argument \"%s\" to option ", argval);
|
||||
fprintf(fp, "[!] invalid argument \"%s\" to option ", argval);
|
||||
arg_print_option(fp, shortopts, longopts, datatype, "\n");
|
||||
break;
|
||||
|
||||
|
@ -2554,18 +2554,18 @@ static void arg_lit_errorfn(
|
|||
|
||||
switch (errorcode) {
|
||||
case EMINCOUNT:
|
||||
fprintf(fp, "%s: missing option ", progname);
|
||||
fprintf(fp, "[!] %s: missing option ", progname);
|
||||
arg_print_option(fp, shortopts, longopts, datatype, "\n");
|
||||
fprintf(fp, "\n");
|
||||
break;
|
||||
|
||||
case EMAXCOUNT:
|
||||
fprintf(fp, "%s: extraneous option ", progname);
|
||||
fprintf(fp, "[!] %s: extraneous option ", progname);
|
||||
arg_print_option(fp, shortopts, longopts, datatype, "\n");
|
||||
break;
|
||||
}
|
||||
|
||||
ARG_TRACE(("%s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp,
|
||||
ARG_TRACE(("[!] %s:errorfn(%p, %p, %d, %s, %s)\n", __FILE__, parent, fp,
|
||||
errorcode, argval, progname));
|
||||
}
|
||||
|
||||
|
@ -2859,7 +2859,7 @@ static void arg_rex_errorfn(struct arg_rex *parent,
|
|||
/* make argval NULL safe */
|
||||
argval = argval ? argval : "";
|
||||
|
||||
fprintf(fp, "%s: ", progname);
|
||||
fprintf(fp, "[!] %s: ", progname);
|
||||
switch (errorcode) {
|
||||
case EMINCOUNT:
|
||||
fputs("missing option ", fp);
|
||||
|
@ -3790,7 +3790,7 @@ static void arg_str_errorfn(
|
|||
/* make argval NULL safe */
|
||||
argval = argval ? argval : "";
|
||||
|
||||
fprintf(fp, "%s: ", progname);
|
||||
fprintf(fp, "[!] %s: ", progname);
|
||||
switch (errorcode) {
|
||||
case EMINCOUNT:
|
||||
fputs("missing option ", fp);
|
||||
|
|
|
@ -118,7 +118,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta
|
|||
if (nerrors > 0) {
|
||||
/* Display the error details contained in the arg_end struct.*/
|
||||
arg_print_errors(stdout, ((struct arg_end *)(ctx->argtable)[vargtableLen - 1]), ctx->programName);
|
||||
PrintAndLogEx(WARNING, "Try '%s --help' for more information.\n", ctx->programName);
|
||||
PrintAndLogEx(WARNING, "Try " _YELLOW_("'%s --help'") " for more information.\n", ctx->programName);
|
||||
fflush(stdout);
|
||||
return 3;
|
||||
}
|
||||
|
@ -269,15 +269,19 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
|||
return 0;
|
||||
}
|
||||
|
||||
// hexstr -> u64, w optional len input and default value fallback.
|
||||
// 0 = failed
|
||||
// 1 = OK
|
||||
// 3 = optional param - not set
|
||||
uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def) {
|
||||
uint64_t rv = 0;
|
||||
uint8_t data[8];
|
||||
int datalen = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), &datalen);
|
||||
if (res == 0 && datalen > 0) {
|
||||
for (uint8_t i = 0; i < datalen; i++) {
|
||||
uint8_t d[8];
|
||||
int dlen = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), d, sizeof(d), &dlen);
|
||||
if (res == 0 && dlen > 0) {
|
||||
for (uint8_t i = 0; i < dlen; i++) {
|
||||
rv <<= 8;
|
||||
rv |= data[i];
|
||||
rv |= d[i];
|
||||
}
|
||||
} else {
|
||||
rv = def;
|
||||
|
@ -285,4 +289,56 @@ uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_
|
|||
return rv;
|
||||
}
|
||||
|
||||
// hexstr -> u64, w optional len input and default value fallback.
|
||||
// 0 = failed
|
||||
// 1 = OK
|
||||
// 2 = wrong len param, use default
|
||||
// 3 = optional param, if fail, use default.
|
||||
int arg_get_u64_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint64_t def, uint64_t *out, uint8_t nlen, bool optional) {
|
||||
int n = 0;
|
||||
uint8_t d[nlen];
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), d, sizeof(d), &n);
|
||||
if (res == 0 && n == nlen) {
|
||||
uint64_t rv = 0;
|
||||
for (uint8_t i = 0; i < n; i++) {
|
||||
rv <<= 8;
|
||||
rv |= d[i];
|
||||
}
|
||||
*out = rv;
|
||||
return 1;
|
||||
} else if (res == 0 && n) {
|
||||
*out = def;
|
||||
return 2;
|
||||
} else if (res == 0 && n == 0 && optional) {
|
||||
*out = def;
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int arg_get_u32_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out) {
|
||||
return arg_get_u32_hexstr_def_nlen(ctx, paramnum, def, out, 4, false);
|
||||
}
|
||||
|
||||
int arg_get_u32_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out, uint8_t nlen, bool optional) {
|
||||
int n = 0;
|
||||
uint8_t d[nlen];
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), d, sizeof(d), &n);
|
||||
if (res == 0 && n == nlen) {
|
||||
uint32_t rv = 0;
|
||||
for (uint8_t i = 0; i < n; i++) {
|
||||
rv <<= 8;
|
||||
rv |= d[i];
|
||||
}
|
||||
*out = rv;
|
||||
return 1;
|
||||
} else if (res == 0 && n) {
|
||||
*out = def;
|
||||
return 2;
|
||||
} else if (res == 0 && n == 0 && optional) {
|
||||
*out = def;
|
||||
return 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,4 +68,13 @@ int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
|
|||
int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen);
|
||||
|
||||
uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def);
|
||||
int arg_get_u64_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint64_t def, uint64_t *out, uint8_t nlen, bool optional);
|
||||
int arg_get_u32_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out);
|
||||
int arg_get_u32_hexstr_def_nlen(CLIParserContext *ctx, uint8_t paramnum, uint32_t def, uint32_t *out, uint8_t nlen, bool optional);
|
||||
|
||||
#define CP_SUCCESS_OPTIONAL 1
|
||||
#define CP_SUCCESS 0
|
||||
#define CP_ENOPARAM -1
|
||||
#define CP_WRONGLEN -2
|
||||
|
||||
#endif
|
||||
|
|
|
@ -143,7 +143,7 @@ bitslice_test_nonces_t bitslice_test_nonces_NOSIMD;
|
|||
bitslice_test_nonces_t bitslice_test_nonces_dispatch;
|
||||
|
||||
#if defined (_WIN32)
|
||||
#define malloc_bitslice(x) __builtin_assume_aligned(_aligned_malloc((x), MAX_BITSLICES/8), MAX_BITSLICES/8)
|
||||
#define malloc_bitslice(x) __builtin_assume_aligned(_aligned_malloc((x), MAX_BITSLICES / 8), MAX_BITSLICES / 8)
|
||||
#define free_bitslice(x) _aligned_free(x)
|
||||
#elif defined (__APPLE__)
|
||||
static void *malloc_bitslice(size_t x) {
|
||||
|
@ -156,7 +156,7 @@ static void *malloc_bitslice(size_t x) {
|
|||
}
|
||||
#define free_bitslice(x) free(x)
|
||||
#else
|
||||
#define malloc_bitslice(x) memalign(MAX_BITSLICES/8, (x))
|
||||
#define malloc_bitslice(x) memalign(MAX_BITSLICES / 8, (x))
|
||||
#define free_bitslice(x) free(x)
|
||||
#endif
|
||||
|
||||
|
@ -559,6 +559,10 @@ void SetSIMDInstr(SIMDExecInstr instr) {
|
|||
static SIMDExecInstr GetSIMDInstr(void) {
|
||||
SIMDExecInstr instr;
|
||||
|
||||
#if defined(COMPILER_HAS_SIMD)
|
||||
__builtin_cpu_init();
|
||||
#endif
|
||||
|
||||
#if defined(COMPILER_HAS_SIMD_AVX512)
|
||||
if (__builtin_cpu_supports("avx512f"))
|
||||
instr = SIMD_AVX512;
|
||||
|
|
|
@ -465,7 +465,8 @@ float brute_force_benchmark(void) {
|
|||
|
||||
free(test_candidates[0].states[ODD_STATE]);
|
||||
free(test_candidates[0].states[EVEN_STATE]);
|
||||
|
||||
test_candidates[0].len[ODD_STATE] = 0;
|
||||
test_candidates[0].len[EVEN_STATE] = 0;
|
||||
return bf_rate;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
typedef struct guess_sum_a8 {
|
||||
float prob;
|
||||
uint64_t num_states;
|
||||
uint8_t sum_a8_idx;
|
||||
uint16_t sum_a8_idx;
|
||||
} guess_sum_a8_t;
|
||||
|
||||
typedef struct noncelistentry {
|
||||
|
@ -40,7 +40,7 @@ typedef struct noncelist {
|
|||
guess_sum_a8_t sum_a8_guess[NUM_SUMS];
|
||||
bool sum_a8_guess_dirty;
|
||||
float expected_num_brute_force;
|
||||
uint8_t BitFlips[0x400];
|
||||
uint16_t BitFlips[0x400];
|
||||
uint32_t *states_bitarray[2];
|
||||
uint32_t num_states_bitarray[2];
|
||||
bool all_bitflips_dirty[2];
|
||||
|
|
|
@ -372,10 +372,11 @@ static void precalculate_bit0_bitflip_bitarrays(uint8_t const bitflip, uint16_t
|
|||
for (odd_even_t odd_even = EVEN_STATE; odd_even <= ODD_STATE; odd_even++) {
|
||||
count[odd_even] = count_states(test_bitarray[odd_even]);
|
||||
if (count[odd_even] != 1 << 24) {
|
||||
printf("Writing %u possible %s states for bitflip property %03x (%d (%1.2f%%) states eliminated)\n",
|
||||
printf("Writing %u possible %s states for bitflip property %03x (%u (%1.2f%%) states eliminated)\n",
|
||||
count[odd_even],
|
||||
odd_even == EVEN_STATE ? "even" : "odd",
|
||||
bitflip, (1 << 24) - count[odd_even],
|
||||
bitflip,
|
||||
(1 << 24) - count[odd_even],
|
||||
(float)((1 << 24) - count[odd_even]) / (1 << 24) * 100.0);
|
||||
#ifndef TEST_RUN
|
||||
write_bitflips_file(odd_even, bitflip, sum_a0, test_bitarray[odd_even], count[odd_even]);
|
||||
|
@ -399,10 +400,11 @@ static void precalculate_bit0_bitflip_bitarrays(uint8_t const bitflip, uint16_t
|
|||
}
|
||||
count[odd_even] = count_states(test_bitarray_2nd);
|
||||
if (count[odd_even] != 1 << 24) {
|
||||
printf("Writing %u possible %s states for bitflip property %03x (%d (%1.2f%%) states eliminated)\n",
|
||||
printf("Writing %u possible %s states for bitflip property %03x (%u (%1.2f%%) states eliminated)\n",
|
||||
count[odd_even],
|
||||
odd_even == EVEN_STATE ? "even" : "odd",
|
||||
bitflip | BITFLIP_2ND_BYTE, (1 << 24) - count[odd_even],
|
||||
bitflip | BITFLIP_2ND_BYTE,
|
||||
(1 << 24) - count[odd_even],
|
||||
(float)((1 << 24) - count[odd_even]) / (1 << 24) * 100.0);
|
||||
#ifndef TEST_RUN
|
||||
write_bitflips_file(odd_even, bitflip | BITFLIP_2ND_BYTE, sum_a0, test_bitarray_2nd, count[odd_even]);
|
||||
|
@ -484,10 +486,11 @@ static void precalculate_bit0_bitflip_bitarrays(uint8_t const bitflip, uint16_t
|
|||
for (odd_even_t odd_even = EVEN_STATE; odd_even <= ODD_STATE; odd_even++) {
|
||||
count[odd_even] = count_states(test_not_bitarray[odd_even]);
|
||||
if (count[odd_even] != 1 << 24) {
|
||||
printf("Writing %u possible %s states for bitflip property %03x (%d (%1.2f%%) states eliminated)\n",
|
||||
printf("Writing %u possible %s states for bitflip property %03x (%u (%1.2f%%) states eliminated)\n",
|
||||
count[odd_even],
|
||||
odd_even == EVEN_STATE ? "even" : "odd",
|
||||
bitflip | 0x100, (1 << 24) - count[odd_even],
|
||||
bitflip | 0x100,
|
||||
(1 << 24) - count[odd_even],
|
||||
(float)((1 << 24) - count[odd_even]) / (1 << 24) * 100.0);
|
||||
#ifndef TEST_RUN
|
||||
write_bitflips_file(odd_even, bitflip | 0x100, sum_a0, test_not_bitarray[odd_even], count[odd_even]);
|
||||
|
@ -511,10 +514,11 @@ static void precalculate_bit0_bitflip_bitarrays(uint8_t const bitflip, uint16_t
|
|||
}
|
||||
count[odd_even] = count_states(test_bitarray_2nd);
|
||||
if (count[odd_even] != 1 << 24) {
|
||||
printf("Writing %u possible %s states for bitflip property %03x (%d (%1.2f%%) states eliminated)\n",
|
||||
printf("Writing %u possible %s states for bitflip property %03x (%u (%1.2f%%) states eliminated)\n",
|
||||
count[odd_even],
|
||||
odd_even == EVEN_STATE ? "even" : "odd",
|
||||
bitflip | 0x100 | BITFLIP_2ND_BYTE, (1 << 24) - count[odd_even],
|
||||
bitflip | 0x100 | BITFLIP_2ND_BYTE,
|
||||
(1 << 24) - count[odd_even],
|
||||
(float)((1 << 24) - count[odd_even]) / (1 << 24) * 100.0);
|
||||
#ifndef TEST_RUN
|
||||
write_bitflips_file(odd_even, bitflip | 0x100 | BITFLIP_2ND_BYTE, sum_a0, test_bitarray_2nd, count[odd_even]);
|
||||
|
@ -532,7 +536,6 @@ static void precalculate_bit0_bitflip_bitarrays(uint8_t const bitflip, uint16_t
|
|||
free_bitarray(test_not_bitarray[EVEN_STATE]);
|
||||
free_bitarray(test_bitarray[ODD_STATE]);
|
||||
free_bitarray(test_bitarray[EVEN_STATE]);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -1284,3 +1284,12 @@ AABAFFCC7612
|
|||
#
|
||||
534F4C415249
|
||||
534f4c303232
|
||||
#
|
||||
# Nespresso, smart card
|
||||
# key-gen algo, these keys are for one card
|
||||
ff9a84635bd2
|
||||
6f30126ee7e4
|
||||
6039abb101bb
|
||||
f1a1239a4487
|
||||
#
|
||||
b882fd4a9f78
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
43464F494D48504E4C4359454E528841 #NHIF
|
||||
6AC292FAA1315B4D858AB3A3D7D5933A
|
||||
404142434445464748494a4b4c4d4e4f
|
||||
3112B738D8862CCD34302EB299AAB456 # Gallagher AES (https://pastebin.com/GkbGLz8r)
|
||||
00112233445566778899aabbccddeeff
|
||||
2b7e151628aed2a6abf7158809cf4f3c
|
||||
fbeed618357133667c85e08f7236a8de
|
||||
|
|
|
@ -27,6 +27,8 @@ A5B4C3D2
|
|||
00434343
|
||||
44B44CAE
|
||||
88661858
|
||||
# MKF fobs
|
||||
E9920427
|
||||
# paxton bullit?
|
||||
575F4F4B
|
||||
#
|
||||
|
|
|
@ -32,4 +32,4 @@ rm $2
|
|||
echo "hf mf eclr" >> $2
|
||||
echo "hf mf eload" $1 >> $2
|
||||
echo "hf mf ekeyprn" >> $2
|
||||
echo "hf mf sim u" `cat $1.eml | (read -n 8 uid; echo $uid)` >> $2
|
||||
echo "hf mf sim -u" `cat $1.eml | (read -n 8 uid; echo $uid)` >> $2
|
||||
|
|
|
@ -6,7 +6,7 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = 'Martin Holst Swende'
|
||||
version = 'v1.0.2'
|
||||
version = 'v1.0.3'
|
||||
desc = [[
|
||||
This script takes a dumpfile from 'hf mf dump' and converts it to a format that can be used
|
||||
by the emulator
|
||||
|
@ -46,7 +46,7 @@ end
|
|||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
print('[!!] ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, err
|
||||
end
|
||||
|
@ -115,8 +115,7 @@ local function main(args)
|
|||
|
||||
local dumpdata = readdump(infile)
|
||||
-- The hex-data is now in ascii-format,
|
||||
if dumpdata == NIL then return oops('Dumpfle not loaded') end
|
||||
|
||||
if dumpdata == nil then return oops('Dumpfle not loaded') end
|
||||
|
||||
-- But first, check the uid
|
||||
local uid = string.sub(dumpdata, 1, 8)
|
||||
|
@ -124,8 +123,7 @@ local function main(args)
|
|||
|
||||
-- Format some linebreaks
|
||||
dumpdata = convert_to_emulform(dumpdata)
|
||||
if dumpdata == NIL then return oops('Dumpfle not loaded') end
|
||||
|
||||
if dumpdata == nil then return oops('Dumpfle not loaded') end
|
||||
|
||||
local outfile = io.open(output, 'w')
|
||||
if outfile == nil then
|
||||
|
@ -134,7 +132,7 @@ local function main(args)
|
|||
|
||||
outfile:write(dumpdata:lower())
|
||||
io.close(outfile)
|
||||
print(('Wrote an emulator-dump to the file %s'):format(output))
|
||||
print(('[+] Wrote an emulator-dump to the file %s'):format(output))
|
||||
end
|
||||
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = 'Martin Holst Swende'
|
||||
version = 'v1.0.2'
|
||||
version = 'v1.0.3'
|
||||
desc =[[
|
||||
This script takes a dumpfile and produces a html based dump, which is a
|
||||
bit more easily analyzed.
|
||||
|
@ -45,7 +45,7 @@ end
|
|||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
print('[!!] ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, err
|
||||
end
|
||||
|
@ -76,7 +76,7 @@ local function main(args)
|
|||
local filename, err = dumplib.convert_bin_to_html(input,output, 16)
|
||||
if err then return oops(err) end
|
||||
|
||||
print(('Wrote a HTML dump to the file %s'):format(filename))
|
||||
print(('[+] Wrote a HTML dump to the file %s'):format(filename))
|
||||
end
|
||||
|
||||
--[[
|
||||
|
|
|
@ -5,7 +5,7 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = 'Iceman'
|
||||
version = 'v1.0.2'
|
||||
version = 'v1.0.3'
|
||||
desc =[[
|
||||
This script takes an dumpfile in EML (ASCII) format and converts it to the PM3 dumpbin file to be used with `hf mf restore`
|
||||
]]
|
||||
|
@ -40,7 +40,7 @@ end
|
|||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
print('[!!] ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, err
|
||||
end
|
||||
|
@ -82,7 +82,7 @@ local function main(args)
|
|||
local filename, err = dumplib.convert_eml_to_bin(input,output)
|
||||
if err then return oops(err) end
|
||||
|
||||
ExitMsg(('Wrote a BIN dump to the file %s'):format(filename))
|
||||
ExitMsg(('[+] Wrote a BIN dump to the file %s'):format(filename))
|
||||
end
|
||||
|
||||
main(args)
|
||||
|
|
|
@ -7,7 +7,7 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = 'Martin Holst Swende'
|
||||
version = 'v1.0.2'
|
||||
version = 'v1.0.3'
|
||||
desc = [[
|
||||
This script takes a dumpfile on EML (ASCII) format and produces a html based dump, which is a
|
||||
bit more easily analyzed.
|
||||
|
@ -44,7 +44,7 @@ end
|
|||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
print('[!!] ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, err
|
||||
end
|
||||
|
@ -75,7 +75,7 @@ local function main(args)
|
|||
local filename, err = dumplib.convert_eml_to_html(input,output)
|
||||
if err then return oops(err) end
|
||||
|
||||
print(('Wrote a HTML dump to the file %s'):format(filename))
|
||||
print(('[+] Wrote a HTML dump to the file %s'):format(filename))
|
||||
end
|
||||
|
||||
--[[
|
||||
|
|
|
@ -6,16 +6,16 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = "Martin Holst Swende \n @Marshmellow \n @iceman"
|
||||
version = 'v1.0.2'
|
||||
version = 'v1.0.4'
|
||||
desc =[[
|
||||
This script takes a dumpfile from 'hf mfu dump' and converts it to a format that can be used
|
||||
by the emulator
|
||||
]]
|
||||
example = [[
|
||||
script run hf_mfu_dumptoemulator -i dumpdata-foobar.bin
|
||||
script run data_mfu_bin2eml -i dumpdata-foobar.bin
|
||||
]]
|
||||
usage = [[
|
||||
script run hf_mfu_dumptoemulator [-i <file>] [-o <file>]
|
||||
script run data_mfu_bin2eml [-i <file>] [-o <file>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h This help
|
||||
|
@ -43,7 +43,7 @@ end
|
|||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
print('[!!] ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, err
|
||||
end
|
||||
|
@ -133,7 +133,7 @@ local function main(args)
|
|||
|
||||
outfile:write(dumpdata:lower())
|
||||
io.close(outfile)
|
||||
print(('Wrote an emulator-dump to the file %s'):format(output))
|
||||
print(('[+] Wrote an emulator-dump to the file %s'):format(output))
|
||||
end
|
||||
|
||||
--[[
|
|
@ -582,14 +582,14 @@ function writeToTag(tag)
|
|||
-- write pm3-buffer to Tag
|
||||
for i=1, WriteBytes do
|
||||
if (i > 7) then
|
||||
cmd = ("hf legic wrbl o %02x d %s "):format(i-1, padString(bytes[i]))
|
||||
cmd = ("hf legic wrbl -o %d -d %s "):format(i-1, padString(bytes[i]))
|
||||
print(acgreen..cmd..acoff)
|
||||
core.console(cmd)
|
||||
core.clearCommandBuffer()
|
||||
elseif (i == 7) then
|
||||
if (writeDCF) then
|
||||
-- write DCF in reverse order (requires 'mosci-patch')
|
||||
cmd = ('hf legic wrbl o 05 d %s%s'):format(padString(bytes[i-1]), padString(bytes[i]))
|
||||
cmd = ('hf legic wrbl -o 5 -d %s%s'):format(padString(bytes[i-1]), padString(bytes[i]))
|
||||
print(acgreen..cmd..acoff)
|
||||
core.console(cmd)
|
||||
core.clearCommandBuffer()
|
||||
|
@ -704,13 +704,32 @@ function writeFile(bytes, filename)
|
|||
return true
|
||||
end
|
||||
|
||||
function getRandomTempName()
|
||||
local upperCase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
local lowerCase = "abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
local characterSet = upperCase .. lowerCase
|
||||
|
||||
local keyLength = 8
|
||||
local output = ""
|
||||
|
||||
for i = 1, keyLength do
|
||||
local rand = math.random(#characterSet)
|
||||
output = output .. string.sub(characterSet, rand, rand)
|
||||
end
|
||||
|
||||
output = "hf-legic-temp-" .. output
|
||||
|
||||
return output
|
||||
end
|
||||
|
||||
---
|
||||
-- read from pm3 into virtual-tag
|
||||
function readFromPM3()
|
||||
local tag, bytes, infile
|
||||
--infile="legic.temp"
|
||||
infile=os.tmpname()
|
||||
core.console("hf legic dump f "..infile)
|
||||
infile=getRandomTempName()
|
||||
core.console("hf legic dump -f "..infile)
|
||||
tag=readFile(infile..".bin")
|
||||
os.remove(infile)
|
||||
os.remove(infile..".bin")
|
||||
|
|
|
@ -456,7 +456,7 @@ local function writeToTag(plainBytes)
|
|||
-- write data to file
|
||||
if (writeOutputBytes(bytes, "hf-legic-UID-dump.bin")) then
|
||||
-- write pm3-buffer to Tag
|
||||
cmd = ('hf legic restore f hf-legic-UID-dump')
|
||||
cmd = ('hf legic restore -f hf-legic-UID-dump')
|
||||
core.console(cmd)
|
||||
end
|
||||
end
|
||||
|
@ -530,13 +530,13 @@ local function main(args)
|
|||
res = res .."\ncreated clone_dump from\n\t"..infile.." crc: "..oldcrc.."\ndump_file:"
|
||||
res = res .."\n\t"..outfile.." crc: "..string.sub(newcrc, -2)
|
||||
res = res .."\nyou may load the new file with:"
|
||||
res = res ..ansicolors.yellow.."hf legic eload f "..outfile..ansicolors.reset
|
||||
res = res ..ansicolors.yellow.."hf legic eload -f "..outfile..ansicolors.reset
|
||||
res = res .."\n\nif you don't write to tag immediately ('-w' switch) you will need to recalculate each segmentCRC"
|
||||
res = res .."\nafter writing this dump to a tag!"
|
||||
res = res .."\n\na segmentCRC gets calculated over MCD,MSN0..3, Segment-Header0..3"
|
||||
res = res .."\ne.g. (based on Segment00 of the data from "..infile.."):"
|
||||
res = res .."\n"
|
||||
res = res ..ansicolors.yellow.."hf legic crc d "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26].." u "..newcrc.." c 8"..ansicolors.reset
|
||||
res = res ..ansicolors.yellow.."hf legic crc -d "..bytes[1]..bytes[2]..bytes[3]..bytes[4]..bytes[23]..bytes[24]..bytes[25]..bytes[26].." --mcc "..newcrc.." -t 8"..ansicolors.reset
|
||||
-- this can not be calculated without knowing the new MCD, MSN0..2
|
||||
print(res)
|
||||
end
|
||||
|
|
|
@ -99,7 +99,7 @@ local function nested(key,sak)
|
|||
else
|
||||
print("I don't know how many sectors there are on this type of card, defaulting to 16")
|
||||
end
|
||||
local cmd = string.format('hf mf nested %d 0 A %s d', typ, key)
|
||||
local cmd = string.format('hf mf nested -t %d -b 0 --keya -k %s --dumpkeys', typ, key)
|
||||
core.console(cmd)
|
||||
end
|
||||
|
||||
|
@ -123,7 +123,7 @@ local function dump_tag(uid, numsectors)
|
|||
|
||||
local dumpfile = 'hf-mf-'..uid..'-dump'
|
||||
|
||||
local dmp = ('hf mf dump %s f %s'):format(typ, dumpfile)
|
||||
local dmp = ('hf mf dump -t %s -f %s'):format(typ, dumpfile)
|
||||
core.console(dmp)
|
||||
|
||||
-- Save the global args, those are *our* arguments
|
||||
|
|
|
@ -14,7 +14,7 @@ This script will generate 'hf mf wrbl' commands for each block to format a Mifar
|
|||
Alla datablocks gets 0x00
|
||||
As default the script sets the keys A/B to 0xFFFFFFFFFFFF
|
||||
and the access bytes will become 0x78,0x77,0x88
|
||||
The GDB will become 0x00
|
||||
The GPB will become 0x00
|
||||
|
||||
The script will skip the manufactoring block 0.
|
||||
]]
|
||||
|
@ -169,7 +169,7 @@ local function main(args)
|
|||
GetCardInfo()
|
||||
|
||||
-- Show info
|
||||
print( string.format('Estimating number of blocks: %d', numBlocks))
|
||||
print( string.format('Estimating number of blocks: %d', numBlocks + 1))
|
||||
print( string.format('Old key: %s', OldKey))
|
||||
print( string.format('New key: %s', NewKey))
|
||||
print( string.format('New Access: %s', Accessbytes))
|
||||
|
|
|
@ -147,7 +147,7 @@ local function main(args)
|
|||
|
||||
--Trying to find the other keys
|
||||
if useNested then
|
||||
core.console( ('hf mf nested 1 0 A %s d'):format(keyA) )
|
||||
core.console( ('hf mf nested -t 1 -b 0 --keya -k %s --dumpkeys'):format(keyA) )
|
||||
end
|
||||
|
||||
core.clearCommandBuffer()
|
||||
|
|
|
@ -496,7 +496,7 @@ local function main(args)
|
|||
err = LoadEmulator(uid, blocks)
|
||||
if err then return oops(err) end
|
||||
core.clearCommandBuffer()
|
||||
print('The simulation is now prepared.\n --> run \"hf mf sim u '..uid..'\" <--')
|
||||
print('The simulation is now prepared.\n --> run \"hf mf sim -u '..uid..'\" <--')
|
||||
end
|
||||
end
|
||||
main(args)
|
||||
|
|
|
@ -99,10 +99,10 @@ local function main(args)
|
|||
local command = ''
|
||||
|
||||
if mftype == 'mfc' then
|
||||
command = 'hf 14a sim t 1 u %014x'
|
||||
command = 'hf 14a sim -t 1 -u %014x'
|
||||
msg('Bruteforcing Mifare Classic card numbers')
|
||||
elseif mftype == 'mfu' then
|
||||
command = 'hf 14a sim t 2 u %014x'
|
||||
command = 'hf 14a sim -t 2 -u %014x'
|
||||
msg('Bruteforcing Mifare Ultralight card numbers')
|
||||
else
|
||||
return print(usage)
|
||||
|
|
|
@ -44,8 +44,8 @@ arguments = [[
|
|||
-c read magic configuration
|
||||
-u UID (14 hexsymbols), set UID on tag
|
||||
-t tag type to impersonate
|
||||
1 = UL_EV1 48k
|
||||
2 = UL_EV1 128k
|
||||
1 = UL EV1 48b
|
||||
2 = UL EV1 128b
|
||||
3 = NTAG 210
|
||||
4 = NTAG 212
|
||||
5 = NTAG 213 (true)
|
||||
|
@ -60,7 +60,7 @@ arguments = [[
|
|||
-p password (8 hexsymbols), set password on tag.
|
||||
-a pack ( 4 hexsymbols), set pack on tag.
|
||||
-s signature data (64 hexsymbols), set signature data on tag.
|
||||
-o OTP data (8 hexsymbols), set one-time-pad data on tag.
|
||||
-o OTP data (8 hexsymbols), set `One-Time Programmable` data on tag.
|
||||
-v version data (16 hexsymbols), set version data on tag.
|
||||
-w wipe tag. You can specify password if the tag has been locked down. Fills tag with zeros and put default values for NTAG213 (like -t 5)
|
||||
-k pwd to use with the wipe option
|
||||
|
|
|
@ -4,26 +4,32 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = "Iceman"
|
||||
version = 'v1.0.2'
|
||||
version = 'v1.0.3'
|
||||
desc = [[
|
||||
This script tries to set UID on a mifare Ultralight magic card which either
|
||||
- answers to chinese backdoor commands
|
||||
- brickable magic tag (must write in one session)
|
||||
|
||||
It defaults to GEN1A type of uid changeable card.
|
||||
]]
|
||||
example = [[
|
||||
-- backdoor magic tag
|
||||
-- backdoor magic tag (gen1a)
|
||||
script run hf_mfu_setuid -u 11223344556677
|
||||
|
||||
-- brickable magic tag
|
||||
-- backdoor magic tag (gen1b)
|
||||
script run hf_mfu_setuid -b -u 11223344556677
|
||||
|
||||
-- brickable magic tag (gen2)
|
||||
script run hf_mfu_setuid -2 -u 11223344556677
|
||||
]]
|
||||
usage = [[
|
||||
script run hf_mfu_setuid [-h] [-b] [-u <uid>]
|
||||
script run hf_mfu_setuid [-h] [-b] [-2] [-u <uid>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
-u <UID> : UID (14 hexsymbols)
|
||||
-b : write to brickable magic tag
|
||||
-b : write to magic tag GEN1B
|
||||
-2 : write to brickable magic tag GEN2
|
||||
]]
|
||||
|
||||
local DEBUG = true
|
||||
|
@ -65,23 +71,33 @@ local function help()
|
|||
end
|
||||
--
|
||||
--- Set UID on magic command enabled
|
||||
function magicUID(b0, b1, b2)
|
||||
function magicUID(b0, b1, b2, isgen1a)
|
||||
|
||||
print('Using backdoor Magic tag function')
|
||||
if isgen1a then
|
||||
print('Using backdoor Magic tag (gen1a) function')
|
||||
else
|
||||
print('Using backdoor Magic tag (gen1b) function')
|
||||
end
|
||||
|
||||
-- write block 0
|
||||
core.console('hf 14a raw -k -a -b 7 40')
|
||||
if isgen1a then
|
||||
core.console('hf 14a raw -k -a 43')
|
||||
end
|
||||
core.console('hf 14a raw -c -a A200'..b0)
|
||||
|
||||
-- write block 1
|
||||
core.console('hf 14a raw -k -a -b 7 40')
|
||||
if isgen1a then
|
||||
core.console('hf 14a raw -k -a 43')
|
||||
end
|
||||
core.console('hf 14a raw -c -a A201'..b1)
|
||||
|
||||
-- write block 2
|
||||
core.console('hf 14a raw -k -a -b 7 40')
|
||||
if isgen1a then
|
||||
core.console('hf 14a raw -k -a 43')
|
||||
end
|
||||
core.console('hf 14a raw -c -a A202'..b2)
|
||||
end
|
||||
--
|
||||
|
@ -113,10 +129,11 @@ function main(args)
|
|||
local tagtype = 1
|
||||
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'hu:b') do
|
||||
for o, a in getopt.getopt(args, 'hu:b2') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'u' then uid = a end
|
||||
if o == 'b' then tagtype = 2 end
|
||||
if o == '2' then tagtype = 3 end
|
||||
end
|
||||
|
||||
-- uid string checks
|
||||
|
@ -137,10 +154,11 @@ function main(args)
|
|||
|
||||
core.clearCommandBuffer()
|
||||
|
||||
if tagtype == 2 then
|
||||
if tagtype == 3 then
|
||||
brickableUID(block0, block1, block2)
|
||||
else
|
||||
magicUID(block0, block1, block2)
|
||||
local is_gen1a = (tagtype == 1)
|
||||
magicUID(block0, block1, block2, is_gen1a)
|
||||
end
|
||||
|
||||
--halt
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
local getopt = require('getopt')
|
||||
local ansicolors = require('ansicolors')
|
||||
local utils = require('utils')
|
||||
|
||||
copyright = 'Copyright (c) 2019 IceSQL AB. All rights reserved.'
|
||||
author = 'Christian Herrmann'
|
||||
version = 'v1.0.1'
|
||||
version = 'v1.0.3'
|
||||
desc = [[
|
||||
This script initialize a Proxmark3 RDV4.0 with
|
||||
- uploading dictionary files to flashmem
|
||||
|
@ -82,10 +83,14 @@ function main(args)
|
|||
-- T55x7 Device configuration
|
||||
print('Configure T55XX device side to match RDV4')
|
||||
print(dash)
|
||||
core.console('lf t55xx deviceconfig r 0 a 29 b 17 c 15 d 47 e 15 p')
|
||||
core.console('lf t55xx deviceconfig r 1 a 29 b 17 c 18 d 50 e 15 p')
|
||||
core.console('lf t55xx deviceconfig r 2 a 29 b 17 c 18 d 40 e 15 p')
|
||||
core.console('lf t55xx deviceconfig r 3 a 29 b 17 c 15 d 31 e 15 f 47 g 63 p')
|
||||
core.console('lf t55xx deviceconfig --r0 -a 29 -b 17 -c 15 -d 47 -e 15 -p')
|
||||
utils.Sleep(1)
|
||||
core.console('lf t55xx deviceconfig --r1 -a 29 -b 17 -c 18 -d 50 -e 15 -p')
|
||||
utils.Sleep(1)
|
||||
core.console('lf t55xx deviceconfig --r2 -a 29 -b 17 -c 18 -d 40 -e 15 -p')
|
||||
utils.Sleep(1)
|
||||
core.console('lf t55xx deviceconfig --r3 -a 29 -b 17 -c 15 -d 31 -e 15 -f 47 -g 63 -p')
|
||||
utils.Sleep(1)
|
||||
|
||||
print('')
|
||||
print('')
|
||||
|
|
212
client/luascripts/lf_em4100_bulk.lua
Normal file
212
client/luascripts/lf_em4100_bulk.lua
Normal file
|
@ -0,0 +1,212 @@
|
|||
local getopt = require('getopt')
|
||||
local utils = require('utils')
|
||||
local ac = require('ansicolors')
|
||||
|
||||
copyright = ''
|
||||
author = "Christian Herrmann"
|
||||
version = 'v1.0.2'
|
||||
desc = [[
|
||||
Perform bulk EM410x enrollment of T5577 RFID tags. It keeps track of last card id used.
|
||||
If called with -s, this value resets "session".
|
||||
|
||||
if press <enter> it defaults to Y, which writes a ID.
|
||||
Any other input char will exit the script.
|
||||
|
||||
You can supply a password, which will set the config block / block 7 on the T5577.
|
||||
|
||||
The verify option will issue a 'lf em 410x reader' command, so you can manually verify
|
||||
that the write worked.
|
||||
|
||||
]]
|
||||
example = [[
|
||||
-- resets and start enrolling EM410x id 11CC334455
|
||||
script run lf_em4100_bulk.lua -s 11CC334455
|
||||
|
||||
-- continue enrolling from where last iteration
|
||||
script run lf_em4100_bulk.lua -c
|
||||
|
||||
-- reset and start enrolling from 11223344,
|
||||
-- protecting the tag with password 010203
|
||||
-- and verify the em id write.
|
||||
script run lf_em4100_bulk.lua -s 1122334455 -p 01020304 -v
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_en4100_bulk.lua [-h] [-c] [-p password] [-s <start cn>] [-v]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : this help
|
||||
-c : continue from last card number used
|
||||
-p : Password protecting the T5577.
|
||||
-s : starting card number
|
||||
-v : verify write by executing a `lf em 410x reader`
|
||||
]]
|
||||
|
||||
-- Some globals
|
||||
local DEBUG = false
|
||||
local ENROLL_STATUS_FN = 'lf_em4100_status.txt'
|
||||
---
|
||||
-- A debug printout-function
|
||||
local function dbg(args)
|
||||
if not DEBUG then return end
|
||||
if type(args) == 'table' then
|
||||
local i = 1
|
||||
while args[i] do
|
||||
dbg(args[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print('###', args)
|
||||
end
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
return nil, errr
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
local function help()
|
||||
print(copyright)
|
||||
print(author)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(ac.cyan..'Usage'..ac.reset)
|
||||
print(usage)
|
||||
print(ac.cyan..'Arguments'..ac.reset)
|
||||
print(arguments)
|
||||
print(ac.cyan..'Example usage'..ac.reset)
|
||||
print(example)
|
||||
end
|
||||
---
|
||||
-- Exit message
|
||||
local function exitMsg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print(msg)
|
||||
print()
|
||||
end
|
||||
---
|
||||
--
|
||||
local function readfile()
|
||||
local f = io.open(ENROLL_STATUS_FN, "r")
|
||||
if f == nil then
|
||||
return nil, string.format("Could not read file %s", ENROLL_STATUS_FN)
|
||||
end
|
||||
local t = f:read("*all")
|
||||
f:close()
|
||||
local cn_hi = tonumber(t:sub(1, 2), 16)
|
||||
local cn_low = tonumber(t:sub(3, 10), 16)
|
||||
print(('Using EM4100 ID '..ac.green..'%02X%08X'..ac.reset..' from `'..ac.yellow..'%s'..ac.reset..'`'):format(cn_hi, cn_low, ENROLL_STATUS_FN))
|
||||
return cn_hi, cn_low
|
||||
end
|
||||
---
|
||||
--
|
||||
local function writefile(cn_hi, cn_low)
|
||||
local f = io.open(ENROLL_STATUS_FN, "w")
|
||||
if f == nil then
|
||||
return nil, string.format("Could not write to file %s", ENROLL_STATUS_FN)
|
||||
end
|
||||
f:write(("%02X%08X\n"):format(cn_hi, cn_low))
|
||||
f:close()
|
||||
print(('Wrote EM4100 ID '..ac.green..'%02X%08X'..ac.reset..' to `'..ac.yellow..'%s'..ac.reset..'`'):format(cn_hi, cn_low, ENROLL_STATUS_FN))
|
||||
return true, 'Ok'
|
||||
end
|
||||
|
||||
---
|
||||
-- main
|
||||
local function main(args)
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print()
|
||||
|
||||
if #args == 0 then return help() end
|
||||
|
||||
local shall_verify = false
|
||||
local shall_continue = false
|
||||
local got_pwd = false
|
||||
local startid = ''
|
||||
local ipwd = ''
|
||||
|
||||
|
||||
for o, a in getopt.getopt(args, 'cp:s:hv') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'c' then shall_continue = true end
|
||||
if o == 's' then startid = a end
|
||||
if o == 'p' then
|
||||
ipwd = a
|
||||
got_pwd = true
|
||||
end
|
||||
if o == 'v' then shall_verify = true end
|
||||
end
|
||||
|
||||
-- if reset/start over, check -s
|
||||
if not shall_continue then
|
||||
if startid == nil then return oops('empty card number string') end
|
||||
if #startid == 0 then return oops('empty card number string') end
|
||||
if #startid ~= 10 then return oops('card number wrong length. Must be 5 hex bytes') end
|
||||
end
|
||||
|
||||
if got_pwd then
|
||||
if ipwd == nil then return oops('empty password') end
|
||||
if #ipwd == 0 then return oops('empty password') end
|
||||
if #ipwd ~= 8 then return oops('password wrong length. Must be 4 hex bytes') end
|
||||
end
|
||||
|
||||
core.console('clear')
|
||||
print(ac.red..'disable hints for less output'..ac.reset)
|
||||
core.console('pref set hint --off')
|
||||
print('')
|
||||
|
||||
local hi = tonumber(startid:sub(1, 2), 16)
|
||||
local low = tonumber(startid:sub(3, 10), 16)
|
||||
local pwd = tonumber(ipwd, 16)
|
||||
|
||||
if got_pwd then
|
||||
print(('Will protect T5577 with password '..ac.green..'%08X'..ac.reset):format(pwd))
|
||||
end
|
||||
|
||||
if shall_verify then
|
||||
print('Will verify write afterwards')
|
||||
end
|
||||
|
||||
if shall_continue then
|
||||
print('Continue enrolling from last save')
|
||||
hi, low = readfile()
|
||||
else
|
||||
print('reset & starting enrolling from refresh')
|
||||
end
|
||||
|
||||
local template = 'EM4100 ID '..ac.green..'%02X%08X'..ac.reset
|
||||
for i = low, low + 10000, 1 do
|
||||
print('')
|
||||
print( string.rep('--',20) )
|
||||
local msg = (template):format(hi, i)
|
||||
local ans = utils.input(msg, 'y'):lower()
|
||||
if ans == 'y' then
|
||||
core.console( ('lf em 410x clone --id %02X%08X'):format(hi, i) )
|
||||
-- print ( ('lf em 410x clone --id %02X%08X'):format(hi, i) )
|
||||
|
||||
if got_pwd then
|
||||
core.console('lf t55 detect')
|
||||
core.console(('lf t55 protect -n %08x'):format(pwd))
|
||||
end
|
||||
|
||||
if shall_verify then
|
||||
core.console('lf em 410x reader')
|
||||
end
|
||||
else
|
||||
print(ac.red..'User aborted'..ac.reset)
|
||||
low = i
|
||||
break
|
||||
end
|
||||
end
|
||||
writefile(hi, low)
|
||||
|
||||
print('enabling hints again')
|
||||
core.console('pref set hint --on')
|
||||
end
|
||||
|
||||
main(args)
|
104
client/luascripts/ntag_getsig.lua
Normal file
104
client/luascripts/ntag_getsig.lua
Normal file
|
@ -0,0 +1,104 @@
|
|||
local getopt = require('getopt')
|
||||
local lib14a = require('read14a')
|
||||
local cmds = require('commands')
|
||||
local ansicolors = require('ansicolors')
|
||||
|
||||
copyright = 'Copyright 2021 A. Ozkal, released under GPLv2+.'
|
||||
author = 'Ave'
|
||||
version = 'v1.0.0'
|
||||
desc = [[
|
||||
This script attempts to grab signatures from an NTAG or MFULEV1 card and print it in a machine parsable way
|
||||
]]
|
||||
example = [[
|
||||
script run ntag_getsig
|
||||
]]
|
||||
usage = [[
|
||||
script run ntag_getsig [-h]
|
||||
]]
|
||||
arguments = [[
|
||||
-h : This help
|
||||
]]
|
||||
|
||||
local function help()
|
||||
print(author)
|
||||
print(version)
|
||||
print(desc)
|
||||
print(ansicolors.cyan..'Usage'..ansicolors.reset)
|
||||
print(usage)
|
||||
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
|
||||
print(arguments)
|
||||
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
|
||||
print(example)
|
||||
end
|
||||
|
||||
-- Used to send raw data to the firmware to subsequently forward the data to the card.
|
||||
-- from mifareplus.lua
|
||||
local function sendRaw(rawdata, crc, power)
|
||||
-- print(("<sent>: %s"):format(rawdata))
|
||||
|
||||
local flags = lib14a.ISO14A_COMMAND.ISO14A_RAW
|
||||
if crc then
|
||||
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC
|
||||
end
|
||||
if power then
|
||||
flags = flags + lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT
|
||||
end
|
||||
|
||||
local command = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER,
|
||||
arg1 = flags, -- Send raw
|
||||
arg2 = string.len(rawdata) / 2, -- arg2 contains the length, which is half the length of the ASCII-string rawdata
|
||||
data = rawdata
|
||||
}
|
||||
local ignore_response = false
|
||||
local result, err = command:sendMIX(ignore_response)
|
||||
if result then
|
||||
--unpack the first 4 parts of the result as longs, and the last as an extremely long string to later be cut down based on arg1, the number of bytes returned
|
||||
local count,cmd,arg1,arg2,arg3,data = bin.unpack('LLLLH512',result)
|
||||
|
||||
returned_bytes = string.sub(data, 1, arg1 * 2)
|
||||
if #returned_bytes > 0 then
|
||||
-- print(("<recvd>: %s"):format(returned_bytes)) -- need to multiply by 2 because the hex digits are actually two bytes when they are strings
|
||||
return returned_bytes
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
print("Error sending the card raw data.")
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
---
|
||||
-- The main entry point
|
||||
function main(args)
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'h') do
|
||||
if o == 'h' then return help() end
|
||||
end
|
||||
|
||||
local tag, err = lib14a.read(true, false)
|
||||
|
||||
if not err then
|
||||
local sig = sendRaw("3C00", true, true)
|
||||
local ver = sendRaw("60", true, false)
|
||||
if sig and ver then -- if false, that's a fail right there
|
||||
sig = string.sub(sig, 0, -5)
|
||||
ver = string.sub(ver, 0, -5)
|
||||
local text = tag.name..","..ver..","..tag.uid..","..sig
|
||||
print(text)
|
||||
|
||||
local filename = "originalitysig.csv"
|
||||
local outfile = io.open(filename, "a")
|
||||
if outfile ~= nil then
|
||||
outfile:write(text.."\n")
|
||||
io.close(outfile)
|
||||
else
|
||||
print(ansicolors.red.."Couldn't open file originalitysig.csv."..ansicolors.reset)
|
||||
end
|
||||
else
|
||||
print(ansicolors.red.."Read FAILED."..ansicolors.reset)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
main(args)
|
|
@ -7,11 +7,11 @@ local ansicolors = require('ansicolors')
|
|||
|
||||
copyright = ''
|
||||
author = 'Iceman'
|
||||
version = 'v1.0.3'
|
||||
version = 'v1.0.4'
|
||||
desc = [[
|
||||
This script will load several traces files in current working directory/traces/ folder and do
|
||||
"data load"
|
||||
"lf search 1 u"
|
||||
"lf search -1u"
|
||||
|
||||
The following tracefiles will be loaded:
|
||||
em*.pm3
|
||||
|
@ -109,7 +109,7 @@ local function main(args)
|
|||
end
|
||||
p.close();
|
||||
|
||||
local cmdLFSEARCH = 'lf search 1 u'
|
||||
local cmdLFSEARCH = 'lf search -1u'
|
||||
|
||||
-- main loop
|
||||
io.write('Starting to test traces > ')
|
||||
|
|
|
@ -4749,14 +4749,14 @@
|
|||
"application": "Security and Access Control",
|
||||
"company": "PEC (New Zealand) Ltd.",
|
||||
"mad": "0x4811",
|
||||
"service_provider": "Cardax",
|
||||
"service_provider": "Cardax / Gallagher",
|
||||
"system_integrator": ""
|
||||
},
|
||||
{
|
||||
"application": "Security and Access Control",
|
||||
"company": "PEC (New Zealand) Ltd.",
|
||||
"mad": "0x4812",
|
||||
"service_provider": "Cardax",
|
||||
"service_provider": "Cardax / Gallagher",
|
||||
"system_integrator": ""
|
||||
},
|
||||
{
|
||||
|
@ -6096,6 +6096,13 @@
|
|||
"service_provider": "CDVI",
|
||||
"system_integrator": "CDVI"
|
||||
},
|
||||
{
|
||||
"application": "(access control and security) VIGIK",
|
||||
"company": "NORALSY",
|
||||
"mad": "0x4980",
|
||||
"service_provider": "NORALSY",
|
||||
"system_integrator": "NORALSY"
|
||||
},
|
||||
{
|
||||
"application": "Card Administratin, cardholder adminstration, access control & security, company services, miscellaneous applications",
|
||||
"company": "Ministry of Defense",
|
||||
|
|
|
@ -36,7 +36,7 @@ static int openAIDFile(json_t **root, bool verbose) {
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (verbose) PrintAndLogEx(SUCCESS, "Loaded file (%s) OK. %zu records.", path, json_array_size(*root));
|
||||
PrintAndLogEx(DEBUG, "Loaded file " _YELLOW_("%s") " " _GREEN_("%zu") " records ( " _GREEN_("ok") " )", path, json_array_size(*root));
|
||||
out:
|
||||
free(path);
|
||||
return retval;
|
||||
|
@ -145,22 +145,22 @@ int PrintAIDDescription(json_t *xroot, char *aid, bool verbose) {
|
|||
const char *description = jsonStrGet(elm, "Description");
|
||||
const char *type = jsonStrGet(elm, "Type");
|
||||
|
||||
if (!verbose) {
|
||||
PrintAndLogEx(SUCCESS, "AID %s | %s | %s", vaid, vendor, name);
|
||||
if (verbose == false) {
|
||||
PrintAndLogEx(SUCCESS, "AID : " _YELLOW_("%s") " | %s | %s", vaid, vendor, name);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Input AID: %s", aid);
|
||||
PrintAndLogEx(SUCCESS, "Input AID..... " _YELLOW_("%s"), aid);
|
||||
if (aid)
|
||||
PrintAndLogEx(SUCCESS, "Found AID: %s", vaid);
|
||||
PrintAndLogEx(SUCCESS, "Found AID..... " _YELLOW_("%s"), vaid);
|
||||
if (vendor)
|
||||
PrintAndLogEx(SUCCESS, "Vendor: %s", vendor);
|
||||
PrintAndLogEx(SUCCESS, "Vendor........ " _YELLOW_("%s"), vendor);
|
||||
if (type)
|
||||
PrintAndLogEx(SUCCESS, "Type: %s", type);
|
||||
PrintAndLogEx(SUCCESS, "Type.......... " _YELLOW_("%s"), type);
|
||||
if (name)
|
||||
PrintAndLogEx(SUCCESS, "Name: %s", name);
|
||||
PrintAndLogEx(SUCCESS, "Name.......... " _YELLOW_("%s"), name);
|
||||
if (country)
|
||||
PrintAndLogEx(SUCCESS, "Country: %s", country);
|
||||
PrintAndLogEx(SUCCESS, "Country....... %s", country);
|
||||
if (description)
|
||||
PrintAndLogEx(SUCCESS, "Description: %s", description);
|
||||
PrintAndLogEx(SUCCESS, "Description... %s", description);
|
||||
}
|
||||
|
||||
out:
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -769,22 +769,22 @@ static int CmdBiphaseDecodeRaw(const char *Cmd) {
|
|||
int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose) {
|
||||
//ask raw demod GraphBuffer first
|
||||
|
||||
uint8_t BitStream[MAX_DEMOD_BUF_LEN];
|
||||
size_t size = getFromGraphBuf(BitStream);
|
||||
uint8_t bs[MAX_DEMOD_BUF_LEN];
|
||||
size_t size = getFromGraphBuf(bs);
|
||||
if (size == 0) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: no data in graphbuf");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
int startIdx = 0;
|
||||
//invert here inverts the ask raw demoded bits which has no effect on the demod, but we need the pointer
|
||||
int errCnt = askdemod_ext(BitStream, &size, &clk, &invert, maxErr, 0, 0, &startIdx);
|
||||
int errCnt = askdemod_ext(bs, &size, &clk, &invert, maxErr, 0, 0, &startIdx);
|
||||
if (errCnt < 0 || errCnt > maxErr) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: no data or error found %d, clock: %d", errCnt, clk);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
//attempt to Biphase decode BitStream
|
||||
errCnt = BiphaseRawDecode(BitStream, &size, &offset, invert);
|
||||
errCnt = BiphaseRawDecode(bs, &size, &offset, invert);
|
||||
if (errCnt < 0) {
|
||||
if (g_debugMode || verbose) PrintAndLogEx(DEBUG, "DEBUG: Error BiphaseRawDecode: %d", errCnt);
|
||||
return PM3_ESOFT;
|
||||
|
@ -795,7 +795,7 @@ int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose) {
|
|||
}
|
||||
|
||||
//success set DemodBuffer and return
|
||||
setDemodBuff(BitStream, size, 0);
|
||||
setDemodBuff(bs, size, 0);
|
||||
setClockGrid(clk, startIdx + clk * offset / 2);
|
||||
if (g_debugMode || verbose) {
|
||||
PrintAndLogEx(DEBUG, "Biphase Decoded using offset %d | clock %d | #errors %d | start index %d\ndata\n", offset, clk, errCnt, (startIdx + clk * offset / 2));
|
||||
|
@ -1428,7 +1428,7 @@ static int CmdRawDemod(const char *Cmd) {
|
|||
else if (str_startswith(Cmd, "am")) ans = Cmdaskmandemod(Cmd + 2);
|
||||
else if (str_startswith(Cmd, "ar")) ans = Cmdaskrawdemod(Cmd + 2);
|
||||
else if (str_startswith(Cmd, "nr") || Cmd[0] == 'n') ans = CmdNRZrawDemod(Cmd + 2);
|
||||
else if (str_startswith(Cmd, "p1") || Cmd[0] == 'p') ans = CmdPSK1rawDemod(Cmd + 2);
|
||||
else if (str_startswith(Cmd, "p1")) ans = CmdPSK1rawDemod(Cmd + 2);
|
||||
else if (str_startswith(Cmd, "p2")) ans = CmdPSK2rawDemod(Cmd + 2);
|
||||
else PrintAndLogEx(WARNING, "Unknown modulation entered - see help ('h') for parameter structure");
|
||||
|
||||
|
@ -1576,7 +1576,7 @@ int getSamplesEx(uint32_t start, uint32_t end, bool verbose) {
|
|||
|
||||
uint32_t n = end - start;
|
||||
|
||||
if (n <= 0 || n > pm3_capabilities.bigbuf_size - 1)
|
||||
if (n == 0 || n > pm3_capabilities.bigbuf_size - 1)
|
||||
n = pm3_capabilities.bigbuf_size - 1;
|
||||
|
||||
if (verbose)
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <ctype.h>
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "cliparser.h"
|
||||
#include "pmflash.h"
|
||||
#include "pmflash.h" // rdv40validation_t
|
||||
#include "fileutils.h" // saveFile
|
||||
#include "comms.h" // getfromdevice
|
||||
#include "cmdflashmemspiffs.h" // spiffs commands
|
||||
|
@ -26,6 +26,123 @@
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
//-------------------------------------------------------------------------------------
|
||||
// RRG Public RSA Key
|
||||
#define RRG_RSA_KEY_LEN 128
|
||||
|
||||
// public key Exponent E
|
||||
#define RRG_RSA_E "010001"
|
||||
|
||||
// public key modulus N
|
||||
#define RRG_RSA_N "E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF" \
|
||||
"4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F" \
|
||||
"9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33" \
|
||||
"DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5"
|
||||
|
||||
// Following example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c)
|
||||
// private key - Exponent D
|
||||
#define RSA_D "24BF6185468786FDD303083D25E64EFC" \
|
||||
"66CA472BC44D253102F8B4A9D3BFA750" \
|
||||
"91386C0077937FE33FA3252D28855837" \
|
||||
"AE1B484A8A9A45F7EE8C0C634F99E8CD" \
|
||||
"DF79C5CE07EE72C7F123142198164234" \
|
||||
"CABB724CF78B8173B9F880FC86322407" \
|
||||
"AF1FEDFDDE2BEB674CA15F3E81A1521E" \
|
||||
"071513A1E85B5DFA031F21ECAE91A34D"
|
||||
|
||||
// prime P
|
||||
#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
|
||||
"2C01CAD19EA484A87EA4377637E75500" \
|
||||
"FCB2005C5C7DD6EC4AC023CDA285D796" \
|
||||
"C3D9E75E1EFC42488BB4F1D13AC30A57"
|
||||
|
||||
// prime Q
|
||||
#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \
|
||||
"E211C2B9E5DB1ED0BF61D0D9899620F4" \
|
||||
"910E4168387E3C30AA1E00C339A79508" \
|
||||
"8452DD96A9A5EA5D9DCA68DA636032AF"
|
||||
|
||||
#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \
|
||||
"3C94D22288ACD763FD8E5600ED4A702D" \
|
||||
"F84198A5F06C2E72236AE490C93F07F8" \
|
||||
"3CC559CD27BC2D1CA488811730BB5725"
|
||||
|
||||
#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \
|
||||
"D8AAEA56749EA28623272E4F7D0592AF" \
|
||||
"7C1F1313CAC9471B5C523BFE592F517B" \
|
||||
"407A1BD76C164B93DA2D32A383E58357"
|
||||
|
||||
#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \
|
||||
"F38D18D2B2F0E2DD275AA977E2BF4411" \
|
||||
"F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
|
||||
"A74206CEC169D74BF5A8C50D6F48EA08"
|
||||
|
||||
int rdv4_get_signature(rdv40_validation_t *out) {
|
||||
if (out == NULL) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_FLASHMEM_INFO, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||
if (isok == false) {
|
||||
PrintAndLogEx(FAILED, "fail reading from flashmemory");
|
||||
return PM3_EFLASH;
|
||||
}
|
||||
|
||||
//rdv40_validation_t mem;
|
||||
memcpy(out, (rdv40_validation_t *)resp.data.asBytes, sizeof(rdv40_validation_t));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// validate signature
|
||||
int rdv4_validate(rdv40_validation_t *mem) {
|
||||
|
||||
// Flash ID hash (sha1)
|
||||
uint8_t sha_hash[20] = {0};
|
||||
mbedtls_sha1(mem->flashid, sizeof(mem->flashid), sha_hash);
|
||||
|
||||
// set up RSA
|
||||
mbedtls_rsa_context rsa;
|
||||
mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
rsa.len = RRG_RSA_KEY_LEN;
|
||||
mbedtls_mpi_read_string(&rsa.N, 16, RRG_RSA_N);
|
||||
mbedtls_mpi_read_string(&rsa.E, 16, RRG_RSA_E);
|
||||
|
||||
// Verify (public key)
|
||||
int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, mem->signature);
|
||||
mbedtls_rsa_free(&rsa);
|
||||
|
||||
if (is_verified == 0) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
static int rdv4_sign_write(uint8_t *signature, uint8_t slen){
|
||||
// save to mem
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
SendCommandOLD(CMD_FLASHMEM_WRITE, FLASH_MEM_SIGNATURE_OFFSET, FLASH_MEM_SIGNATURE_LEN, 0, signature, slen);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
} else {
|
||||
if (!resp.oldarg[0]) {
|
||||
PrintAndLogEx(FAILED, "Writing signature ( "_RED_("fail") ")");
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "Writing signature ( "_GREEN_("ok") " ) at offset %u", FLASH_MEM_SIGNATURE_OFFSET);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
static int CmdFlashmemSpiBaudrate(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
|
@ -344,23 +461,14 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
|||
// shall_write = arg_get_lit(ctx, 2);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_FLASHMEM_INFO, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||
if (isok == false) {
|
||||
PrintAndLogEx(FAILED, "failed");
|
||||
return PM3_EFLASH;
|
||||
}
|
||||
|
||||
// validate signature here
|
||||
// validate signature data
|
||||
rdv40_validation_t mem;
|
||||
memcpy(&mem, (rdv40_validation_t *)resp.data.asBytes, sizeof(rdv40_validation_t));
|
||||
int res = rdv4_get_signature(&mem);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = rdv4_validate(&mem);
|
||||
|
||||
// Flash ID hash (sha1)
|
||||
uint8_t sha_hash[20] = {0};
|
||||
|
@ -369,7 +477,6 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
|||
// print header
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Flash memory Information") " ---------");
|
||||
// PrintAndLogEx(INFO, "-----------------------------------------------------------------");
|
||||
PrintAndLogEx(INFO, "ID................... %s", sprint_hex_inrow(mem.flashid, sizeof(mem.flashid)));
|
||||
PrintAndLogEx(INFO, "SHA1................. %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash)));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -378,69 +485,16 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, " %s", sprint_hex_inrow(mem.signature + (i * 32), 32));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// RRG Public RSA Key
|
||||
//
|
||||
|
||||
// public key Exponent E
|
||||
#define RSA_E "010001"
|
||||
|
||||
// public key modulus N
|
||||
#define RSA_N "E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF" \
|
||||
"4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F" \
|
||||
"9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33" \
|
||||
"DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5"
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
// Example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c)
|
||||
//
|
||||
|
||||
// private key Exponent D
|
||||
#define RSA_D "24BF6185468786FDD303083D25E64EFC" \
|
||||
"66CA472BC44D253102F8B4A9D3BFA750" \
|
||||
"91386C0077937FE33FA3252D28855837" \
|
||||
"AE1B484A8A9A45F7EE8C0C634F99E8CD" \
|
||||
"DF79C5CE07EE72C7F123142198164234" \
|
||||
"CABB724CF78B8173B9F880FC86322407" \
|
||||
"AF1FEDFDDE2BEB674CA15F3E81A1521E" \
|
||||
"071513A1E85B5DFA031F21ECAE91A34D"
|
||||
|
||||
// prime P
|
||||
#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \
|
||||
"2C01CAD19EA484A87EA4377637E75500" \
|
||||
"FCB2005C5C7DD6EC4AC023CDA285D796" \
|
||||
"C3D9E75E1EFC42488BB4F1D13AC30A57"
|
||||
|
||||
// prime Q
|
||||
#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \
|
||||
"E211C2B9E5DB1ED0BF61D0D9899620F4" \
|
||||
"910E4168387E3C30AA1E00C339A79508" \
|
||||
"8452DD96A9A5EA5D9DCA68DA636032AF"
|
||||
|
||||
#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \
|
||||
"3C94D22288ACD763FD8E5600ED4A702D" \
|
||||
"F84198A5F06C2E72236AE490C93F07F8" \
|
||||
"3CC559CD27BC2D1CA488811730BB5725"
|
||||
|
||||
#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \
|
||||
"D8AAEA56749EA28623272E4F7D0592AF" \
|
||||
"7C1F1313CAC9471B5C523BFE592F517B" \
|
||||
"407A1BD76C164B93DA2D32A383E58357"
|
||||
|
||||
#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \
|
||||
"F38D18D2B2F0E2DD275AA977E2BF4411" \
|
||||
"F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
|
||||
"A74206CEC169D74BF5A8C50D6F48EA08"
|
||||
|
||||
#define KEY_LEN 128
|
||||
|
||||
mbedtls_rsa_context rsa;
|
||||
mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
|
||||
|
||||
rsa.len = KEY_LEN;
|
||||
rsa.len = RRG_RSA_KEY_LEN;
|
||||
|
||||
mbedtls_mpi_read_string(&rsa.N, 16, RSA_N);
|
||||
mbedtls_mpi_read_string(&rsa.E, 16, RSA_E);
|
||||
// add public key
|
||||
mbedtls_mpi_read_string(&rsa.N, 16, RRG_RSA_N);
|
||||
mbedtls_mpi_read_string(&rsa.E, 16, RRG_RSA_E);
|
||||
|
||||
// add private key
|
||||
mbedtls_mpi_read_string(&rsa.D, 16, RSA_D);
|
||||
mbedtls_mpi_read_string(&rsa.P, 16, RSA_P);
|
||||
mbedtls_mpi_read_string(&rsa.Q, 16, RSA_Q);
|
||||
|
@ -448,8 +502,6 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
|||
mbedtls_mpi_read_string(&rsa.DQ, 16, RSA_DQ);
|
||||
mbedtls_mpi_read_string(&rsa.QP, 16, RSA_QP);
|
||||
|
||||
bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0 || mbedtls_rsa_check_privkey(&rsa) == 0);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA Public key") " --------------");
|
||||
|
||||
|
@ -466,48 +518,35 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, " %.64s", str_pk + 64);
|
||||
PrintAndLogEx(INFO, " %.64s", str_pk + 128);
|
||||
PrintAndLogEx(INFO, " %.64s", str_pk + 192);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
const char *msgkey = "RSA key validation... ";
|
||||
if (is_keyok)
|
||||
PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgkey);
|
||||
else
|
||||
PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgkey);
|
||||
|
||||
//
|
||||
uint8_t from_device[KEY_LEN];
|
||||
uint8_t sign[KEY_LEN];
|
||||
bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0 || mbedtls_rsa_check_privkey(&rsa) == 0);
|
||||
PrintAndLogEx(
|
||||
(is_keyok) ? SUCCESS : FAILED,
|
||||
"RSA key validation... ( %s )",
|
||||
(is_keyok) ? _GREEN_("ok") : _RED_("fail")
|
||||
);
|
||||
|
||||
// to be verified
|
||||
memcpy(from_device, mem.signature, KEY_LEN);
|
||||
uint8_t from_device[RRG_RSA_KEY_LEN];
|
||||
memcpy(from_device, mem.signature, RRG_RSA_KEY_LEN);
|
||||
|
||||
// to be signed (all zeros
|
||||
memset(sign, 0, KEY_LEN);
|
||||
// to be signed
|
||||
uint8_t sign[RRG_RSA_KEY_LEN];
|
||||
memset(sign, 0, RRG_RSA_KEY_LEN);
|
||||
|
||||
// Signing (private key)
|
||||
if (shall_sign) {
|
||||
|
||||
int is_signed = mbedtls_rsa_pkcs1_sign(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, sign);
|
||||
const char *msgsign = "RSA signing.......... ";
|
||||
if (is_signed == 0)
|
||||
PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgsign);
|
||||
else
|
||||
PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgsign);
|
||||
PrintAndLogEx(
|
||||
(is_signed == 0) ? SUCCESS : FAILED,
|
||||
"RSA signing.......... ( %s )",
|
||||
(is_signed == 0) ? _GREEN_("ok") : _RED_("fail")
|
||||
);
|
||||
|
||||
if (shall_write) {
|
||||
// save to mem
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(CMD_FLASHMEM_WRITE, FLASH_MEM_SIGNATURE_OFFSET, FLASH_MEM_SIGNATURE_LEN, 0, sign, sizeof(sign));
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
} else {
|
||||
|
||||
if (!resp.oldarg[0])
|
||||
PrintAndLogEx(FAILED, "Writing signature failed");
|
||||
else
|
||||
PrintAndLogEx(SUCCESS, "Writing signature ok [offset: %u]", FLASH_MEM_SIGNATURE_OFFSET);
|
||||
|
||||
}
|
||||
rdv4_sign_write(sign, RRG_RSA_KEY_LEN);
|
||||
}
|
||||
PrintAndLogEx(INFO, "Signed");
|
||||
for (int i = 0; i < (sizeof(sign) / 32); i++) {
|
||||
|
@ -517,14 +556,15 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
|||
|
||||
// Verify (public key)
|
||||
int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device);
|
||||
const char *msgverify = "RSA verification..... ";
|
||||
if (is_verified == 0)
|
||||
PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgverify);
|
||||
else
|
||||
PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgverify);
|
||||
mbedtls_rsa_free(&rsa);
|
||||
|
||||
PrintAndLogEx(
|
||||
(is_verified == 0) ? SUCCESS : FAILED,
|
||||
"RSA verification..... ( %s )",
|
||||
(is_verified == 0) ? _GREEN_("ok") : _RED_("fail")
|
||||
);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
mbedtls_rsa_free(&rsa);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#define CMDFLASHMEM_H__
|
||||
|
||||
#include "common.h"
|
||||
#include "pmflash.h" // rdv40validation_t
|
||||
|
||||
typedef enum {
|
||||
DICTIONARY_NONE = 0,
|
||||
|
@ -21,5 +22,6 @@ typedef enum {
|
|||
} Dictionary_t;
|
||||
|
||||
int CmdFlashMem(const char *Cmd);
|
||||
|
||||
int rdv4_get_signature(rdv40_validation_t *out);
|
||||
int rdv4_validate(rdv40_validation_t *mem);
|
||||
#endif
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "cmdhf.h"
|
||||
|
||||
#include <ctype.h> // tolower
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "cliparser.h" // parse
|
||||
#include "comms.h" // clearCommandBuffer
|
||||
|
@ -23,8 +22,10 @@
|
|||
#include "cmdhf14b.h" // ISO14443-B
|
||||
#include "cmdhf15.h" // ISO15693
|
||||
#include "cmdhfepa.h"
|
||||
#include "cmdhfemrtd.h" // eMRTD
|
||||
#include "cmdhflegic.h" // LEGIC
|
||||
#include "cmdhficlass.h" // ICLASS
|
||||
#include "cmdhfjooki.h" // MFU based Jooki
|
||||
#include "cmdhfmf.h" // CLASSIC
|
||||
#include "cmdhfmfu.h" // ULTRALIGHT/NTAG etc
|
||||
#include "cmdhfmfp.h" // Mifare Plus
|
||||
|
@ -46,50 +47,20 @@
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_hf_search(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf search");
|
||||
PrintAndLogEx(NORMAL, "Will try to find a HF read out of the unknown tag.");
|
||||
PrintAndLogEx(NORMAL, "Continues to search for all different HF protocols");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - This help");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_hf_sniff(void) {
|
||||
PrintAndLogEx(NORMAL, "The high frequency sniffer will assign all available memory on device for sniffed data");
|
||||
PrintAndLogEx(NORMAL, "Use " _YELLOW_("'data samples'")" command to download from device, and " _YELLOW_("'data plot'")" to look at it");
|
||||
PrintAndLogEx(NORMAL, "Press button to quit the sniffing.\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf sniff <skip pairs> <skip triggers>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - This help");
|
||||
PrintAndLogEx(NORMAL, " <skip pairs> - skip sample pairs");
|
||||
PrintAndLogEx(NORMAL, " <skip triggers> - skip number of triggers");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf sniff"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf sniff 1000 0"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_hf_tune(void) {
|
||||
PrintAndLogEx(NORMAL, "Continuously measure HF antenna tuning.");
|
||||
PrintAndLogEx(NORMAL, "Press button or `enter` to interrupt.");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf tune [h] [<iter>]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - This help");
|
||||
PrintAndLogEx(NORMAL, " <iter> - number of iterations (default: 0=infinite)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf tune 1"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdHFSearch(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_hf_search();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf search",
|
||||
"Will try to find a HF read out of the unknown tag.\n"
|
||||
"Continues to search for all different HF protocols.",
|
||||
"hf search"
|
||||
);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
int res = PM3_ESOFT;
|
||||
|
||||
|
@ -141,7 +112,7 @@ int CmdHFSearch(const char *Cmd) {
|
|||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, " Searching for LEGIC tag...");
|
||||
if (IfPm3Legicrf()) {
|
||||
if (readLegicUid(false) == PM3_SUCCESS) {
|
||||
if (readLegicUid(false, false) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("LEGIC Prime tag") " found\n");
|
||||
res = PM3_SUCCESS;
|
||||
}
|
||||
|
@ -189,18 +160,51 @@ int CmdHFSearch(const char *Cmd) {
|
|||
|
||||
PROMPT_CLEARLINE;
|
||||
if (res != PM3_SUCCESS) {
|
||||
|
||||
PrintAndLogEx(WARNING, _RED_("No known/supported 13.56 MHz tags found"));
|
||||
res = PM3_ESOFT;
|
||||
}
|
||||
|
||||
DropField();
|
||||
return res;
|
||||
}
|
||||
|
||||
int CmdHFTune(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_hf_tune();
|
||||
int iter = param_get32ex(Cmd, 0, 0, 10);
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf tune",
|
||||
"Continuously measure HF antenna tuning.\n"
|
||||
"Press button or <Enter> to interrupt.",
|
||||
"hf tune\n"
|
||||
"hf tune --mix"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_0("n", "iter", "<dec>", "number of iterations (default: 0=infinite)"),
|
||||
arg_lit0(NULL, "bar", "bar style"),
|
||||
arg_lit0(NULL, "mix", "mixed style"),
|
||||
arg_lit0(NULL, "value", "values style"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
uint32_t iter = arg_get_u32_def(ctx, 1, 0);
|
||||
bool is_bar = arg_get_lit(ctx, 2);
|
||||
bool is_mix = arg_get_lit(ctx, 3);
|
||||
bool is_value = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if ((is_bar + is_mix + is_value) > 1) {
|
||||
PrintAndLogEx(ERR, "Select only one output style");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
barMode_t style = session.bar_mode;
|
||||
if (is_bar)
|
||||
style = STYLE_BAR;
|
||||
if (is_mix)
|
||||
style = STYLE_MIXED;
|
||||
if (is_value)
|
||||
style = STYLE_VALUE;
|
||||
|
||||
PrintAndLogEx(INFO, "Measuring HF antenna, click " _GREEN_("pm3 button") " or press " _GREEN_("Enter") " to exit");
|
||||
PacketResponseNG resp;
|
||||
|
@ -214,6 +218,12 @@ int CmdHFTune(const char *Cmd) {
|
|||
}
|
||||
|
||||
mode[0] = 2;
|
||||
|
||||
uint32_t max = 0xFFFF;
|
||||
bool first = true;
|
||||
|
||||
print_progress(0, max, style);
|
||||
|
||||
// loop forever (till button pressed) if iter = 0 (default)
|
||||
for (uint8_t i = 0; iter == 0 || i < iter; i++) {
|
||||
if (kbd_enter_pressed()) {
|
||||
|
@ -224,15 +234,23 @@ int CmdHFTune(const char *Cmd) {
|
|||
if (!WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000)) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF measure, aborting");
|
||||
return PM3_ETIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((resp.status == PM3_EOPABORTED) || (resp.length != sizeof(uint16_t))) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t volt = resp.data.asDwords[0] & 0xFFFF;
|
||||
PrintAndLogEx(INPLACE, " %u mV / %2u V", volt, (uint16_t)(volt / 1000));
|
||||
if (first) {
|
||||
max = (volt * 1.03);
|
||||
first = false;
|
||||
}
|
||||
if (volt > max) {
|
||||
max = (volt * 1.03);
|
||||
}
|
||||
print_progress(volt, max, style);
|
||||
}
|
||||
mode[0] = 3;
|
||||
|
||||
|
@ -241,7 +259,7 @@ int CmdHFTune(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF shutdown, aborting");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "\x1b%c[2K\r", 30);
|
||||
PrintAndLogEx(INFO, "Done.");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -251,16 +269,31 @@ int CmdHFTune(const char *Cmd) {
|
|||
// Takes all available bigbuff memory
|
||||
// data sample to download? Not sure what we can do with the data.
|
||||
int CmdHFSniff(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_hf_sniff();
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf sniff",
|
||||
"The high frequency sniffer will assign all available memory on device for sniffed data.\n"
|
||||
"Use `data samples` to download from device and `data plot` to visualize it.\n"
|
||||
"Press button to quit the sniffing.",
|
||||
"hf sniff\n"
|
||||
"hf sniff --sp 1000 --st 0 -> skip 1000 pairs, skip 0 triggers"
|
||||
);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_u64_0(NULL, "sp", "<dec>", "skip sample pairs"),
|
||||
arg_u64_0(NULL, "st", "<dec>", "skip number of triggers"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
||||
struct {
|
||||
uint32_t samplesToSkip;
|
||||
uint32_t triggersToSkip;
|
||||
} PACKED params;
|
||||
|
||||
params.samplesToSkip = param_get32ex(Cmd, 0, 0, 10);
|
||||
params.triggersToSkip = param_get32ex(Cmd, 1, 0, 10);
|
||||
params.samplesToSkip = arg_get_u32_def(ctx, 1, 0);
|
||||
params.triggersToSkip = arg_get_u32_def(ctx, 2, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_SNIFF, (uint8_t *)¶ms, sizeof(params));
|
||||
|
@ -362,8 +395,10 @@ static command_t CommandTable[] = {
|
|||
{"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"},
|
||||
// {"cryptorf", CmdHFCryptoRF, AlwaysAvailable, "{ CryptoRF RFIDs... }"},
|
||||
{"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"},
|
||||
{"emrtd", CmdHFeMRTD, AlwaysAvailable, "{ Machine Readable Travel Document... }"},
|
||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / FeliCa RFIDs... }"},
|
||||
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
||||
{"jooki", CmdHF_Jooki, AlwaysAvailable, "{ Jooki RFIDs... }"},
|
||||
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},
|
||||
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"},
|
||||
{"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"},
|
||||
|
@ -381,7 +416,7 @@ static command_t CommandTable[] = {
|
|||
{"plot", CmdHFPlot, IfPm3Hfplot, "Plot signal"},
|
||||
{"tune", CmdHFTune, IfPm3Present, "Continuously measure HF antenna tuning"},
|
||||
{"search", CmdHFSearch, AlwaysAvailable, "Search for known HF tags"},
|
||||
{"sniff", CmdHFSniff, IfPm3Hfsniff, "<samples to skip (10000)> <triggers to skip (1)> Generic HF Sniff"},
|
||||
{"sniff", CmdHFSniff, IfPm3Hfsniff, "Generic HF Sniff"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -27,7 +27,7 @@ int CmdHF14ASniff(const char *Cmd); // used by hf topaz sniff
|
|||
int CmdHF14ASim(const char *Cmd); // used by hf mfu sim
|
||||
|
||||
int hf14a_getconfig(hf14a_config *config);
|
||||
int hf14a_setconfig(hf14a_config *config);
|
||||
int hf14a_setconfig(hf14a_config *config, bool verbose);
|
||||
int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search);
|
||||
const char *getTagInfo(uint8_t uid);
|
||||
int Hf14443_4aGetCardData(iso14a_card_select_t *card);
|
||||
|
|
|
@ -24,8 +24,11 @@
|
|||
#include "protocols.h" // definitions of ISO14B/7816 protocol
|
||||
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "mifare/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||
#include "aidsearch.h"
|
||||
|
||||
#define MAX_14B_TIMEOUT 40542464U // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s
|
||||
#define TIMEOUT 2000
|
||||
#define APDU_TIMEOUT 2000
|
||||
|
||||
// iso14b apdu input frame length
|
||||
static uint16_t apdu_frame_length = 0;
|
||||
|
@ -34,21 +37,6 @@ bool apdu_in_framing_enable = true;
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_hf_14b_write_srx(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14b [h] sriwrite <1|2> <block> <data>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " <1|2> 1 = SRIX4K , 2 = SRI512");
|
||||
PrintAndLogEx(NORMAL, " <block> (hex) block number depends on tag, special block == FF");
|
||||
PrintAndLogEx(NORMAL, " <data> hex bytes of data to be written");
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriwrite 1 7F 11223344"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriwrite 1 FF 11223344"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriwrite 2 15 11223344"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14b sriwrite 2 FF 11223344"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int switch_off_field_14b(void) {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
@ -63,6 +51,103 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) {
|
|||
return d[n] * 0x0100 + d[n + 1];
|
||||
}
|
||||
|
||||
static void hf14b_aid_search(bool verbose) {
|
||||
|
||||
int elmindx = 0;
|
||||
json_t *root = AIDSearchInit(verbose);
|
||||
if (root == NULL) {
|
||||
switch_off_field_14b();
|
||||
return;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "-------------------- " _CYAN_("AID Search") " --------------------");
|
||||
|
||||
bool found = false;
|
||||
bool leave_signal_on = true;
|
||||
bool activate_field = true;
|
||||
for (elmindx = 0; elmindx < json_array_size(root); elmindx++) {
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
|
||||
json_t *data = AIDSearchGetElm(root, elmindx);
|
||||
uint8_t vaid[200] = {0};
|
||||
int vaidlen = 0;
|
||||
if (!AIDGetFromElm(data, vaid, sizeof(vaid), &vaidlen) || !vaidlen)
|
||||
continue;
|
||||
|
||||
|
||||
// COMPUTE APDU
|
||||
uint8_t apdu_data[PM3_CMD_DATA_SIZE] = {0};
|
||||
int apdu_len = 0;
|
||||
sAPDU apdu = (sAPDU) {0x00, 0xa4, 0x04, 0x00, vaidlen, vaid};
|
||||
|
||||
if (APDUEncodeS(&apdu, false, 0x00, apdu_data, &apdu_len)) {
|
||||
PrintAndLogEx(ERR, "APDU encoding error.");
|
||||
return;
|
||||
}
|
||||
|
||||
PrintAndLogEx(DEBUG, ">>>> %s", sprint_hex(apdu_data, apdu_len));
|
||||
|
||||
int resultlen = 0;
|
||||
uint8_t result[1024] = {0};
|
||||
int res = exchange_14b_apdu(apdu_data, apdu_len, activate_field, leave_signal_on, result, sizeof(result), &resultlen, -1);
|
||||
activate_field = false;
|
||||
if (res)
|
||||
continue;
|
||||
|
||||
uint16_t sw = get_sw(result, resultlen);
|
||||
|
||||
uint8_t dfname[200] = {0};
|
||||
size_t dfnamelen = 0;
|
||||
if (resultlen > 3) {
|
||||
struct tlvdb *tlv = tlvdb_parse_multi(result, resultlen);
|
||||
if (tlv) {
|
||||
// 0x84 Dedicated File (DF) Name
|
||||
const struct tlv *dfnametlv = tlvdb_get_tlv(tlvdb_find_full(tlv, 0x84));
|
||||
if (dfnametlv) {
|
||||
dfnamelen = dfnametlv->len;
|
||||
memcpy(dfname, dfnametlv->value, dfnamelen);
|
||||
}
|
||||
tlvdb_free(tlv);
|
||||
}
|
||||
}
|
||||
|
||||
if (sw == 0x9000 || sw == 0x6283 || sw == 0x6285) {
|
||||
if (sw == 0x9000) {
|
||||
if (verbose) PrintAndLogEx(SUCCESS, "Application ( " _GREEN_("ok") " )");
|
||||
} else {
|
||||
if (verbose) PrintAndLogEx(WARNING, "Application ( " _RED_("blocked") " )");
|
||||
}
|
||||
|
||||
PrintAIDDescriptionBuf(root, vaid, vaidlen, verbose);
|
||||
|
||||
if (dfnamelen) {
|
||||
if (dfnamelen == vaidlen) {
|
||||
if (memcmp(dfname, vaid, vaidlen) == 0) {
|
||||
if (verbose) PrintAndLogEx(INFO, "(DF) Name found and equal to AID");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen));
|
||||
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "(DF) Name not equal to AID: %s :", sprint_hex(dfname, dfnamelen));
|
||||
PrintAIDDescriptionBuf(root, dfname, dfnamelen, verbose);
|
||||
}
|
||||
} else {
|
||||
if (verbose) PrintAndLogEx(INFO, "(DF) Name not found");
|
||||
}
|
||||
|
||||
if (verbose) PrintAndLogEx(SUCCESS, "----------------------------------------------------");
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
switch_off_field_14b();
|
||||
if (verbose == false && found)
|
||||
PrintAndLogEx(INFO, "----------------------------------------------------");
|
||||
}
|
||||
|
||||
static bool wait_cmd_14b(bool verbose, bool is_select) {
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
@ -102,7 +187,6 @@ static bool wait_cmd_14b(bool verbose, bool is_select) {
|
|||
(crc) ? _GREEN_("ok") : _RED_("fail")
|
||||
);
|
||||
} else if (len == 0) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "no response from tag");
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len));
|
||||
|
@ -187,7 +271,7 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
|
|||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b raw",
|
||||
"Sends raw bytes to card ",
|
||||
"Sends raw bytes to card",
|
||||
"hf 14b raw -cks --data 0200a40400 -> standard select\n"
|
||||
"hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n"
|
||||
"hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n"
|
||||
|
@ -200,7 +284,7 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
|
|||
arg_lit0(NULL, "sr", "activate field, use SRx ST select"),
|
||||
arg_lit0(NULL, "cts", "activate field, use ASK C-ticket select"),
|
||||
arg_lit0("c", "crc", "calculate and append CRC"),
|
||||
arg_lit0("r", "noresponse", "do not read response from card"),
|
||||
arg_lit0(NULL, "noresponse", "do not read response from card"),
|
||||
arg_int0("t", "timeout", "<dec>", "timeout in ms"),
|
||||
arg_lit0("v", "verbose", "verbose"),
|
||||
arg_strx0("d", "data", "<hex>", "data, bytes to send"),
|
||||
|
@ -244,18 +328,20 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
|
|||
}
|
||||
CLIParserFree(ctx);
|
||||
|
||||
|
||||
uint32_t time_wait = 0;
|
||||
if (user_timeout > 0) {
|
||||
|
||||
#define MAX_14B_TIMEOUT 40542464 // = (2^32-1) * (8*16) / 13560000Hz * 1000ms/s
|
||||
flags |= ISO14B_SET_TIMEOUT;
|
||||
if (user_timeout > MAX_14B_TIMEOUT) {
|
||||
user_timeout = MAX_14B_TIMEOUT;
|
||||
|
||||
uint32_t max_timeout = user_timeout;
|
||||
if (max_timeout > MAX_14B_TIMEOUT) {
|
||||
max_timeout = MAX_14B_TIMEOUT;
|
||||
PrintAndLogEx(INFO, "set timeout to 40542 seconds (11.26 hours). The max we can wait for response");
|
||||
}
|
||||
time_wait = 13560000 / 1000 / (8 * 16) * user_timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
|
||||
time_wait = ((13560000 / 1000 / (8 * 16)) * max_timeout); // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "using timeout %u", user_timeout);
|
||||
PrintAndLogEx(INFO, "using timeout %u", max_timeout);
|
||||
}
|
||||
|
||||
if (keep_field_on == 0)
|
||||
|
@ -308,8 +394,7 @@ static bool get_14b_UID(iso14b_card_select_t *card) {
|
|||
if (card == NULL)
|
||||
return false;
|
||||
|
||||
int status = 0;
|
||||
|
||||
int status;
|
||||
PacketResponseNG resp;
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
@ -628,12 +713,12 @@ static void print_ct_general_info(void *vcard) {
|
|||
memcpy(&card, (iso14b_cts_card_select_t *)vcard, sizeof(iso14b_cts_card_select_t));
|
||||
|
||||
uint32_t uid32 = (card.uid[0] | card.uid[1] << 8 | card.uid[2] << 16 | card.uid[3] << 24);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "ASK C-Ticket");
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s") " ( " _YELLOW_("%010u") " )", sprint_hex(card.uid, sizeof(card.uid)), uid32);
|
||||
PrintAndLogEx(SUCCESS, " Product Code: %02X", card.pc);
|
||||
PrintAndLogEx(SUCCESS, " Facility Code: %02X", card.fc);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
}
|
||||
|
||||
// iceman, calypso?
|
||||
|
@ -649,7 +734,7 @@ static void print_ct_general_info(void *vcard) {
|
|||
// 0200a4040010a000000018300301000000000000000000 (resp 02 6a 82 [4b 4c])
|
||||
|
||||
// 14b get and print Full Info (as much as we know)
|
||||
static bool HF14B_Std_Info(bool verbose) {
|
||||
static bool HF14B_Std_Info(bool verbose, bool do_aid_search) {
|
||||
|
||||
bool is_success = false;
|
||||
|
||||
|
@ -670,14 +755,21 @@ static bool HF14B_Std_Info(bool verbose) {
|
|||
int status = resp.oldarg[0];
|
||||
|
||||
switch (status) {
|
||||
case 0:
|
||||
case 0: {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "-------------------- " _CYAN_("Tag information") " --------------------");
|
||||
PrintAndLogEx(SUCCESS, " UID : " _GREEN_("%s"), sprint_hex(card.uid, card.uidlen));
|
||||
PrintAndLogEx(SUCCESS, " ATQB : %s", sprint_hex(card.atqb, sizeof(card.atqb)));
|
||||
PrintAndLogEx(SUCCESS, " CHIPID : %02X", card.chipid);
|
||||
print_atqb_resp(card.atqb, card.cid);
|
||||
|
||||
if (do_aid_search) {
|
||||
hf14b_aid_search(verbose);
|
||||
}
|
||||
|
||||
is_success = true;
|
||||
break;
|
||||
}
|
||||
case -1:
|
||||
if (verbose) PrintAndLogEx(FAILED, "ISO 14443-3 ATTRIB fail");
|
||||
break;
|
||||
|
@ -693,7 +785,7 @@ static bool HF14B_Std_Info(bool verbose) {
|
|||
}
|
||||
|
||||
// SRx get and print full info (needs more info...)
|
||||
static bool HF14B_ST_Info(bool verbose) {
|
||||
static bool HF14B_ST_Info(bool verbose, bool do_aid_search) {
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
@ -711,6 +803,10 @@ static bool HF14B_ST_Info(bool verbose) {
|
|||
return false;
|
||||
|
||||
print_st_general_info(card.uid, card.uidlen);
|
||||
|
||||
if (do_aid_search) {
|
||||
hf14b_aid_search(verbose);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -724,13 +820,15 @@ static int CmdHF14Binfo(const char *Cmd) {
|
|||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("s", "aidsearch", "checks if AIDs from aidlist.json is present on the card and prints information about found AIDs"),
|
||||
arg_lit0("v", "verbose", "verbose"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
bool verbose = arg_get_lit(ctx, 1);
|
||||
bool do_aid_search = arg_get_lit(ctx, 1);
|
||||
bool verbose = arg_get_lit(ctx, 2);
|
||||
CLIParserFree(ctx);
|
||||
return infoHF14B(verbose);
|
||||
return infoHF14B(verbose, do_aid_search);
|
||||
}
|
||||
|
||||
static bool HF14B_st_reader(bool verbose) {
|
||||
|
@ -1025,56 +1123,78 @@ static int CmdHF14BWriteSri(const char *Cmd) {
|
|||
* Special block FF = otp_lock_reg block.
|
||||
* Data len 4 bytes-
|
||||
*/
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
uint8_t blockno = -1;
|
||||
uint8_t data[4] = {0x00};
|
||||
bool isSrix4k = true;
|
||||
char str[30];
|
||||
memset(str, 0x00, sizeof(str));
|
||||
|
||||
if (strlen(Cmd) < 1 || cmdp == 'h') return usage_hf_14b_write_srx();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf 14b sriwrite",
|
||||
"Write data to a SRI512 | SRIX4K block",
|
||||
"hf 14b sriwrite --4k -b 100 -d 11223344\n"
|
||||
"hf 14b sriwrite --4k --sb -d 11223344 --> special block write\n"
|
||||
"hf 14b sriwrite --512 -b 15 -d 11223344\n"
|
||||
"hf 14b sriwrite --512 --sb -d 11223344 --> special block write\n"
|
||||
);
|
||||
|
||||
if (cmdp == '2')
|
||||
isSrix4k = false;
|
||||
|
||||
//blockno = param_get8(Cmd, 1);
|
||||
|
||||
if (param_gethex(Cmd, 1, &blockno, 2)) {
|
||||
PrintAndLogEx(WARNING, "block number must include 2 HEX symbols");
|
||||
return 0;
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0("b", "block", "<dec>", "block number"),
|
||||
arg_str1("d", "data", "<hex>", "4 hex bytes"),
|
||||
arg_lit0(NULL, "512", "target SRI 512 tag"),
|
||||
arg_lit0(NULL, "4k", "target SRIX 4k tag"),
|
||||
arg_lit0(NULL, "sb", "special block write at end of memory (0xFF)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
int blockno = arg_get_int_def(ctx, 1, -1);
|
||||
int dlen = 0;
|
||||
uint8_t data[4] = {0,0,0,0};
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 2), data, sizeof(data), &dlen);
|
||||
if (res) {
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (isSrix4k) {
|
||||
if (blockno > 0x7f && blockno != 0xff) {
|
||||
PrintAndLogEx(FAILED, "block number out of range");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
} else {
|
||||
if (blockno > 0x0f && blockno != 0xff) {
|
||||
PrintAndLogEx(FAILED, "block number out of range");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
bool use_sri512 = arg_get_lit(ctx, 3);
|
||||
bool use_srix4k = arg_get_lit(ctx, 4);
|
||||
bool special = arg_get_lit(ctx, 5);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (dlen != sizeof(data)) {
|
||||
PrintAndLogEx(FAILED, "data must be 4 hex bytes, got %d", dlen);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (param_gethex(Cmd, 2, data, 8)) {
|
||||
PrintAndLogEx(WARNING, "data must include 8 HEX symbols");
|
||||
return PM3_ESOFT;
|
||||
if (use_sri512 + use_srix4k > 1) {
|
||||
PrintAndLogEx(FAILED, "Select only one card type");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (blockno == 0xff) {
|
||||
if (use_srix4k && blockno > 0x7F) {
|
||||
PrintAndLogEx(FAILED, "block number out of range, max 127 (0x7F)");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (use_sri512 && blockno > 0x0F) {
|
||||
PrintAndLogEx(FAILED, "block number out of range, max 15 (0x0F)");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
// special block at end of memory
|
||||
if (special) {
|
||||
blockno = 0xFF;
|
||||
PrintAndLogEx(SUCCESS, "[%s] Write special block %02X [ " _YELLOW_("%s")" ]",
|
||||
(isSrix4k) ? "SRIX4K" : "SRI512",
|
||||
(use_srix4k) ? "SRIX4K" : "SRI512",
|
||||
blockno,
|
||||
sprint_hex(data, 4)
|
||||
sprint_hex(data, sizeof(data))
|
||||
);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "[%s] Write block %02X [ " _YELLOW_("%s")" ]",
|
||||
(isSrix4k) ? "SRIX4K" : "SRI512",
|
||||
(use_srix4k) ? "SRIX4K" : "SRI512",
|
||||
blockno,
|
||||
sprint_hex(data, 4)
|
||||
sprint_hex(data, sizeof(data))
|
||||
);
|
||||
}
|
||||
|
||||
char str[36];
|
||||
memset(str, 0x00, sizeof(str));
|
||||
sprintf(str, "--sr -c --data %02x%02x%02x%02x%02x%02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]);
|
||||
return CmdHF14BCmdRaw(str);
|
||||
}
|
||||
|
@ -1414,7 +1534,7 @@ static int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) {
|
||||
static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout, int user_timeout) {
|
||||
*chainingout = false;
|
||||
|
||||
if (activateField) {
|
||||
|
@ -1429,16 +1549,27 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool
|
|||
if (chainingin)
|
||||
flags = ISO14B_SEND_CHAINING;
|
||||
|
||||
uint32_t time_wait = 0;
|
||||
if (user_timeout > 0) {
|
||||
|
||||
flags |= ISO14B_SET_TIMEOUT;
|
||||
if (user_timeout > MAX_14B_TIMEOUT) {
|
||||
user_timeout = MAX_14B_TIMEOUT;
|
||||
PrintAndLogEx(INFO, "set timeout to 40542 seconds (11.26 hours). The max we can wait for response");
|
||||
}
|
||||
time_wait = (uint32_t)((13560000 / 1000 / (8 * 16)) * user_timeout); // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
|
||||
}
|
||||
|
||||
// "Command APDU" length should be 5+255+1, but javacard's APDU buffer might be smaller - 133 bytes
|
||||
// https://stackoverflow.com/questions/32994936/safe-max-java-card-apdu-data-command-and-respond-size
|
||||
// here length PM3_CMD_DATA_SIZE=512
|
||||
if (datain)
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, (datainlen & 0xFFFF), 0, datain, datainlen & 0xFFFF);
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, (datainlen & 0xFFFF), time_wait, datain, datainlen & 0xFFFF);
|
||||
else
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, 0, 0, NULL, 0);
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_APDU | flags, 0, time_wait, NULL, 0);
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, MAX(APDU_TIMEOUT, user_timeout))) {
|
||||
uint8_t *recv = resp.data.asBytes;
|
||||
int rlen = resp.oldarg[0];
|
||||
uint8_t res = resp.oldarg[1];
|
||||
|
@ -1488,7 +1619,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||
int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, int user_timeout) {
|
||||
*dataoutlen = 0;
|
||||
bool chaining = false;
|
||||
int res;
|
||||
|
@ -1505,7 +1636,7 @@ static int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field
|
|||
bool chainBlockNotLast = ((clen + vlen) < datainlen);
|
||||
|
||||
*dataoutlen = 0;
|
||||
res = handle_14b_apdu(chainBlockNotLast, &datain[clen], vlen, v_activate_field, dataout, maxdataoutlen, dataoutlen, &chaining);
|
||||
res = handle_14b_apdu(chainBlockNotLast, &datain[clen], vlen, v_activate_field, dataout, maxdataoutlen, dataoutlen, &chaining, user_timeout);
|
||||
if (res) {
|
||||
if (leave_signal_on == false)
|
||||
switch_off_field_14b();
|
||||
|
@ -1534,7 +1665,7 @@ static int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field
|
|||
|
||||
} else {
|
||||
|
||||
res = handle_14b_apdu(false, datain, datainlen, activate_field, dataout, maxdataoutlen, dataoutlen, &chaining);
|
||||
res = handle_14b_apdu(false, datain, datainlen, activate_field, dataout, maxdataoutlen, dataoutlen, &chaining, user_timeout);
|
||||
if (res != PM3_SUCCESS) {
|
||||
if (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
|
@ -1545,7 +1676,7 @@ static int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field
|
|||
|
||||
while (chaining) {
|
||||
// I-block with chaining
|
||||
res = handle_14b_apdu(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining);
|
||||
res = handle_14b_apdu(false, NULL, 0, false, &dataout[*dataoutlen], maxdataoutlen, dataoutlen, &chaining, user_timeout);
|
||||
if (res != PM3_SUCCESS) {
|
||||
if (leave_signal_on == false) {
|
||||
switch_off_field_14b();
|
||||
|
@ -1593,6 +1724,7 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"),
|
||||
arg_int0("l", "le", "<int>", "Le apdu parameter if `m` parameter included"),
|
||||
arg_strx1(NULL, "hex", "<hex>", "<APDU | data> if `m` parameter included"),
|
||||
arg_int0(NULL, "timeout", "<dec>", "timeout in ms"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -1652,6 +1784,7 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
// len = data + PCB(1b) + CRC(2b)
|
||||
CLIGetHexBLessWithReturn(ctx, 8, data, &datalen, 1 + 2);
|
||||
}
|
||||
int user_timeout = arg_get_int_def(ctx, 9, -1);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s",
|
||||
|
@ -1669,7 +1802,7 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "can't decode APDU.");
|
||||
}
|
||||
|
||||
int res = exchange_14b_apdu(data, datalen, activate_field, leave_signal_on, data, PM3_CMD_DATA_SIZE, &datalen);
|
||||
int res = exchange_14b_apdu(data, datalen, activate_field, leave_signal_on, data, PM3_CMD_DATA_SIZE, &datalen, user_timeout);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
@ -1708,7 +1841,7 @@ static int CmdHF14BNdef(const char *Cmd) {
|
|||
uint8_t aSELECT_AID[80];
|
||||
int aSELECT_AID_n = 0;
|
||||
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
|
||||
int res = exchange_14b_apdu(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
int res = exchange_14b_apdu(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
|
||||
if (res) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -1734,7 +1867,7 @@ static int CmdHF14BNdef(const char *Cmd) {
|
|||
uint8_t aSELECT_FILE_NDEF[30];
|
||||
int aSELECT_FILE_NDEF_n = 0;
|
||||
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
|
||||
res = exchange_14b_apdu(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
res = exchange_14b_apdu(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
|
@ -1749,7 +1882,7 @@ static int CmdHF14BNdef(const char *Cmd) {
|
|||
uint8_t aREAD_NDEF[30];
|
||||
int aREAD_NDEF_n = 0;
|
||||
param_gethex_to_eol("00b0000002", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
|
||||
res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
|
||||
if (res) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -1768,7 +1901,7 @@ static int CmdHF14BNdef(const char *Cmd) {
|
|||
aREAD_NDEF_n = 0;
|
||||
param_gethex_to_eol("00b00002", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
|
||||
aREAD_NDEF[4] = offset;
|
||||
res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
|
||||
res = exchange_14b_apdu(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen, -1);
|
||||
if (res) {
|
||||
goto out;
|
||||
}
|
||||
|
@ -1816,14 +1949,14 @@ int CmdHF14B(const char *Cmd) {
|
|||
}
|
||||
|
||||
// get and print all info known about any known 14b tag
|
||||
int infoHF14B(bool verbose) {
|
||||
int infoHF14B(bool verbose, bool do_aid_search) {
|
||||
|
||||
// try std 14b (atqb)
|
||||
if (HF14B_Std_Info(verbose))
|
||||
if (HF14B_Std_Info(verbose, do_aid_search))
|
||||
return 1;
|
||||
|
||||
// try ST 14b
|
||||
if (HF14B_ST_Info(verbose))
|
||||
if (HF14B_ST_Info(verbose, do_aid_search))
|
||||
return 1;
|
||||
|
||||
// try unknown 14b read commands (to be identified later)
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
int CmdHF14B(const char *Cmd);
|
||||
|
||||
int infoHF14B(bool verbose);
|
||||
int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field, bool leave_signal_on, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, int user_timeout);
|
||||
|
||||
int infoHF14B(bool verbose, bool do_aid_search);
|
||||
int readHF14B(bool verbose);
|
||||
#endif
|
||||
|
|
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