mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-22 14:23:50 -07:00
Merge pull request #2419 from Antiklesys/master
Implemented VB6 rng for iclass lookup elite key search
This commit is contained in:
commit
665b4a5a93
3 changed files with 90 additions and 17 deletions
|
@ -10,6 +10,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
- Added `pm3_tears_for_fears.py` - a ISO14443b tear off script by Pierre Granier
|
- Added `pm3_tears_for_fears.py` - a ISO14443b tear off script by Pierre Granier
|
||||||
- Added new t55xx password (002BCFCF) sniffed from cheap cloner (@davidbeauchamp)
|
- Added new t55xx password (002BCFCF) sniffed from cheap cloner (@davidbeauchamp)
|
||||||
- Fixed 'hf 14b sim' - now works (@michi-jung)
|
- Fixed 'hf 14b sim' - now works (@michi-jung)
|
||||||
|
- Added VB6 Rng for iclass elite keys lookup by porting @bettse work in the Flipper Zero Picopass App (@antiklesys)
|
||||||
|
|
||||||
## [Aurora.4.18589][2024-05-28]
|
## [Aurora.4.18589][2024-05-28]
|
||||||
- Fixed the pm3 regressiontests for Hitag2Crack (@iceman1001)
|
- Fixed the pm3 regressiontests for Hitag2Crack (@iceman1001)
|
||||||
|
|
|
@ -3774,29 +3774,84 @@ out:
|
||||||
|
|
||||||
// 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.
|
||||||
|
#define INITIAL_SEED 0x429080 // VB6 KDF Seed Value
|
||||||
|
|
||||||
|
// Functions for generating keys using RNG
|
||||||
|
uint32_t seed = INITIAL_SEED;
|
||||||
|
uint8_t key_state[8];
|
||||||
|
bool prepared = false;
|
||||||
|
|
||||||
|
void picopass_elite_reset(void) {
|
||||||
|
memset(key_state, 0, sizeof(key_state));
|
||||||
|
seed = INITIAL_SEED;
|
||||||
|
prepared = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t picopass_elite_lcg(void) {
|
||||||
|
uint32_t mod = 0x1000000; // 2^24
|
||||||
|
uint32_t a = 0xFD43FD;
|
||||||
|
uint32_t c = 0xC39EC3;
|
||||||
|
|
||||||
|
return (a * seed + c) % mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t picopass_elite_rng(void) {
|
||||||
|
seed = picopass_elite_lcg();
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t picopass_elite_nextByte(void) {
|
||||||
|
return (picopass_elite_rng() >> 16) & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void picopass_elite_nextKey(uint8_t* key) {
|
||||||
|
if(prepared) {
|
||||||
|
for(size_t i = 0; i < 7; i++) {
|
||||||
|
key_state[i] = key_state[i + 1];
|
||||||
|
}
|
||||||
|
key_state[7] = picopass_elite_nextByte();
|
||||||
|
} else {
|
||||||
|
for(size_t i = 0; i < 8; i++) {
|
||||||
|
key_state[i] = picopass_elite_nextByte();
|
||||||
|
}
|
||||||
|
prepared = true;
|
||||||
|
}
|
||||||
|
memcpy(key, key_state, 8);
|
||||||
|
}
|
||||||
|
|
||||||
static int CmdHFiClassLookUp(const char *Cmd) {
|
static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf iclass lookup",
|
CLIParserInit(&ctx, "hf iclass lookup",
|
||||||
"This command take sniffed trace data and try to recovery a iCLASS Standard or iCLASS Elite key.",
|
"This command take sniffed trace data and try to recovery a iCLASS Standard or iCLASS Elite key.",
|
||||||
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic\n"
|
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic\n"
|
||||||
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite"
|
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b -f iclass_default_keys.dic --elite\n"
|
||||||
|
"hf iclass lookup --csn 9655a400f8ff12e0 --epurse f0ffffffffffffff --macs 0000000089cb984b --vb6rng"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_str1("f", "file", "<fn>", "Dictionary file with default iclass keys"),
|
arg_str0("f", "file", "<fn>", "Dictionary file with default iclass keys"),
|
||||||
arg_str1(NULL, "csn", "<hex>", "Specify CSN as 8 hex bytes"),
|
arg_str1(NULL, "csn", "<hex>", "Specify CSN as 8 hex bytes"),
|
||||||
arg_str1(NULL, "epurse", "<hex>", "Specify ePurse as 8 hex bytes"),
|
arg_str1(NULL, "epurse", "<hex>", "Specify ePurse as 8 hex bytes"),
|
||||||
arg_str1(NULL, "macs", "<hex>", "MACs"),
|
arg_str1(NULL, "macs", "<hex>", "MACs"),
|
||||||
arg_lit0(NULL, "elite", "Elite computations applied to key"),
|
arg_lit0(NULL, "elite", "Elite computations applied to key"),
|
||||||
arg_lit0(NULL, "raw", "no computations applied to key"),
|
arg_lit0(NULL, "raw", "no computations applied to key"),
|
||||||
|
arg_lit0(NULL, "vb6rng", "use the VB6 rng for elite keys instead of a dictionary file"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
|
bool use_vb6kdf = arg_get_lit(ctx, 7);
|
||||||
int fnlen = 0;
|
int fnlen = 0;
|
||||||
char filename[FILE_PATH_SIZE] = {0};
|
char filename[FILE_PATH_SIZE] = {0};
|
||||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
|
||||||
|
bool use_elite = arg_get_lit(ctx, 5);
|
||||||
|
bool use_raw = arg_get_lit(ctx, 6);
|
||||||
|
if(use_vb6kdf){
|
||||||
|
use_elite = true;
|
||||||
|
}else{
|
||||||
|
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||||
|
}
|
||||||
|
|
||||||
int csn_len = 0;
|
int csn_len = 0;
|
||||||
uint8_t csn[8] = {0};
|
uint8_t csn[8] = {0};
|
||||||
|
@ -3834,15 +3889,12 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool use_elite = arg_get_lit(ctx, 5);
|
|
||||||
bool use_raw = arg_get_lit(ctx, 6);
|
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
uint8_t CCNR[12];
|
uint8_t CCNR[12];
|
||||||
uint8_t MAC_TAG[4] = { 0, 0, 0, 0 };
|
uint8_t MAC_TAG[4] = { 0, 0, 0, 0 };
|
||||||
|
|
||||||
// stupid copy.. CCNR is a combo of epurse and reader nonce
|
// Stupid copy.. CCNR is a combo of epurse and reader nonce
|
||||||
memcpy(CCNR, epurse, 8);
|
memcpy(CCNR, epurse, 8);
|
||||||
memcpy(CCNR + 8, macs, 4);
|
memcpy(CCNR + 8, macs, 4);
|
||||||
memcpy(MAC_TAG, macs + 4, 4);
|
memcpy(MAC_TAG, macs + 4, 4);
|
||||||
|
@ -3853,20 +3905,34 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
|
PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR)));
|
||||||
PrintAndLogEx(SUCCESS, "TAG MAC: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG)));
|
PrintAndLogEx(SUCCESS, "TAG MAC: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG)));
|
||||||
|
|
||||||
// run time
|
// Run time
|
||||||
uint64_t t1 = msclock();
|
uint64_t t1 = msclock();
|
||||||
|
|
||||||
uint8_t *keyBlock = NULL;
|
uint8_t *keyBlock = NULL;
|
||||||
uint32_t keycount = 0;
|
uint32_t keycount = 0;
|
||||||
|
|
||||||
// load keys
|
if (!use_vb6kdf) {
|
||||||
int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
|
// Load keys
|
||||||
if (res != PM3_SUCCESS || keycount == 0) {
|
int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
|
||||||
free(keyBlock);
|
if (res != PM3_SUCCESS || keycount == 0) {
|
||||||
return res;
|
free(keyBlock);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Generate 5000 keys using VB6 KDF
|
||||||
|
keycount = 5000;
|
||||||
|
keyBlock = malloc(keycount * 8);
|
||||||
|
if (!keyBlock) {
|
||||||
|
return PM3_EMALLOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
picopass_elite_reset();
|
||||||
|
for (uint32_t i = 0; i < keycount; i++) {
|
||||||
|
picopass_elite_nextKey(keyBlock + (i * 8));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//iclass_prekey_t
|
// Iclass_prekey_t
|
||||||
iclass_prekey_t *prekey = calloc(keycount, sizeof(iclass_prekey_t));
|
iclass_prekey_t *prekey = calloc(keycount, sizeof(iclass_prekey_t));
|
||||||
if (!prekey) {
|
if (!prekey) {
|
||||||
free(keyBlock);
|
free(keyBlock);
|
||||||
|
@ -3883,7 +3949,7 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
|
|
||||||
PrintAndLogEx(INFO, "Sorting...");
|
PrintAndLogEx(INFO, "Sorting...");
|
||||||
|
|
||||||
// sort mac list.
|
// Sort mac list
|
||||||
qsort(prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
|
qsort(prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
|
||||||
|
|
||||||
PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", "DEBIT");
|
PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", "DEBIT");
|
||||||
|
@ -3891,7 +3957,7 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
iclass_prekey_t lookup;
|
iclass_prekey_t lookup;
|
||||||
memcpy(lookup.mac, MAC_TAG, 4);
|
memcpy(lookup.mac, MAC_TAG, 4);
|
||||||
|
|
||||||
// binsearch
|
// Binsearch
|
||||||
item = (iclass_prekey_t *) bsearch(&lookup, prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
|
item = (iclass_prekey_t *) bsearch(&lookup, prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
|
||||||
|
|
||||||
if (item != NULL) {
|
if (item != NULL) {
|
||||||
|
@ -3900,7 +3966,7 @@ static int CmdHFiClassLookUp(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
t1 = msclock() - t1;
|
t1 = msclock() - t1;
|
||||||
PrintAndLogEx(SUCCESS, "time in iclass lookup " _YELLOW_("%.3f") " seconds", (float)t1 / 1000.0);
|
PrintAndLogEx(SUCCESS, "Time in iclass lookup " _YELLOW_("%.3f") " seconds", (float)t1 / 1000.0);
|
||||||
|
|
||||||
free(prekey);
|
free(prekey);
|
||||||
free(keyBlock);
|
free(keyBlock);
|
||||||
|
|
|
@ -36,4 +36,10 @@ void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt);
|
||||||
|
|
||||||
uint8_t get_pagemap(const picopass_hdr_t *hdr);
|
uint8_t get_pagemap(const picopass_hdr_t *hdr);
|
||||||
bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key);
|
bool check_known_default(uint8_t *csn, uint8_t *epurse, uint8_t *rmac, uint8_t *tmac, uint8_t *key);
|
||||||
|
|
||||||
|
void picopass_elite_nextKey(uint8_t* key);
|
||||||
|
void picopass_elite_reset(void);
|
||||||
|
uint32_t picopass_elite_rng(void);
|
||||||
|
uint32_t picopass_elite_lcg(void);
|
||||||
|
uint8_t picopass_elite_nextByte(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue