hf iclass list - now tries to recovery key

This commit is contained in:
iceman1001 2020-08-19 21:51:10 +02:00
commit 508151ee3a
5 changed files with 141 additions and 72 deletions

View file

@ -362,6 +362,46 @@ static int usage_hf_iclass_permutekey(void) {
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 {
None = 0,
DES,
@ -415,7 +455,7 @@ static uint8_t notset(uint8_t val, uint8_t 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;
}
@ -2926,9 +2966,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
char filename[FILE_PATH_SIZE] = {0};
uint8_t fileNameLen = 0;
iclass_premac_t *pre = NULL;
// time
uint64_t t1 = msclock();
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
@ -2973,7 +3011,7 @@ static int CmdHFiClassCheckKeys(const char *Cmd) {
return res;
}
pre = calloc(keycount, sizeof(iclass_premac_t));
iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t));
if (!pre) {
free(keyBlock);
return PM3_EMALLOC;
@ -3116,20 +3154,6 @@ out:
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.
// Standard or Elite / HighSecurity mode. It uses a default key dictionary list in order to work.
static int CmdHFiClassLookUp(const char *Cmd) {

View file

@ -13,6 +13,7 @@
#include "common.h"
#include "fileutils.h"
#include "pm3_cmd.h"
typedef struct iclass_block {
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 PrintPreCalcMac(uint8_t *keys, uint32_t keycnt, iclass_premac_t *pre_list);
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

View file

@ -23,6 +23,7 @@
#include "crc16.h"
#include "crapto1/crapto1.h"
#include "protocols.h"
#include "cmdhficlass.h"
enum MifareAuthSeq {
masNone,
@ -326,59 +327,99 @@ void annotateIso14443a(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
applyIso14443a(exp, size, cmd, cmdsize);
}
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
uint8_t c = cmd[0] & 0x0F;
uint8_t parity = 0;
for (uint8_t i = 0; i < 7; i++) {
parity ^= (cmd[0] >> i) & 1;
}
void annotateIclass(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize, bool isResponse) {
switch (c) {
case ICLASS_CMD_HALT:
snprintf(exp, size, "HALT");
break;
case ICLASS_CMD_SELECT:
snprintf(exp, size, "SELECT");
break;
case ICLASS_CMD_ACTALL:
snprintf(exp, size, "ACTALL");
break;
case ICLASS_CMD_DETECT:
snprintf(exp, size, "DETECT");
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;
enum pico_state {PICO_NONE, PICO_SELECT, PICO_AUTH_EPURSE, PICO_AUTH_MACS };
static enum pico_state curr_state = PICO_NONE;
static uint8_t csn[8];
static uint8_t epurse[8];
static uint8_t rmac[4];
static uint8_t tmac[4];
if ( isResponse == false ) {
uint8_t c = cmd[0] & 0x0F;
uint8_t parity = 0;
for (uint8_t i = 0; i < 7; i++) {
parity ^= (cmd[0] >> i) & 1;
}
case ICLASS_CMD_PAGESEL:
snprintf(exp, size, "PAGESEL(%d)", cmd[1]);
break;
case ICLASS_CMD_UPDATE:
snprintf(exp, size, "UPDATE(%d)", cmd[1]);
break;
case ICLASS_CMD_READCHECK:
if (ICLASS_CREDIT(cmd[0])) {
snprintf(exp, size, "READCHECK[Kc](%d)", cmd[1]);
} else {
snprintf(exp, size, "READCHECK[Kd](%d)", cmd[1]);
switch (c) {
case ICLASS_CMD_HALT:
snprintf(exp, size, "HALT");
curr_state = PICO_NONE;
break;
case ICLASS_CMD_SELECT:
snprintf(exp, size, "SELECT");
curr_state = PICO_SELECT;
break;
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_ACT:
snprintf(exp, size, "ACT");
break;
default:
snprintf(exp, size, "?");
break;
case ICLASS_CMD_PAGESEL:
snprintf(exp, size, "PAGESEL(%d)", cmd[1]);
curr_state = PICO_NONE;
break;
case ICLASS_CMD_UPDATE:
snprintf(exp, size, "UPDATE(%d)", cmd[1]);
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;
}

View file

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

View file

@ -387,6 +387,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
case PROTO_HITAGS:
annotateHitagS(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
break;
case ICLASS:
annotateIclass(explanation, sizeof(explanation), frame, data_len, hdr->isResponse);
break;
default:
break;
}
@ -397,9 +400,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
case LEGIC:
annotateLegic(explanation, sizeof(explanation), frame, data_len);
break;
case ICLASS:
annotateIclass(explanation, sizeof(explanation), frame, data_len);
break;
case ISO_14443A:
annotateIso14443a(explanation, sizeof(explanation), frame, data_len);
break;