Implemented VB6 rng for iclass lookup elite key search

Ported @bettse work from the Flipper Zero Picopass repository to use the lookup function with the VB6 rng
This commit is contained in:
Antiklesys 2024-07-12 11:18:17 +08:00
commit 96e3e07faa
3 changed files with 90 additions and 17 deletions

View file

@ -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 new t55xx password (002BCFCF) sniffed from cheap cloner (@davidbeauchamp)
- 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]
- Fixed the pm3 regressiontests for Hitag2Crack (@iceman1001)

View file

@ -3774,29 +3774,84 @@ out:
// 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.
#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) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf iclass lookup",
"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 --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[] = {
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, "epurse", "<hex>", "Specify ePurse as 8 hex bytes"),
arg_str1(NULL, "macs", "<hex>", "MACs"),
arg_lit0(NULL, "elite", "Elite 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
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
bool use_vb6kdf = arg_get_lit(ctx, 7);
int fnlen = 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;
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);
uint8_t CCNR[12];
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 + 8, macs, 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, "TAG MAC: %s", sprint_hex(MAC_TAG, sizeof(MAC_TAG)));
// run time
// Run time
uint64_t t1 = msclock();
uint8_t *keyBlock = NULL;
uint32_t keycount = 0;
// load keys
int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
if (res != PM3_SUCCESS || keycount == 0) {
free(keyBlock);
return res;
if (!use_vb6kdf) {
// Load keys
int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount);
if (res != PM3_SUCCESS || keycount == 0) {
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));
if (!prekey) {
free(keyBlock);
@ -3883,7 +3949,7 @@ static int CmdHFiClassLookUp(const char *Cmd) {
PrintAndLogEx(INFO, "Sorting...");
// sort mac list.
// Sort mac list
qsort(prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", "DEBIT");
@ -3891,7 +3957,7 @@ static int CmdHFiClassLookUp(const char *Cmd) {
iclass_prekey_t lookup;
memcpy(lookup.mac, MAC_TAG, 4);
// binsearch
// Binsearch
item = (iclass_prekey_t *) bsearch(&lookup, prekey, keycount, sizeof(iclass_prekey_t), cmp_uint32);
if (item != NULL) {
@ -3900,7 +3966,7 @@ static int CmdHFiClassLookUp(const char *Cmd) {
}
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(keyBlock);

View file

@ -36,4 +36,10 @@ void PrintPreCalc(iclass_prekey_t *list, uint32_t itemcnt);
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);
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