mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
hf iclass list - now tries to recovery key
This commit is contained in:
parent
9ade745f07
commit
508151ee3a
5 changed files with 141 additions and 72 deletions
|
@ -362,6 +362,46 @@ static int usage_hf_iclass_permutekey(void) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cmp_uint32(const void *a, const void *b) {
|
||||||
|
|
||||||
|
const iclass_prekey_t *x = (const iclass_prekey_t *)a;
|
||||||
|
const iclass_prekey_t *y = (const iclass_prekey_t *)b;
|
||||||
|
|
||||||
|
uint32_t mx = bytes_to_num((uint8_t *)x->mac, 4);
|
||||||
|
uint32_t my = bytes_to_num((uint8_t *)y->mac, 4);
|
||||||
|
|
||||||
|
if (mx < my)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return mx > my;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t* rmac, uint8_t* tmac, uint8_t* key) {
|
||||||
|
|
||||||
|
iclass_prekey_t *prekey = calloc(ICLASS_KEYS_MAX, sizeof(iclass_prekey_t));
|
||||||
|
if (prekey == false) {
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ccnr[12];
|
||||||
|
memcpy(ccnr, epurse, 8);
|
||||||
|
memcpy(ccnr + 8, rmac, 4);
|
||||||
|
|
||||||
|
GenerateMacKeyFrom(csn, ccnr, false, false, (uint8_t*)iClass_Key_Table, ICLASS_KEYS_MAX, prekey);
|
||||||
|
qsort(prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32);
|
||||||
|
|
||||||
|
iclass_prekey_t lookup;
|
||||||
|
memcpy(lookup.mac, tmac, 4);
|
||||||
|
|
||||||
|
// binsearch
|
||||||
|
iclass_prekey_t * item = (iclass_prekey_t *) bsearch(&lookup, prekey, ICLASS_KEYS_MAX, sizeof(iclass_prekey_t), cmp_uint32);
|
||||||
|
if (item != NULL) {
|
||||||
|
memcpy(key, item->key, 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
None = 0,
|
None = 0,
|
||||||
DES,
|
DES,
|
||||||
|
@ -415,7 +455,7 @@ static uint8_t notset(uint8_t val, uint8_t mask) {
|
||||||
return !(val & mask);
|
return !(val & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t get_pagemap(const picopass_hdr *hdr) {
|
uint8_t get_pagemap(const picopass_hdr *hdr) {
|
||||||
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
return (hdr->conf.fuses & (FUSE_CRYPT0 | FUSE_CRYPT1)) >> 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2926,9 +2966,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
||||||
|
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
uint8_t fileNameLen = 0;
|
uint8_t fileNameLen = 0;
|
||||||
iclass_premac_t *pre = NULL;
|
|
||||||
|
|
||||||
// time
|
|
||||||
uint64_t t1 = msclock();
|
uint64_t t1 = msclock();
|
||||||
|
|
||||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||||
|
@ -2973,7 +3011,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre = calloc(keycount, sizeof(iclass_premac_t));
|
iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t));
|
||||||
if (!pre) {
|
if (!pre) {
|
||||||
free(keyBlock);
|
free(keyBlock);
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
|
@ -3116,20 +3154,6 @@ out:
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmp_uint32(const void *a, const void *b) {
|
|
||||||
|
|
||||||
const iclass_prekey_t *x = (const iclass_prekey_t *)a;
|
|
||||||
const iclass_prekey_t *y = (const iclass_prekey_t *)b;
|
|
||||||
|
|
||||||
uint32_t mx = bytes_to_num((uint8_t *)x->mac, 4);
|
|
||||||
uint32_t my = bytes_to_num((uint8_t *)y->mac, 4);
|
|
||||||
|
|
||||||
if (mx < my)
|
|
||||||
return -1;
|
|
||||||
else
|
|
||||||
return mx > my;
|
|
||||||
}
|
|
||||||
|
|
||||||
// this method tries to identify in which configuration mode a iCLASS / iCLASS SE reader is in.
|
// this method tries to identify in which configuration mode a iCLASS / iCLASS SE reader is in.
|
||||||
// Standard or Elite / HighSecurity mode. It uses a default key dictionary list in order to work.
|
// Standard or Elite / HighSecurity mode. It uses a default key dictionary list in order to work.
|
||||||
static int CmdHFiClassLookUp(const char *Cmd) {
|
static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "fileutils.h"
|
#include "fileutils.h"
|
||||||
|
#include "pm3_cmd.h"
|
||||||
|
|
||||||
typedef struct iclass_block {
|
typedef struct iclass_block {
|
||||||
uint8_t d[8];
|
uint8_t d[8];
|
||||||
|
@ -38,4 +39,7 @@ void GenerateMacFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite,
|
||||||
void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite, uint8_t *keys, uint32_t keycnt, iclass_prekey_t *list);
|
void GenerateMacKeyFrom(uint8_t *CSN, uint8_t *CCNR, bool use_raw, bool use_elite, uint8_t *keys, uint32_t keycnt, iclass_prekey_t *list);
|
||||||
void PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list);
|
void PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list);
|
||||||
void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt);
|
void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt);
|
||||||
|
|
||||||
|
uint8_t get_pagemap(const picopass_hdr *hdr);
|
||||||
|
bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t* rmac, uint8_t* tmac, uint8_t* key);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "crc16.h"
|
#include "crc16.h"
|
||||||
#include "crapto1/crapto1.h"
|
#include "crapto1/crapto1.h"
|
||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
|
#include "cmdhficlass.h"
|
||||||
|
|
||||||
enum MifareAuthSeq {
|
enum MifareAuthSeq {
|
||||||
masNone,
|
masNone,
|
||||||
|
@ -326,59 +327,99 @@ void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||||
applyIso14443a(exp, size, cmd, cmdsize);
|
applyIso14443a(exp, size, cmd, cmdsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse) {
|
||||||
uint8_t c = cmd[0] & 0x0F;
|
|
||||||
uint8_t parity = 0;
|
|
||||||
for (uint8_t i = 0; i < 7; i++) {
|
|
||||||
parity ^= (cmd[0] >> i) & 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (c) {
|
enum pico_state {PICO_NONE, PICO_SELECT, PICO_AUTH_EPURSE, PICO_AUTH_MACS };
|
||||||
case ICLASS_CMD_HALT:
|
static enum pico_state curr_state = PICO_NONE;
|
||||||
snprintf(exp, size, "HALT");
|
static uint8_t csn[8];
|
||||||
break;
|
static uint8_t epurse[8];
|
||||||
case ICLASS_CMD_SELECT:
|
static uint8_t rmac[4];
|
||||||
snprintf(exp, size, "SELECT");
|
static uint8_t tmac[4];
|
||||||
break;
|
|
||||||
case ICLASS_CMD_ACTALL:
|
if ( isResponse == false ) {
|
||||||
snprintf(exp, size, "ACTALL");
|
uint8_t c = cmd[0] & 0x0F;
|
||||||
break;
|
uint8_t parity = 0;
|
||||||
case ICLASS_CMD_DETECT:
|
for (uint8_t i = 0; i < 7; i++) {
|
||||||
snprintf(exp, size, "DETECT");
|
parity ^= (cmd[0] >> i) & 1;
|
||||||
break;
|
|
||||||
case ICLASS_CMD_CHECK:
|
|
||||||
snprintf(exp, size, "CHECK");
|
|
||||||
break;
|
|
||||||
case ICLASS_CMD_READ4:
|
|
||||||
snprintf(exp, size, "READ4(%d)", cmd[1]);
|
|
||||||
break;
|
|
||||||
case ICLASS_CMD_READ_OR_IDENTIFY: {
|
|
||||||
if (cmdsize > 1) {
|
|
||||||
snprintf(exp, size, "READ(%d)", cmd[1]);
|
|
||||||
} else {
|
|
||||||
snprintf(exp, size, "IDENTIFY");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case ICLASS_CMD_PAGESEL:
|
|
||||||
snprintf(exp, size, "PAGESEL(%d)", cmd[1]);
|
switch (c) {
|
||||||
break;
|
case ICLASS_CMD_HALT:
|
||||||
case ICLASS_CMD_UPDATE:
|
snprintf(exp, size, "HALT");
|
||||||
snprintf(exp, size, "UPDATE(%d)", cmd[1]);
|
curr_state = PICO_NONE;
|
||||||
break;
|
break;
|
||||||
case ICLASS_CMD_READCHECK:
|
case ICLASS_CMD_SELECT:
|
||||||
if (ICLASS_CREDIT(cmd[0])) {
|
snprintf(exp, size, "SELECT");
|
||||||
snprintf(exp, size, "READCHECK[Kc](%d)", cmd[1]);
|
curr_state = PICO_SELECT;
|
||||||
} else {
|
break;
|
||||||
snprintf(exp, size, "READCHECK[Kd](%d)", cmd[1]);
|
case ICLASS_CMD_ACTALL:
|
||||||
|
snprintf(exp, size, "ACTALL");
|
||||||
|
curr_state = PICO_NONE;
|
||||||
|
break;
|
||||||
|
case ICLASS_CMD_DETECT:
|
||||||
|
snprintf(exp, size, "DETECT");
|
||||||
|
curr_state = PICO_NONE;
|
||||||
|
break;
|
||||||
|
case ICLASS_CMD_CHECK:
|
||||||
|
snprintf(exp, size, "CHECK");
|
||||||
|
curr_state = PICO_AUTH_MACS;
|
||||||
|
memcpy(rmac, cmd + 1, 4);
|
||||||
|
memcpy(tmac, cmd + 5, 4);
|
||||||
|
break;
|
||||||
|
case ICLASS_CMD_READ4:
|
||||||
|
snprintf(exp, size, "READ4(%d)", cmd[1]);
|
||||||
|
break;
|
||||||
|
case ICLASS_CMD_READ_OR_IDENTIFY: {
|
||||||
|
|
||||||
|
if (cmdsize > 1) {
|
||||||
|
snprintf(exp, size, "READ(%d)", cmd[1]);
|
||||||
|
} else {
|
||||||
|
snprintf(exp, size, "IDENTIFY");
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
break;
|
case ICLASS_CMD_PAGESEL:
|
||||||
case ICLASS_CMD_ACT:
|
snprintf(exp, size, "PAGESEL(%d)", cmd[1]);
|
||||||
snprintf(exp, size, "ACT");
|
curr_state = PICO_NONE;
|
||||||
break;
|
break;
|
||||||
default:
|
case ICLASS_CMD_UPDATE:
|
||||||
snprintf(exp, size, "?");
|
snprintf(exp, size, "UPDATE(%d)", cmd[1]);
|
||||||
break;
|
curr_state = PICO_NONE;
|
||||||
|
break;
|
||||||
|
case ICLASS_CMD_READCHECK:
|
||||||
|
if (ICLASS_CREDIT(cmd[0])) {
|
||||||
|
snprintf(exp, size, "READCHECK[Kc](%d)", cmd[1]);
|
||||||
|
curr_state = PICO_AUTH_EPURSE;
|
||||||
|
} else {
|
||||||
|
snprintf(exp, size, "READCHECK[Kd](%d)", cmd[1]);
|
||||||
|
curr_state = PICO_AUTH_EPURSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ICLASS_CMD_ACT:
|
||||||
|
snprintf(exp, size, "ACT");
|
||||||
|
curr_state = PICO_NONE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
snprintf(exp, size, "?");
|
||||||
|
curr_state = PICO_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (curr_state == PICO_SELECT) {
|
||||||
|
memcpy(csn, cmd, 8);
|
||||||
|
curr_state = PICO_NONE;
|
||||||
|
} else if (curr_state == PICO_AUTH_EPURSE) {
|
||||||
|
memcpy(epurse, cmd, 8);
|
||||||
|
} else if ( curr_state == PICO_AUTH_MACS) {
|
||||||
|
|
||||||
|
uint8_t key[8];
|
||||||
|
if (check_known_default(csn, epurse, rmac, tmac, key)) {
|
||||||
|
snprintf(exp, size, "( " _GREEN_("%s") ")", sprint_hex(key, 8) );
|
||||||
|
}
|
||||||
|
curr_state = PICO_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ uint8_t iclass_CRC_check(bool isResponse, uint8_t *d, uint8_t n);
|
||||||
|
|
||||||
int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
int applyIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
|
|
||||||
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse);
|
||||||
void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
void annotateTopaz(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateTopaz(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
void annotateLegic(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
void annotateLegic(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||||
|
|
|
@ -387,6 +387,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
case PROTO_HITAGS:
|
case PROTO_HITAGS:
|
||||||
annotateHitagS(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
|
annotateHitagS(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
|
||||||
break;
|
break;
|
||||||
|
case ICLASS:
|
||||||
|
annotateIclass(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -397,9 +400,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
case LEGIC:
|
case LEGIC:
|
||||||
annotateLegic(explanation, sizeof(explanation), frame, data_len);
|
annotateLegic(explanation, sizeof(explanation), frame, data_len);
|
||||||
break;
|
break;
|
||||||
case ICLASS:
|
|
||||||
annotateIclass(explanation, sizeof(explanation), frame, data_len);
|
|
||||||
break;
|
|
||||||
case ISO_14443A:
|
case ISO_14443A:
|
||||||
annotateIso14443a(explanation, sizeof(explanation), frame, data_len);
|
annotateIso14443a(explanation, sizeof(explanation), frame, data_len);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue