Merge pull request #1 from Proxmark/master

test update
This commit is contained in:
Artem V Gnatyuk 2018-11-01 17:27:55 +07:00 committed by GitHub
commit b887641ae8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
278 changed files with 40981 additions and 10323 deletions

2
.gitignore vendored
View file

@ -18,8 +18,10 @@
!client/hardnested/tables/*.z
usb_cmd.lua
version.c
armsrc/fpga_version_info.c
client/ui/ui_overlays.h
*.Td
.DS_Store
*.exe
hardnested_stats.txt

View file

@ -2,21 +2,73 @@
All notable changes to this project will be documented in this file.
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
## [unreleased][unreleased]
### Changed
- Improved backdoor detection missbehaving magic s50/1k tag (Fl0-0)
- Changed hf mfp security. Now it works in all the modes. (drHatson)
### Fixed
### Added
- `hf mfp` group of commands (Merlok)
## [v3.1.0][2018-10-10]
### Changed
- Adjusted `lf cmdread` to respond to client when complete and the client will then automatically call `data samples`
- Improved backdoor detection misbehaving magic s50/1k tag (Fl0-0)
- Deleted wipe functionality from `hf mf csetuid` (Merlok)
- Changed `hf mf nested` logic (Merlok)
- Added `hf mf nested` mode: autosearch keys for attack (from well known keys) (Merlok)
- `hf mf nested` Check keys after they have found (Merlok)
- `hf mf chk` Move main cycle to arm (Merlok)
- Changed proxmark command line parameter `flush` to `-f` or `-flush` (Merlok)
- Changed `hf 14a reader` to just request-anticolission-select sequence (Merlok)
- Changed `hf 14a raw` - works with LED's and some exchange logic (Merlok)
- Changed TLV parser messages to more convenient (Merlok)
- Rewritten Legic Prime reader (`hf legic reader`, `write` and `fill`) - it is using xcorrelation now (AntiCat)
- `hf 14a` commands works via argtable3 commandline parsing library (Merlok)
- HID LF operations on firmware updated for complete native support of long (>37 bit) HID tags (grauerfuchs)
- Changed Legic Prime tag simulator (`hf legic sim`) to run from 212 kHz SSP clock for better reliability (AntiCat)
### Fixed
- Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok)
- Changed driver file proxmark3.inf to support both old and new Product/Vendor IDs (piwi)
- Changed all command line parsers in `hf emv` commands to argtable (Merlok)
- Implemented AppNap API, fixing #283 and #627 OSX USB comm issues (AntiCat)
### Added
- Added `sc` smartcard (contact card) commands - reader, info, raw, upgrade, setclock, list (hardware version RDV4.0 only) must turn option on in makefile options (Willok, Iceman, marshmellow)
- Added a bitbang mode to `lf cmdread` if delay is 0 the cmd bits turn off and on the antenna with 0 and 1 respectively (marshmellow)
- Added PAC/Stanley detection to lf search (marshmellow)
- Added lf pac demod and lf pac read - extracts the raw blocks from a PAC/Stanley tag (marshmellow)
- Added hf mf c* commands compatibity for 4k and gen1b backdoor (Fl0-0)
- Added hf mf c* commands compatibility for 4k and gen1b backdoor (Fl0-0)
- Added backdoor detection for gen1b magic s70/4k tag (Fl0-0)
- Added data fsktonrz, a fsk cleaning/demodulating routine for weak fsk signal. Note: follow this up with a `data rawdemod nr` to finish demoding your signal. (marshmellow)
- Added lf em 410xbrute, LF EM410x reader bruteforce attack by simulating UIDs from a file (Fl0-0)
- Added `hf mf cwipe` command. It wipes "magic Chinese" card. For 1a generation it uses card's "wipe" command. For gen1a and gen1b it uses a write command. (Merlok)
- Added to `hf mf nested` source key check before attack (Merlok)
- Added to `hf mf nested` after attack it checks all found keys on non-open sectors (Merlok)
- `hf mf chk` Added settings to set iso14443a operations timeout. default timeout set to 500us (Merlok)
- Added to `hf mf nested` parameters `s` and `ss` for checking slow cards (Merlok)
- Added to proxmark command line parameters `w` - wait 20s for serial port (Merlok)
- Added to proxmark command line parameters `c` and `l` - execute command and lua script from command line (Merlok)
- Added to proxmark ability to execute commands from stdin (pipe) (Merlok)
- Added `hf 14a info` and moved there functionality from `hf 14a reader` (Merlok)
- Added to `hf 14a info` detection of weak prng from Iceman1001 fork (Merlok)
- Added to `hf 14a apdu` - exchange apdu via iso1443-4 (Merlok)
- Added to `hf 14a apdu` - apdu and tlv results parser (Merlok)
- Added `hf emv` group of commands (Merlok)
- Added `hf emv search` `hf emv pse` - commands for selection of EMV application (Merlok)
- Added `hf emv select` - command for select EMV application (Merlok)
- Added `hf emv exec` - command for execute EMV transaction (Merlok)
- Added to `hf emv exec` MSD path for VISA and Mastercard and some other compatible EMV cards (Merlok)
- Added to `hf emv exec` SDA, DDA, fast DDA, CDA calculations for VISA and Mastercard and some other compatible EMV cards (Merlok)
- Added `hf emv test` - crypto tests for DES, AES, SHA, RSA, SDA, DDA, CDA and some other crypto functions (Merlok)
- Added `hf list mf` - deciphers crypto1 stream and works with first authentication and weak nested authentications (Merlok)
- Added to `hf emv` commands: `gpo`, `readrec`, `genac`, `challenge`, `intauth` - commands working with EMV cards (Merlok)
- Added `lf hid encode` and `lf hid decode` commands to translate printed HID card data to and from the packed data transmitted by a prox tag (grauerfuchs)
- Added `lf hid write` command, which operates as a macro for encode followed by clone operations (grauerfuchs)
## [3.0.1][2017-06-08]
@ -32,7 +84,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
- Added lf hitag write 24, the command writes a block to hitag2 tags in crypto mode (henjo)
### Added
- Added hf mf hardnested, an attack working for hardened Mifare cards (EV1, Mifare Plus SL1) where hf mf nested fails
- Added hf mf hardnested, an attack working for hardened Mifare cards (EV1, Mifare Plus SL1) where hf mf nested fails (piwi)
- Added experimental testmode write option for t55xx (danger) (marshmellow)
- Added t55xx p1detect to `lf search` chip detections (marshmellow)
- Added lf t55xx p1detect, detect page 1 of a t55xx tag based on E015 mfg code (marshmellow)
@ -194,5 +246,3 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
### Added
- iClass functionality: full simulation of iclass tags, so tags can be simulated with data (not only CSN). Not yet support for write/update, but readers don't seem to enforce update. (holiman).
- iClass decryption. Proxmark can now decrypt data on an iclass tag, but requires you to have the HID decryption key locally on your computer, as this is not bundled with the sourcecode.

55
CI/.travis.yml Normal file
View file

@ -0,0 +1,55 @@
# Travis-CI config
# variable REPOSITORY_EP must be filled with repository name. as sample: "merlokk/proxmark3"
language: c
compiler: gcc
# Test on Linux and MacOS
matrix:
include:
- os: osx
osx_image: xcode7.3 # OS X 10.11
- os: osx
osx_image: xcode8.3 # OS X 10.12
- os: osx
osx_image: xcode9.4 # OS X 10.13
- os: osx
osx_image: xcode10 # OS X 10.13
- os: linux
dist: trusty
sudo: required
before_install:
## Install ARM toolchain on Linux.
## add our homebrew tap for MacOS
## Note: all dependencies on MacOS should be resolved by the brew install command
echo $REPOSITORY_EP;
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
sudo apt-get update -qq;
sudo apt-get install -y gcc-arm-none-eabi;
elif [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew update;
if [[ "$REPOSITORY_EP" == "" ]]; then
brew tap proxmark/proxmark3;
else
brew tap "$REPOSITORY_EP" --env=std;
fi
fi
install:
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
brew info proxmark3;
brew install -v --HEAD proxmark3;
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
make all;
fi
before_script:
script:
## for the time being we are satisfied if it can be build and then successfully started
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then
proxmark3 /dev/notexists travis_test_commands.scr ;
elif [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
./client/proxmark3 /dev/notexists travis_test_commands.scr ;
fi

321
CI/appveyor.yml Normal file
View file

@ -0,0 +1,321 @@
version: 3.0.1.{build}
image: Visual Studio 2017
clone_folder: C:\ProxSpace\pm3
init:
- ps: >-
$psversiontable
#Get-ChildItem Env:
$releasename=""
$env:APPVEYOR_REPO_COMMIT_SHORT = $env:APPVEYOR_REPO_COMMIT.Substring(0, 8)
if ($env:appveyor_repo_tag -match "true"){
$releasename=$env:APPVEYOR_REPO_TAG_NAME + "/"
}
$releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT_SHORT + "]"
Write-Host "repository: $env:appveyor_repo_name branch:$env:APPVEYOR_REPO_BRANCH release: $releasename" -ForegroundColor Yellow
Add-AppveyorMessage -Message "[$env:APPVEYOR_REPO_COMMIT_SHORT]$env:appveyor_repo_name($env:APPVEYOR_REPO_BRANCH)" -Category Information -Details "repository: $env:appveyor_repo_name branch: $env:APPVEYOR_REPO_BRANCH release: $releasename"
iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
clone_script:
- ps: >-
Write-Host "Removing ProxSpace..." -NoNewLine
cd \
Remove-Item -Recurse -Force -Path c:\ProxSpace\*
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Git clone ProxSpace..." -NoNewLine
git clone -q https://github.com/Gator96100/ProxSpace c:\ProxSpace
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Removing pm3 dir..." -NoNewLine
Remove-Item -Recurse -Force -Path c:\ProxSpace\pm3\*
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." -NoNewLine
if(-not $env:appveyor_pull_request_number) {
git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder
cd $env:appveyor_build_folder
git checkout -qf $env:appveyor_repo_commit
} else {
git clone -q https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder
cd $env:appveyor_build_folder
git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge:
git checkout -qf FETCH_HEAD
}
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Fill msys2\etc\fstab file..." -NoNewLine
New-Item c:\ProxSpace\msys2\etc\fstab -type file -force -value "# For a description of the file format, see the Users Guide`n# http://cygwin.com/cygwin-ug-net/using.html#mount-table`nnone / cygdrive binary,posix=0,noacl,user 0 0 `nC:\ProxSpace\pm3 /pm3 ntfs noacl 0 0 `nC:\ProxSpace\gcc-arm-none-eabi /gcc-arm-none-eabi ntfs noacl 0 0 `n"
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Update msys2 packages..." -NoNewLine
$env:Path = "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path"
C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1
C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1
Write-Host "[ OK ]" -ForegroundColor Green
install:
- ps: >-
function Exec-External {
param(
[Parameter(Position=0,Mandatory=1)][scriptblock] $command
)
& $command
if ($LASTEXITCODE -ne 0) {
throw ("Command returned non-zero error-code ${LASTEXITCODE}: $command")
}
}
build_script:
- ps: >-
"C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path"
$env:MINGW_HOME="C:\ProxSpace\msys2\mingw32"
$env:MSYS_HOME="C:\ProxSpace\msys2"
$env:MSYSTEM="MINGW32"
$env:MINGW_PREFIX="/mingw32"
$env:SHELL="/bin/bash"
$env:MSYSTEM_CHOST="i686-w64-mingw32"
#make
bash -c -i 'pwd;make clean;make all'
#some checks
if(!(Test-Path C:\ProxSpace\pm3\client\proxmark3.exe)){
throw "Main file proxmark3.exe not exists."
}
if(!(Test-Path C:\ProxSpace\pm3\armsrc\obj\fullimage.elf)){
throw "ARM file fullimage.elf not exists."
}
if(!(Test-Path C:\ProxSpace\pm3\client\hardnested\tables\*.bin.z)){
throw "Files in hardnested\tables not exists."
}
#copy
Write-Host "Copy release files..." -NoNewLine -ForegroundColor Yellow
New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release
Copy-Item C:\ProxSpace\pm3\client\*.exe C:\ProxSpace\Release
New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release\arm
Copy-Item C:\ProxSpace\pm3\armsrc\obj\*.elf C:\ProxSpace\Release\arm
Copy-Item C:\ProxSpace\pm3\bootrom\obj\*.elf C:\ProxSpace\Release\arm
New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release\scripts
Copy-Item C:\ProxSpace\pm3\client\scripts\*.lua C:\ProxSpace\Release\scripts
New-Item -ItemType Directory -Force -Path C:\ProxSpace\Release\hardnested\tables
Copy-Item C:\ProxSpace\pm3\client\hardnested\*.bin C:\ProxSpace\Release\hardnested
Copy-Item C:\ProxSpace\pm3\client\hardnested\tables\*.bin.z C:\ProxSpace\Release\hardnested\tables
Write-Host "[ OK ]" -ForegroundColor Green
#archive and push
$releasename=""
if ($env:appveyor_repo_tag -match "true"){
$releasename=$env:APPVEYOR_REPO_TAG_NAME + "/"
}
$releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT.Substring(0, 7) + "]"
Write-Host "Archive and publish release files ($releasename)..." -NoNewLine -ForegroundColor Yellow
cd C:\ProxSpace
7z a release.zip C:\ProxSpace\Release
Push-AppveyorArtifact release.zip -DeploymentName "$releasename"
Write-Host "[ OK ]" -ForegroundColor Green
Write-Host "Builded..." -ForegroundColor Yellow
test_script:
- ps: >-
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
cd c:\ProxSpace\pm3
$global:TestsPassed=$true
Function ExecTest($Name, $File, $Cmd, $CheckResult) {
#--- begin Job
$Job = Start-Job -ScriptBlock {
[bool]$res=$false
$TestTime=[System.Environment]::TickCount
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
Set-Location $using:PWD
$sb=[scriptblock]::Create("$using:Cmd")
#execute scriptblock
Write-host "Test [$using:Name] job: $using:Cmd"
$Cond=&$sb
if ($Cond -eq $null){
} ElseIf($using:CheckResult -ne $null) {
[String]$searchstr=""
if ($Cond -is [Object]){
ForEach($line in $Cond){
Write-host $line -ForegroundColor Gray
$searchstr += $line
}
}else{
Write-host "$Cond" -ForegroundColor Gray
$searchstr = $Cond
}
If($searchstr -like "*$using:CheckResult*") {
$res=$true
}
$Cond="*$using:CheckResult*"
} Else {
If (!($Cond -is [bool] -or $Cond -is [byte] -or $Cond -is [int16] -or $Cond -is [int32] -or $Cond -is [int64] -or $Cond -is [float])){
if ($Cond -is "String" -and $Cond -like "*passed*"){
$res= $true
}
if ($Cond -is "String" -and $Cond -like "*true*"){
$res= $true
}
} Else {
$res=$Cond
}
}
If ($res) {
Write-host "Result[$using:Name]: $Cond" -ForegroundColor Green
Add-AppveyorTest -Name "$using:Name" -Framework NUnit -Filename "$using:File" -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)"
}Else {
Write-host "Result[$using:Name]: $Cond" -ForegroundColor Red
Add-AppveyorTest -Name "$using:Name" -Framework NUnit -Filename "$using:File" -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)" -ErrorMessage "command:$using:Cmd`nresult:$Cond"
}
return $res
}
#--- end Job
[bool]$res=$false
# Wait 120 sec timeout for Job
if(Wait-Job $Job -Timeout 150){
$Results = $Job | Receive-Job
if($Results -like "true"){
$res=$true
}
} else {
Write-host "Test [$Name] timeout" -ForegroundColor Red
Add-AppveyorTest -Name "$Name" -Framework NUnit -Filename "$File" -Outcome Failed -Duration 60000 -ErrorMessage "timeout"
}
Remove-Job -Force $Job
if(!$res){
$global:TestsPassed=$false
}
}
Write-Host "Running tests..." -ForegroundColor Yellow
#file test
ExecTest "proxmark3 exists" "proxmark3.exe" {Test-Path C:\ProxSpace\Release\proxmark3.exe}
ExecTest "arm image exists" "\arm\fullimage1.elf" {Test-Path C:\ProxSpace\Release\arm\fullimage.elf}
ExecTest "bootrom exists" "bootrom.elf" {Test-Path C:\ProxSpace\Release\arm\bootrom.elf}
ExecTest "hardnested tables exists" "hardnested" {Test-Path C:\ProxSpace\Release\hardnested\tables\*.z}
ExecTest "release exists" "release.zip" {Test-Path C:\ProxSpace\release.zip}
#proxmark logic tests
ExecTest "proxmark help" "proxmark3 -h" {bash -lc 'cd ~/client;./proxmark3 -h | grep -q Execute && echo Passed || echo Failed'}
ExecTest "proxmark help hardnested" "proxmark3 -h" {bash -lc 'cd ~/client;./proxmark3 -h | grep -q hardnested && echo Passed || echo Failed'}
ExecTest "hf mf offline text" "hf mf" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf mf'"} "at_enc"
ExecTest "hf mf hardnested" "hf mf hardnested" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf mf hardnested t 1 000000000000'"} "found:"
#proxmark crypto tests
ExecTest "hf emv test" "hf emv test" {bash -lc "cd ~/client;./proxmark3 comx -c 'hf emv test'"} "Tests ?OK"
if ($global:TestsPassed) {
Write-Host "Tests [ OK ]" -ForegroundColor Green
} else {
Write-Host "Tests [ ERROR ]" -ForegroundColor Red
throw "Tests error."
}
on_success:
- ps: Write-Host "Build success..." -ForegroundColor Green
on_failure:
- ps: Write-Host "Build error." -ForegroundColor Red
on_finish:
- ps: $blockRdp = $false; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))

20
CI/readme.md Normal file
View file

@ -0,0 +1,20 @@
# How to configure continuous integration
Here 2 CI configuration files:
1. for [travis](travis-ci.org)
2. for [appveyor](appveyor.com)
It needs to put files from this directory to repository root and then configure CI from appropriate WEB portal.
## travis
- Copy .travis.yml and travis_test_commands.scr files to repository root
- Configure CI from http://travis-ci.org
- It needs to fork https://github.com/Proxmark/homebrew-proxmark3 from your proxmark repository home
- Put to file `proxmark3.rb` in line `head "https://github.com/proxmark/proxmark3.git"` your repository link. As sample: `head "https://github.com/merlokk/proxmark3.git"`
## appveyor
- Just copy appveyor.yml file to root and configure it from http://appveyor.com

View file

@ -0,0 +1,3 @@
hf mf hardnested t 1 000000000000
hf emv test
exit

View file

@ -1,56 +1,38 @@
NOTICE:
(2014-03-26)
This is now the official Proxmark repository!
INTRODUCTION:
# proxmark3: the official Proxmark repository!
The proxmark3 is a powerful general purpose RFID tool, the size of a deck
of cards, designed to snoop, listen and emulate everything from
Low Frequency (125kHz) to High Frequency (13.56MHz) tags.
**Low Frequency (125kHz)** to **High Frequency (13.56MHz)** tags.
This repository contains enough software, logic (for the FPGA), and design
documentation for the hardware that you could, at least in theory,
do something useful with a proxmark3.
RESOURCES:
## Resources
* This repository!
https://github.com/Proxmark/proxmark3
* [This repository!](https://github.com/Proxmark/proxmark3)
* [The Wiki](https://github.com/Proxmark/proxmark3/wiki)
* [The GitHub Pages website](http://proxmark.github.io/proxmark3/)
* [The Forum](http://www.proxmark.org/forum)
* The IRC channel: irc.freenode.org #proxmark3 ([chat in your browser](http://webchat.freenode.net/?channels=#proxmark3))
* [The Homebrew formula repository](https://github.com/Proxmark/homebrew-proxmark3)
* The Wiki
https://github.com/Proxmark/proxmark3/wiki
* The GitHub page
http://proxmark.github.io/proxmark3/
* The Forum
http://www.proxmark.org/forum
* The IRC chanel
irc.freenode.org #proxmark3
-or-
http://webchat.freenode.net/?channels=#proxmark3
* The Homebrew formula repository
https://github.com/Proxmark/homebrew-proxmark3
DEVELOPMENT:
## Development
The tools required to build or run the project will vary depending on
your operating system. Please refer to the Wiki for details.
your operating system. Please refer to [the wiki](https://github.com/Proxmark/proxmark3/wiki) for details.
* https://github.com/Proxmark/proxmark3/wiki
OBTAINING HARDWARE:
## Obtaining hardware
The Proxmark3 is available for purchase (assembled and tested) from the
following locations:
* https://proxmark3.com/ - RyscCorp (us)
* http://www.elechouse.com/ - Elechouse (HK)
* https://lab401.com/ - Lab401 (FR)
* http://www.rfxsecure.com/ - RFxSecure (SG)
* http://proxmark3.tictail.com/ - IceSQL (SE)
* [RyscCorp](https://proxmark3.com/) (US)
* [Hackerwarehouse](https://hackerwarehouse.com/) (US)
* [Elechouse](http://www.elechouse.com/) (HK)
* [Lab401](https://lab401.com/) (FR)
* [RFxSecure](http://www.rfxsecure.com/) (SG)
* [IceSQL](http://proxmark3.tictail.com/) (SE)
Most of the ultra-low-volume contract assemblers could put
something like this together with a reasonable yield. A run of around
@ -70,7 +52,7 @@ The printed circuit board artwork is also available, as Gerbers and an
Excellon drill file.
LICENSING:
## License
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View file

@ -136,6 +136,10 @@ void set_tracing(bool enable) {
tracing = enable;
}
bool get_tracing(void) {
return tracing;
}
/**
* Get the number of bytes traced
* @return

View file

@ -37,6 +37,7 @@ extern void BigBuf_print_status(void);
extern uint16_t BigBuf_get_traceLen(void);
extern void clear_trace(void);
extern void set_tracing(bool enable);
extern bool get_tracing(void);
extern bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t iLen, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
extern int LogTraceHitag(const uint8_t * btBytes, int iBits, int iSamples, uint32_t dwParity, int bReader);
extern uint8_t emlSet(uint8_t *data, uint32_t offset, uint32_t length);

View file

@ -10,17 +10,23 @@ APP_INCLUDES = apps.h
#remove one of the following defines and comment out the relevant line
#in the next section to remove that particular feature from compilation
APP_CFLAGS = -DWITH_ISO14443a_StandAlone -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b -DWITH_ICLASS -DWITH_LEGICRF -DWITH_HITAG -DWITH_CRC -DON_DEVICE -DWITH_HFSNOOP \
APP_CFLAGS = -DON_DEVICE \
-fno-strict-aliasing -ffunction-sections -fdata-sections
#-DWITH_LCD
#SRC_LCD = fonts.c LCD.c
include ../common/Makefile_Enabled_Options.common
ifneq (,$(findstring WITH_LCD,$(APP_CFLAGS)))
SRC_LCD = fonts.c LCD.c
else
SRC_LCD =
endif
SRC_LF = lfops.c hitag2.c hitagS.c lfsampling.c pcf7931.c lfdemod.c protocols.c
SRC_ISO15693 = iso15693.c iso15693tools.c
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c
SRC_ISO14443a = epa.c iso14443a.c mifareutil.c mifarecmd.c mifaresniff.c mifaresim.c
SRC_ISO14443b = iso14443b.c
SRC_CRAPTO1 = crypto1.c des.c
SRC_CRC = iso14443crc.c crc.c crc16.c crc32.c parity.c
SRC_SMARTCARD = i2c.c
#the FPGA bitstream files. Note: order matters!
FPGA_BITSTREAMS = fpga_lf.bit fpga_hf.bit
@ -39,6 +45,7 @@ THUMBSRC = start.c \
$(SRC_ISO15693) \
$(SRC_LF) \
$(SRC_ZLIB) \
$(SRC_SMARTCARD) \
appmain.c \
printf.c \
util.c \
@ -49,16 +56,20 @@ THUMBSRC = start.c \
# These are to be compiled in ARM mode
ARMSRC = fpgaloader.c \
legicrf.c \
legicrfsim.c \
legic_prng.c \
$(SRC_ISO14443a) \
$(SRC_ISO14443b) \
$(SRC_CRAPTO1) \
$(SRC_CRC) \
legic_prng.c \
iclass.c \
BigBuf.c \
optimized_cipher.c \
hfsnoop.c
VERSIONSRC = version.c \
fpga_version_info.c
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
include ../common/Makefile.common
@ -69,6 +80,14 @@ all: $(OBJS)
.DELETE_ON_ERROR:
# version.c should be remade on every compilation
.PHONY: version.c
version.c: default_version.c
perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@
fpga_version_info.c: $(FPGA_BITSTREAMS) $(FPGA_COMPRESSOR)
$(FPGA_COMPRESSOR) -v $(filter %.bit,$^) $@
$(OBJDIR)/fpga_all.o: $(OBJDIR)/fpga_all.bit.z
$(OBJCOPY) -O elf32-littlearm -I binary -B arm --prefix-sections=fpga_all_bit $^ $@

View file

@ -16,22 +16,26 @@
#include "cmd.h"
#include "proxmark3.h"
#include "apps.h"
#include "fpga.h"
#include "util.h"
#include "printf.h"
#include "string.h"
#include "legicrf.h"
#include "legicrfsim.h"
#include "hitag2.h"
#include "hitagS.h"
#include "lfsampling.h"
#include "BigBuf.h"
#include "mifareutil.h"
#include "pcf7931.h"
#include "i2c.h"
#ifdef WITH_LCD
#include "LCD.h"
#endif
// Craig Young - 14a stand-alone code
#ifdef WITH_ISO14443a_StandAlone
#ifdef WITH_ISO14443a
#include "iso14443a.h"
#endif
@ -136,34 +140,27 @@ void Dbhexdump(int len, uint8_t *d, bool bAsci) {
//-----------------------------------------------------------------------------
static int ReadAdc(int ch)
{
uint32_t d;
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
AT91C_BASE_ADC->ADC_MR =
ADC_MODE_PRESCALE(63 /* was 32 */) | // ADC_CLK = MCK / ((63+1) * 2) = 48MHz / 128 = 375kHz
ADC_MODE_STARTUP_TIME(1 /* was 16 */) | // Startup Time = (1+1) * 8 / ADC_CLK = 16 / 375kHz = 42,7us Note: must be > 20us
ADC_MODE_SAMPLE_HOLD_TIME(15 /* was 8 */); // Sample & Hold Time SHTIM = 15 / ADC_CLK = 15 / 375kHz = 40us
// Note: ADC_MODE_PRESCALE and ADC_MODE_SAMPLE_HOLD_TIME are set to the maximum allowed value.
// Both AMPL_LO and AMPL_HI are very high impedance (10MOhm) outputs, the input capacitance of the ADC is 12pF (typical). This results in a time constant
// of RC = 10MOhm * 12pF = 120us. Even after the maximum configurable sample&hold time of 40us the input capacitor will not be fully charged.
// AMPL_HI is a high impedance (10MOhm || 1MOhm) output, the input capacitance of the ADC is 12pF (typical). This results in a time constant
// of RC = (0.91MOhm) * 12pF = 10.9us. Even after the maximum configurable sample&hold time of 40us the input capacitor will not be fully charged.
//
// The maths are:
// If there is a voltage v_in at the input, the voltage v_cap at the capacitor (this is what we are measuring) will be
//
// v_cap = v_in * (1 - exp(-RC/SHTIM)) = v_in * (1 - exp(-3)) = v_in * 0,95 (i.e. an error of 5%)
//
// Note: with the "historic" values in the comments above, the error was 34% !!!
// v_cap = v_in * (1 - exp(-SHTIM/RC)) = v_in * (1 - exp(-40us/10.9us)) = v_in * 0,97 (i.e. an error of 3%)
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST;
AT91C_BASE_ADC->ADC_MR =
ADC_MODE_PRESCALE(63) | // ADC_CLK = MCK / ((63+1) * 2) = 48MHz / 128 = 375kHz
ADC_MODE_STARTUP_TIME(1) | // Startup Time = (1+1) * 8 / ADC_CLK = 16 / 375kHz = 42,7us Note: must be > 20us
ADC_MODE_SAMPLE_HOLD_TIME(15); // Sample & Hold Time SHTIM = 15 / ADC_CLK = 15 / 375kHz = 40us
AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ch);
AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START;
while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch)))
;
d = AT91C_BASE_ADC->ADC_CDR[ch];
while(!(AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ch))) {};
return d;
return AT91C_BASE_ADC->ADC_CDR[ch] & 0x3ff;
}
int AvgAdc(int ch) // was static - merlok
@ -178,6 +175,26 @@ int AvgAdc(int ch) // was static - merlok
return (a + 15) >> 5;
}
static int AvgAdc_Voltage_HF(void)
{
int AvgAdc_Voltage_Low, AvgAdc_Voltage_High;
AvgAdc_Voltage_Low= (MAX_ADC_HF_VOLTAGE_LOW * AvgAdc(ADC_CHAN_HF_LOW)) >> 10;
// if voltage range is about to be exceeded, use high voltage ADC channel if available (RDV40 only)
if (AvgAdc_Voltage_Low > MAX_ADC_HF_VOLTAGE_LOW - 300) {
AvgAdc_Voltage_High = (MAX_ADC_HF_VOLTAGE_HIGH * AvgAdc(ADC_CHAN_HF_HIGH)) >> 10;
if (AvgAdc_Voltage_High >= AvgAdc_Voltage_Low) {
return AvgAdc_Voltage_High;
}
}
return AvgAdc_Voltage_Low;
}
static int AvgAdc_Voltage_LF(void)
{
return (MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10;
}
void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv, uint8_t LF_Results[])
{
int i, adcval = 0, peak = 0;
@ -193,15 +210,17 @@ void MeasureAntennaTuningLfOnly(int *vLf125, int *vLf134, int *peakf, int *peakv
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
SpinDelay(50);
for (i=255; i>=19; i--) {
WDT_HIT();
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, i);
SpinDelay(20);
adcval = ((MAX_ADC_LF_VOLTAGE * AvgAdc(ADC_CHAN_LF)) >> 10);
adcval = AvgAdc_Voltage_LF();
if (i==95) *vLf125 = adcval; // voltage at 125Khz
if (i==89) *vLf134 = adcval; // voltage at 134Khz
LF_Results[i] = adcval>>8; // scale int to fit in byte for graphing purposes
LF_Results[i] = adcval >> 9; // scale int to fit in byte for graphing purposes
if(LF_Results[i] > peak) {
*peakv = adcval;
peak = LF_Results[i];
@ -222,9 +241,8 @@ void MeasureAntennaTuningHfOnly(int *vHf)
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
SpinDelay(20);
*vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
*vHf = AvgAdc_Voltage_HF();
LED_A_OFF();
return;
}
@ -249,7 +267,7 @@ void MeasureAntennaTuning(int mode)
}
}
cmd_send(CMD_MEASURED_ANTENNA_TUNING, vLf125 | (vLf134<<16), vHf, peakf | (peakv<<16), LF_Results, 256);
cmd_send(CMD_MEASURED_ANTENNA_TUNING, vLf125>>1 | (vLf134>>1<<16), vHf, peakf | (peakv>>1<<16), LF_Results, 256);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_B_OFF();
return;
@ -266,8 +284,8 @@ void MeasureAntennaTuningHf(void)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
for (;;) {
SpinDelay(20);
vHf = (MAX_ADC_HF_VOLTAGE * AvgAdc(ADC_CHAN_HF)) >> 10;
SpinDelay(500);
vHf = AvgAdc_Voltage_HF();
Dbprintf("%d mV",vHf);
if (BUTTON_PRESS()) break;
@ -291,6 +309,8 @@ void ReadMem(int addr)
extern struct version_information version_information;
/* bootrom version information is pointed to from _bootphase1_version_pointer */
extern char *_bootphase1_version_pointer, _flash_start, _flash_end, _bootrom_start, _bootrom_end, __data_src_start__;
void SendVersion(void)
{
char temp[USB_CMD_DATA_SIZE]; /* Limited data payload in USB packets */
@ -311,10 +331,17 @@ void SendVersion(void)
FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information);
strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1);
FpgaGatherVersion(FPGA_BITSTREAM_LF, temp, sizeof(temp));
strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1);
FpgaGatherVersion(FPGA_BITSTREAM_HF, temp, sizeof(temp));
strncat(VersionString, temp, sizeof(VersionString) - strlen(VersionString) - 1);
for (int i = 0; i < fpga_bitstream_num; i++) {
strncat(VersionString, fpga_version_information[i], sizeof(VersionString) - strlen(VersionString) - 1);
strncat(VersionString, "\n", sizeof(VersionString) - strlen(VersionString) - 1);
}
// test availability of SmartCard slot
if (I2C_is_available()) {
strncat(VersionString, "SmartCard Slot: available\n", sizeof(VersionString) - strlen(VersionString) - 1);
} else {
strncat(VersionString, "SmartCard Slot: not available\n", sizeof(VersionString) - strlen(VersionString) - 1);
}
// Send Chip ID and used flash memory
uint32_t text_and_rodata_section_size = (uint32_t)&__data_src_start__ - (uint32_t)&_flash_start;
@ -358,17 +385,20 @@ void SendStatus(void)
{
BigBuf_print_status();
Fpga_print_status();
#ifdef WITH_SMARTCARD
I2C_print_status();
#endif
printConfig(); //LF Sampling config
printUSBSpeed();
Dbprintf("Various");
Dbprintf(" MF_DBGLEVEL......%d", MF_DBGLEVEL);
Dbprintf(" ToSendMax........%d",ToSendMax);
Dbprintf(" ToSendBit........%d",ToSendBit);
Dbprintf(" MF_DBGLEVEL........%d", MF_DBGLEVEL);
Dbprintf(" ToSendMax..........%d", ToSendMax);
Dbprintf(" ToSendBit..........%d", ToSendBit);
cmd_send(CMD_ACK,1,0,0,0,0);
}
#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF)
#if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF_StandAlone)
#define OPTS 2
@ -399,8 +429,8 @@ void StandAloneMode14a()
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
int selected = 0;
int playing = 0, iGotoRecord = 0, iGotoClone = 0;
int cardRead[OPTS] = {0};
bool playing = false, GotoRecord = false, GotoClone = false;
bool cardRead[OPTS] = {false};
uint8_t readUID[10] = {0};
uint32_t uid_1st[OPTS]={0};
uint32_t uid_2nd[OPTS]={0};
@ -416,9 +446,9 @@ void StandAloneMode14a()
WDT_HIT();
SpinDelay(300);
if (iGotoRecord == 1 || cardRead[selected] == 0)
if (GotoRecord || !cardRead[selected])
{
iGotoRecord = 0;
GotoRecord = false;
LEDsoff();
LED(selected + 1, 0);
LED(LED_RED2, 0);
@ -443,14 +473,14 @@ void StandAloneMode14a()
else if (cardRead[(selected+1)%OPTS]) {
Dbprintf("Button press detected but no card in bank[%d] so playing from bank[%d]", selected, (selected+1)%OPTS);
selected = (selected+1)%OPTS;
break; // playing = 1;
break;
}
else {
Dbprintf("Button press detected but no stored tag to play. (Ignoring button)");
SpinDelay(300);
}
}
if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid, true, 0))
if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid, true, 0, true))
continue;
else
{
@ -493,14 +523,14 @@ void StandAloneMode14a()
LED(selected + 1, 0);
// Next state is replay:
playing = 1;
playing = true;
cardRead[selected] = 1;
cardRead[selected] = true;
}
/* MF Classic UID clone */
else if (iGotoClone==1)
else if (GotoClone)
{
iGotoClone=0;
GotoClone=false;
LEDsoff();
LED(selected + 1, 0);
LED(LED_ORANGE, 250);
@ -551,7 +581,7 @@ void StandAloneMode14a()
MifareCGetBlock(0x3F, 1, 0, oldBlock0);
if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) {
Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected);
playing = 1;
playing = true;
}
else {
Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0],oldBlock0[1],oldBlock0[2],oldBlock0[3]);
@ -569,14 +599,14 @@ void StandAloneMode14a()
if (memcmp(testBlock0,newBlock0,16)==0)
{
DbpString("Cloned successfull!");
cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it
playing = 0;
iGotoRecord = 1;
cardRead[selected] = false; // Only if the card was cloned successfully should we clear it
playing = false;
GotoRecord = true;
selected = (selected+1) % OPTS;
}
else {
Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected);
playing = 1;
playing = true;
}
}
LEDsoff();
@ -584,14 +614,12 @@ void StandAloneMode14a()
}
// Change where to record (or begin playing)
else if (playing==1) // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected])
else if (playing) // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected])
{
LEDsoff();
LED(selected + 1, 0);
// Begin transmitting
if (playing)
{
LED(LED_GREEN, 0);
DbpString("Playing");
for ( ; ; ) {
@ -620,12 +648,12 @@ void StandAloneMode14a()
else if (button_action == BUTTON_SINGLE_CLICK) {
selected = (selected + 1) % OPTS;
Dbprintf("Done playing. Switching to record mode on bank %d",selected);
iGotoRecord = 1;
GotoRecord = true;
break;
}
else if (button_action == BUTTON_HOLD) {
Dbprintf("Playtime over. Begin cloning...");
iGotoClone = 1;
GotoClone = true;
break;
}
WDT_HIT();
@ -636,20 +664,16 @@ void StandAloneMode14a()
LEDsoff();
LED(selected + 1, 0);
}
else
while(BUTTON_PRESS())
WDT_HIT();
}
}
}
#elif WITH_LF
#elif WITH_LF_StandAlone
// samy's sniff and repeat routine
void SamyRun()
{
StandAloneMode();
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
int high[OPTS], low[OPTS];
int tops[OPTS], high[OPTS], low[OPTS];
int selected = 0;
int playing = 0;
int cardRead = 0;
@ -683,7 +707,10 @@ void SamyRun()
/* need this delay to prevent catching some weird data */
SpinDelay(500);
CmdHIDdemodFSK(1, &high[selected], &low[selected], 0);
CmdHIDdemodFSK(1, &tops[selected], &high[selected], &low[selected], 0);
if (tops[selected] > 0)
Dbprintf("Recorded %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]);
else
Dbprintf("Recorded %x %x%08x", selected, high[selected], low[selected]);
LEDsoff();
@ -705,6 +732,9 @@ void SamyRun()
LED(LED_ORANGE, 0);
// record
if (tops[selected] > 0)
Dbprintf("Cloning %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]);
else
Dbprintf("Cloning %x %x%08x", selected, high[selected], low[selected]);
// wait for button to be released
@ -714,7 +744,10 @@ void SamyRun()
/* need this delay to prevent catching some weird data */
SpinDelay(500);
CopyHIDtoT55x7(0, high[selected], low[selected], 0);
CopyHIDtoT55x7(tops[selected] & 0x000FFFFF, high[selected], low[selected], (tops[selected] != 0 && ((high[selected]& 0xFFFFFFC0) != 0)));
if (tops[selected] > 0)
Dbprintf("Cloned %x %x%08x%08x", selected, tops[selected], high[selected], low[selected]);
else
Dbprintf("Cloned %x %x%08x", selected, high[selected], low[selected]);
LEDsoff();
@ -748,8 +781,12 @@ void SamyRun()
// wait for button to be released
while(BUTTON_PRESS())
WDT_HIT();
if (tops[selected] > 0)
Dbprintf("%x %x%08x%08x", selected, tops[selected], high[selected], low[selected]);
else
Dbprintf("%x %x%08x", selected, high[selected], low[selected]);
CmdHIDsimTAG(high[selected], low[selected], 0);
CmdHIDsimTAG(tops[selected], high[selected], low[selected], 0);
DbpString("Done playing");
if (BUTTON_HELD(1000) > 0)
{
@ -814,13 +851,15 @@ static const int LIGHT_LEN = sizeof(LIGHT_SCHEME)/sizeof(LIGHT_SCHEME[0]);
void ListenReaderField(int limit)
{
int lf_av, lf_av_new, lf_baseline= 0, lf_max;
int hf_av, hf_av_new, hf_baseline= 0, hf_max;
int lf_av, lf_av_new=0, lf_baseline= 0, lf_max;
int hf_av, hf_av_new=0, hf_baseline= 0, hf_max;
int mode=1, display_val, display_max, i;
#define LF_ONLY 1
#define HF_ONLY 2
#define REPORT_CHANGE 10 // report new values only if they have changed at least by REPORT_CHANGE
#define REPORT_CHANGE_PERCENT 5 // report new values only if they have changed at least by REPORT_CHANGE_PERCENT
#define MIN_HF_FIELD 300 // in mode 1 signal HF field greater than MIN_HF_FIELD above baseline
#define MIN_LF_FIELD 1200 // in mode 1 signal LF field greater than MIN_LF_FIELD above baseline
// switch off FPGA - we don't want to measure our own signal
@ -829,23 +868,23 @@ void ListenReaderField(int limit)
LEDsoff();
lf_av = lf_max = AvgAdc(ADC_CHAN_LF);
lf_av = lf_max = AvgAdc_Voltage_LF();
if(limit != HF_ONLY) {
Dbprintf("LF 125/134kHz Baseline: %dmV", (MAX_ADC_LF_VOLTAGE * lf_av) >> 10);
Dbprintf("LF 125/134kHz Baseline: %dmV", lf_av);
lf_baseline = lf_av;
}
hf_av = hf_max = AvgAdc(ADC_CHAN_HF);
hf_av = hf_max = AvgAdc_Voltage_HF();
if (limit != LF_ONLY) {
Dbprintf("HF 13.56MHz Baseline: %dmV", (MAX_ADC_HF_VOLTAGE * hf_av) >> 10);
Dbprintf("HF 13.56MHz Baseline: %dmV", hf_av);
hf_baseline = hf_av;
}
for(;;) {
if (BUTTON_PRESS()) {
SpinDelay(500);
if (BUTTON_PRESS()) {
switch (mode) {
case 1:
mode=2;
@ -858,21 +897,22 @@ void ListenReaderField(int limit)
return;
break;
}
while (BUTTON_PRESS());
}
WDT_HIT();
if (limit != HF_ONLY) {
if(mode == 1) {
if (ABS(lf_av - lf_baseline) > REPORT_CHANGE)
if (lf_av - lf_baseline > MIN_LF_FIELD)
LED_D_ON();
else
LED_D_OFF();
}
lf_av_new = AvgAdc(ADC_CHAN_LF);
lf_av_new = AvgAdc_Voltage_LF();
// see if there's a significant change
if(ABS(lf_av - lf_av_new) > REPORT_CHANGE) {
Dbprintf("LF 125/134kHz Field Change: %5dmV", (MAX_ADC_LF_VOLTAGE * lf_av_new) >> 10);
if (ABS((lf_av - lf_av_new)*100/(lf_av?lf_av:1)) > REPORT_CHANGE_PERCENT) {
Dbprintf("LF 125/134kHz Field Change: %5dmV", lf_av_new);
lf_av = lf_av_new;
if (lf_av > lf_max)
lf_max = lf_av;
@ -881,16 +921,17 @@ void ListenReaderField(int limit)
if (limit != LF_ONLY) {
if (mode == 1){
if (ABS(hf_av - hf_baseline) > REPORT_CHANGE)
if (hf_av - hf_baseline > MIN_HF_FIELD)
LED_B_ON();
else
LED_B_OFF();
}
hf_av_new = AvgAdc(ADC_CHAN_HF);
hf_av_new = AvgAdc_Voltage_HF();
// see if there's a significant change
if(ABS(hf_av - hf_av_new) > REPORT_CHANGE) {
Dbprintf("HF 13.56MHz Field Change: %5dmV", (MAX_ADC_HF_VOLTAGE * hf_av_new) >> 10);
if (ABS((hf_av - hf_av_new)*100/(hf_av?hf_av:1)) > REPORT_CHANGE_PERCENT) {
Dbprintf("HF 13.56MHz Field Change: %5dmV", hf_av_new);
hf_av = hf_av_new;
if (hf_av > hf_max)
hf_max = hf_av;
@ -947,10 +988,10 @@ void UsbPacketReceived(uint8_t *packet, int len)
cmd_send(CMD_ACK,SnoopLF(),0,0,0,0);
break;
case CMD_HID_DEMOD_FSK:
CmdHIDdemodFSK(c->arg[0], 0, 0, 1);
CmdHIDdemodFSK(c->arg[0], 0, 0, 0, 1);
break;
case CMD_HID_SIM_TAG:
CmdHIDsimTAG(c->arg[0], c->arg[1], 1);
CmdHIDsimTAG(c->arg[0], c->arg[1], c->arg[2], 1);
break;
case CMD_FSK_SIM_TAG:
CmdFSKsimTAG(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
@ -1090,7 +1131,7 @@ void UsbPacketReceived(uint8_t *packet, int len)
#ifdef WITH_LEGICRF
case CMD_SIMULATE_TAG_LEGIC_RF:
LegicRfSimulate(c->arg[0], c->arg[1], c->arg[2]);
LegicRfSimulate(c->arg[0]);
break;
case CMD_WRITER_LEGIC_RF:
@ -1199,6 +1240,9 @@ void UsbPacketReceived(uint8_t *packet, int len)
break;
// Work with "magic Chinese" card
case CMD_MIFARE_CWIPE:
MifareCWipe(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
case CMD_MIFARE_CSETBLOCK:
MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
@ -1257,6 +1301,31 @@ void UsbPacketReceived(uint8_t *packet, int len)
HfSnoop(c->arg[0], c->arg[1]);
break;
#endif
#ifdef WITH_SMARTCARD
case CMD_SMART_ATR: {
SmartCardAtr();
break;
}
case CMD_SMART_SETCLOCK:{
SmartCardSetClock(c->arg[0]);
break;
}
case CMD_SMART_RAW: {
SmartCardRaw(c->arg[0], c->arg[1], c->d.asBytes);
break;
}
case CMD_SMART_UPLOAD: {
// upload file from client
uint8_t *mem = BigBuf_get_addr();
memcpy( mem + c->arg[0], c->d.asBytes, USB_CMD_DATA_SIZE);
cmd_send(CMD_ACK,1,0,0,0,0);
break;
}
case CMD_SMART_UPGRADE: {
SmartCardUpgrade(c->arg[0]);
break;
}
#endif
case CMD_BUFF_CLEAR:
BigBuf_Clear();
@ -1432,7 +1501,7 @@ void __attribute__((noreturn)) AppMain(void)
}
WDT_HIT();
#ifdef WITH_LF
#ifdef WITH_LF_StandAlone
#ifndef WITH_ISO14443a_StandAlone
if (BUTTON_HELD(1000) > 0)
SamyRun();

View file

@ -42,8 +42,9 @@ void Dbprintf(const char *fmt, ...);
void Dbhexdump(int len, uint8_t *d, bool bAsci);
// ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV
#define MAX_ADC_HF_VOLTAGE 36300
#define MAX_ADC_HF_VOLTAGE_LOW 36300
// ADC Vref = 3300mV, and an (10000k+240k):240k voltage divider on the LF input can measure voltages up to 140800 mV
#define MAX_ADC_HF_VOLTAGE_HIGH 140800
#define MAX_ADC_LF_VOLTAGE 140800
int AvgAdc(int ch);
@ -68,11 +69,11 @@ void AcquireTiType(void);
void AcquireRawBitsTI(void);
void SimulateTagLowFrequency(int period, int gap, int ledcontrol);
void SimulateTagLowFrequencyBidir(int divisor, int max_bitlen);
void CmdHIDsimTAG(int hi, int lo, int ledcontrol);
void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol);
void CmdFSKsimTAG(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream);
void CmdASKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream);
void CmdPSKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream);
void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol);
void CmdHIDdemodFSK(int findone, int *high2, int *high, int *low, int ledcontrol);
void CmdAWIDdemodFSK(int findone, int *high, int *low, int ledcontrol); // Realtime demodulation mode for AWID26
void CmdEM410xdemod(int findone, int *high, int *low, int ledcontrol);
void CmdIOdemodFSK(int findone, int *high, int *low, int ledcontrol);
@ -99,14 +100,9 @@ void ReadSTMemoryIso14443b(uint32_t);
void RAMFUNC SnoopIso14443b(void);
void SendRawCommand14443B(uint32_t, uint32_t, uint8_t, uint8_t[]);
/// iso14443a.h
void RAMFUNC SnoopIso14443a(uint8_t param);
void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data);
void ReaderIso14443a(UsbCommand * c);
// Also used in iclass.c
bool RAMFUNC LogTrace(const uint8_t *btBytes, uint16_t len, uint32_t timestamp_start, uint32_t timestamp_end, uint8_t *parity, bool readerToTag);
void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *parity);
void iso14a_set_trigger(bool enable);
void RAMFUNC SniffMifare(uint8_t param);
@ -115,8 +111,6 @@ void EPA_PACE_Collect_Nonce(UsbCommand * c);
void EPA_PACE_Replay(UsbCommand *c);
// mifarecmd.h
void ReaderMifare(bool first_try);
int32_t dist_nt(uint32_t nt1, uint32_t nt2);
void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data);
void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareUC_Auth(uint8_t arg0, uint8_t *datain);
@ -127,14 +121,15 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain);
void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags, uint8_t *datain);
void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain);
void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain);
void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); // Work with "magic Chinese" card
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
void MifareCIdent(); // is "magic chinese" card?
void MifareUSetPwd(uint8_t arg0, uint8_t *datain);

View file

@ -530,7 +530,7 @@ int EPA_Setup()
// power up the field
iso14443a_setup(FPGA_HF_ISO14443A_READER_MOD);
// select the card
return_code = iso14443a_select_card(uid, &card_select_info, NULL, true, 0);
return_code = iso14443a_select_card(uid, &card_select_info, NULL, true, 0, false);
if (return_code == 1) {
// send the PPS request
ReaderTransmit((uint8_t *)pps, sizeof(pps), NULL);

View file

@ -10,20 +10,21 @@
// mode once it is configured.
//-----------------------------------------------------------------------------
#include "fpgaloader.h"
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "fpgaloader.h"
#include "apps.h"
#include "fpga.h"
#include "proxmark3.h"
#include "util.h"
#include "string.h"
#include "BigBuf.h"
#include "zlib.h"
extern void Dbprintf(const char *fmt, ...);
// remember which version of the bitstream we have already downloaded to the FPGA
static int downloaded_bitstream = FPGA_BITSTREAM_ERR;
static int downloaded_bitstream = 0;
// this is where the bitstreams are located in memory:
extern uint8_t _binary_obj_fpga_all_bit_z_start, _binary_obj_fpga_all_bit_z_end;
@ -31,10 +32,7 @@ extern uint8_t _binary_obj_fpga_all_bit_z_start, _binary_obj_fpga_all_bit_z_end;
static uint8_t *fpga_image_ptr = NULL;
static uint32_t uncompressed_bytes_cnt;
static const uint8_t _bitparse_fixed_header[] = {0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01};
#define FPGA_BITSTREAM_FIXED_HEADER_SIZE sizeof(_bitparse_fixed_header)
#define OUTPUT_BUFFER_LEN 80
#define FPGA_INTERLEAVE_SIZE 288
//-----------------------------------------------------------------------------
// Set up the Serial Peripheral Interface as master
@ -114,10 +112,10 @@ void SetupSpi(int mode)
}
//-----------------------------------------------------------------------------
// Set up the synchronous serial port, with the one set of options that we
// always use when we are talking to the FPGA. Both RX and TX are enabled.
// Set up the synchronous serial port with the set of options that fits
// the FPGA mode. Both RX and TX are always enabled.
//-----------------------------------------------------------------------------
void FpgaSetupSsc(void)
void FpgaSetupSsc(uint8_t FPGA_mode)
{
// First configure the GPIOs, and get ourselves a clock.
AT91C_BASE_PIOA->PIO_ASR =
@ -136,11 +134,15 @@ void FpgaSetupSsc(void)
// on RX clock rising edge, sampled on falling edge
AT91C_BASE_SSC->SSC_RCMR = SSC_CLOCK_MODE_SELECT(1) | SSC_CLOCK_MODE_START(1);
// 8 bits per transfer, no loopback, MSB first, 1 transfer per sync
// 8, 16 or 32 bits per transfer, no loopback, MSB first, 1 transfer per sync
// pulse, no output sync
if ((FPGA_mode & 0xe0) == FPGA_MAJOR_MODE_HF_READER_RX_XCORR) {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(16) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
} else {
AT91C_BASE_SSC->SSC_RFMR = SSC_FRAME_MODE_BITS_IN_WORD(8) | AT91C_SSC_MSBF | SSC_FRAME_MODE_WORDS_PER_TRANSFER(0);
}
// clock comes from TK pin, no clock output, outputs change on falling
// TX clock comes from TK pin, no clock output, outputs change on falling
// edge of TK, sample on rising edge of TK, start on positive-going edge of sync
AT91C_BASE_SSC->SSC_TCMR = SSC_CLOCK_MODE_SELECT(2) | SSC_CLOCK_MODE_START(5);
@ -156,17 +158,16 @@ void FpgaSetupSsc(void)
// ourselves, not to another buffer). The stuff to manipulate those buffers
// is in apps.h, because it should be inlined, for speed.
//-----------------------------------------------------------------------------
bool FpgaSetupSscDma(uint8_t *buf, int len)
bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count)
{
if (buf == NULL) return false;
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; // Disable DMA Transfer
AT91C_BASE_PDC_SSC->PDC_RPR = (uint32_t) buf; // transfer to this memory address
AT91C_BASE_PDC_SSC->PDC_RCR = len; // transfer this many bytes
AT91C_BASE_PDC_SSC->PDC_RCR = sample_count; // transfer this many samples
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) buf; // next transfer to same memory address
AT91C_BASE_PDC_SSC->PDC_RNCR = len; // ... with same number of bytes
AT91C_BASE_PDC_SSC->PDC_RNCR = sample_count; // ... with same number of samples AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go!
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; // go!
return true;
}
@ -201,7 +202,7 @@ static int get_from_fpga_combined_stream(z_streamp compressed_fpga_stream, uint8
//----------------------------------------------------------------------------
static int get_from_fpga_stream(int bitstream_version, z_streamp compressed_fpga_stream, uint8_t *output_buffer)
{
while((uncompressed_bytes_cnt / FPGA_INTERLEAVE_SIZE) % FPGA_BITSTREAM_MAX != (bitstream_version - 1)) {
while((uncompressed_bytes_cnt / FPGA_INTERLEAVE_SIZE) % fpga_bitstream_num != (bitstream_version - 1)) {
// skip undesired data belonging to other bitstream_versions
get_from_fpga_combined_stream(compressed_fpga_stream, output_buffer);
}
@ -234,7 +235,7 @@ static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_s
// initialize z_stream structure for inflate:
compressed_fpga_stream->next_in = &_binary_obj_fpga_all_bit_z_start;
compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_start - &_binary_obj_fpga_all_bit_z_end;
compressed_fpga_stream->avail_in = &_binary_obj_fpga_all_bit_z_end - &_binary_obj_fpga_all_bit_z_start;
compressed_fpga_stream->next_out = output_buffer;
compressed_fpga_stream->avail_out = OUTPUT_BUFFER_LEN;
compressed_fpga_stream->zalloc = &fpga_inflate_malloc;
@ -248,8 +249,8 @@ static bool reset_fpga_stream(int bitstream_version, z_streamp compressed_fpga_s
header[i] = get_from_fpga_stream(bitstream_version, compressed_fpga_stream, output_buffer);
}
// Check for a valid .bit file (starts with _bitparse_fixed_header)
if(memcmp(_bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0) {
// Check for a valid .bit file (starts with bitparse_fixed_header)
if(memcmp(bitparse_fixed_header, header, FPGA_BITSTREAM_FIXED_HEADER_SIZE) == 0) {
return true;
} else {
return false;
@ -434,82 +435,14 @@ void FpgaDownloadAndGo(int bitstream_version)
inflateEnd(&compressed_fpga_stream);
// turn off antenna
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// free eventually allocated BigBuf memory
BigBuf_free(); BigBuf_Clear_ext(false);
}
//-----------------------------------------------------------------------------
// Gather version information from FPGA image. Needs to decompress the begin
// of the respective (HF or LF) image.
// Note: decompression makes use of (i.e. overwrites) BigBuf[]. It is therefore
// advisable to call this only once and store the results for later use.
//-----------------------------------------------------------------------------
void FpgaGatherVersion(int bitstream_version, char *dst, int len)
{
unsigned int fpga_info_len;
char tempstr[40] = {0x00};
z_stream compressed_fpga_stream;
uint8_t output_buffer[OUTPUT_BUFFER_LEN] = {0x00};
dst[0] = '\0';
// ensure that we can allocate enough memory for decompression:
BigBuf_free(); BigBuf_Clear_ext(false);
if (!reset_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer))
return;
if(bitparse_find_section(bitstream_version, 'a', &fpga_info_len, &compressed_fpga_stream, output_buffer)) {
for (uint16_t i = 0; i < fpga_info_len; i++) {
char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer);
if (i < sizeof(tempstr)) {
tempstr[i] = c;
}
}
if (!memcmp("fpga_lf", tempstr, 7))
strncat(dst, "LF ", len-1);
else if (!memcmp("fpga_hf", tempstr, 7))
strncat(dst, "HF ", len-1);
}
strncat(dst, "FPGA image built", len-1);
if(bitparse_find_section(bitstream_version, 'b', &fpga_info_len, &compressed_fpga_stream, output_buffer)) {
strncat(dst, " for ", len-1);
for (uint16_t i = 0; i < fpga_info_len; i++) {
char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer);
if (i < sizeof(tempstr)) {
tempstr[i] = c;
}
}
strncat(dst, tempstr, len-1);
}
if(bitparse_find_section(bitstream_version, 'c', &fpga_info_len, &compressed_fpga_stream, output_buffer)) {
strncat(dst, " on ", len-1);
for (uint16_t i = 0; i < fpga_info_len; i++) {
char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer);
if (i < sizeof(tempstr)) {
tempstr[i] = c;
}
}
strncat(dst, tempstr, len-1);
}
if(bitparse_find_section(bitstream_version, 'd', &fpga_info_len, &compressed_fpga_stream, output_buffer)) {
strncat(dst, " at ", len-1);
for (uint16_t i = 0; i < fpga_info_len; i++) {
char c = (char)get_from_fpga_stream(bitstream_version, &compressed_fpga_stream, output_buffer);
if (i < sizeof(tempstr)) {
tempstr[i] = c;
}
}
strncat(dst, tempstr, len-1);
}
strncat(dst, "\n", len-1);
inflateEnd(&compressed_fpga_stream);
}
//-----------------------------------------------------------------------------
// Send a 16 bit command/data pair to the FPGA.
// The bit format is: C3 C2 C1 C0 D11 D10 D9 D8 D7 D6 D5 D4 D3 D2 D1 D0
@ -559,12 +492,8 @@ void SetAdcMuxFor(uint32_t whichGpio)
}
void Fpga_print_status(void) {
Dbprintf("Fgpa");
switch(downloaded_bitstream) {
case FPGA_BITSTREAM_HF: Dbprintf(" mode....................HF"); break;
case FPGA_BITSTREAM_LF: Dbprintf(" mode....................LF"); break;
default: Dbprintf(" mode....................%d", downloaded_bitstream); break;
}
Dbprintf("Currently loaded FPGA image:");
Dbprintf(" %s", fpga_version_information[downloaded_bitstream-1]);
}
int FpgaGetCurrent() {

View file

@ -10,13 +10,18 @@
// mode once it is configured.
//-----------------------------------------------------------------------------
#ifndef __FPGALOADER_H
#define __FPGALOADER_H
#include <stdint.h>
#include <stdbool.h>
void FpgaSendCommand(uint16_t cmd, uint16_t v);
void FpgaWriteConfWord(uint8_t v);
void FpgaDownloadAndGo(int bitstream_version);
void FpgaGatherVersion(int bitstream_version, char *dst, int len);
void FpgaSetupSsc(void);
void FpgaSetupSsc(uint8_t mode);
void SetupSpi(int mode);
bool FpgaSetupSscDma(uint8_t *buf, int len);
bool FpgaSetupSscDma(uint8_t *buf, uint16_t sample_count);
void Fpga_print_status();
int FpgaGetCurrent();
#define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
@ -24,12 +29,9 @@ int FpgaGetCurrent();
void SetAdcMuxFor(uint32_t whichGpio);
// definitions for multiple FPGA config files support
#define FPGA_BITSTREAM_MAX 2 // the total number of FPGA bitstreams (configs)
#define FPGA_BITSTREAM_ERR 0
#define FPGA_BITSTREAM_LF 1
#define FPGA_BITSTREAM_HF 2
// Definitions for the FPGA commands.
#define FPGA_CMD_SET_CONFREG (1<<12)
#define FPGA_CMD_SET_DIVISOR (2<<12)
@ -72,3 +74,5 @@ void SetAdcMuxFor(uint32_t whichGpio);
#define FPGA_HF_ISO14443A_TAGSIM_MOD (2<<0)
#define FPGA_HF_ISO14443A_READER_LISTEN (3<<0)
#define FPGA_HF_ISO14443A_READER_MOD (4<<0)
#endif

View file

@ -37,7 +37,7 @@ void HfSnoop(int samplesToSkip, int triggersToSkip)
// Select correct configs
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SNOOP);
// connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SNOOP);

View file

@ -813,13 +813,13 @@ void SnoopHitag(uint32_t type) {
int lastbit;
bool bSkip;
int tag_sof;
byte_t rx[HITAG_FRAME_LEN];
byte_t rx[HITAG_FRAME_LEN] = {0};
size_t rxlen=0;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
// Clean up trace and prepare it for storing frames
set_tracing(TRUE);
set_tracing(true);
clear_trace();
auth_table_len = 0;
@ -1032,7 +1032,7 @@ void SimulateHitagTag(bool tag_mem_supplied, byte_t* data) {
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
// Clean up trace and prepare it for storing frames
set_tracing(TRUE);
set_tracing(true);
clear_trace();
auth_table_len = 0;
@ -1217,7 +1217,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
int reset_sof;
int tag_sof;
int t_wait = HITAG_T_WAIT_MAX;
bool bStop;
bool bStop = false;
bool bQuitTraceFull = false;
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
@ -1225,7 +1225,7 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
bSuccessful = false;
// Clean up trace and prepare it for storing frames
set_tracing(TRUE);
set_tracing(true);
clear_trace();
//DbpString("Starting Hitag reader family");
@ -1324,7 +1324,6 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
frame_count = 0;
response = 0;
lastbit = 1;
bStop = false;
// Tag specific configuration settings (sof, timings, etc.)
if (htf < 10){
@ -1521,7 +1520,11 @@ void ReaderHitag(hitag_function htf, hitag_data* htd) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
//Dbprintf("frame received: %d",frame_count);
//DbpString("All done");
if (bSuccessful)
cmd_send(CMD_ACK,bSuccessful,0,0,(byte_t*)tag.sectors,48);
else
cmd_send(CMD_ACK,bSuccessful,0,0,0,0);
}
void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
@ -1545,7 +1548,7 @@ void WriterHitag(hitag_function htf, hitag_data* htd, int page) {
bSuccessful = false;
// Clean up trace and prepare it for storing frames
set_tracing(TRUE);
set_tracing(true);
clear_trace();
//DbpString("Starting Hitag reader family");

View file

@ -210,7 +210,7 @@ static void hitag_send_bit(int bit) {
;
LOW(GPIO_SSC_DOUT);
while (AT91C_BASE_TC0->TC_CV < T0 * 32)
;;
;
}
LED_A_OFF();
break;
@ -945,7 +945,6 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) {
int i, j;
byte_t rx[HITAG_FRAME_LEN];
size_t rxlen = 0;
//bool bQuitTraceFull = false;
bQuiet = false;
byte_t txbuf[HITAG_FRAME_LEN];
byte_t* tx = txbuf;
@ -953,7 +952,7 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) {
BigBuf_free();
// Clean up trace and prepare it for storing frames
set_tracing(TRUE);
set_tracing(true);
clear_trace();
DbpString("Starting HitagS simulation");
@ -985,39 +984,39 @@ void SimulateHitagSTag(bool tag_mem_supplied, byte_t* data) {
tag.max_page=0;
//con1
tag.auth=0;
if((tag.pages[1][2]&0x80)==1)
if (tag.pages[1][2]&0x80)
tag.auth=1;
tag.LCON=0;
if((tag.pages[1][2]&0x2)==1)
if (tag.pages[1][2]&0x2)
tag.LCON=1;
tag.LKP=0;
if((tag.pages[1][2]&0x1)==1)
if (tag.pages[1][2]&0x1)
tag.LKP=1;
//con2
//0=read write 1=read only
tag.LCK7=0;
if((tag.pages[1][1]&0x80)==1)
if (tag.pages[1][1]&0x80)
tag.LCK7=1;
tag.LCK6=0;
if((tag.pages[1][1]&0x40)==1)
if (tag.pages[1][1]&0x40)
tag.LCK6=1;
tag.LCK5=0;
if((tag.pages[1][1]&0x20)==1)
if (tag.pages[1][1]&0x20)
tag.LCK5=1;
tag.LCK4=0;
if((tag.pages[1][1]&0x10)==1)
if (tag.pages[1][1]&0x10)
tag.LCK4=1;
tag.LCK3=0;
if((tag.pages[1][1]&0x8)==1)
if (tag.pages[1][1]&0x8)
tag.LCK3=1;
tag.LCK2=0;
if((tag.pages[1][1]&0x4)==1)
if (tag.pages[1][1]&0x4)
tag.LCK2=1;
tag.LCK1=0;
if((tag.pages[1][1]&0x2)==1)
if (tag.pages[1][1]&0x2)
tag.LCK1=1;
tag.LCK0=0;
if((tag.pages[1][1]&0x1)==1)
if (tag.pages[1][1]&0x1)
tag.LCK0=1;
// Set up simulator mode, frequency divisor which will drive the FPGA
@ -1216,7 +1215,7 @@ void ReadHitagS(hitag_function htf, hitag_data* htd) {
bSuccessful = false;
// Clean up trace and prepare it for storing frames
set_tracing(TRUE);
set_tracing(true);
clear_trace();
bQuiet = false;
@ -1560,7 +1559,7 @@ void WritePageHitagS(hitag_function htf, hitag_data* htd,int page_) {
tag.tstate = NO_OP;
// Clean up trace and prepare it for storing frames
set_tracing(TRUE);
set_tracing(true);
clear_trace();
bQuiet = false;
@ -1847,7 +1846,7 @@ void check_challenges(bool file_given, byte_t* data) {
bSuccessful = false;
// Clean up trace and prepare it for storing frames
set_tracing(TRUE);
set_tracing(true);
clear_trace();
bQuiet = false;

823
armsrc/i2c.c Normal file
View file

@ -0,0 +1,823 @@
//-----------------------------------------------------------------------------
// Willok, June 2018
// Edits by Iceman, July 2018
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// The main i2c code, for communications with smart card module
//-----------------------------------------------------------------------------
#include "i2c.h"
#include <stdint.h>
#include <stdbool.h>
#include "string.h" //for memset memcmp
#include "proxmark3.h"
#include "mifareutil.h" // for MF_DBGLEVEL
#include "BigBuf.h"
#include "apps.h"
#ifdef WITH_SMARTCARD
#include "smartcard.h"
#endif
// 定义连接引脚
#define GPIO_RST AT91C_PIO_PA1
#define GPIO_SCL AT91C_PIO_PA5
#define GPIO_SDA AT91C_PIO_PA7
#define SCL_H HIGH(GPIO_SCL)
#define SCL_L LOW(GPIO_SCL)
#define SDA_H HIGH(GPIO_SDA)
#define SDA_L LOW(GPIO_SDA)
#define SCL_read (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SCL)
#define SDA_read (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SDA)
#define I2C_ERROR "I2C_WaitAck Error"
static volatile unsigned long c;
// 直接使用循环来延时,一个循环 6 条指令48M Delay=1 大概为 200kbps
// timer.
// I2CSpinDelayClk(4) = 12.31us
// I2CSpinDelayClk(1) = 3.07us
static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) {
for (c = delay * 2; c; c--) {};
}
// 通讯延迟函数 communication delay function
#define I2C_DELAY_1CLK I2CSpinDelayClk(1)
#define I2C_DELAY_2CLK I2CSpinDelayClk(2)
#define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x))
#define ISO7618_MAX_FRAME 255
static void I2C_init(void) {
// Configure reset pin
AT91C_BASE_PIOA->PIO_PPUDR = GPIO_RST; // disable pull up resistor
AT91C_BASE_PIOA->PIO_MDDR = GPIO_RST; // push-pull output (multidriver disabled)
// Configure SCL and SDA pins
AT91C_BASE_PIOA->PIO_PPUER |= (GPIO_SCL | GPIO_SDA); // enable pull up resistor
AT91C_BASE_PIOA->PIO_MDER |= (GPIO_SCL | GPIO_SDA); // open drain output (multidriver enabled) - requires external pull up resistor
// set all three outputs to high
AT91C_BASE_PIOA->PIO_SODR |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
// configure all three pins as output, controlled by PIOA
AT91C_BASE_PIOA->PIO_OER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
AT91C_BASE_PIOA->PIO_PER |= (GPIO_SCL | GPIO_SDA | GPIO_RST);
}
// 设置复位状态
// set the reset state
static void I2C_SetResetStatus(uint8_t LineRST, uint8_t LineSCK, uint8_t LineSDA) {
if (LineRST)
HIGH(GPIO_RST);
else
LOW(GPIO_RST);
if (LineSCK)
HIGH(GPIO_SCL);
else
LOW(GPIO_SCL);
if (LineSDA)
HIGH(GPIO_SDA);
else
LOW(GPIO_SDA);
}
// 复位进入主程序
// Reset the SIM_Adapter, then enter the main program
// Note: the SIM_Adapter will not enter the main program after power up. Please run this function before use SIM_Adapter.
static void I2C_Reset_EnterMainProgram(void) {
I2C_SetResetStatus(0, 0, 0); // 拉低复位线
SpinDelay(30);
I2C_SetResetStatus(1, 0, 0); // 解除复位
SpinDelay(30);
I2C_SetResetStatus(1, 1, 1); // 拉高数据线
SpinDelay(10);
}
// 等待时钟变高
// Wait for the clock to go High.
static bool WaitSCL_H_delay(uint32_t delay) {
while (delay--) {
if (SCL_read) {
return true;
}
I2C_DELAY_1CLK;
}
return false;
}
// 15000 * 3.07us = 46050us. 46.05ms
static bool WaitSCL_H(void) {
return WaitSCL_H_delay(15000);
}
bool WaitSCL_L_delay(uint32_t delay) {
while (delay--) {
if (!SCL_read) {
return true;
}
I2C_DELAY_1CLK;
}
return false;
}
bool WaitSCL_L(void) {
return WaitSCL_L_delay(15000);
}
static bool I2C_Start(void) {
I2C_DELAY_XCLK(4);
SDA_H; I2C_DELAY_1CLK;
SCL_H;
if (!WaitSCL_H()) return false;
I2C_DELAY_2CLK;
if (!SCL_read) return false;
if (!SDA_read) return false;
SDA_L; I2C_DELAY_2CLK;
return true;
}
// send i2c STOP
static void I2C_Stop(void) {
SCL_L; I2C_DELAY_2CLK;
SDA_L; I2C_DELAY_2CLK;
SCL_H; I2C_DELAY_2CLK;
if (!WaitSCL_H()) return;
SDA_H;
I2C_DELAY_XCLK(8);
}
static bool I2C_WaitAck(void) {
SCL_L; I2C_DELAY_1CLK;
SDA_H; I2C_DELAY_1CLK;
SCL_H;
if (!WaitSCL_H())
return false;
I2C_DELAY_2CLK;
I2C_DELAY_2CLK;
if (SDA_read) {
SCL_L;
return false;
}
SCL_L;
return true;
}
static void I2C_SendByte(uint8_t data) {
uint8_t bits = 8;
while (bits--) {
SCL_L; I2C_DELAY_1CLK;
if (data & 0x80)
SDA_H;
else
SDA_L;
data <<= 1;
I2C_DELAY_1CLK;
SCL_H;
if (!WaitSCL_H())
return;
I2C_DELAY_2CLK;
}
SCL_L;
}
bool I2C_is_available(void) {
I2C_init();
I2C_Reset_EnterMainProgram();
if (!I2C_Start()) // some other device is active on the bus
return true;
I2C_SendByte(I2C_DEVICE_ADDRESS_MAIN & 0xFE);
if (!I2C_WaitAck()) { // no response from smartcard reader
I2C_Stop();
return false;
}
I2C_Stop();
return true;
}
#ifdef WITH_SMARTCARD
// 复位进入引导模式
// Reset the SIM_Adapter, then enter the bootloader program
// ReserveFor firmware update.
static void I2C_Reset_EnterBootloader(void) {
I2C_SetResetStatus(0, 1, 1); // 拉低复位线
SpinDelay(100);
I2C_SetResetStatus(1, 1, 1); // 解除复位
SpinDelay(10);
}
// Wait max 300ms or until SCL goes LOW.
// Which ever comes first
static bool WaitSCL_L_300ms(void) {
volatile uint16_t delay = 310;
while ( delay-- ) {
// exit on SCL LOW
if (!SCL_read)
return true;
SpinDelay(1);
}
return (delay == 0);
}
static bool I2C_WaitForSim() {
// variable delay here.
if (!WaitSCL_L_300ms())
return false;
// 8051 speaks with smart card.
// 1000*50*3.07 = 153.5ms
// 1byte transfer == 1ms with max frame being 256bytes
if (!WaitSCL_H_delay(10 * 1000 * 50))
return false;
return true;
}
// Send i2c ACK
static void I2C_Ack(void) {
SCL_L; I2C_DELAY_2CLK;
SDA_L; I2C_DELAY_2CLK;
SCL_H; I2C_DELAY_2CLK;
if (!WaitSCL_H()) return;
SCL_L; I2C_DELAY_2CLK;
}
// Send i2c NACK
static void I2C_NoAck(void) {
SCL_L; I2C_DELAY_2CLK;
SDA_H; I2C_DELAY_2CLK;
SCL_H; I2C_DELAY_2CLK;
if (!WaitSCL_H()) return;
SCL_L; I2C_DELAY_2CLK;
}
static int16_t I2C_ReadByte(void) {
uint8_t bits = 8, b = 0;
SDA_H;
while (bits--) {
b <<= 1;
SCL_L;
if (!WaitSCL_L()) return -2;
I2C_DELAY_1CLK;
SCL_H;
if (!WaitSCL_H()) return -1;
I2C_DELAY_1CLK;
if (SDA_read)
b |= 0x01;
}
SCL_L;
return b;
}
// Sends one byte ( command to be written, SlaveDevice address)
static bool I2C_WriteCmd(uint8_t device_cmd, uint8_t device_address) {
bool bBreak = true;
do {
if (!I2C_Start())
return false;
//[C0]
I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck())
break;
I2C_SendByte(device_cmd);
if (!I2C_WaitAck())
break;
bBreak = false;
} while (false);
I2C_Stop();
if (bBreak) {
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
return false;
}
return true;
}
// 写入1字节数据 (待写入数据,待写入地址,器件类型)
// Sends 1 byte data (Data to be written, command to be written , SlaveDevice address ).
static bool I2C_WriteByte(uint8_t data, uint8_t device_cmd, uint8_t device_address) {
bool bBreak = true;
do {
if (!I2C_Start())
return false;
I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck())
break;
I2C_SendByte(device_cmd);
if (!I2C_WaitAck())
break;
I2C_SendByte(data);
if (!I2C_WaitAck())
break;
bBreak = false;
} while (false);
I2C_Stop();
if (bBreak) {
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
return false;
}
return true;
}
// 写入1串数据待写入数组地址待写入长度待写入地址器件类型
//Sends a string of data (Array, length, command to be written , SlaveDevice address ).
// len = uint8 (max buffer to write 256bytes)
static bool I2C_BufferWrite(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
bool bBreak = true;
do {
if (!I2C_Start())
return false;
I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck())
break;
I2C_SendByte(device_cmd);
if (!I2C_WaitAck())
break;
while (len) {
I2C_SendByte(*data);
if (!I2C_WaitAck())
break;
len--;
data++;
}
if (len == 0)
bBreak = false;
} while (false);
I2C_Stop();
if (bBreak) {
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
return false;
}
return true;
}
// 读出1串数据存放读出数据待读出长度带读出地址器件类型
// read 1 strings of data (Data array, Readout length, command to be written , SlaveDevice address ).
// len = uint8 (max buffer to read 256bytes)
static int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t device_address) {
if ( !data || len == 0 )
return 0;
// extra wait 500us (514us measured)
// 200us (xx measured)
SpinDelayUs(600);
bool bBreak = true;
uint16_t readcount = 0;
do {
if (!I2C_Start())
return 0;
// 0xB0 / 0xC0 == i2c write
I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck())
break;
I2C_SendByte(device_cmd);
if (!I2C_WaitAck())
break;
// 0xB1 / 0xC1 == i2c read
I2C_Start();
I2C_SendByte(device_address | 1);
if (!I2C_WaitAck())
break;
bBreak = false;
} while (false);
if (bBreak) {
I2C_Stop();
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
return 0;
}
while (len) {
int16_t tmp = I2C_ReadByte();
if ( tmp < 0 )
return tmp;
*data = (uint8_t)tmp & 0xFF;
len--;
// 读取的第一个字节为后续长度
// The first byte in response is the message length
if (!readcount && (len > *data)) {
len = *data;
} else {
data++;
}
readcount++;
// acknowledgements. After last byte send NACK.
if (len == 0)
I2C_NoAck();
else
I2C_Ack();
}
I2C_Stop();
// return bytecount - first byte (which is length byte)
return --readcount;
}
static int16_t I2C_ReadFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
//START, 0xB0, 0x00, 0x00, START, 0xB1, xx, yy, zz, ......, STOP
bool bBreak = true;
uint8_t readcount = 0;
// sending
do {
if (!I2C_Start())
return 0;
// 0xB0 / 0xC0 i2c write
I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck())
break;
// msb
I2C_SendByte(msb);
if (!I2C_WaitAck())
break;
// lsb
I2C_SendByte(lsb);
if (!I2C_WaitAck())
break;
// 0xB1 / 0xC1 i2c read
I2C_Start();
I2C_SendByte(device_address | 1);
if (!I2C_WaitAck())
break;
bBreak = false;
} while (false);
if (bBreak) {
I2C_Stop();
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
return 0;
}
// reading
while (len) {
int16_t tmp = I2C_ReadByte();
if ( tmp < 0 )
return tmp;
*data = (uint8_t)tmp & 0xFF;
data++;
readcount++;
len--;
// acknowledgements. After last byte send NACK.
if (len == 0)
I2C_NoAck();
else
I2C_Ack();
}
I2C_Stop();
return readcount;
}
static bool I2C_WriteFW(uint8_t *data, uint8_t len, uint8_t msb, uint8_t lsb, uint8_t device_address) {
//START, 0xB0, 0x00, 0x00, xx, yy, zz, ......, STOP
bool bBreak = true;
do {
if (!I2C_Start())
return false;
// 0xB0 == i2c write
I2C_SendByte(device_address & 0xFE);
if (!I2C_WaitAck())
break;
// msb
I2C_SendByte(msb);
if (!I2C_WaitAck())
break;
// lsb
I2C_SendByte(lsb);
if (!I2C_WaitAck())
break;
while (len) {
I2C_SendByte(*data);
if (!I2C_WaitAck())
break;
len--;
data++;
}
if (len == 0)
bBreak = false;
} while (false);
I2C_Stop();
if (bBreak) {
if ( MF_DBGLEVEL > 3 ) DbpString(I2C_ERROR);
return false;
}
return true;
}
void I2C_print_status(void) {
DbpString("Smart card module (ISO 7816)");
uint8_t resp[] = {0,0,0,0};
I2C_init();
I2C_Reset_EnterMainProgram();
uint8_t len = I2C_BufferRead(resp, sizeof(resp), I2C_DEVICE_CMD_GETVERSION, I2C_DEVICE_ADDRESS_MAIN);
if ( len > 0 )
Dbprintf(" version.................v%x.%02x", resp[0], resp[1]);
else
DbpString(" version.................FAILED");
}
// Will read response from smart card module, retries 3 times to get the data.
static bool sc_rx_bytes(uint8_t* dest, uint8_t *destlen) {
uint8_t i = 3;
int16_t len = 0;
while (i--) {
I2C_WaitForSim();
len = I2C_BufferRead(dest, *destlen, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
if ( len > 1 ){
break;
} else if ( len == 1 ) {
continue;
} else if ( len <= 0 ) {
return false;
}
}
// after three
if ( len <= 1 )
return false;
*destlen = (uint8_t)len & 0xFF;
return true;
}
static bool GetATR(smart_card_atr_t *card_ptr) {
if ( !card_ptr ) {
return false;
}
card_ptr->atr_len = 0;
memset(card_ptr->atr, 0, sizeof(card_ptr->atr));
// Send ATR
// start [C0 01] stop start C1 len aa bb cc stop]
I2C_WriteCmd(I2C_DEVICE_CMD_GENERATE_ATR, I2C_DEVICE_ADDRESS_MAIN);
uint8_t cmd[1] = {1};
LogTrace(cmd, 1, 0, 0, NULL, true);
// wait for sim card to answer.
// 1byte = 1ms, max frame 256bytes. Should wait 256ms at least just in case.
if (!I2C_WaitForSim())
return false;
// read bytes from module
uint8_t len = sizeof(card_ptr->atr);
if ( !sc_rx_bytes(card_ptr->atr, &len) )
return false;
uint8_t pos_td = 1;
if ( (card_ptr->atr[1] & 0x10) == 0x10) pos_td++;
if ( (card_ptr->atr[1] & 0x20) == 0x20) pos_td++;
if ( (card_ptr->atr[1] & 0x40) == 0x40) pos_td++;
// T0 indicate presence T=0 vs T=1. T=1 has checksum TCK
if ( (card_ptr->atr[1] & 0x80) == 0x80) {
pos_td++;
// 1 == T1 , presence of checksum TCK
if ( (card_ptr->atr[pos_td] & 0x01) == 0x01) {
uint8_t chksum = 0;
// xor property. will be zero when xored with chksum.
for (uint8_t i = 1; i < len; ++i)
chksum ^= card_ptr->atr[i];
if ( chksum ) {
if ( MF_DBGLEVEL > 2) DbpString("Wrong ATR checksum");
}
}
}
// for some reason we only get first byte of atr, if that is so, send dummy command to retrieve the rest of the atr
if (len == 1) {
uint8_t data[1] = {0};
I2C_BufferWrite(data, len, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN);
if ( !I2C_WaitForSim() )
return false;
uint8_t len2 = I2C_BufferRead(card_ptr->atr + len, sizeof(card_ptr->atr) - len, I2C_DEVICE_CMD_READ, I2C_DEVICE_ADDRESS_MAIN);
len = len + len2;
}
card_ptr->atr_len = len;
LogTrace(card_ptr->atr, card_ptr->atr_len, 0, 0, NULL, false);
return true;
}
void SmartCardAtr(void) {
smart_card_atr_t card;
LED_D_ON();
clear_trace();
set_tracing(true);
I2C_init();
I2C_Reset_EnterMainProgram();
bool isOK = GetATR( &card );
cmd_send(CMD_ACK, isOK, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
set_tracing(false);
LEDsoff();
}
void SmartCardRaw( uint64_t arg0, uint64_t arg1, uint8_t *data ) {
LED_D_ON();
uint8_t len = 0;
uint8_t *resp = BigBuf_malloc(ISO7618_MAX_FRAME);
smartcard_command_t flags = arg0;
if ((flags & SC_CONNECT))
clear_trace();
set_tracing(true);
if ((flags & SC_CONNECT)) {
I2C_init();
I2C_Reset_EnterMainProgram();
if ( !(flags & SC_NO_SELECT) ) {
smart_card_atr_t card;
bool gotATR = GetATR( &card );
//cmd_send(CMD_ACK, gotATR, sizeof(smart_card_atr_t), 0, &card, sizeof(smart_card_atr_t));
if ( !gotATR )
goto OUT;
}
}
if ((flags & SC_RAW)) {
LogTrace(data, arg1, 0, 0, NULL, true);
// Send raw bytes
// asBytes = A0 A4 00 00 02
// arg1 = len 5
I2C_BufferWrite(data, arg1, I2C_DEVICE_CMD_SEND, I2C_DEVICE_ADDRESS_MAIN);
if ( !I2C_WaitForSim() )
goto OUT;
// read bytes from module
len = ISO7618_MAX_FRAME;
sc_rx_bytes(resp, &len);
LogTrace(resp, len, 0, 0, NULL, false);
}
OUT:
cmd_send(CMD_ACK, len, 0, 0, resp, len);
set_tracing(false);
LEDsoff();
}
void SmartCardUpgrade(uint64_t arg0) {
LED_C_ON();
#define I2C_BLOCK_SIZE 128
// write. Sector0, with 11,22,33,44
// erase is 128bytes, and takes 50ms to execute
I2C_init();
I2C_Reset_EnterBootloader();
bool isOK = true;
int16_t res = 0;
uint16_t length = arg0;
uint16_t pos = 0;
uint8_t *fwdata = BigBuf_get_addr();
uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE);
while (length) {
uint8_t msb = (pos >> 8) & 0xFF;
uint8_t lsb = pos & 0xFF;
Dbprintf("FW %02X%02X", msb, lsb);
size_t size = MIN(I2C_BLOCK_SIZE, length);
// write
res = I2C_WriteFW(fwdata+pos, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
if ( !res ) {
DbpString("Writing failed");
isOK = false;
break;
}
// writing takes time.
SpinDelay(50);
// read
res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT);
if ( res <= 0) {
DbpString("Reading back failed");
isOK = false;
break;
}
// cmp
if ( 0 != memcmp(fwdata+pos, verfiydata, size)) {
DbpString("not equal data");
isOK = false;
break;
}
length -= size;
pos += size;
}
cmd_send(CMD_ACK, isOK, pos, 0, 0, 0);
LED_C_OFF();
}
// unfinished (or not needed?)
//void SmartCardSetBaud(uint64_t arg0) {
//}
void SmartCardSetClock(uint64_t arg0) {
LED_D_ON();
set_tracing(true);
I2C_init();
I2C_Reset_EnterMainProgram();
// Send SIM CLC
// start [C0 05 xx] stop
I2C_WriteByte(arg0, I2C_DEVICE_CMD_SIM_CLC, I2C_DEVICE_ADDRESS_MAIN);
cmd_send(CMD_ACK, 1, 0, 0, 0, 0);
set_tracing(false);
LEDsoff();
}
#endif

37
armsrc/i2c.h Normal file
View file

@ -0,0 +1,37 @@
//-----------------------------------------------------------------------------
// Willok, June 2018
// Edits by Iceman, July 2018
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// The main i2c code, for communications with smart card module
//-----------------------------------------------------------------------------
#ifndef __I2C_H
#define __I2C_H
#include <stdint.h>
#include <stdbool.h>
#define I2C_DEVICE_ADDRESS_BOOT 0xB0
#define I2C_DEVICE_ADDRESS_MAIN 0xC0
#define I2C_DEVICE_CMD_GENERATE_ATR 0x01
#define I2C_DEVICE_CMD_SEND 0x02
#define I2C_DEVICE_CMD_READ 0x03
#define I2C_DEVICE_CMD_SETBAUD 0x04
#define I2C_DEVICE_CMD_SIM_CLC 0x05
#define I2C_DEVICE_CMD_GETVERSION 0x06
bool I2C_is_available(void);
#ifdef WITH_SMARTCARD
void SmartCardAtr(void);
void SmartCardRaw(uint64_t arg0, uint64_t arg1, uint8_t *data);
void SmartCardUpgrade(uint64_t arg0);
void SmartCardSetClock(uint64_t arg0);
void I2C_print_status(void);
#endif
#endif // __I2C_H

View file

@ -42,6 +42,7 @@
#include "string.h"
#include "common.h"
#include "cmd.h"
#include "iso14443a.h"
// Needed for CRC in emulation mode;
// same construction as in ISO 14443;
// different initial value (CRC_ICLASS)
@ -90,7 +91,7 @@ static RAMFUNC int OutOfNDecoding(int bit)
if(!Uart.bitBuffer) {
Uart.bitBuffer = bit ^ 0xFF0;
return FALSE;
return false;
}
else {
Uart.bitBuffer <<= 4;
@ -101,7 +102,7 @@ static RAMFUNC int OutOfNDecoding(int bit)
Uart.output[Uart.byteCnt] = Uart.bitBuffer & 0xFF;
Uart.byteCnt++;
Uart.swapper = 0;
if(Uart.byteCnt > 15) { return TRUE; }
if(Uart.byteCnt > 15) { return true; }
}
else {
Uart.swapper = 1;
@ -138,12 +139,12 @@ static RAMFUNC int OutOfNDecoding(int bit)
Uart.highCnt = 0;
if(Uart.byteCnt == 0) {
// Its not straightforward to show single EOFs
// So just leave it and do not return TRUE
// So just leave it and do not return true
Uart.output[0] = 0xf0;
Uart.byteCnt++;
}
else {
return TRUE;
return true;
}
}
else if(Uart.state != STATE_START_OF_COMMUNICATION) {
@ -262,7 +263,7 @@ static RAMFUNC int OutOfNDecoding(int bit)
Uart.byteCnt++;
Uart.output[Uart.byteCnt] = 0xAA;
Uart.byteCnt++;
return TRUE;
return true;
}*/
}
@ -317,7 +318,7 @@ static RAMFUNC int OutOfNDecoding(int bit)
}
}
return FALSE;
return false;
}
//=============================================================================
@ -370,7 +371,7 @@ static RAMFUNC int ManchesterDecoding(int v)
if(Demod.buff < 3) {
Demod.buff++;
return FALSE;
return false;
}
if(Demod.state==DEMOD_UNSYNCD) {
@ -472,7 +473,7 @@ static RAMFUNC int ManchesterDecoding(int v)
Demod.len++;
Demod.state = DEMOD_UNSYNCD;
// error = 0x0f;
return TRUE;
return true;
}
else {
Demod.state = DEMOD_ERROR_WAIT;
@ -556,7 +557,7 @@ static RAMFUNC int ManchesterDecoding(int v)
}
Demod.state = DEMOD_UNSYNCD;
return TRUE;
return true;
}
else {
Demod.output[Demod.len] = 0xad;
@ -611,14 +612,14 @@ static RAMFUNC int ManchesterDecoding(int v)
Demod.len++;
Demod.output[Demod.len] = 0xBB;
Demod.len++;
return TRUE;
return true;
}
}
} // end (state != UNSYNCED)
return FALSE;
return false;
}
//=============================================================================
@ -638,7 +639,7 @@ void RAMFUNC SnoopIClass(void)
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
//int triggered = FALSE; // FALSE to wait first for card
//int triggered = false; // false to wait first for card
// The command (reader -> tag) that we're receiving.
// The length of a received command will in most cases be no more than 18 bytes.
@ -655,9 +656,9 @@ void RAMFUNC SnoopIClass(void)
// The DMA buffer, used to stream samples from the FPGA
uint8_t *dmaBuf = BigBuf_malloc(DMA_BUFFER_SIZE);
set_tracing(TRUE);
set_tracing(true);
clear_trace();
iso14a_set_trigger(FALSE);
iso14a_set_trigger(false);
int lastRxCounter;
uint8_t *upTo;
@ -675,7 +676,7 @@ void RAMFUNC SnoopIClass(void)
Demod.state = DEMOD_UNSYNCD;
// Setup for the DMA.
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
upTo = dmaBuf;
lastRxCounter = DMA_BUFFER_SIZE;
FpgaSetupSscDma((uint8_t *)dmaBuf, DMA_BUFFER_SIZE);
@ -748,12 +749,12 @@ void RAMFUNC SnoopIClass(void)
time_stop = (GetCountSspClk()-time_0) << 4;
LED_C_ON();
//if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,TRUE)) break;
//if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, TRUE)) break;
//if(!LogTrace(Uart.output,Uart.byteCnt, rsamples, Uart.parityBits,true)) break;
//if(!LogTrace(NULL, 0, Uart.endTime*16 - DELAY_READER_AIR2ARM_AS_SNIFFER, 0, true)) break;
if(tracing) {
uint8_t parity[MAX_PARITY_SIZE];
GetParity(Uart.output, Uart.byteCnt, parity);
LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, TRUE);
LogTrace(Uart.output,Uart.byteCnt, time_start, time_stop, parity, true);
}
@ -781,7 +782,7 @@ void RAMFUNC SnoopIClass(void)
if(tracing) {
uint8_t parity[MAX_PARITY_SIZE];
GetParity(Demod.output, Demod.len, parity);
LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, FALSE);
LogTrace(Demod.output, Demod.len, time_start, time_stop, parity, false);
}
// And ready to receive another response.
@ -829,7 +830,7 @@ void rotateCSN(uint8_t* originalCSN, uint8_t* rotatedCSN) {
//-----------------------------------------------------------------------------
// Wait for commands from reader
// Stop when button is pressed
// Or return TRUE when command is captured
// Or return true when command is captured
//-----------------------------------------------------------------------------
static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen)
{
@ -847,7 +848,7 @@ static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen)
for(;;) {
WDT_HIT();
if(BUTTON_PRESS()) return FALSE;
if(BUTTON_PRESS()) return false;
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0x00;
@ -857,7 +858,7 @@ static int GetIClassCommandFromReader(uint8_t *received, int *len, int maxLen)
if(OutOfNDecoding(b & 0x0f)) {
*len = Uart.byteCnt;
return TRUE;
return true;
}
}
}
@ -992,7 +993,7 @@ void SimulateIClass(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Enable and clear the trace
set_tracing(TRUE);
set_tracing(true);
clear_trace();
//Use the emulator memory for SIM
uint8_t *emulator = BigBuf_get_EM_addr();
@ -1162,7 +1163,7 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
StartCountSspClk();
// We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
// To control where we are in the protocol
int cmdsRecvd = 0;
@ -1324,11 +1325,11 @@ int doIClassSimulation( int simulationMode, uint8_t *reader_mac_buf)
if (tracing) {
uint8_t parity[MAX_PARITY_SIZE];
GetParity(receivedCmd, len, parity);
LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, TRUE);
LogTrace(receivedCmd,len, (r2t_time-time_0)<< 4, (r2t_time-time_0) << 4, parity, true);
if (trace_data != NULL) {
GetParity(trace_data, trace_data_size, parity);
LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, FALSE);
LogTrace(trace_data, trace_data_size, (t2r_time-time_0) << 4, (t2r_time-time_0) << 4, parity, false);
}
if(!tracing) {
DbpString("Trace full");
@ -1359,7 +1360,7 @@ static int SendIClassAnswer(uint8_t *resp, int respLen, int delay)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR|FPGA_HF_SIMULATOR_MODULATE_424K_8BIT);
AT91C_BASE_SSC->SSC_THR = 0x00;
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
while(!BUTTON_PRESS()) {
if((AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY)){
b = AT91C_BASE_SSC->SSC_RHR; (void) b;
@ -1397,7 +1398,7 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int
int c;
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
AT91C_BASE_SSC->SSC_THR = 0x00;
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
if (wait)
{
@ -1419,7 +1420,7 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int
uint8_t sendbyte;
bool firstpart = TRUE;
bool firstpart = true;
c = 0;
for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
@ -1511,14 +1512,14 @@ void ReaderTransmitIClass(uint8_t* frame, int len)
if (tracing) {
uint8_t par[MAX_PARITY_SIZE];
GetParity(frame, len, par);
LogTrace(frame, len, rsamples, rsamples, par, TRUE);
LogTrace(frame, len, rsamples, rsamples, par, true);
}
}
//-----------------------------------------------------------------------------
// Wait a certain time for tag response
// If a response is captured return TRUE
// If it takes too long return FALSE
// If a response is captured return true
// If it takes too long return false
//-----------------------------------------------------------------------------
static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) //uint8_t *buffer
{
@ -1537,27 +1538,27 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples,
uint8_t b;
if (elapsed) *elapsed = 0;
bool skip = FALSE;
bool skip = false;
c = 0;
for(;;) {
WDT_HIT();
if(BUTTON_PRESS()) return FALSE;
if(BUTTON_PRESS()) return false;
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0x00; // To make use of exact timing of next command from reader!!
if (elapsed) (*elapsed)++;
}
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
if(c < timeout) { c++; } else { return FALSE; }
if(c < timeout) { c++; } else { return false; }
b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
skip = !skip;
if(skip) continue;
if(ManchesterDecoding(b & 0x0f)) {
*samples = c << 3;
return TRUE;
return true;
}
}
}
@ -1566,14 +1567,14 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples,
int ReaderReceiveIClass(uint8_t* receivedAnswer)
{
int samples = 0;
if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return FALSE;
if (!GetIClassAnswer(receivedAnswer,160,&samples,0)) return false;
rsamples += samples;
if (tracing) {
uint8_t parity[MAX_PARITY_SIZE];
GetParity(receivedAnswer, Demod.len, parity);
LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,FALSE);
LogTrace(receivedAnswer,Demod.len,rsamples,rsamples,parity,false);
}
if(samples == 0) return FALSE;
if(samples == 0) return false;
return Demod.len;
}
@ -1581,11 +1582,11 @@ void setupIclassReader()
{
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Reset trace buffer
set_tracing(TRUE);
set_tracing(true);
clear_trace();
// Setup SSC
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_ISO14443A);
// Start from off (no field generated)
// Signal field is off with the appropriate LED
LED_D_OFF();
@ -1821,7 +1822,7 @@ void ReaderIClass_Replay(uint8_t arg0, uint8_t *MAC) {
uint8_t resp[ICLASS_BUFFER_SIZE];
setupIclassReader();
set_tracing(TRUE);
set_tracing(true);
while(!BUTTON_PRESS()) {

File diff suppressed because it is too large Load diff

View file

@ -15,18 +15,42 @@
#include <stdint.h>
#include <stdbool.h>
#include "usb_cmd.h"
#include "mifare.h"
typedef struct {
uint8_t* response;
uint8_t* modulation;
uint16_t response_n;
uint16_t modulation_n;
uint32_t ProxToAirDuration;
uint8_t par; // enough for precalculated parity of 8 Byte responses
} tag_response_info_t;
extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
extern void AppendCrc14443a(uint8_t *data, int len);
extern void RAMFUNC SnoopIso14443a(uint8_t param);
extern void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t *data);
extern void ReaderIso14443a(UsbCommand *c);
extern void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing);
extern void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing);
extern void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing);
extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par);
extern void ReaderMifare(bool first_try);
extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity);
extern int EmSendCmd(uint8_t *resp, uint16_t respLen);
extern int EmSendCmdEx(uint8_t *resp, uint16_t respLen);
extern int EmSend4bit(uint8_t resp);
extern int EmSendCmdPar(uint8_t *resp, uint16_t respLen, uint8_t *par);
extern int EmSendPrecompiledCmd(tag_response_info_t *response_info);
extern bool prepare_allocated_tag_modulation(tag_response_info_t *response_info, uint8_t **buffer, size_t *buffer_size);
extern void iso14443a_setup(uint8_t fpga_minor_mode);
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data);
extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades);
extern int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *resp_data, uint32_t *cuid_ptr, bool anticollision, uint8_t num_cascades, bool no_rats);
extern void iso14a_set_trigger(bool enable);
extern void iso14a_set_timeout(uint32_t timeout);
#endif /* __ISO14443A_H */

View file

@ -1,5 +1,6 @@
//-----------------------------------------------------------------------------
// Jonathan Westhues, split Nov 2006
// piwi 2018
//
// 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
@ -16,8 +17,8 @@
#include "iso14443crc.h"
#define RECEIVE_SAMPLES_TIMEOUT 2000
#define ISO14443B_DMA_BUFFER_SIZE 256
#define RECEIVE_SAMPLES_TIMEOUT 1000 // TR0 max is 256/fs = 256/(848kHz) = 302us or 64 samples from FPGA. 1000 seems to be much too high?
#define ISO14443B_DMA_BUFFER_SIZE 128
// PCB Block number for APDUs
static uint8_t pcb_blocknum = 0;
@ -243,7 +244,7 @@ static RAMFUNC int Handle14443bUartBit(uint8_t bit)
LED_A_OFF(); // Finished receiving
Uart.state = STATE_UNSYNCD;
if (Uart.byteCnt != 0) {
return TRUE;
return true;
}
} else {
// this is an error
@ -259,7 +260,7 @@ static RAMFUNC int Handle14443bUartBit(uint8_t bit)
break;
}
return FALSE;
return false;
}
@ -283,7 +284,7 @@ static void UartInit(uint8_t *data)
// Receive a command (from the reader to us, where we are the simulated tag),
// and store it in the given buffer, up to the given maximum length. Keeps
// spinning, waiting for a well-framed command, until either we get one
// (returns TRUE) or someone presses the pushbutton on the board (FALSE).
// (returns true) or someone presses the pushbutton on the board (false).
//
// Assume that we're called with the SSC (to the FPGA) and ADC path set
// correctly.
@ -302,20 +303,20 @@ static int GetIso14443bCommandFromReader(uint8_t *received, uint16_t *len)
for(;;) {
WDT_HIT();
if(BUTTON_PRESS()) return FALSE;
if(BUTTON_PRESS()) return false;
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
for(uint8_t mask = 0x80; mask != 0x00; mask >>= 1) {
if(Handle14443bUartBit(b & mask)) {
*len = Uart.byteCnt;
return TRUE;
return true;
}
}
}
}
return FALSE;
return false;
}
//-----------------------------------------------------------------------------
@ -347,7 +348,7 @@ void SimulateIso14443bTag(void)
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
clear_trace();
set_tracing(TRUE);
set_tracing(true);
const uint8_t *resp;
uint8_t *respCode;
@ -374,7 +375,7 @@ void SimulateIso14443bTag(void)
// We need to listen to the high-frequency, peak-detected path.
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
cmdsRecvd = 0;
@ -387,7 +388,7 @@ void SimulateIso14443bTag(void)
if (tracing) {
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(receivedCmd, len, 0, 0, parity, TRUE);
LogTrace(receivedCmd, len, 0, 0, parity, true);
}
// Good, look at the command now.
@ -440,7 +441,7 @@ void SimulateIso14443bTag(void)
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR | FPGA_HF_SIMULATOR_MODULATE_BPSK);
AT91C_BASE_SSC->SSC_THR = 0xff;
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
// Transmit the response.
uint16_t i = 0;
@ -464,7 +465,7 @@ void SimulateIso14443bTag(void)
// trace the response:
if (tracing) {
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(resp, respLen, 0, 0, parity, FALSE);
LogTrace(resp, respLen, 0, 0, parity, false);
}
}
@ -535,60 +536,11 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
#define SUBCARRIER_DETECT_THRESHOLD 8
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by abs(ci) + abs(cq)
/* #define CHECK_FOR_SUBCARRIER() { \
v = ci; \
if(v < 0) v = -v; \
if(cq > 0) { \
v += cq; \
} else { \
v -= cq; \
} \
}
*/
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
//note: couldn't we just use MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2) from common.h - marshmellow
#define CHECK_FOR_SUBCARRIER() { \
v = MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2); \
}
/*
if(ci < 0) { \
if(cq < 0) { \ // ci < 0, cq < 0
if (cq < ci) { \
v = -cq - (ci >> 1); \
} else { \
v = -ci - (cq >> 1); \
} \
} else { \ // ci < 0, cq >= 0
if (cq < -ci) { \
v = -ci + (cq >> 1); \
} else { \
v = cq - (ci >> 1); \
} \
} \
} else { \
if(cq < 0) { \ // ci >= 0, cq < 0
if (-cq < ci) { \
v = ci - (cq >> 1); \
} else { \
v = -cq + (ci >> 1); \
} \
} else { \ // ci >= 0, cq >= 0
if (cq < ci) { \
v = ci + (cq >> 1); \
} else { \
v = cq + (ci >> 1); \
} \
} \
} \
}
*/
#define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2))
switch(Demod.state) {
case DEMOD_UNSYNCD:
CHECK_FOR_SUBCARRIER();
if(v > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
if(AMPLITUDE(ci,cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
Demod.state = DEMOD_PHASE_REF_TRAINING;
Demod.sumI = ci;
Demod.sumQ = cq;
@ -598,8 +550,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
case DEMOD_PHASE_REF_TRAINING:
if(Demod.posCount < 8) {
CHECK_FOR_SUBCARRIER();
if (v > SUBCARRIER_DETECT_THRESHOLD) {
if (AMPLITUDE(ci,cq) > SUBCARRIER_DETECT_THRESHOLD) {
// set the reference phase (will code a logic '1') by averaging over 32 1/fs.
// note: synchronization time > 80 1/fs
Demod.sumI += ci;
@ -702,7 +653,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
LED_C_OFF();
if(s == 0x000) {
// This is EOF (start, stop and all data bits == '0'
return TRUE;
return true;
}
}
}
@ -716,7 +667,7 @@ static RAMFUNC int Handle14443bSamplesDemod(int ci, int cq)
break;
}
return FALSE;
return false;
}
@ -739,13 +690,14 @@ static void DemodInit(uint8_t *data)
/*
* Demodulate the samples we received from the tag, also log to tracebuffer
* quiet: set to 'TRUE' to disable debug output
* quiet: set to 'true' to disable debug output
*/
static void GetSamplesFor14443bDemod(int n, bool quiet)
{
int max = 0;
bool gotFrame = FALSE;
int lastRxCounter, ci, cq, samples = 0;
int maxBehindBy = 0;
bool gotFrame = false;
int lastRxCounter, samples = 0;
int8_t ci, cq;
// Allocate memory from BigBuf for some buffers
// free all previous allocations first
@ -755,15 +707,19 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
uint8_t *receivedResponse = BigBuf_malloc(MAX_FRAME_SIZE);
// The DMA buffer, used to stream samples from the FPGA
int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE);
uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t));
// Set up the demodulator for tag -> reader responses.
DemodInit(receivedResponse);
// wait for last transfer to complete
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY))
// Setup and start DMA.
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
int8_t *upTo = dmaBuf;
uint16_t *upTo = dmaBuf;
lastRxCounter = ISO14443B_DMA_BUFFER_SIZE;
// Signal field is ON with the appropriate LED:
@ -772,43 +728,44 @@ static void GetSamplesFor14443bDemod(int n, bool quiet)
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_848_KHZ);
for(;;) {
int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;
if(behindBy > max) max = behindBy;
while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1)) > 2) {
ci = upTo[0];
cq = upTo[1];
upTo += 2;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) {
upTo = dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo;
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE;
int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1);
if(behindBy > maxBehindBy) {
maxBehindBy = behindBy;
}
lastRxCounter -= 2;
if(lastRxCounter <= 0) {
if(behindBy < 1) continue;
ci = *upTo >> 8;
cq = *upTo;
upTo++;
lastRxCounter--;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content.
upTo = dmaBuf; // start reading the circular buffer from the beginning
lastRxCounter += ISO14443B_DMA_BUFFER_SIZE;
}
samples += 2;
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated.
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers
}
samples++;
if(Handle14443bSamplesDemod(ci, cq)) {
gotFrame = TRUE;
gotFrame = true;
break;
}
if(samples > n) {
break;
}
}
if(samples > n || gotFrame) {
break;
}
}
FpgaDisableSscDma();
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", max, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ);
if (!quiet) Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d", maxBehindBy, samples, gotFrame, Demod.len, Demod.sumI, Demod.sumQ);
//Tracing
if (tracing && Demod.len > 0) {
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE);
LogTrace(Demod.output, Demod.len, 0, 0, parity, false);
}
}
@ -820,11 +777,7 @@ static void TransmitFor14443b(void)
{
int c;
FpgaSetupSsc();
while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0xff;
}
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
// Signal field is ON with the appropriate Red LED
LED_D_ON();
@ -832,31 +785,15 @@ static void TransmitFor14443b(void)
LED_B_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
for(c = 0; c < 10;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = 0xff;
c++;
}
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
(void)r;
}
WDT_HIT();
}
c = 0;
for(;;) {
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
AT91C_BASE_SSC->SSC_THR = ToSend[c];
AT91C_BASE_SSC->SSC_THR = ~ToSend[c];
c++;
if(c >= ToSendMax) {
break;
}
}
if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
(void)r;
}
WDT_HIT();
}
LED_B_OFF(); // Finished sending
@ -874,19 +811,14 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
ToSendReset();
// Establish initial reference level
for(i = 0; i < 40; i++) {
ToSendStuffBit(1);
}
// Send SOF
for(i = 0; i < 10; i++) {
ToSendStuffBit(0);
}
ToSendStuffBit(1);
ToSendStuffBit(1);
for(i = 0; i < len; i++) {
// Stop bits/EGT
ToSendStuffBit(1);
ToSendStuffBit(1);
// Start bit
ToSendStuffBit(0);
// Data bits
@ -899,19 +831,18 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len)
}
b >>= 1;
}
}
// Send EOF
ToSendStuffBit(1);
for(i = 0; i < 10; i++) {
ToSendStuffBit(0);
}
for(i = 0; i < 8; i++) {
// Stop bit
ToSendStuffBit(1);
}
// And then a little more, to make sure that the last character makes
// it out before we switch to rx mode.
for(i = 0; i < 24; i++) {
// Send EOF
for(i = 0; i < 10; i++) {
ToSendStuffBit(0);
}
ToSendStuffBit(1);
// ensure that last byte is filled up
for(i = 0; i < 8; i++) {
ToSendStuffBit(1);
}
@ -929,7 +860,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len)
TransmitFor14443b();
if (tracing) {
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(cmd,len, 0, 0, parity, TRUE);
LogTrace(cmd,len, 0, 0, parity, true);
}
}
@ -951,7 +882,7 @@ int iso14443b_apdu(uint8_t const *message, size_t message_length, uint8_t *respo
// send
CodeAndTransmit14443bAsReader(message_frame, message_length + 4);
// get response
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT*100, TRUE);
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if(Demod.len < 3)
{
return 0;
@ -981,7 +912,7 @@ int iso14443b_select_card()
// first, wake up the tag
CodeAndTransmit14443bAsReader(wupb, sizeof(wupb));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
// ATQB too short?
if (Demod.len < 14)
{
@ -996,7 +927,7 @@ int iso14443b_select_card()
attrib[7] = Demod.output[10] & 0x0F;
ComputeCrc14443(CRC_14443_B, attrib, 9, attrib + 9, attrib + 10);
CodeAndTransmit14443bAsReader(attrib, sizeof(attrib));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
// Answer to ATTRIB too short?
if(Demod.len < 3)
{
@ -1011,7 +942,7 @@ int iso14443b_select_card()
void iso14443b_setup() {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// Set up the synchronous serial port
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
// connect Demodulated Signal to ADC:
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
@ -1019,9 +950,6 @@ void iso14443b_setup() {
LED_D_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
// Start the timer
StartCountSspClk();
DemodReset();
UartReset();
}
@ -1047,7 +975,7 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
SpinDelay(200);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
// Now give it time to spin up.
// Signal field is on with the appropriate LED
@ -1056,15 +984,17 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
SpinDelay(200);
clear_trace();
set_tracing(TRUE);
set_tracing(true);
// First command: wake up the tag using the INITIATE command
uint8_t cmd1[] = {0x06, 0x00, 0x97, 0x5b};
CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len == 0) {
DbpString("No response from tag");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return;
} else {
Dbprintf("Randomly generated Chip ID (+ 2 byte CRC): %02x %02x %02x",
@ -1077,20 +1007,26 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
cmd1[1] = Demod.output[0];
ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 3) {
Dbprintf("Expected 3 bytes from tag, got %d", Demod.len);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return;
}
// Check the CRC of the answer:
ComputeCrc14443(CRC_14443_B, Demod.output, 1 , &cmd1[2], &cmd1[3]);
if(cmd1[2] != Demod.output[1] || cmd1[3] != Demod.output[2]) {
DbpString("CRC Error reading select response.");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return;
}
// Check response from the tag: should be the same UID as the command we just sent:
if (cmd1[1] != Demod.output[0]) {
Dbprintf("Bad response to SELECT from Tag, aborting: %02x %02x", cmd1[1], Demod.output[0]);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return;
}
@ -1099,9 +1035,11 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
cmd1[0] = 0x0B;
ComputeCrc14443(CRC_14443_B, cmd1, 1 , &cmd1[1], &cmd1[2]);
CodeAndTransmit14443bAsReader(cmd1, 3); // Only first three bytes for this one
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 10) {
Dbprintf("Expected 10 bytes from tag, got %d", Demod.len);
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return;
}
// The check the CRC of the answer (use cmd1 as temporary variable):
@ -1128,9 +1066,11 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
cmd1[1] = i;
ComputeCrc14443(CRC_14443_B, cmd1, 2, &cmd1[2], &cmd1[3]);
CodeAndTransmit14443bAsReader(cmd1, sizeof(cmd1));
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
if (Demod.len != 6) { // Check if we got an answer from the tag
DbpString("Expected 6 bytes from tag, got less...");
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return;
}
// The check the CRC of the answer (use cmd1 as temporary variable):
@ -1149,6 +1089,9 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
}
i++;
}
LED_D_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
}
@ -1171,22 +1114,17 @@ void ReadSTMemoryIso14443b(uint32_t dwLast)
*/
void RAMFUNC SnoopIso14443b(void)
{
// We won't start recording the frames that we acquire until we trigger;
// a good trigger condition to get started is probably when we see a
// response from the tag.
int triggered = TRUE; // TODO: set and evaluate trigger condition
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
BigBuf_free();
clear_trace();
set_tracing(TRUE);
set_tracing(true);
// The DMA buffer, used to stream samples from the FPGA
int8_t *dmaBuf = (int8_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE);
uint16_t *dmaBuf = (uint16_t*) BigBuf_malloc(ISO14443B_DMA_BUFFER_SIZE * sizeof(uint16_t));
int lastRxCounter;
int8_t *upTo;
int ci, cq;
uint16_t *upTo;
int8_t ci, cq;
int maxBehindBy = 0;
// Count of samples received so far, so that we can include timing
@ -1211,55 +1149,57 @@ void RAMFUNC SnoopIso14443b(void)
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// Setup for the DMA.
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_RX_XCORR);
upTo = dmaBuf;
lastRxCounter = ISO14443B_DMA_BUFFER_SIZE;
FpgaSetupSscDma((uint8_t*) dmaBuf, ISO14443B_DMA_BUFFER_SIZE);
uint8_t parity[MAX_PARITY_SIZE];
bool TagIsActive = FALSE;
bool ReaderIsActive = FALSE;
bool TagIsActive = false;
bool ReaderIsActive = false;
// We won't start recording the frames that we acquire until we trigger.
// A good trigger condition to get started is probably when we see a
// reader command
bool triggered = false;
// And now we loop, receiving samples.
for(;;) {
int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) &
(ISO14443B_DMA_BUFFER_SIZE-1);
int behindBy = (lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR) & (ISO14443B_DMA_BUFFER_SIZE-1);
if(behindBy > maxBehindBy) {
maxBehindBy = behindBy;
}
if(behindBy < 2) continue;
if(behindBy < 1) continue;
ci = upTo[0];
cq = upTo[1];
upTo += 2;
lastRxCounter -= 2;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) {
upTo = dmaBuf;
ci = *upTo>>8;
cq = *upTo;
upTo++;
lastRxCounter--;
if(upTo >= dmaBuf + ISO14443B_DMA_BUFFER_SIZE) { // we have read all of the DMA buffer content.
upTo = dmaBuf; // start reading the circular buffer from the beginning again
lastRxCounter += ISO14443B_DMA_BUFFER_SIZE;
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf;
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE;
if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) {
Dbprintf("About to blow circular buffer - aborted! behindBy=%d", behindBy);
break;
}
}
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_ENDRX)) { // DMA Counter Register had reached 0, already rotated.
AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) dmaBuf; // refresh the DMA Next Buffer and
AT91C_BASE_PDC_SSC->PDC_RNCR = ISO14443B_DMA_BUFFER_SIZE; // DMA Next Counter registers
WDT_HIT();
if(behindBy > (9*ISO14443B_DMA_BUFFER_SIZE/10)) { // TODO: understand whether we can increase/decrease as we want or not?
Dbprintf("blew circular buffer! behindBy=%d", behindBy);
break;
}
if(!tracing) {
DbpString("Reached trace limit");
break;
}
if(BUTTON_PRESS()) {
DbpString("cancelled");
break;
}
}
samples += 2;
samples++;
if (!TagIsActive) { // no need to try decoding reader data if the tag is sending
if(Handle14443bUartBit(ci & 0x01)) {
if(triggered && tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE);
triggered = true;
if(tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
}
/* And ready to receive another command. */
UartReset();
@ -1268,8 +1208,9 @@ void RAMFUNC SnoopIso14443b(void)
DemodReset();
}
if(Handle14443bUartBit(cq & 0x01)) {
if(triggered && tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, TRUE);
triggered = true;
if(tracing) {
LogTrace(Uart.output, Uart.byteCnt, samples, samples, parity, true);
}
/* And ready to receive another command. */
UartReset();
@ -1280,17 +1221,15 @@ void RAMFUNC SnoopIso14443b(void)
ReaderIsActive = (Uart.state > STATE_GOT_FALLING_EDGE_OF_SOF);
}
if(!ReaderIsActive) { // no need to try decoding tag data if the reader is sending - and we cannot afford the time
if(Handle14443bSamplesDemod(ci | 0x01, cq | 0x01)) {
if(!ReaderIsActive && triggered) { // no need to try decoding tag data if the reader is sending or not yet triggered
if(Handle14443bSamplesDemod(ci/2, cq/2)) {
//Use samples as a time measurement
if(tracing)
{
uint8_t parity[MAX_PARITY_SIZE];
LogTrace(Demod.output, Demod.len, samples, samples, parity, FALSE);
LogTrace(Demod.output, Demod.len, samples, samples, parity, false);
}
triggered = TRUE;
// And ready to receive another response.
DemodReset();
}
@ -1301,7 +1240,6 @@ void RAMFUNC SnoopIso14443b(void)
FpgaDisableSscDma();
LEDsoff();
AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS;
DbpString("Snoop statistics:");
Dbprintf(" Max behind by: %i", maxBehindBy);
Dbprintf(" Uart State: %x", Uart.state);
@ -1327,15 +1265,19 @@ void SendRawCommand14443B(uint32_t datalen, uint32_t recv, uint8_t powerfield, u
{
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
FpgaSetupSsc();
// switch field on and give tag some time to power up
LED_D_ON();
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER_TX);
SpinDelay(10);
if (datalen){
set_tracing(TRUE);
set_tracing(true);
CodeAndTransmit14443bAsReader(data, datalen);
if(recv) {
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, TRUE);
GetSamplesFor14443bDemod(RECEIVE_SAMPLES_TIMEOUT, true);
uint16_t iLen = MIN(Demod.len, USB_CMD_DATA_SIZE);
cmd_send(CMD_ACK, iLen, 0, 0, Demod.output, iLen);
}

View file

@ -7,7 +7,7 @@
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Routines to support ISO 14443 type A.
// Routines to support ISO 14443 type B.
//-----------------------------------------------------------------------------
#ifndef __ISO14443B_H

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,6 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 2018 AntiCat
//
// 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
@ -11,8 +12,7 @@
#ifndef __LEGICRF_H
#define __LEGICRF_H
extern void LegicRfSimulate(int phase, int frame, int reqresp);
extern int LegicRfReader(int bytes, int offset);
extern void LegicRfReader(int bytes, int offset);
extern void LegicRfWriter(int bytes, int offset);
#endif /* __LEGICRF_H */

469
armsrc/legicrfsim.c Normal file
View file

@ -0,0 +1,469 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 2016 Iceman
// 2018 AntiCat
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// LEGIC RF simulation code
//-----------------------------------------------------------------------------
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "legicrfsim.h"
#include "legic_prng.h"
#include "legic.h"
#include "crc.h"
#include "usb_cdc.h" // for usb_poll_validate_length
static uint8_t* legic_mem; /* card memory, used for sim */
static legic_card_select_t card;/* metadata of currently selected card */
static crc_t legic_crc;
//-----------------------------------------------------------------------------
// Frame timing and pseudorandom number generator
//
// The Prng is forwarded every 99.1us (TAG_BIT_PERIOD), except when the reader is
// transmitting. In that case the prng has to be forwarded every bit transmitted:
// - 31.3us for a 0 (RWD_TIME_0)
// - 99.1us for a 1 (RWD_TIME_1)
//
// The data dependent timing makes writing comprehensible code significantly
// harder. The current aproach forwards the prng data based if there is data on
// air and time based, using GetCountSspClk(), during computational and wait
// periodes. SSP Clock is clocked by the FPGA at 212 kHz (subcarrier frequency).
//
// To not have the necessity to calculate/guess exection time dependend timeouts
// tx_frame and rx_frame use a shared timestamp to coordinate tx and rx timeslots.
//-----------------------------------------------------------------------------
static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
#define TAG_FRAME_WAIT 70 /* 330us from READER frame end to TAG frame start */
#define TAG_ACK_WAIT 758 /* 3.57ms from READER frame end to TAG write ACK */
#define TAG_BIT_PERIOD 21 /* 99.1us */
#define RWD_TIME_PAUSE 4 /* 18.9us */
#define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */
#define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */
#define RWD_CMD_TIMEOUT 40 /* 40 * 99.1us (arbitrary value) */
#define RWD_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */
#define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 bits */
#define RWD_PULSE 1 /* Pulse is signaled with GPIO_SSC_DIN high */
#define RWD_PAUSE 0 /* Pause is signaled with GPIO_SSC_DIN low */
//-----------------------------------------------------------------------------
// Demodulation
//-----------------------------------------------------------------------------
// Returns true if a pulse/pause is received within timeout
static inline bool wait_for(bool value, const uint32_t timeout) {
while((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) {
if(GetCountSspClk() > timeout) {
return false;
}
}
return true;
}
// Returns a demedulated bit or -1 on code violation
//
// rx_bit decodes bits using a thresholds. rx_bit has to be called by as soon as
// a frame starts (first pause is received). rx_bit checks for a pause up to
// 18.9us followed by a pulse of 80.2us or 42.4us:
// - A bit length <18.9us is a code violation
// - A bit length >80.2us is a 1
// - A bit length <80.2us is a 0
// - A bit length >148.6us is a code violation
static inline int8_t rx_bit() {
// backup ts for threshold calculation
uint32_t bit_start = last_frame_end;
// wait for pause to end
if(!wait_for(RWD_PULSE, bit_start + RWD_TIME_1*3/2)) {
return -1;
}
// wait for next pause
if(!wait_for(RWD_PAUSE, bit_start + RWD_TIME_1*3/2)) {
return -1;
}
// update bit and frame end
last_frame_end = GetCountSspClk();
// check for code violation (bit to short)
if(last_frame_end - bit_start < RWD_TIME_PAUSE) {
return -1;
}
// apply threshold (average of RWD_TIME_0 and )
return (last_frame_end - bit_start > (RWD_TIME_0 + RWD_TIME_1) / 2);
}
//-----------------------------------------------------------------------------
// Modulation
//
// LEGIC RF uses a very basic load modulation from card to reader:
// - Subcarrier on for a 1
// - Subcarrier off for for a 0
//
// The 212kHz subcarrier is generated by the FPGA as well as a mathcing ssp clk.
// Each bit is transfered in a 99.1us slot and the first timeslot starts 330us
// after the final 20us pause generated by the reader.
//-----------------------------------------------------------------------------
// Transmits a bit
//
// Note: The Subcarrier is not disabled during bits to prevent glitches. This is
// not mandatory but results in a cleaner signal. tx_frame will disable
// the subcarrier when the frame is done.
static inline void tx_bit(bool bit) {
LED_C_ON();
if(bit) {
// modulate subcarrier
HIGH(GPIO_SSC_DOUT);
} else {
// do not modulate subcarrier
LOW(GPIO_SSC_DOUT);
}
// wait for tx timeslot to end
last_frame_end += TAG_BIT_PERIOD;
while(GetCountSspClk() < last_frame_end) { };
LED_C_OFF();
}
//-----------------------------------------------------------------------------
// Frame Handling
//
// The LEGIC RF protocol from reader to card does not include explicit frame
// start/stop information or length information. The tag detects end of frame
// trough an extended pulse (>99.1us) without a pause.
// In reverse direction (card to reader) the number of bites is well known
// and depends only the command received (IV, ACK, READ or WRITE).
//-----------------------------------------------------------------------------
static void tx_frame(uint32_t frame, uint8_t len) {
// wait for next tx timeslot
last_frame_end += TAG_FRAME_WAIT;
legic_prng_forward(TAG_FRAME_WAIT/TAG_BIT_PERIOD - 1);
while(GetCountSspClk() < last_frame_end) { };
// transmit frame, MSB first
for(uint8_t i = 0; i < len; ++i) {
bool bit = (frame >> i) & 0x01;
tx_bit(bit ^ legic_prng_get_bit());
legic_prng_forward(1);
};
// disable subcarrier
LOW(GPIO_SSC_DOUT);
}
static void tx_ack() {
// wait for ack timeslot
last_frame_end += TAG_ACK_WAIT;
legic_prng_forward(TAG_ACK_WAIT/TAG_BIT_PERIOD - 1);
while(GetCountSspClk() < last_frame_end) { };
// transmit ack (ack is not encrypted)
tx_bit(true);
legic_prng_forward(1);
// disable subcarrier
LOW(GPIO_SSC_DOUT);
}
// Returns a demedulated frame or -1 on code violation
//
// Since TX to RX delay is arbitrary rx_frame has to:
// - detect start of frame (first pause)
// - forward prng based on ts/TAG_BIT_PERIOD
// - receive the frame
// - detect end of frame (last pause)
static int32_t rx_frame(uint8_t *len) {
int32_t frame = 0;
// add 2 SSP clock cycles (1 for tx and 1 for rx pipeline delay)
// those will be substracted at the end of the rx phase
last_frame_end -= 2;
// wait for first pause (start of frame)
for(uint8_t i = 0; true; ++i) {
// increment prng every TAG_BIT_PERIOD
last_frame_end += TAG_BIT_PERIOD;
legic_prng_forward(1);
// if start of frame was received exit delay loop
if(wait_for(RWD_PAUSE, last_frame_end)) {
last_frame_end = GetCountSspClk();
break;
}
// check for code violation
if(i > RWD_CMD_TIMEOUT) {
return -1;
}
}
// receive frame
for(*len = 0; true; ++(*len)) {
// receive next bit
LED_D_ON();
int8_t bit = rx_bit();
LED_D_OFF();
// check for code violation and to short / long frame
if((bit < 0) && ((*len < RWD_MIN_FRAME_LEN) || (*len > RWD_MAX_FRAME_LEN))) {
return -1;
}
// check for code violation caused by end of frame
if(bit < 0) {
break;
}
// append bit
frame |= (bit ^ legic_prng_get_bit()) << (*len);
legic_prng_forward(1);
}
// rx_bit sets coordination timestamp to start of pause, append pause duration
// and substract 2 SSP clock cycles (1 for rx and 1 for tx pipeline delay) to
// obtain exact end of frame.
last_frame_end += RWD_TIME_PAUSE - 2;
return frame;
}
//-----------------------------------------------------------------------------
// Legic Simulator
//-----------------------------------------------------------------------------
static int32_t init_card(uint8_t cardtype, legic_card_select_t *p_card) {
p_card->tagtype = cardtype;
switch(p_card->tagtype) {
case 0:
p_card->cmdsize = 6;
p_card->addrsize = 5;
p_card->cardsize = 22;
break;
case 1:
p_card->cmdsize = 9;
p_card->addrsize = 8;
p_card->cardsize = 256;
break;
case 2:
p_card->cmdsize = 11;
p_card->addrsize = 10;
p_card->cardsize = 1024;
break;
default:
p_card->cmdsize = 0;
p_card->addrsize = 0;
p_card->cardsize = 0;
return 2;
}
return 0;
}
static void init_tag() {
// configure FPGA
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_SIMULATOR
| FPGA_HF_SIMULATOR_MODULATE_212K);
SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
// configure SSC with defaults
FpgaSetupSsc(FPGA_MAJOR_MODE_HF_SIMULATOR);
// first pull output to low to prevent glitches then re-claim GPIO_SSC_DOUT
LOW(GPIO_SSC_DOUT);
AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT;
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
// reserve a cardmem, meaning we can use the tracelog function in bigbuff easier.
legic_mem = BigBuf_get_addr();
// init crc calculator
crc_init(&legic_crc, 4, 0x19 >> 1, 0x05, 0);
// start 212kHz timer (running from SSP Clock)
StartCountSspClk();
}
// Setup reader to card connection
//
// The setup consists of a three way handshake:
// - Receive initialisation vector 7 bits
// - Transmit card type 6 bits
// - Receive Acknowledge 6 bits
static int32_t setup_phase(legic_card_select_t *p_card) {
uint8_t len = 0;
// init coordination timestamp
last_frame_end = GetCountSspClk();
// reset prng
legic_prng_init(0);
// wait for iv
int32_t iv = rx_frame(&len);
if((len != 7) || (iv < 0)) {
return -1;
}
// configure prng
legic_prng_init(iv);
// reply with card type
switch(p_card->tagtype) {
case 0:
tx_frame(0x0D, 6);
break;
case 1:
tx_frame(0x1D, 6);
break;
case 2:
tx_frame(0x3D, 6);
break;
}
// wait for ack
int32_t ack = rx_frame(&len);
if((len != 6) || (ack < 0)) {
return -1;
}
// validate data
switch(p_card->tagtype) {
case 0:
if(ack != 0x19) return -1;
break;
case 1:
if(ack != 0x39) return -1;
break;
case 2:
if(ack != 0x39) return -1;
break;
}
// During rx the prng is clocked using the variable reader period.
// Since rx_frame detects end of frame by detecting a code violation,
// the prng is off by one bit period after each rx phase. Hence, tx
// code advances the prng by (TAG_FRAME_WAIT/TAG_BIT_PERIOD - 1).
// This is not possible for back to back rx, so this quirk reduces
// the gap by one period.
last_frame_end += TAG_BIT_PERIOD;
return 0;
}
static uint8_t calc_crc4(uint16_t cmd, uint8_t cmd_sz, uint8_t value) {
crc_clear(&legic_crc);
crc_update(&legic_crc, (value << cmd_sz) | cmd, 8 + cmd_sz);
return crc_finish(&legic_crc);
}
static int32_t connected_phase(legic_card_select_t *p_card) {
uint8_t len = 0;
// wait for command
int32_t cmd = rx_frame(&len);
if(cmd < 0) {
return -1;
}
// check if command is LEGIC_READ
if(len == p_card->cmdsize) {
// prepare data
uint8_t byte = legic_mem[cmd >> 1];
uint8_t crc = calc_crc4(cmd, p_card->cmdsize, byte);
// transmit data
tx_frame((crc << 8) | byte, 12);
return 0;
}
// check if command is LEGIC_WRITE
if(len == p_card->cmdsize + 8 + 4) {
// decode data
uint16_t mask = (1 << p_card->addrsize) - 1;
uint16_t addr = (cmd >> 1) & mask;
uint8_t byte = (cmd >> p_card->cmdsize) & 0xff;
uint8_t crc = (cmd >> (p_card->cmdsize + 8)) & 0xf;
// check received against calculated crc
uint8_t calc_crc = calc_crc4(addr << 1, p_card->cmdsize, byte);
if(calc_crc != crc) {
Dbprintf("!!! crc mismatch: %x != %x !!!", calc_crc, crc);
return -1;
}
// store data
legic_mem[addr] = byte;
// transmit ack
tx_ack();
return 0;
}
return -1;
}
//-----------------------------------------------------------------------------
// Command Line Interface
//
// Only this function is public / called from appmain.c
//-----------------------------------------------------------------------------
void LegicRfSimulate(uint8_t cardtype) {
// configure ARM and FPGA
init_tag();
// verify command line input
if(init_card(cardtype, &card) != 0) {
DbpString("Unknown tagtype.");
goto OUT;
}
LED_A_ON();
DbpString("Starting Legic emulator, press button to end");
while(!BUTTON_PRESS() && !usb_poll_validate_length()) {
WDT_HIT();
// wait for carrier, restart after timeout
if(!wait_for(RWD_PULSE, GetCountSspClk() + TAG_BIT_PERIOD)) {
continue;
}
// wait for connection, restart on error
if(setup_phase(&card)) {
continue;
}
// conection is established, process commands until one fails
while(!connected_phase(&card)) {
WDT_HIT();
}
}
OUT:
DbpString("Stopped");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_A_OFF();
LED_C_OFF();
LED_D_OFF();
StopTicks();
}

19
armsrc/legicrfsim.h Normal file
View file

@ -0,0 +1,19 @@
//-----------------------------------------------------------------------------
// (c) 2009 Henryk Plötz <henryk@ploetzli.ch>
// 2018 AntiCat
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// LEGIC RF emulation public interface
//-----------------------------------------------------------------------------
#ifndef __LEGICRFSIM_H
#define __LEGICRFSIM_H
#include "proxmark3.h"
extern void LegicRfSimulate(uint8_t tagtype);
#endif /* __LEGICRFSIM_H */

View file

@ -4,7 +4,7 @@
// the license.
//-----------------------------------------------------------------------------
// Miscellaneous routines for low frequency tag operations.
// Tags supported here so far are Texas Instruments (TI), HID
// Tags supported here so far are Texas Instruments (TI), HID, EM4x05, EM410x
// Also routines for raw mode reading/simulating of LF waveform
//-----------------------------------------------------------------------------
@ -28,51 +28,103 @@
*/
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command)
{
// start timer
StartTicks();
int divisor_used = 95; // 125 KHz
// see if 'h' was specified
// use lf config settings
sample_config *sc = getSamplingConfig();
if (command[strlen((char *) command) - 1] == 'h')
divisor_used = 88; // 134.8 KHz
sample_config sc = { 0,0,1, divisor_used, 0};
setSamplingConfig(&sc);
//clear read buffer
BigBuf_Clear_keep_EM();
/* Make sure the tag is reset */
// Make sure the tag is reset
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(2500);
WaitMS(2500);
LFSetupFPGAForADC(sc.divisor, 1);
// clear read buffer (after fpga bitstream loaded...)
BigBuf_Clear_keep_EM();
// power on
LFSetupFPGAForADC(sc->divisor, 1);
// And a little more time for the tag to fully power up
SpinDelay(2000);
WaitMS(2000);
// if delay_off = 0 then just bitbang 1 = antenna on 0 = off for respective periods.
bool bitbang = delay_off == 0;
// now modulate the reader field
if (bitbang) {
// HACK it appears the loop and if statements take up about 7us so adjust waits accordingly...
uint8_t hack_cnt = 7;
if (period_0 < hack_cnt || period_1 < hack_cnt) {
DbpString("Warning periods cannot be less than 7us in bit bang mode");
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
return;
}
// hack2 needed--- it appears to take about 8-16us to turn the antenna back on
// leading to ~ 1 to 2 125khz samples extra in every off period
// so we should test for last 0 before next 1 and reduce period_0 by this extra amount...
// but is this time different for every antenna or other hw builds??? more testing needed
// prime cmd_len to save time comparing strings while modulating
int cmd_len = 0;
while(command[cmd_len] != '\0' && command[cmd_len] != ' ')
cmd_len++;
int counter = 0;
bool off = false;
for (counter = 0; counter < cmd_len; counter++) {
// if cmd = 0 then turn field off
if (command[counter] == '0') {
// if field already off leave alone (affects timing otherwise)
if (off == false) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
off = true;
}
// note we appear to take about 7us to switch over (or run the if statements/loop...)
WaitUS(period_0-hack_cnt);
// else if cmd = 1 then turn field on
} else {
// if field already on leave alone (affects timing otherwise)
if (off) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
LED_D_ON();
off = false;
}
// note we appear to take about 7us to switch over (or run the if statements/loop...)
WaitUS(period_1-hack_cnt);
}
}
} else { // old mode of cmd read using delay as off period
while(*command != '\0' && *command != ' ') {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
SpinDelayUs(delay_off);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor);
WaitUS(delay_off);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor);
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
LED_D_ON();
if(*(command++) == '0')
SpinDelayUs(period_0);
else
SpinDelayUs(period_1);
if(*(command++) == '0') {
WaitUS(period_0);
} else {
WaitUS(period_1);
}
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
SpinDelayUs(delay_off);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc.divisor);
WaitUS(delay_off);
FpgaSendCommand(FPGA_CMD_SET_DIVISOR, sc->divisor);
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD);
// now do the read
DoAcquisition_config(false, 0);
// Turn off antenna
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// tell client we are done
cmd_send(CMD_ACK,0,0,0,0,0);
}
/* blank r/w tag data stream
@ -516,7 +568,7 @@ static void fcAll(uint8_t fc, int *n, uint8_t clock, uint16_t *modCnt)
uint8_t wavesPerClock = clock/fc;
uint8_t mod = clock % fc; //modifier
uint8_t modAdj = fc/mod; //how often to apply modifier
bool modAdjOk = !(fc % mod); //if (fc % mod==0) modAdjOk=TRUE;
bool modAdjOk = !(fc % mod); //if (fc % mod==0) modAdjOk=true;
// loop through clock - step field clock
for (uint8_t idx=0; idx < wavesPerClock; idx++){
// put 1/2 FC length 1's and 1/2 0's per field clock wave (to create the wave)
@ -541,7 +593,7 @@ static void fcAll(uint8_t fc, int *n, uint8_t clock, uint16_t *modCnt)
// prepare a waveform pattern in the buffer based on the ID given then
// simulate a HID tag until the button is pressed
void CmdHIDsimTAG(int hi, int lo, int ledcontrol)
void CmdHIDsimTAG(int hi2, int hi, int lo, int ledcontrol)
{
int n=0, i=0;
/*
@ -554,8 +606,8 @@ void CmdHIDsimTAG(int hi, int lo, int ledcontrol)
nor 1 bits, they are special patterns (a = set of 12 fc8 and b = set of 10 fc10)
*/
if (hi>0xFFF) {
DbpString("Tags can only have 44 bits. - USE lf simfsk for larger tags");
if (hi2>0x0FFFFFFF) {
DbpString("Tags can only have 44 or 84 bits. - USE lf simfsk for larger tags");
return;
}
// set LF so we don't kill the bigbuf we are setting with simulation data.
@ -569,6 +621,27 @@ void CmdHIDsimTAG(int hi, int lo, int ledcontrol)
fc(8, &n); fc(10, &n); // logical 0
WDT_HIT();
if (hi2 > 0 || hi > 0xFFF){
// manchester encode bits 91 to 64 (91-84 are part of the header)
for (i=27; i>=0; i--) {
if ((i%4)==3) fc(0,&n);
if ((hi2>>i)&1) {
fc(10, &n); fc(8, &n); // low-high transition
} else {
fc(8, &n); fc(10, &n); // high-low transition
}
}
WDT_HIT();
// manchester encode bits 63 to 32
for (i=31; i>=0; i--) {
if ((i%4)==3) fc(0,&n);
if ((hi>>i)&1) {
fc(10, &n); fc(8, &n); // low-high transition
} else {
fc(8, &n); fc(10, &n); // high-low transition
}
}
} else {
// manchester encode bits 43 to 32
for (i=11; i>=0; i--) {
if ((i%4)==3) fc(0,&n);
@ -578,6 +651,7 @@ void CmdHIDsimTAG(int hi, int lo, int ledcontrol)
fc(8, &n); fc(10, &n); // high-low transition
}
}
}
WDT_HIT();
// manchester encode bits 31 to 0
@ -768,9 +842,9 @@ void CmdPSKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream)
for (i=0; i<size; i++){
if (BitStream[i] == curPhase){
pskSimBit(carrier, &n, clk, &curPhase, FALSE);
pskSimBit(carrier, &n, clk, &curPhase, false);
} else {
pskSimBit(carrier, &n, clk, &curPhase, TRUE);
pskSimBit(carrier, &n, clk, &curPhase, true);
}
}
Dbprintf("Simulating with Carrier: %d, clk: %d, invert: %d, n: %d",carrier, clk, invert, n);
@ -787,7 +861,7 @@ void CmdPSKsimTag(uint16_t arg1, uint16_t arg2, size_t size, uint8_t *BitStream)
}
// loop to get raw HID waveform then FSK demodulate the TAG ID from it
void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
void CmdHIDdemodFSK(int findone, int *high2, int *high, int *low, int ledcontrol)
{
uint8_t *dest = BigBuf_get_addr();
//const size_t sizeOfBigBuff = BigBuf_max_traceLen();
@ -802,7 +876,6 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
BigBuf_Clear_keep_EM();
while(!BUTTON_PRESS() && !usb_poll_validate_length()) {
WDT_HIT();
if (ledcontrol) LED_A_ON();
@ -813,60 +886,70 @@ void CmdHIDdemodFSK(int findone, int *high, int *low, int ledcontrol)
idx = HIDdemodFSK(dest, &size, &hi2, &hi, &lo, &dummyIdx);
if (idx>0 && lo>0 && (size==96 || size==192)){
// go over previously decoded manchester data and decode into usable tag ID
if (hi2 != 0){ //extra large HID tags 88/192 bits
Dbprintf("TAG ID: %x%08x%08x (%d)",
(unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
}else { //standard HID tags 44/96 bits
//Dbprintf("TAG ID: %x%08x (%d)",(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF); //old print cmd
uint8_t bitlen = 0;
uint32_t fc = 0;
uint32_t cardnum = 0;
if (((hi>>5)&1) == 1){//if bit 38 is set then < 37 bit format is used
uint32_t lo2=0;
lo2=(((hi & 31) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit
uint8_t idx3 = 1;
while(lo2 > 1){ //find last bit set to 1 (format len bit)
lo2=lo2 >> 1;
idx3++;
bool decoded = false;
// go over previously decoded manchester data and decode into usable tag ID
if ((hi2 & 0x000FFFF) != 0){ //extra large HID tags 88/192 bits
uint32_t bp = hi2 & 0x000FFFFF;
bitlen = 63;
while (bp > 0) {
bp = bp >> 1;
bitlen++;
}
bitlen = idx3+19;
fc =0;
cardnum=0;
if(bitlen == 26){
} else if ((hi >> 6) > 0) {
uint32_t bp = hi;
bitlen = 31;
while (bp > 0) {
bp = bp >> 1;
bitlen++;
}
} else if (((hi >> 5) & 1) == 0) {
bitlen = 37;
} else if ((hi & 0x0000001F) > 0 ) {
uint32_t bp = (hi & 0x0000001F);
bitlen = 31;
while (bp > 0) {
bp = bp >> 1;
bitlen++;
}
} else {
uint32_t bp = lo;
bitlen = 0;
while (bp > 0) {
bp = bp >> 1;
bitlen++;
}
}
switch (bitlen){
case 26:
cardnum = (lo>>1)&0xFFFF;
fc = (lo>>17)&0xFF;
}
if(bitlen == 37){
cardnum = (lo>>1)&0x7FFFF;
fc = ((hi&0xF)<<12)|(lo>>20);
}
if(bitlen == 34){
cardnum = (lo>>1)&0xFFFF;
fc= ((hi&1)<<15)|(lo>>17);
}
if(bitlen == 35){
decoded = true;
break;
case 35:
cardnum = (lo>>1)&0xFFFFF;
fc = ((hi&1)<<11)|(lo>>21);
decoded = true;
break;
}
}
else { //if bit 38 is not set then 37 bit format is used
bitlen= 37;
fc =0;
cardnum=0;
if(bitlen==37){
cardnum = (lo>>1)&0x7FFFF;
fc = ((hi&0xF)<<12)|(lo>>20);
}
}
//Dbprintf("TAG ID: %x%08x (%d)",
// (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
Dbprintf("TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d",
(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF,
if (hi2 != 0) //extra large HID tags 88/192 bits
Dbprintf("TAG ID: %x%08x%08x (%d)",
(unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
else
Dbprintf("TAG ID: %x%08x (%d)",
(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
if (decoded)
Dbprintf("Format Len: %dbits - FC: %d - Card: %d",
(unsigned int) bitlen, (unsigned int) fc, (unsigned int) cardnum);
}
if (findone){
if (ledcontrol) LED_A_OFF();
*high2 = hi2;
*high = hi;
*low = lo;
break;
@ -1159,7 +1242,7 @@ void T55xxResetRead(void) {
TurnReadLFOn(READ_GAP);
// Acquisition
DoPartialAcquisition(0, true, BigBuf_max_traceLen());
DoPartialAcquisition(0, true, BigBuf_max_traceLen(), 0);
// Turn the field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
@ -1291,7 +1374,7 @@ void T55xxReadBlock(uint16_t arg0, uint8_t Block, uint32_t Pwd) {
// Acquisition
// Now do the acquisition
DoPartialAcquisition(0, true, 12000);
DoPartialAcquisition(0, true, 12000, 0);
// Turn the field off
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
@ -1690,7 +1773,7 @@ void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode) {
SendForward(fwd_bit_count);
WaitUS(400);
// Now do the acquisition
DoPartialAcquisition(20, true, 6000);
DoPartialAcquisition(20, true, 6000, 1000);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_A_OFF();
@ -1723,7 +1806,7 @@ void EM4xWriteWord(uint32_t flag, uint32_t Data, uint32_t Pwd) {
WaitUS(6500);
//Capture response if one exists
DoPartialAcquisition(20, true, 6000);
DoPartialAcquisition(20, true, 6000, 1000);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off
LED_A_OFF();
@ -1766,7 +1849,7 @@ void Cotag(uint32_t arg0) {
SetAdcMuxFor(GPIO_MUXSEL_LOPKD);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC);
// start clock - 1.5ticks is 1us
StartTicks();

View file

@ -101,7 +101,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
// Give it a bit of time for the resonant antenna to settle.
SpinDelay(50);
// Now set up the SSC to get the ADC samples that are now streaming at us.
FpgaSetupSsc();
FpgaSetupSsc(FPGA_MAJOR_MODE_LF_ADC);
}
/**
@ -119,7 +119,7 @@ void LFSetupFPGAForADC(int divisor, bool lf_field)
* @param silent - is true, now outputs are made. If false, dbprints the status
* @return the number of bits occupied by the samples.
*/
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize)
uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averaging, int trigger_threshold, bool silent, int bufsize, int cancel_after)
{
//.
uint8_t *dest = BigBuf_get_addr();
@ -140,6 +140,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
uint32_t sample_sum =0 ;
uint32_t sample_total_numbers =0 ;
uint32_t sample_total_saved =0 ;
uint32_t cancel_counter = 0;
while(!BUTTON_PRESS() && !usb_poll_validate_length() ) {
WDT_HIT();
@ -151,9 +152,13 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
sample = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
LED_D_OFF();
// threshold either high or low values 128 = center 0. if trigger = 178
if ((trigger_threshold > 0) && (sample < (trigger_threshold+128)) && (sample > (128-trigger_threshold))) //
if ((trigger_threshold > 0) && (sample < (trigger_threshold+128)) && (sample > (128-trigger_threshold))) { //
if (cancel_after > 0) {
cancel_counter++;
if (cancel_after == cancel_counter) break;
}
continue;
}
trigger_threshold = 0;
sample_total_numbers++;
@ -213,7 +218,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint32_t bits_per_sample, bool averag
*/
uint32_t DoAcquisition_default(int trigger_threshold, bool silent)
{
return DoAcquisition(1,8,0,trigger_threshold,silent,0);
return DoAcquisition(1,8,0,trigger_threshold,silent,0,0);
}
uint32_t DoAcquisition_config(bool silent, int sample_size)
{
@ -222,11 +227,12 @@ uint32_t DoAcquisition_config(bool silent, int sample_size)
,config.averaging
,config.trigger_threshold
,silent
,sample_size);
,sample_size
,0);
}
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size) {
return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size);
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, int cancel_after) {
return DoAcquisition(1,8,0,trigger_threshold,silent,sample_size,cancel_after);
}
uint32_t ReadLF(bool activeField, bool silent, int sample_size)
@ -260,7 +266,7 @@ uint32_t SnoopLF()
}
/**
* acquisition of Cotag LF signal. Similart to other LF, since the Cotag has such long datarate RF/384
* acquisition of Cotag LF signal. Similar to other LF, since the Cotag has such long datarate RF/384
* and is Manchester?, we directly gather the manchester data into bigbuff
**/
#define COTAG_T1 384
@ -329,8 +335,8 @@ uint32_t doCotagAcquisitionManchester() {
uint8_t sample = 0, firsthigh = 0, firstlow = 0;
uint16_t sample_counter = 0, period = 0;
uint8_t curr = 0, prev = 0;
while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) ) {
uint16_t noise_counter = 0;
while (!BUTTON_PRESS() && !usb_poll_validate_length() && (sample_counter < bufsize) && (noise_counter < (COTAG_T1<<1)) ) {
WDT_HIT();
if (AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY) {
AT91C_BASE_SSC->SSC_THR = 0x43;
@ -343,14 +349,20 @@ uint32_t doCotagAcquisitionManchester() {
// find first peak
if ( !firsthigh ) {
if (sample < COTAG_ONE_THRESHOLD)
if (sample < COTAG_ONE_THRESHOLD) {
noise_counter++;
continue;
}
noise_counter = 0;
firsthigh = 1;
}
if ( !firstlow ){
if (sample > COTAG_ZERO_THRESHOLD )
if (sample > COTAG_ZERO_THRESHOLD ) {
noise_counter++;
continue;
}
noise_counter=0;
firstlow = 1;
}

View file

@ -21,7 +21,7 @@ uint32_t SampleLF(bool silent, int sample_size);
uint32_t SnoopLF();
// adds sample size to default options
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size);
uint32_t DoPartialAcquisition(int trigger_threshold, bool silent, int sample_size, int cancel_after);
/**
* @brief Does sample acquisition, ignoring the config values set in the sample_config.

View file

@ -20,9 +20,8 @@
#include "parity.h"
#include "crc.h"
#define AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
#define PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
#define HARDNESTED_AUTHENTICATION_TIMEOUT 848 // card times out 1ms after wrong authentication (according to NXP documentation)
#define HARDNESTED_PRE_AUTHENTICATION_LEADTIME 400 // some (non standard) cards need a pause after select before they are ready for first authentication
// the block number for the ISO14443-4 PCB
static uint8_t pcb_blocknum = 0;
@ -59,7 +58,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
@ -106,7 +105,7 @@ void MifareUC_Auth(uint8_t arg0, uint8_t *keybytes){
clear_trace();
if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) {
if(!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
OnError(0);
return;
@ -141,7 +140,7 @@ void MifareUReadBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
clear_trace();
int len = iso14443a_select_card(NULL, NULL, NULL, true, 0);
int len = iso14443a_select_card(NULL, NULL, NULL, true, 0, true);
if(!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%02X)",len);
OnError(1);
@ -217,7 +216,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LED_C_OFF();
isOK = 1;
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
isOK = 0;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
}
@ -281,7 +280,7 @@ void MifareUReadCard(uint8_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
return;
}
int len = iso14443a_select_card(NULL, NULL, NULL, true, 0);
int len = iso14443a_select_card(NULL, NULL, NULL, true, 0, true);
if (!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card (RC:%d)",len);
OnError(1);
@ -383,7 +382,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
LED_C_OFF();
while (true) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
};
@ -483,7 +482,7 @@ void MifareUWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t *datain)
clear_trace();
if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) {
if(!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
OnError(0);
return;
@ -542,7 +541,7 @@ void MifareUSetPwd(uint8_t arg0, uint8_t *datain){
clear_trace();
if(!iso14443a_select_card(NULL, NULL, NULL, true, 0)) {
if(!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
OnError(0);
return;
@ -662,7 +661,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)) {
if(!iso14443a_select_card(uid, &card_info, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (ALL)");
continue;
}
@ -674,14 +673,14 @@ 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_select_card(uid, NULL, NULL, false, cascade_levels)) {
if(!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("AcquireNonces: Can't select card (UID)");
continue;
}
}
if (slow) {
timeout = GetCountSspClk() + PRE_AUTHENTICATION_LEADTIME;
timeout = GetCountSspClk() + HARDNESTED_PRE_AUTHENTICATION_LEADTIME;
while(GetCountSspClk() < timeout);
}
@ -698,10 +697,11 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
continue;
}
// send a dummy byte as reader response in order to trigger the cards authentication timeout
uint8_t dummy_answer = 0;
ReaderTransmit(&dummy_answer, 1, NULL);
timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
// send an incomplete dummy response in order to trigger the card's authentication failure timeout
uint8_t dummy_answer[1] = {0};
ReaderTransmit(dummy_answer, 1, NULL);
timeout = GetCountSspClk() + HARDNESTED_AUTHENTICATION_TIMEOUT;
num_nonces++;
if (num_nonces % 2) {
@ -807,7 +807,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
continue;
}
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
rtr--;
continue;
@ -881,7 +881,7 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
continue;
}
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Nested: Can't select card");
continue;
};
@ -961,24 +961,14 @@ void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t calibrate, uint8_t *dat
// MIFARE check keys. key count up to 85.
//
//-----------------------------------------------------------------------------
void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
void MifareChkKeys(uint16_t arg0, uint16_t arg1, uint8_t arg2, uint8_t *datain)
{
uint8_t blockNo = arg0 & 0xff;
uint8_t keyType = (arg0 >> 8) & 0xff;
bool clearTrace = arg1;
bool clearTrace = arg1 & 0x01;
bool multisectorCheck = arg1 & 0x02;
uint8_t set14aTimeout = (arg1 >> 8) & 0xff;
uint8_t keyCount = arg2;
uint64_t ui64Key = 0;
bool have_uid = false;
uint8_t cascade_levels = 0;
uint32_t timeout = 0;
int i;
byte_t isOK = 0;
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
// clear debug level
int OLD_MF_DBGLEVEL = MF_DBGLEVEL;
@ -992,52 +982,33 @@ void MifareChkKeys(uint16_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain)
if (clearTrace) clear_trace();
set_tracing(true);
for (i = 0; i < keyCount; i++) {
// if(mifare_classic_halt(pcs, cuid)) {
// if (MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Halt error");
// }
// Iceman: use piwi's faster nonce collecting part in hardnested.
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)) {
if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card");
--i; // try same key once again
continue;
}
switch (card_info.uidlen) {
case 4 : cascade_levels = 1; break;
case 7 : cascade_levels = 2; break;
case 10: cascade_levels = 3; break;
default: break;
}
have_uid = true;
} else { // no need for anticollision. We can directly select the card
if(!iso14443a_select_card(uid, NULL, NULL, false, cascade_levels)) {
if (OLD_MF_DBGLEVEL >= 1) Dbprintf("ChkKeys: Can't select card (UID)");
--i; // try same key once again
continue;
}
if (set14aTimeout){
iso14a_set_timeout(set14aTimeout * 10); // timeout: ms = x/106 35-minimum, 50-OK 106-recommended 500-safe
}
ui64Key = bytes_to_num(datain + i * 6, 6);
if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
uint8_t dummy_answer = 0;
ReaderTransmit(&dummy_answer, 1, NULL);
timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
// wait for the card to become ready again
while(GetCountSspClk() < timeout);
continue;
}
isOK = 1;
break;
}
if (multisectorCheck) {
TKeyIndex keyIndex = {{0}};
uint8_t sectorCnt = blockNo;
int res = MifareMultisectorChk(datain, keyCount, sectorCnt, keyType, OLD_MF_DBGLEVEL, &keyIndex);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6);
if (res >= 0) {
cmd_send(CMD_ACK, 1, 0, 0, keyIndex, 80);
} else {
cmd_send(CMD_ACK, 0, 0, 0, NULL, 0);
}
LED_B_OFF();
} else {
int res = MifareChkBlockKeys(datain, keyCount, blockNo, keyType, OLD_MF_DBGLEVEL);
LED_B_ON();
if (res > 0) {
cmd_send(CMD_ACK, 1, 0, 0, datain + (res - 1) * 6, 6);
} else {
cmd_send(CMD_ACK, 0, 0, 0, NULL, 0);
}
LED_B_OFF();
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
@ -1111,7 +1082,7 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
bool isOK = true;
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
isOK = false;
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
}
@ -1170,6 +1141,143 @@ void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn)
//
//-----------------------------------------------------------------------------
static bool isBlockTrailer(int blockN) {
if (blockN >= 0 && blockN < 128) {
return ((blockN & 0x03) == 0x03);
}
if (blockN >= 128 && blockN <= 256) {
return ((blockN & 0x0F) == 0x0F);
}
return false;
}
void MifareCWipe(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// var
byte_t isOK = 0;
uint32_t numBlocks = arg0;
// cmdParams:
// bit 0 - wipe gen1a
// bit 1 - fill card with default data
// bit 2 - gen1a = 0, gen1b = 1
uint8_t cmdParams = arg1;
bool needWipe = cmdParams & 0x01;
bool needFill = cmdParams & 0x02;
bool gen1b = cmdParams & 0x04;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
uint8_t block0[16] = {0x01, 0x02, 0x03, 0x04, 0x04, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAF};
uint8_t block1[16] = {0x00};
uint8_t blockK[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x08, 0x77, 0x8F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
uint8_t d_block[18] = {0x00};
// card commands
uint8_t wupC1[] = { 0x40 };
uint8_t wupC2[] = { 0x43 };
uint8_t wipeC[] = { 0x41 };
// iso14443 setup
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// tracing
clear_trace();
set_tracing(true);
while (true){
// wipe
if (needWipe){
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wipeC error");
break;
};
if(mifare_classic_halt(NULL, 0)) {
if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
};
};
// put default data
if (needFill){
// select commands
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
// gen1b magic tag : do no issue wupC2 and don't expect 0x0a response after SELECT_UID (after getting UID from chip in 'hf mf csetuid' command)
if (!gen1b) {
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if(!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("wupC2 error");
break;
};
}
// send blocks command
for (int blockNo = 0; blockNo < numBlocks; blockNo++) {
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send command error");
break;
};
// check type of block and add crc
if (!isBlockTrailer(blockNo)){
memcpy(d_block, block1, 16);
} else {
memcpy(d_block, blockK, 16);
}
if (blockNo == 0) {
memcpy(d_block, block0, 16);
}
AppendCrc14443a(d_block, 16);
// send write command
ReaderTransmit(d_block, sizeof(d_block), NULL);
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1) Dbprintf("write block send data error");
break;
};
}
// halt
// do no issue halt command for gen1b
if (!gen1b) {
if (mifare_classic_halt(NULL, 0)) {
if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
break;
}
}
}
break;
}
// send USB response
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,NULL,0);
LED_B_OFF();
// reset fpga
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
return;
}
void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){
// params
@ -1212,9 +1320,10 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
// get UID from chip
if (workFlags & 0x01) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0)) {
if(!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card");
break;
// Continue, if we set wrong UID or wrong UID checksum or some ATQA or SAK we will can't select card. But we need to write block 0 to make card work.
//break;
};
if(mifare_classic_halt(NULL, cuid)) {
@ -1239,7 +1348,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
break;
};
if(mifare_classic_halt(NULL, cuid)) {
if(mifare_classic_halt(NULL, 0)) {
if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
// Continue, some magic tags misbehavies and send an answer to it.
// break;
@ -1283,7 +1392,7 @@ void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datai
if (workFlags & 0x04) {
// do no issue halt command for gen1b magic tag (#db# halt error. response len: 1)
if (!(workFlags & 0x40)) {
if (mifare_classic_halt(NULL, cuid)) {
if (mifare_classic_halt(NULL, 0)) {
if (MF_DBGLEVEL > 2) Dbprintf("Halt error");
// Continue, some magic tags misbehavies and send an answer to it.
// break;
@ -1406,6 +1515,14 @@ void MifareCIdent(){
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(true);
ReaderTransmitBitsPar(wupC1,7,0, NULL);
if(ReaderReceive(receivedAnswer, receivedAnswerPar) && (receivedAnswer[0] == 0x0a)) {
isOK = 2;
@ -1419,7 +1536,12 @@ void MifareCIdent(){
// From iceman1001: removed the if, since some magic tags misbehavies and send an answer to it.
mifare_classic_halt(NULL, 0);
LED_B_ON();
cmd_send(CMD_ACK,isOK,0,0,0,0);
LED_B_OFF();
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
//
@ -1435,7 +1557,7 @@ void Mifare_DES_Auth1(uint8_t arg0, uint8_t *datain){
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
int len = iso14443a_select_card(uid, NULL, &cuid, true, 0);
int len = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
if(!len) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Can't select card");
OnError(1);

View file

@ -16,7 +16,6 @@
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "string.h"
#include "iso14443crc.h"
#include "iso14443a.h"

779
armsrc/mifaresim.c Normal file
View file

@ -0,0 +1,779 @@
//-----------------------------------------------------------------------------
// Merlok - June 2011, 2012
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Mifare Classic Card Simulation
//-----------------------------------------------------------------------------
#include "mifaresim.h"
#include "iso14443a.h"
#include "iso14443crc.h"
#include "crapto1/crapto1.h"
#include "BigBuf.h"
#include "string.h"
#include "mifareutil.h"
#include "fpgaloader.h"
#include "proxmark3.h"
#include "usb_cdc.h"
#include "cmd.h"
#include "protocols.h"
#include "apps.h"
//mifare emulator states
#define MFEMUL_NOFIELD 0
#define MFEMUL_IDLE 1
#define MFEMUL_SELECT1 2
#define MFEMUL_SELECT2 3
#define MFEMUL_SELECT3 4
#define MFEMUL_AUTH1 5
#define MFEMUL_AUTH2 6
#define MFEMUL_WORK 7
#define MFEMUL_WRITEBL2 8
#define MFEMUL_INTREG_INC 9
#define MFEMUL_INTREG_DEC 10
#define MFEMUL_INTREG_REST 11
#define MFEMUL_HALTED 12
#define cardSTATE_TO_IDLE() { cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF(); }
#define AC_DATA_READ 0
#define AC_DATA_WRITE 1
#define AC_DATA_INC 2
#define AC_DATA_DEC_TRANS_REST 3
#define AC_KEYA_READ 0
#define AC_KEYA_WRITE 1
#define AC_KEYB_READ 2
#define AC_KEYB_WRITE 3
#define AC_AC_READ 4
#define AC_AC_WRITE 5
#define AUTHKEYA 0
#define AUTHKEYB 1
#define AUTHKEYNONE 0xff
static bool IsTrailerAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
uint8_t sector_trailer[16];
emlGetMem(sector_trailer, blockNo, 1);
uint8_t AC = ((sector_trailer[7] >> 5) & 0x04)
| ((sector_trailer[8] >> 2) & 0x02)
| ((sector_trailer[8] >> 7) & 0x01);
switch (action) {
case AC_KEYA_READ: {
return false;
break;
}
case AC_KEYA_WRITE: {
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x01))
|| (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03)));
break;
}
case AC_KEYB_READ: {
return (keytype == AUTHKEYA && (AC == 0x00 || AC == 0x02 || AC == 0x01));
break;
}
case AC_KEYB_WRITE: {
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x04))
|| (keytype == AUTHKEYB && (AC == 0x04 || AC == 0x03)));
break;
}
case AC_AC_READ: {
return ((keytype == AUTHKEYA)
|| (keytype == AUTHKEYB && !(AC == 0x00 || AC == 0x02 || AC == 0x01)));
break;
}
case AC_AC_WRITE: {
return ((keytype == AUTHKEYA && (AC == 0x01))
|| (keytype == AUTHKEYB && (AC == 0x03 || AC == 0x05)));
break;
}
default: return false;
}
}
static bool IsDataAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action)
{
uint8_t sector_trailer[16];
emlGetMem(sector_trailer, SectorTrailer(blockNo), 1);
uint8_t sector_block;
if (blockNo < 32*4) {
sector_block = blockNo & 0x03;
} else {
sector_block = (blockNo & 0x0f) / 5;
}
uint8_t AC;
switch (sector_block) {
case 0x00: {
AC = ((sector_trailer[7] >> 2) & 0x04)
| ((sector_trailer[8] << 1) & 0x02)
| ((sector_trailer[8] >> 4) & 0x01);
break;
}
case 0x01: {
AC = ((sector_trailer[7] >> 3) & 0x04)
| ((sector_trailer[8] >> 0) & 0x02)
| ((sector_trailer[8] >> 5) & 0x01);
break;
}
case 0x02: {
AC = ((sector_trailer[7] >> 4) & 0x04)
| ((sector_trailer[8] >> 1) & 0x02)
| ((sector_trailer[8] >> 6) & 0x01);
break;
}
default:
return false;
}
switch (action) {
case AC_DATA_READ: {
return ((keytype == AUTHKEYA && !(AC == 0x03 || AC == 0x05 || AC == 0x07))
|| (keytype == AUTHKEYB && !(AC == 0x07)));
break;
}
case AC_DATA_WRITE: {
return ((keytype == AUTHKEYA && (AC == 0x00))
|| (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x04 || AC == 0x06 || AC == 0x03)));
break;
}
case AC_DATA_INC: {
return ((keytype == AUTHKEYA && (AC == 0x00))
|| (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06)));
break;
}
case AC_DATA_DEC_TRANS_REST: {
return ((keytype == AUTHKEYA && (AC == 0x00 || AC == 0x06 || AC == 0x01))
|| (keytype == AUTHKEYB && (AC == 0x00 || AC == 0x06 || AC == 0x01)));
break;
}
}
return false;
}
static bool IsAccessAllowed(uint8_t blockNo, uint8_t keytype, uint8_t action) {
if (IsSectorTrailer(blockNo)) {
return IsTrailerAccessAllowed(blockNo, keytype, action);
} else {
return IsDataAccessAllowed(blockNo, keytype, action);
}
}
static void MifareSimInit(uint8_t flags, uint8_t *datain, tag_response_info_t **responses, uint32_t *cuid, uint8_t *uid_len) {
#define TAG_RESPONSE_COUNT 5 // number of precompiled responses
static uint8_t rATQA[] = {0x04, 0x00}; // indicate Mifare classic 1k 4Byte UID
static uint8_t rUIDBCC1[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 1st cascade level
static uint8_t rUIDBCC2[] = {0x00, 0x00, 0x00, 0x00, 0x00}; // UID 2nd cascade level
static uint8_t rSAKfinal[]= {0x08, 0xb6, 0xdd}; // mifare 1k indicated
static uint8_t rSAK1[] = {0x04, 0xda, 0x17}; // indicate UID not finished
*uid_len = 4;
// UID can be set from emulator memory or incoming data and can be 4 or 7 bytes long
if (flags & FLAG_4B_UID_IN_DATA) { // get UID from datain
memcpy(rUIDBCC1, datain, 4);
} else if (flags & FLAG_7B_UID_IN_DATA) {
rUIDBCC1[0] = 0x88;
memcpy(rUIDBCC1+1, datain, 3);
memcpy(rUIDBCC2, datain+3, 4);
*uid_len = 7;
} else {
uint8_t probable_atqa;
emlGetMemBt(&probable_atqa, 7, 1); // get UID from emul memory - weak guess at length
if (probable_atqa == 0x00) { // ---------- 4BUID
emlGetMemBt(rUIDBCC1, 0, 4);
} else { // ---------- 7BUID
rUIDBCC1[0] = 0x88;
emlGetMemBt(rUIDBCC1+1, 0, 3);
emlGetMemBt(rUIDBCC2, 3, 4);
*uid_len = 7;
}
}
switch (*uid_len) {
case 4:
*cuid = bytes_to_num(rUIDBCC1, 4);
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
if (MF_DBGLEVEL >= 2) {
Dbprintf("4B UID: %02x%02x%02x%02x",
rUIDBCC1[0], rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3] );
}
break;
case 7:
rATQA[0] |= 0x40;
*cuid = bytes_to_num(rUIDBCC2, 4);
rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3];
rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3];
if (MF_DBGLEVEL >= 2) {
Dbprintf("7B UID: %02x %02x %02x %02x %02x %02x %02x",
rUIDBCC1[1], rUIDBCC1[2], rUIDBCC1[3], rUIDBCC2[0], rUIDBCC2[1], rUIDBCC2[2], rUIDBCC2[3] );
}
break;
default:
break;
}
static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = {
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type
{ .response = rUIDBCC1, .response_n = sizeof(rUIDBCC1) }, // Anticollision cascade1 - respond with first part of uid
{ .response = rUIDBCC2, .response_n = sizeof(rUIDBCC2) }, // Anticollision cascade2 - respond with 2nd part of uid
{ .response = rSAKfinal, .response_n = sizeof(rSAKfinal) }, // Acknowledge select - last cascade
{ .response = rSAK1, .response_n = sizeof(rSAK1) } // Acknowledge select - previous cascades
};
// Prepare ("precompile") the responses of the anticollision phase. There will be not enough time to do this at the moment the reader sends its REQA or SELECT
// There are 7 predefined responses with a total of 18 bytes data to transmit. Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
// 18 * 8 data bits, 18 * 1 parity bits, 5 start bits, 5 stop bits, 5 correction bits -> need 177 bytes buffer
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 177 // number of bytes required for precompiled responses
uint8_t *free_buffer_pointer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
size_t free_buffer_size = ALLOCATED_TAG_MODULATION_BUFFER_SIZE;
for (size_t i = 0; i < TAG_RESPONSE_COUNT; i++) {
prepare_allocated_tag_modulation(&responses_init[i], &free_buffer_pointer, &free_buffer_size);
}
*responses = responses_init;
// indices into responses array:
#define ATQA 0
#define UIDBCC1 1
#define UIDBCC2 2
#define SAKfinal 3
#define SAK1 4
}
static bool HasValidCRC(uint8_t *receivedCmd, uint16_t receivedCmd_len) {
uint8_t CRC_byte_1, CRC_byte_2;
ComputeCrc14443(CRC_14443_A, receivedCmd, receivedCmd_len-2, &CRC_byte_1, &CRC_byte_2);
return (receivedCmd[receivedCmd_len-2] == CRC_byte_1 && receivedCmd[receivedCmd_len-1] == CRC_byte_2);
}
/**
*MIFARE 1K simulate.
*
*@param flags :
* FLAG_INTERACTIVE - In interactive mode, we are expected to finish the operation with an ACK
* FLAG_4B_UID_IN_DATA - means that there is a 4-byte UID in the data-section, we're expected to use that
* FLAG_7B_UID_IN_DATA - means that there is a 7-byte UID in the data-section, we're expected to use that
* FLAG_10B_UID_IN_DATA - use 10-byte UID in the data-section not finished
* FLAG_NR_AR_ATTACK - means we should collect NR_AR responses for bruteforcing later
* FLAG_RANDOM_NONCE - means we should generate some pseudo-random nonce data (only allows moebius attack)
*@param exitAfterNReads, exit simulation after n blocks have been read, 0 is infinite ...
* (unless reader attack mode enabled then it runs util it gets enough nonces to recover all keys attmpted)
*/
void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain)
{
tag_response_info_t *responses;
uint8_t uid_len = 4;
uint32_t cuid = 0;
uint8_t cardWRBL = 0;
uint8_t cardAUTHSC = 0;
uint8_t cardAUTHKEY = AUTHKEYNONE; // no authentication
uint32_t cardRr = 0;
//uint32_t rn_enc = 0;
uint32_t ans = 0;
uint32_t cardINTREG = 0;
uint8_t cardINTBLOCK = 0;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
uint32_t numReads = 0;//Counts numer of times reader reads a block
uint8_t receivedCmd[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedCmd_dec[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedCmd_par[MAX_MIFARE_PARITY_SIZE];
uint16_t receivedCmd_len;
uint8_t response[MAX_MIFARE_FRAME_SIZE];
uint8_t response_par[MAX_MIFARE_PARITY_SIZE];
uint8_t rAUTH_NT[] = {0x01, 0x02, 0x03, 0x04};
uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00};
//Here, we collect UID,sector,keytype,NT,AR,NR,NT2,AR2,NR2
// This will be used in the reader-only attack.
//allow collecting up to 7 sets of nonces to allow recovery of up to 7 keys
#define ATTACK_KEY_COUNT 7 // keep same as define in cmdhfmf.c -> readerAttack() (Cannot be more than 7)
nonces_t ar_nr_resp[ATTACK_KEY_COUNT*2]; //*2 for 2 separate attack types (nml, moebius) 36 * 7 * 2 bytes = 504 bytes
memset(ar_nr_resp, 0x00, sizeof(ar_nr_resp));
uint8_t ar_nr_collected[ATTACK_KEY_COUNT*2]; //*2 for 2nd attack type (moebius)
memset(ar_nr_collected, 0x00, sizeof(ar_nr_collected));
uint8_t nonce1_count = 0;
uint8_t nonce2_count = 0;
uint8_t moebius_n_count = 0;
bool gettingMoebius = false;
uint8_t mM = 0; //moebius_modifier for collection storage
// Authenticate response - nonce
uint32_t nonce;
if (flags & FLAG_RANDOM_NONCE) {
nonce = prand();
} else {
nonce = bytes_to_num(rAUTH_NT, 4);
}
// free eventually allocated BigBuf memory but keep Emulator Memory
BigBuf_free_keep_EM();
MifareSimInit(flags, datain, &responses, &cuid, &uid_len);
// We need to listen to the high-frequency, peak-detected path.
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
// clear trace
clear_trace();
set_tracing(true);
ResetSspClk();
bool finished = false;
bool button_pushed = BUTTON_PRESS();
int cardSTATE = MFEMUL_NOFIELD;
while (!button_pushed && !finished && !usb_poll_validate_length()) {
WDT_HIT();
// find reader field
if (cardSTATE == MFEMUL_NOFIELD) {
int vHf = (MAX_ADC_HF_VOLTAGE_LOW * AvgAdc(ADC_CHAN_HF_LOW)) >> 10;
if (vHf > MF_MINFIELDV) {
LED_A_ON();
cardSTATE_TO_IDLE();
}
button_pushed = BUTTON_PRESS();
continue;
}
//Now, get data
int res = EmGetCmd(receivedCmd, &receivedCmd_len, receivedCmd_par);
if (res == 2) { //Field is off!
LEDsoff();
cardSTATE = MFEMUL_NOFIELD;
continue;
} else if (res == 1) { // button pressed
button_pushed = true;
break;
}
// WUPA in HALTED state or REQA or WUPA in any other state
if (receivedCmd_len == 1 && ((receivedCmd[0] == ISO14443A_CMD_REQA && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == ISO14443A_CMD_WUPA)) {
EmSendPrecompiledCmd(&responses[ATQA]);
// init crypto block
crypto1_destroy(pcs);
cardAUTHKEY = AUTHKEYNONE;
if (flags & FLAG_RANDOM_NONCE) {
nonce = prand();
}
LED_B_OFF();
LED_C_OFF();
cardSTATE = MFEMUL_SELECT1;
continue;
}
switch (cardSTATE) {
case MFEMUL_NOFIELD:
case MFEMUL_HALTED:
case MFEMUL_IDLE:{
break;
}
case MFEMUL_SELECT1:{
// select all - 0x93 0x20
if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x20)) {
if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL1 received");
EmSendPrecompiledCmd(&responses[UIDBCC1]);
break;
}
// select card - 0x93 0x70 ...
if (receivedCmd_len == 9 &&
(receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], responses[UIDBCC1].response, 4) == 0)) {
if (MF_DBGLEVEL >= 4) Dbprintf("SELECT CL1 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]);
if (uid_len == 4) {
EmSendPrecompiledCmd(&responses[SAKfinal]);
LED_B_ON();
cardSTATE = MFEMUL_WORK;
break;
} else if (uid_len == 7) {
EmSendPrecompiledCmd(&responses[SAK1]);
cardSTATE = MFEMUL_SELECT2;
break;
}
}
cardSTATE_TO_IDLE();
break;
}
case MFEMUL_SELECT2:{
// select all cl2 - 0x95 0x20
if (receivedCmd_len == 2 && (receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x20)) {
if (MF_DBGLEVEL >= 4) Dbprintf("SELECT ALL CL2 received");
EmSendPrecompiledCmd(&responses[UIDBCC2]);
break;
}
// select cl2 card - 0x95 0x70 xxxxxxxxxxxx
if (receivedCmd_len == 9 &&
(receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], responses[UIDBCC2].response, 4) == 0)) {
if (uid_len == 7) {
if (MF_DBGLEVEL >= 4) Dbprintf("SELECT CL2 %02x%02x%02x%02x received",receivedCmd[2],receivedCmd[3],receivedCmd[4],receivedCmd[5]);
EmSendPrecompiledCmd(&responses[SAKfinal]);
LED_B_ON();
cardSTATE = MFEMUL_WORK;
break;
}
}
cardSTATE_TO_IDLE();
break;
}
case MFEMUL_WORK:{
if (receivedCmd_len != 4) { // all commands must have exactly 4 bytes
break;
}
bool encrypted_data = (cardAUTHKEY != AUTHKEYNONE) ;
if (encrypted_data) {
// decrypt seqence
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec);
} else {
memcpy(receivedCmd_dec, receivedCmd, receivedCmd_len);
}
if (!HasValidCRC(receivedCmd_dec, receivedCmd_len)) { // all commands must have a valid CRC
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
break;
}
if (receivedCmd_dec[0] == MIFARE_AUTH_KEYA || receivedCmd_dec[0] == MIFARE_AUTH_KEYB) {
// if authenticating to a block that shouldn't exist - as long as we are not doing the reader attack
if (receivedCmd_dec[1] >= 16 * 4 && !(flags & FLAG_NR_AR_ATTACK)) {
//is this the correct response to an auth on a out of range block? marshmellow
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]);
break;
}
cardAUTHSC = receivedCmd_dec[1] / 4; // received block num
cardAUTHKEY = receivedCmd_dec[0] & 0x01;
crypto1_destroy(pcs);//Added by martin
crypto1_create(pcs, emlGetKey(cardAUTHSC, cardAUTHKEY));
if (!encrypted_data) { // first authentication
if (MF_DBGLEVEL >= 4) Dbprintf("Reader authenticating for block %d (0x%02x) with key %d",receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY);
crypto1_word(pcs, cuid ^ nonce, 0);//Update crypto state
num_to_bytes(nonce, 4, rAUTH_AT); // Send nonce
} else { // nested authentication
if (MF_DBGLEVEL >= 4) Dbprintf("Reader doing nested authentication for block %d (0x%02x) with key %d", receivedCmd_dec[1], receivedCmd_dec[1], cardAUTHKEY);
ans = nonce ^ crypto1_word(pcs, cuid ^ nonce, 0);
num_to_bytes(ans, 4, rAUTH_AT);
}
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
cardSTATE = MFEMUL_AUTH1;
break;
}
if (!encrypted_data) { // all other commands must be encrypted (authenticated)
break;
}
if(receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK
|| receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK
|| receivedCmd_dec[0] == MIFARE_CMD_INC
|| receivedCmd_dec[0] == MIFARE_CMD_DEC
|| receivedCmd_dec[0] == MIFARE_CMD_RESTORE
|| receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) {
if (receivedCmd_dec[1] >= 16 * 4) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on out of range block: %d (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]);
break;
}
if (receivedCmd_dec[1] / 4 != cardAUTHSC) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate (0x%02x) on block (0x%02x) not authenticated for (0x%02x), nacking",receivedCmd_dec[0],receivedCmd_dec[1],cardAUTHSC);
break;
}
}
if (receivedCmd_dec[0] == ISO14443A_CMD_READBLOCK) {
uint8_t blockNo = receivedCmd_dec[1];
if (MF_DBGLEVEL >= 4) {
Dbprintf("Reader reading block %d (0x%02x)", blockNo, blockNo);
}
emlGetMem(response, blockNo, 1);
if (IsSectorTrailer(blockNo)) {
memset(response, 0x00, 6); // keyA can never be read
if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_KEYB_READ)) {
memset(response+10, 0x00, 6); // keyB cannot be read
}
if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_AC_READ)) {
memset(response+6, 0x00, 4); // AC bits cannot be read
}
} else {
if (!IsAccessAllowed(blockNo, cardAUTHKEY, AC_DATA_READ)) {
memset(response, 0x00, 16); // datablock cannot be read
}
}
AppendCrc14443a(response, 16);
mf_crypto1_encrypt(pcs, response, 18, response_par);
EmSendCmdPar(response, 18, response_par);
numReads++;
if(exitAfterNReads > 0 && numReads == exitAfterNReads) {
Dbprintf("%d reads done, exiting", numReads);
finished = true;
}
break;
}
if (receivedCmd_dec[0] == ISO14443A_CMD_WRITEBLOCK) {
uint8_t blockNo = receivedCmd_dec[1];
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0xA0 write block %d (%02x)", blockNo, blockNo);
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
cardWRBL = blockNo;
cardSTATE = MFEMUL_WRITEBL2;
break;
}
if (receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE) {
uint8_t blockNo = receivedCmd_dec[1];
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo);
if (emlCheckValBl(blockNo)) {
if (MF_DBGLEVEL >= 2) Dbprintf("Reader tried to operate on block, but emlCheckValBl failed, nacking");
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
break;
}
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
cardWRBL = blockNo;
if (receivedCmd_dec[0] == MIFARE_CMD_INC)
cardSTATE = MFEMUL_INTREG_INC;
if (receivedCmd_dec[0] == MIFARE_CMD_DEC)
cardSTATE = MFEMUL_INTREG_DEC;
if (receivedCmd_dec[0] == MIFARE_CMD_RESTORE)
cardSTATE = MFEMUL_INTREG_REST;
break;
}
if (receivedCmd_dec[0] == MIFARE_CMD_TRANSFER) {
uint8_t blockNo = receivedCmd_dec[1];
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd_dec[0], blockNo, blockNo);
if (emlSetValBl(cardINTREG, cardINTBLOCK, receivedCmd_dec[1]))
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
else
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
break;
}
// halt
if (receivedCmd_dec[0] == ISO14443A_CMD_HALT && receivedCmd_dec[1] == 0x00) {
if (MF_DBGLEVEL >= 4) Dbprintf("--> HALTED.");
LED_B_OFF();
LED_C_OFF();
cardSTATE = MFEMUL_HALTED;
break;
}
// command not allowed
if (MF_DBGLEVEL >= 4) Dbprintf("Received command not allowed, nacking");
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
break;
}
case MFEMUL_AUTH1:{
if (receivedCmd_len != 8) {
cardSTATE_TO_IDLE();
break;
}
uint32_t nr = bytes_to_num(receivedCmd, 4);
uint32_t ar = bytes_to_num(&receivedCmd[4], 4);
// Collect AR/NR per keytype & sector
if(flags & FLAG_NR_AR_ATTACK) {
for (uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
if ( ar_nr_collected[i+mM]==0 || ((cardAUTHSC == ar_nr_resp[i+mM].sector) && (cardAUTHKEY == ar_nr_resp[i+mM].keytype) && (ar_nr_collected[i+mM] > 0)) ) {
// if first auth for sector, or matches sector and keytype of previous auth
if (ar_nr_collected[i+mM] < 2) {
// if we haven't already collected 2 nonces for this sector
if (ar_nr_resp[ar_nr_collected[i+mM]].ar != ar) {
// Avoid duplicates... probably not necessary, ar should vary.
if (ar_nr_collected[i+mM]==0) {
// first nonce collect
ar_nr_resp[i+mM].cuid = cuid;
ar_nr_resp[i+mM].sector = cardAUTHSC;
ar_nr_resp[i+mM].keytype = cardAUTHKEY;
ar_nr_resp[i+mM].nonce = nonce;
ar_nr_resp[i+mM].nr = nr;
ar_nr_resp[i+mM].ar = ar;
nonce1_count++;
// add this nonce to first moebius nonce
ar_nr_resp[i+ATTACK_KEY_COUNT].cuid = cuid;
ar_nr_resp[i+ATTACK_KEY_COUNT].sector = cardAUTHSC;
ar_nr_resp[i+ATTACK_KEY_COUNT].keytype = cardAUTHKEY;
ar_nr_resp[i+ATTACK_KEY_COUNT].nonce = nonce;
ar_nr_resp[i+ATTACK_KEY_COUNT].nr = nr;
ar_nr_resp[i+ATTACK_KEY_COUNT].ar = ar;
ar_nr_collected[i+ATTACK_KEY_COUNT]++;
} else { // second nonce collect (std and moebius)
ar_nr_resp[i+mM].nonce2 = nonce;
ar_nr_resp[i+mM].nr2 = nr;
ar_nr_resp[i+mM].ar2 = ar;
if (!gettingMoebius) {
nonce2_count++;
// check if this was the last second nonce we need for std attack
if ( nonce2_count == nonce1_count ) {
// done collecting std test switch to moebius
// first finish incrementing last sample
ar_nr_collected[i+mM]++;
// switch to moebius collection
gettingMoebius = true;
mM = ATTACK_KEY_COUNT;
if (flags & FLAG_RANDOM_NONCE) {
nonce = prand();
} else {
nonce = nonce*7;
}
break;
}
} else {
moebius_n_count++;
// if we've collected all the nonces we need - finish.
if (nonce1_count == moebius_n_count) finished = true;
}
}
ar_nr_collected[i+mM]++;
}
}
// we found right spot for this nonce stop looking
break;
}
}
}
// --- crypto
crypto1_word(pcs, nr , 1);
cardRr = ar ^ crypto1_word(pcs, 0, 0);
// test if auth OK
if (cardRr != prng_successor(nonce, 64)){
if (MF_DBGLEVEL >= 2) Dbprintf("AUTH FAILED for sector %d with key %c. cardRr=%08x, succ=%08x",
cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B',
cardRr, prng_successor(nonce, 64));
// Shouldn't we respond anything here?
// Right now, we don't nack or anything, which causes the
// reader to do a WUPA after a while. /Martin
// -- which is the correct response. /piwi
cardAUTHKEY = AUTHKEYNONE; // not authenticated
cardSTATE_TO_IDLE();
break;
}
ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0);
num_to_bytes(ans, 4, rAUTH_AT);
EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT));
if (MF_DBGLEVEL >= 4) Dbprintf("AUTH COMPLETED for sector %d with key %c.", cardAUTHSC, cardAUTHKEY == AUTHKEYA ? 'A' : 'B');
LED_C_ON();
cardSTATE = MFEMUL_WORK;
break;
}
case MFEMUL_WRITEBL2:{
if (receivedCmd_len == 18) {
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, receivedCmd_dec);
if (HasValidCRC(receivedCmd_dec, receivedCmd_len)) {
if (IsSectorTrailer(cardWRBL)) {
emlGetMem(response, cardWRBL, 1);
if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYA_WRITE)) {
memcpy(receivedCmd_dec, response, 6); // don't change KeyA
}
if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_KEYB_WRITE)) {
memcpy(receivedCmd_dec+10, response+10, 6); // don't change KeyA
}
if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_AC_WRITE)) {
memcpy(receivedCmd_dec+6, response+6, 4); // don't change AC bits
}
} else {
if (!IsAccessAllowed(cardWRBL, cardAUTHKEY, AC_DATA_WRITE)) {
memcpy(receivedCmd_dec, response, 16); // don't change anything
}
}
emlSetMem(receivedCmd_dec, cardWRBL, 1);
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK)); // always ACK?
cardSTATE = MFEMUL_WORK;
break;
}
}
cardSTATE_TO_IDLE();
break;
}
case MFEMUL_INTREG_INC:{
if (receivedCmd_len == 6) {
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans);
if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
cardSTATE_TO_IDLE();
break;
}
cardINTREG = cardINTREG + ans;
}
cardSTATE = MFEMUL_WORK;
break;
}
case MFEMUL_INTREG_DEC:{
if (receivedCmd_len == 6) {
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans);
if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
cardSTATE_TO_IDLE();
break;
}
}
cardINTREG = cardINTREG - ans;
cardSTATE = MFEMUL_WORK;
break;
}
case MFEMUL_INTREG_REST:{
mf_crypto1_decryptEx(pcs, receivedCmd, receivedCmd_len, (uint8_t*)&ans);
if (emlGetValBl(&cardINTREG, &cardINTBLOCK, cardWRBL)) {
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_NACK_NA));
cardSTATE_TO_IDLE();
break;
}
cardSTATE = MFEMUL_WORK;
break;
}
}
button_pushed = BUTTON_PRESS();
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
if(flags & FLAG_NR_AR_ATTACK && MF_DBGLEVEL >= 1) {
for ( uint8_t i = 0; i < ATTACK_KEY_COUNT; i++) {
if (ar_nr_collected[i] == 2) {
Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i<ATTACK_KEY_COUNT/2) ? "keyA" : "keyB", ar_nr_resp[i].sector);
Dbprintf("../tools/mfkey/mfkey32 %08x %08x %08x %08x %08x %08x",
ar_nr_resp[i].cuid, //UID
ar_nr_resp[i].nonce, //NT
ar_nr_resp[i].nr, //NR1
ar_nr_resp[i].ar, //AR1
ar_nr_resp[i].nr2, //NR2
ar_nr_resp[i].ar2 //AR2
);
}
}
for ( uint8_t i = ATTACK_KEY_COUNT; i < ATTACK_KEY_COUNT*2; i++) {
if (ar_nr_collected[i] == 2) {
Dbprintf("Collected two pairs of AR/NR which can be used to extract %s from reader for sector %d:", (i<ATTACK_KEY_COUNT/2) ? "keyA" : "keyB", ar_nr_resp[i].sector);
Dbprintf("../tools/mfkey/mfkey32v2 %08x %08x %08x %08x %08x %08x %08x",
ar_nr_resp[i].cuid, //UID
ar_nr_resp[i].nonce, //NT
ar_nr_resp[i].nr, //NR1
ar_nr_resp[i].ar, //AR1
ar_nr_resp[i].nonce2,//NT2
ar_nr_resp[i].nr2, //NR2
ar_nr_resp[i].ar2 //AR2
);
}
}
}
if (MF_DBGLEVEL >= 1) Dbprintf("Emulator stopped. Tracing: %d trace length: %d ", get_tracing(), BigBuf_get_traceLen());
if(flags & FLAG_INTERACTIVE) { // Interactive mode flag, means we need to send ACK
//Send the collected ar_nr in the response
cmd_send(CMD_ACK,CMD_SIMULATE_MIFARE_CARD,button_pushed,0,&ar_nr_resp,sizeof(ar_nr_resp));
}
}

View file

@ -1,23 +1,20 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// Merlok - June 2011, 2012
// Gerhard de Koning Gans - May 2008
// Hagen Fritsch - June 2010
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Data utilities
// Mifare Classic Card Simulation
//-----------------------------------------------------------------------------
#ifndef DATA_H__
#define DATA_H__
#ifndef __MIFARESIM_H
#define __MIFARESIM_H
#include <stdint.h>
#define FILE_PATH_SIZE 1000
extern uint8_t* sample_buf;
#define arraylen(x) (sizeof(x)/sizeof((x)[0]))
void GetFromBigBuf(uint8_t *dest, int bytes, int start_index);
extern void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain);
#endif

View file

@ -35,7 +35,7 @@ bool MfSniffInit(void){
sniffSAK = 0;
sniffUIDType = SNF_UID_4;
return FALSE;
return false;
}
bool MfSniffEnd(void){
@ -43,7 +43,7 @@ bool MfSniffEnd(void){
cmd_send(CMD_ACK,0,0,0,0,0);
LED_B_OFF();
return FALSE;
return false;
}
bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, uint16_t bitCnt, bool reader) {
@ -59,32 +59,27 @@ bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, ui
memset(sniffUID, 0x00, 8);
memset(sniffATQA, 0x00, 2);
sniffSAK = 0;
sniffState = SNF_WUPREQ;
sniffState = SNF_ATQA;
if (data[0] == 0x40)
sniffState = SNF_MAGIC_WUPC2;
}
break;
}
case SNF_WUPREQ:{
case SNF_MAGIC_WUPC2:
if ((len == 1) && (reader) && (data[0] == 0x43) ) {
sniffState = SNF_CARD_IDLE;
}
break;
case SNF_ATQA:{
if ((!reader) && (len == 2)) { // ATQA from tag
memcpy(sniffATQA, data, 2);
sniffState = SNF_ATQA;
}
break;
}
case SNF_ATQA:{
if ((reader) && (len == 2) && (data[0] == 0x93) && (data[1] == 0x20)) { // Select ALL from reader
sniffState = SNF_ANTICOL1;
}
break;
}
case SNF_ANTICOL1:{
if ((!reader) && (len == 5) && ((data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4])) { // UID from tag (CL1)
memcpy(sniffUID + 3, data, 4);
sniffState = SNF_UID1;
}
break;
}
case SNF_UID1:{
if ((reader) && (len == 9) && (data[0] == 0x93) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { // Select 4 Byte UID from reader
memcpy(sniffUID + 3, &data[2], 4);
sniffState = SNF_SAK;
}
break;
@ -92,25 +87,19 @@ bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, ui
case SNF_SAK:{
if ((!reader) && (len == 3) && (CheckCrc14443(CRC_14443_A, data, 3))) { // SAK from card?
sniffSAK = data[0];
if (sniffUID[3] == 0x88) { // CL2 UID part to be expected
sniffState = SNF_ANTICOL2;
if ((sniffUID[3] == 0x88) && (sniffUIDType == SNF_UID_4)) { // CL2 UID part to be expected
sniffUIDType = SNF_UID_7;
memcpy(sniffUID, sniffUID + 4, 3);
sniffState = SNF_UID2;
} else { // select completed
sniffState = SNF_CARD_IDLE;
}
}
break;
}
case SNF_ANTICOL2:{
if ((!reader) && (len == 5) && ((data[0] ^ data[1] ^ data[2] ^ data[3]) == data[4])) { // CL2 UID
memcpy(sniffUID, sniffUID+4, 3);
memcpy(sniffUID+3, data, 4);
sniffUIDType = SNF_UID_7;
sniffState = SNF_UID2;
}
break;
}
case SNF_UID2:{
if ((reader) && (len == 9) && (data[0] == 0x95) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) { // Select 2nd part of 7 Byte UID
if ((reader) && (len == 9) && (data[0] == 0x95) && (data[1] == 0x70) && (CheckCrc14443(CRC_14443_A, data, 9))) {
memcpy(sniffUID + 3, &data[2], 4);
sniffState = SNF_SAK;
}
break;
@ -123,17 +112,11 @@ bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, ui
sniffBuf[11] = sniffSAK;
sniffBuf[12] = 0xFF;
sniffBuf[13] = 0xFF;
LogTrace(sniffBuf, 14, 0, 0, NULL, TRUE);
LogTrace(sniffBuf, 14, 0, 0, NULL, true);
sniffState = SNF_CARD_CMD;
} // intentionally no break;
case SNF_CARD_CMD:{
LogTrace(data, len, 0, 0, NULL, TRUE);
sniffState = SNF_CARD_RESP;
timerData = GetTickCount();
break;
}
case SNF_CARD_RESP:{
LogTrace(data, len, 0, 0, NULL, FALSE);
sniffState = SNF_CARD_CMD;
LogTrace(data, len, 0, 0, parity, reader);
timerData = GetTickCount();
break;
}
@ -144,14 +127,14 @@ bool RAMFUNC MfSniffLogic(const uint8_t *data, uint16_t len, uint8_t *parity, ui
}
return FALSE;
return false;
}
bool RAMFUNC MfSniffSend(uint16_t maxTimeoutMs) {
if (BigBuf_get_traceLen() && (GetTickCount() > timerData + maxTimeoutMs)) {
return intMfSniffSend();
}
return FALSE;
return false;
}
// internal sending function. not a RAMFUNC.
@ -179,5 +162,5 @@ bool intMfSniffSend() {
clear_trace();
return TRUE;
return true;
}

View file

@ -27,6 +27,7 @@
#define SNF_CARD_IDLE 9
#define SNF_CARD_CMD 10
#define SNF_CARD_RESP 11
#define SNF_MAGIC_WUPC2 12
#define SNF_UID_4 0
#define SNF_UID_7 0

View file

@ -9,13 +9,15 @@
// Work with mifare cards.
//-----------------------------------------------------------------------------
#include <string.h>
#include "mifareutil.h"
#include <string.h>
#include <stdbool.h>
#include "proxmark3.h"
#include "apps.h"
#include "util.h"
#include "parity.h"
#include "iso14443crc.h"
#include "iso14443a.h"
#include "crapto1/crapto1.h"
@ -24,23 +26,27 @@
int MF_DBGLEVEL = MF_DBG_ALL;
// crypto1 helpers
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len){
void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out){
uint8_t bt = 0;
int i;
if (len != 1) {
for (i = 0; i < len; i++)
data[i] = crypto1_byte(pcs, 0x00, 0) ^ data[i];
data_out[i] = crypto1_byte(pcs, 0x00, 0) ^ data_in[i];
} else {
bt = 0;
for (i = 0; i < 4; i++)
bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data[0], i)) << i;
bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(data_in[0], i)) << i;
data[0] = bt;
data_out[0] = bt;
}
return;
}
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len){
mf_crypto1_decryptEx(pcs, data, len, data);
}
void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par) {
uint8_t bt = 0;
int i;
@ -399,29 +405,46 @@ int mifare_ultra_auth(uint8_t *keybytes){
return 1;
}
#define MFU_MAX_RETRIES 5
int mifare_ultra_readblock(uint8_t blockNo, uint8_t *blockData)
{
uint16_t len;
uint8_t bt[2];
uint8_t receivedAnswer[MAX_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_PARITY_SIZE];
uint8_t retries;
int result = 0;
for (retries = 0; retries < MFU_MAX_RETRIES; retries++) {
len = mifare_sendcmd_short(NULL, 1, 0x30, blockNo, receivedAnswer, receivedAnswerPar, NULL);
if (len == 1) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: %02x", receivedAnswer[0]);
return 1;
result = 1;
continue;
}
if (len != 18) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd Error: card timeout. len: %x", len);
return 2;
result = 2;
continue;
}
memcpy(bt, receivedAnswer + 16, 2);
AppendCrc14443a(receivedAnswer, 16);
if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) {
if (MF_DBGLEVEL >= MF_DBG_ERROR) Dbprintf("Cmd CRC response error.");
return 3;
result = 3;
continue;
}
// No errors encountered; don't retry
result = 0;
break;
}
if (result != 0) {
Dbprintf("Cmd Error: too many retries; read failed");
return result;
}
memcpy(blockData, receivedAnswer, 14);
@ -581,6 +604,19 @@ uint8_t FirstBlockOfSector(uint8_t sectorNo)
}
uint8_t SectorTrailer(uint8_t blockNo)
{
if (blockNo < 32*4) {
return (blockNo | 0x03);
} else {
return (blockNo | 0x0f);
}
}
bool IsSectorTrailer(uint8_t blockNo)
{
return (blockNo == SectorTrailer(blockNo));
}
// work with emulator memory
void emlSetMem(uint8_t *data, int blockNum, int blocksCount) {
@ -764,3 +800,125 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){
}
return 1;
}
//-----------------------------------------------------------------------------
// MIFARE check keys
//
//-----------------------------------------------------------------------------
// one key check
int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uint64_t ui64Key, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel) {
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
// Iceman: use piwi's faster nonce collecting part in hardnested.
if (*cascade_levels == 0) { // 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 (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card");
return 1;
}
switch (card_info.uidlen) {
case 4 : *cascade_levels = 1; break;
case 7 : *cascade_levels = 2; break;
case 10: *cascade_levels = 3; break;
default: break;
}
} else { // no need for anticollision. We can directly select the card
if(!iso14443a_select_card(uid, NULL, NULL, false, *cascade_levels, true)) {
if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card (UID) lvl=%d", *cascade_levels);
return 1;
}
}
if(mifare_classic_auth(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
// SpinDelayUs(AUTHENTICATION_TIMEOUT); // it not needs because mifare_classic_auth have timeout from iso14a_set_timeout()
return 2;
} else {
/* // let it be here. it like halt command, but maybe it will work in some strange cases
uint8_t dummy_answer = 0;
ReaderTransmit(&dummy_answer, 1, NULL);
int timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
// wait for the card to become ready again
while(GetCountSspClk() < timeout) {};
*/
// it needs after success authentication
mifare_classic_halt(pcs, *cuid);
}
return 0;
}
// multi key check
int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel) {
uint8_t uid[10];
uint32_t cuid = 0;
uint8_t cascade_levels = 0;
uint64_t ui64Key = 0;
int retryCount = 0;
for (uint8_t i = 0; i < keyCount; i++) {
// Allow button press / usb cmd to interrupt device
if (BUTTON_PRESS() && !usb_poll_validate_length()) {
Dbprintf("ChkKeys: Cancel operation. Exit...");
return -2;
}
ui64Key = bytes_to_num(keys + i * 6, 6);
int res = MifareChkBlockKey(uid, &cuid, &cascade_levels, ui64Key, blockNo, keyType, debugLevel);
// can't select
if (res == 1) {
retryCount++;
if (retryCount >= 5) {
Dbprintf("ChkKeys: block=%d key=%d. Can't select. Exit...", blockNo, keyType);
return -1;
}
--i; // try the same key once again
SpinDelay(20);
// Dbprintf("ChkKeys: block=%d key=%d. Try the same key once again...", blockNo, keyType);
continue;
}
// can't authenticate
if (res == 2) {
retryCount = 0;
continue; // can't auth. wrong key.
}
return i + 1;
}
return 0;
}
// multisector multikey check
int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint8_t debugLevel, TKeyIndex *keyIndex) {
int res = 0;
// int clk = GetCountSspClk();
for(int sc = 0; sc < SectorCount; sc++){
WDT_HIT();
int keyAB = keyType;
do {
res = MifareChkBlockKeys(keys, keyCount, FirstBlockOfSector(sc), keyAB & 0x01, debugLevel);
if (res < 0){
return res;
}
if (res > 0){
(*keyIndex)[keyAB & 0x01][sc] = res;
}
} while(--keyAB > 0);
}
// Dbprintf("%d %d", GetCountSspClk() - clk, (GetCountSspClk() - clk)/(SectorCount*keyCount*(keyType==2?2:1)));
return 0;
}

View file

@ -12,7 +12,11 @@
#ifndef __MIFAREUTIL_H
#define __MIFAREUTIL_H
#include <stdint.h>
#include <stdbool.h>
#include "crapto1/crapto1.h"
#include "usb_cdc.h"
// mifare authentication
#define CRYPT_NONE 0
@ -38,23 +42,6 @@
extern int MF_DBGLEVEL;
//mifare emulator states
#define MFEMUL_NOFIELD 0
#define MFEMUL_IDLE 1
#define MFEMUL_SELECT1 2
#define MFEMUL_SELECT2 3
#define MFEMUL_SELECT3 4
#define MFEMUL_AUTH1 5
#define MFEMUL_AUTH2 6
#define MFEMUL_WORK 7
#define MFEMUL_WRITEBL2 8
#define MFEMUL_INTREG_INC 9
#define MFEMUL_INTREG_DEC 10
#define MFEMUL_INTREG_REST 11
#define MFEMUL_HALTED 12
#define cardSTATE_TO_IDLE() cardSTATE = MFEMUL_IDLE; LED_B_OFF(); LED_C_OFF();
//functions
int mifare_sendcmd(uint8_t cmd, uint8_t *data, uint8_t data_size, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
int mifare_sendcmd_short(struct Crypto1State *pcs, uint8_t crypted, uint8_t cmd, uint8_t data, uint8_t* answer, uint8_t *answer_parity, uint32_t *timing);
@ -82,12 +69,15 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData);
// crypto functions
void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *receivedCmd, int len);
void mf_crypto1_decryptEx(struct Crypto1State *pcs, uint8_t *data_in, int len, uint8_t *data_out);
void mf_crypto1_encrypt(struct Crypto1State *pcs, uint8_t *data, uint16_t len, uint8_t *par);
uint8_t mf_crypto1_encrypt4bit(struct Crypto1State *pcs, uint8_t data);
// Mifare memory structure
uint8_t NumBlocksPerSector(uint8_t sectorNo);
uint8_t FirstBlockOfSector(uint8_t sectorNo);
bool IsSectorTrailer(uint8_t blockNo);
uint8_t SectorTrailer(uint8_t blockNo);
// emulator functions
void emlClearMem(void);
@ -99,4 +89,10 @@ int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum);
int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum);
int emlCheckValBl(int blockNum);
// mifare check keys
typedef uint8_t TKeyIndex[2][40];
int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uint64_t ui64Key, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel);
int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel);
int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint8_t debugLevel, TKeyIndex *keyIndex);
#endif

View file

@ -22,7 +22,7 @@
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
* by the Free Software Foundation, or, at your option, any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of

View file

@ -1,3 +1,40 @@
/*****************************************************************************
* WARNING
*
* THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
*
* USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
* PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
* AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
*
* THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
*
*****************************************************************************
*
* This file is part of loclass. It is a reconstructon of the cipher engine
* used in iClass, and RFID techology.
*
* The implementation is based on the work performed by
* Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
* Milosch Meriac in the paper "Dismantling IClass".
*
* Copyright (C) 2014 Martin Holst Swende
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation, or, at your option, any later version.
*
* This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with loclass. If not, see <http://www.gnu.org/licenses/>.
*
*
****************************************************************************/
#ifndef OPTIMIZED_CIPHER_H
#define OPTIMIZED_CIPHER_H
#include <stdint.h>

View file

@ -175,6 +175,7 @@ reswitch: switch (ch = (u_char)*fmt++) {
padc = '0';
goto reswitch;
}
// intentionally fall through to next case
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
for (n = 0;; ++fmt) {

View file

@ -81,11 +81,6 @@ void lsl (uint8_t *data, size_t len) {
data[len - 1] <<= 1;
}
int32_t le24toh (uint8_t data[3])
{
return (data[2] << 16) | (data[1] << 8) | data[0];
}
void LEDsoff()
{
LED_A_OFF();
@ -292,6 +287,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers
strncat(dst, "\n", len - strlen(dst) - 1);
}
// -------------------------------------------------------------------------
// timer lib
// -------------------------------------------------------------------------
@ -312,6 +308,7 @@ void StartTickCount()
// note: worst case precision is approx 2.5%
}
/*
* Get the current count.
*/
@ -319,6 +316,7 @@ uint32_t RAMFUNC GetTickCount(){
return AT91C_BASE_RTTC->RTTC_RTVR;// was * 2;
}
// -------------------------------------------------------------------------
// microseconds timer
// -------------------------------------------------------------------------
@ -344,10 +342,12 @@ void StartCountUS()
AT91C_BASE_TCB->TCB_BCR = 1;
}
uint32_t RAMFUNC GetCountUS(){
return (AT91C_BASE_TC1->TC_CV * 0x8000) + ((AT91C_BASE_TC0->TC_CV * 2) / 3); //was /15) * 10);
}
static uint32_t GlobalUsCounter = 0;
uint32_t RAMFUNC GetDeltaCountUS(){
@ -373,13 +373,13 @@ void StartCountSspClk()
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_TIMER_DIV1_CLOCK // TC1 Clock = MCK(48MHz)/2 = 24MHz
| AT91C_TC_CPCSTOP // Stop clock on RC compare
| AT91C_TC_EEVTEDG_RISING // Trigger on rising edge of Event
| AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16)
| AT91C_TC_EEVT_TIOB // Event-Source: TIOB1 (= ssp_clk from FPGA = 13,56MHz/16 ... 13,56MHz/4)
| AT91C_TC_ENETRG // Enable external trigger event
| AT91C_TC_WAVESEL_UP // Upmode without automatic trigger on RC compare
| AT91C_TC_WAVE // Waveform Mode
| AT91C_TC_AEEVT_SET // Set TIOA1 on external event
| AT91C_TC_ACPC_CLEAR; // Clear TIOA1 on RC Compare
AT91C_BASE_TC1->TC_RC = 0x04; // RC Compare value = 0x04
AT91C_BASE_TC1->TC_RC = 0x02; // RC Compare value = 0x02
// use TC0 to count TIOA1 pulses
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // disable TC0
@ -402,7 +402,7 @@ void StartCountSspClk()
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN; // enable TC2
//
// synchronize the counter with the ssp_frame signal. Note: FPGA must be in any iso14446 mode, otherwise the frame signal would not be present
// synchronize the counter with the ssp_frame signal. Note: FPGA must be in a FPGA mode with SSC transfer, otherwise SSC_FRAME and SSC_CLK signals would not be present
//
while(!(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME)); // wait for ssp_frame to go high (start of frame)
while(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_FRAME); // wait for ssp_frame to be low
@ -416,8 +416,11 @@ void StartCountSspClk()
// (just started with the transfer of the 4th Bit).
// The high word of the counter (TC2) will not reset until the low word (TC0) overflows. Therefore need to wait quite some time before
// we can use the counter.
while (AT91C_BASE_TC0->TC_CV < 0xFFF0);
while (AT91C_BASE_TC0->TC_CV < 0xFFFF);
// Note: needs one more SSP_CLK cycle (1.18 us) until TC2 resets. Don't call GetCountSspClk() that soon.
}
void ResetSspClk(void) {
//enable clock of timer and software trigger
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
@ -425,78 +428,112 @@ void ResetSspClk(void) {
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
while (AT91C_BASE_TC2->TC_CV > 0);
}
uint32_t RAMFUNC GetCountSspClk(){
uint32_t tmp_count;
tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
if ((tmp_count & 0x0000ffff) == 0) { //small chance that we may have missed an increment in TC2
return (AT91C_BASE_TC2->TC_CV << 16);
}
else {
return tmp_count;
}
uint32_t GetCountSspClk(){
uint32_t hi, lo;
do {
hi = AT91C_BASE_TC2->TC_CV;
lo = AT91C_BASE_TC0->TC_CV;
} while(hi != AT91C_BASE_TC2->TC_CV);
return (hi << 16) | lo;
}
// -------------------------------------------------------------------------
// Timer for bitbanging, or LF stuff when you need a very precis timer
// 1us = 1.5ticks
// -------------------------------------------------------------------------
void StartTicks(void){
// initialization of the timer
// tc1 is higher 0xFFFF0000
// tc0 is lower 0x0000FFFF
AT91C_BASE_PMC->PMC_PCER |= (1 << AT91C_ID_TC0) | (1 << AT91C_ID_TC1);
AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE;
// disable TC0 and TC1 for re-configuration
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
// first configure TC1 (higher, 0xFFFF0000) 16 bit counter
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // just connect to TIOA0 from TC0
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG; // re-enable timer and wait for TC0
// second configure TC0 (lower, 0x0000FFFF) 16 bit counter
AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | // MCK(48MHz) / 32
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO | AT91C_TC_ACPA_CLEAR |
AT91C_TC_ACPC_SET | AT91C_TC_ASWTRG_SET;
AT91C_BASE_TC0->TC_RA = 1;
AT91C_BASE_TC0->TC_RC = 0;
AT91C_TC_WAVE | AT91C_TC_WAVESEL_UP_AUTO |
AT91C_TC_ACPA_CLEAR | // RA comperator clears TIOA (carry bit)
AT91C_TC_ACPC_SET | // RC comperator sets TIOA (carry bit)
AT91C_TC_ASWTRG_SET; // SWTriger sets TIOA (carry bit)
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
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS; // timer disable
AT91C_BASE_TC1->TC_CMR = AT91C_TC_CLKS_XC1; // from TC0
// synchronized startup procedure
while (AT91C_BASE_TC0->TC_CV > 0); // wait until TC0 returned to zero
while (AT91C_BASE_TC0->TC_CV < 2); // and has started (TC_CV > TC_RA, now TC1 is cleared)
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TCB->TCB_BCR = 1;
// wait until timer becomes zero.
while (AT91C_BASE_TC1->TC_CV > 0);
// return to zero
AT91C_BASE_TC1->TC_CCR = AT91C_TC_SWTRG;
AT91C_BASE_TC0->TC_CCR = AT91C_TC_SWTRG;
while (AT91C_BASE_TC0->TC_CV > 0);
}
uint32_t GetTicks(void) {
uint32_t hi, lo;
do {
hi = AT91C_BASE_TC1->TC_CV;
lo = AT91C_BASE_TC0->TC_CV;
} while(hi != AT91C_BASE_TC1->TC_CV);
return (hi << 16) | lo;
}
// Wait - Spindelay in ticks.
// if called with a high number, this will trigger the WDT...
void WaitTicks(uint32_t ticks){
if ( ticks == 0 ) return;
ticks += GET_TICKS;
while (GET_TICKS < ticks);
ticks += GetTicks();
while (GetTicks() < ticks);
}
// Wait / Spindelay in us (microseconds)
// 1us = 1.5ticks.
void WaitUS(uint16_t us){
if ( us == 0 ) return;
WaitTicks( (uint32_t)(us * 1.5) );
WaitTicks( (uint32_t)us * 3 / 2 ) ;
}
void WaitMS(uint16_t ms){
if (ms == 0) return;
WaitTicks( (uint32_t)(ms * 1500) );
WaitTicks( (uint32_t)ms * 1500 );
}
// Starts Clock and waits until its reset
void ResetTicks(void){
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
while (AT91C_BASE_TC1->TC_CV > 0);
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
while (AT91C_BASE_TC0->TC_CV > 0);
}
void ResetTimer(AT91PS_TC timer){
timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
while(timer->TC_CV > 0) ;
}
// stop clock
void StopTicks(void){
AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS;
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKDIS;
}
static uint64_t next_random = 1;
/* Generates a (non-cryptographically secure) 32-bit random number.
@ -512,4 +549,3 @@ uint32_t prand() {
next_random = next_random * 6364136223846793005 + 1;
return (uint32_t)(next_random >> 32) % 0xffffffff;
}

View file

@ -34,7 +34,6 @@ void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len);
void rol(uint8_t *data, const size_t len);
void lsl (uint8_t *data, size_t len);
int32_t le24toh (uint8_t data[3]);
void LED(int led, int ms);
void LEDsoff();
@ -44,7 +43,7 @@ void FormatVersionInformation(char *dst, int len, const char *prefix, void *vers
//iceman's ticks.h
#ifndef GET_TICKS
# define GET_TICKS (uint32_t)((AT91C_BASE_TC1->TC_CV << 16) | AT91C_BASE_TC0->TC_CV)
# define GET_TICKS GetTicks()
#endif
void SpinDelay(int ms);
@ -62,6 +61,7 @@ void ResetSspClk(void);
uint32_t RAMFUNC GetCountSspClk();
extern void StartTicks(void);
extern uint32_t GetTicks(void);
extern void WaitTicks(uint32_t ticks);
extern void WaitUS(uint16_t us);
extern void WaitMS(uint16_t ms);

View file

@ -10,6 +10,7 @@
ARMSRC =
THUMBSRC = cmd.c usb_cdc.c bootrom.c
ASMSRC = ram-reset.s flash-reset.s
VERSIONSRC = version.c
## There is a strange bug with the linker: Sometimes it will not emit the glue to call
## BootROM from ARM mode. The symbol is emitted, but the section will be filled with
@ -21,6 +22,11 @@ ASMSRC = ram-reset.s flash-reset.s
# stdint.h provided locally until GCC 4.5 becomes C99 compliant
APP_CFLAGS = -I.
# version.c should be remade on every compilation
.PHONY: version.c
version.c: default_version.c
perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
include ../common/Makefile.common

View file

@ -12,16 +12,28 @@ TARFLAGS = -C .. --ignore-failed-read -rvf
RM = rm -f
MV = mv
#COMMON_FLAGS = -m32
ENV_LDFLAGS := $(LDFLAGS)
ENV_CFLAGS := $(CFLAGS)
VPATH = ../common ../zlib ../uart
OBJDIR = obj
LDLIBS = -L/opt/local/lib -L/usr/local/lib -lreadline -lpthread -lm
LUALIB = ../liblua/liblua.a
LDFLAGS = $(COMMON_FLAGS)
CFLAGS = -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall $(COMMON_FLAGS) -g -O3
JANSSONLIBPATH = ./jansson
JANSSONLIB = $(JANSSONLIBPATH)/libjansson.a
LDFLAGS = $(ENV_LDFLAGS)
CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../common/polarssl -I../zlib -I../uart -I/opt/local/include -I../liblua -I$(JANSSONLIBPATH) -Wall -g -O3
CXXFLAGS = -I../include -Wall -O3
APP_CFLAGS =
include ../common/Makefile_Enabled_Options.common
CFLAGS += $(APP_CFLAGS)
ifneq (,$(findstring WITH_SMARTCARD,$(APP_CFLAGS)))
SRC_SMARTCARD = cmdsmartcard.c
else
SRC_SMARTCARD =
endif
LUAPLATFORM = generic
platform = $(shell uname)
ifneq (,$(findstring MINGW,$(platform)))
@ -29,6 +41,8 @@ ifneq (,$(findstring MINGW,$(platform)))
else
ifeq ($(platform),Darwin)
LUAPLATFORM = macosx
OBJCSRCS = util_darwin.m
LDFLAGS += -framework Foundation -framework AppKit
else
LUALIB += -ldl
LDLIBS += -ltermcap -lncurses
@ -36,6 +50,7 @@ else
endif
endif
ifneq (,$(findstring WITH_GUI,$(APP_CFLAGS)))
# Check for correctly configured Qt5
QTINCLUDES = $(shell pkg-config --cflags Qt5Core Qt5Widgets 2>/dev/null)
QTLDLIBS = $(shell pkg-config --libs Qt5Core Qt5Widgets 2>/dev/null)
@ -64,6 +79,7 @@ ifeq ($(QTINCLUDES), )
UIC = $(QTDIR)/bin/uic
endif
endif
endif
ifneq ($(QTLDLIBS), )
@ -78,15 +94,26 @@ DEPFLAGS = -MT $@ -MMD -MP -MF $(OBJDIR)/$*.Td
# make temporary to final dependeny files after successful compilation
POSTCOMPILE = $(MV) -f $(OBJDIR)/$*.Td $(OBJDIR)/$*.d
CORESRCS = uart_posix.c \
uart_win32.c \
util.c \
util_posix.c
util_posix.c \
ui.c \
comms.c
CMDSRCS = crapto1/crapto1.c\
CMDSRCS = $(SRC_SMARTCARD) \
crapto1/crapto1.c\
crapto1/crypto1.c\
polarssl/des.c \
polarssl/aes.c\
polarssl/aes_cmac128.c\
polarssl/bignum.c\
polarssl/rsa.c\
polarssl/sha1.c\
polarssl/libpcrypto.c\
cliparser/argtable3.c\
cliparser/cliparser.c\
mfkey.c\
loclass/cipher.c \
loclass/cipherutils.c \
@ -95,18 +122,36 @@ CMDSRCS = crapto1/crapto1.c\
loclass/fileutils.c\
whereami.c\
mifarehost.c\
mifare4.c\
parity.c\
crc.c \
crc16.c \
crc64.c \
iso14443crc.c \
iso15693tools.c \
data.c \
graph.c \
ui.c \
cmddata.c \
lfdemod.c \
emv/crypto_polarssl.c\
emv/crypto.c\
emv/emv_pk.c\
emv/emv_pki.c\
emv/emv_pki_priv.c\
emv/test/cryptotest.c\
emv/apduinfo.c\
emv/dump.c\
emv/tlv.c\
emv/emv_tags.c\
emv/dol.c\
emv/emvjson.c\
emv/emvcore.c\
emv/test/crypto_test.c\
emv/test/sda_test.c\
emv/test/dda_test.c\
emv/test/cda_test.c\
emv/cmdemv.c\
cmdhf.c \
cmdhflist.c \
cmdhf14a.c \
cmdhf14b.c \
cmdhf15.c \
@ -114,6 +159,7 @@ CMDSRCS = crapto1/crapto1.c\
cmdhflegic.c \
cmdhficlass.c \
cmdhfmf.c \
cmdhfmfp.c \
cmdhfmfu.c \
cmdhfmfhard.c \
hardnested/hardnested_bruteforce.c \
@ -125,6 +171,8 @@ CMDSRCS = crapto1/crapto1.c\
cmdlfem4x.c \
cmdlffdx.c \
cmdlfgproxii.c \
hidcardformatutils.c\
hidcardformats.c\
cmdlfhid.c \
cmdlfhitag.c \
cmdlfio.c \
@ -148,15 +196,7 @@ CMDSRCS = crapto1/crapto1.c\
cmdscript.c\
pm3_binlib.c\
pm3_bitlib.c\
protocols.c\
sha1.c\
cmdcrc.c\
reveng/reveng.c\
reveng/cli.c\
reveng/bmpbit.c\
reveng/model.c\
reveng/poly.c\
reveng/getopt.c\
protocols.c
cpu_arch = $(shell uname -m)
ifneq ($(findstring 86, $(cpu_arch)), )
@ -177,6 +217,7 @@ QTGUISRCS = proxgui.cpp proxguiqt.cpp proxguiqt.moc.cpp guidummy.cpp
COREOBJS = $(CORESRCS:%.c=$(OBJDIR)/%.o)
CMDOBJS = $(CMDSRCS:%.c=$(OBJDIR)/%.o)
OBJCOBJS = $(OBJCSRCS:%.m=$(OBJDIR)/%.o)
ZLIBOBJS = $(ZLIBSRCS:%.c=$(OBJDIR)/%.o)
MULTIARCHOBJS = $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_NOSIMD.o) \
$(MULTIARCHSRCS:%.c=$(OBJDIR)/%_MMX.o) \
@ -184,14 +225,7 @@ MULTIARCHOBJS = $(MULTIARCHSRCS:%.c=$(OBJDIR)/%_NOSIMD.o) \
$(MULTIARCHSRCS:%.c=$(OBJDIR)/%_AVX.o) \
$(MULTIARCHSRCS:%.c=$(OBJDIR)/%_AVX2.o)
GCC_VERSION := $(shell gcc --version | awk '/gcc/{print $$NF;}' | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/')
CLANG_VERSION := $(shell gcc --version | awk '/Apple LLVM version/{print $$4;}' | sed -e 's/\.\([0-9][0-9]\)/\1/g' -e 's/\.\([0-9]\)/0\1/g' -e 's/^[0-9]\{3,4\}$$/&00/')
ifneq ($(CLANG_VERSION), )
SUPPORTS_AVX512 := $(shell [ $(CLANG_VERSION) -ge 80000 ] && echo "True" )
endif
ifneq ($(GCC_VERSION), )
SUPPORTS_AVX512 := $(shell [ $(GCC_VERSION) -ge 40900 ] && echo "True" )
endif
SUPPORTS_AVX512 := $(shell echo | gcc -E -mavx512f - > /dev/null 2>&1 && echo "True" )
HARD_SWITCH_NOSIMD = -mno-mmx -mno-sse2 -mno-avx -mno-avx2
HARD_SWITCH_MMX = -mmmx -mno-sse2 -mno-avx -mno-avx2
HARD_SWITCH_SSE2 = -mmmx -msse2 -mno-avx -mno-avx2
@ -209,19 +243,19 @@ endif
BINS = proxmark3 flasher fpga_compress
WINBINS = $(patsubst %, %.exe, $(BINS))
CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h
CLEAN = $(BINS) $(WINBINS) $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(ZLIBOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(OBJDIR)/*.o *.moc.cpp ui/ui_overlays.h
# need to assign dependancies to build these first...
all: lua_build $(BINS)
all: lua_build jansson_build $(BINS)
all-static: LDLIBS:=-static $(LDLIBS)
all-static: proxmark3 flasher fpga_compress
proxmark3: LDLIBS+=$(LUALIB) $(QTLDLIBS)
proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua
$(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@
proxmark3: LDLIBS+=$(LUALIB) $(JANSSONLIB) $(QTLDLIBS)
proxmark3: $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) lualibs/usb_cmd.lua
$(LD) $(LDFLAGS) $(OBJDIR)/proxmark3.o $(COREOBJS) $(CMDOBJS) $(OBJCOBJS) $(QTGUIOBJS) $(MULTIARCHOBJS) $(ZLIBOBJS) $(LDLIBS) -o $@
flasher: $(OBJDIR)/flash.o $(OBJDIR)/flasher.o $(COREOBJS)
flasher: $(OBJDIR)/flash.o $(OBJDIR)/flasher.o $(COREOBJS) $(OBJCOBJS)
$(LD) $(LDFLAGS) $^ $(LDLIBS) -o $@
fpga_compress: $(OBJDIR)/fpga_compress.o $(ZLIBOBJS)
@ -241,6 +275,7 @@ lualibs/usb_cmd.lua: ../include/usb_cmd.h
clean:
$(RM) $(CLEAN)
cd ../liblua && make clean
cd ./jansson && make clean
tarbin: $(BINS)
$(TAR) $(TARFLAGS) ../proxmark3-$(platform)-bin.tar $(BINS:%=client/%) $(WINBINS:%=client/%)
@ -249,6 +284,10 @@ lua_build:
@echo Compiling liblua, using platform $(LUAPLATFORM)
cd ../liblua && make $(LUAPLATFORM)
jansson_build:
@echo Compiling jansson
cd ./jansson && make all
.PHONY: all clean
$(OBJDIR)/%_NOSIMD.o : %.c $(OBJDIR)/%.d
@ -279,6 +318,10 @@ $(OBJDIR)/%.o : %.cpp $(OBJDIR)/%.d
$(CXX) $(DEPFLAGS) $(CXXFLAGS) $(QTINCLUDES) -c -o $@ $<
$(POSTCOMPILE)
%.o: %.m
$(OBJDIR)/%.o : %.m $(OBJDIR)/%.d
$(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $<
$(POSTCOMPILE)
#$(CMDOBJS) $(COREOBJS): $(notdir $(%.c)) %.d
# $(CC) $(DEPFLAGS) $(CFLAGS) -c -o $@ $<
@ -294,10 +337,10 @@ $(OBJDIR)/%.o : %.cpp $(OBJDIR)/%.d
DEPENDENCY_FILES = $(patsubst %.c, $(OBJDIR)/%.d, $(CORESRCS) $(CMDSRCS) $(ZLIBSRCS) $(MULTIARCHSRCS)) \
$(patsubst %.cpp, $(OBJDIR)/%.d, $(QTGUISRCS)) \
$(patsubst %.m, $(OBJDIR)/%.d, $(OBJCSRCS)) \
$(OBJDIR)/proxmark3.d $(OBJDIR)/flash.d $(OBJDIR)/flasher.d $(OBJDIR)/fpga_compress.d
$(DEPENDENCY_FILES): ;
.PRECIOUS: $(DEPENDENCY_FILES)
-include $(DEPENDENCY_FILES)

View file

@ -0,0 +1,13 @@
# Command line parser
cliparser - librari for proxmark with command line parsing high level functions.
## External libraries:
### argtable
Argtable3 is a single-file, ANSI C, command-line parsing library that parses GNU-style command-line options.
You can download argtable3 from this repository https://github.com/argtable/argtable3
[argtable3 license](https://github.com/argtable/argtable3/blob/master/LICENSE)

5005
client/cliparser/argtable3.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,305 @@
/*******************************************************************************
* This file is part of the argtable3 library.
*
* Copyright (C) 1998-2001,2003-2011,2013 Stewart Heitmann
* <sheitmann@users.sourceforge.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of STEWART HEITMANN nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL STEWART HEITMANN BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
#ifndef ARGTABLE3
#define ARGTABLE3
#include <stdio.h> /* FILE */
#include <time.h> /* struct tm */
#ifdef __cplusplus
extern "C" {
#endif
#define ARG_REX_ICASE 1
/* bit masks for arg_hdr.flag */
enum
{
ARG_TERMINATOR=0x1,
ARG_HASVALUE=0x2,
ARG_HASOPTVALUE=0x4
};
typedef void (arg_resetfn)(void *parent);
typedef int (arg_scanfn)(void *parent, const char *argval);
typedef int (arg_checkfn)(void *parent);
typedef void (arg_errorfn)(void *parent, FILE *fp, int error, const char *argval, const char *progname);
/*
* The arg_hdr struct defines properties that are common to all arg_xxx structs.
* The argtable library requires each arg_xxx struct to have an arg_hdr
* struct as its first data member.
* The argtable library functions then use this data to identify the
* properties of the command line option, such as its option tags,
* datatype string, and glossary strings, and so on.
* Moreover, the arg_hdr struct contains pointers to custom functions that
* are provided by each arg_xxx struct which perform the tasks of parsing
* that particular arg_xxx arguments, performing post-parse checks, and
* reporting errors.
* These functions are private to the individual arg_xxx source code
* and are the pointer to them are initiliased by that arg_xxx struct's
* constructor function. The user could alter them after construction
* if desired, but the original intention is for them to be set by the
* constructor and left unaltered.
*/
struct arg_hdr
{
char flag; /* Modifier flags: ARG_TERMINATOR, ARG_HASVALUE. */
const char *shortopts; /* String defining the short options */
const char *longopts; /* String defiing the long options */
const char *datatype; /* Description of the argument data type */
const char *glossary; /* Description of the option as shown by arg_print_glossary function */
int mincount; /* Minimum number of occurences of this option accepted */
int maxcount; /* Maximum number of occurences if this option accepted */
void *parent; /* Pointer to parent arg_xxx struct */
arg_resetfn *resetfn; /* Pointer to parent arg_xxx reset function */
arg_scanfn *scanfn; /* Pointer to parent arg_xxx scan function */
arg_checkfn *checkfn; /* Pointer to parent arg_xxx check function */
arg_errorfn *errorfn; /* Pointer to parent arg_xxx error function */
void *priv; /* Pointer to private header data for use by arg_xxx functions */
};
struct arg_rem
{
struct arg_hdr hdr; /* The mandatory argtable header struct */
};
struct arg_lit
{
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
};
struct arg_int
{
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
int *ival; /* Array of parsed argument values */
};
struct arg_dbl
{
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
double *dval; /* Array of parsed argument values */
};
struct arg_str
{
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
const char **sval; /* Array of parsed argument values */
};
struct arg_rex
{
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */
const char **sval; /* Array of parsed argument values */
};
struct arg_file
{
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args*/
const char **filename; /* Array of parsed filenames (eg: /home/foo.bar) */
const char **basename; /* Array of parsed basenames (eg: foo.bar) */
const char **extension; /* Array of parsed extensions (eg: .bar) */
};
struct arg_date
{
struct arg_hdr hdr; /* The mandatory argtable header struct */
const char *format; /* strptime format string used to parse the date */
int count; /* Number of matching command line args */
struct tm *tmval; /* Array of parsed time values */
};
enum {ARG_ELIMIT=1, ARG_EMALLOC, ARG_ENOMATCH, ARG_ELONGOPT, ARG_EMISSARG};
struct arg_end
{
struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of errors encountered */
int *error; /* Array of error codes */
void **parent; /* Array of pointers to offending arg_xxx struct */
const char **argval; /* Array of pointers to offending argv[] string */
};
/**** arg_xxx constructor functions *********************************/
struct arg_rem* arg_rem(const char* datatype, const char* glossary);
struct arg_lit* arg_lit0(const char* shortopts,
const char* longopts,
const char* glossary);
struct arg_lit* arg_lit1(const char* shortopts,
const char* longopts,
const char *glossary);
struct arg_lit* arg_litn(const char* shortopts,
const char* longopts,
int mincount,
int maxcount,
const char *glossary);
struct arg_key* arg_key0(const char* keyword,
int flags,
const char* glossary);
struct arg_key* arg_key1(const char* keyword,
int flags,
const char* glossary);
struct arg_key* arg_keyn(const char* keyword,
int flags,
int mincount,
int maxcount,
const char* glossary);
struct arg_int* arg_int0(const char* shortopts,
const char* longopts,
const char* datatype,
const char* glossary);
struct arg_int* arg_int1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_int* arg_intn(const char* shortopts,
const char* longopts,
const char *datatype,
int mincount,
int maxcount,
const char *glossary);
struct arg_dbl* arg_dbl0(const char* shortopts,
const char* longopts,
const char* datatype,
const char* glossary);
struct arg_dbl* arg_dbl1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_dbl* arg_dbln(const char* shortopts,
const char* longopts,
const char *datatype,
int mincount,
int maxcount,
const char *glossary);
struct arg_str* arg_str0(const char* shortopts,
const char* longopts,
const char* datatype,
const char* glossary);
struct arg_str* arg_str1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_str* arg_strn(const char* shortopts,
const char* longopts,
const char* datatype,
int mincount,
int maxcount,
const char *glossary);
struct arg_rex* arg_rex0(const char* shortopts,
const char* longopts,
const char* pattern,
const char* datatype,
int flags,
const char* glossary);
struct arg_rex* arg_rex1(const char* shortopts,
const char* longopts,
const char* pattern,
const char* datatype,
int flags,
const char *glossary);
struct arg_rex* arg_rexn(const char* shortopts,
const char* longopts,
const char* pattern,
const char* datatype,
int mincount,
int maxcount,
int flags,
const char *glossary);
struct arg_file* arg_file0(const char* shortopts,
const char* longopts,
const char* datatype,
const char* glossary);
struct arg_file* arg_file1(const char* shortopts,
const char* longopts,
const char* datatype,
const char *glossary);
struct arg_file* arg_filen(const char* shortopts,
const char* longopts,
const char* datatype,
int mincount,
int maxcount,
const char *glossary);
struct arg_date* arg_date0(const char* shortopts,
const char* longopts,
const char* format,
const char* datatype,
const char* glossary);
struct arg_date* arg_date1(const char* shortopts,
const char* longopts,
const char* format,
const char* datatype,
const char *glossary);
struct arg_date* arg_daten(const char* shortopts,
const char* longopts,
const char* format,
const char* datatype,
int mincount,
int maxcount,
const char *glossary);
struct arg_end* arg_end(int maxerrors);
/**** other functions *******************************************/
int arg_nullcheck(void **argtable);
int arg_parse(int argc, char **argv, void **argtable);
void arg_print_option(FILE *fp, const char *shortopts, const char *longopts, const char *datatype, const char *suffix);
void arg_print_syntax(FILE *fp, void **argtable, const char *suffix);
void arg_print_syntaxv(FILE *fp, void **argtable, const char *suffix);
void arg_print_glossary(FILE *fp, void **argtable, const char *format);
void arg_print_glossary_gnu(FILE *fp, void **argtable);
void arg_print_errors(FILE* fp, struct arg_end* end, const char* progname);
void arg_freetable(void **argtable, size_t n);
/**** deprecated functions, for back-compatibility only ********/
void arg_free(void **argtable);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,205 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2017 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Command line parser core commands
//-----------------------------------------------------------------------------
#include "cliparser.h"
#include <stdio.h>
#include <string.h>
void **argtable = NULL;
size_t argtableLen = 0;
char *programName = NULL;
char *programHint = NULL;
char *programHelp = NULL;
char buf[500] = {0};
int CLIParserInit(char *vprogramName, char *vprogramHint, char *vprogramHelp) {
argtable = NULL;
argtableLen = 0;
programName = vprogramName;
programHint = vprogramHint;
programHelp = vprogramHelp;
memset(buf, 0x00, 500);
return 0;
}
int CLIParserParseArg(int argc, char **argv, void* vargtable[], size_t vargtableLen, bool allowEmptyExec) {
int nerrors;
argtable = vargtable;
argtableLen = vargtableLen;
/* verify the argtable[] entries were allocated sucessfully */
if (arg_nullcheck(argtable) != 0) {
/* NULL entries were detected, some allocations must have failed */
printf("ERROR: Insufficient memory\n");
return 2;
}
/* Parse the command line as defined by argtable[] */
nerrors = arg_parse(argc, argv, argtable);
/* special case: '--help' takes precedence over error reporting */
if ((argc < 2 && !allowEmptyExec) ||((struct arg_lit *)argtable[0])->count > 0) { // help must be the first record
printf("Usage: %s", programName);
arg_print_syntaxv(stdout, argtable, "\n");
if (programHint)
printf("%s\n\n", programHint);
arg_print_glossary(stdout, argtable, " %-20s %s\n");
printf("\n");
if (programHelp)
printf("%s \n", programHelp);
return 1;
}
/* If the parser returned any errors then display them and exit */
if (nerrors > 0) {
/* Display the error details contained in the arg_end struct.*/
arg_print_errors(stdout, ((struct arg_end *)argtable[vargtableLen - 1]), programName);
printf("Try '%s --help' for more information.\n", programName);
return 3;
}
return 0;
}
enum ParserState {
PS_FIRST,
PS_ARGUMENT,
PS_OPTION,
};
#define isSpace(c)(c == ' ' || c == '\t')
int CLIParserParseString(const char* str, void* vargtable[], size_t vargtableLen, bool allowEmptyExec) {
return CLIParserParseStringEx(str, vargtable, vargtableLen, allowEmptyExec, false);
}
int CLIParserParseStringEx(const char* str, void* vargtable[], size_t vargtableLen, bool allowEmptyExec, bool clueData) {
int argc = 0;
char *argv[200] = {NULL};
int len = strlen(str);
char *bufptr = buf;
char *spaceptr = NULL;
enum ParserState state = PS_FIRST;
argv[argc++] = bufptr;
// param0 = program name
memcpy(buf, programName, strlen(programName) + 1); // with 0x00
bufptr += strlen(programName) + 1;
if (len)
argv[argc++] = bufptr;
// parse params
for (int i = 0; i < len; i++) {
switch(state){
case PS_FIRST: // first char
if (!clueData || str[i] == '-'){ // first char before space is '-' - next element - option OR not "clueData" for not-option fields
state = PS_OPTION;
if (spaceptr) {
bufptr = spaceptr;
*bufptr = 0x00;
bufptr++;
argv[argc++] = bufptr;
}
}
spaceptr = NULL;
case PS_ARGUMENT:
if (state == PS_FIRST)
state = PS_ARGUMENT;
if (isSpace(str[i])) {
spaceptr = bufptr;
state = PS_FIRST;
}
*bufptr = str[i];
bufptr++;
break;
case PS_OPTION:
if (isSpace(str[i])){
state = PS_FIRST;
*bufptr = 0x00;
bufptr++;
argv[argc++] = bufptr;
break;
}
*bufptr = str[i];
bufptr++;
break;
}
}
return CLIParserParseArg(argc, argv, vargtable, vargtableLen, allowEmptyExec);
}
void CLIParserFree() {
arg_freetable(argtable, argtableLen);
argtable = NULL;
return;
}
// convertors
int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
*datalen = 0;
int ibuf = 0;
uint8_t buf[256] = {0};
int res = CLIParamStrToBuf(argstr, buf, maxdatalen * 2, &ibuf); // *2 because here HEX
if (res || !ibuf)
return res;
switch(param_gethex_to_eol((char *)buf, 0, data, maxdatalen, datalen)) {
case 1:
printf("Parameter error: Invalid HEX value.\n");
return 1;
case 2:
printf("Parameter error: parameter too large.\n");
return 2;
case 3:
printf("Parameter error: Hex string must have even number of digits.\n");
return 3;
}
return 0;
}
int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) {
*datalen = 0;
if (!argstr->count)
return 0;
uint8_t buf[256] = {0};
int ibuf = 0;
for (int i = 0; i < argstr->count; i++) {
int len = strlen(argstr->sval[i]);
memcpy(&buf[ibuf], argstr->sval[i], len);
ibuf += len;
}
buf[ibuf] = 0;
if (!ibuf)
return 0;
if (ibuf > maxdatalen)
return 2;
memcpy(data, buf, ibuf);
*datalen = ibuf;
return 0;
}

View file

@ -0,0 +1,41 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2017 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Command line parser core commands
//-----------------------------------------------------------------------------
#include "argtable3.h"
#include "util.h"
#include <stdbool.h>
#define arg_param_begin arg_lit0("hH", "help", "print this help and exit")
#define arg_param_end arg_end(20)
#define arg_getsize(a) (sizeof(a) / sizeof(a[0]))
#define arg_get_lit(n)(((struct arg_lit*)argtable[n])->count)
#define arg_get_int_count(n)(((struct arg_int*)argtable[n])->count)
#define arg_get_int(n)(((struct arg_int*)argtable[n])->ival[0])
#define arg_get_int_def(n,def)(arg_get_int_count(n)?(arg_get_int(n)):(def))
#define arg_get_str(n)((struct arg_str*)argtable[n])
#define arg_get_str_len(n)(strlen(((struct arg_str*)argtable[n])->sval[0]))
#define arg_strx1(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 1, 250, (glossary)))
#define arg_strx0(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 0, 250, (glossary)))
#define CLIExecWithReturn(cmd, atbl, ifempty) if (CLIParserParseString(cmd, atbl, arg_getsize(atbl), ifempty)){CLIParserFree();return 0;}
#define CLIGetHexBLessWithReturn(paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree();return 1;}
#define CLIGetHexWithReturn(paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;}
#define CLIGetStrWithReturn(paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str(paramnum), data, sizeof(data), datalen)) {CLIParserFree();return 1;}
extern int CLIParserInit(char *vprogramName, char *vprogramHint, char *vprogramHelp);
extern int CLIParserParseString(const char* str, void* argtable[], size_t vargtableLen, bool allowEmptyExec);
extern int CLIParserParseStringEx(const char* str, void* vargtable[], size_t vargtableLen, bool allowEmptyExec, bool clueData);
extern int CLIParserParseArg(int argc, char **argv, void* argtable[], size_t vargtableLen, bool allowEmptyExec);
extern void CLIParserFree();
extern int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen);
extern int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen);

View file

@ -1,547 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2015 iceman <iceman at iuse.se>
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// CRC Calculations from the software reveng commands
//-----------------------------------------------------------------------------
#ifdef _WIN32
# include <io.h>
# include <fcntl.h>
# ifndef STDIN_FILENO
# define STDIN_FILENO 0
# endif /* STDIN_FILENO */
#endif /* _WIN32 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include "cmdmain.h"
#include "cmdcrc.h"
#include "reveng/reveng.h"
#include "ui.h"
#include "util.h"
#define MAX_ARGS 20
int uerr(char *msg){
PrintAndLog("%s",msg);
return 0;
}
int split(char *str, char *arr[MAX_ARGS]){
int beginIndex = 0;
int endIndex;
int maxWords = MAX_ARGS;
int wordCnt = 0;
while(1){
while(isspace(str[beginIndex])){
++beginIndex;
}
if(str[beginIndex] == '\0') {
break;
}
endIndex = beginIndex;
while (str[endIndex] && !isspace(str[endIndex])){
++endIndex;
}
int len = endIndex - beginIndex;
char *tmp = calloc(len + 1, sizeof(char));
memcpy(tmp, &str[beginIndex], len);
arr[wordCnt++] = tmp;
//PrintAndLog("DEBUG cnt: %d, %s",wordCnt-1, arr[wordCnt-1]);
beginIndex = endIndex;
if (wordCnt == maxWords)
break;
}
return wordCnt;
}
int CmdCrc(const char *Cmd)
{
char name[] = {"reveng "};
char Cmd2[50 + 7];
memcpy(Cmd2, name, 7);
memcpy(Cmd2 + 7, Cmd, 50);
char *argv[MAX_ARGS];
int argc = split(Cmd2, argv);
if (argc == 3 && memcmp(argv[1],"-g",2)==0) {
CmdrevengSearch(argv[2]);
} else {
reveng_main(argc, argv);
}
//PrintAndLog("DEBUG argc: %d, %s %s Cmd: %s",argc, argv[0], Cmd2, Cmd);
for(int i = 0; i < argc; ++i){
free(argv[i]);
}
return 0;
}
//returns array of model names and the count of models returning
// as well as a width array for the width of each model
int GetModels(char *Models[], int *count, uint8_t *width){
/* default values */
static model_t model = {
PZERO, /* no CRC polynomial, user must specify */
PZERO, /* Init = 0 */
P_BE, /* RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h */
PZERO, /* XorOut = 0 */
PZERO, /* check value unused */
NULL /* no model name */
};
int ibperhx = 8;//, obperhx = 8;
int rflags = 0, uflags = 0; /* search and UI flags */
poly_t apoly, crc, qpoly = PZERO, *apolys = NULL, *pptr = NULL, *qptr = NULL;
model_t pset = model, *candmods, *mptr;
/* stdin must be binary */
#ifdef _WIN32
_setmode(STDIN_FILENO, _O_BINARY);
#endif /* _WIN32 */
SETBMP();
int args = 0, psets, pass;
int Cnt = 0;
if (width[0] == 0) { //reveng -D
*count = mcount();
if(!*count)
return uerr("no preset models available");
for(int mode = 0; mode < *count; ++mode) {
mbynum(&model, mode);
mcanon(&model);
size_t size = (model.name && *model.name) ? strlen(model.name) : 6;
char *tmp = calloc(size+1, sizeof(char));
if (tmp==NULL)
return uerr("out of memory?");
memcpy(tmp, model.name, size);
Models[mode] = tmp;
width[mode] = plen(model.spoly);
}
mfree(&model);
} else { //reveng -s
if(~model.flags & P_MULXN)
return uerr("cannot search for non-Williams compliant models");
praloc(&model.spoly, (unsigned long)width[0]);
praloc(&model.init, (unsigned long)width[0]);
praloc(&model.xorout, (unsigned long)width[0]);
if(!plen(model.spoly))
palloc(&model.spoly, (unsigned long)width[0]);
else
width[0] = (uint8_t)plen(model.spoly);
/* special case if qpoly is zero, search to end of range */
if(!ptst(qpoly))
rflags &= ~R_HAVEQ;
/* not going to be sending additional args at this time (maybe future?)
// allocate argument array
args = argc - optind;
if(!(apolys = malloc(args * sizeof(poly_t))))
return uerr("cannot allocate memory for argument list");
for(pptr = apolys; optind < argc; ++optind) {
if(uflags & C_INFILE)
*pptr++ = rdpoly(argv[optind], model.flags, ibperhx);
else
*pptr++ = strtop(argv[optind], model.flags, ibperhx);
}
// exit value of pptr is used hereafter!
*/
/* if endianness not specified, try
* little-endian then big-endian.
* NB: crossed-endian algorithms will not be
* searched.
*/
/* scan against preset models */
if(~uflags & C_FORCE) {
pass = 0;
Cnt = 0;
do {
psets = mcount();
//PrintAndLog("psets: %d",psets);
while(psets) {
mbynum(&pset, --psets);
/* skip if different width, or refin or refout don't match */
if(plen(pset.spoly) != width[0] || (model.flags ^ pset.flags) & (P_REFIN | P_REFOUT))
continue;
/* skip if the preset doesn't match specified parameters */
if(rflags & R_HAVEP && pcmp(&model.spoly, &pset.spoly))
continue;
if(rflags & R_HAVEI && psncmp(&model.init, &pset.init))
continue;
if(rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout))
continue;
//for additional args (not used yet, maybe future?)
apoly = pclone(pset.xorout);
if(pset.flags & P_REFOUT)
prev(&apoly);
for(qptr = apolys; qptr < pptr; ++qptr) {
crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
if(ptst(crc)) {
pfree(&crc);
break;
} else
pfree(&crc);
}
pfree(&apoly);
if(qptr == pptr) {
/* the selected model solved all arguments */
mcanon(&pset);
size_t size = (pset.name && *pset.name) ? strlen(pset.name) : 6;
//PrintAndLog("Size: %d, %s, count: %d",size,pset.name, Cnt);
char *tmp = calloc(size+1, sizeof(char));
if (tmp==NULL){
PrintAndLog("out of memory?");
return 0;
}
width[Cnt] = width[0];
memcpy(tmp, pset.name, size);
Models[Cnt++] = tmp;
*count = Cnt;
uflags |= C_RESULT;
}
}
mfree(&pset);
/* toggle refIn/refOut and reflect arguments */
if(~rflags & R_HAVERI) {
model.flags ^= P_REFIN | P_REFOUT;
for(qptr = apolys; qptr < pptr; ++qptr)
prevch(qptr, ibperhx);
}
} while(~rflags & R_HAVERI && ++pass < 2);
}
//got everything now free the memory...
if(uflags & C_RESULT) {
for(qptr = apolys; qptr < pptr; ++qptr)
pfree(qptr);
}
if(!(model.flags & P_REFIN) != !(model.flags & P_REFOUT))
return uerr("cannot search for crossed-endian models");
pass = 0;
do {
mptr = candmods = reveng(&model, qpoly, rflags, args, apolys);
if(mptr && plen(mptr->spoly))
uflags |= C_RESULT;
while(mptr && plen(mptr->spoly)) {
mfree(mptr++);
}
free(candmods);
if(~rflags & R_HAVERI) {
model.flags ^= P_REFIN | P_REFOUT;
for(qptr = apolys; qptr < pptr; ++qptr)
prevch(qptr, ibperhx);
}
} while(~rflags & R_HAVERI && ++pass < 2);
for(qptr = apolys; qptr < pptr; ++qptr)
pfree(qptr);
free(apolys);
if(~uflags & C_RESULT)
return uerr("no models found");
mfree(&model);
}
return 1;
}
//test call to GetModels
int CmdrevengTest(const char *Cmd){
char *Models[80];
int count = 0;
uint8_t widtharr[80] = {0};
uint8_t width = 0;
width = param_get8(Cmd, 0);
//PrintAndLog("width: %d",width);
if (width > 89)
return uerr("Width cannot exceed 89");
widtharr[0] = width;
int ans = GetModels(Models, &count, widtharr);
if (!ans) return 0;
PrintAndLog("Count: %d",count);
for (int i = 0; i < count; i++){
PrintAndLog("Model %d: %s, width: %d",i,Models[i], widtharr[i]);
free(Models[i]);
}
return 1;
}
//-c || -v
//inModel = valid model name string - CRC-8
//inHexStr = input hex string to calculate crc on
//reverse = reverse calc option if true
//endian = {0 = calc default endian input and output, b = big endian input and output, B = big endian output, r = right justified
// l = little endian input and output, L = little endian output only, t = left justified}
//result = calculated crc hex string
int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result){
/* default values */
static model_t model = {
PZERO, // no CRC polynomial, user must specify
PZERO, // Init = 0
P_BE, // RefIn = false, RefOut = false, plus P_RTJUST setting in reveng.h
PZERO, // XorOut = 0
PZERO, // check value unused
NULL // no model name
};
int ibperhx = 8, obperhx = 8;
int rflags = 0; // search flags
int c;
//unsigned long width;
poly_t apoly, crc;
char *string;
// stdin must be binary
#ifdef _WIN32
_setmode(STDIN_FILENO, _O_BINARY);
#endif /* _WIN32 */
SETBMP();
//set model
if(!(c = mbynam(&model, inModel))) {
fprintf(stderr,"error: preset model '%s' not found. Use reveng -D to list presets.\n", inModel);
return 0;
}
if(c < 0)
return uerr("no preset models available");
// must set width so that parameter to -ipx is not zeroed
//width = plen(model.spoly);
rflags |= R_HAVEP | R_HAVEI | R_HAVERI | R_HAVERO | R_HAVEX;
//set flags
switch (endian) {
case 'b': /* b big-endian (RefIn = false, RefOut = false ) */
model.flags &= ~P_REFIN;
rflags |= R_HAVERI;
/* fall through: */
case 'B': /* B big-endian output (RefOut = false) */
model.flags &= ~P_REFOUT;
rflags |= R_HAVERO;
mnovel(&model);
/* fall through: */
case 'r': /* r right-justified */
model.flags |= P_RTJUST;
break;
case 'l': /* l little-endian input and output */
model.flags |= P_REFIN;
rflags |= R_HAVERI;
/* fall through: */
case 'L': /* L little-endian output */
model.flags |= P_REFOUT;
rflags |= R_HAVERO;
mnovel(&model);
/* fall through: */
case 't': /* t left-justified */
model.flags &= ~P_RTJUST;
break;
}
mcanon(&model);
if (reverse) {
// v calculate reversed CRC
/* Distinct from the -V switch as this causes
* the arguments and output to be reversed as well.
*/
// reciprocate Poly
prcp(&model.spoly);
/* mrev() does:
* if(refout) prev(init); else prev(xorout);
* but here the entire argument polynomial is
* reflected, not just the characters, so RefIn
* and RefOut are not inverted as with -V.
* Consequently Init is the mirror image of the
* one resulting from -V, and so we have:
*/
if(~model.flags & P_REFOUT) {
prev(&model.init);
prev(&model.xorout);
}
// swap init and xorout
apoly = model.init;
model.init = model.xorout;
model.xorout = apoly;
}
// c calculate CRC
// validate inputs
/* if(plen(model.spoly) == 0) {
* fprintf(stderr,"%s: no polynomial specified for -%c (add -w WIDTH -p POLY)\n", myname, mode);
* exit(EXIT_FAILURE);
* }
*/
/* in the Williams model, xorout is applied after the refout stage.
* as refout is part of ptostr(), we reverse xorout here.
*/
if(model.flags & P_REFOUT)
prev(&model.xorout);
apoly = strtop(inHexStr, model.flags, ibperhx);
if(reverse)
prev(&apoly);
crc = pcrc(apoly, model.spoly, model.init, model.xorout, model.flags);
if(reverse)
prev(&crc);
string = ptostr(crc, model.flags, obperhx);
for (int i = 0; i < 50; i++){
result[i] = string[i];
if (result[i]==0) break;
}
free(string);
pfree(&crc);
pfree(&apoly);
return 1;
}
//test call to RunModel
int CmdrevengTestC(const char *Cmd){
int cmdp = 0;
char inModel[30] = {0x00};
char inHexStr[30] = {0x00};
char result[30];
int dataLen;
char endian = 0;
dataLen = param_getstr(Cmd, cmdp++, inModel);
if (dataLen < 4) return 0;
dataLen = param_getstr(Cmd, cmdp++, inHexStr);
if (dataLen < 4) return 0;
bool reverse = (param_get8(Cmd, cmdp++)) ? true : false;
endian = param_getchar(Cmd, cmdp++);
//PrintAndLog("mod: %s, hex: %s, rev %d", inModel, inHexStr, reverse);
int ans = RunModel(inModel, inHexStr, reverse, endian, result);
if (!ans) return 0;
PrintAndLog("Result: %s",result);
return 1;
}
//returns a calloced string (needs to be freed)
char *SwapEndianStr(const char *inStr, const size_t len, const uint8_t blockSize){
char *tmp = calloc(len+1, sizeof(char));
for (uint8_t block=0; block < (uint8_t)(len/blockSize); block++){
for (size_t i = 0; i < blockSize; i+=2){
tmp[i+(blockSize*block)] = inStr[(blockSize-1-i-1)+(blockSize*block)];
tmp[i+(blockSize*block)+1] = inStr[(blockSize-1-i)+(blockSize*block)];
}
}
return tmp;
}
// takes hex string in and searches for a matching result (hex string must include checksum)
int CmdrevengSearch(const char *Cmd){
char inHexStr[50] = {0x00};
int dataLen = param_getstr(Cmd, 0, inHexStr);
if (dataLen < 4) return 0;
char *Models[80];
int count = 0;
uint8_t width[80];
width[0] = 0;
uint8_t crcChars = 0;
char result[30];
char revResult[30];
int ans = GetModels(Models, &count, width);
bool found = false;
if (!ans) return 0;
// try each model and get result
for (int i = 0; i < count; i++){
/*if (found) {
free(Models[i]);
continue;
}*/
// round up to # of characters in this model's crc
crcChars = ((width[i]+7)/8)*2;
// can't test a model that has more crc digits than our data
if (crcChars >= dataLen)
continue;
memset(result, 0, 30);
char *inCRC = calloc(crcChars+1, sizeof(char));
memcpy(inCRC, inHexStr+(dataLen-crcChars), crcChars);
char *outHex = calloc(dataLen-crcChars+1, sizeof(char));
memcpy(outHex, inHexStr, dataLen-crcChars);
//PrintAndLog("DEBUG: dataLen: %d, crcChars: %d, Model: %s, CRC: %s, width: %d, outHex: %s",dataLen, crcChars, Models[i], inCRC, width[i], outHex);
ans = RunModel(Models[i], outHex, false, 0, result);
if (ans) {
//test for match
if (memcmp(result, inCRC, crcChars)==0){
PrintAndLog("\nFound a possible match!\nModel: %s\nValue: %s\n",Models[i], result);
//optional - stop searching if found...
found = true;
} else {
if (crcChars > 2){
char *swapEndian = SwapEndianStr(result, crcChars, crcChars);
if (memcmp(swapEndian, inCRC, crcChars)==0){
PrintAndLog("\nFound a possible match!\nModel: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian);
//optional - stop searching if found...
found = true;
}
free(swapEndian);
}
}
}
//if (!found){
ans = RunModel(Models[i], outHex, true, 0, revResult);
if (ans) {
//test for match
if (memcmp(revResult, inCRC, crcChars)==0){
PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue: %s\n",Models[i], revResult);
//optional - stop searching if found...
found = true;
} else {
if (crcChars > 2){
char *swapEndian = SwapEndianStr(revResult, crcChars, crcChars);
if (memcmp(swapEndian, inCRC, crcChars)==0){
PrintAndLog("\nFound a possible match!\nModel Reversed: %s\nValue EndianSwapped: %s\n",Models[i], swapEndian);
//optional - stop searching if found...
found = true;
}
free(swapEndian);
}
}
}
//}
free(inCRC);
free(outHex);
free(Models[i]);
}
if (!found) PrintAndLog("\nNo matches found\n");
return 1;
}

View file

@ -1,20 +0,0 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2015 iceman <iceman at iuse.se>
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// CRC Calculations from the software reveng commands
//-----------------------------------------------------------------------------
#ifndef CMDCRC_H__
#define CMDCRC_H__
int CmdCrc(const char *Cmd);
int CmdrevengTest(const char *Cmd);
int CmdrevengTestC(const char *Cmd);
int CmdrevengSearch(const char *Cmd);
int GetModels(char *Models[], int *count, uint8_t *width);
int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *result);
#endif

View file

@ -8,15 +8,15 @@
// Data and Graph commands
//-----------------------------------------------------------------------------
#include "cmddata.h"
#include <stdio.h> // also included in util.h
#include <string.h> // also included in util.h
#include <inttypes.h>
#include <limits.h> // for CmdNorm INT_MIN && INT_MAX
#include "data.h" // also included in util.h
#include "cmddata.h"
#include "util.h"
#include "cmdmain.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h" // for show graph controls
#include "graph.h" // for graph data
#include "cmdparser.h"// already included in cmdmain.h
@ -591,8 +591,7 @@ int CmdBitsamples(const char *Cmd)
int cnt = 0;
uint8_t got[12288];
GetFromBigBuf(got,sizeof(got),0);
WaitForResponse(CMD_ACK,NULL);
GetFromBigBuf(got, sizeof(got), 0 , NULL, -1, false);
for (int j = 0; j < sizeof(got); j++) {
for (int k = 0; k < 8; k++) {
@ -1131,8 +1130,7 @@ int CmdHexsamples(const char *Cmd)
return 0;
}
GetFromBigBuf(got,requested,offset);
WaitForResponse(CMD_ACK,NULL);
GetFromBigBuf(got, requested, offset, NULL, -1, false);
i = 0;
for (j = 0; j < requested; j++) {
@ -1200,10 +1198,9 @@ int getSamples(int n, bool silent)
n = sizeof(got);
if (!silent) PrintAndLog("Reading %d bytes from device memory\n", n);
GetFromBigBuf(got,n,0);
if (!silent) PrintAndLog("Data fetched");
UsbCommand response;
WaitForResponse(CMD_ACK, &response);
GetFromBigBuf(got, n, 0, &response, -1, false);
if (!silent) PrintAndLog("Data fetched");
uint8_t bits_per_sample = 8;
//Old devices without this feature would send 0 at arg[0]
@ -1281,26 +1278,36 @@ int CmdTuneSamples(const char *Cmd)
peakf = resp.arg[2] & 0xffff;
peakv = resp.arg[2] >> 16;
PrintAndLog("");
PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/1000.0);
PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/1000.0);
PrintAndLog("# LF optimal: %5.2f V @%9.2f kHz", peakv/1000.0, 12000.0/(peakf+1));
if (arg & FLAG_TUNE_LF)
{
PrintAndLog("# LF antenna: %5.2f V @ 125.00 kHz", vLf125/500.0);
PrintAndLog("# LF antenna: %5.2f V @ 134.00 kHz", vLf134/500.0);
PrintAndLog("# LF optimal: %5.2f V @%9.2f kHz", peakv/500.0, 12000.0/(peakf+1));
}
if (arg & FLAG_TUNE_HF)
PrintAndLog("# HF antenna: %5.2f V @ 13.56 MHz", vHf/1000.0);
#define LF_UNUSABLE_V 2948 // was 2000. Changed due to bugfix in voltage measurements. LF results are now 47% higher.
#define LF_MARGINAL_V 14739 // was 10000. Changed due to bugfix bug in voltage measurements. LF results are now 47% higher.
#define HF_UNUSABLE_V 3167 // was 2000. Changed due to bugfix in voltage measurements. HF results are now 58% higher.
#define HF_MARGINAL_V 7917 // was 5000. Changed due to bugfix in voltage measurements. HF results are now 58% higher.
#define LF_UNUSABLE_V 3000
#define LF_MARGINAL_V 15000
#define HF_UNUSABLE_V 3200
#define HF_MARGINAL_V 8000
if (peakv < LF_UNUSABLE_V)
if (arg & FLAG_TUNE_LF)
{
if (peakv<<1 < LF_UNUSABLE_V)
PrintAndLog("# Your LF antenna is unusable.");
else if (peakv < LF_MARGINAL_V)
else if (peakv<<1 < LF_MARGINAL_V)
PrintAndLog("# Your LF antenna is marginal.");
}
if (arg & FLAG_TUNE_HF)
{
if (vHf < HF_UNUSABLE_V)
PrintAndLog("# Your HF antenna is unusable.");
else if (vHf < HF_MARGINAL_V)
PrintAndLog("# Your HF antenna is marginal.");
}
if (peakv >= LF_UNUSABLE_V) {
if (peakv<<1 >= LF_UNUSABLE_V) {
for (int i = 0; i < 256; i++) {
GraphBuffer[i] = resp.d.asBytes[i] - 128;
}

View file

@ -1,5 +1,6 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// Merlok - 2017
//
// 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,18 +9,18 @@
// High frequency commands
//-----------------------------------------------------------------------------
#include "cmdhf.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "proxmark3.h"
#include "comms.h"
#include "util.h"
#include "data.h"
#include "ui.h"
#include "iso14443crc.h"
#include "parity.h"
#include "cmdmain.h"
#include "cmdparser.h"
#include "cmdhf.h"
#include "cmdhf14a.h"
#include "cmdhf14b.h"
#include "cmdhf15.h"
@ -27,9 +28,12 @@
#include "cmdhflegic.h"
#include "cmdhficlass.h"
#include "cmdhfmf.h"
#include "cmdhfmfp.h"
#include "cmdhfmfu.h"
#include "cmdhftopaz.h"
#include "protocols.h"
#include "emv/cmdemv.h"
#include "cmdhflist.h"
static int CmdHelp(const char *Cmd);
@ -40,236 +44,6 @@ int CmdHFTune(const char *Cmd)
return 0;
}
void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
switch(cmd[0])
{
case ISO14443A_CMD_WUPA: snprintf(exp,size,"WUPA"); break;
case ISO14443A_CMD_ANTICOLL_OR_SELECT:{
// 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor)
// 93 70 = Select (usage: 9370+5bytes 9320 answer - answer: 1byte SAK)
if(cmd[1] == 0x70)
{
snprintf(exp,size,"SELECT_UID"); break;
}else
{
snprintf(exp,size,"ANTICOLL"); break;
}
}
case ISO14443A_CMD_ANTICOLL_OR_SELECT_2:{
//95 20 = Anticollision of cascade level2
//95 70 = Select of cascade level2
if(cmd[2] == 0x70)
{
snprintf(exp,size,"SELECT_UID-2"); break;
}else
{
snprintf(exp,size,"ANTICOLL-2"); break;
}
}
case ISO14443A_CMD_REQA: snprintf(exp,size,"REQA"); break;
case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break;
case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break;
case ISO14443A_CMD_HALT: snprintf(exp,size,"HALT"); break;
case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break;
case MIFARE_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break;
case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break;
case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break;
case MIFARE_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break;
case MIFARE_AUTH_KEYA:{
if ( cmdsize > 3)
snprintf(exp,size,"AUTH-A(%d)",cmd[1]);
else
// case MIFARE_ULEV1_VERSION : both 0x60.
snprintf(exp,size,"EV1 VERSION");
break;
}
case MIFARE_AUTH_KEYB: snprintf(exp,size,"AUTH-B(%d)",cmd[1]); break;
case MIFARE_MAGICWUPC1: snprintf(exp,size,"MAGIC WUPC1"); break;
case MIFARE_MAGICWUPC2: snprintf(exp,size,"MAGIC WUPC2"); break;
case MIFARE_MAGICWIPEC: snprintf(exp,size,"MAGIC WIPEC"); break;
case MIFARE_ULC_AUTH_1: snprintf(exp,size,"AUTH "); break;
case MIFARE_ULC_AUTH_2: snprintf(exp,size,"AUTH_ANSW"); break;
case MIFARE_ULEV1_AUTH:
if ( cmdsize == 7 )
snprintf(exp,size,"PWD-AUTH KEY: 0x%02x%02x%02x%02x", cmd[1], cmd[2], cmd[3], cmd[4] );
else
snprintf(exp,size,"PWD-AUTH");
break;
case MIFARE_ULEV1_FASTREAD:{
if ( cmdsize >=3 && cmd[2] <= 0xE6)
snprintf(exp,size,"READ RANGE (%d-%d)",cmd[1],cmd[2]);
else
snprintf(exp,size,"?");
break;
}
case MIFARE_ULC_WRITE:{
if ( cmd[1] < 0x21 )
snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]);
else
snprintf(exp,size,"?");
break;
}
case MIFARE_ULEV1_READ_CNT:{
if ( cmd[1] < 5 )
snprintf(exp,size,"READ CNT(%d)",cmd[1]);
else
snprintf(exp,size,"?");
break;
}
case MIFARE_ULEV1_INCR_CNT:{
if ( cmd[1] < 5 )
snprintf(exp,size,"INCR(%d)",cmd[1]);
else
snprintf(exp,size,"?");
break;
}
case MIFARE_ULEV1_READSIG: snprintf(exp,size,"READ_SIG"); break;
case MIFARE_ULEV1_CHECKTEAR: snprintf(exp,size,"CHK_TEARING(%d)",cmd[1]); break;
case MIFARE_ULEV1_VCSL: snprintf(exp,size,"VCSL"); break;
default: snprintf(exp,size,"?"); break;
}
return;
}
void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
switch(cmd[0])
{
case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break;
case ICLASS_CMD_READ_OR_IDENTIFY:{
if(cmdsize > 1){
snprintf(exp,size,"READ(%d)",cmd[1]);
}else{
snprintf(exp,size,"IDENTIFY");
}
break;
}
case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break;
case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL(%d)", cmd[1]); break;
case ICLASS_CMD_READCHECK_KC:snprintf(exp,size,"READCHECK[Kc](%d)", cmd[1]); break;
case ICLASS_CMD_READCHECK_KD:snprintf(exp,size,"READCHECK[Kd](%d)", cmd[1]); break;
case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break;
case ICLASS_CMD_DETECT: snprintf(exp,size,"DETECT"); break;
case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break;
case ICLASS_CMD_UPDATE: snprintf(exp,size,"UPDATE(%d)",cmd[1]); break;
case ICLASS_CMD_ACT: snprintf(exp,size,"ACT"); break;
case ICLASS_CMD_READ4: snprintf(exp,size,"READ4(%d)",cmd[1]); break;
default: snprintf(exp,size,"?"); break;
}
return;
}
void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
if(cmd[0] == 0x26)
{
switch(cmd[1]){
case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");break;
case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");break;
default: snprintf(exp,size,"?"); break;
}
}else if(cmd[0] == 0x02)
{
switch(cmd[1])
{
case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");break;
case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");break;
case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");break;
case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");break;
case ISO15693_SELECT :snprintf(exp, size, "SELECT");break;
case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");break;
case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");break;
case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");break;
case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");break;
case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");break;
case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");break;
case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");break;
default: snprintf(exp,size,"?"); break;
}
}
}
void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
switch(cmd[0]) {
case TOPAZ_REQA :snprintf(exp, size, "REQA");break;
case TOPAZ_WUPA :snprintf(exp, size, "WUPA");break;
case TOPAZ_RID :snprintf(exp, size, "RID");break;
case TOPAZ_RALL :snprintf(exp, size, "RALL");break;
case TOPAZ_READ :snprintf(exp, size, "READ");break;
case TOPAZ_WRITE_E :snprintf(exp, size, "WRITE-E");break;
case TOPAZ_WRITE_NE :snprintf(exp, size, "WRITE-NE");break;
case TOPAZ_RSEG :snprintf(exp, size, "RSEG");break;
case TOPAZ_READ8 :snprintf(exp, size, "READ8");break;
case TOPAZ_WRITE_E8 :snprintf(exp, size, "WRITE-E8");break;
case TOPAZ_WRITE_NE8 :snprintf(exp, size, "WRITE-NE8");break;
default: snprintf(exp,size,"?"); break;
}
}
/**
06 00 = INITIATE
0E xx = SELECT ID (xx = Chip-ID)
0B = Get UID
08 yy = Read Block (yy = block number)
09 yy dd dd dd dd = Write Block (yy = block number; dd dd dd dd = data to be written)
0C = Reset to Inventory
0F = Completion
0A 11 22 33 44 55 66 = Authenticate (11 22 33 44 55 66 = data to authenticate)
**/
void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
switch(cmd[0]){
case ISO14443B_REQB : snprintf(exp,size,"REQB");break;
case ISO14443B_ATTRIB : snprintf(exp,size,"ATTRIB");break;
case ISO14443B_HALT : snprintf(exp,size,"HALT");break;
case ISO14443B_INITIATE : snprintf(exp,size,"INITIATE");break;
case ISO14443B_SELECT : snprintf(exp,size,"SELECT(%d)",cmd[1]);break;
case ISO14443B_GET_UID : snprintf(exp,size,"GET UID");break;
case ISO14443B_READ_BLK : snprintf(exp,size,"READ_BLK(%d)", cmd[1]);break;
case ISO14443B_WRITE_BLK : snprintf(exp,size,"WRITE_BLK(%d)",cmd[1]);break;
case ISO14443B_RESET : snprintf(exp,size,"RESET");break;
case ISO14443B_COMPLETION : snprintf(exp,size,"COMPLETION");break;
case ISO14443B_AUTHENTICATE : snprintf(exp,size,"AUTHENTICATE");break;
default : snprintf(exp,size ,"?");break;
}
}
/**
* @brief iso14443A_CRC_check Checks CRC in command or response
* @param isResponse
* @param data
* @param len
* @return 0 : CRC-command, CRC not ok
* 1 : CRC-command, CRC ok
* 2 : Not crc-command
*/
uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
{
uint8_t b1,b2;
if(len <= 2) return 2;
if(isResponse & (len < 6)) return 2;
ComputeCrc14443(CRC_14443_A, data, len-2, &b1, &b2);
if (b1 != data[len-2] || b2 != data[len-1]) {
return 0;
} else {
return 1;
}
}
/**
* @brief iso14443B_CRC_check Checks CRC in command or response
* @param isResponse
@ -417,6 +191,8 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
uint8_t topaz_reader_command[9];
uint32_t timestamp, first_timestamp, EndOfTransmissionTimestamp;
char explanation[30] = {0};
uint8_t mfData[32] = {0};
size_t mfDataLen = 0;
if (tracepos + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) > traceLen) return traceLen;
@ -465,6 +241,9 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
case TOPAZ:
crcStatus = iso14443B_CRC_check(isResponse, frame, data_len);
break;
case PROTO_MIFARE:
crcStatus = mifare_CRC_check(isResponse, frame, data_len);
break;
case ISO_14443A:
crcStatus = iso14443A_CRC_check(isResponse, frame, data_len);
break;
@ -513,6 +292,9 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
EndOfTransmissionTimestamp = timestamp + duration;
if (protocol == PROTO_MIFARE)
annotateMifare(explanation, sizeof(explanation), frame, data_len, parityBytes, parity_len, isResponse);
if(!isResponse)
{
switch(protocol) {
@ -542,11 +324,24 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
}
}
if (DecodeMifareData(frame, data_len, parityBytes, isResponse, mfData, &mfDataLen)) {
memset(explanation, 0x00, sizeof(explanation));
if (!isResponse) {
explanation[0] = '>';
annotateIso14443a(&explanation[1], sizeof(explanation) - 1, mfData, mfDataLen);
}
uint8_t crcc = iso14443A_CRC_check(isResponse, mfData, mfDataLen);
PrintAndLog(" | * | dec |%-64s | %-4s| %s",
sprint_hex(mfData, mfDataLen),
(crcc == 0 ? "!crc" : (crcc == 1 ? " ok " : " ")),
(true) ? explanation : "");
};
if (is_last_record(tracepos, trace, traceLen)) return traceLen;
if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) {
uint32_t next_timestamp = *((uint32_t *)(trace + tracepos));
PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d",
PrintAndLog(" %10d | %10d | %s | fdt (Frame Delay Time): %d",
(EndOfTransmissionTimestamp - first_timestamp),
(next_timestamp - first_timestamp),
" ",
@ -559,29 +354,60 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
int CmdHFList(const char *Cmd)
{
#ifdef WITH_SMARTCARD
PrintAndLog("TEST_WITH_SMARTCARD");
#endif
#ifdef WITH_TEST
PrintAndLog("TEST_WITH_TEST");
#endif
bool showWaitCycles = false;
bool markCRCBytes = false;
bool loadFromFile = false;
bool saveToFile = false;
char param1 = '\0';
char param2 = '\0';
char param3 = '\0';
char type[40] = {0};
int tlen = param_getstr(Cmd,0,type);
char param1 = param_getchar(Cmd, 1);
char param2 = param_getchar(Cmd, 2);
bool errors = false;
char filename[FILE_PATH_SIZE] = {0};
uint8_t protocol = 0;
//Validate params
// parse command line
int tlen = param_getstr(Cmd, 0, type, sizeof(type));
if (param_getlength(Cmd, 1) == 1) {
param1 = param_getchar(Cmd, 1);
} else {
param_getstr(Cmd, 1, filename, sizeof(filename));
}
if (param_getlength(Cmd, 2) == 1) {
param2 = param_getchar(Cmd, 2);
} else if (strlen(filename) == 0) {
param_getstr(Cmd, 2, filename, sizeof(filename));
}
if (param_getlength(Cmd, 3) == 1) {
param3 = param_getchar(Cmd, 3);
} else if (strlen(filename) == 0) {
param_getstr(Cmd, 3, filename, sizeof(filename));
}
// Validate param1
bool errors = false;
if(tlen == 0) {
errors = true;
}
if(param1 == 'h'
|| (param1 != 0 && param1 != 'f' && param1 != 'c')
|| (param2 != 0 && param2 != 'f' && param2 != 'c')) {
|| (param1 != 0 && param1 != 'f' && param1 != 'c' && param1 != 'l')
|| (param2 != 0 && param2 != 'f' && param2 != 'c' && param2 != 'l')
|| (param3 != 0 && param3 != 'f' && param3 != 'c' && param3 != 'l')) {
errors = true;
}
if(!errors) {
if(strcmp(type, "iclass") == 0) {
protocol = ICLASS;
} else if(strcmp(type, "mf") == 0) {
protocol = PROTO_MIFARE;
} else if(strcmp(type, "14a") == 0) {
protocol = ISO_14443A;
} else if(strcmp(type, "14b") == 0) {
@ -590,46 +416,96 @@ int CmdHFList(const char *Cmd)
protocol = TOPAZ;
} else if(strcmp(type,"raw") == 0) {
protocol = -1; //No crc, no annotations
} else if (strcmp(type, "save") == 0) {
saveToFile = true;
} else {
errors = true;
}
}
if (param1 == 'f' || param2 == 'f' || param3 == 'f') {
showWaitCycles = true;
}
if (param1 == 'c' || param2 == 'c' || param3 == 'c') {
markCRCBytes = true;
}
if (param1 == 'l' || param2 == 'l' || param3 == 'l') {
loadFromFile = true;
}
if ((loadFromFile || saveToFile) && strlen(filename) == 0) {
errors = true;
}
if (loadFromFile && saveToFile) {
errors = true;
}
if (errors) {
PrintAndLog("List protocol data in trace buffer.");
PrintAndLog("Usage: hf list <protocol> [f][c]");
PrintAndLog("List or save protocol data.");
PrintAndLog("Usage: hf list <protocol> [f] [c] [l <filename>]");
PrintAndLog(" hf list save <filename>");
PrintAndLog(" f - show frame delay times as well");
PrintAndLog(" c - mark CRC bytes");
PrintAndLog(" l - load data from file instead of trace buffer");
PrintAndLog(" save - save data to file");
PrintAndLog("Supported <protocol> values:");
PrintAndLog(" raw - just show raw data without annotations");
PrintAndLog(" 14a - interpret data as iso14443a communications");
PrintAndLog(" mf - interpret data as iso14443a communications and decrypt crypto1 stream");
PrintAndLog(" 14b - interpret data as iso14443b communications");
PrintAndLog(" iclass - interpret data as iclass communications");
PrintAndLog(" topaz - interpret data as topaz communications");
PrintAndLog("");
PrintAndLog("example: hf list 14a f");
PrintAndLog("example: hf list iclass");
PrintAndLog("example: hf list save myCardTrace.trc");
PrintAndLog("example: hf list 14a l myCardTrace.trc");
return 0;
}
if (param1 == 'f' || param2 == 'f') {
showWaitCycles = true;
}
if (param1 == 'c' || param2 == 'c') {
markCRCBytes = true;
}
uint8_t *trace;
uint16_t tracepos = 0;
trace = malloc(USB_CMD_DATA_SIZE);
uint32_t tracepos = 0;
uint32_t traceLen = 0;
if (loadFromFile) {
#define TRACE_CHUNK_SIZE (1<<16) // 64K to start with. Will be enough for BigBuf and some room for future extensions
FILE *tracefile = NULL;
size_t bytes_read;
trace = malloc(TRACE_CHUNK_SIZE);
if (trace == NULL) {
PrintAndLog("Cannot allocate memory for trace");
return 2;
}
if ((tracefile = fopen(filename,"rb")) == NULL) {
PrintAndLog("Could not open file %s", filename);
free(trace);
return 0;
}
while (!feof(tracefile)) {
bytes_read = fread(trace+traceLen, 1, TRACE_CHUNK_SIZE, tracefile);
traceLen += bytes_read;
if (!feof(tracefile)) {
uint8_t *p = realloc(trace, traceLen + TRACE_CHUNK_SIZE);
if (p == NULL) {
PrintAndLog("Cannot allocate memory for trace");
free(trace);
fclose(tracefile);
return 2;
}
trace = p;
}
}
fclose(tracefile);
} else {
trace = malloc(USB_CMD_DATA_SIZE);
// Query for the size of the trace
UsbCommand response;
GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0);
WaitForResponse(CMD_ACK, &response);
uint16_t traceLen = response.arg[2];
GetFromBigBuf(trace, USB_CMD_DATA_SIZE, 0, &response, -1, false);
traceLen = response.arg[2];
if (traceLen > USB_CMD_DATA_SIZE) {
uint8_t *p = realloc(trace, traceLen);
if (p == NULL) {
@ -638,10 +514,20 @@ int CmdHFList(const char *Cmd)
return 2;
}
trace = p;
GetFromBigBuf(trace, traceLen, 0);
WaitForResponse(CMD_ACK, NULL);
GetFromBigBuf(trace, traceLen, 0, NULL, -1, false);
}
}
if (saveToFile) {
FILE *tracefile = NULL;
if ((tracefile = fopen(filename,"wb")) == NULL) {
PrintAndLog("Could not create file %s", filename);
return 1;
}
fwrite(trace, 1, traceLen, tracefile);
PrintAndLog("Recorded Activity (TraceLen = %d bytes) written to file %s", traceLen, filename);
fclose(tracefile);
} else {
PrintAndLog("Recorded Activity (TraceLen = %d bytes)", traceLen);
PrintAndLog("");
PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
@ -651,10 +537,12 @@ int CmdHFList(const char *Cmd)
PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Annotation |");
PrintAndLog("------------|------------|-----|-----------------------------------------------------------------|-----|--------------------|");
ClearAuthData();
while(tracepos < traceLen)
{
tracepos = printTraceLine(tracepos, traceLen, trace, protocol, showWaitCycles, markCRCBytes);
}
}
free(trace);
return 0;
@ -663,7 +551,7 @@ int CmdHFList(const char *Cmd)
int CmdHFSearch(const char *Cmd){
int ans = 0;
PrintAndLog("");
ans = CmdHF14AReader("s");
ans = CmdHF14AInfo("s");
if (ans > 0) {
PrintAndLog("\nValid ISO14443A Tag Found - Quiting Search\n");
return ans;
@ -703,10 +591,12 @@ static command_t CommandTable[] =
{"14b", CmdHF14B, 1, "{ ISO14443B RFIDs... }"},
{"15", CmdHF15, 1, "{ ISO15693 RFIDs... }"},
{"epa", CmdHFEPA, 1, "{ German Identification Card... }"},
{"emv", CmdHFEMV, 1, "{ EMV cards... }"},
{"legic", CmdHFLegic, 0, "{ LEGIC RFIDs... }"},
{"iclass", CmdHFiClass, 1, "{ ICLASS RFIDs... }"},
{"mf", CmdHFMF, 1, "{ MIFARE RFIDs... }"},
{"mfu", CmdHFMFUltra, 1, "{ MIFARE Ultralight RFIDs... }"},
{"mfp", CmdHFMFP, 1, "{ MIFARE Plus RFIDs... }"},
{"topaz", CmdHFTopaz, 1, "{ TOPAZ (NFC Type 1) RFIDs... }"},
{"tune", CmdHFTune, 0, "Continuously measure HF antenna tuning"},
{"list", CmdHFList, 1, "List protocol data in trace buffer"},

View file

@ -1,5 +1,5 @@
//-----------------------------------------------------------------------------
// 2011, Merlok
// 2011, 2017 Merlok
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
@ -9,27 +9,31 @@
// High frequency ISO14443A commands
//-----------------------------------------------------------------------------
#include "cmdhf14a.h"
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include "util.h"
#include "util_posix.h"
#include "iso14443crc.h"
#include "data.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "cmdparser.h"
#include "cmdhf14a.h"
#include "common.h"
#include "cmdmain.h"
#include "mifare.h"
#include "cmdhfmfu.h"
#include "mifarehost.h"
#include "cliparser/cliparser.h"
#include "emv/apduinfo.h"
#include "emv/emvcore.h"
static int CmdHelp(const char *Cmd);
static void waitCmd(uint8_t iLen);
static int waitCmd(uint8_t iLen);
// structure and database for uid -> tagtype lookups
typedef struct {
@ -37,7 +41,7 @@ typedef struct {
char* desc;
} manufactureName;
const manufactureName manufactureMapping[] = {
static const manufactureName manufactureMapping[] = {
// ID, "Vendor Country"
{ 0x01, "Motorola UK" },
{ 0x02, "ST Microelectronics SA France" },
@ -110,7 +114,6 @@ const manufactureName manufactureMapping[] = {
{ 0x00, "no tag-info available" } // must be the last entry
};
// get a product description based on the UID
// uid[8] tag uid
// returns description of the best match
@ -133,7 +136,117 @@ int CmdHF14AList(const char *Cmd)
return 0;
}
int CmdHF14AReader(const char *Cmd)
int Hf14443_4aGetCardData(iso14a_card_select_t * card) {
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
memcpy(card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
if(select_status == 0) {
PrintAndLog("E->iso14443a card select failed");
return 1;
}
if(select_status == 2) {
PrintAndLog("E->Card doesn't support iso14443-4 mode");
return 1;
}
if(select_status == 3) {
PrintAndLog("E->Card doesn't support standard iso14443-3 anticollision");
PrintAndLog("\tATQA : %02x %02x", card->atqa[1], card->atqa[0]);
return 1;
}
PrintAndLog(" UID: %s", sprint_hex(card->uid, card->uidlen));
PrintAndLog("ATQA: %02x %02x", card->atqa[1], card->atqa[0]);
PrintAndLog(" SAK: %02x [%" PRIu64 "]", card->sak, resp.arg[0]);
if(card->ats_len < 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
PrintAndLog("E-> Error ATS length(%d) : %s", card->ats_len, sprint_hex(card->ats, card->ats_len));
return 1;
}
PrintAndLog(" ATS: %s", sprint_hex(card->ats, card->ats_len));
return 0;
}
int CmdHF14AReader(const char *Cmd) {
uint32_t cm = ISO14A_CONNECT;
bool leaveSignalON = false;
CLIParserInit("hf 14a reader", "Executes ISO1443A anticollision-select group of commands.", NULL);
void* argtable[] = {
arg_param_begin,
arg_lit0("kK", "keep", "keep the field active after command executed"),
arg_lit0("xX", "drop", "just drop the signal field"),
arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"),
arg_param_end
};
if (CLIParserParseString(Cmd, argtable, arg_getsize(argtable), true)){
CLIParserFree();
return 0;
}
leaveSignalON = arg_get_lit(1);
if (arg_get_lit(2)) {
cm = cm - ISO14A_CONNECT;
}
if (arg_get_lit(3)) {
cm |= ISO14A_NO_RATS;
}
CLIParserFree();
if (leaveSignalON)
cm |= ISO14A_NO_DISCONNECT;
UsbCommand c = {CMD_READER_ISO_14443a, {cm, 0, 0}};
SendCommand(&c);
if (ISO14A_CONNECT & cm) {
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
if(select_status == 0) {
PrintAndLog("iso14443a card select failed");
return 1;
}
if(select_status == 3) {
PrintAndLog("Card doesn't support standard iso14443-3 anticollision");
PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
return 1;
}
PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
PrintAndLog(" SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]);
if(card.ats_len >= 3) { // a valid ATS consists of at least the length byte (TL) and 2 CRC bytes
PrintAndLog(" ATS : %s", sprint_hex(card.ats, card.ats_len));
}
if (leaveSignalON) {
PrintAndLog("Card is selected. You can now start sending commands");
}
}
if (!leaveSignalON) {
PrintAndLog("Field dropped.");
}
return 0;
}
int CmdHF14AInfo(const char *Cmd)
{
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
SendCommand(&c);
@ -169,10 +282,12 @@ int CmdHF14AReader(const char *Cmd)
PrintAndLog(" UID : %s", sprint_hex(card.uid, card.uidlen));
PrintAndLog("ATQA : %02x %02x", card.atqa[1], card.atqa[0]);
PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]);
PrintAndLog(" SAK : %02x [%" PRIu64 "]", card.sak, resp.arg[0]);
bool isMifareClassic = true;
switch (card.sak) {
case 0x00:
isMifareClassic = false;
//***************************************test****************
// disconnect
@ -405,26 +520,20 @@ int CmdHF14AReader(const char *Cmd)
// try to see if card responses to "chinese magic backdoor" commands.
c.cmd = CMD_MIFARE_CIDENT;
c.arg[0] = 0;
c.arg[1] = 0;
c.arg[2] = 0;
SendCommand(&c);
WaitForResponse(CMD_ACK,&resp);
(void)mfCIdentify();
uint8_t isGeneration = resp.arg[0] & 0xff;
switch( isGeneration ){
case 1: PrintAndLog("Answers to chinese magic backdoor commands (GEN 1a): YES"); break;
case 2: PrintAndLog("Answers to chinese magic backdoor commands (GEN 1b): YES"); break;
default: PrintAndLog("Answers to chinese magic backdoor commands: NO"); break;
if (isMifareClassic) {
switch(DetectClassicPrng()) {
case 0:
PrintAndLog("Prng detection: HARDENED (hardnested)");
break;
case 1:
PrintAndLog("Prng detection: WEAK");
break;
default:
PrintAndLog("Prng detection error.");
}
}
// disconnect
c.cmd = CMD_READER_ISO_14443a;
c.arg[0] = 0;
c.arg[1] = 0;
c.arg[2] = 0;
SendCommand(&c);
return select_status;
}
@ -442,7 +551,7 @@ int CmdHF14ACUIDs(const char *Cmd)
// repeat n times
for (int i = 0; i < n; i++) {
// execute anticollision procedure
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_RATS, 0, 0}};
SendCommand(&c);
UsbCommand resp;
@ -573,6 +682,236 @@ int CmdHF14ASnoop(const char *Cmd) {
return 0;
}
void DropField() {
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
SendCommand(&c);
}
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
static bool responseNum = false;
uint16_t cmdc = 0;
*dataoutlen = 0;
if (activateField) {
responseNum = false;
UsbCommand resp;
// Anticollision + SELECT card
UsbCommand ca = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_CLEAR_TRACE, 0, 0}};
SendCommand(&ca);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLog("14aRAW ERROR: Proxmark connection timeout.");
return 1;
}
// check result
if (resp.arg[0] == 0) {
PrintAndLog("14aRAW ERROR: No card in field.");
return 1;
}
if (resp.arg[0] != 1 && resp.arg[0] != 2) {
PrintAndLog("14aRAW ERROR: card not in iso14443-4. res=%d.", resp.arg[0]);
return 1;
}
if (resp.arg[0] == 2) { // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
// get ATS
UsbCommand cr = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT, 2, 0}};
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
memcpy(cr.d.asBytes, rats, 2);
SendCommand(&cr);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLog("14aRAW ERROR: Proxmark connection timeout.");
return 1;
}
if (resp.arg[0] <= 0) { // ats_len
PrintAndLog("14aRAW ERROR: Can't get ATS.");
return 1;
}
}
}
if (leaveSignalON)
cmdc |= ISO14A_NO_DISCONNECT;
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_RAW | ISO14A_APPEND_CRC | cmdc, (datainlen & 0xFFFF) + 2, 0}};
uint8_t header[] = {0x0a | responseNum, 0x00};
responseNum ^= 1;
memcpy(c.d.asBytes, header, 2);
memcpy(&c.d.asBytes[2], datain, datainlen);
SendCommand(&c);
uint8_t *recv;
UsbCommand resp;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
recv = resp.d.asBytes;
int iLen = resp.arg[0];
if(!iLen) {
PrintAndLog("14aRAW ERROR: No card response.");
return 1;
}
*dataoutlen = iLen - 2;
if (*dataoutlen < 0)
*dataoutlen = 0;
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
PrintAndLog("14aRAW ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
return 2;
}
if (recv[0] != header[0]) {
PrintAndLog("14aRAW ERROR: iso14443-4 framing error. Card send %2x must be %2x", dataout[0], header[0]);
return 2;
}
memcpy(dataout, &recv[2], *dataoutlen);
// CRC Check
if (iLen == -1) {
PrintAndLog("14aRAW ERROR: ISO 14443A CRC error.");
return 3;
}
} else {
PrintAndLog("14aRAW ERROR: Reply timeout.");
return 4;
}
return 0;
}
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
uint16_t cmdc = 0;
if (activateField) {
cmdc |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE;
}
if (leaveSignalON)
cmdc |= ISO14A_NO_DISCONNECT;
// "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 USB_CMD_DATA_SIZE=512
// timeout must be authomatically set by "get ATS"
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_APDU | cmdc, (datainlen & 0xFFFF), 0}};
memcpy(c.d.asBytes, datain, datainlen);
SendCommand(&c);
uint8_t *recv;
UsbCommand resp;
if (activateField) {
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
PrintAndLog("APDU ERROR: Proxmark connection timeout.");
return 1;
}
if (resp.arg[0] != 1) {
PrintAndLog("APDU ERROR: Proxmark error %d.", resp.arg[0]);
return 1;
}
}
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
recv = resp.d.asBytes;
int iLen = resp.arg[0];
*dataoutlen = iLen - 2;
if (*dataoutlen < 0)
*dataoutlen = 0;
if (maxdataoutlen && *dataoutlen > maxdataoutlen) {
PrintAndLog("APDU ERROR: Buffer too small(%d). Needs %d bytes", *dataoutlen, maxdataoutlen);
return 2;
}
memcpy(dataout, recv, *dataoutlen);
if(!iLen) {
PrintAndLog("APDU ERROR: No APDU response.");
return 1;
}
// check block TODO
if (iLen == -2) {
PrintAndLog("APDU ERROR: Block type mismatch.");
return 2;
}
// CRC Check
if (iLen == -1) {
PrintAndLog("APDU ERROR: ISO 14443A CRC error.");
return 3;
}
// check apdu length
if (iLen < 4) {
PrintAndLog("APDU ERROR: Small APDU response. Len=%d", iLen);
return 2;
}
} else {
PrintAndLog("APDU ERROR: Reply timeout.");
return 4;
}
return 0;
}
// ISO14443-4. 7. Half-duplex block transmission protocol
int CmdHF14AAPDU(const char *cmd) {
uint8_t data[USB_CMD_DATA_SIZE];
int datalen = 0;
bool activateField = false;
bool leaveSignalON = false;
bool decodeTLV = false;
CLIParserInit("hf 14a apdu",
"Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL)",
"Sample:\n\thf 14a apdu -st 00A404000E325041592E5359532E444446303100\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("sS", "select", "activate field and select card"),
arg_lit0("kK", "keep", "leave the signal field ON after receive response"),
arg_lit0("tT", "tlv", "executes TLV decoder if it possible"),
arg_strx1(NULL, NULL, "<APDU (hex)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, false);
activateField = arg_get_lit(1);
leaveSignalON = arg_get_lit(2);
decodeTLV = arg_get_lit(3);
// len = data + PCB(1b) + CRC(2b)
CLIGetHexBLessWithReturn(4, data, &datalen, 1 + 2);
CLIParserFree();
// PrintAndLog("---str [%d] %s", arg_get_str(4)->count, arg_get_str(4)->sval[0]);
PrintAndLog(">>>>[%s%s%s] %s", activateField ? "sel ": "", leaveSignalON ? "keep ": "", decodeTLV ? "TLV": "", sprint_hex(data, datalen));
int res = ExchangeAPDU14a(data, datalen, activateField, leaveSignalON, data, USB_CMD_DATA_SIZE, &datalen);
if (res)
return res;
PrintAndLog("<<<< %s", sprint_hex(data, datalen));
PrintAndLog("APDU response: %02x %02x - %s", data[datalen - 2], data[datalen - 1], GetAPDUCodeDescription(data[datalen - 2], data[datalen - 1]));
// TLV decoder
if (decodeTLV && datalen > 4) {
TLVPrintFromBuffer(data, datalen - 2);
}
return 0;
}
int CmdHF14ACmdRaw(const char *cmd) {
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
@ -581,102 +920,62 @@ int CmdHF14ACmdRaw(const char *cmd) {
bool power = false;
bool active = false;
bool active_select = false;
bool no_rats = false;
uint16_t numbits = 0;
bool bTimeout = false;
uint32_t timeout = 0;
bool topazmode = false;
char buf[5]="";
int i = 0;
uint8_t data[USB_CMD_DATA_SIZE];
uint16_t datalen = 0;
uint32_t temp;
int datalen = 0;
if (strlen(cmd)<2) {
PrintAndLog("Usage: hf 14a raw [-r] [-c] [-p] [-f] [-b] [-t] <number of bits> <0A 0B 0C ... hex>");
PrintAndLog(" -r do not read response");
PrintAndLog(" -c calculate and append CRC");
PrintAndLog(" -p leave the signal field ON after receive");
PrintAndLog(" -a active signal field ON without select");
PrintAndLog(" -s active signal field ON with select");
PrintAndLog(" -b number of bits to send. Useful for send partial byte");
PrintAndLog(" -t timeout in ms");
PrintAndLog(" -T use Topaz protocol to send command");
// extract parameters
CLIParserInit("hf 14a raw", "Send raw hex data to tag",
"Sample:\n"\
"\thf 14a raw -pa -b7 -t1000 52 -- execute WUPA\n"\
"\thf 14a raw -p 9320 -- anticollision\n"\
"\thf 14a raw -psc 60 00 -- select and mifare AUTH\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("rR", "nreply", "do not read response"),
arg_lit0("cC", "crc", "calculate and append CRC"),
arg_lit0("pP", "power", "leave the signal field ON after receive"),
arg_lit0("aA", "active", "active signal field ON without select"),
arg_lit0("sS", "actives", "active signal field ON with select"),
arg_int0("bB", "bits", NULL, "number of bits to send. Useful for send partial byte"),
arg_int0("t", "timeout", NULL, "timeout in ms"),
arg_lit0("T", "topaz", "use Topaz protocol to send command"),
arg_lit0("3", NULL, "ISO14443-3 select only (skip RATS)"),
arg_strx1(NULL, NULL, "<data (hex)>", NULL),
arg_param_end
};
// defaults
arg_get_int(6) = 0;
arg_get_int(7) = 0;
if (CLIParserParseString(cmd, argtable, arg_getsize(argtable), false)){
CLIParserFree();
return 0;
}
// strip
while (*cmd==' ' || *cmd=='\t') cmd++;
while (cmd[i]!='\0') {
if (cmd[i]==' ' || cmd[i]=='\t') { i++; continue; }
if (cmd[i]=='-') {
switch (cmd[i+1]) {
case 'r':
reply = false;
break;
case 'c':
crc = true;
break;
case 'p':
power = true;
break;
case 'a':
active = true;
break;
case 's':
active_select = true;
break;
case 'b':
sscanf(cmd+i+2,"%d",&temp);
numbits = temp & 0xFFFF;
i+=3;
while(cmd[i]!=' ' && cmd[i]!='\0') { i++; }
i-=2;
break;
case 't':
bTimeout = true;
sscanf(cmd+i+2,"%d",&temp);
timeout = temp;
i+=3;
while(cmd[i]!=' ' && cmd[i]!='\0') { i++; }
i-=2;
break;
case 'T':
topazmode = true;
break;
default:
PrintAndLog("Invalid option");
return 0;
}
i+=2;
continue;
}
if ((cmd[i]>='0' && cmd[i]<='9') ||
(cmd[i]>='a' && cmd[i]<='f') ||
(cmd[i]>='A' && cmd[i]<='F') ) {
buf[strlen(buf)+1]=0;
buf[strlen(buf)]=cmd[i];
i++;
if (strlen(buf)>=2) {
sscanf(buf,"%x",&temp);
data[datalen]=(uint8_t)(temp & 0xff);
*buf=0;
if (datalen > sizeof(data)-1) {
if (crc)
PrintAndLog("Buffer is full, we can't add CRC to your data");
break;
} else {
datalen++;
}
}
continue;
}
PrintAndLog("Invalid char on input");
return 0;
reply = !arg_get_lit(1);
crc = arg_get_lit(2);
power = arg_get_lit(3);
active = arg_get_lit(4);
active_select = arg_get_lit(5);
numbits = arg_get_int(6) & 0xFFFF;
timeout = arg_get_int(7);
bTimeout = (timeout > 0);
topazmode = arg_get_lit(8);
no_rats = arg_get_lit(9);
// len = data + CRC(2b)
if (CLIParamHexToBuf(arg_get_str(10), data, sizeof(data) -2, &datalen)) {
CLIParserFree();
return 1;
}
CLIParserFree();
// logic
if(crc && datalen>0 && datalen<sizeof(data)-2)
{
uint8_t first, second;
@ -691,7 +990,7 @@ int CmdHF14ACmdRaw(const char *cmd) {
if(active || active_select)
{
c.arg[0] |= ISO14A_CONNECT;
c.arg[0] |= ISO14A_CONNECT | ISO14A_CLEAR_TRACE;
if(active)
c.arg[0] |= ISO14A_NO_SELECT;
}
@ -718,6 +1017,10 @@ int CmdHF14ACmdRaw(const char *cmd) {
c.arg[0] |= ISO14A_TOPAZMODE;
}
if(no_rats) {
c.arg[0] |= ISO14A_NO_RATS;
}
// Max buffer is USB_CMD_DATA_SIZE (512)
c.arg[1] = (datalen & 0xFFFF) | ((uint32_t)numbits << 16);
memcpy(c.d.asBytes,data,datalen);
@ -725,27 +1028,36 @@ int CmdHF14ACmdRaw(const char *cmd) {
SendCommand(&c);
if (reply) {
int res = 0;
if (active_select)
waitCmd(1);
if(datalen>0)
res = waitCmd(1);
if (!res && datalen > 0)
waitCmd(0);
} // if reply
return 0;
}
static void waitCmd(uint8_t iSelect)
{
static int waitCmd(uint8_t iSelect) {
uint8_t *recv;
UsbCommand resp;
char *hexout;
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
recv = resp.d.asBytes;
uint8_t iLen = iSelect ? resp.arg[1] : resp.arg[0];
PrintAndLog("received %i octets", iLen);
uint8_t iLen = resp.arg[0];
if (iSelect){
iLen = resp.arg[1];
if (iLen){
PrintAndLog("Card selected. UID[%i]:", iLen);
} else {
PrintAndLog("Can't select card.");
}
} else {
PrintAndLog("received %i bytes:", iLen);
}
if(!iLen)
return;
return 1;
hexout = (char *)malloc(iLen * 3 + 1);
if (hexout != NULL) {
for (int i = 0; i < iLen; i++) { // data in hex
@ -755,29 +1067,31 @@ static void waitCmd(uint8_t iSelect)
free(hexout);
} else {
PrintAndLog("malloc failed your client has low memory?");
return 2;
}
} else {
PrintAndLog("timeout while waiting for reply.");
return 3;
}
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"list", CmdHF14AList, 0, "[Deprecated] List ISO 14443a history"},
{"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"},
{"reader", CmdHF14AReader, 0, "Start acting like an ISO14443 Type A reader"},
{"info", CmdHF14AInfo, 0, "Reads card and shows information about it"},
{"cuids", CmdHF14ACUIDs, 0, "<n> Collect n>0 ISO14443 Type A UIDs in one go"},
{"sim", CmdHF14ASim, 0, "<UID> -- Simulate ISO 14443a tag"},
{"snoop", CmdHF14ASnoop, 0, "Eavesdrop ISO 14443 Type A"},
{"apdu", CmdHF14AAPDU, 0, "Send an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol"},
{"raw", CmdHF14ACmdRaw, 0, "Send raw hex data to tag"},
{NULL, NULL, 0, NULL}
};
int CmdHF14A(const char *Cmd) {
// flush
WaitForResponseTimeout(CMD_ACK,NULL,100);
// parse
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}

View file

@ -13,13 +13,22 @@
#define CMDHF14A_H__
#include <stdint.h>
#include <stdbool.h>
#include "mifare.h"
int CmdHF14A(const char *Cmd);
int CmdHF14AList(const char *Cmd);
int CmdHF14AMifare(const char *Cmd);
int CmdHF14AReader(const char *Cmd);
extern int CmdHF14AInfo(const char *Cmd);
int CmdHF14ASim(const char *Cmd);
int CmdHF14ASnoop(const char *Cmd);
char* getTagInfo(uint8_t uid);
extern void DropField();
extern int Hf14443_4aGetCardData(iso14a_card_select_t * card);
extern int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
extern int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
#endif

View file

@ -8,19 +8,19 @@
// High frequency ISO14443B commands
//-----------------------------------------------------------------------------
#include "cmdhf14b.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include "iso14443crc.h"
#include "proxmark3.h"
#include "data.h"
#include "comms.h"
#include "graph.h"
#include "util.h"
#include "ui.h"
#include "cmdparser.h"
#include "cmdhf14b.h"
#include "cmdmain.h"
#include "cmdhf14a.h"

View file

@ -11,6 +11,8 @@
#ifndef CMDHF14B_H__
#define CMDHF14B_H__
#include <stdbool.h>
int CmdHF14B(const char *Cmd);
int CmdHF14BList(const char *Cmd);
int CmdHF14BInfo(const char *Cmd);

View file

@ -22,19 +22,20 @@
// the client. Signal Processing & decoding is done on the pc. This is the slowest
// variant, but offers the possibility to analyze the waveforms directly.
#include "cmdhf15.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "proxmark3.h"
#include "data.h"
#include "comms.h"
#include "graph.h"
#include "ui.h"
#include "util.h"
#include "cmdparser.h"
#include "cmdhf15.h"
#include "iso15693tools.h"
#include "protocols.h"
#include "cmdmain.h"
#define FrameSOF Iso15693FrameSOF
@ -212,9 +213,8 @@ int getUID(uint8_t *buf)
for (int retry=0;retry<3; retry++) { // don't give up the at the first try
req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
req[1]=ISO15_CMD_INVENTORY;
req[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1;
req[1] = ISO15693_INVENTORY;
req[2] = 0; // mask length
reqlen = AddCrc(req,3);
c.arg[0] = reqlen;
@ -223,7 +223,7 @@ int getUID(uint8_t *buf)
if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
recv = resp.d.asBytes;
if (resp.arg[0]>=12 && ISO15_CRC_CHECK==Crc(recv,12)) {
if (resp.arg[0]>=12 && ISO15693_CRC_CHECK==Crc(recv,12)) {
memcpy(buf,&recv[2],8);
return 1;
}
@ -268,7 +268,7 @@ static char* TagErrorStr(uint8_t error) {
case 0x02: return "The command is not recognised";
case 0x03: return "The option is not supported.";
case 0x0f: return "Unknown error.";
case 0x10: return "The specified block is not available (doesnt exist).";
case 0x10: return "The specified block is not available (doesn't exist).";
case 0x11: return "The specified block is already -locked and thus cannot be locked again";
case 0x12: return "The specified block is locked and its content cannot be changed.";
case 0x13: return "The specified block was not successfully programmed.";
@ -286,12 +286,12 @@ int CmdHF15Demod(const char *Cmd)
int i, j;
int max = 0, maxPos = 0;
int skip = 4;
int skip = 2;
if (GraphTraceLen < 1000) return 0;
if (GraphTraceLen < 2000) return 0;
// First, correlate for SOF
for (i = 0; i < 100; i++) {
for (i = 0; i < 200; i++) {
int corr = 0;
for (j = 0; j < arraylen(FrameSOF); j += skip) {
corr += FrameSOF[j] * GraphBuffer[i + (j / skip)];
@ -310,10 +310,15 @@ int CmdHF15Demod(const char *Cmd)
memset(outBuf, 0, sizeof(outBuf));
uint8_t mask = 0x01;
for (;;) {
int corr0 = 0, corr1 = 0, corrEOF = 0;
int corr0 = 0, corr00 = 0, corr01 = 0, corr1 = 0, corrEOF = 0;
for(j = 0; j < arraylen(Logic0); j += skip) {
corr0 += Logic0[j]*GraphBuffer[i+(j/skip)];
}
corr01 = corr00 = corr0;
for(j = 0; j < arraylen(Logic0); j += skip) {
corr00 += Logic0[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)];
corr01 += Logic1[j]*GraphBuffer[i+arraylen(Logic0)/skip+(j/skip)];
}
for(j = 0; j < arraylen(Logic1); j += skip) {
corr1 += Logic1[j]*GraphBuffer[i+(j/skip)];
}
@ -321,10 +326,12 @@ int CmdHF15Demod(const char *Cmd)
corrEOF += FrameEOF[j]*GraphBuffer[i+(j/skip)];
}
// Even things out by the length of the target waveform.
corr00 *= 2;
corr01 *= 2;
corr0 *= 4;
corr1 *= 4;
if (corrEOF > corr1 && corrEOF > corr0) {
if(corrEOF > corr1 && corrEOF > corr00 && corrEOF > corr01) {
PrintAndLog("EOF at %d", i);
break;
} else if (corr1 > corr0) {
@ -366,7 +373,8 @@ int CmdHF15Read(const char *Cmd)
return 0;
}
// Record Activity without enabeling carrier
// Record Activity without enabling carrier
// TODO: currently it DOES enable the carrier
int CmdHF15Record(const char *Cmd)
{
UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693};
@ -416,6 +424,7 @@ int CmdHF15Sim(const char *Cmd)
PrintAndLog("Starting simulating UID %02X %02X %02X %02X %02X %02X %02X %02X",
uid[0],uid[1],uid[2],uid[3],uid[4], uid[5], uid[6], uid[7]);
PrintAndLog("Press the button to stop simulation");
UsbCommand c = {CMD_SIMTAG_ISO_15693, {0, 0, 0}};
memcpy(c.d.asBytes,uid,8);
@ -454,9 +463,8 @@ int CmdHF15DumpMem(const char*Cmd) {
for (int retry=0; retry<5; retry++) {
req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[1]=ISO15_CMD_READ;
req[0]= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS;
req[1] = ISO15693_READBLOCK;
memcpy(&req[2],uid,8);
req[10] = blocknum;
reqlen = AddCrc(req,11);
@ -466,8 +474,8 @@ int CmdHF15DumpMem(const char*Cmd) {
if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15693_RES_ERROR)) {
retry=0;
*output=0; // reset outputstring
sprintf(output, "Block %02x ",blocknum);
@ -491,7 +499,7 @@ int CmdHF15DumpMem(const char*Cmd) {
// TODO: need fix
// if (resp.arg[0]<3)
// PrintAndLog("Lost Connection");
// else if (ISO15_CRC_CHECK!=Crc(resp.d.asBytes,resp.arg[0]))
// else if (ISO15693_CRC_CHECK!=Crc(resp.d.asBytes,resp.arg[0]))
// PrintAndLog("CRC Failed");
// else
// PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1]));
@ -539,9 +547,8 @@ int CmdHF15CmdInquiry(const char *Cmd)
uint8_t *req=c.d.asBytes;
int reqlen=0;
req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
req[1]=ISO15_CMD_INVENTORY;
req[0] = ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1;
req[1] = ISO15693_INVENTORY;
req[2] = 0; // mask length
reqlen=AddCrc(req,3);
c.arg[0] = reqlen;
@ -567,7 +574,7 @@ int CmdHF15CmdInquiry(const char *Cmd)
int CmdHF15CmdDebug( const char *cmd) {
int debug = atoi(cmd);
if (strlen(cmd) < 1) {
PrintAndLog("Usage: hf 15 cmd debug <0|1>");
PrintAndLog("Usage: hf 15 debug <0|1>");
PrintAndLog(" 0 no debugging");
PrintAndLog(" 1 turn debugging on");
return 0;
@ -698,7 +705,7 @@ int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdle
while (**cmd==' ' || **cmd=='\t') (*cmd)++;
if (strstr(*cmd,"-o")==*cmd) {
req[reqlen]=ISO15_REQ_OPTION;
req[reqlen]=ISO15693_REQ_OPTION;
(*cmd)+=2;
}
@ -713,23 +720,20 @@ int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdle
case 's':
case 'S':
// you must have selected the tag earlier
req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY | ISO15_REQ_SELECT;
req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_SELECT;
memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
reqlen += iso15cmdlen;
break;
case 'u':
case 'U':
// unaddressed mode may not be supported by all vendors
req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY;
req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH;
memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
reqlen += iso15cmdlen;
break;
case '*':
// we scan for the UID ourself
req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS;
memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
reqlen+=iso15cmdlen;
if (!getUID(uid)) {
@ -741,8 +745,7 @@ int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdle
reqlen+=8;
break;
default:
req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
req[reqlen++] |= ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS;
memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
reqlen+=iso15cmdlen;
@ -801,7 +804,7 @@ int CmdHF15CmdSysinfo(const char *Cmd) {
return 0;
}
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_SYSINFO},1);
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15693_GET_SYSTEM_INFO},1);
reqlen=c.arg[0];
reqlen=AddCrc(req,reqlen);
@ -811,8 +814,8 @@ int CmdHF15CmdSysinfo(const char *Cmd) {
if (WaitForResponseTimeout(CMD_ACK,&resp,1000) && resp.arg[0]>2) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15693_RES_ERROR)) {
*output=0; // reset outputstring
for ( i=1; i<resp.arg[0]-2; i++) {
sprintf(output+strlen(output),"%02X ",recv[i]);
@ -888,7 +891,7 @@ int CmdHF15CmdReadmulti(const char *Cmd) {
return 0;
}
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_READMULTI},1);
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15693_READ_MULTI_BLOCK},1);
reqlen=c.arg[0];
pagenum=strtol(cmd,NULL,0);
@ -912,8 +915,8 @@ int CmdHF15CmdReadmulti(const char *Cmd) {
if (WaitForResponseTimeout(CMD_ACK,&resp,1000) && resp.arg[0]>2) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15693_RES_ERROR)) {
*output=0; // reset outputstring
for ( int i=1; i<resp.arg[0]-2; i++) {
sprintf(output+strlen(output),"%02X ",recv[i]);
@ -966,7 +969,7 @@ int CmdHF15CmdRead(const char *Cmd) {
return 0;
}
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_READ},1);
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15693_READBLOCK},1);
reqlen=c.arg[0];
pagenum=strtol(cmd,NULL,0);
@ -985,8 +988,8 @@ int CmdHF15CmdRead(const char *Cmd) {
if (WaitForResponseTimeout(CMD_ACK,&resp,1000) && resp.arg[0]>2) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15693_RES_ERROR)) {
*output=0; // reset outputstring
//sprintf(output, "Block %2i ",blocknum);
for ( int i=1; i<resp.arg[0]-2; i++) {
@ -1043,7 +1046,7 @@ int CmdHF15CmdWrite(const char *Cmd) {
return 0;
}
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_WRITE},1);
prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15693_WRITEBLOCK},1);
reqlen=c.arg[0];
// *cmd -> page num ; *cmd2 -> data
@ -1078,8 +1081,8 @@ int CmdHF15CmdWrite(const char *Cmd) {
if (WaitForResponseTimeout(CMD_ACK,&resp,2000) && resp.arg[0]>2) {
recv = resp.d.asBytes;
if (ISO15_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15_RES_ERROR)) {
if (ISO15693_CRC_CHECK==Crc(recv,resp.arg[0])) {
if (!(recv[0] & ISO15693_RES_ERROR)) {
PrintAndLog("OK");
} else {
PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1]));

View file

@ -11,6 +11,8 @@
#ifndef CMDHF15_H__
#define CMDHF15_H__
#include <stdbool.h>
int CmdHF15(const char *Cmd);
int CmdHF15Demod(const char *Cmd);

View file

@ -17,7 +17,7 @@
#include <stdio.h>
#include "util.h"
#include "util_posix.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
@ -202,10 +202,7 @@ int CmdHelp(const char *Cmd)
int CmdHFEPA(const char *Cmd)
{
// flush
WaitForResponseTimeout(CMD_ACK,NULL,100);
// parse
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}

View file

@ -14,9 +14,9 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <ctype.h>
#include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
#include "data.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "cmdparser.h"
#include "cmdhficlass.h"
@ -32,6 +32,7 @@
#include "protocols.h"
#include "usb_cmd.h"
#include "cmdhfmfu.h"
#include "util_posix.h"
static int CmdHelp(const char *Cmd);
@ -51,6 +52,20 @@ typedef struct iclass_block {
uint8_t d[8];
} iclass_block_t;
int usage_hf_iclass_chk(void) {
PrintAndLog("Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag");
PrintAndLog("Usage: hf iclass chk [h|e|r] <f (*.dic)>");
PrintAndLog("Options:");
PrintAndLog("h Show this help");
PrintAndLog("f <filename> Dictionary file with default iclass keys");
PrintAndLog(" e target Elite / High security key scheme");
PrintAndLog(" r interpret dictionary file as raw (diversified keys)");
PrintAndLog("Samples:");
PrintAndLog(" hf iclass chk f default_iclass_keys.dic");
PrintAndLog(" hf iclass chk f default_iclass_keys.dic e");
return 0;
}
int xorbits_8(uint8_t val) {
uint8_t res = val ^ (val >> 1); //1st pass
res = res ^ (res >> 1); // 2nd pass
@ -278,7 +293,7 @@ int CmdHFiClassELoad(const char *Cmd) {
//File handling and reading
FILE *f;
char filename[FILE_PATH_SIZE];
if(opt == 'f' && param_getstr(Cmd, 1, filename) > 0)
if(opt == 'f' && param_getstr(Cmd, 1, filename, sizeof(filename)) > 0)
{
f = fopen(filename, "rb");
}else{
@ -384,7 +399,7 @@ int CmdHFiClassDecrypt(const char *Cmd) {
//Open the tagdump-file
FILE *f;
char filename[FILE_PATH_SIZE];
if(opt == 'f' && param_getstr(Cmd, 1, filename) > 0) {
if(opt == 'f' && param_getstr(Cmd, 1, filename, sizeof(filename)) > 0) {
f = fopen(filename, "rb");
if ( f == NULL ) {
PrintAndLog("Could not find file %s", filename);
@ -531,7 +546,7 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u
memcpy(div_key, KEY, 8);
else
HFiClassCalcDivKey(CSN, KEY, div_key, elite);
PrintAndLog("Authing with %s: %02x%02x%02x%02x%02x%02x%02x%02x", rawkey ? "raw key" : "diversified key", div_key[0],div_key[1],div_key[2],div_key[3],div_key[4],div_key[5],div_key[6],div_key[7]);
if (verbose) PrintAndLog("Authing with %s: %02x%02x%02x%02x%02x%02x%02x%02x", rawkey ? "raw key" : "diversified key", div_key[0],div_key[1],div_key[2],div_key[3],div_key[4],div_key[5],div_key[6],div_key[7]);
doMAC(CCNR, div_key, MAC);
UsbCommand resp;
@ -541,12 +556,12 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u
SendCommand(&d);
if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
{
PrintAndLog("Auth Command execute timeout");
if (verbose) PrintAndLog("Auth Command execute timeout");
return false;
}
uint8_t isOK = resp.arg[0] & 0xff;
if (!isOK) {
PrintAndLog("Authentication error");
if (verbose) PrintAndLog("Authentication error");
return false;
}
return true;
@ -605,7 +620,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
case 'c':
case 'C':
have_credit_key = true;
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 16) {
errors = param_gethex(tempStr, 0, CreditKEY, dataLen);
} else if (dataLen == 1) {
@ -629,7 +644,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
break;
case 'f':
case 'F':
fileNameLen = param_getstr(Cmd, cmdp+1, filename);
fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename));
if (fileNameLen < 1) {
PrintAndLog("No filename found after f");
errors = true;
@ -639,7 +654,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
case 'k':
case 'K':
have_debit_key = true;
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 16) {
errors = param_gethex(tempStr, 0, KEY, dataLen);
} else if (dataLen == 1) {
@ -683,7 +698,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
SendCommand(&c);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
PrintAndLog("Command execute timeout");
ul_switch_off_field();
DropField();
return 0;
}
uint8_t readStatus = resp.arg[0] & 0xff;
@ -691,7 +706,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
if(readStatus == 0){
PrintAndLog("No tag found...");
ul_switch_off_field();
DropField();
return 0;
}
if( readStatus & (FLAG_ICLASS_READER_CSN|FLAG_ICLASS_READER_CONF|FLAG_ICLASS_READER_CC)){
@ -702,12 +717,12 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
// large memory - not able to dump pages currently
if (numblks > maxBlk) numblks = maxBlk;
}
ul_switch_off_field();
DropField();
// authenticate debit key and get div_key - later store in dump block 3
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, false)){
//try twice - for some reason it sometimes fails the first time...
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, false)){
ul_switch_off_field();
DropField();
return 0;
}
}
@ -718,14 +733,14 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
SendCommand(&w);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
PrintAndLog("Command execute time-out 1");
ul_switch_off_field();
DropField();
return 1;
}
uint32_t blocksRead = resp.arg[1];
uint8_t isOK = resp.arg[0] & 0xff;
if (!isOK && !blocksRead) {
PrintAndLog("Read Block Failed");
ul_switch_off_field();
DropField();
return 0;
}
uint32_t startindex = resp.arg[2];
@ -734,20 +749,19 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
blocksRead = (sizeof(tag_data)/8) - blockno;
}
// response ok - now get bigbuf content of the dump
GetFromBigBuf(tag_data+(blockno*8), blocksRead*8, startindex);
WaitForResponse(CMD_ACK,NULL);
GetFromBigBuf(tag_data+(blockno*8), blocksRead*8, startindex, NULL, -1, false);
size_t gotBytes = blocksRead*8 + blockno*8;
// try AA2
if (have_credit_key) {
//turn off hf field before authenticating with different key
ul_switch_off_field();
DropField();
memset(MAC,0,4);
// AA2 authenticate credit key and git c_div_key - later store in dump block 4
if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false, false)){
//try twice - for some reason it sometimes fails the first time...
if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false, false)){
ul_switch_off_field();
DropField();
return 0;
}
}
@ -760,14 +774,14 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
SendCommand(&w);
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
PrintAndLog("Command execute timeout 2");
ul_switch_off_field();
DropField();
return 0;
}
uint8_t isOK = resp.arg[0] & 0xff;
blocksRead = resp.arg[1];
if (!isOK && !blocksRead) {
PrintAndLog("Read Block Failed 2");
ul_switch_off_field();
DropField();
return 0;
}
@ -777,12 +791,11 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
blocksRead = (sizeof(tag_data) - gotBytes)/8;
}
// get dumped data from bigbuf
GetFromBigBuf(tag_data+gotBytes, blocksRead*8, startindex);
WaitForResponse(CMD_ACK,NULL);
GetFromBigBuf(tag_data+gotBytes, blocksRead*8, startindex, NULL, -1, false);
gotBytes += blocksRead*8;
} else { //field is still on - turn it off...
ul_switch_off_field();
DropField();
}
}
@ -898,7 +911,7 @@ int CmdHFiClass_WriteBlock(const char *Cmd) {
break;
case 'k':
case 'K':
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 16) {
errors = param_gethex(tempStr, 0, KEY, dataLen);
} else if (dataLen == 1) {
@ -930,7 +943,7 @@ int CmdHFiClass_WriteBlock(const char *Cmd) {
if (cmdp < 6) return usage_hf_iclass_writeblock();
int ans = WriteBlock(blockno, bldata, KEY, use_credit_key, elite, rawkey, true);
ul_switch_off_field();
DropField();
return ans;
}
@ -992,7 +1005,7 @@ int CmdHFiClassCloneTag(const char *Cmd) {
break;
case 'f':
case 'F':
fileNameLen = param_getstr(Cmd, cmdp+1, filename);
fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename));
if (fileNameLen < 1) {
PrintAndLog("No filename found after f");
errors = true;
@ -1001,7 +1014,7 @@ int CmdHFiClassCloneTag(const char *Cmd) {
break;
case 'k':
case 'K':
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 16) {
errors = param_gethex(tempStr, 0, KEY, dataLen);
} else if (dataLen == 1) {
@ -1196,7 +1209,7 @@ int CmdHFiClass_ReadBlock(const char *Cmd) {
case 'k':
case 'K':
auth = true;
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 16) {
errors = param_gethex(tempStr, 0, KEY, dataLen);
} else if (dataLen == 1) {
@ -1253,7 +1266,7 @@ int CmdHFiClass_loclass(const char *Cmd) {
char fileName[255] = {0};
if(opt == 'f')
{
if(param_getstr(Cmd, 1, fileName) > 0)
if(param_getstr(Cmd, 1, fileName, sizeof(fileName)) > 0)
{
return bruteforceFileNoKeys(fileName);
}else
@ -1318,14 +1331,14 @@ int CmdHFiClassReadTagFile(const char *Cmd) {
char tempnum[5];
FILE *f;
char filename[FILE_PATH_SIZE];
if (param_getstr(Cmd, 0, filename) < 1)
if (param_getstr(Cmd, 0, filename, sizeof(filename)) < 1)
return usage_hf_iclass_readtagfile();
if (param_getstr(Cmd,1,(char *)&tempnum) < 1)
if (param_getstr(Cmd, 1, tempnum, sizeof(tempnum)) < 1)
startblock = 0;
else
sscanf(tempnum,"%d",&startblock);
if (param_getstr(Cmd,2,(char *)&tempnum) < 1)
if (param_getstr(Cmd,2, tempnum, sizeof(tempnum)) < 1)
endblock = 0;
else
sscanf(tempnum,"%d",&endblock);
@ -1458,7 +1471,7 @@ int CmdHFiClassCalcNewKey(const char *Cmd) {
return usage_hf_iclass_calc_newkey();
case 'e':
case 'E':
dataLen = param_getstr(Cmd, cmdp, tempStr);
dataLen = param_getstr(Cmd, cmdp, tempStr, sizeof(tempStr));
if (dataLen==2)
oldElite = true;
elite = true;
@ -1466,7 +1479,7 @@ int CmdHFiClassCalcNewKey(const char *Cmd) {
break;
case 'n':
case 'N':
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 16) {
errors = param_gethex(tempStr, 0, NEWKEY, dataLen);
} else if (dataLen == 1) {
@ -1485,7 +1498,7 @@ int CmdHFiClassCalcNewKey(const char *Cmd) {
break;
case 'o':
case 'O':
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 16) {
errors = param_gethex(tempStr, 0, OLDKEY, dataLen);
} else if (dataLen == 1) {
@ -1626,7 +1639,7 @@ int CmdHFiClassManageKeys(const char *Cmd) {
return usage_hf_iclass_managekeys();
case 'f':
case 'F':
fileNameLen = param_getstr(Cmd, cmdp+1, filename);
fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename));
if (fileNameLen < 1) {
PrintAndLog("No filename found after f");
errors = true;
@ -1645,7 +1658,7 @@ int CmdHFiClassManageKeys(const char *Cmd) {
case 'k':
case 'K':
operation += 3; //set key
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 16) { //ul-c or ev1/ntag key length
errors = param_gethex(tempStr, 0, KEY, dataLen);
} else {
@ -1699,10 +1712,152 @@ int CmdHFiClassManageKeys(const char *Cmd) {
return 0;
}
int CmdHFiClassCheckKeys(const char *Cmd) {
uint8_t mac[4] = {0x00,0x00,0x00,0x00};
uint8_t key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
uint8_t div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
// elite key, raw key, standard key
bool use_elite = false;
bool use_raw = false;
bool found_debit = false;
bool found_credit = false;
bool errors = false;
uint8_t cmdp = 0x00;
FILE * f;
char filename[FILE_PATH_SIZE] = {0};
uint8_t fileNameLen = 0;
char buf[17];
uint8_t *keyBlock = NULL, *p;
int keyitems = 0, keycnt = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (param_getchar(Cmd, cmdp)) {
case 'h':
case 'H':
return usage_hf_iclass_chk();
case 'f':
case 'F':
fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename));
if (fileNameLen < 1) {
PrintAndLog("No filename found after f");
errors = true;
}
cmdp += 2;
break;
case 'e':
case 'E':
use_elite = true;
cmdp++;
break;
case 'r':
case 'R':
use_raw = true;
cmdp++;
break;
default:
PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
errors = true;
break;
}
}
if (errors) return usage_hf_iclass_chk();
if ( !(f = fopen( filename , "r")) ) {
PrintAndLog("File: %s: not found or locked.", filename);
return 1;
}
while( fgets(buf, sizeof(buf), f) ){
if (strlen(buf) < 16 || buf[15] == '\n')
continue;
while (fgetc(f) != '\n' && !feof(f)) ; //goto next line
if( buf[0]=='#' ) continue; //The line start with # is comment, skip
if (!isxdigit(buf[0])){
PrintAndLog("File content error. '%s' must include 16 HEX symbols",buf);
continue;
}
buf[16] = 0;
p = realloc(keyBlock, 8 * (keyitems += 64));
if (!p) {
PrintAndLog("Cannot allocate memory for default keys");
free(keyBlock);
fclose(f);
return 2;
}
keyBlock = p;
memset(keyBlock + 8 * keycnt, 0, 8);
num_to_bytes(strtoull(buf, NULL, 16), 8, keyBlock + 8 * keycnt);
//PrintAndLog("check key[%2d] %016" PRIx64, keycnt, bytes_to_num(keyBlock + 8*keycnt, 8));
keycnt++;
memset(buf, 0, sizeof(buf));
}
fclose(f);
PrintAndLog("Loaded %2d keys from %s", keycnt, filename);
// time
uint64_t t1 = msclock();
for (uint32_t c = 0; c < keycnt; c += 1) {
printf("."); fflush(stdout);
if (ukbhit()) {
int gc = getchar(); (void)gc;
printf("\naborted via keyboard!\n");
break;
}
memcpy(key, keyBlock + 8 * c , 8);
// debit key. try twice
for (int foo = 0; foo < 2 && !found_debit; foo++) {
if (!select_and_auth(key, mac, div_key, false, use_elite, use_raw, false))
continue;
// key found.
PrintAndLog("\n--------------------------------------------------------");
PrintAndLog(" Found AA1 debit key\t\t[%s]", sprint_hex(key, 8));
found_debit = true;
}
// credit key. try twice
for (int foo = 0; foo < 2 && !found_credit; foo++) {
if (!select_and_auth(key, mac, div_key, true, use_elite, use_raw, false))
continue;
// key found
PrintAndLog("\n--------------------------------------------------------");
PrintAndLog(" Found AA2 credit key\t\t[%s]", sprint_hex(key, 8));
found_credit = true;
}
// both keys found.
if ( found_debit && found_credit )
break;
}
t1 = msclock() - t1;
PrintAndLog("\nTime in iclass checkkeys: %.0f seconds\n", (float)t1/1000.0);
DropField();
free(keyBlock);
PrintAndLog("");
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"calcnewkey", CmdHFiClassCalcNewKey, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"},
{"chk", CmdHFiClassCheckKeys, 0, " Check keys"},
{"clone", CmdHFiClassCloneTag, 0, "[options..] Authenticate and Clone from iClass bin file"},
{"decrypt", CmdHFiClassDecrypt, 1, "[f <fname>] Decrypt tagdump" },
{"dump", CmdHFiClassReader_Dump, 0, "[options..] Authenticate and Dump iClass tag's AA1"},
@ -1723,6 +1878,7 @@ static command_t CommandTable[] =
int CmdHFiClass(const char *Cmd)
{
clearCommandBuffer();
CmdsParse(CommandTable, Cmd);
return 0;
}

View file

@ -34,6 +34,7 @@ int CmdHFiClassSnoop(const char *Cmd);
int CmdHFiClassSim(const char *Cmd);
int CmdHFiClassWriteKeyFile(const char *Cmd);
int CmdHFiClass_WriteBlock(const char *Cmd);
int CmdHFiClassCheckKeys(const char *Cmd);
void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize);
void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite);
#endif

View file

@ -8,16 +8,17 @@
// High frequency Legic commands
//-----------------------------------------------------------------------------
#include "cmdhflegic.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "proxmark3.h"
#include "data.h"
#include "comms.h"
#include "ui.h"
#include "cmdparser.h"
#include "cmdhflegic.h"
#include "cmdmain.h"
#include "util.h"
static int CmdHelp(const char *Cmd);
static command_t CommandTable[] =
@ -27,7 +28,7 @@ static command_t CommandTable[] =
{"reader", CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"},
{"save", CmdLegicSave, 0, "<filename> [<length>] -- Store samples"},
{"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
{"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
{"sim", CmdLegicRfSim, 0, "[tagtype, 0:MIM22, 1:MIM256, 2:MIM1024] Start tag simulator (use after load or read)"},
{"write", CmdLegicRfWrite,0, "<offset> <length> -- Write sample buffer (user after load or read)"},
{"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
{NULL, NULL, 0, NULL}
@ -64,8 +65,7 @@ int CmdLegicDecode(const char *Cmd)
char token_type[4];
// copy data from proxmark into buffer
GetFromBigBuf(data_buf,sizeof(data_buf),0);
WaitForResponse(CMD_ACK,NULL);
GetFromBigBuf(data_buf, sizeof(data_buf), 0, NULL, -1, false);
// Output CDF System area (9 bytes) plus remaining header area (12 bytes)
@ -294,8 +294,7 @@ int CmdLegicSave(const char *Cmd)
return -1;
}
GetFromBigBuf(got,requested,offset);
WaitForResponse(CMD_ACK,NULL);
GetFromBigBuf(got, requested, offset, NULL, -1, false);
for (int j = 0; j < requested; j += 8) {
fprintf(f, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
@ -321,10 +320,8 @@ int CmdLegicSave(const char *Cmd)
int CmdLegicRfSim(const char *Cmd)
{
UsbCommand c={CMD_SIMULATE_TAG_LEGIC_RF};
c.arg[0] = 6;
c.arg[1] = 3;
c.arg[2] = 0;
sscanf(Cmd, " %" SCNi64 " %" SCNi64 " %" SCNi64, &c.arg[0], &c.arg[1], &c.arg[2]);
c.arg[0] = 1;
sscanf(Cmd, " %" SCNi64, &c.arg[0]);
SendCommand(&c);
return 0;
}

606
client/cmdhflist.c Normal file
View file

@ -0,0 +1,606 @@
//-----------------------------------------------------------------------------
// Copyright (C) Merlok - 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Command: hf mf list. It shows data from arm buffer.
//-----------------------------------------------------------------------------
#include "cmdhflist.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "util.h"
#include "ui.h"
#include "iso14443crc.h"
#include "parity.h"
#include "protocols.h"
#include "crapto1/crapto1.h"
#include "mifarehost.h"
#include "mifaredefault.h"
enum MifareAuthSeq {
masNone,
masNt,
masNrAr,
masAt,
masAuthComplete,
masFirstData,
masData,
masError,
};
static enum MifareAuthSeq MifareAuthState;
static TAuthData AuthData;
void ClearAuthData() {
AuthData.uid = 0;
AuthData.nt = 0;
AuthData.first_auth = true;
AuthData.ks2 = 0;
AuthData.ks3 = 0;
}
/**
* @brief iso14443A_CRC_check Checks CRC in command or response
* @param isResponse
* @param data
* @param len
* @return 0 : CRC-command, CRC not ok
* 1 : CRC-command, CRC ok
* 2 : Not crc-command
*/
uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
{
uint8_t b1,b2;
if(len <= 2) return 2;
if(isResponse & (len < 6)) return 2;
ComputeCrc14443(CRC_14443_A, data, len-2, &b1, &b2);
if (b1 != data[len-2] || b2 != data[len-1]) {
return 0;
} else {
return 1;
}
}
uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len)
{
switch(MifareAuthState) {
case masNone:
case masError:
return iso14443A_CRC_check(isResponse, data, len);
default:
return 2;
}
}
void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
switch(cmd[0])
{
case ICLASS_CMD_ACTALL: snprintf(exp,size,"ACTALL"); break;
case ICLASS_CMD_READ_OR_IDENTIFY:{
if(cmdsize > 1){
snprintf(exp,size,"READ(%d)",cmd[1]);
}else{
snprintf(exp,size,"IDENTIFY");
}
break;
}
case ICLASS_CMD_SELECT: snprintf(exp,size,"SELECT"); break;
case ICLASS_CMD_PAGESEL: snprintf(exp,size,"PAGESEL(%d)", cmd[1]); break;
case ICLASS_CMD_READCHECK_KC:snprintf(exp,size,"READCHECK[Kc](%d)", cmd[1]); break;
case ICLASS_CMD_READCHECK_KD:snprintf(exp,size,"READCHECK[Kd](%d)", cmd[1]); break;
case ICLASS_CMD_CHECK: snprintf(exp,size,"CHECK"); break;
case ICLASS_CMD_DETECT: snprintf(exp,size,"DETECT"); break;
case ICLASS_CMD_HALT: snprintf(exp,size,"HALT"); break;
case ICLASS_CMD_UPDATE: snprintf(exp,size,"UPDATE(%d)",cmd[1]); break;
case ICLASS_CMD_ACT: snprintf(exp,size,"ACT"); break;
case ICLASS_CMD_READ4: snprintf(exp,size,"READ4(%d)",cmd[1]); break;
default: snprintf(exp,size,"?"); break;
}
return;
}
void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
if(cmd[0] == 0x26)
{
switch(cmd[1]){
case ISO15693_INVENTORY :snprintf(exp, size, "INVENTORY");break;
case ISO15693_STAYQUIET :snprintf(exp, size, "STAY_QUIET");break;
default: snprintf(exp,size,"?"); break;
}
}else if(cmd[0] == 0x02)
{
switch(cmd[1])
{
case ISO15693_READBLOCK :snprintf(exp, size, "READBLOCK");break;
case ISO15693_WRITEBLOCK :snprintf(exp, size, "WRITEBLOCK");break;
case ISO15693_LOCKBLOCK :snprintf(exp, size, "LOCKBLOCK");break;
case ISO15693_READ_MULTI_BLOCK :snprintf(exp, size, "READ_MULTI_BLOCK");break;
case ISO15693_SELECT :snprintf(exp, size, "SELECT");break;
case ISO15693_RESET_TO_READY :snprintf(exp, size, "RESET_TO_READY");break;
case ISO15693_WRITE_AFI :snprintf(exp, size, "WRITE_AFI");break;
case ISO15693_LOCK_AFI :snprintf(exp, size, "LOCK_AFI");break;
case ISO15693_WRITE_DSFID :snprintf(exp, size, "WRITE_DSFID");break;
case ISO15693_LOCK_DSFID :snprintf(exp, size, "LOCK_DSFID");break;
case ISO15693_GET_SYSTEM_INFO :snprintf(exp, size, "GET_SYSTEM_INFO");break;
case ISO15693_READ_MULTI_SECSTATUS :snprintf(exp, size, "READ_MULTI_SECSTATUS");break;
default: snprintf(exp,size,"?"); break;
}
}
}
void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
switch(cmd[0]) {
case TOPAZ_REQA :snprintf(exp, size, "REQA");break;
case TOPAZ_WUPA :snprintf(exp, size, "WUPA");break;
case TOPAZ_RID :snprintf(exp, size, "RID");break;
case TOPAZ_RALL :snprintf(exp, size, "RALL");break;
case TOPAZ_READ :snprintf(exp, size, "READ");break;
case TOPAZ_WRITE_E :snprintf(exp, size, "WRITE-E");break;
case TOPAZ_WRITE_NE :snprintf(exp, size, "WRITE-NE");break;
case TOPAZ_RSEG :snprintf(exp, size, "RSEG");break;
case TOPAZ_READ8 :snprintf(exp, size, "READ8");break;
case TOPAZ_WRITE_E8 :snprintf(exp, size, "WRITE-E8");break;
case TOPAZ_WRITE_NE8 :snprintf(exp, size, "WRITE-NE8");break;
default: snprintf(exp,size,"?"); break;
}
}
/**
06 00 = INITIATE
0E xx = SELECT ID (xx = Chip-ID)
0B = Get UID
08 yy = Read Block (yy = block number)
09 yy dd dd dd dd = Write Block (yy = block number; dd dd dd dd = data to be written)
0C = Reset to Inventory
0F = Completion
0A 11 22 33 44 55 66 = Authenticate (11 22 33 44 55 66 = data to authenticate)
**/
void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
switch(cmd[0]){
case ISO14443B_REQB : snprintf(exp,size,"REQB");break;
case ISO14443B_ATTRIB : snprintf(exp,size,"ATTRIB");break;
case ISO14443B_HALT : snprintf(exp,size,"HALT");break;
case ISO14443B_INITIATE : snprintf(exp,size,"INITIATE");break;
case ISO14443B_SELECT : snprintf(exp,size,"SELECT(%d)",cmd[1]);break;
case ISO14443B_GET_UID : snprintf(exp,size,"GET UID");break;
case ISO14443B_READ_BLK : snprintf(exp,size,"READ_BLK(%d)", cmd[1]);break;
case ISO14443B_WRITE_BLK : snprintf(exp,size,"WRITE_BLK(%d)",cmd[1]);break;
case ISO14443B_RESET : snprintf(exp,size,"RESET");break;
case ISO14443B_COMPLETION : snprintf(exp,size,"COMPLETION");break;
case ISO14443B_AUTHENTICATE : snprintf(exp,size,"AUTHENTICATE");break;
default : snprintf(exp,size ,"?");break;
}
}
void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
{
switch(cmd[0])
{
case ISO14443A_CMD_WUPA:
snprintf(exp,size,"WUPA");
break;
case ISO14443A_CMD_ANTICOLL_OR_SELECT:{
// 93 20 = Anticollision (usage: 9320 - answer: 4bytes UID+1byte UID-bytes-xor)
// 93 70 = Select (usage: 9370+5bytes 9320 answer - answer: 1byte SAK)
if(cmd[1] == 0x70)
{
snprintf(exp,size,"SELECT_UID"); break;
}else
{
snprintf(exp,size,"ANTICOLL"); break;
}
}
case ISO14443A_CMD_ANTICOLL_OR_SELECT_2:{
//95 20 = Anticollision of cascade level2
//95 70 = Select of cascade level2
if(cmd[2] == 0x70)
{
snprintf(exp,size,"SELECT_UID-2"); break;
}else
{
snprintf(exp,size,"ANTICOLL-2"); break;
}
}
case ISO14443A_CMD_REQA:
snprintf(exp,size,"REQA");
break;
case ISO14443A_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break;
case ISO14443A_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break;
case ISO14443A_CMD_HALT:
snprintf(exp,size,"HALT");
MifareAuthState = masNone;
break;
case ISO14443A_CMD_RATS: snprintf(exp,size,"RATS"); break;
case MIFARE_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break;
case MIFARE_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break;
case MIFARE_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break;
case MIFARE_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break;
case MIFARE_AUTH_KEYA:
if ( cmdsize > 3) {
snprintf(exp,size,"AUTH-A(%d)",cmd[1]);
MifareAuthState = masNt;
} else {
// case MIFARE_ULEV1_VERSION : both 0x60.
snprintf(exp,size,"EV1 VERSION");
}
break;
case MIFARE_AUTH_KEYB:
MifareAuthState = masNt;
snprintf(exp,size,"AUTH-B(%d)",cmd[1]);
break;
case MIFARE_MAGICWUPC1: snprintf(exp,size,"MAGIC WUPC1"); break;
case MIFARE_MAGICWUPC2: snprintf(exp,size,"MAGIC WUPC2"); break;
case MIFARE_MAGICWIPEC: snprintf(exp,size,"MAGIC WIPEC"); break;
case MIFARE_ULC_AUTH_1: snprintf(exp,size,"AUTH "); break;
case MIFARE_ULC_AUTH_2: snprintf(exp,size,"AUTH_ANSW"); break;
case MIFARE_ULEV1_AUTH:
if ( cmdsize == 7 )
snprintf(exp,size,"PWD-AUTH KEY: 0x%02x%02x%02x%02x", cmd[1], cmd[2], cmd[3], cmd[4] );
else
snprintf(exp,size,"PWD-AUTH");
break;
case MIFARE_ULEV1_FASTREAD:{
if ( cmdsize >=3 && cmd[2] <= 0xE6)
snprintf(exp,size,"READ RANGE (%d-%d)",cmd[1],cmd[2]);
else
snprintf(exp,size,"?");
break;
}
case MIFARE_ULC_WRITE:{
if ( cmd[1] < 0x21 )
snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]);
else
snprintf(exp,size,"?");
break;
}
case MIFARE_ULEV1_READ_CNT:{
if ( cmd[1] < 5 )
snprintf(exp,size,"READ CNT(%d)",cmd[1]);
else
snprintf(exp,size,"?");
break;
}
case MIFARE_ULEV1_INCR_CNT:{
if ( cmd[1] < 5 )
snprintf(exp,size,"INCR(%d)",cmd[1]);
else
snprintf(exp,size,"?");
break;
}
case MIFARE_ULEV1_READSIG: snprintf(exp,size,"READ_SIG"); break;
case MIFARE_ULEV1_CHECKTEAR: snprintf(exp,size,"CHK_TEARING(%d)",cmd[1]); break;
case MIFARE_ULEV1_VCSL: snprintf(exp,size,"VCSL"); break;
default: snprintf(exp,size,"?"); break;
}
return;
}
void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8_t* parity, uint8_t paritysize, bool isResponse) {
if (!isResponse && cmdsize == 1) {
switch(cmd[0]) {
case ISO14443A_CMD_WUPA:
case ISO14443A_CMD_REQA:
MifareAuthState = masNone;
break;
default:
break;
}
}
// get UID
if (MifareAuthState == masNone) {
if (cmdsize == 9 && cmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && cmd[1] == 0x70) {
ClearAuthData();
AuthData.uid = bytes_to_num(&cmd[2], 4);
}
if (cmdsize == 9 && cmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && cmd[1] == 0x70) {
ClearAuthData();
AuthData.uid = bytes_to_num(&cmd[2], 4);
}
}
switch(MifareAuthState) {
case masNt:
if (cmdsize == 4 && isResponse) {
snprintf(exp,size,"AUTH: nt %s", (AuthData.first_auth) ? "" : "(enc)");
MifareAuthState = masNrAr;
if (AuthData.first_auth) {
AuthData.nt = bytes_to_num(cmd, 4);
} else {
AuthData.nt_enc = bytes_to_num(cmd, 4);
AuthData.nt_enc_par = parity[0];
}
return;
} else {
MifareAuthState = masError;
}
break;
case masNrAr:
if (cmdsize == 8 && !isResponse) {
snprintf(exp,size,"AUTH: nr ar (enc)");
MifareAuthState = masAt;
AuthData.nr_enc = bytes_to_num(cmd, 4);
AuthData.ar_enc = bytes_to_num(&cmd[4], 4);
AuthData.ar_enc_par = parity[0] << 4;
return;
} else {
MifareAuthState = masError;
}
break;
case masAt:
if (cmdsize == 4 && isResponse) {
snprintf(exp,size,"AUTH: at (enc)");
MifareAuthState = masAuthComplete;
AuthData.at_enc = bytes_to_num(cmd, 4);
AuthData.at_enc_par = parity[0];
return;
} else {
MifareAuthState = masError;
}
break;
default:
break;
}
if (!isResponse && ((MifareAuthState == masNone) || (MifareAuthState == masError)))
annotateIso14443a(exp, size, cmd, cmdsize);
}
bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen) {
static struct Crypto1State *traceCrypto1;
static uint64_t mfLastKey;
*mfDataLen = 0;
if (MifareAuthState == masAuthComplete) {
if (traceCrypto1) {
crypto1_destroy(traceCrypto1);
traceCrypto1 = NULL;
}
MifareAuthState = masFirstData;
return false;
}
if (cmdsize > 32)
return false;
if (MifareAuthState == masFirstData) {
if (AuthData.first_auth) {
AuthData.ks2 = AuthData.ar_enc ^ prng_successor(AuthData.nt, 64);
AuthData.ks3 = AuthData.at_enc ^ prng_successor(AuthData.nt, 96);
mfLastKey = GetCrypto1ProbableKey(&AuthData);
PrintAndLog(" | * | key | probable key:%012"PRIx64" Prng:%s ks2:%08x ks3:%08x | |",
mfLastKey,
validate_prng_nonce(AuthData.nt) ? "WEAK": "HARD",
AuthData.ks2,
AuthData.ks3);
AuthData.first_auth = false;
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3);
} else {
if (traceCrypto1) {
crypto1_destroy(traceCrypto1);
traceCrypto1 = NULL;
}
// check last used key
if (mfLastKey) {
if (NestedCheckKey(mfLastKey, &AuthData, cmd, cmdsize, parity)) {
PrintAndLog(" | * | key | last used key:%012"PRIx64" ks2:%08x ks3:%08x | |",
mfLastKey,
AuthData.ks2,
AuthData.ks3);
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3);
};
}
// check default keys
if (!traceCrypto1) {
for (int defaultKeyCounter = 0; defaultKeyCounter < MifareDefaultKeysSize; defaultKeyCounter++){
if (NestedCheckKey(MifareDefaultKeys[defaultKeyCounter], &AuthData, cmd, cmdsize, parity)) {
PrintAndLog(" | * | key | default key:%012"PRIx64" ks2:%08x ks3:%08x | |",
MifareDefaultKeys[defaultKeyCounter],
AuthData.ks2,
AuthData.ks3);
mfLastKey = MifareDefaultKeys[defaultKeyCounter];
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3);
break;
};
}
}
// nested
if (!traceCrypto1 && validate_prng_nonce(AuthData.nt)) {
uint32_t ntx = prng_successor(AuthData.nt, 90);
for (int i = 0; i < 16383; i++) {
ntx = prng_successor(ntx, 1);
if (NTParityChk(&AuthData, ntx)){
uint32_t ks2 = AuthData.ar_enc ^ prng_successor(ntx, 64);
uint32_t ks3 = AuthData.at_enc ^ prng_successor(ntx, 96);
struct Crypto1State *pcs = lfsr_recovery64(ks2, ks3);
memcpy(mfData, cmd, cmdsize);
mf_crypto1_decrypt(pcs, mfData, cmdsize, 0);
crypto1_destroy(pcs);
if (CheckCrypto1Parity(cmd, cmdsize, mfData, parity) && CheckCrc14443(CRC_14443_A, mfData, cmdsize)) {
AuthData.ks2 = ks2;
AuthData.ks3 = ks3;
AuthData.nt = ntx;
mfLastKey = GetCrypto1ProbableKey(&AuthData);
PrintAndLog(" | * | key | nested probable key:%012"PRIx64" ks2:%08x ks3:%08x | |",
mfLastKey,
AuthData.ks2,
AuthData.ks3);
traceCrypto1 = lfsr_recovery64(AuthData.ks2, AuthData.ks3);
break;
}
}
}
}
//hardnested
if (!traceCrypto1) {
printf("hardnested not implemented. uid:%x nt:%x ar_enc:%x at_enc:%x\n", AuthData.uid, AuthData.nt, AuthData.ar_enc, AuthData.at_enc);
MifareAuthState = masError;
/* TOO SLOW( needs to have more strong filter. with this filter - aprox 4 mln tests
uint32_t t = msclock();
uint32_t t1 = t;
int n = 0;
for (uint32_t i = 0; i < 0xFFFFFFFF; i++) {
if (NTParityChk(&AuthData, i)){
uint32_t ks2 = AuthData.ar_enc ^ prng_successor(i, 64);
uint32_t ks3 = AuthData.at_enc ^ prng_successor(i, 96);
struct Crypto1State *pcs = lfsr_recovery64(ks2, ks3);
n++;
if (!(n % 100000)) {
printf("delta=%d n=%d ks2=%x ks3=%x \n", msclock() - t1 , n, ks2, ks3);
t1 = msclock();
}
}
}
printf("delta=%d n=%d\n", msclock() - t, n);
*/
}
}
MifareAuthState = masData;
}
if (MifareAuthState == masData && traceCrypto1) {
memcpy(mfData, cmd, cmdsize);
mf_crypto1_decrypt(traceCrypto1, mfData, cmdsize, 0);
*mfDataLen = cmdsize;
}
return *mfDataLen > 0;
}
bool NTParityChk(TAuthData *ad, uint32_t ntx) {
if (
(oddparity8(ntx >> 8 & 0xff) ^ (ntx & 0x01) ^ ((ad->nt_enc_par >> 5) & 0x01) ^ (ad->nt_enc & 0x01)) ||
(oddparity8(ntx >> 16 & 0xff) ^ (ntx >> 8 & 0x01) ^ ((ad->nt_enc_par >> 6) & 0x01) ^ (ad->nt_enc >> 8 & 0x01)) ||
(oddparity8(ntx >> 24 & 0xff) ^ (ntx >> 16 & 0x01) ^ ((ad->nt_enc_par >> 7) & 0x01) ^ (ad->nt_enc >> 16 & 0x01))
)
return false;
uint32_t ar = prng_successor(ntx, 64);
if (
(oddparity8(ar >> 8 & 0xff) ^ (ar & 0x01) ^ ((ad->ar_enc_par >> 5) & 0x01) ^ (ad->ar_enc & 0x01)) ||
(oddparity8(ar >> 16 & 0xff) ^ (ar >> 8 & 0x01) ^ ((ad->ar_enc_par >> 6) & 0x01) ^ (ad->ar_enc >> 8 & 0x01)) ||
(oddparity8(ar >> 24 & 0xff) ^ (ar >> 16 & 0x01) ^ ((ad->ar_enc_par >> 7) & 0x01) ^ (ad->ar_enc >> 16 & 0x01))
)
return false;
uint32_t at = prng_successor(ntx, 96);
if (
(oddparity8(ar & 0xff) ^ (at >> 24 & 0x01) ^ ((ad->ar_enc_par >> 4) & 0x01) ^ (ad->at_enc >> 24 & 0x01)) ||
(oddparity8(at >> 8 & 0xff) ^ (at & 0x01) ^ ((ad->at_enc_par >> 5) & 0x01) ^ (ad->at_enc & 0x01)) ||
(oddparity8(at >> 16 & 0xff) ^ (at >> 8 & 0x01) ^ ((ad->at_enc_par >> 6) & 0x01) ^ (ad->at_enc >> 8 & 0x01)) ||
(oddparity8(at >> 24 & 0xff) ^ (at >> 16 & 0x01) ^ ((ad->at_enc_par >> 7) & 0x01) ^ (ad->at_enc >> 16 & 0x01))
)
return false;
return true;
}
bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity) {
uint8_t buf[32] = {0};
struct Crypto1State *pcs;
AuthData.ks2 = 0;
AuthData.ks3 = 0;
pcs = crypto1_create(key);
uint32_t nt1 = crypto1_word(pcs, ad->nt_enc ^ ad->uid, 1) ^ ad->nt_enc;
uint32_t ar = prng_successor(nt1, 64);
uint32_t at = prng_successor(nt1, 96);
crypto1_word(pcs, ad->nr_enc, 1);
// uint32_t nr1 = crypto1_word(pcs, ad->nr_enc, 1) ^ ad->nr_enc; // if needs deciphered nr
uint32_t ar1 = crypto1_word(pcs, 0, 0) ^ ad->ar_enc;
uint32_t at1 = crypto1_word(pcs, 0, 0) ^ ad->at_enc;
if (!(ar == ar1 && at == at1 && NTParityChk(ad, nt1))) {
crypto1_destroy(pcs);
return false;
}
memcpy(buf, cmd, cmdsize);
mf_crypto1_decrypt(pcs, buf, cmdsize, 0);
crypto1_destroy(pcs);
if (!CheckCrypto1Parity(cmd, cmdsize, buf, parity))
return false;
if(!CheckCrc14443(CRC_14443_A, buf, cmdsize))
return false;
AuthData.nt = nt1;
AuthData.ks2 = AuthData.ar_enc ^ ar;
AuthData.ks3 = AuthData.at_enc ^ at;
return true;
}
bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc) {
for (int i = 0; i < cmdsize - 1; i++) {
if (oddparity8(cmd[i]) ^ (cmd[i + 1] & 0x01) ^ ((parity_enc[i / 8] >> (7 - i % 8)) & 0x01) ^ (cmd_enc[i + 1] & 0x01))
return false;
}
return true;
}
uint64_t GetCrypto1ProbableKey(TAuthData *ad) {
struct Crypto1State *revstate = lfsr_recovery64(ad->ks2, ad->ks3);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, 0, 0);
lfsr_rollback_word(revstate, ad->nr_enc, 1);
lfsr_rollback_word(revstate, ad->uid ^ ad->nt, 0);
uint64_t lfsr = 0;
crypto1_get_lfsr(revstate, &lfsr);
crypto1_destroy(revstate);
return lfsr;
}

47
client/cmdhflist.h Normal file
View file

@ -0,0 +1,47 @@
//-----------------------------------------------------------------------------
// Copyright (C) Merlok - 2017
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Command: hf mf list. It shows data from arm buffer.
//-----------------------------------------------------------------------------
#ifndef CMDHFLIST_H
#define CMDHFLIST_H
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint32_t uid; // UID
uint32_t nt; // tag challenge
uint32_t nt_enc; // encrypted tag challenge
uint8_t nt_enc_par; // encrypted tag challenge parity
uint32_t nr_enc; // encrypted reader challenge
uint32_t ar_enc; // encrypted reader response
uint8_t ar_enc_par; // encrypted reader response parity
uint32_t at_enc; // encrypted tag response
uint8_t at_enc_par; // encrypted tag response parity
bool first_auth; // is first authentication
uint32_t ks2; // ar ^ ar_enc
uint32_t ks3; // at ^ at_enc
} TAuthData;
extern void ClearAuthData();
extern uint8_t iso14443A_CRC_check(bool isResponse, uint8_t* data, uint8_t len);
extern uint8_t mifare_CRC_check(bool isResponse, uint8_t* data, uint8_t len);
extern void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateIso15693(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateTopaz(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateIso14443b(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize);
extern void annotateMifare(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize, uint8_t* parity, uint8_t paritysize, bool isResponse);
extern bool DecodeMifareData(uint8_t *cmd, uint8_t cmdsize, uint8_t *parity, bool isResponse, uint8_t *mfData, size_t *mfDataLen);
extern bool NTParityChk(TAuthData *ad, uint32_t ntx);
extern bool NestedCheckKey(uint64_t key, TAuthData *ad, uint8_t *cmd, uint8_t cmdsize, uint8_t *parity);
extern bool CheckCrypto1Parity(uint8_t *cmd_enc, uint8_t cmdsize, uint8_t *cmd, uint8_t *parity_enc);
extern uint64_t GetCrypto1ProbableKey(TAuthData *ad);
#endif // CMDHFLIST

File diff suppressed because it is too large Load diff

View file

@ -11,6 +11,8 @@
#ifndef CMDHFMF_H__
#define CMDHFMF_H__
#include "mifaredefault.h"
extern int CmdHFMF(const char *Cmd);
extern int CmdHF14AMfDbg(const char* cmd);
@ -34,6 +36,7 @@ extern int CmdHF14AMfELoad(const char* cmd);
extern int CmdHF14AMfESave(const char* cmd);
extern int CmdHF14AMfECFill(const char* cmd);
extern int CmdHF14AMfEKeyPrn(const char* cmd);
extern int CmdHF14AMfCWipe(const char* cmd);
extern int CmdHF14AMfCSetUID(const char* cmd);
extern int CmdHF14AMfCSetBlk(const char* cmd);
extern int CmdHF14AMfCGetBlk(const char* cmd);

View file

@ -25,6 +25,7 @@
#include <locale.h>
#include <math.h>
#include "proxmark3.h"
#include "comms.h"
#include "cmdmain.h"
#include "ui.h"
#include "util.h"
@ -32,6 +33,7 @@
#include "crapto1/crapto1.h"
#include "parity.h"
#include "hardnested/hardnested_bruteforce.h"
#include "hardnested/hardnested_bf_core.h"
#include "hardnested/hardnested_bitarray_core.h"
#include "zlib.h"
@ -71,27 +73,32 @@ static float brute_force_per_second;
static void get_SIMD_instruction_set(char* instruction_set) {
#if defined (__i386__) || defined (__x86_64__)
#if !defined(__APPLE__) || (defined(__APPLE__) && (__clang_major__ > 8 || __clang_major__ == 8 && __clang_minor__ >= 1))
#if (__GNUC__ >= 5) && (__GNUC__ > 5 || __GNUC_MINOR__ > 2)
if (__builtin_cpu_supports("avx512f")) strcpy(instruction_set, "AVX512F");
else if (__builtin_cpu_supports("avx2")) strcpy(instruction_set, "AVX2");
#else
if (__builtin_cpu_supports("avx2")) strcpy(instruction_set, "AVX2");
#endif
else if (__builtin_cpu_supports("avx")) strcpy(instruction_set, "AVX");
else if (__builtin_cpu_supports("sse2")) strcpy(instruction_set, "SSE2");
else if (__builtin_cpu_supports("mmx")) strcpy(instruction_set, "MMX");
else
#endif
#endif
switch(GetSIMDInstrAuto()) {
case SIMD_AVX512:
strcpy(instruction_set, "AVX512F");
break;
case SIMD_AVX2:
strcpy(instruction_set, "AVX2");
break;
case SIMD_AVX:
strcpy(instruction_set, "AVX");
break;
case SIMD_SSE2:
strcpy(instruction_set, "SSE2");
break;
case SIMD_MMX:
strcpy(instruction_set, "MMX");
break;
default:
strcpy(instruction_set, "no");
break;
}
}
static void print_progress_header(void) {
char progress_text[80];
char instr_set[12] = "";
char instr_set[12] = {0};
get_SIMD_instruction_set(instr_set);
sprintf(progress_text, "Start using %d threads and %s SIMD core", num_CPUs(), instr_set);
PrintAndLog("\n\n");
@ -144,12 +151,6 @@ static inline void set_bit24(uint32_t *bitarray, uint32_t index)
}
static inline void clear_bit24(uint32_t *bitarray, uint32_t index)
{
bitarray[index>>5] &= ~(0x80000000>>(index&0x0000001f));
}
static inline uint32_t test_bit24(uint32_t *bitarray, uint32_t index)
{
return bitarray[index>>5] & (0x80000000>>(index&0x0000001f));
@ -190,40 +191,6 @@ static inline uint32_t next_state(uint32_t *bitarray, uint32_t state)
}
static inline uint32_t next_not_state(uint32_t *bitarray, uint32_t state)
{
if (++state == 1<<24) return 1<<24;
uint32_t index = state >> 5;
uint_fast8_t bit = state & 0x1f;
uint32_t line = bitarray[index] << bit;
while (bit <= 0x1f) {
if ((line & 0x80000000) == 0) return state;
state++;
bit++;
line <<= 1;
}
index++;
while (bitarray[index] == 0xffffffff && state < 1<<24) {
index++;
state += 0x20;
}
if (state >= 1<<24) return 1<<24;
#if defined __GNUC__
return state + __builtin_clz(~bitarray[index]);
#else
bit = 0x00;
line = bitarray[index];
while (bit <= 0x1f) {
if ((line & 0x80000000) == 0) return state;
state++;
bit++;
line <<= 1;
}
return 1<<24;
#endif
}
#define BITFLIP_2ND_BYTE 0x0200
@ -309,7 +276,6 @@ static void init_bitflip_bitarrays(void)
if (bytesread != filesize) {
printf("File read error with %s. Aborting...\n", state_file_name);
fclose(statesfile);
inflateEnd(&compressed_stream);
exit(5);
}
fclose(statesfile);
@ -1192,7 +1158,13 @@ static bool timeout(void)
}
static void *check_for_BitFlipProperties_thread(void *args)
static void
#ifdef __has_attribute
#if __has_attribute(force_align_arg_pointer)
__attribute__((force_align_arg_pointer))
#endif
#endif
*check_for_BitFlipProperties_thread(void *args)
{
uint8_t first_byte = ((uint8_t *)args)[0];
uint8_t last_byte = ((uint8_t *)args)[1];
@ -1940,7 +1912,13 @@ static void init_book_of_work(void)
}
static void *generate_candidates_worker_thread(void *args)
static void
#ifdef __has_attribute
#if __has_attribute(force_align_arg_pointer)
__attribute__((force_align_arg_pointer))
#endif
#endif
*generate_candidates_worker_thread(void *args)
{
uint16_t *sum_args = (uint16_t *)args;
uint16_t sum_a0 = sums[sum_args[0]];
@ -2529,6 +2507,10 @@ int mfnestedhard(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBloc
{
char progress_text[80];
char instr_set[12] = {0};
get_SIMD_instruction_set(instr_set);
PrintAndLog("Using %s SIMD core.", instr_set);
srand((unsigned) time(NULL));
brute_force_per_second = brute_force_benchmark();
write_stats = false;

759
client/cmdhfmfp.c Normal file
View file

@ -0,0 +1,759 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 Merlok
// Copyright (C) 2018 drHatson
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Plus commands
//-----------------------------------------------------------------------------
#include "cmdhfmfp.h"
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "comms.h"
#include "cmdmain.h"
#include "util.h"
#include "ui.h"
#include "cmdhf14a.h"
#include "mifare.h"
#include "mifare4.h"
#include "cliparser/cliparser.h"
#include "polarssl/libpcrypto.h"
static const uint8_t DefaultKey[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
typedef struct {
uint8_t Code;
const char *Description;
} PlusErrorsElm;
static const PlusErrorsElm PlusErrors[] = {
{0xFF, ""},
{0x00, "Transfer cannot be granted within the current authentication."},
{0x06, "Access Conditions not fulfilled. Block does not exist, block is not a value block."},
{0x07, "Too many read or write commands in the session or in the transaction."},
{0x08, "Invalid MAC in command or response"},
{0x09, "Block Number is not valid"},
{0x0a, "Invalid block number, not existing block number"},
{0x0b, "The current command code not available at the current card state."},
{0x0c, "Length error"},
{0x0f, "General Manipulation Error. Failure in the operation of the PICC (cannot write to the data block), etc."},
{0x90, "OK"},
};
int PlusErrorsLen = sizeof(PlusErrors) / sizeof(PlusErrorsElm);
const char * GetErrorDescription(uint8_t errorCode) {
for(int i = 0; i < PlusErrorsLen; i++)
if (errorCode == PlusErrors[i].Code)
return PlusErrors[i].Description;
return PlusErrors[0].Description;
}
static int CmdHelp(const char *Cmd);
static bool VerboseMode = false;
void SetVerboseMode(bool verbose) {
VerboseMode = verbose;
}
int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
if(VerboseMode)
PrintAndLog(">>> %s", sprint_hex(datain, datainlen));
int res = ExchangeRAW14a(datain, datainlen, activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
if(VerboseMode)
PrintAndLog("<<< %s", sprint_hex(dataout, *dataoutlen));
return res;
}
int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00};
memmove(&rcmd[3], key, 16);
return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
}
int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
uint8_t rcmd[1] = {0xaa};
return intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
}
int MFPReadBlock(mf4Session *session, bool plain, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
uint8_t rcmd[4 + 8] = {(plain?(0x37):(0x33)), blockNum, 0x00, blockCount};
if (!plain && session)
CalculateMAC(session, mtypReadCmd, blockNum, blockCount, rcmd, 4, &rcmd[4], VerboseMode);
int res = intExchangeRAW14aPlus(rcmd, plain?4:sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
if(res)
return res;
if (session)
session->R_Ctr++;
if(session && mac && *dataoutlen > 11)
CalculateMAC(session, mtypReadResp, blockNum, blockCount, dataout, *dataoutlen - 8 - 2, mac, VerboseMode);
return 0;
}
int MFPWriteBlock(mf4Session *session, uint8_t blockNum, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
uint8_t rcmd[1 + 2 + 16 + 8] = {0xA3, blockNum, 0x00};
memmove(&rcmd[3], data, 16);
if (session)
CalculateMAC(session, mtypWriteCmd, blockNum, 1, rcmd, 19, &rcmd[19], VerboseMode);
int res = intExchangeRAW14aPlus(rcmd, sizeof(rcmd), activateField, leaveSignalON, dataout, maxdataoutlen, dataoutlen);
if(res)
return res;
if (session)
session->W_Ctr++;
if(session && mac && *dataoutlen > 3)
CalculateMAC(session, mtypWriteResp, blockNum, 1, dataout, *dataoutlen, mac, VerboseMode);
return 0;
}
int CmdHFMFPInfo(const char *cmd) {
if (cmd && strlen(cmd) > 0)
PrintAndLog("WARNING: command don't have any parameters.\n");
// info about 14a part
CmdHF14AInfo("");
// Mifare Plus info
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
SendCommand(&c);
UsbCommand resp;
WaitForResponse(CMD_ACK,&resp);
iso14a_card_select_t card;
memcpy(&card, (iso14a_card_select_t *)resp.d.asBytes, sizeof(iso14a_card_select_t));
uint64_t select_status = resp.arg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision
if (select_status == 1 || select_status == 2) {
PrintAndLog("----------------------------------------------");
PrintAndLog("Mifare Plus info:");
// MIFARE Type Identification Procedure
// https://www.nxp.com/docs/en/application-note/AN10833.pdf
uint16_t ATQA = card.atqa[0] + (card.atqa[1] << 8);
if (ATQA == 0x0004) PrintAndLog("ATQA: Mifare Plus 2k 4bUID");
if (ATQA == 0x0002) PrintAndLog("ATQA: Mifare Plus 4k 4bUID");
if (ATQA == 0x0044) PrintAndLog("ATQA: Mifare Plus 2k 7bUID");
if (ATQA == 0x0042) PrintAndLog("ATQA: Mifare Plus 4k 7bUID");
uint8_t SLmode = 0xff;
if (card.sak == 0x08) {
PrintAndLog("SAK: Mifare Plus 2k 7bUID");
if (select_status == 2) SLmode = 1;
}
if (card.sak == 0x18) {
PrintAndLog("SAK: Mifare Plus 4k 7bUID");
if (select_status == 2) SLmode = 1;
}
if (card.sak == 0x10) {
PrintAndLog("SAK: Mifare Plus 2k");
if (select_status == 2) SLmode = 2;
}
if (card.sak == 0x11) {
PrintAndLog("SAK: Mifare Plus 4k");
if (select_status == 2) SLmode = 2;
}
if (card.sak == 0x20) {
PrintAndLog("SAK: Mifare Plus SL0/SL3 or Mifare desfire");
if (card.ats_len > 0) {
SLmode = 3;
// check SL0
uint8_t data[250] = {0};
int datalen = 0;
// https://github.com/Proxmark/proxmark3/blob/master/client/scripts/mifarePlus.lua#L161
uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00};
int res = ExchangeRAW14a(cmd, sizeof(cmd), false, false, data, sizeof(data), &datalen);
if (!res && datalen > 1 && data[0] == 0x09) {
SLmode = 0;
}
}
}
if (SLmode != 0xff)
PrintAndLog("Mifare Plus SL mode: SL%d", SLmode);
else
PrintAndLog("Mifare Plus SL mode: unknown(");
} else {
PrintAndLog("Mifare Plus info not available.");
}
DropField();
return 0;
}
int CmdHFMFPWritePerso(const char *cmd) {
uint8_t keyNum[64] = {0};
int keyNumLen = 0;
uint8_t key[64] = {0};
int keyLen = 0;
CLIParserInit("hf mfp wrp",
"Executes Write Perso command. Can be used in SL0 mode only.",
"Usage:\n\thf mfp wrp 4000 000102030405060708090a0b0c0d0e0f -> write key (00..0f) to key number 4000 \n"
"\thf mfp wrp 4000 -> write default key(0xff..0xff) to key number 4000");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_str1(NULL, NULL, "<HEX key number (2b)>", NULL),
arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
CLIGetHexWithReturn(2, keyNum, &keyNumLen);
CLIGetHexWithReturn(3, key, &keyLen);
CLIParserFree();
SetVerboseMode(verbose);
if (!keyLen) {
memmove(key, DefaultKey, 16);
keyLen = 16;
}
if (keyNumLen != 2) {
PrintAndLog("Key number length must be 2 bytes instead of: %d", keyNumLen);
return 1;
}
if (keyLen != 16) {
PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
return 1;
}
uint8_t data[250] = {0};
int datalen = 0;
int res = MFPWritePerso(keyNum, key, true, false, data, sizeof(data), &datalen);
if (res) {
PrintAndLog("Exchange error: %d", res);
return res;
}
if (datalen != 3) {
PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
return 1;
}
if (data[0] != 0x90) {
PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0]));
return 1;
}
PrintAndLog("Write OK.");
return 0;
}
uint16_t CardAddresses[] = {0x9000, 0x9001, 0x9002, 0x9003, 0x9004, 0xA000, 0xA001, 0xA080, 0xA081, 0xC000, 0xC001};
int CmdHFMFPInitPerso(const char *cmd) {
int res;
uint8_t key[256] = {0};
int keyLen = 0;
uint8_t keyNum[2] = {0};
uint8_t data[250] = {0};
int datalen = 0;
CLIParserInit("hf mfp initp",
"Executes Write Perso command for all card's keys. Can be used in SL0 mode only.",
"Usage:\n\thf mfp initp 000102030405060708090a0b0c0d0e0f -> fill all the keys with key (00..0f)\n"
"\thf mfp initp -vv -> fill all the keys with default key(0xff..0xff) and show all the data exchange");
void* argtable[] = {
arg_param_begin,
arg_litn("vV", "verbose", 0, 2, "show internal data."),
arg_strx0(NULL, NULL, "<HEX key (16b)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
bool verbose2 = arg_get_lit(1) > 1;
CLIGetHexWithReturn(2, key, &keyLen);
CLIParserFree();
if (keyLen && keyLen != 16) {
PrintAndLog("Key length must be 16 bytes instead of: %d", keyLen);
return 1;
}
if (!keyLen)
memmove(key, DefaultKey, 16);
SetVerboseMode(verbose2);
for (uint16_t sn = 0x4000; sn < 0x4050; sn++) {
keyNum[0] = sn >> 8;
keyNum[1] = sn & 0xff;
res = MFPWritePerso(keyNum, key, (sn == 0x4000), true, data, sizeof(data), &datalen);
if (!res && (datalen == 3) && data[0] == 0x09) {
PrintAndLog("2k card detected.");
break;
}
if (res || (datalen != 3) || data[0] != 0x90) {
PrintAndLog("Write error on address %04x", sn);
break;
}
}
SetVerboseMode(verbose);
for (int i = 0; i < sizeof(CardAddresses) / 2; i++) {
keyNum[0] = CardAddresses[i] >> 8;
keyNum[1] = CardAddresses[i] & 0xff;
res = MFPWritePerso(keyNum, key, false, true, data, sizeof(data), &datalen);
if (!res && (datalen == 3) && data[0] == 0x09) {
PrintAndLog("Skipped[%04x]...", CardAddresses[i]);
} else {
if (res || (datalen != 3) || data[0] != 0x90) {
PrintAndLog("Write error on address %04x", CardAddresses[i]);
break;
}
}
}
DropField();
if (res)
return res;
PrintAndLog("Done.");
return 0;
}
int CmdHFMFPCommitPerso(const char *cmd) {
CLIParserInit("hf mfp commitp",
"Executes Commit Perso command. Can be used in SL0 mode only.",
"Usage:\n\thf mfp commitp -> \n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_int0(NULL, NULL, "SL mode", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
CLIParserFree();
SetVerboseMode(verbose);
uint8_t data[250] = {0};
int datalen = 0;
int res = MFPCommitPerso(true, false, data, sizeof(data), &datalen);
if (res) {
PrintAndLog("Exchange error: %d", res);
return res;
}
if (datalen != 3) {
PrintAndLog("Command must return 3 bytes instead of: %d", datalen);
return 1;
}
if (data[0] != 0x90) {
PrintAndLog("Command error: %02x %s", data[0], GetErrorDescription(data[0]));
return 1;
}
PrintAndLog("Switch level OK.");
return 0;
}
int CmdHFMFPAuth(const char *cmd) {
uint8_t keyn[250] = {0};
int keynlen = 0;
uint8_t key[250] = {0};
int keylen = 0;
CLIParserInit("hf mfp auth",
"Executes AES authentication command for Mifare Plus card",
"Usage:\n\thf mfp auth 4000 000102030405060708090a0b0c0d0e0f -> executes authentication\n"
"\thf mfp auth 9003 FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF -v -> executes authentication and shows all the system data\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_str1(NULL, NULL, "<Key Num (HEX 2 bytes)>", NULL),
arg_str1(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, true);
bool verbose = arg_get_lit(1);
CLIGetHexWithReturn(2, keyn, &keynlen);
CLIGetHexWithReturn(3, key, &keylen);
CLIParserFree();
if (keynlen != 2) {
PrintAndLog("ERROR: <Key Num> must be 2 bytes long instead of: %d", keynlen);
return 1;
}
if (keylen != 16) {
PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
return 1;
}
return MifareAuth4(NULL, keyn, key, true, false, verbose);
}
int CmdHFMFPRdbl(const char *cmd) {
uint8_t keyn[2] = {0};
uint8_t key[250] = {0};
int keylen = 0;
CLIParserInit("hf mfp rdbl",
"Reads several blocks from Mifare Plus card.",
"Usage:\n\thf mfp rdbl 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read block 0 data\n"
"\thf mfp rdbl 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_int0("nN", "count", "blocks count (by default 1).", NULL),
arg_lit0("bB", "keyb", "use key B (by default keyA)."),
arg_lit0("pP", "plain", "plain communication mode between reader and card."),
arg_int1(NULL, NULL, "<Block Num (0..255)>", NULL),
arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, false);
bool verbose = arg_get_lit(1);
int blocksCount = arg_get_int_def(2, 1);
bool keyB = arg_get_lit(3);
int plain = arg_get_lit(4);
uint32_t blockn = arg_get_int(5);
CLIGetHexWithReturn(6, key, &keylen);
CLIParserFree();
SetVerboseMode(verbose);
if (!keylen) {
memmove(key, DefaultKey, 16);
keylen = 16;
}
if (blockn > 255) {
PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockn);
return 1;
}
if (keylen != 16) {
PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
return 1;
}
// 3 blocks - wo iso14443-4 chaining
if (blocksCount > 3) {
PrintAndLog("ERROR: blocks count must be less than 3 instead of: %d", blocksCount);
return 1;
}
if (blocksCount > 1 && mfIsSectorTrailer(blockn)) {
PrintAndLog("WARNING: trailer!");
}
uint8_t sectorNum = mfSectorNum(blockn & 0xff);
uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
keyn[0] = uKeyNum >> 8;
keyn[1] = uKeyNum & 0xff;
if (verbose)
PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockn, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
mf4Session session;
int res = MifareAuth4(&session, keyn, key, true, true, verbose);
if (res) {
PrintAndLog("Authentication error: %d", res);
return res;
}
uint8_t data[250] = {0};
int datalen = 0;
uint8_t mac[8] = {0};
res = MFPReadBlock(&session, plain, blockn & 0xff, blocksCount, false, false, data, sizeof(data), &datalen, mac);
if (res) {
PrintAndLog("Read error: %d", res);
return res;
}
if (datalen && data[0] != 0x90) {
PrintAndLog("Card read error: %02x %s", data[0], GetErrorDescription(data[0]));
return 6;
}
if (datalen != 1 + blocksCount * 16 + 8 + 2) {
PrintAndLog("Error return length:%d", datalen);
return 5;
}
int indx = blockn;
for(int i = 0; i < blocksCount; i++) {
PrintAndLog("data[%03d]: %s", indx, sprint_hex(&data[1 + i * 16], 16));
indx++;
if (mfIsSectorTrailer(indx) && i != blocksCount - 1){
PrintAndLog("data[%03d]: ------------------- trailer -------------------", indx);
indx++;
}
}
if (memcmp(&data[blocksCount * 16 + 1], mac, 8)) {
PrintAndLog("WARNING: mac not equal...");
PrintAndLog("MAC card: %s", sprint_hex(&data[blocksCount * 16 + 1], 8));
PrintAndLog("MAC reader: %s", sprint_hex(mac, 8));
} else {
if(verbose)
PrintAndLog("MAC: %s", sprint_hex(&data[blocksCount * 16 + 1], 8));
}
return 0;
}
int CmdHFMFPRdsc(const char *cmd) {
uint8_t keyn[2] = {0};
uint8_t key[250] = {0};
int keylen = 0;
CLIParserInit("hf mfp rdsc",
"Reads one sector from Mifare Plus card.",
"Usage:\n\thf mfp rdsc 0 000102030405060708090a0b0c0d0e0f -> executes authentication and read sector 0 data\n"
"\thf mfp rdsc 1 -v -> executes authentication and shows sector 1 data with default key 0xFF..0xFF and some additional data\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_lit0("bB", "keyb", "use key B (by default keyA)."),
arg_lit0("pP", "plain", "plain communication mode between reader and card."),
arg_int1(NULL, NULL, "<Sector Num (0..255)>", NULL),
arg_str0(NULL, NULL, "<Key Value (HEX 16 bytes)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, false);
bool verbose = arg_get_lit(1);
bool keyB = arg_get_lit(2);
bool plain = arg_get_lit(3);
uint32_t sectorNum = arg_get_int(4);
CLIGetHexWithReturn(5, key, &keylen);
CLIParserFree();
SetVerboseMode(verbose);
if (!keylen) {
memmove(key, DefaultKey, 16);
keylen = 16;
}
if (sectorNum > 39) {
PrintAndLog("ERROR: <Sector Num> must be in range [0..39] instead of: %d", sectorNum);
return 1;
}
if (keylen != 16) {
PrintAndLog("ERROR: <Key Value> must be 16 bytes long instead of: %d", keylen);
return 1;
}
uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
keyn[0] = uKeyNum >> 8;
keyn[1] = uKeyNum & 0xff;
if (verbose)
PrintAndLog("--sector[%d]:%02x key:%04x", mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
mf4Session session;
int res = MifareAuth4(&session, keyn, key, true, true, verbose);
if (res) {
PrintAndLog("Authentication error: %d", res);
return res;
}
uint8_t data[250] = {0};
int datalen = 0;
uint8_t mac[8] = {0};
for(int n = mfFirstBlockOfSector(sectorNum); n < mfFirstBlockOfSector(sectorNum) + mfNumBlocksPerSector(sectorNum); n++) {
res = MFPReadBlock(&session, plain, n & 0xff, 1, false, true, data, sizeof(data), &datalen, mac);
if (res) {
PrintAndLog("Read error: %d", res);
DropField();
return res;
}
if (datalen && data[0] != 0x90) {
PrintAndLog("Card read error: %02x %s", data[0], GetErrorDescription(data[0]));
DropField();
return 6;
}
if (datalen != 1 + 16 + 8 + 2) {
PrintAndLog("Error return length:%d", datalen);
DropField();
return 5;
}
PrintAndLog("data[%03d]: %s", n, sprint_hex(&data[1], 16));
if (memcmp(&data[1 + 16], mac, 8)) {
PrintAndLog("WARNING: mac on block %d not equal...", n);
PrintAndLog("MAC card: %s", sprint_hex(&data[1 + 16], 8));
PrintAndLog("MAC reader: %s", sprint_hex(mac, 8));
} else {
if(verbose)
PrintAndLog("MAC: %s", sprint_hex(&data[1 + 16], 8));
}
}
DropField();
return 0;
}
int CmdHFMFPWrbl(const char *cmd) {
uint8_t keyn[2] = {0};
uint8_t key[250] = {0};
int keylen = 0;
uint8_t datain[250] = {0};
int datainlen = 0;
CLIParserInit("hf mfp wrbl",
"Writes one block to Mifare Plus card.",
"Usage:\n\thf mfp wrbl 1 ff0000000000000000000000000000ff 000102030405060708090a0b0c0d0e0f -> writes block 1 data\n"
"\thf mfp wrbl 2 ff0000000000000000000000000000ff -v -> writes block 2 data with default key 0xFF..0xFF and some additional data\n");
void* argtable[] = {
arg_param_begin,
arg_lit0("vV", "verbose", "show internal data."),
arg_lit0("bB", "keyb", "use key B (by default keyA)."),
arg_int1(NULL, NULL, "<Block Num (0..255)>", NULL),
arg_str1(NULL, NULL, "<Data (HEX 16 bytes)>", NULL),
arg_str0(NULL, NULL, "<Key (HEX 16 bytes)>", NULL),
arg_param_end
};
CLIExecWithReturn(cmd, argtable, false);
bool verbose = arg_get_lit(1);
bool keyB = arg_get_lit(2);
uint32_t blockNum = arg_get_int(3);
CLIGetHexWithReturn(4, datain, &datainlen);
CLIGetHexWithReturn(5, key, &keylen);
CLIParserFree();
SetVerboseMode(verbose);
if (!keylen) {
memmove(key, DefaultKey, 16);
keylen = 16;
}
if (blockNum > 39) {
PrintAndLog("ERROR: <Block Num> must be in range [0..255] instead of: %d", blockNum);
return 1;
}
if (keylen != 16) {
PrintAndLog("ERROR: <Key> must be 16 bytes long instead of: %d", keylen);
return 1;
}
if (datainlen != 16) {
PrintAndLog("ERROR: <Data> must be 16 bytes long instead of: %d", datainlen);
return 1;
}
uint8_t sectorNum = mfSectorNum(blockNum & 0xff);
uint16_t uKeyNum = 0x4000 + sectorNum * 2 + (keyB ? 1 : 0);
keyn[0] = uKeyNum >> 8;
keyn[1] = uKeyNum & 0xff;
if (verbose)
PrintAndLog("--block:%d sector[%d]:%02x key:%04x", blockNum & 0xff, mfNumBlocksPerSector(sectorNum), sectorNum, uKeyNum);
mf4Session session;
int res = MifareAuth4(&session, keyn, key, true, true, verbose);
if (res) {
PrintAndLog("Authentication error: %d", res);
return res;
}
uint8_t data[250] = {0};
int datalen = 0;
uint8_t mac[8] = {0};
res = MFPWriteBlock(&session, blockNum & 0xff, datain, false, false, data, sizeof(data), &datalen, mac);
if (res) {
PrintAndLog("Write error: %d", res);
DropField();
return res;
}
if (datalen != 3 && (datalen != 3 + 8)) {
PrintAndLog("Error return length:%d", datalen);
DropField();
return 5;
}
if (datalen && data[0] != 0x90) {
PrintAndLog("Card write error: %02x %s", data[0], GetErrorDescription(data[0]));
DropField();
return 6;
}
if (memcmp(&data[1], mac, 8)) {
PrintAndLog("WARNING: mac not equal...");
PrintAndLog("MAC card: %s", sprint_hex(&data[1], 8));
PrintAndLog("MAC reader: %s", sprint_hex(mac, 8));
} else {
if(verbose)
PrintAndLog("MAC: %s", sprint_hex(&data[1], 8));
}
DropField();
PrintAndLog("Write OK.");
return 0;
}
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"info", CmdHFMFPInfo, 0, "Info about Mifare Plus tag"},
{"wrp", CmdHFMFPWritePerso, 0, "Write Perso command"},
{"initp", CmdHFMFPInitPerso, 0, "Fills all the card's keys"},
{"commitp", CmdHFMFPCommitPerso, 0, "Move card to SL1 or SL3 mode"},
{"auth", CmdHFMFPAuth, 0, "Authentication"},
{"rdbl", CmdHFMFPRdbl, 0, "Read blocks"},
{"rdsc", CmdHFMFPRdsc, 0, "Read sectors"},
{"wrbl", CmdHFMFPWrbl, 0, "Write blocks"},
{NULL, NULL, 0, NULL}
};
int CmdHFMFP(const char *Cmd) {
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}
int CmdHelp(const char *Cmd) {
CmdsHelp(CommandTable);
return 0;
}

18
client/cmdhfmfp.h Normal file
View file

@ -0,0 +1,18 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2018 Merlok
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// High frequency MIFARE Plus commands
//-----------------------------------------------------------------------------
#ifndef CMDHFMFP_H__
#define CMDHFMFP_H__
#include "mifaredefault.h"
extern int CmdHFMFP(const char *Cmd);
#endif

View file

@ -12,7 +12,7 @@
#include <stdint.h>
#include <stdio.h>
#include "proxmark3.h"
#include "comms.h"
#include "usb_cmd.h"
#include "cmdmain.h"
#include "ui.h"
@ -22,7 +22,6 @@
#include "mifare.h"
#include "util.h"
#include "protocols.h"
#include "data.h"
#define MAX_UL_BLOCKS 0x0f
#define MAX_ULC_BLOCKS 0x2b
@ -108,13 +107,7 @@ char *getUlev1CardSizeStr( uint8_t fsize ){
}
static void ul_switch_on_field(void) {
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT, 0, 0}};
clearCommandBuffer();
SendCommand(&c);
}
void ul_switch_off_field(void) {
UsbCommand c = {CMD_READER_ISO_14443a, {0, 0, 0}};
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0}};
clearCommandBuffer();
SendCommand(&c);
}
@ -159,7 +152,7 @@ static int ul_select( iso14a_card_select_t *card ){
ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500);
if (!ans || resp.arg[0] < 1) {
PrintAndLog("iso14443a card select failed");
ul_switch_off_field();
DropField();
return 0;
}
@ -232,7 +225,7 @@ static int ul_auth_select( iso14a_card_select_t *card, TagTypeUL_t tagtype, bool
if (hasAuthKey) {
if (ulev1_requestAuthentication(authenticationkey, pack, packSize) < 1) {
ul_switch_off_field();
DropField();
PrintAndLog("Error: Authentication Failed UL-EV1/NTAG");
return 0;
}
@ -556,7 +549,7 @@ static int ulc_magic_test(){
} else {
returnValue = UL;
}
ul_switch_off_field();
DropField();
return returnValue;
}
*/
@ -569,7 +562,7 @@ static int ul_magic_test(){
if ( !ul_select(&card) )
return UL_ERROR;
int status = ul_comp_write(0, NULL, 0);
ul_switch_off_field();
DropField();
if ( status == 0 )
return MAGIC;
return 0;
@ -588,14 +581,14 @@ uint32_t GetHF14AMfU_Type(void){
// Ultralight - ATQA / SAK
if ( card.atqa[1] != 0x00 || card.atqa[0] != 0x44 || card.sak != 0x00 ) {
PrintAndLog("Tag is not Ultralight | NTAG | MY-D [ATQA: %02X %02X SAK: %02X]\n", card.atqa[1], card.atqa[0], card.sak);
ul_switch_off_field();
DropField();
return UL_ERROR;
}
if ( card.uid[0] != 0x05) {
len = ulev1_getVersion(version, sizeof(version));
ul_switch_off_field();
DropField();
switch (len) {
case 0x0A: {
@ -635,7 +628,7 @@ uint32_t GetHF14AMfU_Type(void){
// do UL_C check first...
uint8_t nonce[11] = {0x00};
status = ulc_requestAuthentication(nonce, sizeof(nonce));
ul_switch_off_field();
DropField();
if (status > 1) {
tagtype = UL_C;
} else {
@ -656,15 +649,15 @@ uint32_t GetHF14AMfU_Type(void){
tagtype = UNKNOWN;
}
}
ul_switch_off_field();
DropField();
}
}
if (tagtype & UL) {
tagtype = ul_fudan_check();
ul_switch_off_field();
DropField();
}
} else {
ul_switch_off_field();
DropField();
// Infinition MY-D tests Exam high nibble
uint8_t nib = (card.uid[1] & 0xf0) >> 4;
switch ( nib ){
@ -709,7 +702,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
return usage_hf_mfu_info();
case 'k':
case 'K':
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length
errors = param_gethex(tempStr, 0, authenticationkey, dataLen);
dataLen /= 2; // handled as bytes from now on
@ -751,7 +744,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
// read pages 0,1,2,3 (should read 4pages)
status = ul_read(0, data, sizeof(data));
if ( status == -1 ) {
ul_switch_off_field();
DropField();
PrintAndLog("Error: tag didn't answer to READ");
return status;
} else if (status == 16) {
@ -769,7 +762,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
status = ul_read(0x28, ulc_conf, sizeof(ulc_conf));
if ( status == -1 ){
PrintAndLog("Error: tag didn't answer to READ UL-C");
ul_switch_off_field();
DropField();
return status;
}
if (status == 16) ulc_print_configuration(ulc_conf);
@ -780,14 +773,14 @@ int CmdHF14AMfUInfo(const char *Cmd){
uint8_t ulc_deskey[16] = {0x00};
status = ul_read(0x2C, ulc_deskey, sizeof(ulc_deskey));
if ( status == -1 ) {
ul_switch_off_field();
DropField();
PrintAndLog("Error: tag didn't answer to READ magic");
return status;
}
if (status == 16) ulc_print_3deskey(ulc_deskey);
} else {
ul_switch_off_field();
DropField();
// if we called info with key, just return
if ( hasAuthKey ) return 1;
@ -822,7 +815,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
status = ulev1_readSignature( ulev1_signature, sizeof(ulev1_signature));
if ( status == -1 ) {
PrintAndLog("Error: tag didn't answer to READ SIGNATURE");
ul_switch_off_field();
DropField();
return status;
}
if (status == 32) ulev1_print_signature( ulev1_signature, sizeof(ulev1_signature));
@ -837,7 +830,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
status = ulev1_getVersion(version, sizeof(version));
if ( status == -1 ) {
PrintAndLog("Error: tag didn't answer to GETVERSION");
ul_switch_off_field();
DropField();
return status;
} else if (status == 10) {
ulev1_print_version(version);
@ -857,7 +850,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
status = ul_read(startconfigblock, ulev1_conf, sizeof(ulev1_conf));
if ( status == -1 ) {
PrintAndLog("Error: tag didn't answer to READ EV1");
ul_switch_off_field();
DropField();
return status;
} else if (status == 16) {
// save AUTHENTICATION LIMITS for later:
@ -887,7 +880,7 @@ int CmdHF14AMfUInfo(const char *Cmd){
}
}
ul_switch_off_field();
DropField();
if (locked) PrintAndLog("\nTag appears to be locked, try using the key to get more info");
PrintAndLog("");
return 1;
@ -1244,7 +1237,7 @@ int CmdHF14AMfUDump(const char *Cmd){
return usage_hf_mfu_dump();
case 'k':
case 'K':
dataLen = param_getstr(Cmd, cmdp+1, tempStr);
dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
if (dataLen == 32 || dataLen == 8) { //ul-c or ev1/ntag key length
errors = param_gethex(tempStr, 0, authenticationkey, dataLen);
dataLen /= 2;
@ -1262,7 +1255,7 @@ int CmdHF14AMfUDump(const char *Cmd){
break;
case 'n':
case 'N':
fileNlen = param_getstr(Cmd, cmdp+1, filename);
fileNlen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename));
if (!fileNlen) errors = true;
if (fileNlen > FILE_PATH_SIZE-5) fileNlen = FILE_PATH_SIZE-5;
cmdp += 2;
@ -1331,8 +1324,7 @@ int CmdHF14AMfUDump(const char *Cmd){
PrintAndLog("Data exceeded Buffer size!");
bufferSize = sizeof(data);
}
GetFromBigBuf(data, bufferSize, startindex);
WaitForResponse(CMD_ACK,NULL);
GetFromBigBuf(data, bufferSize, startindex, NULL, -1, false);
Pages = bufferSize/4;
// Load lock bytes.
@ -1842,7 +1834,7 @@ static command_t CommandTable[] =
};
int CmdHFMFUltra(const char *Cmd){
WaitForResponseTimeout(CMD_ACK,NULL,100);
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}

View file

@ -16,7 +16,6 @@ int CmdHF14AMfUInfo(const char *Cmd);
uint32_t GetHF14AMfU_Type(void);
int ul_print_type(uint32_t tagtype, uint8_t spacer);
void ul_switch_off_field(void);
int usage_hf_mfu_dump(void);
int usage_hf_mfu_info(void);

View file

@ -8,17 +8,18 @@
// High frequency Topaz (NFC Type 1) commands
//-----------------------------------------------------------------------------
#include "cmdhftopaz.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "cmdmain.h"
#include "cmdparser.h"
#include "cmdhftopaz.h"
#include "cmdhf14a.h"
#include "ui.h"
#include "mifare.h"
#include "proxmark3.h"
#include "comms.h"
#include "iso14443crc.h"
#include "protocols.h"
@ -454,7 +455,7 @@ int CmdHFTopazReader(const char *Cmd)
PrintAndLog("HR0 : %02x (%sa Topaz tag (%scapable of carrying a NDEF message), %s memory map)", rid_response[0],
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
(rid_response[0] & 0xF0) == 0x10 ? "" : "not ",
(rid_response[0] & 0x0F) == 0x10 ? "static" : "dynamic");
(rid_response[0] & 0x0F) == 0x01 ? "static" : "dynamic");
PrintAndLog("HR1 : %02x", rid_response[1]);
status = topaz_rall(uid_echo, rall_response);
@ -553,10 +554,7 @@ static command_t CommandTable[] =
int CmdHFTopaz(const char *Cmd) {
// flush
WaitForResponseTimeout(CMD_ACK,NULL,100);
// parse
(void)WaitForResponseTimeout(CMD_ACK,NULL,100);
CmdsParse(CommandTable, Cmd);
return 0;
}

View file

@ -8,17 +8,17 @@
// Hardware commands
//-----------------------------------------------------------------------------
#include "cmdhw.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "ui.h"
#include "proxmark3.h"
#include "comms.h"
#include "cmdparser.h"
#include "cmdhw.h"
#include "cmdmain.h"
#include "cmddata.h"
#include "data.h"
/* low-level hardware control */
@ -408,30 +408,19 @@ int CmdVersion(const char *Cmd)
clearCommandBuffer();
UsbCommand c = {CMD_VERSION};
static UsbCommand resp = {0, {0, 0, 0}};
UsbCommand resp = {0, {0, 0, 0}};
if (resp.arg[0] == 0 && resp.arg[1] == 0) { // no cached information available
SendCommand(&c);
if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
PrintAndLog("Prox/RFID mark3 RFID instrument");
PrintAndLog((char*)resp.d.asBytes);
lookupChipID(resp.arg[0], resp.arg[1]);
}
} else {
PrintAndLog("[[[ Cached information ]]]\n");
PrintAndLog("Prox/RFID mark3 RFID instrument");
PrintAndLog((char*)resp.d.asBytes);
lookupChipID(resp.arg[0], resp.arg[1]);
PrintAndLog("");
}
return 0;
}
int CmdStatus(const char *Cmd)
{
uint8_t speed_test_buffer[USB_CMD_DATA_SIZE];
sample_buf = speed_test_buffer;
clearCommandBuffer();
UsbCommand c = {CMD_STATUS};
SendCommand(&c);

View file

@ -8,21 +8,21 @@
// Low frequency commands
//-----------------------------------------------------------------------------
#include "cmdlf.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include "proxmark3.h"
#include "cmdlf.h"
#include "comms.h"
#include "lfdemod.h" // for psk2TOpsk1
#include "util.h" // for parsing cli command utils
#include "ui.h" // for show graph controls
#include "graph.h" // for graph data
#include "cmdparser.h" // for getting cli commands included in cmdmain.h
#include "cmdmain.h" // for sending cmds to device
#include "data.h" // for GetFromBigBuf
#include "cmddata.h" // for `lf search`
#include "cmdlfawid.h" // for awid menu
#include "cmdlfem4x.h" // for em4x menu
@ -54,26 +54,24 @@ static int CmdHelp(const char *Cmd);
int usage_lf_cmdread(void)
{
PrintAndLog("Usage: lf cmdread d <delay period> z <zero period> o <one period> c <cmdbytes> [H] ");
PrintAndLog("Usage: lf cmdread d <delay period> z <zero period> o <one period> c <cmdbytes> ");
PrintAndLog("Options: ");
PrintAndLog(" h This help");
PrintAndLog(" L Low frequency (125 KHz)");
PrintAndLog(" H High frequency (134 KHz)");
PrintAndLog(" d <delay> delay OFF period");
PrintAndLog(" z <zero> time period ZERO");
PrintAndLog(" o <one> time period ONE");
PrintAndLog(" d <delay> delay OFF period between bits (0 for bitbang mode)");
PrintAndLog(" z <zero> time period ZERO (antenna off in bitbang mode)");
PrintAndLog(" o <one> time period ONE (antenna on in bitbang mode)");
PrintAndLog(" c <cmd> Command bytes");
PrintAndLog(" ************* All periods in microseconds");
PrintAndLog(" ************* Use lf config to configure options.");
PrintAndLog("Examples:");
PrintAndLog(" lf cmdread d 80 z 100 o 200 c 11000");
PrintAndLog(" lf cmdread d 80 z 100 o 100 c 11000 H");
PrintAndLog(" lf cmdread d 80 z 100 o 100 c 11000");
return 0;
}
/* send a command before reading */
int CmdLFCommandRead(const char *Cmd)
{
static char dummy[3] = {0x20,0x00,0x00};
UsbCommand c = {CMD_MOD_THEN_ACQUIRE_RAW_ADC_SAMPLES_125K};
bool errors = false;
//uint8_t divisor = 95; //125khz
@ -84,16 +82,8 @@ int CmdLFCommandRead(const char *Cmd)
{
case 'h':
return usage_lf_cmdread();
case 'H':
//divisor = 88;
dummy[1]='h';
cmdp++;
break;
case 'L':
cmdp++;
break;
case 'c':
param_getstr(Cmd, cmdp+1, (char *)&c.d.asBytes);
param_getstr(Cmd, cmdp+1, (char *)&c.d.asBytes, sizeof(c.d.asBytes));
cmdp+=2;
break;
case 'd':
@ -121,11 +111,13 @@ int CmdLFCommandRead(const char *Cmd)
//Validations
if(errors) return usage_lf_cmdread();
// in case they specified 'H'
strcpy((char *)&c.d.asBytes + strlen((char *)c.d.asBytes), dummy);
clearCommandBuffer();
SendCommand(&c);
WaitForResponse(CMD_ACK,NULL);
getSamples(0, true);
return 0;
}
@ -335,7 +327,7 @@ int CmdLFSetConfig(const char *Cmd)
}
bool lf_read(bool silent, uint32_t samples) {
if (offline) return false;
if (IsOffline()) return false;
UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_125K, {silent,samples,0}};
clearCommandBuffer();
//And ship it to device
@ -491,7 +483,7 @@ int CmdLFfskSim(const char *Cmd)
uint8_t fcHigh=0, fcLow=0, clk=0;
uint8_t invert=0;
bool errors = false;
char hexData[32] = {0x00}; // store entered hex data
char hexData[64] = {0x00}; // store entered hex data
uint8_t data[255] = {0x00};
int dataLen = 0;
uint8_t cmdp = 0;
@ -522,7 +514,7 @@ int CmdLFfskSim(const char *Cmd)
// cmdp++;
// break;
case 'd':
dataLen = param_getstr(Cmd, cmdp+1, hexData);
dataLen = param_getstr(Cmd, cmdp+1, hexData, sizeof(hexData));
if (dataLen==0) {
errors=true;
} else {
@ -593,7 +585,7 @@ int CmdLFaskSim(const char *Cmd)
uint8_t encoding = 1, separator = 0;
uint8_t clk=0, invert=0;
bool errors = false;
char hexData[32] = {0x00};
char hexData[64] = {0x00};
uint8_t data[255]= {0x00}; // store entered hex data
int dataLen = 0;
uint8_t cmdp = 0;
@ -628,7 +620,7 @@ int CmdLFaskSim(const char *Cmd)
cmdp++;
break;
case 'd':
dataLen = param_getstr(Cmd, cmdp+1, hexData);
dataLen = param_getstr(Cmd, cmdp+1, hexData, sizeof(hexData));
if (dataLen==0) {
errors=true;
} else {
@ -687,7 +679,7 @@ int CmdLFpskSim(const char *Cmd)
uint8_t carrier=0, clk=0;
uint8_t invert=0;
bool errors = false;
char hexData[32] = {0x00}; // store entered hex data
char hexData[64] = {0x00}; // store entered hex data
uint8_t data[255] = {0x00};
int dataLen = 0;
uint8_t cmdp = 0;
@ -723,7 +715,7 @@ int CmdLFpskSim(const char *Cmd)
cmdp++;
break;
case 'd':
dataLen = param_getstr(Cmd, cmdp+1, hexData);
dataLen = param_getstr(Cmd, cmdp+1, hexData, sizeof(hexData));
if (dataLen==0) {
errors=true;
} else {
@ -878,7 +870,7 @@ int CmdVchDemod(const char *Cmd)
int CheckChipType(char cmdp) {
uint32_t wordData = 0;
if (offline || cmdp == '1') return 0;
if (IsOffline() || cmdp == '1') return 0;
save_restoreGB(GRAPH_SAVE);
save_restoreDB(GRAPH_SAVE);
@ -923,7 +915,7 @@ int CmdLFfind(const char *Cmd)
return 0;
}
if (!offline && (cmdp != '1')) {
if (!IsOffline() && (cmdp != '1')) {
lf_read(true, 30000);
} else if (GraphTraceLen < minLength) {
PrintAndLog("Data in Graphbuffer was too small.");
@ -939,13 +931,13 @@ int CmdLFfind(const char *Cmd)
// only run if graphbuffer is just noise as it should be for hitag/cotag
if (graphJustNoise(GraphBuffer, testLen)) {
// only run these tests if we are in online mode
if (!offline && (cmdp != '1')) {
if (!IsOffline() && (cmdp != '1')) {
// test for em4x05 in reader talk first mode.
if (EM4x05Block0Test(&wordData)) {
PrintAndLog("\nValid EM4x05/EM4x69 Chip Found\nUse lf em 4x05readword/dump commands to read\n");
return 1;
}
ans=CmdLFHitagReader("26");
ans=CmdLFHitagReader("26"); // 26 = RHT2F_UID_ONLY
if (ans==0) {
return 1;
}
@ -955,6 +947,7 @@ int CmdLFfind(const char *Cmd)
return 1;
}
}
PrintAndLog("\nNo Data Found! - maybe not an LF tag?\n");
return 0;
}

View file

@ -11,10 +11,11 @@
// FSK2a, RF/50, 96 bits (complete)
//-----------------------------------------------------------------------------
#include "cmdlfawid.h"
#include <string.h>
#include <stdio.h> // sscanf
#include "proxmark3.h" // Definitions, USB controls, etc
#include "cmdlfawid.h"
#include "comms.h" // Definitions, USB controls, etc
#include "ui.h" // PrintAndLog
#include "cmdparser.h" // CmdsParse, CmdsHelp
#include "lfdemod.h" // parityTest +

View file

@ -7,14 +7,15 @@
//-----------------------------------------------------------------------------
// Low frequency COTAG commands
//-----------------------------------------------------------------------------
#include "cmdlfcotag.h"
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "cmddata.h"
#include "data.h"
#include "cmdlfcotag.h"
#include "lfdemod.h"
#include "usb_cmd.h"
#include "cmdmain.h"
@ -99,10 +100,9 @@ int CmdCOTAGRead(const char *Cmd) {
getSamples(0, true); break;
}
case 1: {
GetFromBigBuf(DemodBuffer, COTAG_BITS, 0);
DemodBufferLen = COTAG_BITS;
UsbCommand response;
if ( !WaitForResponseTimeout(CMD_ACK, &response, 1000) ) {
DemodBufferLen = COTAG_BITS;
if (!GetFromBigBuf(DemodBuffer, COTAG_BITS, 0, &response, 1000, true)) {
PrintAndLog("timeout while waiting for reply.");
return -1;
}

View file

@ -8,14 +8,14 @@
// Low frequency EM4x commands
//-----------------------------------------------------------------------------
#include "cmdlfem4x.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "cmdlfem4x.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "util.h"
#include "data.h"
#include "graph.h"
#include "cmdparser.h"
#include "cmddata.h"
@ -335,7 +335,7 @@ int CmdEM410xBrute(const char *Cmd)
delay = param_get32ex(Cmd, 4, 1000, 10);
}
param_getstr(Cmd, 0, filename);
param_getstr(Cmd, 0, filename, sizeof(filename));
uidBlock = calloc(stUidBlock, 5);
if (uidBlock == NULL) return 1;
@ -606,7 +606,7 @@ int EM4x50Read(const char *Cmd, bool verbose)
char tmp2[20];
int phaseoff;
high = low = 0;
memset(tmpbuff, 0, MAX_GRAPH_TRACE_LEN / 64);
memset(tmpbuff, 0, sizeof(tmpbuff));
// get user entry if any
sscanf(Cmd, "%i %i", &clk, &invert);
@ -804,8 +804,7 @@ int usage_lf_em_read(void) {
bool downloadSamplesEM() {
// 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples)
uint8_t got[6000];
GetFromBigBuf(got, sizeof(got), 0);
if ( !WaitForResponseTimeout(CMD_ACK, NULL, 4000) ) {
if (!GetFromBigBuf(got, sizeof(got), 0, NULL, 4000, true)) {
PrintAndLog("command execution time out");
return false;
}
@ -950,7 +949,6 @@ int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *wordDa
}
int testLen = (GraphTraceLen < 1000) ? GraphTraceLen : 1000;
if (graphJustNoise(GraphBuffer, testLen)) {
PrintAndLog("no tag not found");
return -1;
}
//attempt demod:

View file

@ -13,7 +13,7 @@
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include "proxmark3.h"
#include "comms.h"
#include "ui.h" // for PrintAndLog
#include "util.h"
#include "cmdparser.h"

View file

@ -6,19 +6,136 @@
// the license.
//-----------------------------------------------------------------------------
// Low frequency HID commands (known)
//
// Useful resources:
// RF interface, programming a T55x7 clone, 26-bit HID H10301 encoding:
// http://www.proxmark.org/files/Documents/125%20kHz%20-%20HID/HID_format_example.pdf
//
// "Understanding Card Data Formats"
// https://www.hidglobal.com/sites/default/files/hid-understanding_card_data_formats-wp-en.pdf
//
// "What Format Do You Need?"
// https://www.hidglobal.com/sites/default/files/resource_files/hid-prox-br-en.pdf
//-----------------------------------------------------------------------------
#include "cmdlfhid.h"
#include <stdio.h>
#include <string.h>
#include "cmdlfhid.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "graph.h"
#include "cmdparser.h"
#include "cmddata.h" //for g_debugMode, demodbuff cmds
#include "lfdemod.h" // for HIDdemodFSK
#include "hidcardformats.h"
#include "hidcardformatutils.h"
#include "util.h" // for param_get8,32,64
/**
* Converts a hex string to component "hi2", "hi" and "lo" 32-bit integers, one nibble
* at a time.
*
* Returns the number of nibbles (4 bits) entered.
*/
int hexstring_to_int96(/* out */ uint32_t* hi2,/* out */ uint32_t* hi, /* out */ uint32_t* lo, const char* str) {
// TODO: Replace this with param_gethex when it supports arbitrary length
// inputs.
int n = 0, i = 0;
while (sscanf(&str[i++], "%1x", &n ) == 1) {
*hi2 = (*hi2 << 4) | (*hi >> 28);
*hi = (*hi << 4) | (*lo >> 28);
*lo = (*lo << 4) | (n & 0xf);
}
return i - 1;
}
void usage_encode(){
PrintAndLog("Usage: lf hid encode <format> [<field> <value (decimal)>] {...}");
PrintAndLog(" Fields: c: Card number");
PrintAndLog(" f: Facility code");
PrintAndLog(" i: Issue Level");
PrintAndLog(" o: OEM code");
PrintAndLog(" example: lf hid encode H10301 f 123 c 4567");
}
void PrintProxTagId(hidproxmessage_t *packed){
if (packed->top != 0) {
PrintAndLog("HID Prox TAG ID: %x%08x%08x",
(uint32_t)packed->top, (uint32_t)packed->mid, (uint32_t)packed->bot);
} else {
PrintAndLog("HID Prox TAG ID: %x%08x",
(uint32_t)packed->mid, (uint32_t)packed->bot);
}
}
bool Encode(/* in */ const char *Cmd, /* out */ hidproxmessage_t *packed){
int formatIndex = -1;
char format[16];
memset(format, 0, sizeof(format));
if (!strcmp(Cmd, "help") || !strcmp(Cmd, "h") || !strcmp(Cmd, "list") || !strcmp(Cmd, "?")){
usage_encode();
return false;
} else {
param_getstr(Cmd, 0, format, sizeof(format));
formatIndex = HIDFindCardFormat(format);
if (formatIndex == -1) {
printf("Unknown format: %s\r\n", format);
return false;
}
}
hidproxcard_t data;
memset(&data, 0, sizeof(hidproxcard_t));
uint8_t cmdp = 1;
while(param_getchar(Cmd, cmdp) != 0x00) {
switch(param_getchar(Cmd, cmdp)) {
case 'I':
case 'i':
data.IssueLevel = param_get32ex(Cmd, cmdp+1, 0, 10);
cmdp += 2;
break;
case 'F':
case 'f':
data.FacilityCode = param_get32ex(Cmd, cmdp+1, 0, 10);
cmdp += 2;
break;
case 'C':
case 'c':
data.CardNumber = param_get64ex(Cmd, cmdp+1, 0, 10);
cmdp += 2;
break;
case 'o':
case 'O':
data.OEM = param_get32ex(Cmd, cmdp+1, 0, 10);
cmdp += 2;
break;
default:
PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
return false;
}
}
memset(packed, 0, sizeof(hidproxmessage_t));
if (!HIDPack(formatIndex, &data, packed))
{
PrintAndLog("The card data could not be encoded in the selected format.");
return false;
} else {
return true;
}
}
void Write(hidproxmessage_t *packed){
UsbCommand c;
c.d.asBytes[0] = (packed->top != 0 && ((packed->mid & 0xFFFFFFC0) != 0))
? 1 : 0; // Writing long format?
c.cmd = CMD_HID_CLONE_TAG;
c.arg[0] = (packed->top & 0x000FFFFF);
c.arg[1] = packed->mid;
c.arg[2] = packed->bot;
SendCommand(&c);
}
static int CmdHelp(const char *Cmd);
//by marshmellow (based on existing demod + holiman's refactor)
//HID Prox demod - FSK RF/50 with preamble of 00011101 (then manchester encoded)
@ -54,50 +171,13 @@ int CmdFSKdemodHID(const char *Cmd)
if (g_debugMode) PrintAndLog("DEBUG: Error - no values found");
return 0;
}
if (hi2 != 0){ //extra large HID tags
PrintAndLog("HID Prox TAG ID: %x%08x%08x (%d)",
(unsigned int) hi2, (unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF);
}
else { //standard HID tags <38 bits
uint8_t fmtLen = 0;
uint32_t fc = 0;
uint32_t cardnum = 0;
if (((hi>>5)&1)==1){//if bit 38 is set then < 37 bit format is used
uint32_t lo2=0;
lo2=(((hi & 31) << 12) | (lo>>20)); //get bits 21-37 to check for format len bit
uint8_t idx3 = 1;
while(lo2>1){ //find last bit set to 1 (format len bit)
lo2=lo2>>1;
idx3++;
}
fmtLen =idx3+19;
fc =0;
cardnum=0;
if(fmtLen==26){
cardnum = (lo>>1)&0xFFFF;
fc = (lo>>17)&0xFF;
}
if(fmtLen==34){
cardnum = (lo>>1)&0xFFFF;
fc= ((hi&1)<<15)|(lo>>17);
}
if(fmtLen==35){
cardnum = (lo>>1)&0xFFFFF;
fc = ((hi&1)<<11)|(lo>>21);
}
}
else { //if bit 38 is not set then 37 bit format is used
fmtLen = 37;
fc = 0;
cardnum = 0;
if(fmtLen == 37){
cardnum = (lo>>1)&0x7FFFF;
fc = ((hi&0xF)<<12)|(lo>>20);
}
}
PrintAndLog("HID Prox TAG ID: %x%08x (%d) - Format Len: %dbit - FC: %d - Card: %d",
(unsigned int) hi, (unsigned int) lo, (unsigned int) (lo>>1) & 0xFFFF,
(unsigned int) fmtLen, (unsigned int) fc, (unsigned int) cardnum);
hidproxmessage_t packed = initialize_proxmessage_object(hi2, hi, lo);
PrintProxTagId(&packed);
bool ret = HIDTryUnpack(&packed, false);
if (!ret) {
PrintAndLog("Invalid or unsupported tag length.");
}
setDemodBuf(BitStream,BitLen,idx);
setClockGrid(50, waveIdx + (idx*50));
@ -120,67 +200,92 @@ int CmdHIDReadFSK(const char *Cmd)
int CmdHIDSim(const char *Cmd)
{
uint32_t hi = 0, lo = 0;
int n = 0, i = 0;
while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (n & 0xf);
uint32_t hi2 = 0, hi = 0, lo = 0;
hexstring_to_int96(&hi2, &hi, &lo, Cmd);
if (hi2 != 0) {
PrintAndLog("Emulating tag with ID %x%08x%08x", hi2, hi, lo);
} else {
PrintAndLog("Emulating tag with ID %x%08x", hi, lo);
}
PrintAndLog("Emulating tag with ID %x%08x", hi, lo);
PrintAndLog("Press pm3-button to abort simulation");
UsbCommand c = {CMD_HID_SIM_TAG, {hi, lo, 0}};
UsbCommand c = {CMD_HID_SIM_TAG, {hi2, hi, lo}};
SendCommand(&c);
return 0;
}
int CmdHIDClone(const char *Cmd)
{
unsigned int hi2 = 0, hi = 0, lo = 0;
int n = 0, i = 0;
UsbCommand c;
if (strchr(Cmd,'l') != 0) {
while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
hi2 = (hi2 << 4) | (hi >> 28);
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (n & 0xf);
}
PrintAndLog("Cloning tag with long ID %x%08x%08x", hi2, hi, lo);
c.d.asBytes[0] = 1;
}
else {
while (sscanf(&Cmd[i++], "%1x", &n ) == 1) {
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (n & 0xf);
}
PrintAndLog("Cloning tag with ID %x%08x", hi, lo);
hi2 = 0;
c.d.asBytes[0] = 0;
}
c.cmd = CMD_HID_CLONE_TAG;
c.arg[0] = hi2;
c.arg[1] = hi;
c.arg[2] = lo;
SendCommand(&c);
unsigned int top = 0, mid = 0, bot = 0;
hexstring_to_int96(&top, &mid, &bot, Cmd);
hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot);
Write(&packed);
return 0;
}
int CmdHIDDecode(const char *Cmd){
if (strlen(Cmd)<3) {
PrintAndLog("Usage: lf hid decode <id> {p}");
PrintAndLog(" (optional) p: Ignore invalid parity");
PrintAndLog(" sample: lf hid decode 2006f623ae");
return 0;
}
uint32_t top = 0, mid = 0, bot = 0;
bool ignoreParity = false;
hexstring_to_int96(&top, &mid, &bot, Cmd);
hidproxmessage_t packed = initialize_proxmessage_object(top, mid, bot);
char opt = param_getchar(Cmd, 1);
if (opt == 'p') ignoreParity = true;
HIDTryUnpack(&packed, ignoreParity);
return 0;
}
int CmdHIDEncode(const char *Cmd) {
if (strlen(Cmd) == 0) {
usage_encode();
return 0;
}
hidproxmessage_t packed;
memset(&packed, 0, sizeof(hidproxmessage_t));
if (Encode(Cmd, &packed))
PrintProxTagId(&packed);
return 0;
}
int CmdHIDWrite(const char *Cmd) {
if (strlen(Cmd) == 0) {
usage_encode();
return 0;
}
hidproxmessage_t packed;
memset(&packed, 0, sizeof(hidproxmessage_t));
if (Encode(Cmd, &packed)){
PrintProxTagId(&packed);
Write(&packed);
}
return 0;
}
int CmdHIDFormats(){
HIDListFormats();
return 0;
}
static int CmdHelp(const char *Cmd); // define this now so the below won't error out.
static command_t CommandTable[] =
{
{"help", CmdHelp, 1, "This help"},
{"demod", CmdFSKdemodHID, 1, "Demodulate HID Prox from GraphBuffer"},
{"read", CmdHIDReadFSK, 0, "['1'] Realtime HID FSK Read from antenna (option '1' for one tag only)"},
{"sim", CmdHIDSim, 0, "<ID> -- HID tag simulator"},
{"clone", CmdHIDClone, 0, "<ID> ['l'] -- Clone HID to T55x7 (tag must be in antenna)(option 'l' for 84bit ID)"},
{"clone", CmdHIDClone, 0, "<ID> -- Clone HID to T55x7 (tag must be in antenna)"},
{"decode", CmdHIDDecode, 1, "<ID> -- Try to decode an HID tag and show its contents"},
{"encode", CmdHIDEncode, 1, "<format> <fields> -- Encode an HID ID with the specified format and fields"},
{"formats", CmdHIDFormats, 1, "List supported card formats"},
{"write", CmdHIDWrite, 0, "<format> <fields> -- Encode and write to a T55x7 tag (tag must be in antenna)"},
{NULL, NULL, 0, NULL}
};

View file

@ -11,10 +11,15 @@
#ifndef CMDLFHID_H__
#define CMDLFHID_H__
#include <stdint.h>
#include <stdbool.h>
int CmdLFHID(const char *Cmd);
int CmdFSKdemodHID(const char *Cmd);
int CmdHIDReadDemod(const char *Cmd);
int CmdHIDSim(const char *Cmd);
int CmdHIDClone(const char *Cmd);
int CmdHIDDecode(const char *Cmd);
int CmdHIDEncode(const char *Cmd);
int CmdHIDWrite(const char *Cmd);
#endif

View file

@ -8,11 +8,12 @@
// Low frequency Hitag support
//-----------------------------------------------------------------------------
#include "cmdlfhitag.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "data.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "cmdparser.h"
#include "common.h"
@ -34,8 +35,7 @@ int CmdLFHitagList(const char *Cmd)
// Query for the actual size of the trace
UsbCommand response;
GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0);
WaitForResponse(CMD_ACK, &response);
GetFromBigBuf(got, USB_CMD_DATA_SIZE, 0, &response, -1, false);
uint16_t traceLen = response.arg[2];
if (traceLen > USB_CMD_DATA_SIZE) {
uint8_t *p = realloc(got, traceLen);
@ -45,8 +45,7 @@ int CmdLFHitagList(const char *Cmd)
return 2;
}
got = p;
GetFromBigBuf(got, traceLen, 0);
WaitForResponse(CMD_ACK,NULL);
GetFromBigBuf(got, traceLen, 0, NULL, -1, false);
}
PrintAndLog("recorded activity (TraceLen = %d bytes):");
@ -67,6 +66,7 @@ int CmdLFHitagList(const char *Cmd)
if (strlen(filename) > 0) {
if ((pf = fopen(filename,"wb")) == NULL) {
PrintAndLog("Error: Could not open file [%s]",filename);
free(got);
return 1;
}
}
@ -167,7 +167,7 @@ int CmdLFHitagSim(const char *Cmd) {
return 1;
}
tag_mem_supplied = true;
if (fread(c.d.asBytes,48,1,pf) == 0) {
if (fread(c.d.asBytes,1,48,pf) != 48) {
PrintAndLog("Error: File reading error");
fclose(pf);
return 1;
@ -239,6 +239,7 @@ int CmdLFHitagReader(const char *Cmd) {
c.arg[0] = htf;
// Send the command to the proxmark
clearCommandBuffer();
SendCommand(&c);
UsbCommand resp;
@ -289,7 +290,7 @@ int CmdLFHitagSimS(const char *Cmd) {
return 1;
}
tag_mem_supplied = true;
if (fread(c.d.asBytes, 4*64, 1, pf) == 0) {
if (fread(c.d.asBytes, 1, 4*64, pf) != 4*64) {
PrintAndLog("Error: File reading error");
fclose(pf);
return 1;
@ -321,7 +322,7 @@ int CmdLFHitagCheckChallenges(const char *Cmd) {
return 1;
}
file_given = true;
if (fread(c.d.asBytes,8*60,1,pf) == 0) {
if (fread(c.d.asBytes,1,8*60,pf) != 8*60) {
PrintAndLog("Error: File reading error");
fclose(pf);
return 1;

View file

@ -8,10 +8,11 @@
// PSK1, rf/32, 64 or 224 bits (known)
//-----------------------------------------------------------------------------
#include "cmdlfindala.h"
#include <stdio.h>
#include <string.h>
#include "cmdlfindala.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "graph.h"
#include "cmdparser.h"
@ -286,7 +287,7 @@ int CmdIndalaDemod(const char *Cmd) {
}
int CmdIndalaClone(const char *Cmd) {
UsbCommand c;
UsbCommand c = {0};
unsigned int uid1, uid2, uid3, uid4, uid5, uid6, uid7;
uid1 = uid2 = uid3 = uid4 = uid5 = uid6 = uid7 = 0;

View file

@ -8,14 +8,14 @@
// FSK2a, rf/64, 64 bits (complete)
//-----------------------------------------------------------------------------
#include "cmdlfio.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include <limits.h>
#include "cmdlfio.h"
#include "proxmark3.h"
#include "data.h"
#include "comms.h"
#include "graph.h"
#include "ui.h"
#include "cmdparser.h"

View file

@ -9,10 +9,11 @@
//-----------------------------------------------------------------------------
#include "cmdlfjablotron.h"
#include <string.h>
#include <inttypes.h>
#include <stdbool.h>
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "util.h"
#include "graph.h"

View file

@ -7,12 +7,14 @@
// Low frequency Honeywell NexWatch tag commands
// PSK1 RF/16, RF/2, 128 bits long (known)
//-----------------------------------------------------------------------------
#include "cmdlfnexwatch.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <stdbool.h>
#include "cmdlfnexwatch.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "util.h"
#include "graph.h"

View file

@ -7,11 +7,13 @@
// Low frequency Noralsy tag commands
// ASK/Manchester, STT, RF/32, 96 bits long (some bits unknown)
//-----------------------------------------------------------------------------
#include "cmdlfnoralsy.h"
#include <string.h>
#include <inttypes.h>
#include <math.h>
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "util.h"
#include "graph.h"

View file

@ -7,10 +7,12 @@
// Low frequency Stanley/PAC tag commands
// NRZ, RF/32, 128 bits long (unknown cs)
//-----------------------------------------------------------------------------
#include "cmdlfpac.h"
#include <string.h>
#include <inttypes.h>
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "util.h"
#include "graph.h"

View file

@ -8,9 +8,12 @@
//-----------------------------------------------------------------------------
// Low frequency PCF7931 commands
//-----------------------------------------------------------------------------
#include "cmdlfpcf7931.h"
#include <stdio.h>
#include <string.h>
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "util.h"
#include "graph.h"
@ -18,7 +21,6 @@
#include "cmddata.h"
#include "cmdmain.h"
#include "cmdlf.h"
#include "cmdlfpcf7931.h"
static int CmdHelp(const char *Cmd);

View file

@ -12,6 +12,8 @@
#ifndef CMDLFPCF7931_H__
#define CMDLFPCF7931_H__
#include <stdint.h>
struct pcf7931_config{
uint8_t Pwd[7];
uint16_t InitDelay;

View file

@ -7,11 +7,13 @@
// Low frequency Presco tag commands
// ASK/Manchester, rf/32, 128 bits (complete)
//-----------------------------------------------------------------------------
#include "cmdlfpresco.h"
#include <string.h>
#include <inttypes.h>
#include <stdio.h>
#include "cmdlfpresco.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "util.h"
#include "graph.h"
@ -71,7 +73,7 @@ int GetWiegandFromPresco(const char *Cmd, uint32_t *sitecode, uint32_t *usercode
case 'D':
case 'd':
//param get string int param_getstr(const char *line, int paramnum, char * str)
stringlen = param_getstr(Cmd, cmdp+1, id);
stringlen = param_getstr(Cmd, cmdp+1, id, sizeof(id));
if (stringlen < 2) return -1;
cmdp+=2;
break;

View file

@ -7,11 +7,13 @@
// Low frequency Farpoint / Pyramid tag commands
// FSK2a, rf/50, 128 bits (complete)
//-----------------------------------------------------------------------------
#include "cmdlfpyramid.h"
#include <string.h>
#include <inttypes.h>
#include <stdio.h>
#include "cmdlfpyramid.h"
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "util.h"
#include "graph.h"

View file

@ -7,11 +7,13 @@
// Low frequency Securakey tag commands
// ASK/Manchester, RF/40, 96 bits long (unknown cs)
//-----------------------------------------------------------------------------
#include "cmdlfsecurakey.h"
#include <string.h>
#include <inttypes.h>
#include <math.h>
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "util.h"
#include "graph.h"

View file

@ -7,21 +7,21 @@
// Low frequency T55xx commands
//-----------------------------------------------------------------------------
#include "cmdlft55xx.h"
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
#include <time.h>
#include "proxmark3.h"
#include "comms.h"
#include "ui.h"
#include "graph.h"
#include "cmdmain.h"
#include "cmdparser.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "cmdlft55xx.h"
#include "util.h"
#include "data.h"
#include "lfdemod.h"
#include "cmdhf14a.h" //for getTagInfo
#include "protocols.h"
@ -207,7 +207,7 @@ void printT5xxHeader(uint8_t page){
int CmdT55xxSetConfig(const char *Cmd) {
uint8_t offset = 0;
char modulation[5] = {0x00};
char modulation[6] = {0x00};
char tmp = 0x00;
uint8_t bitRate = 0;
uint8_t rates[9] = {8,16,32,40,50,64,100,128,0};
@ -236,7 +236,7 @@ int CmdT55xxSetConfig(const char *Cmd) {
cmdp+=2;
break;
case 'd':
param_getstr(Cmd, cmdp+1, modulation);
param_getstr(Cmd, cmdp+1, modulation, sizeof(modulation));
cmdp += 2;
if ( strcmp(modulation, "FSK" ) == 0) {
@ -1355,8 +1355,7 @@ int CmdResetRead(const char *Cmd) {
}
uint8_t got[BIGBUF_SIZE-1];
GetFromBigBuf(got,sizeof(got),0);
WaitForResponse(CMD_ACK,NULL);
GetFromBigBuf(got, sizeof(got), 0, NULL, -1 , 0);
setGraphBuf(got, sizeof(got));
return 1;
}
@ -1433,7 +1432,7 @@ int CmdT55xxBruteForce(const char *Cmd) {
//The line start with # is comment, skip
if( buf[0]=='#' ) continue;
if (!isxdigit(buf[0])) {
if (!isxdigit((unsigned char)buf[0])) {
PrintAndLog("File content error. '%s' must include 8 HEX symbols", buf);
continue;
}

View file

@ -10,6 +10,9 @@
#ifndef CMDLFT55XX_H__
#define CMDLFT55XX_H__
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint32_t bl1;
uint32_t bl2;

View file

@ -8,16 +8,17 @@
// Low frequency TI commands
//-----------------------------------------------------------------------------
#include "cmdlfti.h"
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include "crc16.h"
#include "proxmark3.h"
#include "data.h"
#include "comms.h"
#include "ui.h"
#include "graph.h"
#include "cmdparser.h"
#include "cmdlfti.h"
#include "util.h"
static int CmdHelp(const char *Cmd);

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