mirror of
https://github.com/Proxmark/proxmark3.git
synced 2025-07-16 02:03:00 -07:00
Check keys in hf mf nested and hf mf chk (#414)
Improve hf mf chk and hf mf nested * hf mf chk. added interrupt of procedure by usb * extract mifare default keys into separate module * arm side multisector `hf mf chk` * hf mf nested. change key search procedure * hf mf nested. added key check after we have found a key. * small fix hf list f * hf mf chk. add timeout (arm side) and some tweaks.
This commit is contained in:
parent
77aecdd286
commit
275d9e61c2
14 changed files with 375 additions and 218 deletions
|
@ -10,6 +10,8 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Deleted wipe functionality from `hf mf csetuid` (Merlok)
|
- Deleted wipe functionality from `hf mf csetuid` (Merlok)
|
||||||
- Changed `hf mf nested` logic (Merlok)
|
- Changed `hf mf nested` logic (Merlok)
|
||||||
- Added `hf mf nested` mode: autosearch keys for attack (from well known keys) (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)
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
@ -23,6 +25,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- 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 `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` source key check before attack (Merlok)
|
||||||
- Added to `hf mf nested` after attack it checks all found keys on non-open sectors (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)
|
||||||
|
|
||||||
## [3.0.1][2017-06-08]
|
## [3.0.1][2017-06-08]
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,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 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 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 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 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 MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain);
|
||||||
|
|
|
@ -29,4 +29,5 @@ extern void iso14443a_setup(uint8_t fpga_minor_mode);
|
||||||
extern int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, void *data);
|
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, bool no_rats);
|
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_trigger(bool enable);
|
||||||
|
extern void iso14a_set_timeout(uint32_t timeout);
|
||||||
#endif /* __ISO14443A_H */
|
#endif /* __ISO14443A_H */
|
||||||
|
|
|
@ -20,10 +20,6 @@
|
||||||
#include "parity.h"
|
#include "parity.h"
|
||||||
#include "crc.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
|
// the block number for the ISO14443-4 PCB
|
||||||
static uint8_t pcb_blocknum = 0;
|
static uint8_t pcb_blocknum = 0;
|
||||||
// Deselect card by sending a s-block. the crc is precalced for speed
|
// Deselect card by sending a s-block. the crc is precalced for speed
|
||||||
|
@ -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.
|
// 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 blockNo = arg0 & 0xff;
|
||||||
uint8_t keyType = (arg0 >> 8) & 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;
|
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
|
// clear debug level
|
||||||
int OLD_MF_DBGLEVEL = MF_DBGLEVEL;
|
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();
|
if (clearTrace) clear_trace();
|
||||||
set_tracing(true);
|
set_tracing(true);
|
||||||
|
|
||||||
for (i = 0; i < keyCount; i++) {
|
if (set14aTimeout){
|
||||||
// if(mifare_classic_halt(pcs, cuid)) {
|
iso14a_set_timeout(set14aTimeout * 10); // timeout: ms = x/106 35-minimum, 50-OK 106-recommended 500-safe
|
||||||
// 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, true)) {
|
|
||||||
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, true)) {
|
|
||||||
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 (multisectorCheck) {
|
||||||
|
TKeyIndex keyIndex = {{0}};
|
||||||
|
uint8_t sectorCnt = blockNo;
|
||||||
|
int res = MifareMultisectorChk(datain, keyCount, sectorCnt, keyType, OLD_MF_DBGLEVEL, &keyIndex);
|
||||||
|
|
||||||
LED_B_ON();
|
LED_B_ON();
|
||||||
cmd_send(CMD_ACK,isOK,0,0,datain + i * 6,6);
|
if (res >= 0) {
|
||||||
LED_B_OFF();
|
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);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
LEDsoff();
|
LEDsoff();
|
||||||
|
|
|
@ -764,3 +764,125 @@ int mifare_desfire_des_auth2(uint32_t uid, uint8_t *key, uint8_t *blockData){
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// MIFARE check keys
|
||||||
|
//
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// one key check
|
||||||
|
int MifareChkBlockKey(uint8_t *uid, uint32_t *cuid, uint8_t *cascade_levels, uint64_t ui64Key, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel) {
|
||||||
|
|
||||||
|
struct Crypto1State mpcs = {0, 0};
|
||||||
|
struct Crypto1State *pcs;
|
||||||
|
pcs = &mpcs;
|
||||||
|
|
||||||
|
// Iceman: use piwi's faster nonce collecting part in hardnested.
|
||||||
|
if (*cascade_levels == 0) { // need a full select cycle to get the uid first
|
||||||
|
iso14a_card_select_t card_info;
|
||||||
|
if(!iso14443a_select_card(uid, &card_info, cuid, true, 0, true)) {
|
||||||
|
if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
switch (card_info.uidlen) {
|
||||||
|
case 4 : *cascade_levels = 1; break;
|
||||||
|
case 7 : *cascade_levels = 2; break;
|
||||||
|
case 10: *cascade_levels = 3; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
} else { // no need for anticollision. We can directly select the card
|
||||||
|
if(!iso14443a_select_card(uid, NULL, NULL, false, *cascade_levels, true)) {
|
||||||
|
if (debugLevel >= 1) Dbprintf("ChkKeys: Can't select card (UID) lvl=%d", *cascade_levels);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mifare_classic_auth(pcs, *cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
|
||||||
|
// SpinDelayUs(AUTHENTICATION_TIMEOUT); // it not needs because mifare_classic_auth have timeout from iso14a_set_timeout()
|
||||||
|
return 2;
|
||||||
|
} else {
|
||||||
|
/* // let it be here. it like halt command, but maybe it will work in some strange cases
|
||||||
|
uint8_t dummy_answer = 0;
|
||||||
|
ReaderTransmit(&dummy_answer, 1, NULL);
|
||||||
|
int timeout = GetCountSspClk() + AUTHENTICATION_TIMEOUT;
|
||||||
|
// wait for the card to become ready again
|
||||||
|
while(GetCountSspClk() < timeout) {};
|
||||||
|
*/
|
||||||
|
// it needs after success authentication
|
||||||
|
mifare_classic_halt(pcs, *cuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// multi key check
|
||||||
|
int MifareChkBlockKeys(uint8_t *keys, uint8_t keyCount, uint8_t blockNo, uint8_t keyType, uint8_t debugLevel) {
|
||||||
|
uint8_t uid[10];
|
||||||
|
uint32_t cuid = 0;
|
||||||
|
uint8_t cascade_levels = 0;
|
||||||
|
uint64_t ui64Key = 0;
|
||||||
|
|
||||||
|
int retryCount = 0;
|
||||||
|
for (uint8_t i = 0; i < keyCount; i++) {
|
||||||
|
|
||||||
|
// Allow button press / usb cmd to interrupt device
|
||||||
|
if (BUTTON_PRESS() && !usb_poll_validate_length()) {
|
||||||
|
Dbprintf("ChkKeys: Cancel operation. Exit...");
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui64Key = bytes_to_num(keys + i * 6, 6);
|
||||||
|
int res = MifareChkBlockKey(uid, &cuid, &cascade_levels, ui64Key, blockNo, keyType, debugLevel);
|
||||||
|
|
||||||
|
// can't select
|
||||||
|
if (res == 1) {
|
||||||
|
retryCount++;
|
||||||
|
if (retryCount >= 5) {
|
||||||
|
Dbprintf("ChkKeys: block=%d key=%d. Can't select. Exit...", blockNo, keyType);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
--i; // try the same key once again
|
||||||
|
|
||||||
|
SpinDelay(20);
|
||||||
|
// Dbprintf("ChkKeys: block=%d key=%d. Try the same key once again...", blockNo, keyType);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// can't authenticate
|
||||||
|
if (res == 2) {
|
||||||
|
retryCount = 0;
|
||||||
|
continue; // can't auth. wrong key.
|
||||||
|
}
|
||||||
|
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// multisector multikey check
|
||||||
|
int MifareMultisectorChk(uint8_t *keys, uint8_t keyCount, uint8_t SectorCount, uint8_t keyType, uint8_t debugLevel, TKeyIndex *keyIndex) {
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
// int clk = GetCountSspClk();
|
||||||
|
|
||||||
|
for(int sc = 0; sc < SectorCount; sc++){
|
||||||
|
WDT_HIT();
|
||||||
|
|
||||||
|
int keyAB = keyType;
|
||||||
|
do {
|
||||||
|
res = MifareChkBlockKeys(keys, keyCount, FirstBlockOfSector(sc), keyAB & 0x01, debugLevel);
|
||||||
|
if (res < 0){
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
if (res > 0){
|
||||||
|
(*keyIndex)[keyAB & 0x01][sc] = res;
|
||||||
|
}
|
||||||
|
} while(--keyAB > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dbprintf("%d %d", GetCountSspClk() - clk, (GetCountSspClk() - clk)/(SectorCount*keyCount*(keyType==2?2:1)));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#define __MIFAREUTIL_H
|
#define __MIFAREUTIL_H
|
||||||
|
|
||||||
#include "crapto1/crapto1.h"
|
#include "crapto1/crapto1.h"
|
||||||
|
#include "usb_cdc.h"
|
||||||
|
|
||||||
// mifare authentication
|
// mifare authentication
|
||||||
#define CRYPT_NONE 0
|
#define CRYPT_NONE 0
|
||||||
|
@ -20,6 +21,8 @@
|
||||||
#define CRYPT_REQUEST 2
|
#define CRYPT_REQUEST 2
|
||||||
#define AUTH_FIRST 0
|
#define AUTH_FIRST 0
|
||||||
#define AUTH_NESTED 2
|
#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
|
// mifare 4bit card answers
|
||||||
#define CARD_ACK 0x0A // 1010 - ACK
|
#define CARD_ACK 0x0A // 1010 - ACK
|
||||||
|
@ -99,4 +102,10 @@ int emlGetValBl(uint32_t *blReg, uint8_t *blBlock, int blockNum);
|
||||||
int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum);
|
int emlSetValBl(uint32_t blReg, uint8_t blBlock, int blockNum);
|
||||||
int emlCheckValBl(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
|
#endif
|
||||||
|
|
|
@ -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)) {
|
if (showWaitCycles && !isResponse && next_record_is_response(tracepos, trace)) {
|
||||||
uint32_t next_timestamp = *((uint32_t *)(trace + tracepos));
|
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),
|
(EndOfTransmissionTimestamp - first_timestamp),
|
||||||
(next_timestamp - first_timestamp),
|
(next_timestamp - first_timestamp),
|
||||||
" ",
|
" ",
|
||||||
|
|
265
client/cmdhfmf.c
265
client/cmdhfmf.c
|
@ -524,13 +524,6 @@ int CmdHF14AMfRestore(const char *Cmd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint64_t Key[2];
|
|
||||||
int foundKey[2];
|
|
||||||
} sector_t;
|
|
||||||
|
|
||||||
|
|
||||||
# define NESTED_KEY_COUNT 15
|
# define NESTED_KEY_COUNT 15
|
||||||
int CmdHF14AMfNested(const char *Cmd)
|
int CmdHF14AMfNested(const char *Cmd)
|
||||||
{
|
{
|
||||||
|
@ -686,35 +679,12 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
if (e_sector == NULL) return 1;
|
if (e_sector == NULL) return 1;
|
||||||
|
|
||||||
//test current key and additional standard keys first
|
//test current key and additional standard keys first
|
||||||
memcpy(keyBlock, key, 6);
|
for (int defaultKeyCounter = 0; defaultKeyCounter < MifareDefaultKeysSize; defaultKeyCounter++){
|
||||||
num_to_bytes(0xffffffffffff, 6, (uint8_t*)(keyBlock + 1 * 6));
|
num_to_bytes(MifareDefaultKeys[defaultKeyCounter], 6, (uint8_t*)(keyBlock + defaultKeyCounter * 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));
|
|
||||||
num_to_bytes(0x1a2b3c4d5e6f, 6, (uint8_t*)(keyBlock + 14 * 6));
|
|
||||||
|
|
||||||
PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt);
|
PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt);
|
||||||
for (i = 0; i < SectorsCnt; i++) {
|
mfCheckKeysSec(SectorsCnt, 2, MF_CHKKEYS_DEFTIMEOUT, true, NESTED_KEY_COUNT, keyBlock, e_sector);
|
||||||
for (j = 0; j < 2; j++) {
|
|
||||||
if (e_sector[i].foundKey[j]) continue;
|
|
||||||
|
|
||||||
res = mfCheckKeys(FirstBlockOfSector(i), j, true, NESTED_KEY_COUNT, keyBlock, &key64);
|
|
||||||
|
|
||||||
if (!res) {
|
|
||||||
e_sector[i].Key[j] = key64;
|
|
||||||
e_sector[i].foundKey[j] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get known key from array
|
// get known key from array
|
||||||
bool keyFound = false;
|
bool keyFound = false;
|
||||||
|
@ -772,6 +742,9 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
PrintAndLog("Found valid key:%012" PRIx64, key64);
|
PrintAndLog("Found valid key:%012" PRIx64, key64);
|
||||||
e_sector[sectorNo].foundKey[trgKeyType] = 1;
|
e_sector[sectorNo].foundKey[trgKeyType] = 1;
|
||||||
e_sector[sectorNo].Key[trgKeyType] = key64;
|
e_sector[sectorNo].Key[trgKeyType] = key64;
|
||||||
|
|
||||||
|
// try to check this key as a key to the other sectors
|
||||||
|
mfCheckKeysSec(SectorsCnt, 2, MF_CHKKEYS_DEFTIMEOUT, true, 1, keyBlock, e_sector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -781,66 +754,6 @@ int CmdHF14AMfNested(const char *Cmd)
|
||||||
PrintAndLog("\n\n-----------------------------------------------\nNested statistic:\nIterations count: %d", iterations);
|
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);
|
PrintAndLog("Time in nested: %1.3f (%1.3f sec per key)", ((float)(msclock() - msclock1))/1000.0, ((float)(msclock() - msclock1))/iterations/1000.0);
|
||||||
|
|
||||||
// check if we have unrecognized keys
|
|
||||||
bool notFoundKeys = false;
|
|
||||||
for (i = 0; i < SectorsCnt; i++) {
|
|
||||||
for (j = 0; j < 2; j++) {
|
|
||||||
if (!e_sector[i].foundKey[j]) {
|
|
||||||
notFoundKeys = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (notFoundKeys) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (notFoundKeys) {
|
|
||||||
PrintAndLog("-----------------------------------------------\n");
|
|
||||||
PrintAndLog("We have unrecognized keys. Trying to check if we have this keys on key buffer...");
|
|
||||||
|
|
||||||
// fill keyBlock with known keys
|
|
||||||
int cnt = 0;
|
|
||||||
for (i = 0; i < SectorsCnt; i++) {
|
|
||||||
for (j = 0; j < 2; j++) {
|
|
||||||
if (e_sector[i].foundKey[j]) {
|
|
||||||
// try to insert key to keyBlock
|
|
||||||
if (cnt < NESTED_KEY_COUNT) {
|
|
||||||
|
|
||||||
// search for dublicates
|
|
||||||
bool dubl = false;
|
|
||||||
for (int v = 0; v < NESTED_KEY_COUNT; v++) {
|
|
||||||
if (e_sector[i].Key[j] == bytes_to_num((uint8_t*)(keyBlock + v * 6), 6)) {
|
|
||||||
dubl = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert
|
|
||||||
if (!dubl) {
|
|
||||||
num_to_bytes(e_sector[i].Key[j], 6, (uint8_t*)(keyBlock + cnt * 6));
|
|
||||||
cnt++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to auth with known keys to not recognized sectors keys
|
|
||||||
PrintAndLog("Testing keys. Sector count=%d known keys count:%d", SectorsCnt, cnt);
|
|
||||||
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, cnt, keyBlock, &key64);
|
|
||||||
|
|
||||||
if (!res) {
|
|
||||||
e_sector[i].Key[j] = key64;
|
|
||||||
e_sector[i].foundKey[j] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // if (notFoundKeys)
|
|
||||||
|
|
||||||
// print result
|
// print result
|
||||||
PrintAndLog("|---|----------------|---|----------------|---|");
|
PrintAndLog("|---|----------------|---|----------------|---|");
|
||||||
PrintAndLog("|sec|key A |res|key B |res|");
|
PrintAndLog("|sec|key A |res|key B |res|");
|
||||||
|
@ -1022,14 +935,18 @@ int CmdHF14AMfNestedHard(const char *Cmd)
|
||||||
int CmdHF14AMfChk(const char *Cmd)
|
int CmdHF14AMfChk(const char *Cmd)
|
||||||
{
|
{
|
||||||
if (strlen(Cmd)<3) {
|
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(" * - all sectors");
|
||||||
PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");
|
PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");
|
||||||
PrintAndLog("d - write keys to binary file\n");
|
PrintAndLog("d - write keys to binary file\n");
|
||||||
PrintAndLog("t - write keys to emulator memory");
|
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(" sample: hf mf chk 0 A 1234567890ab keys.dic");
|
||||||
PrintAndLog(" hf mf chk *1 ? t");
|
PrintAndLog(" hf mf chk *1 ? t");
|
||||||
PrintAndLog(" hf mf chk *1 ? d");
|
PrintAndLog(" hf mf chk *1 ? d");
|
||||||
|
PrintAndLog(" hf mf chk *1 ? s");
|
||||||
|
PrintAndLog(" hf mf chk *1 ? dss");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1042,42 +959,28 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
int i, res;
|
int i, res;
|
||||||
int keycnt = 0;
|
int keycnt = 0;
|
||||||
char ctmp = 0x00;
|
char ctmp = 0x00;
|
||||||
|
char ctmp3[3] = {0x00};
|
||||||
uint8_t blockNo = 0;
|
uint8_t blockNo = 0;
|
||||||
uint8_t SectorsCnt = 1;
|
uint8_t SectorsCnt = 0;
|
||||||
uint8_t keyType = 0;
|
uint8_t keyType = 0;
|
||||||
uint64_t key64 = 0;
|
uint64_t key64 = 0;
|
||||||
|
uint32_t timeout14a = 0; // timeout in us
|
||||||
|
bool param3InUse = false;
|
||||||
|
|
||||||
int transferToEml = 0;
|
int transferToEml = 0;
|
||||||
int createDumpFile = 0;
|
int createDumpFile = 0;
|
||||||
|
|
||||||
|
sector_t *e_sector = NULL;
|
||||||
|
|
||||||
keyBlock = calloc(stKeyBlock, 6);
|
keyBlock = calloc(stKeyBlock, 6);
|
||||||
if (keyBlock == NULL) return 1;
|
if (keyBlock == NULL) return 1;
|
||||||
|
|
||||||
uint64_t defaultKeys[] =
|
int defaultKeysSize = MifareDefaultKeysSize;
|
||||||
{
|
for (int defaultKeyCounter = 0; defaultKeyCounter < defaultKeysSize; defaultKeyCounter++){
|
||||||
0xffffffffffff, // Default key (first key used by program if no user defined key)
|
num_to_bytes(MifareDefaultKeys[defaultKeyCounter], 6, (uint8_t*)(keyBlock + defaultKeyCounter * 6));
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param_getchar(Cmd, 0)=='*') {
|
if (param_getchar(Cmd, 0)=='*') {
|
||||||
blockNo = 3;
|
|
||||||
SectorsCnt = ParamCardSizeSectors(param_getchar(Cmd + 1, 0));
|
SectorsCnt = ParamCardSizeSectors(param_getchar(Cmd + 1, 0));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1086,10 +989,10 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
ctmp = param_getchar(Cmd, 1);
|
ctmp = param_getchar(Cmd, 1);
|
||||||
switch (ctmp) {
|
switch (ctmp) {
|
||||||
case 'a': case 'A':
|
case 'a': case 'A':
|
||||||
keyType = !0;
|
keyType = 0;
|
||||||
break;
|
break;
|
||||||
case 'b': case 'B':
|
case 'b': case 'B':
|
||||||
keyType = !1;
|
keyType = 1;
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
keyType = 2;
|
keyType = 2;
|
||||||
|
@ -1100,11 +1003,33 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
return 1;
|
return 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// transfer to emulator & create dump file
|
||||||
ctmp = param_getchar(Cmd, 2);
|
ctmp = param_getchar(Cmd, 2);
|
||||||
if (ctmp == 't' || ctmp == 'T') transferToEml = 1;
|
if (ctmp == 't' || ctmp == 'T') transferToEml = 1;
|
||||||
else if (ctmp == 'd' || ctmp == 'D') createDumpFile = 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 (!param_gethex(Cmd, 2 + i, keyBlock + 6 * keycnt, 12)) {
|
||||||
if ( stKeyBlock - keycnt < 2) {
|
if ( stKeyBlock - keycnt < 2) {
|
||||||
p = realloc(keyBlock, 6*(stKeyBlock+=10));
|
p = realloc(keyBlock, 6*(stKeyBlock+=10));
|
||||||
|
@ -1169,6 +1094,7 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fill with default keys
|
||||||
if (keycnt == 0) {
|
if (keycnt == 0) {
|
||||||
PrintAndLog("No key specified, trying default keys");
|
PrintAndLog("No key specified, trying default keys");
|
||||||
for (;keycnt < defaultKeysSize; keycnt++)
|
for (;keycnt < defaultKeysSize; keycnt++)
|
||||||
|
@ -1178,47 +1104,84 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize storage for found keys
|
// initialize storage for found keys
|
||||||
bool validKey[2][40];
|
e_sector = calloc(SectorsCnt, sizeof(sector_t));
|
||||||
uint8_t foundKey[2][40][6];
|
if (e_sector == NULL) return 1;
|
||||||
for (uint16_t t = 0; t < 2; t++) {
|
for (uint8_t keyAB = 0; keyAB < 2; keyAB++) {
|
||||||
for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) {
|
for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) {
|
||||||
validKey[t][sectorNo] = false;
|
e_sector[sectorNo].Key[keyAB] = 0xffffffffffff;
|
||||||
for (uint16_t i = 0; i < 6; i++) {
|
e_sector[sectorNo].foundKey[keyAB] = 0;
|
||||||
foundKey[t][sectorNo][i] = 0xff;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
for ( int t = !keyType; t < 2; keyType==2?(t++):(t=2) ) {
|
bool foundAKey = false;
|
||||||
int b=blockNo;
|
uint32_t max_keys = keycnt > USB_CMD_DATA_SIZE / 6 ? USB_CMD_DATA_SIZE / 6 : keycnt;
|
||||||
for (int i = 0; i < SectorsCnt; ++i) {
|
if (SectorsCnt) {
|
||||||
PrintAndLog("--sector:%2d, block:%3d, key type:%C, key count:%2d ", i, b, t?'B':'A', keycnt);
|
PrintAndLog("To cancel this operation press the button on the proxmark...");
|
||||||
uint32_t max_keys = keycnt>USB_CMD_DATA_SIZE/6?USB_CMD_DATA_SIZE/6:keycnt;
|
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) {
|
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 != 1) {
|
||||||
if (!res) {
|
if (!res) {
|
||||||
PrintAndLog("Found valid key:[%012" PRIx64 "]",key64);
|
PrintAndLog("Found valid key:[%d:%c]%012" PRIx64, blockNo, (keyAB & 0x01)?'B':'A', key64);
|
||||||
num_to_bytes(key64, 6, foundKey[t][i]);
|
foundAKey = true;
|
||||||
validKey[t][i] = true;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintAndLog("Command execute timeout");
|
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) {
|
if (transferToEml) {
|
||||||
uint8_t block[16];
|
uint8_t block[16];
|
||||||
for (uint16_t sectorNo = 0; sectorNo < SectorsCnt; sectorNo++) {
|
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);
|
mfEmlGetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
|
||||||
for (uint16_t t = 0; t < 2; t++) {
|
for (uint16_t t = 0; t < 2; t++) {
|
||||||
if (validKey[t][sectorNo]) {
|
if (e_sector[sectorNo].foundKey[t]) {
|
||||||
memcpy(block + t*10, foundKey[t][sectorNo], 6);
|
num_to_bytes(e_sector[sectorNo].Key[t], 6, block + t * 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mfEmlSetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
|
mfEmlSetMem(block, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
|
||||||
|
@ -1231,16 +1194,22 @@ int CmdHF14AMfChk(const char *Cmd)
|
||||||
FILE *fkeys = fopen("dumpkeys.bin","wb");
|
FILE *fkeys = fopen("dumpkeys.bin","wb");
|
||||||
if (fkeys == NULL) {
|
if (fkeys == NULL) {
|
||||||
PrintAndLog("Could not create file dumpkeys.bin");
|
PrintAndLog("Could not create file dumpkeys.bin");
|
||||||
|
free(e_sector);
|
||||||
free(keyBlock);
|
free(keyBlock);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
for (uint16_t t = 0; t < 2; t++) {
|
uint8_t mkey[6];
|
||||||
fwrite(foundKey[t], 1, 6*SectorsCnt, fkeys);
|
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);
|
fclose(fkeys);
|
||||||
PrintAndLog("Found keys have been dumped to file dumpkeys.bin. 0xffffffffffff has been inserted for unknown keys.");
|
PrintAndLog("Found keys have been dumped to file dumpkeys.bin. 0xffffffffffff has been inserted for unknown keys.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(e_sector);
|
||||||
free(keyBlock);
|
free(keyBlock);
|
||||||
PrintAndLog("");
|
PrintAndLog("");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#ifndef CMDHFMF_H__
|
#ifndef CMDHFMF_H__
|
||||||
#define CMDHFMF_H__
|
#define CMDHFMF_H__
|
||||||
|
|
||||||
|
#include "mifaredefault.h"
|
||||||
|
|
||||||
extern int CmdHFMF(const char *Cmd);
|
extern int CmdHFMF(const char *Cmd);
|
||||||
|
|
||||||
extern int CmdHF14AMfDbg(const char* cmd);
|
extern int CmdHF14AMfDbg(const char* cmd);
|
||||||
|
|
|
@ -139,7 +139,7 @@ int getCommand(UsbCommand* response)
|
||||||
* @param ms_timeout
|
* @param ms_timeout
|
||||||
* @return true if command was returned, otherwise false
|
* @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;
|
UsbCommand resp;
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeou
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
msleep(10); // XXX ugh
|
msleep(10); // XXX ugh
|
||||||
if (dm_seconds == 200) { // Two seconds elapsed
|
if (dm_seconds == 200 && show_warning) { // Two seconds elapsed
|
||||||
PrintAndLog("Waiting for a response from the proxmark...");
|
PrintAndLog("Waiting for a response from the proxmark...");
|
||||||
PrintAndLog("Don't forget to cancel its operation first by pressing on the button");
|
PrintAndLog("Don't forget to cancel its operation first by pressing on the button");
|
||||||
}
|
}
|
||||||
|
@ -163,9 +163,12 @@ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeou
|
||||||
return false;
|
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) {
|
bool WaitForResponse(uint32_t cmd, UsbCommand* response) {
|
||||||
return WaitForResponseTimeout(cmd,response,-1);
|
return WaitForResponseTimeoutW(cmd, response, -1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
extern void UsbCommandReceived(UsbCommand *UC);
|
extern void UsbCommandReceived(UsbCommand *UC);
|
||||||
extern int CommandReceived(char *Cmd);
|
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 WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout);
|
||||||
extern bool WaitForResponse(uint32_t cmd, UsbCommand* response);
|
extern bool WaitForResponse(uint32_t cmd, UsbCommand* response);
|
||||||
extern void clearCommandBuffer();
|
extern void clearCommandBuffer();
|
||||||
|
|
40
client/mifaredefault.h
Normal file
40
client/mifaredefault.h
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) 2017 Merlok
|
||||||
|
//
|
||||||
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||||
|
// the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Mifare default constants
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef MIFAREDEFAULT_H__
|
||||||
|
#define MIFAREDEFAULT_H__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define MifareDefaultKeysSize sizeof(MifareDefaultKeys) / sizeof(uint64_t)
|
||||||
|
|
||||||
|
static const uint64_t MifareDefaultKeys[] =
|
||||||
|
{
|
||||||
|
0xffffffffffff, // Default key (first key used by program if no user defined key)
|
||||||
|
0x000000000000, // Blank key
|
||||||
|
0xa0a1a2a3a4a5, // NFCForum MAD key
|
||||||
|
0xb0b1b2b3b4b5,
|
||||||
|
0xaabbccddeeff,
|
||||||
|
0x1a2b3c4d5e6f,
|
||||||
|
0x123456789abc,
|
||||||
|
0x010203040506,
|
||||||
|
0x123456abcdef,
|
||||||
|
0xabcdef123456,
|
||||||
|
0x4d3a99c351dd,
|
||||||
|
0x1a982c7e459a,
|
||||||
|
0xd3f7d3f7d3f7,
|
||||||
|
0x714c5c886e97,
|
||||||
|
0x587ee5f9350f,
|
||||||
|
0xa0478cc39091,
|
||||||
|
0x533cb6c723f6,
|
||||||
|
0x8fd0a4f256e9
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -228,17 +228,46 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t key
|
||||||
|
|
||||||
*key = -1;
|
*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);
|
memcpy(c.d.asBytes, keyBlock, 6 * keycnt);
|
||||||
SendCommand(&c);
|
SendCommand(&c);
|
||||||
|
|
||||||
UsbCommand resp;
|
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;
|
if ((resp.arg[0] & 0xff) != 0x01) return 2;
|
||||||
*key = bytes_to_num(resp.d.asBytes, 6);
|
*key = bytes_to_num(resp.d.asBytes, 6);
|
||||||
return 0;
|
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
|
// Compare 16 Bits out of cryptostate
|
||||||
int Compare16Bits(const void * a, const void * b) {
|
int Compare16Bits(const void * a, const void * b) {
|
||||||
if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0;
|
if ((*(uint64_t*)b & 0x00ff000000ff0000) == (*(uint64_t*)a & 0x00ff000000ff0000)) return 0;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Merlok, 2011
|
// Merlok, 2011, 2017
|
||||||
// people from mifare@nethemba.com, 2010
|
// people from mifare@nethemba.com, 2010
|
||||||
//
|
//
|
||||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||||
|
@ -15,6 +15,11 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "data.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
|
// mfCSetBlock work flags
|
||||||
#define CSETBLOCK_UID 0x01
|
#define CSETBLOCK_UID 0x01
|
||||||
#define CSETBLOCK_WUPC 0x02
|
#define CSETBLOCK_WUPC 0x02
|
||||||
|
@ -24,11 +29,17 @@
|
||||||
#define CSETBLOCK_SINGLE_OPER 0x1F
|
#define CSETBLOCK_SINGLE_OPER 0x1F
|
||||||
#define CSETBLOCK_MAGIC_1B 0x40
|
#define CSETBLOCK_MAGIC_1B 0x40
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint64_t Key[2];
|
||||||
|
int foundKey[2];
|
||||||
|
} sector_t;
|
||||||
|
|
||||||
extern char logHexFileName[FILE_PATH_SIZE];
|
extern char logHexFileName[FILE_PATH_SIZE];
|
||||||
|
|
||||||
extern int mfDarkside(uint64_t *key);
|
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 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 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 mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||||
extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
extern int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue