Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Fl0-0 2017-10-24 08:05:11 +02:00
commit 0323384554
54 changed files with 2036 additions and 1412 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -15,18 +15,42 @@
#include <stdint.h>
#include <stdbool.h>
#include "usb_cmd.h"
#include "mifare.h"
typedef struct {
uint8_t* response;
uint8_t* modulation;
uint16_t response_n;
uint16_t modulation_n;
uint32_t ProxToAirDuration;
uint8_t par; // enough for precalculated parity of 8 Byte responses
} tag_response_info_t;
extern void GetParity(const uint8_t *pbtCmd, uint16_t len, uint8_t *par);
extern void AppendCrc14443a(uint8_t *data, int len);
extern void RAMFUNC SnoopIso14443a(uint8_t param);
extern void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t *data);
extern void ReaderIso14443a(UsbCommand *c);
extern void ReaderTransmit(uint8_t *frame, uint16_t len, uint32_t *timing);
extern void ReaderTransmitBitsPar(uint8_t *frame, uint16_t bits, uint8_t *par, uint32_t *timing);
extern void ReaderTransmitPar(uint8_t *frame, uint16_t len, uint8_t *par, uint32_t *timing);
extern int ReaderReceive(uint8_t *receivedAnswer, uint8_t *par);
extern void ReaderMifare(bool first_try);
extern int EmGetCmd(uint8_t *received, uint16_t *len, uint8_t *parity);
extern int EmSendCmd(uint8_t *resp, uint16_t respLen);
extern int EmSendCmdEx(uint8_t *resp, uint16_t respLen, 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 */

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -11,6 +11,8 @@
#ifndef CMDHFMF_H__
#define CMDHFMF_H__
#include "mifaredefault.h"
extern int CmdHFMF(const char *Cmd);
extern int CmdHF14AMfDbg(const char* cmd);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

Binary file not shown.

View file

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

View file

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

View file

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

View 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

View file

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

View file

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