From: Merlokbr@gmail.com Date: Fri, 17 Jun 2011 18:39:54 +0000 (+0000) Subject: 1. updated usb commands X-Git-Tag: v1.0.0~253 X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/8556b852ed769280d1b63054ab1bd08fa19b746a 1. updated usb commands 2. added abilities to: clear, get, set, load from card, load from nested card emulator dump 3. tried to fix proxmark promt have seen everywhere (not so good) 4. reorganized arm code --- diff --git a/armsrc/Makefile b/armsrc/Makefile index 565de2fe..b30de757 100644 --- a/armsrc/Makefile +++ b/armsrc/Makefile @@ -16,7 +16,7 @@ APP_CFLAGS = -O2 -DWITH_LF -DWITH_ISO15693 -DWITH_ISO14443a -DWITH_ISO14443b #SRC_LCD = fonts.c LCD.c SRC_LF = lfops.c hitag2.c SRC_ISO15693 = iso15693.c iso15693tools.c -SRC_ISO14443a = iso14443a.c mifareutil.c +SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c SRC_ISO14443b = iso14443.c SRC_CRAPTO1 = crapto1.c crypto1.c diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 501f07a5..f2ae56d8 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -713,6 +713,23 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_SIMULATE_MIFARE_CARD: Mifare1ksim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; + + // emulator + case CMD_MIFARE_SET_DBGMODE: + MifareSetDbgLvl(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; + case CMD_MIFARE_EML_MEMCLR: + MifareEMemClr(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; + case CMD_MIFARE_EML_MEMSET: + MifareEMemSet(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; + case CMD_MIFARE_EML_MEMGET: + MifareEMemGet(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; + case CMD_MIFARE_EML_CARDLOAD: + MifareECardLoad(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; #endif diff --git a/armsrc/apps.h b/armsrc/apps.h index 3b461136..c458595e 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -107,6 +107,8 @@ void SnoopIso14443(void); void RAMFUNC SnoopIso14443a(void); void SimulateIso14443aTag(int tagType, int TagUid); // ## simulate iso14443a tag void ReaderIso14443a(UsbCommand * c, UsbCommand * ack); + +// mifarecmd.h void ReaderMifare(uint32_t parameter); void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *data); void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); @@ -114,6 +116,11 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); +void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); +void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain); /// iso15693.h void RecordRawAdcSamplesIso15693(void); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index ce8467bf..74e269da 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -65,6 +65,13 @@ void iso14a_set_trigger(int enable) { trigger = enable; } +void iso14a_clear_tracelen(void) { + traceLen = 0; +} +void iso14a_set_tracing(int enable) { + tracing = enable; +} + //----------------------------------------------------------------------------- // Generate the parity value for a byte sequence // @@ -836,7 +843,7 @@ static void CodeIso14443aAsTagPar(const uint8_t *cmd, int len, uint32_t dwParity // Flush the buffer in FPGA!! for(i = 0; i < 5; i++) { - ToSend[++ToSendMax] = SEC_F; +// ToSend[++ToSendMax] = SEC_F; } // Convert from last byte pos to length @@ -1989,582 +1996,6 @@ void ReaderMifare(uint32_t parameter) if (MF_DBGLEVEL >= 1) DbpString("COMMAND mifare FINISHED"); } -//----------------------------------------------------------------------------- -// Select, Authenticaate, Read an MIFARE tag. -// read block -//----------------------------------------------------------------------------- -void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) -{ - // params - uint8_t blockNo = arg0; - uint8_t keyType = arg1; - uint64_t ui64Key = 0; - ui64Key = bytes_to_num(datain, 6); - - // variables - byte_t isOK = 0; - byte_t dataoutbuf[16]; - uint8_t uid[8]; - uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - // clear trace - traceLen = 0; -// tracing = false; - - iso14443a_setup(); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - - if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); - break; - }; - - if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); - break; - }; - - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; - - isOK = 1; - break; - } - - // ----------------------------- crypto1 destroy - crypto1_destroy(pcs); - - if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); - - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - - UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; - memcpy(ack.d.asBytes, dataoutbuf, 16); - - LED_B_ON(); - UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); - - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -// tracing = TRUE; - -} - -//----------------------------------------------------------------------------- -// Select, Authenticaate, Read an MIFARE tag. -// read sector (data = 4 x 16 bytes = 64 bytes) -//----------------------------------------------------------------------------- -void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) -{ - // params - uint8_t sectorNo = arg0; - uint8_t keyType = arg1; - uint64_t ui64Key = 0; - ui64Key = bytes_to_num(datain, 6); - - // variables - byte_t isOK = 0; - byte_t dataoutbuf[16 * 4]; - uint8_t uid[8]; - uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - // clear trace - traceLen = 0; -// tracing = false; - - iso14443a_setup(); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - - if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); - break; - }; - - if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 0, dataoutbuf + 16 * 0)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Read block 0 error"); - break; - }; - if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 1, dataoutbuf + 16 * 1)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Read block 1 error"); - break; - }; - if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 2, dataoutbuf + 16 * 2)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Read block 2 error"); - break; - }; - if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 3, dataoutbuf + 16 * 3)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Read block 3 error"); - break; - }; - - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; - - isOK = 1; - break; - } - - // ----------------------------- crypto1 destroy - crypto1_destroy(pcs); - - if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED"); - - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - - UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; - memcpy(ack.d.asBytes, dataoutbuf, 16 * 2); - - LED_B_ON(); - UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - - SpinDelay(100); - - memcpy(ack.d.asBytes, dataoutbuf + 16 * 2, 16 * 2); - UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -// tracing = TRUE; - -} - -//----------------------------------------------------------------------------- -// Select, Authenticaate, Read an MIFARE tag. -// read block -//----------------------------------------------------------------------------- -void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) -{ - // params - uint8_t blockNo = arg0; - uint8_t keyType = arg1; - uint64_t ui64Key = 0; - byte_t blockdata[16]; - - ui64Key = bytes_to_num(datain, 6); - memcpy(blockdata, datain + 10, 16); - - // variables - byte_t isOK = 0; - uint8_t uid[8]; - uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - // clear trace - traceLen = 0; -// tracing = false; - - iso14443a_setup(); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - - if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); - break; - }; - - if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); - break; - }; - - if(mifare_classic_halt(pcs, cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); - break; - }; - - isOK = 1; - break; - } - - // ----------------------------- crypto1 destroy - crypto1_destroy(pcs); - - if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); - - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - - UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; - - LED_B_ON(); - UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); - - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); -// tracing = TRUE; - -} - -// Return 1 if the nonce is invalid else return 0 -int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) { - return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ - (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ - (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; -} - - -//----------------------------------------------------------------------------- -// MIFARE nested authentication. -// -//----------------------------------------------------------------------------- -void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) -{ - // params - uint8_t blockNo = arg0; - uint8_t keyType = arg1; - uint8_t targetBlockNo = arg2 & 0xff; - uint8_t targetKeyType = (arg2 >> 8) & 0xff; - uint64_t ui64Key = 0; - - ui64Key = bytes_to_num(datain, 6); - - // variables - int rtr, i, j, m, len; - int davg, dmin, dmax; - uint8_t uid[8]; - uint32_t cuid, nt1, nt2, nttmp, nttest, par, ks1; - uint8_t par_array[4]; - nestedVector nvector[NES_MAX_INFO + 1][10]; - int nvectorcount[NES_MAX_INFO + 1]; - int ncount = 0; - UsbCommand ack = {CMD_ACK, {0, 0, 0}}; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - uint8_t* receivedAnswer = mifare_get_bigbufptr(); - - //init - for (i = 0; i < NES_MAX_INFO + 1; i++) nvectorcount[i] = 11; // 11 - empty block; - - // clear trace - traceLen = 0; - tracing = false; - - iso14443a_setup(); - - LED_A_ON(); - LED_B_ON(); - LED_C_OFF(); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - - davg = dmax = 0; - dmin = 2000; - - // test nonce distance - for (rtr = 0; rtr < 10; rtr++) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(100); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - - // Test if the action was cancelled - if(BUTTON_PRESS()) { - break; - } - - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - - if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 error"); - break; - }; - - if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error"); - break; - }; - - nttmp = prng_successor(nt1, 500); - for (i = 501; i < 2000; i++) { - nttmp = prng_successor(nttmp, 1); - if (nttmp == nt2) break; - } - - if (i != 2000) { - davg += i; - if (dmin > i) dmin = i; - if (dmax < i) dmax = i; - if (MF_DBGLEVEL >= 4) Dbprintf("r=%d nt1=%08x nt2=%08x distance=%d", rtr, nt1, nt2, i); - } - } - - if (rtr == 0) return; - - davg = davg / rtr; - if (MF_DBGLEVEL >= 3) Dbprintf("distance: min=%d max=%d avg=%d", dmin, dmax, davg); - - LED_B_OFF(); - -// ------------------------------------------------------------------------------------------------- - - LED_C_ON(); - - // get crypted nonces for target sector - for (rtr = 0; rtr < NS_RETRIES_GETNONCE; rtr++) { - if (MF_DBGLEVEL >= 4) Dbprintf("------------------------------"); - - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(100); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - - // Test if the action was cancelled - if(BUTTON_PRESS()) { - break; - } - - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - - if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 error"); - break; - }; - - // nested authentication - len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, &par); - if (len != 4) { - if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error len=%d", len); - break; - }; - - nt2 = bytes_to_num(receivedAnswer, 4); - if (MF_DBGLEVEL >= 4) Dbprintf("r=%d nt1=%08x nt2enc=%08x nt2par=%08x", rtr, nt1, nt2, par); - - // Parity validity check - for (i = 0; i < 4; i++) { - par_array[i] = (oddparity(receivedAnswer[i]) != ((par & 0x08) >> 3)); - par = par << 1; - } - - ncount = 0; - for (m = dmin - NS_TOLERANCE; m < dmax + NS_TOLERANCE; m++) { - nttest = prng_successor(nt1, m); - ks1 = nt2 ^ nttest; - - if (valid_nonce(nttest, nt2, ks1, par_array) && (ncount < 11)){ - - nvector[NES_MAX_INFO][ncount].nt = nttest; - nvector[NES_MAX_INFO][ncount].ks1 = ks1; - ncount++; - nvectorcount[NES_MAX_INFO] = ncount; - if (MF_DBGLEVEL >= 4) Dbprintf("valid m=%d ks1=%08x nttest=%08x", m, ks1, nttest); - } - - } - - // select vector with length less than got - if (nvectorcount[NES_MAX_INFO] != 0) { - m = NES_MAX_INFO; - - for (i = 0; i < NES_MAX_INFO; i++) - if (nvectorcount[i] > 10) { - m = i; - break; - } - - if (m == NES_MAX_INFO) - for (i = 0; i < NES_MAX_INFO; i++) - if (nvectorcount[NES_MAX_INFO] < nvectorcount[i]) { - m = i; - break; - } - - if (m != NES_MAX_INFO) { - for (i = 0; i < nvectorcount[m]; i++) { - nvector[m][i] = nvector[NES_MAX_INFO][i]; - } - nvectorcount[m] = nvectorcount[NES_MAX_INFO]; - } - } - } - - LED_C_OFF(); - - // ----------------------------- crypto1 destroy - crypto1_destroy(pcs); - - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - - for (i = 0; i < NES_MAX_INFO; i++) { - if (nvectorcount[i] > 10) continue; - - for (j = 0; j < nvectorcount[i]; j += 5) { - ncount = nvectorcount[i] - j; - if (ncount > 5) ncount = 5; - - ack.arg[0] = 0; // isEOF = 0 - ack.arg[1] = ncount; - ack.arg[2] = targetBlockNo + (targetKeyType * 0x100); - memset(ack.d.asBytes, 0x00, sizeof(ack.d.asBytes)); - - memcpy(ack.d.asBytes, &cuid, 4); - for (m = 0; m < ncount; m++) { - memcpy(ack.d.asBytes + 8 + m * 8 + 0, &nvector[i][m + j].nt, 4); - memcpy(ack.d.asBytes + 8 + m * 8 + 4, &nvector[i][m + j].ks1, 4); - } - - LED_B_ON(); - SpinDelay(100); - UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); - } - } - - // finalize list - ack.arg[0] = 1; // isEOF = 1 - ack.arg[1] = 0; - ack.arg[2] = 0; - memset(ack.d.asBytes, 0x00, sizeof(ack.d.asBytes)); - - LED_B_ON(); - SpinDelay(300); - UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); - - if (MF_DBGLEVEL >= 4) DbpString("NESTED FINISHED"); - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - - tracing = TRUE; -} - -//----------------------------------------------------------------------------- -// MIFARE check keys. key count up to 8. -// -//----------------------------------------------------------------------------- -void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) -{ - // params - uint8_t blockNo = arg0; - uint8_t keyType = arg1; - uint8_t keyCount = arg2; - uint64_t ui64Key = 0; - - // variables - int i; - byte_t isOK = 0; - uint8_t uid[8]; - uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; - struct Crypto1State *pcs; - pcs = &mpcs; - - // clear debug level - int OLD_MF_DBGLEVEL = MF_DBGLEVEL; - MF_DBGLEVEL = MF_DBG_NONE; - - // clear trace - traceLen = 0; - tracing = TRUE; - - iso14443a_setup(); - - LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); - - SpinDelay(300); - for (i = 0; i < keyCount; i++) { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(100); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - - if(!iso14443a_select_card(uid, NULL, &cuid)) { - if (OLD_MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); - break; - }; - - ui64Key = bytes_to_num(datain + i * 6, 6); - if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { - continue; - }; - - isOK = 1; - break; - } - - // ----------------------------- crypto1 destroy - crypto1_destroy(pcs); - - // add trace trailer - memset(uid, 0x44, 4); - LogTrace(uid, 4, 0, 0, TRUE); - - UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; - if (isOK) memcpy(ack.d.asBytes, datain + i * 6, 6); - - LED_B_ON(); - UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); - - // Thats it... - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - LEDsoff(); - - // restore debug level - MF_DBGLEVEL = OLD_MF_DBGLEVEL; -} //----------------------------------------------------------------------------- // MIFARE 1K simulate. @@ -2573,6 +2004,7 @@ void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { int cardSTATE = MFEMUL_NOFIELD; + int _7BUID = 0; int vHf = 0; // in mV int nextCycleTimeout = 0; int res; @@ -2594,12 +2026,13 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) uint8_t* receivedCmd = eml_get_bigbufptr_recbuf(); uint8_t *response = eml_get_bigbufptr_sendbuf(); - static uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k + static uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k 4BUID static uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; static uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!! static uint8_t rSAK[] = {0x08, 0xb6, 0xdd}; + static uint8_t rSAK1[] = {0x04, 0xda, 0x17}; static uint8_t rAUTH_NT[] = {0x1a, 0xac, 0xff, 0x4f}; static uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; @@ -2608,11 +2041,24 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) traceLen = 0; tracing = true; - // emulator memory - emlClearMem(); - emlGetMemBt(rUIDBCC1, 0, 4); - rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; - + // get UID from emul memory + emlGetMemBt(receivedCmd, 7, 1); + _7BUID = !(receivedCmd[0] == 0x00); + if (!_7BUID) { // ---------- 4BUID + rATQA[0] = 0x04; + + emlGetMemBt(rUIDBCC1, 0, 4); + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + } else { // ---------- 7BUID + rATQA[0] = 0x44; + + rUIDBCC1[0] = 0x88; + emlGetMemBt(&rUIDBCC1[1], 0, 3); + rUIDBCC1[4] = rUIDBCC1[0] ^ rUIDBCC1[1] ^ rUIDBCC1[2] ^ rUIDBCC1[3]; + emlGetMemBt(rUIDBCC2, 3, 4); + rUIDBCC2[4] = rUIDBCC2[0] ^ rUIDBCC2[1] ^ rUIDBCC2[2] ^ rUIDBCC2[3]; + } + // -------------------------------------- test area // Authenticate response - nonce @@ -2650,7 +2096,7 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); SpinDelay(200); - Dbprintf("--> start"); + Dbprintf("--> start. 7buid=%d", _7BUID); // calibrate mkseconds counter GetDeltaCountUS(); while (true) { @@ -2714,19 +2160,23 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // select all if (len == 2 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x20)) { EmSendCmd(rUIDBCC1, sizeof(rUIDBCC1)); - - if (rUIDBCC1[0] == 0x88) { - cardSTATE = MFEMUL_SELECT2; - } } // select card if (len == 9 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) { - EmSendCmd(rSAK, sizeof(rSAK)); + if (!_7BUID) + EmSendCmd(rSAK, sizeof(rSAK)); + else + EmSendCmd(rSAK1, sizeof(rSAK1)); cuid = bytes_to_num(rUIDBCC1, 4); - cardSTATE = MFEMUL_WORK; + if (!_7BUID) { + cardSTATE = MFEMUL_WORK; + } else { + cardSTATE = MFEMUL_SELECT2; + break; + } LED_B_ON(); Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - selTimer); } @@ -2734,12 +2184,23 @@ void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) break; } case MFEMUL_SELECT2:{ + if (len == 2 && (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x20)) { EmSendCmd(rUIDBCC2, sizeof(rUIDBCC2)); + break; + } - cuid = bytes_to_num(rUIDBCC2, 4); - cardSTATE = MFEMUL_WORK; - LED_B_ON(); -Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - selTimer); + // select 2 card + if (len == 9 && + (receivedCmd[0] == 0x95 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC2, 4) == 0)) { + EmSendCmd(rSAK, sizeof(rSAK)); + + cuid = bytes_to_num(rUIDBCC2, 4); + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - selTimer); + break; + } + // TODO: goto work state - i guess there is a command break; } case MFEMUL_AUTH1:{ @@ -2775,6 +2236,7 @@ Dbprintf("AUTH COMPLETED. sec=%d, key=%d time=%d", cardAUTHSC, cardAUTHKEY, GetT if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) { authTimer = GetTickCount(); // EmSendCmd(rAUTH_NT, sizeof(rAUTH_NT)); +//SpinDelayUs(190); EmSendCmd14443aRaw(resp1, resp1Len, 0); LogTrace(NULL, 0, GetDeltaCountUS(), 0, TRUE); // crypto1_create(pcs, key64); diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 9ee20c8e..8d43a5b9 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -27,7 +27,6 @@ #define CARD_MEMORY 6000 #define CARD_MEMORY_LEN 1024 - typedef struct nestedVector { uint32_t nt, ks1; } nestedVector; extern byte_t oddparity (const byte_t bt); @@ -44,4 +43,8 @@ extern void iso14443a_setup(); extern int iso14443a_select_card(uint8_t * uid_ptr, iso14a_card_select_t * resp_data, uint32_t * cuid_ptr); extern void iso14a_set_trigger(int enable); +extern void iso14a_clear_tracelen(void); +extern void iso14a_set_tracing(int enable); +extern int LogTrace(const uint8_t * btBytes, int iLen, int iSamples, uint32_t dwParity, int bReader); + #endif /* __ISO14443A_H */ diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c new file mode 100644 index 00000000..fca4f69b --- /dev/null +++ b/armsrc/mifarecmd.c @@ -0,0 +1,716 @@ +//----------------------------------------------------------------------------- +// Merlok - June 2011 +// Gerhard de Koning Gans - May 2008 +// Hagen Fritsch - June 2010 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to support ISO 14443 type A. +//----------------------------------------------------------------------------- + +#include "mifarecmd.h" +#include "apps.h" + +//----------------------------------------------------------------------------- +// Select, Authenticaate, Read an MIFARE tag. +// read block +//----------------------------------------------------------------------------- +void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + uint8_t keyType = arg1; + uint64_t ui64Key = 0; + ui64Key = bytes_to_num(datain, 6); + + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16]; + uint8_t uid[8]; + uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + // clear trace + iso14a_clear_tracelen(); +// iso14a_set_tracing(false); + + iso14443a_setup(); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + break; + }; + + if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); + break; + }; + + if(mifare_classic_halt(pcs, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + // ----------------------------- crypto1 destroy + crypto1_destroy(pcs); + + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; + memcpy(ack.d.asBytes, dataoutbuf, 16); + + LED_B_ON(); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + +//----------------------------------------------------------------------------- +// Select, Authenticaate, Read an MIFARE tag. +// read sector (data = 4 x 16 bytes = 64 bytes) +//----------------------------------------------------------------------------- +void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) +{ + // params + uint8_t sectorNo = arg0; + uint8_t keyType = arg1; + uint64_t ui64Key = 0; + ui64Key = bytes_to_num(datain, 6); + + // variables + byte_t isOK = 0; + byte_t dataoutbuf[16 * 4]; + uint8_t uid[8]; + uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + // clear trace + iso14a_clear_tracelen(); +// iso14a_set_tracing(false); + + iso14443a_setup(); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + break; + }; + + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 0, dataoutbuf + 16 * 0)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 0 error"); + break; + }; + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 1, dataoutbuf + 16 * 1)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 1 error"); + break; + }; + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 2, dataoutbuf + 16 * 2)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 2 error"); + break; + }; + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 3, dataoutbuf + 16 * 3)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 3 error"); + break; + }; + + if(mifare_classic_halt(pcs, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + // ----------------------------- crypto1 destroy + crypto1_destroy(pcs); + + if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; + memcpy(ack.d.asBytes, dataoutbuf, 16 * 2); + + LED_B_ON(); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + + SpinDelay(100); + + memcpy(ack.d.asBytes, dataoutbuf + 16 * 2, 16 * 2); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + +//----------------------------------------------------------------------------- +// Select, Authenticaate, Read an MIFARE tag. +// read block +//----------------------------------------------------------------------------- +void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + uint8_t keyType = arg1; + uint64_t ui64Key = 0; + byte_t blockdata[16]; + + ui64Key = bytes_to_num(datain, 6); + memcpy(blockdata, datain + 10, 16); + + // variables + byte_t isOK = 0; + uint8_t uid[8]; + uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + // clear trace + iso14a_clear_tracelen(); +// iso14a_set_tracing(false); + + iso14443a_setup(); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); + break; + }; + + if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); + break; + }; + + if(mifare_classic_halt(pcs, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + isOK = 1; + break; + } + + // ----------------------------- crypto1 destroy + crypto1_destroy(pcs); + + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; + + LED_B_ON(); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +// iso14a_set_tracing(TRUE); + +} + +// Return 1 if the nonce is invalid else return 0 +int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) { + return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ + (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ + (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; +} + +//----------------------------------------------------------------------------- +// MIFARE nested authentication. +// +//----------------------------------------------------------------------------- +void MifareNested(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + uint8_t keyType = arg1; + uint8_t targetBlockNo = arg2 & 0xff; + uint8_t targetKeyType = (arg2 >> 8) & 0xff; + uint64_t ui64Key = 0; + + ui64Key = bytes_to_num(datain, 6); + + // variables + int rtr, i, j, m, len; + int davg, dmin, dmax; + uint8_t uid[8]; + uint32_t cuid, nt1, nt2, nttmp, nttest, par, ks1; + uint8_t par_array[4]; + nestedVector nvector[NES_MAX_INFO + 1][10]; + int nvectorcount[NES_MAX_INFO + 1]; + int ncount = 0; + UsbCommand ack = {CMD_ACK, {0, 0, 0}}; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + + //init + for (i = 0; i < NES_MAX_INFO + 1; i++) nvectorcount[i] = 11; // 11 - empty block; + + // clear trace + iso14a_clear_tracelen(); + iso14a_set_tracing(false); + + iso14443a_setup(); + + LED_A_ON(); + LED_B_ON(); + LED_C_OFF(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + davg = dmax = 0; + dmin = 2000; + + // test nonce distance + for (rtr = 0; rtr < 10; rtr++) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(100); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + // Test if the action was cancelled + if(BUTTON_PRESS()) { + break; + } + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 error"); + break; + }; + + if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error"); + break; + }; + + nttmp = prng_successor(nt1, 500); + for (i = 501; i < 2000; i++) { + nttmp = prng_successor(nttmp, 1); + if (nttmp == nt2) break; + } + + if (i != 2000) { + davg += i; + if (dmin > i) dmin = i; + if (dmax < i) dmax = i; + if (MF_DBGLEVEL >= 4) Dbprintf("r=%d nt1=%08x nt2=%08x distance=%d", rtr, nt1, nt2, i); + } + } + + if (rtr == 0) return; + + davg = davg / rtr; + if (MF_DBGLEVEL >= 3) Dbprintf("distance: min=%d max=%d avg=%d", dmin, dmax, davg); + + LED_B_OFF(); + +// ------------------------------------------------------------------------------------------------- + + LED_C_ON(); + + // get crypted nonces for target sector + for (rtr = 0; rtr < NS_RETRIES_GETNONCE; rtr++) { + if (MF_DBGLEVEL >= 4) Dbprintf("------------------------------"); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(100); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + // Test if the action was cancelled + if(BUTTON_PRESS()) { + break; + } + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 error"); + break; + }; + + // nested authentication + len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, &par); + if (len != 4) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error len=%d", len); + break; + }; + + nt2 = bytes_to_num(receivedAnswer, 4); + if (MF_DBGLEVEL >= 4) Dbprintf("r=%d nt1=%08x nt2enc=%08x nt2par=%08x", rtr, nt1, nt2, par); + + // Parity validity check + for (i = 0; i < 4; i++) { + par_array[i] = (oddparity(receivedAnswer[i]) != ((par & 0x08) >> 3)); + par = par << 1; + } + + ncount = 0; + for (m = dmin - NS_TOLERANCE; m < dmax + NS_TOLERANCE; m++) { + nttest = prng_successor(nt1, m); + ks1 = nt2 ^ nttest; + + if (valid_nonce(nttest, nt2, ks1, par_array) && (ncount < 11)){ + + nvector[NES_MAX_INFO][ncount].nt = nttest; + nvector[NES_MAX_INFO][ncount].ks1 = ks1; + ncount++; + nvectorcount[NES_MAX_INFO] = ncount; + if (MF_DBGLEVEL >= 4) Dbprintf("valid m=%d ks1=%08x nttest=%08x", m, ks1, nttest); + } + + } + + // select vector with length less than got + if (nvectorcount[NES_MAX_INFO] != 0) { + m = NES_MAX_INFO; + + for (i = 0; i < NES_MAX_INFO; i++) + if (nvectorcount[i] > 10) { + m = i; + break; + } + + if (m == NES_MAX_INFO) + for (i = 0; i < NES_MAX_INFO; i++) + if (nvectorcount[NES_MAX_INFO] < nvectorcount[i]) { + m = i; + break; + } + + if (m != NES_MAX_INFO) { + for (i = 0; i < nvectorcount[m]; i++) { + nvector[m][i] = nvector[NES_MAX_INFO][i]; + } + nvectorcount[m] = nvectorcount[NES_MAX_INFO]; + } + } + } + + LED_C_OFF(); + + // ----------------------------- crypto1 destroy + crypto1_destroy(pcs); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + for (i = 0; i < NES_MAX_INFO; i++) { + if (nvectorcount[i] > 10) continue; + + for (j = 0; j < nvectorcount[i]; j += 5) { + ncount = nvectorcount[i] - j; + if (ncount > 5) ncount = 5; + + ack.arg[0] = 0; // isEOF = 0 + ack.arg[1] = ncount; + ack.arg[2] = targetBlockNo + (targetKeyType * 0x100); + memset(ack.d.asBytes, 0x00, sizeof(ack.d.asBytes)); + + memcpy(ack.d.asBytes, &cuid, 4); + for (m = 0; m < ncount; m++) { + memcpy(ack.d.asBytes + 8 + m * 8 + 0, &nvector[i][m + j].nt, 4); + memcpy(ack.d.asBytes + 8 + m * 8 + 4, &nvector[i][m + j].ks1, 4); + } + + LED_B_ON(); + SpinDelay(100); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + } + } + + // finalize list + ack.arg[0] = 1; // isEOF = 1 + ack.arg[1] = 0; + ack.arg[2] = 0; + memset(ack.d.asBytes, 0x00, sizeof(ack.d.asBytes)); + + LED_B_ON(); + SpinDelay(300); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + if (MF_DBGLEVEL >= 4) DbpString("NESTED FINISHED"); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + + iso14a_set_tracing(TRUE); +} + +//----------------------------------------------------------------------------- +// MIFARE check keys. key count up to 8. +// +//----------------------------------------------------------------------------- +void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + uint8_t keyType = arg1; + uint8_t keyCount = arg2; + uint64_t ui64Key = 0; + + // variables + int i; + byte_t isOK = 0; + uint8_t uid[8]; + uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + // clear debug level + int OLD_MF_DBGLEVEL = MF_DBGLEVEL; + MF_DBGLEVEL = MF_DBG_NONE; + + // clear trace + iso14a_clear_tracelen(); + iso14a_set_tracing(TRUE); + + iso14443a_setup(); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + SpinDelay(300); + for (i = 0; i < keyCount; i++) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(100); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (OLD_MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + ui64Key = bytes_to_num(datain + i * 6, 6); + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + continue; + }; + + isOK = 1; + break; + } + + // ----------------------------- crypto1 destroy + crypto1_destroy(pcs); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; + if (isOK) memcpy(ack.d.asBytes, datain + i * 6, 6); + + LED_B_ON(); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + + // restore debug level + MF_DBGLEVEL = OLD_MF_DBGLEVEL; +} + +//----------------------------------------------------------------------------- +// MIFARE commands set debug level +// +//----------------------------------------------------------------------------- +void MifareSetDbgLvl(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ + MF_DBGLEVEL = arg0; + Dbprintf("Debug level: %d", MF_DBGLEVEL); +} + +//----------------------------------------------------------------------------- +// Work with emulator memory +// +//----------------------------------------------------------------------------- +void MifareEMemClr(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ + emlClearMem(); +} + +void MifareEMemSet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ + emlSetMem(datain, arg0, arg1); // data, block num, blocks count +} + +void MifareEMemGet(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ + UsbCommand ack = {CMD_ACK, {arg0, arg1, 0}}; + + emlGetMem(ack.d.asBytes, arg0, arg1); // data, block num, blocks count + + LED_B_ON(); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); +} + +//----------------------------------------------------------------------------- +// Load a card into the emulator memory +// +//----------------------------------------------------------------------------- +void MifareECardLoad(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *datain){ + int i; + uint8_t sectorNo = 0; + uint8_t keyType = arg1; + uint64_t ui64Key = 0; + uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + // variables + byte_t dataoutbuf[16]; + uint8_t uid[8]; + + // clear trace + iso14a_clear_tracelen(); + iso14a_set_tracing(false); + + iso14443a_setup(); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + while (true) { + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); + break; + }; + + for (i = 0; i < 16; i++) { + sectorNo = i; + ui64Key = emlGetKey(sectorNo, keyType); + + if (!i){ + if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%d]. Auth error", i); + break; + } + } else { + if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_NESTED)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Sector[%d]. Auth nested error", i); + break; + } + } + + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 0, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 0 error"); + break; + }; + emlSetMem(dataoutbuf, sectorNo * 4 + 0, 1); + + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 1, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 1 error"); + break; + }; + emlSetMem(dataoutbuf, sectorNo * 4 + 1, 1); + + if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 2, dataoutbuf)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 2 error"); + break; + }; + emlSetMem(dataoutbuf, sectorNo * 4 + 2, 1); + } + + if(mifare_classic_halt(pcs, cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); + break; + }; + + break; + } + + // ----------------------------- crypto1 destroy + crypto1_destroy(pcs); + + if (MF_DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED"); + + // add trace trailer + memset(uid, 0x44, 4); + LogTrace(uid, 4, 0, 0, TRUE); + + Dbprintf("Loaded."); +} + +//----------------------------------------------------------------------------- +// MIFARE 1k emulator +// +//----------------------------------------------------------------------------- + diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h new file mode 100644 index 00000000..3c00a343 --- /dev/null +++ b/armsrc/mifarecmd.h @@ -0,0 +1,28 @@ +//----------------------------------------------------------------------------- +// Merlok - June 2011 +// Gerhard de Koning Gans - May 2008 +// Hagen Fritsch - June 2010 +// +// 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. +//----------------------------------------------------------------------------- +// Routines to support ISO 14443 type A. +//----------------------------------------------------------------------------- + +#ifndef __MIFARECMD_H +#define __MIFARECMD_H + +#include "proxmark3.h" +#include "apps.h" +#include "util.h" +#include "string.h" + +#include "iso14443crc.h" +#include "iso14443a.h" +#include "crapto1.h" +#include "mifareutil.h" +#include "common.h" + + +#endif \ No newline at end of file diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 89708135..be36e9db 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -339,6 +339,14 @@ void emlGetMemBt(uint8_t *data, int bytePtr, int byteCount) { memcpy(data, emCARD + bytePtr, byteCount); } +uint64_t emlGetKey(int sectorNum, int keyType) { + uint8_t key[6]; + uint8_t* emCARD = eml_get_bigbufptr_cardmem(); + + memcpy(key, emCARD + 3 * 16 + sectorNum * 4 * 16 + keyType * 10, 6); + return bytes_to_num(key, 6); +} + void emlClearMem(void) { int i; diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 51ff2592..59e3cc5b 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -82,5 +82,6 @@ void emlClearMem(void); void emlSetMem(uint8_t *data, int blockNum, int blocksCount); void emlGetMem(uint8_t *data, int blockNum, int blocksCount); void emlGetMemBt(uint8_t *data, int bytePtr, int byteCount); +uint64_t emlGetKey(int sectorNum, int keyType); #endif \ No newline at end of file diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index ee72dad5..d771c645 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -9,6 +9,7 @@ //----------------------------------------------------------------------------- #include "cmdhfmf.h" +#include "proxmark3.h" static int CmdHelp(const char *Cmd); @@ -268,17 +269,20 @@ int CmdHF14AMfNested(const char *Cmd) uint8_t key[6] = {0, 0, 0, 0, 0, 0}; uint8_t keyBlock[16 * 6]; uint64_t key64 = 0; + int transferToEml = 0; char cmdp, ctmp; if (strlen(Cmd)<3) { PrintAndLog("Usage:"); - PrintAndLog(" all sectors: hf mf nested "); - PrintAndLog(" one sector: hf mf nested o "); + PrintAndLog(" all sectors: hf mf nested [t]"); + PrintAndLog(" one sector: hf mf nested o [t]"); PrintAndLog(" "); PrintAndLog("card memory - 0 - MINI(320 bytes), 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLog("t - transfer keys into emulator memory"); PrintAndLog(" "); PrintAndLog(" sample1: hf mf nested 1 0 A FFFFFFFFFFFF "); + PrintAndLog(" sample1: hf mf nested 1 0 A FFFFFFFFFFFF t "); PrintAndLog(" sample2: hf mf nested o 0 A FFFFFFFFFFFF 4 A"); return 0; } @@ -296,7 +300,7 @@ int CmdHF14AMfNested(const char *Cmd) return 1; } - if (cmdp =='o' || cmdp == 'O') { + if (cmdp == 'o' || cmdp == 'O') { cmdp = 'o'; trgBlockNo = param_get8(Cmd, 4); ctmp = param_getchar(Cmd, 5); @@ -314,8 +318,13 @@ int CmdHF14AMfNested(const char *Cmd) default: SectorsCnt = 16; } } + + ctmp = param_getchar(Cmd, 4); + if (ctmp == 't' || ctmp == 'T') transferToEml = 1; + ctmp = param_getchar(Cmd, 6); + transferToEml |= (ctmp == 't' || ctmp == 'T'); - PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); + PrintAndLog("--block no:%02x key type:%02x key:%s etrans:%d", blockNo, keyType, sprint_hex(key, 6), transferToEml); if (cmdp == 'o') PrintAndLog("--target block no:%02x target key type:%02x ", trgBlockNo, trgKeyType); @@ -333,10 +342,22 @@ int CmdHF14AMfNested(const char *Cmd) res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64); if (res) res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64); - if (!res) + if (!res) { PrintAndLog("Found valid key:%012llx", key64); - else + + // transfer key to the emulator + if (transferToEml) { + mfEmlGetMem(keyBlock, (trgBlockNo / 4) * 4 + 3, 1); + + if (!trgKeyType) + num_to_bytes(key64, 6, keyBlock); + else + num_to_bytes(key64, 6, &keyBlock[10]); + mfEmlSetMem(keyBlock, (trgBlockNo / 4) * 4 + 3, 1); + } + } else { PrintAndLog("No valid key found"); + } } else // ------------------------------------ multiple sectors working { blDiff = blockNo % 4; @@ -401,6 +422,18 @@ int CmdHF14AMfNested(const char *Cmd) } PrintAndLog("|---|----------------|---|----------------|---|"); + // transfer them to the emulator + if (transferToEml) { + for (i = 0; i < SectorsCnt; i++) { + mfEmlGetMem(keyBlock, i * 4 + 3, 1); + if (e_sector[i].foundKey[0]) + num_to_bytes(e_sector[i].Key[1], 6, keyBlock); + if (e_sector[i].foundKey[1]) + num_to_bytes(e_sector[i].Key[1], 6, &keyBlock[10]); + mfEmlSetMem(keyBlock, i * 4 + 3, 1); + } + } + free(e_sector); } @@ -488,7 +521,12 @@ int CmdHF14AMf1kSim(const char *Cmd) int CmdHF14AMfDbg(const char *Cmd) { - if (strlen(Cmd) < 1) { + int dbgMode = param_get32ex(Cmd, 0, 0, 10); + if (dbgMode > 4) { + PrintAndLog("Max debud mode parameter is 4 \n"); + } + + if (strlen(Cmd) < 1 || !param_getchar(Cmd, 0) || dbgMode > 4) { PrintAndLog("Usage: hf mf dbg "); PrintAndLog(" 0 - no debug messages"); PrintAndLog(" 1 - error messages"); @@ -497,19 +535,83 @@ int CmdHF14AMfDbg(const char *Cmd) return 0; } - PrintAndLog("No code here ("); + UsbCommand c = {CMD_MIFARE_SET_DBGMODE, {dbgMode, 0, 0}}; + SendCommand(&c); + return 0; } int CmdHF14AMfEGet(const char *Cmd) { - PrintAndLog("No code here ("); + uint8_t blockNo = 0; + uint8_t data[3 * 16]; + int i; + + if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { + PrintAndLog("Usage: hf mf eget "); + PrintAndLog(" sample: hf mf eget 0 "); + return 0; + } + + blockNo = param_get8(Cmd, 0); + if (blockNo >= 16 * 4) { + PrintAndLog("Block number must be in [0..63] as in MIFARE classic."); + return 1; + } + + PrintAndLog(" "); + if (!mfEmlGetMem(data, blockNo, 3)) { + for (i = 0; i < 3; i++) { + PrintAndLog("data[%d]:%s", blockNo + i, sprint_hex(data + i * 16, 16)); + } + } else { + PrintAndLog("Command execute timeout"); + } + + return 0; +} + +int CmdHF14AMfEClear(const char *Cmd) +{ + if (param_getchar(Cmd, 0) == 'h') { + PrintAndLog("Usage: hf mf eclr"); + PrintAndLog("It set card emulator memory to empty data blocks and key A/B FFFFFFFFFFFF \n"); + return 0; + } + + UsbCommand c = {CMD_MIFARE_EML_MEMCLR, {0, 0, 0}}; + SendCommand(&c); return 0; } int CmdHF14AMfESet(const char *Cmd) { - PrintAndLog("No code here ("); + uint8_t memBlock[16]; + uint8_t blockNo = 0; + + memset(memBlock, 0x00, sizeof(memBlock)); + + if (strlen(Cmd) < 3 || param_getchar(Cmd, 0) == 'h') { + PrintAndLog("Usage: hf mf eset "); + PrintAndLog(" sample: hf mf eset 1 000102030405060708090a0b0c0d0e0f "); + return 0; + } + + blockNo = param_get8(Cmd, 0); + if (blockNo >= 16 * 4) { + PrintAndLog("Block number must be in [0..63] as in MIFARE classic."); + return 1; + } + + if (param_gethex(Cmd, 1, memBlock, 32)) { + PrintAndLog("block data must include 32 HEX symbols"); + return 1; + } + + // 1 - blocks count + UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNo, 1, 0}}; + memcpy(c.d.asBytes, memBlock, 16); + SendCommand(&c); return 0; } @@ -525,6 +627,51 @@ int CmdHF14AMfESave(const char *Cmd) return 0; } +int CmdHF14AMfECFill(const char *Cmd) { + uint8_t keyType = 0; + + if (strlen(Cmd) < 1 || param_getchar(Cmd, 0) == 'h') { + PrintAndLog("Usage: hf mf efill "); + PrintAndLog("sample: hf mf efill A"); + PrintAndLog("Card data blocks transfers to card emulator memory."); + PrintAndLog("Keys must be laid in the simulator memory. \n"); + return 0; + } + + char ctmp = param_getchar(Cmd, 0); + if (ctmp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') keyType = 1; + + UsbCommand c = {CMD_MIFARE_EML_CARDLOAD, {0, keyType, 0}}; + SendCommand(&c); + return 0; +} + +int CmdHF14AMfEKeyPrn(const char *Cmd) { + int i; + uint8_t data[16]; + uint64_t keyA, keyB; + + PrintAndLog("|---|----------------|----------------|"); + PrintAndLog("|sec|key A |key B |"); + PrintAndLog("|---|----------------|----------------|"); + for (i = 0; i < 16; i++) { + if (mfEmlGetMem(data, i * 4 + 3, 1)) { + PrintAndLog("error get block %d", i * 4 + 3); + break; + } + keyA = bytes_to_num(data, 6); + keyB = bytes_to_num(data + 10, 6); + PrintAndLog("|%03d| %012llx | %012llx |", i, keyA, keyB); + } + PrintAndLog("|---|----------------|----------------|"); + + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -536,10 +683,13 @@ static command_t CommandTable[] = {"mifare", CmdHF14AMifare, 0, "Read parity error messages. param - "}, {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, {"sim", CmdHF14AMf1kSim, 0, "Simulate MIFARE 1k card"}, + {"eclr", CmdHF14AMfEClear, 0, "Clear simulator memory block"}, {"eget", CmdHF14AMfEGet, 0, "Set simulator memory block"}, {"eset", CmdHF14AMfESet, 0, "Get simulator memory block"}, {"eload", CmdHF14AMfELoad, 0, "Load from file emul dump"}, {"esave", CmdHF14AMfESave, 0, "Save to file emul dump"}, + {"ecfill", CmdHF14AMfECFill, 0, "Fill simulator memory with help of keys from simulator"}, + {"ekeyprn", CmdHF14AMfEKeyPrn, 0, "Print keys from simulator memory"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdhfmf.h b/client/cmdhfmf.h index a4ca7760..d7ee5a4b 100644 --- a/client/cmdhfmf.h +++ b/client/cmdhfmf.h @@ -15,6 +15,7 @@ #include #include #include +#include "proxmark3.h" #include "iso14443crc.h" #include "data.h" #include "proxusb.h" diff --git a/client/mifarehost.c b/client/mifarehost.c index c6f2fe3f..f52fb602 100644 --- a/client/mifarehost.c +++ b/client/mifarehost.c @@ -195,3 +195,23 @@ int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * key *key = bytes_to_num(resp->d.asBytes, 6); return 0; } + +int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount) { + UsbCommand c = {CMD_MIFARE_EML_MEMGET, {blockNum, blocksCount, 0}}; + + SendCommand(&c); + + UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 1500); + + if (resp == NULL) return 1; + memcpy(data, resp->d.asBytes, blocksCount * 16); + return 0; +} + +int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount) { + UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}}; + memcpy(c.d.asBytes, data, blocksCount * 16); + SendCommand(&c); + return 0; +} + diff --git a/client/mifarehost.h b/client/mifarehost.h index 728dc6cc..fe506f9b 100644 --- a/client/mifarehost.h +++ b/client/mifarehost.h @@ -42,4 +42,6 @@ typedef struct { int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * ResultKeys); int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key); +int mfEmlGetMem(uint8_t *data, int blockNum, int blocksCount); +int mfEmlSetMem(uint8_t *data, int blockNum, int blocksCount); diff --git a/client/proxmark3.c b/client/proxmark3.c index 98b28c3c..fe3ba7c5 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include "proxusb.h" @@ -40,7 +41,11 @@ static void *usb_receiver(void *targ) for (int i = 0; i < strlen(PROXPROMPT); i++) putchar(0x08); UsbCommandReceived(&cmdbuf); - printf(PROXPROMPT); + // there is a big bug ) + if (cmdbuf.cmd > 0x0100 && cmdbuf.cmd < 0x0110) { // debug commands + rl_on_new_line_with_prompt(); + rl_forced_update_display(); + } fflush(NULL); } } @@ -61,21 +66,28 @@ static void *main_loop(void *targ) pthread_create(&reader_thread, NULL, &usb_receiver, &rarg); } - while(1) { - cmd = readline(PROXPROMPT); - if (cmd) { - while(cmd[strlen(cmd) - 1] == ' ') - cmd[strlen(cmd) - 1] = 0x00; - if (cmd[0] != 0x00) { - CommandReceived(cmd); - add_history(cmd); - } - free(cmd); - } else { - printf("\n"); - break; - } - } + read_history(".history"); + while(1) { + cmd = readline(PROXPROMPT); + if (cmd) { + while(cmd[strlen(cmd) - 1] == ' ') + cmd[strlen(cmd) - 1] = 0x00; + + if (cmd[0] != 0x00) { + if (strncmp(cmd, "quit", 4) == 0) { + write_history(".history"); + break; + } + + CommandReceived(cmd); + add_history(cmd); + } + free(cmd); + } else { + printf("\n"); + break; + } + } if (arg->usb_present == 1) { rarg.run = 0; diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 3e8066b0..8b8133cc 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -103,18 +103,20 @@ typedef struct { // For mifare commands #define CMD_MIFARE_SET_DBGMODE 0x0600 -#define CMD_MIFARE_EML_MEMSET 0x0601 -#define CMD_MIFARE_EML_MEMGET 0x0602 +#define CMD_MIFARE_EML_MEMCLR 0x0601 +#define CMD_MIFARE_EML_MEMSET 0x0602 +#define CMD_MIFARE_EML_MEMGET 0x0603 +#define CMD_MIFARE_EML_CARDLOAD 0x0604 -#define CMD_SIMULATE_MIFARE_CARD 0x0603 +#define CMD_SIMULATE_MIFARE_CARD 0x0610 -#define CMD_READER_MIFARE 0x0605 -#define CMD_MIFARE_NESTED 0x0606 +#define CMD_READER_MIFARE 0x0611 +#define CMD_MIFARE_NESTED 0x0612 -#define CMD_MIFARE_READBL 0x0610 -#define CMD_MIFARE_READSC 0x0611 -#define CMD_MIFARE_WRITEBL 0x0612 -#define CMD_MIFARE_CHKKEYS 0x0613 +#define CMD_MIFARE_READBL 0x0620 +#define CMD_MIFARE_READSC 0x0621 +#define CMD_MIFARE_WRITEBL 0x0622 +#define CMD_MIFARE_CHKKEYS 0x0623 #define CMD_UNKNOWN 0xFFFF