mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-08-22 14:13:42 -07:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
0323384554
54 changed files with 2036 additions and 1412 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -8,8 +8,14 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
### Changed
|
||||
- Improved backdoor detection missbehaving 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)
|
||||
|
||||
### Fixed
|
||||
- Changed start sequence in Qt mode (fix: short commands hangs main Qt thread) (Merlok)
|
||||
|
||||
### Added
|
||||
- Added PAC/Stanley detection to lf search (marshmellow)
|
||||
|
@ -19,6 +25,13 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- 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 setings 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)
|
||||
|
||||
## [3.0.1][2017-06-08]
|
||||
|
||||
|
|
142
appveyor.yml
Normal file
142
appveyor.yml
Normal file
|
@ -0,0 +1,142 @@
|
|||
version: 3.0.1.{build}
|
||||
image: Visual Studio 2017
|
||||
clone_folder: C:\ProxSpace\pm3
|
||||
init:
|
||||
- ps: "$psversiontable\n#Get-ChildItem Env:\n\n$releasename=\"\"\n$env:APPVEYOR_REPO_COMMIT_SHORT = $env:APPVEYOR_REPO_COMMIT.Substring(0, 8)\nif ($env:appveyor_repo_tag -match \"true\"){\n $releasename=$env:APPVEYOR_REPO_TAG_NAME + \"/\"\n}\n$releasename+=$env:APPVEYOR_BUILD_VERSION + \" [\" + $env:APPVEYOR_REPO_COMMIT_SHORT + \"]\" \n\nWrite-Host \"repository: $env:appveyor_repo_name branch:$env:APPVEYOR_REPO_BRANCH release: $releasename\" -ForegroundColor Yellow\nAdd-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\"\n\niex ((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 msys\etc\fstab file..." -NoNewLine
|
||||
|
||||
New-Item c:\ProxSpace\msys\etc\fstab -type file -force -value "#Win32_Path Mount_Point`nc:\ProxSpace\devkitARM /devkitARM`nc:\ProxSpace\Qt\5.6 /qt `nc:\ProxSpace\pm3 /pm3`n"
|
||||
|
||||
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: "$env:Path = \"C:\\ProxSpace\\msys\\bin;$env:Path\"\n\n#make\nbash -lc -i \"pwd;make all\"\n\n#some checks\nif(!(Test-Path C:\\ProxSpace\\pm3\\client\\proxmark3.exe)){\nthrow \"Main file proxmark3.exe not exists.\"\n}\nif(!(Test-Path C:\\ProxSpace\\pm3\\armsrc\\obj\\fullimage.elf)){\nthrow \"ARM file fullimage.elf not exists.\"\n}\nif(!(Test-Path C:\\ProxSpace\\pm3\\client\\hardnested\\tables\\*.bin.z)){\nthrow \"Files in hardnested\\tables not exists.\"\n}\n\n#copy\nWrite-Host \"Copy release files...\" -NoNewLine -ForegroundColor Yellow\nNew-Item -ItemType Directory -Force -Path C:\\ProxSpace\\Release\nCopy-Item C:\\ProxSpace\\pm3\\client\\*.exe C:\\ProxSpace\\Release\nNew-Item -ItemType Directory -Force -Path C:\\ProxSpace\\Release\\arm\nCopy-Item C:\\ProxSpace\\pm3\\armsrc\\obj\\*.elf C:\\ProxSpace\\Release\\arm\nCopy-Item C:\\ProxSpace\\pm3\\bootrom\\obj\\*.elf C:\\ProxSpace\\Release\\arm\nNew-Item -ItemType Directory -Force -Path C:\\ProxSpace\\Release\\scripts\nCopy-Item C:\\ProxSpace\\pm3\\client\\scripts\\*.lua C:\\ProxSpace\\Release\\scripts\nNew-Item -ItemType Directory -Force -Path C:\\ProxSpace\\Release\\hardnested\\tables\nCopy-Item C:\\ProxSpace\\pm3\\client\\hardnested\\*.bin C:\\ProxSpace\\Release\\hardnested\nCopy-Item C:\\ProxSpace\\pm3\\client\\hardnested\\tables\\*.bin.z C:\\ProxSpace\\Release\\hardnested\\tables\nWrite-Host \"[ OK ]\" -ForegroundColor Green\n\n#archive and push\n$releasename=\"\"\nif ($env:appveyor_repo_tag -match \"true\"){\n$releasename=$env:APPVEYOR_REPO_TAG_NAME + \"/\"\n}\n$releasename+=$env:APPVEYOR_BUILD_VERSION + \" [\" + $env:APPVEYOR_REPO_COMMIT.Substring(0, 7) + \"]\" \n\nWrite-Host \"Archive and publish release files ($releasename)...\" -NoNewLine -ForegroundColor Yellow\ncd C:\\ProxSpace\n7z a release.zip C:\\ProxSpace\\Release\nPush-AppveyorArtifact release.zip -DeploymentName \"$releasename\"\nWrite-Host \"[ OK ]\" -ForegroundColor Green\n\nWrite-Host \"Builded...\" -ForegroundColor Yellow"
|
||||
test_script:
|
||||
- ps: >-
|
||||
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
|
||||
|
||||
cd c:\ProxSpace\pm3
|
||||
|
||||
|
||||
$global:TestsPassed=$true
|
||||
|
||||
$global:TestTime=[System.Environment]::TickCount
|
||||
|
||||
|
||||
Function ExecTest($Name, $File, $Cond) {
|
||||
[bool]$res=$false;
|
||||
if ($Cond -eq $null){
|
||||
} 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) {
|
||||
Add-AppveyorTest -Name "$Name" -Framework NUnit -Filename "$File" -Outcome Passed -Duration "$([System.Environment]::TickCount-$global:TestTime)"
|
||||
}Else {
|
||||
Add-AppveyorTest -Name "$Name" -Framework NUnit -Filename "$File" -Outcome Failed -Duration "$([System.Environment]::TickCount-$global:TestTime)"
|
||||
$global:TestsPassed=$false
|
||||
}
|
||||
$global:TestTime=[System.Environment]::TickCount
|
||||
}
|
||||
|
||||
|
||||
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' | grep -q at_enc && echo Passed || echo Failed")
|
||||
|
||||
ExecTest "hf mf hardnested" "hf mf hardnested" $(bash -lc "cd ~/client;proxmark3 comx -c 'hf mf hardnested t 1 000000000000' | grep -q 'found:' && echo Passed || echo Failed")
|
||||
|
||||
|
||||
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'))
|
|
@ -136,6 +136,10 @@ void set_tracing(bool enable) {
|
|||
tracing = enable;
|
||||
}
|
||||
|
||||
bool get_tracing(void) {
|
||||
return tracing;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of bytes traced
|
||||
* @return
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -17,7 +17,7 @@ APP_CFLAGS = -DWITH_ISO14443a_StandAlone -DWITH_LF -DWITH_ISO15693 -DWITH_ISO144
|
|||
#SRC_LCD = fonts.c LCD.c
|
||||
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
|
||||
|
|
|
@ -450,7 +450,7 @@ void StandAloneMode14a()
|
|||
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
|
||||
{
|
||||
|
|
|
@ -99,14 +99,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 +110,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,7 +120,7 @@ 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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, bool correctionNeeded);
|
||||
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, bool correctionNeeded);
|
||||
|
||||
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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -20,10 +20,6 @@
|
|||
#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
|
||||
|
||||
|
||||
// the block number for the ISO14443-4 PCB
|
||||
static uint8_t pcb_blocknum = 0;
|
||||
// Deselect card by sending a s-block. the crc is precalced for speed
|
||||
|
@ -59,7 +55,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 +102,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 +137,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 +213,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 +277,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 +379,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 +479,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 +538,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 +658,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,7 +670,7 @@ void MifareAcquireEncryptedNonces(uint32_t arg0, uint32_t arg1, uint32_t flags,
|
|||
}
|
||||
have_uid = true;
|
||||
} else { // no need for anticollision. We can directly select the card
|
||||
if(!iso14443a_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;
|
||||
}
|
||||
|
@ -807,7 +803,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 +877,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 +957,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 +978,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;
|
||||
}
|
||||
}
|
||||
|
||||
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 (set14aTimeout){
|
||||
iso14a_set_timeout(set14aTimeout * 10); // timeout: ms = x/106 35-minimum, 50-OK 106-recommended 500-safe
|
||||
}
|
||||
|
||||
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);
|
||||
LED_B_OFF();
|
||||
LED_B_ON();
|
||||
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 +1078,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");
|
||||
}
|
||||
|
@ -1349,7 +1316,7 @@ 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");
|
||||
// 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;
|
||||
|
@ -1573,7 +1540,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);
|
||||
|
|
620
armsrc/mifaresim.c
Normal file
620
armsrc/mifaresim.c
Normal file
|
@ -0,0 +1,620 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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(); }
|
||||
|
||||
|
||||
|
||||
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 = 0xff; // 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 * AvgAdc(ADC_CHAN_HF)) >> 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], (receivedCmd[0] == ISO14443A_CMD_WUPA));
|
||||
|
||||
// init crypto block
|
||||
crypto1_destroy(pcs);
|
||||
cardAUTHKEY = 0xff;
|
||||
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], false);
|
||||
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], false);
|
||||
LED_B_ON();
|
||||
cardSTATE = MFEMUL_WORK;
|
||||
break;
|
||||
} else if (uid_len == 7) {
|
||||
EmSendPrecompiledCmd(&responses[SAK1], false);
|
||||
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], false);
|
||||
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], false);
|
||||
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 != 0xFF) ;
|
||||
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) {
|
||||
if (MF_DBGLEVEL >= 4) {
|
||||
Dbprintf("Reader reading block %d (0x%02x)",receivedCmd_dec[1],receivedCmd_dec[1]);
|
||||
}
|
||||
emlGetMem(response, receivedCmd_dec[1], 1);
|
||||
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) {
|
||||
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0xA0 write block %d (%02x)",receivedCmd_dec[1],receivedCmd_dec[1]);
|
||||
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_ACK));
|
||||
cardWRBL = receivedCmd_dec[1];
|
||||
cardSTATE = MFEMUL_WRITEBL2;
|
||||
break;
|
||||
}
|
||||
if (receivedCmd_dec[0] == MIFARE_CMD_INC || receivedCmd_dec[0] == MIFARE_CMD_DEC || receivedCmd_dec[0] == MIFARE_CMD_RESTORE) {
|
||||
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x inc(0xC1)/dec(0xC0)/restore(0xC2) block %d (%02x)",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]);
|
||||
if (emlCheckValBl(receivedCmd_dec[1])) {
|
||||
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 = receivedCmd_dec[1];
|
||||
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) {
|
||||
if (MF_DBGLEVEL >= 4) Dbprintf("RECV 0x%02x transfer block %d (%02x)",receivedCmd_dec[0],receivedCmd_dec[1],receivedCmd_dec[1]);
|
||||
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 == 0 ? '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 = 0xff; // 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 == 0 ? '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)) {
|
||||
emlSetMem(receivedCmd_dec, cardWRBL, 1);
|
||||
EmSend4bit(mf_crypto1_encrypt4bit(pcs, CARD_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));
|
||||
}
|
||||
}
|
20
armsrc/mifaresim.h
Normal file
20
armsrc/mifaresim.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef __MIFARESIM_H
|
||||
#define __MIFARESIM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern void Mifare1ksim(uint8_t flags, uint8_t exitAfterNReads, uint8_t arg2, uint8_t *datain);
|
||||
|
||||
#endif
|
|
@ -24,23 +24,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;
|
||||
|
@ -764,3 +768,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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define __MIFAREUTIL_H
|
||||
|
||||
#include "crapto1/crapto1.h"
|
||||
#include "usb_cdc.h"
|
||||
|
||||
// mifare authentication
|
||||
#define CRYPT_NONE 0
|
||||
|
@ -20,6 +21,8 @@
|
|||
#define CRYPT_REQUEST 2
|
||||
#define AUTH_FIRST 0
|
||||
#define AUTH_NESTED 2
|
||||
#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
|
||||
|
||||
// mifare 4bit card answers
|
||||
#define CARD_ACK 0x0A // 1010 - ACK
|
||||
|
@ -38,23 +41,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,6 +68,7 @@ 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);
|
||||
|
||||
|
@ -99,4 +86,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
|
||||
|
|
|
@ -12,14 +12,15 @@ 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
|
||||
LDFLAGS = $(ENV_LDFLAGS)
|
||||
CFLAGS = $(ENV_CFLAGS) -std=c99 -D_ISOC99_SOURCE -I. -I../include -I../common -I../zlib -I../uart -I/opt/local/include -I../liblua -Wall -g -O3
|
||||
CXXFLAGS = -I../include -Wall -O3
|
||||
|
||||
LUAPLATFORM = generic
|
||||
|
|
|
@ -546,7 +546,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trace, ui
|
|||
|
||||
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),
|
||||
" ",
|
||||
|
|
|
@ -442,7 +442,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;
|
||||
|
@ -581,6 +581,7 @@ 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;
|
||||
|
@ -601,6 +602,7 @@ int CmdHF14ACmdRaw(const char *cmd) {
|
|||
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");
|
||||
PrintAndLog(" -3 ISO14443-3 select only (skip RATS)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -645,6 +647,9 @@ int CmdHF14ACmdRaw(const char *cmd) {
|
|||
case 'T':
|
||||
topazmode = true;
|
||||
break;
|
||||
case '3':
|
||||
no_rats = true;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("Invalid option");
|
||||
return 0;
|
||||
|
@ -718,6 +723,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);
|
||||
|
|
423
client/cmdhfmf.c
423
client/cmdhfmf.c
|
@ -222,6 +222,28 @@ uint8_t NumBlocksPerSector(uint8_t sectorNo)
|
|||
}
|
||||
}
|
||||
|
||||
static int ParamCardSizeSectors(const char c) {
|
||||
int numBlocks = 16;
|
||||
switch (c) {
|
||||
case '0' : numBlocks = 5; break;
|
||||
case '2' : numBlocks = 32; break;
|
||||
case '4' : numBlocks = 40; break;
|
||||
default: numBlocks = 16;
|
||||
}
|
||||
return numBlocks;
|
||||
}
|
||||
|
||||
static int ParamCardSizeBlocks(const char c) {
|
||||
int numBlocks = 16 * 4;
|
||||
switch (c) {
|
||||
case '0' : numBlocks = 5 * 4; break;
|
||||
case '2' : numBlocks = 32 * 4; break;
|
||||
case '4' : numBlocks = 32 * 4 + 8 * 16; break;
|
||||
default: numBlocks = 16 * 4;
|
||||
}
|
||||
return numBlocks;
|
||||
}
|
||||
|
||||
int CmdHF14AMfDump(const char *Cmd)
|
||||
{
|
||||
uint8_t sectorNo, blockNo;
|
||||
|
@ -238,14 +260,7 @@ int CmdHF14AMfDump(const char *Cmd)
|
|||
UsbCommand resp;
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
switch (cmdp) {
|
||||
case '0' : numSectors = 5; break;
|
||||
case '1' :
|
||||
case '\0': numSectors = 16; break;
|
||||
case '2' : numSectors = 32; break;
|
||||
case '4' : numSectors = 40; break;
|
||||
default: numSectors = 16;
|
||||
}
|
||||
numSectors = ParamCardSizeSectors(cmdp);
|
||||
|
||||
if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') {
|
||||
PrintAndLog("Usage: hf mf dump [card memory]");
|
||||
|
@ -509,12 +524,34 @@ int CmdHF14AMfRestore(const char *Cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------
|
||||
// Nested
|
||||
//----------------------------------------------
|
||||
# define NESTED_KEY_COUNT 15
|
||||
|
||||
typedef struct {
|
||||
uint64_t Key[2];
|
||||
int foundKey[2];
|
||||
} sector_t;
|
||||
static void parseParamTDS(const char *Cmd, const uint8_t indx, bool *paramT, bool *paramD, uint8_t *timeout) {
|
||||
char ctmp3[3] = {0};
|
||||
int len = param_getlength(Cmd, indx);
|
||||
if (len > 0 && len < 4){
|
||||
param_getstr(Cmd, indx, ctmp3);
|
||||
|
||||
*paramT |= (ctmp3[0] == 't' || ctmp3[0] == 'T');
|
||||
*paramD |= (ctmp3[0] == 'd' || ctmp3[0] == 'D');
|
||||
bool paramS1 = *paramT || *paramD;
|
||||
|
||||
// slow and very slow
|
||||
if (ctmp3[0] == 's' || ctmp3[0] == 'S' || ctmp3[1] == 's' || ctmp3[1] == 'S') {
|
||||
*timeout = 11; // slow
|
||||
|
||||
if (!paramS1 && (ctmp3[1] == 's' || ctmp3[1] == 'S')) {
|
||||
*timeout = 53; // very slow
|
||||
}
|
||||
if (paramS1 && (ctmp3[2] == 's' || ctmp3[2] == 'S')) {
|
||||
*timeout = 53; // very slow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CmdHF14AMfNested(const char *Cmd)
|
||||
{
|
||||
|
@ -526,10 +563,14 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
uint8_t trgKeyType = 0;
|
||||
uint8_t SectorsCnt = 0;
|
||||
uint8_t key[6] = {0, 0, 0, 0, 0, 0};
|
||||
uint8_t keyBlock[14*6];
|
||||
uint8_t keyBlock[NESTED_KEY_COUNT * 6];
|
||||
uint64_t key64 = 0;
|
||||
bool transferToEml = false;
|
||||
// timeout in units. (ms * 106)/10 or us*0.0106
|
||||
uint8_t btimeout14a = MF_CHKKEYS_DEFTIMEOUT; // fast by default
|
||||
|
||||
bool autosearchKey = false;
|
||||
|
||||
bool transferToEml = false;
|
||||
bool createDumpFile = false;
|
||||
FILE *fkeys;
|
||||
uint8_t standart[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
|
@ -539,67 +580,90 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
|
||||
if (strlen(Cmd)<3) {
|
||||
PrintAndLog("Usage:");
|
||||
PrintAndLog(" all sectors: hf mf nested <card memory> <block number> <key A/B> <key (12 hex symbols)> [t,d]");
|
||||
PrintAndLog(" all sectors: hf mf nested <card memory> <block number> <key A/B> <key (12 hex symbols)> [t|d|s|ss]");
|
||||
PrintAndLog(" all sectors autosearch key: hf mf nested <card memory> * [t|d|s|ss]");
|
||||
PrintAndLog(" one sector: hf mf nested o <block number> <key A/B> <key (12 hex symbols)>");
|
||||
PrintAndLog(" <target block number> <target key A/B> [t]");
|
||||
PrintAndLog(" ");
|
||||
PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");
|
||||
PrintAndLog("t - transfer keys into emulator memory");
|
||||
PrintAndLog("d - write keys to binary file");
|
||||
PrintAndLog("t - transfer keys to emulator memory");
|
||||
PrintAndLog("d - write keys to binary file dumpkeys.bin");
|
||||
PrintAndLog("s - Slow (1ms) check keys (required by some non standard cards)");
|
||||
PrintAndLog("ss - Very slow (5ms) check keys");
|
||||
PrintAndLog(" ");
|
||||
PrintAndLog(" sample1: hf mf nested 1 0 A FFFFFFFFFFFF ");
|
||||
PrintAndLog(" sample2: hf mf nested 1 0 A FFFFFFFFFFFF t ");
|
||||
PrintAndLog(" sample3: hf mf nested 1 0 A FFFFFFFFFFFF d ");
|
||||
PrintAndLog(" sample4: hf mf nested o 0 A FFFFFFFFFFFF 4 A");
|
||||
PrintAndLog(" sample5: hf mf nested 1 * t");
|
||||
PrintAndLog(" sample6: hf mf nested 1 * ss");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// <card memory>
|
||||
cmdp = param_getchar(Cmd, 0);
|
||||
blockNo = param_get8(Cmd, 1);
|
||||
ctmp = param_getchar(Cmd, 2);
|
||||
|
||||
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
|
||||
PrintAndLog("Key type must be A or B");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ctmp != 'A' && ctmp != 'a')
|
||||
keyType = 1;
|
||||
|
||||
if (param_gethex(Cmd, 3, key, 12)) {
|
||||
PrintAndLog("Key must include 12 HEX symbols");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (cmdp == 'o' || cmdp == 'O') {
|
||||
cmdp = 'o';
|
||||
trgBlockNo = param_get8(Cmd, 4);
|
||||
ctmp = param_getchar(Cmd, 5);
|
||||
SectorsCnt = 1;
|
||||
} else {
|
||||
SectorsCnt = ParamCardSizeSectors(cmdp);
|
||||
}
|
||||
|
||||
// <block number>. number or autosearch key (*)
|
||||
if (param_getchar(Cmd, 1) == '*') {
|
||||
autosearchKey = true;
|
||||
|
||||
parseParamTDS(Cmd, 2, &transferToEml, &createDumpFile, &btimeout14a);
|
||||
|
||||
PrintAndLog("--nested. sectors:%2d, block no:*, eml:%c, dmp=%c checktimeout=%d us",
|
||||
SectorsCnt, transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106);
|
||||
} else {
|
||||
blockNo = param_get8(Cmd, 1);
|
||||
|
||||
ctmp = param_getchar(Cmd, 2);
|
||||
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
|
||||
PrintAndLog("Target key type must be A or B");
|
||||
PrintAndLog("Key type must be A or B");
|
||||
return 1;
|
||||
}
|
||||
if (ctmp != 'A' && ctmp != 'a')
|
||||
trgKeyType = 1;
|
||||
} else {
|
||||
|
||||
switch (cmdp) {
|
||||
case '0': SectorsCnt = 05; break;
|
||||
case '1': SectorsCnt = 16; break;
|
||||
case '2': SectorsCnt = 32; break;
|
||||
case '4': SectorsCnt = 40; break;
|
||||
default: SectorsCnt = 16;
|
||||
if (ctmp != 'A' && ctmp != 'a')
|
||||
keyType = 1;
|
||||
|
||||
if (param_gethex(Cmd, 3, key, 12)) {
|
||||
PrintAndLog("Key must include 12 HEX symbols");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// check if we can authenticate to sector
|
||||
res = mfCheckKeys(blockNo, keyType, true, 1, key, &key64);
|
||||
if (res) {
|
||||
PrintAndLog("Can't authenticate to block:%3d key type:%c key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6));
|
||||
return 3;
|
||||
}
|
||||
|
||||
// one sector nested
|
||||
if (cmdp == 'o') {
|
||||
trgBlockNo = param_get8(Cmd, 4);
|
||||
|
||||
ctmp = param_getchar(Cmd, 5);
|
||||
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
|
||||
PrintAndLog("Target key type must be A or B");
|
||||
return 1;
|
||||
}
|
||||
if (ctmp != 'A' && ctmp != 'a')
|
||||
trgKeyType = 1;
|
||||
|
||||
parseParamTDS(Cmd, 6, &transferToEml, &createDumpFile, &btimeout14a);
|
||||
} else {
|
||||
parseParamTDS(Cmd, 4, &transferToEml, &createDumpFile, &btimeout14a);
|
||||
}
|
||||
|
||||
PrintAndLog("--nested. sectors:%2d, block no:%3d, key type:%c, eml:%c, dmp=%c checktimeout=%d us",
|
||||
SectorsCnt, blockNo, keyType?'B':'A', transferToEml?'y':'n', createDumpFile?'y':'n', ((int)btimeout14a * 10000) / 106);
|
||||
}
|
||||
|
||||
ctmp = param_getchar(Cmd, 4);
|
||||
if (ctmp == 't' || ctmp == 'T') transferToEml = true;
|
||||
else if (ctmp == 'd' || ctmp == 'D') createDumpFile = true;
|
||||
|
||||
ctmp = param_getchar(Cmd, 6);
|
||||
transferToEml |= (ctmp == 't' || ctmp == 'T');
|
||||
transferToEml |= (ctmp == 'd' || ctmp == 'D');
|
||||
|
||||
if (cmdp == 'o') {
|
||||
// one-sector nested
|
||||
if (cmdp == 'o') { // ------------------------------------ one sector working
|
||||
PrintAndLog("--target block no:%3d, target key type:%c ", trgBlockNo, trgKeyType?'B':'A');
|
||||
int16_t isOK = mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock, true);
|
||||
if (isOK) {
|
||||
|
@ -630,6 +694,7 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
else
|
||||
num_to_bytes(key64, 6, &keyBlock[10]);
|
||||
mfEmlSetMem(keyBlock, sectortrailer, 1);
|
||||
PrintAndLog("Key transferred to emulator memory.");
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("No valid key found");
|
||||
|
@ -643,33 +708,37 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
if (e_sector == NULL) return 1;
|
||||
|
||||
//test current key and additional standard keys first
|
||||
memcpy(keyBlock, key, 6);
|
||||
num_to_bytes(0xffffffffffff, 6, (uint8_t*)(keyBlock + 1 * 6));
|
||||
num_to_bytes(0x000000000000, 6, (uint8_t*)(keyBlock + 2 * 6));
|
||||
num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 3 * 6));
|
||||
num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 4 * 6));
|
||||
num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6));
|
||||
num_to_bytes(0x4d3a99c351dd, 6, (uint8_t*)(keyBlock + 6 * 6));
|
||||
num_to_bytes(0x1a982c7e459a, 6, (uint8_t*)(keyBlock + 7 * 6));
|
||||
num_to_bytes(0xd3f7d3f7d3f7, 6, (uint8_t*)(keyBlock + 8 * 6));
|
||||
num_to_bytes(0x714c5c886e97, 6, (uint8_t*)(keyBlock + 9 * 6));
|
||||
num_to_bytes(0x587ee5f9350f, 6, (uint8_t*)(keyBlock + 10 * 6));
|
||||
num_to_bytes(0xa0478cc39091, 6, (uint8_t*)(keyBlock + 11 * 6));
|
||||
num_to_bytes(0x533cb6c723f6, 6, (uint8_t*)(keyBlock + 12 * 6));
|
||||
num_to_bytes(0x8fd0a4f256e9, 6, (uint8_t*)(keyBlock + 13 * 6));
|
||||
for (int defaultKeyCounter = 0; defaultKeyCounter < MifareDefaultKeysSize; defaultKeyCounter++){
|
||||
num_to_bytes(MifareDefaultKeys[defaultKeyCounter], 6, (uint8_t*)(keyBlock + defaultKeyCounter * 6));
|
||||
}
|
||||
|
||||
PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt);
|
||||
for (i = 0; i < SectorsCnt; i++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
if (e_sector[i].foundKey[j]) continue;
|
||||
|
||||
res = mfCheckKeys(FirstBlockOfSector(i), j, true, 6, keyBlock, &key64);
|
||||
|
||||
if (!res) {
|
||||
e_sector[i].Key[j] = key64;
|
||||
e_sector[i].foundKey[j] = 1;
|
||||
mfCheckKeysSec(SectorsCnt, 2, btimeout14a, true, NESTED_KEY_COUNT, keyBlock, e_sector);
|
||||
|
||||
// get known key from array
|
||||
bool keyFound = false;
|
||||
if (autosearchKey) {
|
||||
for (i = 0; i < SectorsCnt; i++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
if (e_sector[i].foundKey[j]) {
|
||||
// get known key
|
||||
blockNo = i * 4;
|
||||
keyType = j;
|
||||
num_to_bytes(e_sector[i].Key[j], 6, key);
|
||||
|
||||
keyFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (keyFound) break;
|
||||
}
|
||||
|
||||
// Can't found a key....
|
||||
if (!keyFound) {
|
||||
PrintAndLog("Can't found any of the known keys.");
|
||||
return 4;
|
||||
}
|
||||
PrintAndLog("--auto key. block no:%3d, key type:%c key:%s", blockNo, keyType?'B':'A', sprint_hex(key, 6));
|
||||
}
|
||||
|
||||
// nested sectors
|
||||
|
@ -702,15 +771,19 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
PrintAndLog("Found valid key:%012" PRIx64, key64);
|
||||
e_sector[sectorNo].foundKey[trgKeyType] = 1;
|
||||
e_sector[sectorNo].Key[trgKeyType] = key64;
|
||||
|
||||
// try to check this key as a key to the other sectors
|
||||
mfCheckKeysSec(SectorsCnt, 2, btimeout14a, true, 1, keyBlock, e_sector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("Time in nested: %1.3f (%1.3f sec per key)\n\n", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0);
|
||||
|
||||
PrintAndLog("-----------------------------------------------\nIterations count: %d\n\n", iterations);
|
||||
//print them
|
||||
// print nested statistic
|
||||
PrintAndLog("\n\n-----------------------------------------------\nNested statistic:\nIterations count: %d", iterations);
|
||||
PrintAndLog("Time in nested: %1.3f (%1.3f sec per key)", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0);
|
||||
|
||||
// print result
|
||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||
PrintAndLog("|sec|key A |res|key B |res|");
|
||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||
|
@ -720,7 +793,7 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
}
|
||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||
|
||||
// transfer them to the emulator
|
||||
// transfer keys to the emulator memory
|
||||
if (transferToEml) {
|
||||
for (i = 0; i < SectorsCnt; i++) {
|
||||
mfEmlGetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
|
||||
|
@ -730,6 +803,7 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]);
|
||||
mfEmlSetMem(keyBlock, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1);
|
||||
}
|
||||
PrintAndLog("Keys transferred to emulator memory.");
|
||||
}
|
||||
|
||||
// Create dump file
|
||||
|
@ -890,14 +964,18 @@ int CmdHF14AMfNestedHard(const char *Cmd)
|
|||
int CmdHF14AMfChk(const char *Cmd)
|
||||
{
|
||||
if (strlen(Cmd)<3) {
|
||||
PrintAndLog("Usage: hf mf chk <block number>|<*card memory> <key type (A/B/?)> [t|d] [<key (12 hex symbols)>] [<dic (*.dic)>]");
|
||||
PrintAndLog("Usage: hf mf chk <block number>|<*card memory> <key type (A/B/?)> [t|d|s|ss] [<key (12 hex symbols)>] [<dic (*.dic)>]");
|
||||
PrintAndLog(" * - all sectors");
|
||||
PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");
|
||||
PrintAndLog("d - write keys to binary file\n");
|
||||
PrintAndLog("t - write keys to emulator memory");
|
||||
PrintAndLog("s - slow execute. timeout 1ms");
|
||||
PrintAndLog("ss- very slow execute. timeout 5ms");
|
||||
PrintAndLog(" sample: hf mf chk 0 A 1234567890ab keys.dic");
|
||||
PrintAndLog(" hf mf chk *1 ? t");
|
||||
PrintAndLog(" hf mf chk *1 ? d");
|
||||
PrintAndLog(" hf mf chk *1 ? s");
|
||||
PrintAndLog(" hf mf chk *1 ? dss");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -910,49 +988,29 @@ int CmdHF14AMfChk(const char *Cmd)
|
|||
int i, res;
|
||||
int keycnt = 0;
|
||||
char ctmp = 0x00;
|
||||
char ctmp3[3] = {0x00};
|
||||
uint8_t blockNo = 0;
|
||||
uint8_t SectorsCnt = 1;
|
||||
uint8_t SectorsCnt = 0;
|
||||
uint8_t keyType = 0;
|
||||
uint64_t key64 = 0;
|
||||
uint32_t timeout14a = 0; // timeout in us
|
||||
bool param3InUse = false;
|
||||
|
||||
int transferToEml = 0;
|
||||
int createDumpFile = 0;
|
||||
|
||||
sector_t *e_sector = NULL;
|
||||
|
||||
keyBlock = calloc(stKeyBlock, 6);
|
||||
if (keyBlock == NULL) return 1;
|
||||
|
||||
uint64_t defaultKeys[] =
|
||||
{
|
||||
0xffffffffffff, // Default key (first key used by program if no user defined key)
|
||||
0x000000000000, // Blank key
|
||||
0xa0a1a2a3a4a5, // NFCForum MAD key
|
||||
0xb0b1b2b3b4b5,
|
||||
0xaabbccddeeff,
|
||||
0x4d3a99c351dd,
|
||||
0x1a982c7e459a,
|
||||
0xd3f7d3f7d3f7,
|
||||
0x714c5c886e97,
|
||||
0x587ee5f9350f,
|
||||
0xa0478cc39091,
|
||||
0x533cb6c723f6,
|
||||
0x8fd0a4f256e9
|
||||
};
|
||||
int defaultKeysSize = sizeof(defaultKeys) / sizeof(uint64_t);
|
||||
|
||||
for (int defaultKeyCounter = 0; defaultKeyCounter < defaultKeysSize; defaultKeyCounter++)
|
||||
{
|
||||
num_to_bytes(defaultKeys[defaultKeyCounter], 6, (uint8_t*)(keyBlock + defaultKeyCounter * 6));
|
||||
int defaultKeysSize = MifareDefaultKeysSize;
|
||||
for (int defaultKeyCounter = 0; defaultKeyCounter < defaultKeysSize; defaultKeyCounter++){
|
||||
num_to_bytes(MifareDefaultKeys[defaultKeyCounter], 6, (uint8_t*)(keyBlock + defaultKeyCounter * 6));
|
||||
}
|
||||
|
||||
if (param_getchar(Cmd, 0)=='*') {
|
||||
blockNo = 3;
|
||||
switch(param_getchar(Cmd+1, 0)) {
|
||||
case '0': SectorsCnt = 5; break;
|
||||
case '1': SectorsCnt = 16; break;
|
||||
case '2': SectorsCnt = 32; break;
|
||||
case '4': SectorsCnt = 40; break;
|
||||
default: SectorsCnt = 16;
|
||||
}
|
||||
SectorsCnt = ParamCardSizeSectors(param_getchar(Cmd + 1, 0));
|
||||
}
|
||||
else
|
||||
blockNo = param_get8(Cmd, 0);
|
||||
|
@ -960,10 +1018,10 @@ int CmdHF14AMfChk(const char *Cmd)
|
|||
ctmp = param_getchar(Cmd, 1);
|
||||
switch (ctmp) {
|
||||
case 'a': case 'A':
|
||||
keyType = !0;
|
||||
keyType = 0;
|
||||
break;
|
||||
case 'b': case 'B':
|
||||
keyType = !1;
|
||||
keyType = 1;
|
||||
break;
|
||||
case '?':
|
||||
keyType = 2;
|
||||
|
@ -974,11 +1032,33 @@ int CmdHF14AMfChk(const char *Cmd)
|
|||
return 1;
|
||||
};
|
||||
|
||||
// transfer to emulator & create dump file
|
||||
ctmp = param_getchar(Cmd, 2);
|
||||
if (ctmp == 't' || ctmp == 'T') transferToEml = 1;
|
||||
else if (ctmp == 'd' || ctmp == 'D') createDumpFile = 1;
|
||||
if (ctmp == 't' || ctmp == 'T') transferToEml = 1;
|
||||
if (ctmp == 'd' || ctmp == 'D') createDumpFile = 1;
|
||||
|
||||
param3InUse = transferToEml | createDumpFile;
|
||||
|
||||
timeout14a = 500; // fast by default
|
||||
// double parameters - ts, ds
|
||||
int clen = param_getlength(Cmd, 2);
|
||||
if (clen == 2 || clen == 3){
|
||||
param_getstr(Cmd, 2, ctmp3);
|
||||
ctmp = ctmp3[1];
|
||||
}
|
||||
//parse
|
||||
if (ctmp == 's' || ctmp == 'S') {
|
||||
timeout14a = 1000; // slow
|
||||
if (!param3InUse && clen == 2 && (ctmp3[1] == 's' || ctmp3[1] == 'S')) {
|
||||
timeout14a = 5000; // very slow
|
||||
}
|
||||
if (param3InUse && clen == 3 && (ctmp3[2] == 's' || ctmp3[2] == 'S')) {
|
||||
timeout14a = 5000; // very slow
|
||||
}
|
||||
param3InUse = true;
|
||||
}
|
||||
|
||||
for (i = transferToEml || createDumpFile; param_getchar(Cmd, 2 + i); i++) {
|
||||
for (i = param3InUse; param_getchar(Cmd, 2 + i); i++) {
|
||||
if (!param_gethex(Cmd, 2 + i, keyBlock + 6 * keycnt, 12)) {
|
||||
if ( stKeyBlock - keycnt < 2) {
|
||||
p = realloc(keyBlock, 6*(stKeyBlock+=10));
|
||||
|
@ -1043,6 +1123,7 @@ int CmdHF14AMfChk(const char *Cmd)
|
|||
}
|
||||
}
|
||||
|
||||
// fill with default keys
|
||||
if (keycnt == 0) {
|
||||
PrintAndLog("No key specified, trying default keys");
|
||||
for (;keycnt < defaultKeysSize; keycnt++)
|
||||
|
@ -1052,47 +1133,84 @@ int CmdHF14AMfChk(const char *Cmd)
|
|||
}
|
||||
|
||||
// initialize storage for found keys
|
||||
bool validKey[2][40];
|
||||
uint8_t foundKey[2][40][6];
|
||||
for (uint16_t t = 0; t < 2; t++) {
|
||||
e_sector = calloc(SectorsCnt, sizeof(sector_t));
|
||||
if (e_sector == NULL) return 1;
|
||||
for (uint8_t keyAB = 0; keyAB < 2; keyAB++) {
|
||||
for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) {
|
||||
validKey[t][sectorNo] = false;
|
||||
for (uint16_t i = 0; i < 6; i++) {
|
||||
foundKey[t][sectorNo][i] = 0xff;
|
||||
}
|
||||
e_sector[sectorNo].Key[keyAB] = 0xffffffffffff;
|
||||
e_sector[sectorNo].foundKey[keyAB] = 0;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for ( int t = !keyType; t < 2; keyType==2?(t++):(t=2) ) {
|
||||
int b=blockNo;
|
||||
for (int i = 0; i < SectorsCnt; ++i) {
|
||||
PrintAndLog("--sector:%2d, block:%3d, key type:%C, key count:%2d ", i, b, t?'B':'A', keycnt);
|
||||
uint32_t max_keys = keycnt>USB_CMD_DATA_SIZE/6?USB_CMD_DATA_SIZE/6:keycnt;
|
||||
bool foundAKey = false;
|
||||
uint32_t max_keys = keycnt > USB_CMD_DATA_SIZE / 6 ? USB_CMD_DATA_SIZE / 6 : keycnt;
|
||||
if (SectorsCnt) {
|
||||
PrintAndLog("To cancel this operation press the button on the proxmark...");
|
||||
printf("--");
|
||||
for (uint32_t c = 0; c < keycnt; c += max_keys) {
|
||||
|
||||
uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c;
|
||||
res = mfCheckKeysSec(SectorsCnt, keyType, timeout14a * 1.06 / 100, true, size, &keyBlock[6 * c], e_sector); // timeout is (ms * 106)/10 or us*0.0106
|
||||
|
||||
if (res != 1) {
|
||||
if (!res) {
|
||||
printf("o");
|
||||
foundAKey = true;
|
||||
} else {
|
||||
printf(".");
|
||||
}
|
||||
} else {
|
||||
printf("\n");
|
||||
PrintAndLog("Command execute timeout");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int keyAB = keyType;
|
||||
do {
|
||||
for (uint32_t c = 0; c < keycnt; c+=max_keys) {
|
||||
uint32_t size = keycnt-c>max_keys?max_keys:keycnt-c;
|
||||
res = mfCheckKeys(b, t, true, size, &keyBlock[6*c], &key64);
|
||||
|
||||
uint32_t size = keycnt-c > max_keys ? max_keys : keycnt-c;
|
||||
res = mfCheckKeys(blockNo, keyAB & 0x01, true, size, &keyBlock[6 * c], &key64);
|
||||
|
||||
if (res != 1) {
|
||||
if (!res) {
|
||||
PrintAndLog("Found valid key:[%012" PRIx64 "]",key64);
|
||||
num_to_bytes(key64, 6, foundKey[t][i]);
|
||||
validKey[t][i] = true;
|
||||
PrintAndLog("Found valid key:[%d:%c]%012" PRIx64, blockNo, (keyAB & 0x01)?'B':'A', key64);
|
||||
foundAKey = true;
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("Command execute timeout");
|
||||
}
|
||||
}
|
||||
b<127?(b+=4):(b+=16);
|
||||
}
|
||||
} while(--keyAB > 0);
|
||||
}
|
||||
|
||||
|
||||
// print result
|
||||
if (foundAKey) {
|
||||
if (SectorsCnt) {
|
||||
PrintAndLog("");
|
||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||
PrintAndLog("|sec|key A |res|key B |res|");
|
||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||
for (i = 0; i < SectorsCnt; i++) {
|
||||
PrintAndLog("|%03d| %012" PRIx64 " | %d | %012" PRIx64 " | %d |", i,
|
||||
e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]);
|
||||
}
|
||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("");
|
||||
PrintAndLog("No valid keys found.");
|
||||
}
|
||||
|
||||
if (transferToEml) {
|
||||
uint8_t block[16];
|
||||
for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) {
|
||||
if (validKey[0][sectorNo] || validKey[1][sectorNo]) {
|
||||
if (e_sector[sectorNo].foundKey[0] || e_sector[sectorNo].foundKey[1]) {
|
||||
mfEmlGetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
|
||||
for (uint16_t t = 0; t < 2; t++) {
|
||||
if (validKey[t][sectorNo]) {
|
||||
memcpy(block + t*10, foundKey[t][sectorNo], 6);
|
||||
if (e_sector[sectorNo].foundKey[t]) {
|
||||
num_to_bytes(e_sector[sectorNo].Key[t], 6, block + t * 10);
|
||||
}
|
||||
}
|
||||
mfEmlSetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
|
||||
|
@ -1105,16 +1223,22 @@ int CmdHF14AMfChk(const char *Cmd)
|
|||
FILE *fkeys = fopen("dumpkeys.bin","wb");
|
||||
if (fkeys == NULL) {
|
||||
PrintAndLog("Could not create file dumpkeys.bin");
|
||||
free(e_sector);
|
||||
free(keyBlock);
|
||||
return 1;
|
||||
}
|
||||
for (uint16_t t = 0; t < 2; t++) {
|
||||
fwrite(foundKey[t], 1, 6*SectorsCnt, fkeys);
|
||||
uint8_t mkey[6];
|
||||
for (uint8_t t = 0; t < 2; t++) {
|
||||
for (uint8_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) {
|
||||
num_to_bytes(e_sector[sectorNo].Key[t], 6, mkey);
|
||||
fwrite(mkey, 1, 6, fkeys);
|
||||
}
|
||||
}
|
||||
fclose(fkeys);
|
||||
PrintAndLog("Found keys have been dumped to file dumpkeys.bin. 0xffffffffffff has been inserted for unknown keys.");
|
||||
}
|
||||
|
||||
free(e_sector);
|
||||
free(keyBlock);
|
||||
PrintAndLog("");
|
||||
return 0;
|
||||
|
@ -1854,17 +1978,6 @@ int CmdHF14AMfCSetUID(const char *Cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ParamGetCardSize(const char c) {
|
||||
int numBlocks = 16 * 4;
|
||||
switch (c) {
|
||||
case '0' : numBlocks = 5 * 4; break;
|
||||
case '2' : numBlocks = 32 * 4; break;
|
||||
case '4' : numBlocks = 32 * 4 + 8 * 16; break;
|
||||
default: numBlocks = 16 * 4;
|
||||
}
|
||||
return numBlocks;
|
||||
}
|
||||
|
||||
int CmdHF14AMfCWipe(const char *Cmd)
|
||||
{
|
||||
int res, gen = 0;
|
||||
|
@ -1885,7 +1998,7 @@ int CmdHF14AMfCWipe(const char *Cmd)
|
|||
if ((gen != 1) && (gen != 2))
|
||||
return 1;
|
||||
|
||||
numBlocks = ParamGetCardSize(param_getchar(Cmd, 0));
|
||||
numBlocks = ParamCardSizeBlocks(param_getchar(Cmd, 0));
|
||||
|
||||
char cmdp = 0;
|
||||
while(param_getchar(Cmd, cmdp) != 0x00){
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -108,7 +108,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}};
|
||||
UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, 0, 0}};
|
||||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
// Main command parser entry point
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdmain.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
@ -21,7 +24,6 @@
|
|||
#include "cmddata.h"
|
||||
#include "cmdhw.h"
|
||||
#include "cmdlf.h"
|
||||
#include "cmdmain.h"
|
||||
#include "util.h"
|
||||
#include "util_posix.h"
|
||||
#include "cmdscript.h"
|
||||
|
@ -41,6 +43,8 @@ static UsbCommand cmdBuffer[CMD_BUFFER_SIZE];
|
|||
static int cmd_head;//Starts as 0
|
||||
//Points to the position of the last unread command
|
||||
static int cmd_tail;//Starts as 0
|
||||
// to lock cmdBuffer operations from different threads
|
||||
static pthread_mutex_t cmdBufferMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static command_t CommandTable[] =
|
||||
{
|
||||
|
@ -86,7 +90,9 @@ int CmdRev(const char *Cmd)
|
|||
void clearCommandBuffer()
|
||||
{
|
||||
//This is a very simple operation
|
||||
pthread_mutex_lock(&cmdBufferMutex);
|
||||
cmd_tail = cmd_head;
|
||||
pthread_mutex_unlock(&cmdBufferMutex);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,6 +101,7 @@ void clearCommandBuffer()
|
|||
*/
|
||||
void storeCommand(UsbCommand *command)
|
||||
{
|
||||
pthread_mutex_lock(&cmdBufferMutex);
|
||||
if( ( cmd_head+1) % CMD_BUFFER_SIZE == cmd_tail)
|
||||
{
|
||||
//If these two are equal, we're about to overwrite in the
|
||||
|
@ -106,6 +113,7 @@ void storeCommand(UsbCommand *command)
|
|||
memcpy(destination, command, sizeof(UsbCommand));
|
||||
|
||||
cmd_head = (cmd_head +1) % CMD_BUFFER_SIZE; //increment head and wrap
|
||||
pthread_mutex_unlock(&cmdBufferMutex);
|
||||
}
|
||||
|
||||
|
||||
|
@ -116,8 +124,10 @@ void storeCommand(UsbCommand *command)
|
|||
*/
|
||||
int getCommand(UsbCommand* response)
|
||||
{
|
||||
pthread_mutex_lock(&cmdBufferMutex);
|
||||
//If head == tail, there's nothing to read, or if we just got initialized
|
||||
if(cmd_head == cmd_tail){
|
||||
pthread_mutex_unlock(&cmdBufferMutex);
|
||||
return 0;
|
||||
}
|
||||
//Pick out the next unread command
|
||||
|
@ -125,7 +135,7 @@ int getCommand(UsbCommand* response)
|
|||
memcpy(response, last_unread, sizeof(UsbCommand));
|
||||
//Increment tail - this is a circular buffer, so modulo buffer size
|
||||
cmd_tail = (cmd_tail +1 ) % CMD_BUFFER_SIZE;
|
||||
|
||||
pthread_mutex_unlock(&cmdBufferMutex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -139,7 +149,7 @@ int getCommand(UsbCommand* response)
|
|||
* @param ms_timeout
|
||||
* @return true if command was returned, otherwise false
|
||||
*/
|
||||
bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) {
|
||||
bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning) {
|
||||
|
||||
UsbCommand resp;
|
||||
|
||||
|
@ -147,25 +157,34 @@ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeou
|
|||
response = &resp;
|
||||
}
|
||||
|
||||
uint64_t start_time = msclock();
|
||||
|
||||
// Wait until the command is received
|
||||
for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) {
|
||||
while (true) {
|
||||
while(getCommand(response)) {
|
||||
if(response->cmd == cmd){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
msleep(10); // XXX ugh
|
||||
if (dm_seconds == 200) { // Two seconds elapsed
|
||||
if (msclock() - start_time > ms_timeout) {
|
||||
break;
|
||||
}
|
||||
if (msclock() - start_time > 2000 && show_warning) {
|
||||
PrintAndLog("Waiting for a response from the proxmark...");
|
||||
PrintAndLog("Don't forget to cancel its operation first by pressing on the button");
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) {
|
||||
return WaitForResponseTimeoutW(cmd, response, ms_timeout, true);
|
||||
}
|
||||
|
||||
bool WaitForResponse(uint32_t cmd, UsbCommand* response) {
|
||||
return WaitForResponseTimeout(cmd,response,-1);
|
||||
return WaitForResponseTimeoutW(cmd, response, -1, true);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
extern void UsbCommandReceived(UsbCommand *UC);
|
||||
extern int CommandReceived(char *Cmd);
|
||||
extern bool WaitForResponseTimeoutW(uint32_t cmd, UsbCommand* response, size_t ms_timeout, bool show_warning);
|
||||
extern bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout);
|
||||
extern bool WaitForResponse(uint32_t cmd, UsbCommand* response);
|
||||
extern void clearCommandBuffer();
|
||||
|
|
|
@ -43,12 +43,12 @@
|
|||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: fpga_compress <infile1> <infile2> ... <infile_n> <outfile>\n");
|
||||
fprintf(stderr, " Combine n FPGA bitstream files and compress them into one.\n\n");
|
||||
fprintf(stderr, " fpga_compress -d <infile> <outfile>");
|
||||
fprintf(stderr, " Decompress <infile>. Write result to <outfile>");
|
||||
fprintf(stderr, " fpga_compress -t <infile> <outfile>");
|
||||
fprintf(stderr, " Compress hardnested table <infile>. Write result to <outfile>");
|
||||
fprintf(stdout, "Usage: fpga_compress <infile1> <infile2> ... <infile_n> <outfile>\n");
|
||||
fprintf(stdout, " Combine n FPGA bitstream files and compress them into one.\n\n");
|
||||
fprintf(stdout, " fpga_compress -d <infile> <outfile>");
|
||||
fprintf(stdout, " Decompress <infile>. Write result to <outfile>");
|
||||
fprintf(stdout, " fpga_compress -t <infile> <outfile>");
|
||||
fprintf(stdout, " Compress hardnested table <infile>. Write result to <outfile>");
|
||||
}
|
||||
|
||||
|
||||
|
@ -150,7 +150,7 @@ int zlib_compress(FILE *infile[], uint8_t num_infiles, FILE *outfile, bool hardn
|
|||
ret = deflate(&compressed_fpga_stream, Z_FINISH);
|
||||
}
|
||||
|
||||
fprintf(stderr, "compressed %u input bytes to %lu output bytes\n", i, compressed_fpga_stream.total_out);
|
||||
fprintf(stdout, "compressed %u input bytes to %lu output bytes\n", i, compressed_fpga_stream.total_out);
|
||||
|
||||
if (ret != Z_STREAM_END) {
|
||||
fprintf(stderr, "Error in deflate(): %i %s\n", ret, compressed_fpga_stream.msg);
|
||||
|
|
|
@ -22,7 +22,8 @@ local ISO14A_COMMAND = {
|
|||
ISO14A_APPEND_CRC = 0x20,
|
||||
ISO14A_SET_TIMEOUT = 0x40,
|
||||
ISO14A_NO_SELECT = 0x80,
|
||||
ISO14A_TOPAZMODE = 0x100
|
||||
ISO14A_TOPAZMODE = 0x100,
|
||||
ISO14A_NO_RATS = 0x200
|
||||
}
|
||||
|
||||
local ISO14443a_TYPES = {}
|
||||
|
@ -92,9 +93,10 @@ end
|
|||
|
||||
-- This function does a connect and retrieves som einfo
|
||||
-- @param dont_disconnect - if true, does not disable the field
|
||||
-- @param no_rats - if true, skips ISO14443-4 select (RATS)
|
||||
-- @return if successfull: an table containing card info
|
||||
-- @return if unsuccessfull : nil, error
|
||||
local function read14443a(dont_disconnect)
|
||||
local function read14443a(dont_disconnect, no_rats)
|
||||
local command, result, info, err, data
|
||||
|
||||
command = Command:new{cmd = cmds.CMD_READER_ISO_14443a,
|
||||
|
@ -102,6 +104,9 @@ local function read14443a(dont_disconnect)
|
|||
if dont_disconnect then
|
||||
command.arg1 = command.arg1 + ISO14A_COMMAND.ISO14A_NO_DISCONNECT
|
||||
end
|
||||
if no_rats then
|
||||
command.arg1 = command.arg1 + ISO14A_COMMAND.ISO14A_NO_RATS
|
||||
end
|
||||
local result,err = sendToDevice(command)
|
||||
if result then
|
||||
local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL',result)
|
||||
|
|
40
client/mifaredefault.h
Normal file
40
client/mifaredefault.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Mifare default constants
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef MIFAREDEFAULT_H__
|
||||
#define MIFAREDEFAULT_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#define MifareDefaultKeysSize sizeof(MifareDefaultKeys) / sizeof(uint64_t)
|
||||
|
||||
static const uint64_t MifareDefaultKeys[] =
|
||||
{
|
||||
0xffffffffffff, // Default key (first key used by program if no user defined key)
|
||||
0x000000000000, // Blank key
|
||||
0xa0a1a2a3a4a5, // NFCForum MAD key
|
||||
0xb0b1b2b3b4b5,
|
||||
0xaabbccddeeff,
|
||||
0x1a2b3c4d5e6f,
|
||||
0x123456789abc,
|
||||
0x010203040506,
|
||||
0x123456abcdef,
|
||||
0xabcdef123456,
|
||||
0x4d3a99c351dd,
|
||||
0x1a982c7e459a,
|
||||
0xd3f7d3f7d3f7,
|
||||
0x714c5c886e97,
|
||||
0x587ee5f9350f,
|
||||
0xa0478cc39091,
|
||||
0x533cb6c723f6,
|
||||
0x8fd0a4f256e9
|
||||
};
|
||||
|
||||
#endif
|
|
@ -228,17 +228,46 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t key
|
|||
|
||||
*key = -1;
|
||||
|
||||
UsbCommand c = {CMD_MIFARE_CHKKEYS, {((blockNo & 0xff) | ((keyType&0xff)<<8)), clear_trace, keycnt}};
|
||||
UsbCommand c = {CMD_MIFARE_CHKKEYS, {((blockNo & 0xff) | ((keyType & 0xff) << 8)), clear_trace, keycnt}};
|
||||
memcpy(c.d.asBytes, keyBlock, 6 * keycnt);
|
||||
SendCommand(&c);
|
||||
|
||||
UsbCommand resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) return 1;
|
||||
if (!WaitForResponseTimeout(CMD_ACK,&resp,3000)) return 1;
|
||||
if ((resp.arg[0] & 0xff) != 0x01) return 2;
|
||||
*key = bytes_to_num(resp.d.asBytes, 6);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint8_t timeout14a, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector){
|
||||
|
||||
uint8_t keyPtr = 0;
|
||||
|
||||
if (e_sector == NULL)
|
||||
return -1;
|
||||
|
||||
UsbCommand c = {CMD_MIFARE_CHKKEYS, {((sectorCnt & 0xff) | ((keyType & 0xff) << 8)), (clear_trace | 0x02)|((timeout14a & 0xff) << 8), keycnt}};
|
||||
memcpy(c.d.asBytes, keyBlock, 6 * keycnt);
|
||||
SendCommand(&c);
|
||||
|
||||
UsbCommand resp;
|
||||
if (!WaitForResponseTimeoutW(CMD_ACK, &resp, MAX(3000, 1000 + 13 * sectorCnt * keycnt * (keyType == 2 ? 2 : 1)), false)) return 1; // timeout: 13 ms / fail auth
|
||||
if ((resp.arg[0] & 0xff) != 0x01) return 2;
|
||||
|
||||
bool foundAKey = false;
|
||||
for(int sec = 0; sec < sectorCnt; sec++){
|
||||
for(int keyAB = 0; keyAB < 2; keyAB++){
|
||||
keyPtr = *(resp.d.asBytes + keyAB * 40 + sec);
|
||||
if (keyPtr){
|
||||
e_sector[sec].foundKey[keyAB] = true;
|
||||
e_sector[sec].Key[keyAB] = bytes_to_num(keyBlock + (keyPtr - 1) * 6, 6);
|
||||
foundAKey = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundAKey ? 0 : 3;
|
||||
}
|
||||
|
||||
// Compare 16 Bits out of cryptostate
|
||||
int Compare16Bits(const void * a, const void * b) {
|
||||
if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0;
|
||||
|
@ -519,20 +548,20 @@ int mfCIdentify()
|
|||
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));
|
||||
// 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
|
||||
// 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) {
|
||||
uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
|
||||
c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT;
|
||||
c.arg[1] = 2;
|
||||
c.arg[2] = 0;
|
||||
memcpy(c.d.asBytes, rats, 2);
|
||||
SendCommand(&c);
|
||||
WaitForResponse(CMD_ACK,&resp);
|
||||
}
|
||||
// if(select_status != 0) {
|
||||
// uint8_t rats[] = { 0xE0, 0x80 }; // FSDI=8 (FSD=256), CID=0
|
||||
// c.arg[0] = ISO14A_RAW | ISO14A_APPEND_CRC | ISO14A_NO_DISCONNECT;
|
||||
// c.arg[1] = 2;
|
||||
// c.arg[2] = 0;
|
||||
// memcpy(c.d.asBytes, rats, 2);
|
||||
// SendCommand(&c);
|
||||
// WaitForResponse(CMD_ACK,&resp);
|
||||
// }
|
||||
|
||||
c.cmd = CMD_MIFARE_CIDENT;
|
||||
c.arg[0] = 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// Merlok, 2011
|
||||
// Merlok, 2011, 2017
|
||||
// people from mifare@nethemba.com, 2010
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
|
@ -15,6 +15,11 @@
|
|||
#include <stdbool.h>
|
||||
#include "data.h"
|
||||
|
||||
// defaults
|
||||
// timeout in units. (ms * 106)/10 or us*0.0106
|
||||
// 5 == 500us
|
||||
#define MF_CHKKEYS_DEFTIMEOUT 5
|
||||
|
||||
// mfCSetBlock work flags
|
||||
#define CSETBLOCK_UID 0x01
|
||||
#define CSETBLOCK_WUPC 0x02
|
||||
|
@ -24,11 +29,17 @@
|
|||
#define CSETBLOCK_SINGLE_OPER 0x1F
|
||||
#define CSETBLOCK_MAGIC_1B 0x40
|
||||
|
||||
typedef struct {
|
||||
uint64_t Key[2];
|
||||
int foundKey[2];
|
||||
} sector_t;
|
||||
|
||||
extern char logHexFileName[FILE_PATH_SIZE];
|
||||
|
||||
extern int mfDarkside(uint64_t *key);
|
||||
extern int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *ResultKeys, bool calibrate);
|
||||
extern int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key);
|
||||
extern int mfCheckKeysSec(uint8_t sectorCnt, uint8_t keyType, uint8_t timeout14a, bool clear_trace, uint8_t keycnt, uint8_t * keyBlock, sector_t * e_sector);
|
||||
|
||||
extern int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||
|
|
|
@ -107,7 +107,8 @@ static int l_unpack(lua_State *L) /** unpack(f,s, [init]) */
|
|||
size_t len;
|
||||
const char *s=luaL_checklstring(L,2,&len); /* switched s and f */
|
||||
const char *f=luaL_checkstring(L,1);
|
||||
int i_read = luaL_optint(L,3,1)-1;
|
||||
int i_read = luaL_optinteger(L,3,1)-1;
|
||||
// int i_read = luaL_optint(L,3,1)-1;
|
||||
unsigned int i;
|
||||
if (i_read >= 0) {
|
||||
i = i_read;
|
||||
|
@ -347,4 +348,3 @@ int set_bin_library (lua_State *L) {
|
|||
lua_pop(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
static ProxGuiQT *gui = NULL;
|
||||
static WorkerThread *main_loop_thread = NULL;
|
||||
|
||||
WorkerThread::WorkerThread(char *script_cmds_file, bool usb_present) : script_cmds_file(script_cmds_file), usb_present(usb_present)
|
||||
WorkerThread::WorkerThread(char *script_cmds_file, char *script_cmd, bool usb_present) : script_cmds_file(script_cmds_file), script_cmd(script_cmd), usb_present(usb_present)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ WorkerThread::~WorkerThread()
|
|||
}
|
||||
|
||||
void WorkerThread::run() {
|
||||
main_loop(script_cmds_file, usb_present);
|
||||
main_loop(script_cmds_file, script_cmd, usb_present);
|
||||
}
|
||||
|
||||
extern "C" void ShowGraphWindow(void)
|
||||
|
@ -56,11 +56,10 @@ extern "C" void MainGraphics(void)
|
|||
if (!gui)
|
||||
return;
|
||||
|
||||
main_loop_thread->start();
|
||||
gui->MainLoop();
|
||||
}
|
||||
|
||||
extern "C" void InitGraphics(int argc, char **argv, char *script_cmds_file, bool usb_present)
|
||||
extern "C" void InitGraphics(int argc, char **argv, char *script_cmds_file, char *script_cmd, bool usb_present)
|
||||
{
|
||||
#ifdef Q_WS_X11
|
||||
bool useGUI = getenv("DISPLAY") != 0;
|
||||
|
@ -70,18 +69,15 @@ extern "C" void InitGraphics(int argc, char **argv, char *script_cmds_file, bool
|
|||
if (!useGUI)
|
||||
return;
|
||||
|
||||
gui = new ProxGuiQT(argc, argv);
|
||||
main_loop_thread = new WorkerThread(script_cmds_file, usb_present);
|
||||
QObject::connect(main_loop_thread, SIGNAL(finished()), main_loop_thread, SLOT(deleteLater()));
|
||||
QObject::connect(main_loop_thread, SIGNAL(finished()), gui, SLOT(_Exit()));
|
||||
main_loop_thread = new WorkerThread(script_cmds_file, script_cmd, usb_present);
|
||||
gui = new ProxGuiQT(argc, argv, main_loop_thread);
|
||||
}
|
||||
|
||||
|
||||
extern "C" void ExitGraphics(void)
|
||||
{
|
||||
if (!gui)
|
||||
return;
|
||||
if (!gui)
|
||||
return;
|
||||
|
||||
gui->Exit();
|
||||
gui = NULL;
|
||||
gui->Exit();
|
||||
gui = NULL;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ void ShowGraphWindow(void);
|
|||
void HideGraphWindow(void);
|
||||
void RepaintGraphWindow(void);
|
||||
void MainGraphics(void);
|
||||
void InitGraphics(int argc, char **argv, char *script_cmds_file, bool usb_present);
|
||||
void InitGraphics(int argc, char **argv, char *script_cmds_file, char *script_cmd, bool usb_present);
|
||||
void ExitGraphics(void);
|
||||
|
||||
#define MAX_GRAPH_TRACE_LEN (40000*8)
|
||||
|
|
|
@ -85,6 +85,17 @@ void ProxGuiQT::_Exit(void) {
|
|||
delete this;
|
||||
}
|
||||
|
||||
void ProxGuiQT::_StartProxmarkThread(void) {
|
||||
if (!proxmarkThread)
|
||||
return;
|
||||
|
||||
// if thread finished delete self and delete application
|
||||
QObject::connect(proxmarkThread, SIGNAL(finished()), proxmarkThread, SLOT(deleteLater()));
|
||||
QObject::connect(proxmarkThread, SIGNAL(finished()), this, SLOT(_Exit()));
|
||||
// start proxmark thread
|
||||
proxmarkThread->start();
|
||||
}
|
||||
|
||||
void ProxGuiQT::MainLoop()
|
||||
{
|
||||
plotapp = new QApplication(argc, argv);
|
||||
|
@ -94,11 +105,14 @@ void ProxGuiQT::MainLoop()
|
|||
connect(this, SIGNAL(HideGraphWindowSignal()), this, SLOT(_HideGraphWindow()));
|
||||
connect(this, SIGNAL(ExitSignal()), this, SLOT(_Exit()));
|
||||
|
||||
//start proxmark thread after starting event loop
|
||||
QTimer::singleShot(200, this, SLOT(_StartProxmarkThread()));
|
||||
|
||||
plotapp->exec();
|
||||
}
|
||||
|
||||
ProxGuiQT::ProxGuiQT(int argc, char **argv) : plotapp(NULL), plotwidget(NULL),
|
||||
argc(argc), argv(argv)
|
||||
ProxGuiQT::ProxGuiQT(int argc, char **argv, WorkerThread *wthread) : plotapp(NULL), plotwidget(NULL),
|
||||
argc(argc), argv(argv), proxmarkThread(wthread)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -88,6 +88,18 @@ class ProxWidget : public QWidget
|
|||
void vchange_dthr_down(int v);
|
||||
};
|
||||
|
||||
class WorkerThread : public QThread {
|
||||
Q_OBJECT;
|
||||
public:
|
||||
WorkerThread(char*, char*, bool);
|
||||
~WorkerThread();
|
||||
void run();
|
||||
private:
|
||||
char *script_cmds_file = NULL;
|
||||
char *script_cmd = NULL;
|
||||
bool usb_present;
|
||||
};
|
||||
|
||||
class ProxGuiQT : public QObject
|
||||
{
|
||||
Q_OBJECT;
|
||||
|
@ -98,9 +110,10 @@ class ProxGuiQT : public QObject
|
|||
int argc;
|
||||
char **argv;
|
||||
void (*main_func)(void);
|
||||
WorkerThread *proxmarkThread;
|
||||
|
||||
public:
|
||||
ProxGuiQT(int argc, char **argv);
|
||||
ProxGuiQT(int argc, char **argv, WorkerThread *wthread);
|
||||
~ProxGuiQT(void);
|
||||
void ShowGraphWindow(void);
|
||||
void RepaintGraphWindow(void);
|
||||
|
@ -112,6 +125,7 @@ class ProxGuiQT : public QObject
|
|||
void _RepaintGraphWindow(void);
|
||||
void _HideGraphWindow(void);
|
||||
void _Exit(void);
|
||||
void _StartProxmarkThread(void);
|
||||
signals:
|
||||
void ShowGraphWindowSignal(void);
|
||||
void RepaintGraphWindowSignal(void);
|
||||
|
@ -119,16 +133,4 @@ class ProxGuiQT : public QObject
|
|||
void ExitSignal(void);
|
||||
};
|
||||
|
||||
|
||||
class WorkerThread : public QThread {
|
||||
Q_OBJECT;
|
||||
public:
|
||||
WorkerThread(char*, bool);
|
||||
~WorkerThread();
|
||||
void run();
|
||||
private:
|
||||
char *script_cmds_file = NULL;
|
||||
bool usb_present;
|
||||
};
|
||||
|
||||
#endif // PROXGUI_QT
|
||||
|
|
|
@ -18,14 +18,21 @@
|
|||
#include <readline/history.h>
|
||||
|
||||
#include "proxmark3.h"
|
||||
#include "util_posix.h"
|
||||
#include "proxgui.h"
|
||||
#include "cmdmain.h"
|
||||
#include "uart.h"
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
#include "cmdparser.h"
|
||||
#include "cmdhw.h"
|
||||
#include "whereami.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SERIAL_PORT_H "com3"
|
||||
#else
|
||||
#define SERIAL_PORT_H "/dev/ttyACM0"
|
||||
#endif
|
||||
|
||||
// a global mutex to prevent interlaced printing from different threads
|
||||
pthread_mutex_t print_lock;
|
||||
|
@ -66,12 +73,11 @@ static void *uart_receiver(void *targ) {
|
|||
|
||||
while (arg->run) {
|
||||
rxlen = 0;
|
||||
if (uart_receive(sp, prx, sizeof(UsbCommand) - (prx-rx), &rxlen)) {
|
||||
if (uart_receive(sp, prx, sizeof(UsbCommand) - (prx-rx), &rxlen) && rxlen) {
|
||||
prx += rxlen;
|
||||
if (prx-rx < sizeof(UsbCommand)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UsbCommandReceived((UsbCommand*)rx);
|
||||
}
|
||||
prx = rx;
|
||||
|
@ -89,11 +95,13 @@ static void *uart_receiver(void *targ) {
|
|||
}
|
||||
|
||||
|
||||
void main_loop(char *script_cmds_file, bool usb_present) {
|
||||
void main_loop(char *script_cmds_file, char *script_cmd, bool usb_present) {
|
||||
struct receiver_arg rarg;
|
||||
char *cmd = NULL;
|
||||
pthread_t reader_thread;
|
||||
|
||||
bool execCommand = (script_cmd != NULL);
|
||||
bool stdinOnPipe = !isatty(STDIN_FILENO);
|
||||
|
||||
if (usb_present) {
|
||||
rarg.run = 1;
|
||||
pthread_create(&reader_thread, NULL, &uart_receiver, &rarg);
|
||||
|
@ -101,46 +109,68 @@ void main_loop(char *script_cmds_file, bool usb_present) {
|
|||
CmdVersion(NULL);
|
||||
}
|
||||
|
||||
// file with script
|
||||
FILE *script_file = NULL;
|
||||
char script_cmd_buf[256]; // iceman, needs lua script the same file_path_buffer as the rest
|
||||
char script_cmd_buf[256] = {0}; // iceman, needs lua script the same file_path_buffer as the rest
|
||||
|
||||
if (script_cmds_file) {
|
||||
script_file = fopen(script_cmds_file, "r");
|
||||
if (script_file) {
|
||||
printf("using 'scripting' commands file %s\n", script_cmds_file);
|
||||
printf("executing commands from file: %s\n", script_cmds_file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
read_history(".history");
|
||||
|
||||
while(1) {
|
||||
|
||||
// If there is a script file
|
||||
if (script_file)
|
||||
{
|
||||
memset(script_cmd_buf, 0, sizeof(script_cmd_buf));
|
||||
if (!fgets(script_cmd_buf, sizeof(script_cmd_buf), script_file)) {
|
||||
fclose(script_file);
|
||||
script_file = NULL;
|
||||
} else {
|
||||
char *nl;
|
||||
nl = strrchr(script_cmd_buf, '\r');
|
||||
if (nl) *nl = '\0';
|
||||
|
||||
nl = strrchr(script_cmd_buf, '\n');
|
||||
if (nl) *nl = '\0';
|
||||
strcleanrn(script_cmd_buf, sizeof(script_cmd_buf));
|
||||
|
||||
if ((cmd = (char*) malloc(strlen(script_cmd_buf) + 1)) != NULL) {
|
||||
memset(cmd, 0, strlen(script_cmd_buf));
|
||||
strcpy(cmd, script_cmd_buf);
|
||||
printf("%s\n", cmd);
|
||||
if ((cmd = strmcopy(script_cmd_buf)) != NULL) {
|
||||
printf(PROXPROMPT"%s\n", cmd);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If there is a script command
|
||||
if (execCommand){
|
||||
if ((cmd = strmcopy(script_cmd)) != NULL) {
|
||||
printf(PROXPROMPT"%s\n", cmd);
|
||||
}
|
||||
|
||||
execCommand = false;
|
||||
} else {
|
||||
// exit after exec command
|
||||
if (script_cmd)
|
||||
break;
|
||||
|
||||
// if there is a pipe from stdin
|
||||
if (stdinOnPipe) {
|
||||
memset(script_cmd_buf, 0, sizeof(script_cmd_buf));
|
||||
if (!fgets(script_cmd_buf, sizeof(script_cmd_buf), stdin)) {
|
||||
printf("\nStdin end. Exit...\n");
|
||||
break;
|
||||
}
|
||||
strcleanrn(script_cmd_buf, sizeof(script_cmd_buf));
|
||||
|
||||
if ((cmd = strmcopy(script_cmd_buf)) != NULL) {
|
||||
printf(PROXPROMPT"%s\n", cmd);
|
||||
}
|
||||
|
||||
} else {
|
||||
// read command from command prompt
|
||||
cmd = readline(PROXPROMPT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!script_file) {
|
||||
cmd = readline(PROXPROMPT);
|
||||
}
|
||||
|
||||
// execute command
|
||||
if (cmd) {
|
||||
|
||||
while(cmd[strlen(cmd) - 1] == ' ')
|
||||
|
@ -154,12 +184,13 @@ void main_loop(char *script_cmds_file, bool usb_present) {
|
|||
}
|
||||
}
|
||||
free(cmd);
|
||||
cmd = NULL;
|
||||
} else {
|
||||
printf("\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
write_history(".history");
|
||||
|
||||
if (usb_present) {
|
||||
|
@ -171,7 +202,6 @@ void main_loop(char *script_cmds_file, bool usb_present) {
|
|||
fclose(script_file);
|
||||
script_file = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void dumpAllHelp(int markdown)
|
||||
|
@ -212,36 +242,129 @@ static void set_my_executable_path(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void show_help(bool showFullHelp, char *command_line){
|
||||
printf("syntax: %s <port> [-h|-help|-m|-f|-flush|-w|-wait|-c|-command|-l|-lua] [cmd_script_file_name] [command][lua_script_name]\n", command_line);
|
||||
printf("\tLinux example:'%s /dev/ttyACM0'\n", command_line);
|
||||
printf("\tWindows example:'%s com3'\n\n", command_line);
|
||||
|
||||
if (showFullHelp){
|
||||
printf("help: <-h|-help> Dump all interactive command's help at once.\n");
|
||||
printf("\t%s -h\n\n", command_line);
|
||||
printf("markdown: <-m> Dump all interactive help at once in markdown syntax\n");
|
||||
printf("\t%s -m\n\n", command_line);
|
||||
printf("flush: <-f|-flush> Output will be flushed after every print.\n");
|
||||
printf("\t%s -f\n\n", command_line);
|
||||
printf("wait: <-w|-wait> 20sec waiting the serial port to appear in the OS\n");
|
||||
printf("\t%s "SERIAL_PORT_H" -w\n\n", command_line);
|
||||
printf("script: A script file with one proxmark3 command per line.\n\n");
|
||||
printf("command: <-c|-command> Execute one proxmark3 command.\n");
|
||||
printf("\t%s "SERIAL_PORT_H" -c \"hf mf chk 1* ?\"\n", command_line);
|
||||
printf("\t%s "SERIAL_PORT_H" -command \"hf mf nested 1 *\"\n\n", command_line);
|
||||
printf("lua: <-l|-lua> Execute lua script.\n");
|
||||
printf("\t%s "SERIAL_PORT_H" -l hf_read\n\n", command_line);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
srand(time(0));
|
||||
|
||||
bool usb_present = false;
|
||||
bool waitCOMPort = false;
|
||||
bool executeCommand = false;
|
||||
bool addLuaExec = false;
|
||||
char *script_cmds_file = NULL;
|
||||
char *script_cmd = NULL;
|
||||
|
||||
if (argc < 2) {
|
||||
printf("syntax: %s <port>\n\n",argv[0]);
|
||||
printf("\tLinux example:'%s /dev/ttyACM0'\n\n", argv[0]);
|
||||
printf("help: %s -h\n\n", argv[0]);
|
||||
printf("\tDump all interactive help at once\n");
|
||||
printf("markdown: %s -m\n\n", argv[0]);
|
||||
printf("\tDump all interactive help at once in markdown syntax\n");
|
||||
show_help(true, argv[0]);
|
||||
return 1;
|
||||
}
|
||||
if (strcmp(argv[1], "-h") == 0) {
|
||||
printf("syntax: %s <port>\n\n",argv[0]);
|
||||
printf("\tLinux example:'%s /dev/ttyACM0'\n\n", argv[0]);
|
||||
dumpAllHelp(0);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(argv[1], "-m") == 0) {
|
||||
dumpAllHelp(1);
|
||||
return 0;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i],"-help") == 0) {
|
||||
show_help(false, argv[0]);
|
||||
dumpAllHelp(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (strcmp(argv[i], "-m") == 0) {
|
||||
dumpAllHelp(1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(strcmp(argv[i],"-f") == 0 || strcmp(argv[i],"-flush") == 0){
|
||||
printf("Output will be flushed after every print.\n");
|
||||
flushAfterWrite = 1;
|
||||
}
|
||||
|
||||
if(strcmp(argv[i],"-w") == 0 || strcmp(argv[i],"-wait") == 0){
|
||||
waitCOMPort = true;
|
||||
}
|
||||
|
||||
if(strcmp(argv[i],"-c") == 0 || strcmp(argv[i],"-command") == 0){
|
||||
executeCommand = true;
|
||||
}
|
||||
|
||||
if(strcmp(argv[i],"-l") == 0 || strcmp(argv[i],"-lua") == 0){
|
||||
executeCommand = true;
|
||||
addLuaExec = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the user passed the filename of the 'script' to execute, get it from last parameter
|
||||
if (argc > 2 && argv[argc - 1] && argv[argc - 1][0] != '-') {
|
||||
if (executeCommand){
|
||||
script_cmd = argv[argc - 1];
|
||||
|
||||
while(script_cmd[strlen(script_cmd) - 1] == ' ')
|
||||
script_cmd[strlen(script_cmd) - 1] = 0x00;
|
||||
|
||||
if (strlen(script_cmd) == 0) {
|
||||
script_cmd = NULL;
|
||||
} else {
|
||||
if (addLuaExec){
|
||||
// add "script run " to command
|
||||
char *ctmp = NULL;
|
||||
int len = strlen(script_cmd) + 11 + 1;
|
||||
if ((ctmp = (char*) malloc(len)) != NULL) {
|
||||
memset(ctmp, 0, len);
|
||||
strcpy(ctmp, "script run ");
|
||||
strcpy(&ctmp[11], script_cmd);
|
||||
script_cmd = ctmp;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Execute command from commandline: %s\n", script_cmd);
|
||||
}
|
||||
} else {
|
||||
script_cmds_file = argv[argc - 1];
|
||||
}
|
||||
}
|
||||
|
||||
// check command
|
||||
if (executeCommand && (!script_cmd || strlen(script_cmd) == 0)){
|
||||
printf("ERROR: execute command: command not found.\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// set global variables
|
||||
set_my_executable_path();
|
||||
|
||||
bool usb_present = false;
|
||||
char *script_cmds_file = NULL;
|
||||
|
||||
sp = uart_open(argv[1]);
|
||||
// open uart
|
||||
if (!waitCOMPort) {
|
||||
sp = uart_open(argv[1]);
|
||||
} else {
|
||||
printf("Waiting for Proxmark to appear on %s ", argv[1]);
|
||||
int openCount = 0;
|
||||
do {
|
||||
sp = uart_open(argv[1]);
|
||||
msleep(1000);
|
||||
printf(".");
|
||||
} while(++openCount < 20 && (sp == INVALID_SERIAL_PORT || sp == CLAIMED_SERIAL_PORT));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
// check result of uart opening
|
||||
if (sp == INVALID_SERIAL_PORT) {
|
||||
printf("ERROR: invalid serial port\n");
|
||||
usb_present = false;
|
||||
|
@ -254,44 +377,29 @@ int main(int argc, char* argv[]) {
|
|||
usb_present = true;
|
||||
offline = 0;
|
||||
}
|
||||
|
||||
// If the user passed the filename of the 'script' to execute, get it
|
||||
if (argc > 2 && argv[2]) {
|
||||
if (argv[2][0] == 'f' && //buzzy, if a word 'flush' passed, flush the output after every log entry.
|
||||
argv[2][1] == 'l' &&
|
||||
argv[2][2] == 'u' &&
|
||||
argv[2][3] == 's' &&
|
||||
argv[2][4] == 'h')
|
||||
{
|
||||
printf("Output will be flushed after every print.\n");
|
||||
flushAfterWrite = 1;
|
||||
}
|
||||
else
|
||||
script_cmds_file = argv[2];
|
||||
}
|
||||
|
||||
|
||||
// create a mutex to avoid interlacing print commands from our different threads
|
||||
pthread_mutex_init(&print_lock, NULL);
|
||||
|
||||
#ifdef HAVE_GUI
|
||||
#ifdef _WIN32
|
||||
InitGraphics(argc, argv, script_cmds_file, usb_present);
|
||||
InitGraphics(argc, argv, script_cmds_file, script_cmd, usb_present);
|
||||
MainGraphics();
|
||||
#else
|
||||
char* display = getenv("DISPLAY");
|
||||
|
||||
if (display && strlen(display) > 1)
|
||||
{
|
||||
InitGraphics(argc, argv, script_cmds_file, usb_present);
|
||||
InitGraphics(argc, argv, script_cmds_file, script_cmd, usb_present);
|
||||
MainGraphics();
|
||||
}
|
||||
else
|
||||
{
|
||||
main_loop(script_cmds_file, usb_present);
|
||||
main_loop(script_cmds_file, script_cmd, usb_present);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
main_loop(script_cmds_file, usb_present);
|
||||
main_loop(script_cmds_file, script_cmd, usb_present);
|
||||
#endif
|
||||
|
||||
// Clean up the port
|
||||
|
|
|
@ -23,7 +23,7 @@ extern "C" {
|
|||
void SendCommand(UsbCommand *c);
|
||||
const char *get_my_executable_path(void);
|
||||
const char *get_my_executable_directory(void);
|
||||
void main_loop(char *script_cmds_file, bool usb_present);
|
||||
void main_loop(char *script_cmds_file, char *script_cmd, bool usb_present);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ Arguments:
|
|||
-p stay connected - dont inactivate the field
|
||||
-x <payload> Data to send (NO SPACES!)
|
||||
-d Debug flag
|
||||
-t Topaz mode
|
||||
-3 Skip ISO14443-4 select
|
||||
|
||||
Examples :
|
||||
|
||||
|
@ -70,6 +72,7 @@ function help()
|
|||
print(example)
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
-- The main entry point
|
||||
function main(args)
|
||||
|
@ -83,15 +86,19 @@ function main(args)
|
|||
local stayconnected = false
|
||||
local payload = nil
|
||||
local doconnect = true
|
||||
local topaz_mode = false
|
||||
local no_rats = false
|
||||
|
||||
-- Read the parameters
|
||||
for o, a in getopt.getopt(args, 'corcpx:') do
|
||||
for o, a in getopt.getopt(args, 'orcpx:dt3') do
|
||||
if o == "o" then doconnect = false end
|
||||
if o == "r" then ignore_response = true end
|
||||
if o == "c" then appendcrc = true end
|
||||
if o == "p" then stayconnected = true end
|
||||
if o == "x" then payload = a end
|
||||
if o == "d" then DEBUG = true end
|
||||
if o == "t" then topaz_mode = true end
|
||||
if o == "3" then no_rats = true end
|
||||
end
|
||||
|
||||
-- First of all, connect
|
||||
|
@ -99,7 +106,7 @@ function main(args)
|
|||
dbg("doconnect")
|
||||
-- We reuse the connect functionality from a
|
||||
-- common library
|
||||
info, err = lib14a.read1443a(true)
|
||||
info, err = lib14a.read1443a(true, no_rats)
|
||||
|
||||
if err then return oops(err) end
|
||||
print(("Connected to card, uid = %s"):format(info.uid))
|
||||
|
@ -107,7 +114,7 @@ function main(args)
|
|||
|
||||
-- The actual raw payload, if any
|
||||
if payload then
|
||||
res,err = sendRaw(payload,{ignore_response = ignore_response})
|
||||
res,err = sendRaw(payload,{ignore_response = ignore_response, topaz_mode = topaz_mode})
|
||||
if err then return oops(err) end
|
||||
|
||||
if not ignoreresponse then
|
||||
|
@ -137,11 +144,11 @@ function showdata(usbpacket)
|
|||
end
|
||||
|
||||
|
||||
|
||||
function sendRaw(rawdata, options)
|
||||
print(">> ", rawdata)
|
||||
|
||||
local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + lib14a.ISO14A_COMMAND.ISO14A_RAW
|
||||
if options.topaz_mode == true then flags = flags + lib14a.ISO14A_COMMAND.ISO14A_TOPAZMODE end
|
||||
|
||||
local command = Command:new{cmd = cmds.CMD_READER_ISO_14443a,
|
||||
arg1 = flags, -- Send raw
|
||||
|
|
|
@ -406,7 +406,7 @@ function main(args)
|
|||
|
||||
-- GET TAG UID
|
||||
|
||||
result, err = lib14a.read1443a(false)
|
||||
result, err = lib14a.read1443a(false, true)
|
||||
if not result then
|
||||
return oops(err)
|
||||
end
|
||||
|
|
|
@ -71,7 +71,7 @@ end
|
|||
--
|
||||
-- Read information from a card
|
||||
function GetCardInfo()
|
||||
result, err = lib14a.read1443a(false)
|
||||
result, err = lib14a.read1443a(false, true)
|
||||
if not result then
|
||||
print(err)
|
||||
return
|
||||
|
|
|
@ -170,7 +170,7 @@ local function main( args)
|
|||
|
||||
print(desc);
|
||||
|
||||
result, err = reader.read1443a()
|
||||
result, err = reader.read1443a(false, true)
|
||||
if not result then
|
||||
print(err)
|
||||
return
|
||||
|
|
|
@ -56,7 +56,7 @@ end
|
|||
-- @return if unsuccessfull : nil, error
|
||||
function wait_for_mifare()
|
||||
while not core.ukbhit() do
|
||||
res, err = reader.read1443a()
|
||||
res, err = reader.read1443a(false, true)
|
||||
if res then return res end
|
||||
-- err means that there was no response from card
|
||||
end
|
||||
|
|
|
@ -122,7 +122,7 @@ local function main(args)
|
|||
|
||||
|
||||
-- find tag
|
||||
result, err = lib14a.read1443a(false)
|
||||
result, err = lib14a.read1443a(false, true)
|
||||
if not result then return oops(err) end
|
||||
|
||||
-- load keys
|
||||
|
|
|
@ -127,7 +127,7 @@ local function main(args)
|
|||
local cmdSetDbgOff = "hf mf dbg 0"
|
||||
core.console( cmdSetDbgOff)
|
||||
|
||||
result, err = lib14a.read1443a(false)
|
||||
result, err = lib14a.read1443a(false, true)
|
||||
if not result then
|
||||
return oops(err)
|
||||
end
|
||||
|
|
|
@ -623,7 +623,28 @@ void clean_ascii(unsigned char *buf, size_t len) {
|
|||
}
|
||||
}
|
||||
|
||||
// replace \r \n to \0
|
||||
void strcleanrn(char *buf, size_t len) {
|
||||
strcreplace(buf, len, '\n', '\0');
|
||||
strcreplace(buf, len, '\r', '\0');
|
||||
}
|
||||
|
||||
// replace char in buffer
|
||||
void strcreplace(char *buf, size_t len, char from, char to) {
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
if (buf[i] == from)
|
||||
buf[i] = to;
|
||||
}
|
||||
}
|
||||
|
||||
char *strmcopy(char *buf) {
|
||||
char * str = NULL;
|
||||
if ((str = (char*) malloc(strlen(buf) + 1)) != NULL) {
|
||||
memset(str, 0, strlen(buf) + 1);
|
||||
strcpy(str, buf);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
// determine number of logical CPU cores (use for multithreaded functions)
|
||||
|
|
|
@ -77,6 +77,9 @@ extern uint32_t le32toh (uint8_t *data);
|
|||
extern void rol(uint8_t *data, const size_t len);
|
||||
|
||||
extern void clean_ascii(unsigned char *buf, size_t len);
|
||||
void strcleanrn(char *buf, size_t len);
|
||||
void strcreplace(char *buf, size_t len, char from, char to);
|
||||
char *strmcopy(char *buf);
|
||||
|
||||
extern int num_CPUs(void); // number of logical CPUs
|
||||
|
||||
|
|
263
common/usb_cdc.c
263
common/usb_cdc.c
|
@ -38,25 +38,31 @@
|
|||
|
||||
|
||||
#define AT91C_EP_CONTROL 0
|
||||
#define AT91C_EP_IN_SIZE 0x40
|
||||
#define AT91C_EP_OUT 1
|
||||
#define AT91C_EP_OUT_SIZE 0x40
|
||||
#define AT91C_EP_IN 2
|
||||
#define AT91C_EP_NOTIFY 3
|
||||
#define AT91C_EP_OUT_SIZE 0x40
|
||||
#define AT91C_EP_IN_SIZE 0x40
|
||||
|
||||
// Language must always be 0.
|
||||
#define STR_LANGUAGE_CODES 0x00
|
||||
#define STR_MANUFACTURER 0x01
|
||||
#define STR_PRODUCT 0x02
|
||||
|
||||
static const char devDescriptor[] = {
|
||||
/* Device descriptor */
|
||||
0x12, // bLength
|
||||
0x01, // bDescriptorType
|
||||
0x00,0x02, // Complies with USB Spec. Release (0200h = release 2.0)
|
||||
0x02, // bDeviceClass: CDC class code
|
||||
0x00, // bDeviceSubclass: CDC class sub code
|
||||
0x00, // bDeviceProtocol: CDC Device protocol
|
||||
0x02, // bDeviceClass: (Communication Device Class)
|
||||
0x00, // bDeviceSubclass: (unused at this time)
|
||||
0x00, // bDeviceProtocol: (unused at this time)
|
||||
0x08, // bMaxPacketSize0
|
||||
0xc4,0x9a, // Vendor ID (0x9ac4 = J. Westhues)
|
||||
0x8f,0x4b, // Product ID (0x4b8f = Proxmark-3 RFID Instrument)
|
||||
0x01,0x00, // Device release number (0001)
|
||||
0x01, // iManufacturer
|
||||
0x02, // iProduct
|
||||
STR_MANUFACTURER, // iManufacturer
|
||||
STR_PRODUCT, // iProduct
|
||||
0x00, // iSerialNumber
|
||||
0x01 // bNumConfigs
|
||||
};
|
||||
|
@ -74,79 +80,78 @@ static const char cfgDescriptor[] = {
|
|||
0xC0, // CbmAttributes 0xA0
|
||||
0xFA, // CMaxPower
|
||||
|
||||
/* Communication Class Interface Descriptor Requirement */
|
||||
/* Interface 0 Descriptor: Communication Class Interface */
|
||||
0x09, // bLength
|
||||
0x04, // bDescriptorType
|
||||
0x00, // bInterfaceNumber
|
||||
0x00, // bAlternateSetting
|
||||
0x01, // bNumEndpoints
|
||||
0x02, // bInterfaceClass
|
||||
0x02, // bInterfaceSubclass
|
||||
0x01, // bInterfaceProtocol
|
||||
0x02, // bInterfaceClass: Communication Interface Class
|
||||
0x02, // bInterfaceSubclass: Abstract Control Model
|
||||
0x01, // bInterfaceProtocol: Common AT Commands, V.25ter
|
||||
0x00, // iInterface
|
||||
|
||||
/* Header Functional Descriptor */
|
||||
0x05, // bFunction Length
|
||||
0x24, // bDescriptor type: CS_INTERFACE
|
||||
0x00, // bDescriptor subtype: Header Func Desc
|
||||
0x24, // bDescriptor type: CS_INTERFACE
|
||||
0x00, // bDescriptor subtype: Header Functional Descriptor
|
||||
0x10, // bcdCDC:1.1
|
||||
0x01,
|
||||
|
||||
/* ACM Functional Descriptor */
|
||||
0x04, // bFunctionLength
|
||||
0x24, // bDescriptor Type: CS_INTERFACE
|
||||
0x02, // bDescriptor Subtype: ACM Func Desc
|
||||
0x02, // bmCapabilities
|
||||
0x24, // bDescriptor Type: CS_INTERFACE
|
||||
0x02, // bDescriptor Subtype: Abstract Control Management Functional Descriptor
|
||||
0x02, // bmCapabilities: D1: Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State
|
||||
|
||||
/* Union Functional Descriptor */
|
||||
0x05, // bFunctionLength
|
||||
0x24, // bDescriptorType: CS_INTERFACE
|
||||
0x06, // bDescriptor Subtype: Union Func Desc
|
||||
0x00, // bMasterInterface: Communication Class Interface
|
||||
0x01, // bSlaveInterface0: Data Class Interface
|
||||
0x24, // bDescriptorType: CS_INTERFACE
|
||||
0x06, // bDescriptor Subtype: Union Functional Descriptor
|
||||
0x00, // bMasterInterface: Communication Class Interface
|
||||
0x01, // bSlaveInterface0: Data Class Interface
|
||||
|
||||
/* Call Management Functional Descriptor */
|
||||
0x05, // bFunctionLength
|
||||
0x24, // bDescriptor Type: CS_INTERFACE
|
||||
0x01, // bDescriptor Subtype: Call Management Func Desc
|
||||
0x00, // bmCapabilities: D1 + D0
|
||||
0x01, // bDataInterface: Data Class Interface 1
|
||||
0x24, // bDescriptor Type: CS_INTERFACE
|
||||
0x01, // bDescriptor Subtype: Call Management Functional Descriptor
|
||||
0x00, // bmCapabilities: Device sends/receives call management information only over the Communication Class interface. Device does not handle call management itself
|
||||
0x01, // bDataInterface: Data Class Interface 1
|
||||
|
||||
/* Endpoint 1 descriptor */
|
||||
0x07, // bLength
|
||||
0x05, // bDescriptorType
|
||||
0x83, // bEndpointAddress, Endpoint 03 - IN
|
||||
0x03, // bmAttributes INT
|
||||
0x08, // wMaxPacketSize
|
||||
0x83, // bEndpointAddress: Endpoint 03 - IN
|
||||
0x03, // bmAttributes: INT
|
||||
0x08, // wMaxPacketSize: 8
|
||||
0x00,
|
||||
0xFF, // bInterval
|
||||
|
||||
/* Data Class Interface Descriptor Requirement */
|
||||
/* Interface 1 Descriptor: Data Class Interface */
|
||||
0x09, // bLength
|
||||
0x04, // bDescriptorType
|
||||
0x01, // bInterfaceNumber
|
||||
0x00, // bAlternateSetting
|
||||
0x02, // bNumEndpoints
|
||||
0x0A, // bInterfaceClass
|
||||
0x00, // bInterfaceSubclass
|
||||
0x00, // bInterfaceProtocol
|
||||
0x0A, // bInterfaceClass: Data Interface Class
|
||||
0x00, // bInterfaceSubclass: not used
|
||||
0x00, // bInterfaceProtocol: No class specific protocol required)
|
||||
0x00, // iInterface
|
||||
|
||||
/* First alternate setting */
|
||||
/* Endpoint 1 descriptor */
|
||||
0x07, // bLength
|
||||
0x05, // bDescriptorType
|
||||
0x01, // bEndpointAddress, Endpoint 01 - OUT
|
||||
0x02, // bmAttributes BULK
|
||||
AT91C_EP_OUT_SIZE, // wMaxPacketSize
|
||||
0x01, // bEndpointAddress: Endpoint 01 - OUT
|
||||
0x02, // bmAttributes: BULK
|
||||
AT91C_EP_OUT_SIZE, // wMaxPacketSize
|
||||
0x00,
|
||||
0x00, // bInterval
|
||||
|
||||
/* Endpoint 2 descriptor */
|
||||
0x07, // bLength
|
||||
0x05, // bDescriptorType
|
||||
0x82, // bEndpointAddress, Endpoint 02 - IN
|
||||
0x02, // bmAttributes BULK
|
||||
0x82, // bEndpointAddress: Endpoint 02 - IN
|
||||
0x02, // bmAttributes: BULK
|
||||
AT91C_EP_IN_SIZE, // wMaxPacketSize
|
||||
0x00,
|
||||
0x00 // bInterval
|
||||
|
@ -157,7 +162,9 @@ static const char StrDescLanguageCodes[] = {
|
|||
0x03, // Type is string
|
||||
0x09, 0x04 // supported language Code 0 = 0x0409 (English)
|
||||
};
|
||||
|
||||
|
||||
// Note: ModemManager (Linux) ignores Proxmark3 devices by matching the
|
||||
// manufacturer string "proxmark.org". Don't change this.
|
||||
static const char StrDescManufacturer[] = {
|
||||
26, // Length
|
||||
0x03, // Type is string
|
||||
|
@ -182,20 +189,18 @@ static const char StrDescProduct[] = {
|
|||
'M', 0x00,
|
||||
'3', 0x00
|
||||
};
|
||||
|
||||
static const char* const pStrings[] =
|
||||
{
|
||||
StrDescLanguageCodes,
|
||||
StrDescManufacturer,
|
||||
StrDescProduct
|
||||
};
|
||||
|
||||
const char* getStringDescriptor(uint8_t idx)
|
||||
{
|
||||
if(idx >= (sizeof(pStrings) / sizeof(pStrings[0]))) {
|
||||
return(NULL);
|
||||
} else {
|
||||
return(pStrings[idx]);
|
||||
switch (idx) {
|
||||
case STR_LANGUAGE_CODES:
|
||||
return StrDescLanguageCodes;
|
||||
case STR_MANUFACTURER:
|
||||
return StrDescManufacturer;
|
||||
case STR_PRODUCT:
|
||||
return StrDescProduct;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -262,6 +267,7 @@ AT91S_CDC_LINE_CODING line = {
|
|||
0, // None Parity
|
||||
8}; // 8 Data bits
|
||||
|
||||
|
||||
void AT91F_CDC_Enumerate();
|
||||
|
||||
AT91PS_UDP pUdp = AT91C_BASE_UDP;
|
||||
|
@ -269,52 +275,55 @@ byte_t btConfiguration = 0;
|
|||
byte_t btConnection = 0;
|
||||
byte_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;
|
||||
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn usb_disable
|
||||
//* \brief This function deactivates the USB device
|
||||
//*----------------------------------------------------------------------------
|
||||
void usb_disable() {
|
||||
// Disconnect the USB device
|
||||
AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU;
|
||||
|
||||
// Clear all lingering interrupts
|
||||
if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) {
|
||||
pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;
|
||||
}
|
||||
// Disconnect the USB device
|
||||
AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU;
|
||||
|
||||
// Clear all lingering interrupts
|
||||
if(pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) {
|
||||
pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn usb_enable
|
||||
//* \brief This function Activates the USB device
|
||||
//*----------------------------------------------------------------------------
|
||||
void usb_enable() {
|
||||
// Set the PLL USB Divider
|
||||
AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
|
||||
|
||||
// Specific Chip USB Initialisation
|
||||
// Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock
|
||||
AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
|
||||
|
||||
// Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO
|
||||
// Set in PIO mode and Configure in Output
|
||||
AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode
|
||||
AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output
|
||||
|
||||
// Clear for set the Pullup resistor
|
||||
AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU;
|
||||
|
||||
// Disconnect and reconnect USB controller for 100ms
|
||||
usb_disable();
|
||||
|
||||
// Wait for a short while
|
||||
for (volatile size_t i=0; i<0x100000; i++);
|
||||
// Set the PLL USB Divider
|
||||
AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
|
||||
|
||||
// Reconnect USB reconnect
|
||||
AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU;
|
||||
AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU;
|
||||
// Specific Chip USB Initialisation
|
||||
// Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock
|
||||
AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
|
||||
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
|
||||
|
||||
// Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO
|
||||
// Set in PIO mode and Configure in Output
|
||||
AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode
|
||||
AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output
|
||||
|
||||
// Clear for set the Pullup resistor
|
||||
AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU;
|
||||
|
||||
// Disconnect and reconnect USB controller for 100ms
|
||||
usb_disable();
|
||||
|
||||
// Wait for a short while
|
||||
for (volatile size_t i=0; i<0x100000; i++);
|
||||
|
||||
// Reconnect USB reconnect
|
||||
AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU;
|
||||
AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU;
|
||||
}
|
||||
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn usb_check
|
||||
//* \brief Test if the device is configured and handle enumeration
|
||||
|
@ -331,8 +340,7 @@ bool usb_check() {
|
|||
pUdp->UDP_FADDR = AT91C_UDP_FEN;
|
||||
// Configure endpoint 0
|
||||
pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
|
||||
}
|
||||
else if (isr & AT91C_UDP_EPINT0) {
|
||||
} else if (isr & AT91C_UDP_EPINT0) {
|
||||
pUdp->UDP_ICR = AT91C_UDP_EPINT0;
|
||||
AT91F_CDC_Enumerate();
|
||||
}
|
||||
|
@ -342,10 +350,11 @@ bool usb_check() {
|
|||
|
||||
bool usb_poll()
|
||||
{
|
||||
if (!usb_check()) return false;
|
||||
return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);
|
||||
if (!usb_check()) return false;
|
||||
return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
In github PR #129, some users appears to get a false positive from
|
||||
usb_poll, which returns true, but the usb_read operation
|
||||
|
@ -356,7 +365,6 @@ bool usb_poll()
|
|||
**/
|
||||
bool usb_poll_validate_length()
|
||||
{
|
||||
|
||||
if (!usb_check()) return false;
|
||||
if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) return false;
|
||||
return (pUdp->UDP_CSR[AT91C_EP_OUT] >> 16) > 0;
|
||||
|
@ -393,48 +401,54 @@ uint32_t usb_read(byte_t* data, size_t len) {
|
|||
return nbBytesRcv;
|
||||
}
|
||||
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn usb_write
|
||||
//* \brief Send through endpoint 2
|
||||
//*----------------------------------------------------------------------------
|
||||
uint32_t usb_write(const byte_t* data, const size_t len) {
|
||||
size_t length = len;
|
||||
size_t length = len;
|
||||
uint32_t cpt = 0;
|
||||
|
||||
if (!length) return 0;
|
||||
if (!usb_check()) return 0;
|
||||
|
||||
if (!length) return 0;
|
||||
if (!usb_check()) return 0;
|
||||
|
||||
// Send the first packet
|
||||
cpt = MIN(length, AT91C_EP_IN_SIZE-1);
|
||||
cpt = MIN(length, AT91C_EP_IN_SIZE);
|
||||
length -= cpt;
|
||||
while (cpt--) pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
|
||||
while (cpt--) {
|
||||
pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
|
||||
}
|
||||
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
|
||||
|
||||
while (length) {
|
||||
// Fill the second bank
|
||||
cpt = MIN(length, AT91C_EP_IN_SIZE-1);
|
||||
// Fill the next bank
|
||||
cpt = MIN(length, AT91C_EP_IN_SIZE);
|
||||
length -= cpt;
|
||||
while (cpt--) pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
|
||||
// Wait for the first bank to be sent
|
||||
while (cpt--) {
|
||||
pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
|
||||
}
|
||||
// Wait for the previous bank to be sent
|
||||
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {
|
||||
if (!usb_check()) return length;
|
||||
}
|
||||
}
|
||||
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
|
||||
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);
|
||||
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
|
||||
}
|
||||
|
||||
|
||||
// Wait for the end of transfer
|
||||
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {
|
||||
if (!usb_check()) return length;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
|
||||
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn AT91F_USB_SendData
|
||||
//* \brief Send Data through the control endpoint
|
||||
|
@ -477,6 +491,7 @@ static void AT91F_USB_SendData(AT91PS_UDP pUdp, const char *pData, uint32_t leng
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn AT91F_USB_SendZlp
|
||||
//* \brief Send zero length packet through the control endpoint
|
||||
|
@ -488,6 +503,7 @@ void AT91F_USB_SendZlp(AT91PS_UDP pUdp) {
|
|||
while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_TXCOMP);
|
||||
}
|
||||
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn AT91F_USB_SendStall
|
||||
//* \brief Stall the control endpoint
|
||||
|
@ -499,6 +515,7 @@ void AT91F_USB_SendStall(AT91PS_UDP pUdp) {
|
|||
while (pUdp->UDP_CSR[AT91C_EP_CONTROL] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));
|
||||
}
|
||||
|
||||
|
||||
//*----------------------------------------------------------------------------
|
||||
//* \fn AT91F_CDC_Enumerate
|
||||
//* \brief This function is a callback invoked when a SETUP packet is received
|
||||
|
@ -510,16 +527,16 @@ void AT91F_CDC_Enumerate() {
|
|||
if ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_RXSETUP) )
|
||||
return;
|
||||
|
||||
bmRequestType = pUdp->UDP_FDR[0];
|
||||
bRequest = pUdp->UDP_FDR[0];
|
||||
wValue = (pUdp->UDP_FDR[0] & 0xFF);
|
||||
wValue |= (pUdp->UDP_FDR[0] << 8);
|
||||
wIndex = (pUdp->UDP_FDR[0] & 0xFF);
|
||||
wIndex |= (pUdp->UDP_FDR[0] << 8);
|
||||
wLength = (pUdp->UDP_FDR[0] & 0xFF);
|
||||
wLength |= (pUdp->UDP_FDR[0] << 8);
|
||||
bmRequestType = pUdp->UDP_FDR[AT91C_EP_CONTROL];
|
||||
bRequest = pUdp->UDP_FDR[AT91C_EP_CONTROL];
|
||||
wValue = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);
|
||||
wValue |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);
|
||||
wIndex = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);
|
||||
wIndex |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);
|
||||
wLength = (pUdp->UDP_FDR[AT91C_EP_CONTROL] & 0xFF);
|
||||
wLength |= (pUdp->UDP_FDR[AT91C_EP_CONTROL] << 8);
|
||||
|
||||
if (bmRequestType & 0x80) {
|
||||
if (bmRequestType & 0x80) { // Data Phase Transfer Direction Device to Host
|
||||
UDP_SET_EP_FLAGS(AT91C_EP_CONTROL, AT91C_UDP_DIR);
|
||||
while ( !(pUdp->UDP_CSR[AT91C_EP_CONTROL] & AT91C_UDP_DIR) );
|
||||
}
|
||||
|
@ -553,29 +570,29 @@ void AT91F_CDC_Enumerate() {
|
|||
btConfiguration = wValue;
|
||||
AT91F_USB_SendZlp(pUdp);
|
||||
pUdp->UDP_GLBSTATE = (wValue) ? AT91C_UDP_CONFG : AT91C_UDP_FADDEN;
|
||||
pUdp->UDP_CSR[1] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;
|
||||
pUdp->UDP_CSR[2] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;
|
||||
pUdp->UDP_CSR[3] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;
|
||||
pUdp->UDP_CSR[AT91C_EP_OUT] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT) : 0;
|
||||
pUdp->UDP_CSR[AT91C_EP_IN] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN) : 0;
|
||||
pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (wValue) ? (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN) : 0;
|
||||
break;
|
||||
case STD_GET_CONFIGURATION:
|
||||
AT91F_USB_SendData(pUdp, (char *) &(btConfiguration), sizeof(btConfiguration));
|
||||
break;
|
||||
case STD_GET_STATUS_ZERO:
|
||||
wStatus = 0;
|
||||
wStatus = 0; // Device is Bus powered, remote wakeup disabled
|
||||
AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));
|
||||
break;
|
||||
case STD_GET_STATUS_INTERFACE:
|
||||
wStatus = 0;
|
||||
wStatus = 0; // reserved for future use
|
||||
AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));
|
||||
break;
|
||||
case STD_GET_STATUS_ENDPOINT:
|
||||
wStatus = 0;
|
||||
wIndex &= 0x0F;
|
||||
if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= 3)) {
|
||||
if ((pUdp->UDP_GLBSTATE & AT91C_UDP_CONFG) && (wIndex <= AT91C_EP_NOTIFY)) {
|
||||
wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;
|
||||
AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));
|
||||
}
|
||||
else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == 0)) {
|
||||
else if ((pUdp->UDP_GLBSTATE & AT91C_UDP_FADDEN) && (wIndex == AT91C_EP_CONTROL)) {
|
||||
wStatus = (pUdp->UDP_CSR[wIndex] & AT91C_UDP_EPEDS) ? 0 : 1;
|
||||
AT91F_USB_SendData(pUdp, (char *) &wStatus, sizeof(wStatus));
|
||||
}
|
||||
|
@ -590,7 +607,7 @@ void AT91F_CDC_Enumerate() {
|
|||
break;
|
||||
case STD_SET_FEATURE_ENDPOINT:
|
||||
wIndex &= 0x0F;
|
||||
if ((wValue == 0) && wIndex && (wIndex <= 3)) {
|
||||
if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {
|
||||
pUdp->UDP_CSR[wIndex] = 0;
|
||||
AT91F_USB_SendZlp(pUdp);
|
||||
}
|
||||
|
@ -605,13 +622,13 @@ void AT91F_CDC_Enumerate() {
|
|||
break;
|
||||
case STD_CLEAR_FEATURE_ENDPOINT:
|
||||
wIndex &= 0x0F;
|
||||
if ((wValue == 0) && wIndex && (wIndex <= 3)) {
|
||||
if (wIndex == 1)
|
||||
pUdp->UDP_CSR[1] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);
|
||||
else if (wIndex == 2)
|
||||
pUdp->UDP_CSR[2] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);
|
||||
else if (wIndex == 3)
|
||||
pUdp->UDP_CSR[3] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_ISO_IN);
|
||||
if ((wValue == 0) && (wIndex >= AT91C_EP_OUT) && (wIndex <= AT91C_EP_NOTIFY)) {
|
||||
if (wIndex == AT91C_EP_OUT)
|
||||
pUdp->UDP_CSR[AT91C_EP_OUT] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_OUT);
|
||||
else if (wIndex == AT91C_EP_IN)
|
||||
pUdp->UDP_CSR[AT91C_EP_IN] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_BULK_IN);
|
||||
else if (wIndex == AT91C_EP_NOTIFY)
|
||||
pUdp->UDP_CSR[AT91C_EP_NOTIFY] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_INT_IN);
|
||||
AT91F_USB_SendZlp(pUdp);
|
||||
}
|
||||
else
|
||||
|
|
BIN
fpga/fpga_hf.bit
BIN
fpga/fpga_hf.bit
Binary file not shown.
|
@ -34,13 +34,13 @@ always @(negedge ck_1356megb)
|
|||
|
||||
(* clock_signal = "yes" *) reg adc_clk; // sample frequency, always 16 * fc
|
||||
always @(ck_1356megb, xcorr_is_848, xcorr_quarter_freq, fc_div)
|
||||
if (xcorr_is_848 & ~xcorr_quarter_freq) // fc = 847.5 kHz
|
||||
if (xcorr_is_848 & ~xcorr_quarter_freq) // fc = 847.5 kHz, standard ISO14443B
|
||||
adc_clk <= ck_1356megb;
|
||||
else if (~xcorr_is_848 & ~xcorr_quarter_freq) // fc = 424.25 kHz
|
||||
else if (~xcorr_is_848 & ~xcorr_quarter_freq) // fc = 423.75 kHz
|
||||
adc_clk <= fc_div[0];
|
||||
else if (xcorr_is_848 & xcorr_quarter_freq) // fc = 212.125 kHz
|
||||
else if (xcorr_is_848 & xcorr_quarter_freq) // fc = 211.875 kHz
|
||||
adc_clk <= fc_div[1];
|
||||
else // fc = 106.0625 kHz
|
||||
else // fc = 105.9375 kHz
|
||||
adc_clk <= fc_div[2];
|
||||
|
||||
// When we're a reader, we just need to do the BPSK demod; but when we're an
|
||||
|
@ -69,13 +69,16 @@ begin
|
|||
end
|
||||
end
|
||||
|
||||
// Let us report a correlation every 4 subcarrier cycles, or 4*16 samples,
|
||||
// Let us report a correlation every 4 subcarrier cycles, or 4*16=64 samples,
|
||||
// so we need a 6-bit counter.
|
||||
reg [5:0] corr_i_cnt;
|
||||
// And a couple of registers in which to accumulate the correlations.
|
||||
// we would add/sub at most 32 times adc_d, the signed result can be held in 14 bits.
|
||||
reg signed [13:0] corr_i_accum;
|
||||
reg signed [13:0] corr_q_accum;
|
||||
// We would add at most 32 times the difference between unmodulated and modulated signal. It should
|
||||
// be safe to assume that a tag will not be able to modulate the carrier signal by more than 25%.
|
||||
// 32 * 255 * 0,25 = 2040, which can be held in 11 bits. Add 1 bit for sign.
|
||||
reg signed [11:0] corr_i_accum;
|
||||
reg signed [11:0] corr_q_accum;
|
||||
// we will report maximum 8 significant bits
|
||||
reg signed [7:0] corr_i_out;
|
||||
reg signed [7:0] corr_q_out;
|
||||
// clock and frame signal for communication to ARM
|
||||
|
@ -99,16 +102,16 @@ begin
|
|||
begin
|
||||
if(snoop)
|
||||
begin
|
||||
// Send only 7 most significant bits of tag signal (signed), LSB is reader signal:
|
||||
corr_i_out <= {corr_i_accum[13:7], after_hysteresis_prev_prev};
|
||||
corr_q_out <= {corr_q_accum[13:7], after_hysteresis_prev};
|
||||
// Send 7 most significant bits of tag signal (signed), plus 1 bit reader signal
|
||||
corr_i_out <= {corr_i_accum[11:5], after_hysteresis_prev_prev};
|
||||
corr_q_out <= {corr_q_accum[11:5], after_hysteresis_prev};
|
||||
after_hysteresis_prev_prev <= after_hysteresis;
|
||||
end
|
||||
else
|
||||
begin
|
||||
// 8 most significant bits of tag signal
|
||||
corr_i_out <= corr_i_accum[13:6];
|
||||
corr_q_out <= corr_q_accum[13:6];
|
||||
// 8 bits of tag signal
|
||||
corr_i_out <= corr_i_accum[11:4];
|
||||
corr_q_out <= corr_q_accum[11:4];
|
||||
end
|
||||
|
||||
corr_i_accum <= adc_d;
|
||||
|
|
|
@ -24,33 +24,36 @@ module hi_read_tx(
|
|||
output dbg;
|
||||
input shallow_modulation;
|
||||
|
||||
// low frequency outputs, not relevant
|
||||
assign pwr_lo = 1'b0;
|
||||
assign pwr_oe2 = 1'b0;
|
||||
|
||||
// The high-frequency stuff. For now, for testing, just bring out the carrier,
|
||||
// and allow the ARM to modulate it over the SSP.
|
||||
reg pwr_hi;
|
||||
reg pwr_oe1;
|
||||
reg pwr_oe2;
|
||||
reg pwr_oe3;
|
||||
reg pwr_oe4;
|
||||
|
||||
always @(ck_1356megb or ssp_dout or shallow_modulation)
|
||||
begin
|
||||
if(shallow_modulation)
|
||||
begin
|
||||
pwr_hi <= ck_1356megb;
|
||||
pwr_oe1 <= ~ssp_dout;
|
||||
pwr_oe2 <= ~ssp_dout;
|
||||
pwr_oe3 <= ~ssp_dout;
|
||||
pwr_oe4 <= 1'b0;
|
||||
pwr_oe1 <= 1'b0;
|
||||
pwr_oe3 <= 1'b0;
|
||||
pwr_oe4 <= ~ssp_dout;
|
||||
end
|
||||
else
|
||||
begin
|
||||
pwr_hi <= ck_1356megb & ssp_dout;
|
||||
pwr_oe1 <= 1'b0;
|
||||
pwr_oe2 <= 1'b0;
|
||||
pwr_oe3 <= 1'b0;
|
||||
pwr_oe4 <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
// Then just divide the 13.56 MHz clock down to produce appropriate clocks
|
||||
// for the synchronous serial port.
|
||||
|
||||
|
@ -83,7 +86,6 @@ end
|
|||
|
||||
assign ssp_din = after_hysteresis;
|
||||
|
||||
assign pwr_lo = 1'b0;
|
||||
assign dbg = ssp_din;
|
||||
|
||||
endmodule
|
||||
|
|
|
@ -34,7 +34,8 @@ typedef enum ISO14A_COMMAND {
|
|||
ISO14A_APPEND_CRC = (1 << 5),
|
||||
ISO14A_SET_TIMEOUT = (1 << 6),
|
||||
ISO14A_NO_SELECT = (1 << 7),
|
||||
ISO14A_TOPAZMODE = (1 << 8)
|
||||
ISO14A_TOPAZMODE = (1 << 8),
|
||||
ISO14A_NO_RATS = (1 << 9)
|
||||
} iso14a_command_t;
|
||||
|
||||
typedef struct {
|
||||
|
|
54
tools/at91sam7s512-busblaster.cfg
Normal file
54
tools/at91sam7s512-busblaster.cfg
Normal file
|
@ -0,0 +1,54 @@
|
|||
## General OpenOCD configuration
|
||||
# Ports
|
||||
telnet_port 4444
|
||||
gdb_port 3333
|
||||
|
||||
## Interface configuration section
|
||||
# Interface
|
||||
|
||||
# you can use
|
||||
#source [find interface/ftdi/dp_busblaster.cfg]
|
||||
# or
|
||||
|
||||
interface ftdi
|
||||
ftdi_device_desc "Dual RS232-HS"
|
||||
ftdi_vid_pid 0x0403 0x6010
|
||||
|
||||
ftdi_layout_init 0x0c08 0x0f1b
|
||||
ftdi_layout_signal nTRST -data 0x0100 -noe 0x0400
|
||||
ftdi_layout_signal nSRST -data 0x0200 -noe 0x0800
|
||||
|
||||
adapter_khz 1000
|
||||
|
||||
## Chipset configuration section
|
||||
# use combined on interfaces or targets that can't set TRST/SRST separately
|
||||
reset_config srst_only srst_pulls_trst
|
||||
|
||||
jtag newtap sam7x cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0x3f0f0f0f
|
||||
|
||||
target create sam7x.cpu arm7tdmi -endian little -chain-position sam7x.cpu
|
||||
|
||||
sam7x.cpu configure -event reset-init {
|
||||
soft_reset_halt
|
||||
mww 0xfffffd00 0xa5000004 # RSTC_CR: Reset peripherals
|
||||
mww 0xfffffd44 0x00008000 # WDT_MR: disable watchdog
|
||||
mww 0xfffffd08 0xa5000001 # RSTC_MR enable user reset
|
||||
mww 0xfffffc20 0x00005001 # CKGR_MOR : enable the main oscillator
|
||||
sleep 10
|
||||
mww 0xfffffc2c 0x000b1c02 # CKGR_PLLR: 16MHz * 12/2 = 96MHz
|
||||
sleep 10
|
||||
mww 0xfffffc30 0x00000007 # PMC_MCKR : MCK = PLL / 2 = 48 MHz
|
||||
sleep 10
|
||||
mww 0xffffff60 0x00480100 # MC_FMR: flash mode (FWS=1,FMCN=72)
|
||||
sleep 100
|
||||
|
||||
}
|
||||
|
||||
# GDB can also flash my flash!
|
||||
gdb_memory_map enable
|
||||
gdb_breakpoint_override hard
|
||||
#armv4_5 core_state arm
|
||||
|
||||
sam7x.cpu configure -work-area-virt 0 -work-area-phys 0x00200000 -work-area-size 0x10000 -work-area-backup 0
|
||||
flash bank sam7x512.flash.0 at91sam7 0 0 0 0 sam7x.cpu 0 0 0 0 0 0 0 18432
|
||||
flash bank sam7x512.flash.1 at91sam7 0 0 0 0 sam7x.cpu 1 0 0 0 0 0 0 18432
|
|
@ -1,8 +1,8 @@
|
|||
VPATH = ../../common ../../common/crapto1 ../../client
|
||||
CC = gcc
|
||||
LD = gcc
|
||||
CFLAGS = -std=c99 -D_ISOC99_SOURCE -I../../include -I../../common -I../../client -Wall -O3
|
||||
LDFLAGS =
|
||||
CFLAGS += -std=c99 -D_ISOC99_SOURCE -I../../include -I../../common -I../../client -Wall -O3
|
||||
LDFLAGS +=
|
||||
|
||||
OBJS = crypto1.o crapto1.o parity.o util_posix.o mfkey.o
|
||||
EXES = mfkey32 mfkey64
|
||||
|
|
|
@ -107,15 +107,13 @@ void uart_close(const serial_port sp) {
|
|||
free(sp);
|
||||
}
|
||||
|
||||
bool uart_receive(const serial_port sp, byte_t* pbtRx, size_t pszMaxRxLen, size_t* pszRxLen) {
|
||||
ReadFile(((serial_port_windows*)sp)->hPort,pbtRx,pszMaxRxLen,(LPDWORD)pszRxLen,NULL);
|
||||
return (*pszRxLen != 0);
|
||||
bool uart_receive(const serial_port sp, byte_t *pbtRx, size_t pszMaxRxLen, size_t *pszRxLen) {
|
||||
return ReadFile(((serial_port_windows*)sp)->hPort, pbtRx, pszMaxRxLen, (LPDWORD)pszRxLen, NULL);
|
||||
}
|
||||
|
||||
bool uart_send(const serial_port sp, const byte_t* pbtTx, const size_t szTxLen) {
|
||||
DWORD dwTxLen = 0;
|
||||
return WriteFile(((serial_port_windows*)sp)->hPort,pbtTx,szTxLen,&dwTxLen,NULL);
|
||||
return (dwTxLen != 0);
|
||||
return WriteFile(((serial_port_windows*)sp)->hPort, pbtTx, szTxLen, &dwTxLen, NULL);
|
||||
}
|
||||
|
||||
bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue