diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 8be02778d..49718ee88 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -707,6 +707,9 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_MIFARE_NESTED: MifareNested(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; + case CMD_MIFARE_CHKKEYS: + MifareChkKeys(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; case CMD_SIMULATE_MIFARE_CARD: Mifare1ksim(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); break; diff --git a/armsrc/apps.h b/armsrc/apps.h index e60fc924a..322f2674d 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -109,7 +109,8 @@ 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); void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain); -void MifareNested(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); /// iso15693.h diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index b64a1942a..9e1eea540 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1698,12 +1698,12 @@ void ReaderMifare(uint32_t parameter) tracing = FALSE; byte_t nt[4] = {0,0,0,0}; - byte_t nt_attacked[4]; + byte_t nt_attacked[4], nt_noattack[4]; byte_t par_list[8] = {0,0,0,0,0,0,0,0}; byte_t ks_list[8] = {0,0,0,0,0,0,0,0}; - num_to_bytes(parameter, 4, nt_attacked); + num_to_bytes(parameter, 4, nt_noattack); int isOK = 0, isNULL = 0; - + while(TRUE) { LED_C_ON(); @@ -1732,6 +1732,8 @@ void ReaderMifare(uint32_t parameter) // Receive 4 bit answer if (ReaderReceive(receivedAnswer)) { + if ( (parameter != 0) && (memcmp(nt, nt_noattack, 4) == 0) ) continue; + isNULL = (nt_attacked[0] = 0) && (nt_attacked[1] = 0) && (nt_attacked[2] = 0) && (nt_attacked[3] = 0); if ( (isNULL != 0 ) && (memcmp(nt, nt_attacked, 4) != 0) ) continue; @@ -1786,7 +1788,7 @@ void ReaderMifare(uint32_t parameter) LEDsoff(); tracing = TRUE; -// DbpString("COMMAND mifare FINISHED"); + if (MF_DBGLEVEL >= 1) DbpString("COMMAND mifare FINISHED"); } //----------------------------------------------------------------------------- @@ -1822,22 +1824,22 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) while (true) { if(!iso14443a_select_card(uid, NULL, &cuid)) { - Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { - Dbprintf("Auth error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { - Dbprintf("Read block error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Read block error"); break; }; if(mifare_classic_halt(pcs, cuid)) { - Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; @@ -1848,7 +1850,7 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); -// DbpString("READ BLOCK FINISHED"); + if (MF_DBGLEVEL >= 2) DbpString("READ BLOCK FINISHED"); // add trace trailer uid[0] = 0xff; @@ -1905,34 +1907,34 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) while (true) { if(!iso14443a_select_card(uid, NULL, &cuid)) { - Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) { - Dbprintf("Auth error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 0, dataoutbuf + 16 * 0)) { - Dbprintf("Read block 0 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 0 error"); break; }; if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 1, dataoutbuf + 16 * 1)) { - Dbprintf("Read block 1 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 1 error"); break; }; if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 2, dataoutbuf + 16 * 2)) { - Dbprintf("Read block 2 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 2 error"); break; }; if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 3, dataoutbuf + 16 * 3)) { - Dbprintf("Read block 3 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Read block 3 error"); break; }; if(mifare_classic_halt(pcs, cuid)) { - Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; @@ -1943,7 +1945,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); -// DbpString("READ BLOCK FINISHED"); + if (MF_DBGLEVEL >= 2) DbpString("READ SECTOR FINISHED"); // add trace trailer uid[0] = 0xff; @@ -2005,23 +2007,23 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_C_OFF(); while (true) { - if(!iso14443a_select_card(uid, NULL, &cuid)) { - Dbprintf("Can't select card"); + 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)) { - Dbprintf("Auth error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { - Dbprintf("Write block error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Write block error"); break; }; if(mifare_classic_halt(pcs, cuid)) { - Dbprintf("Halt error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Halt error"); break; }; @@ -2032,7 +2034,7 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); -// DbpString("WRITE BLOCK FINISHED"); + if (MF_DBGLEVEL >= 2) DbpString("WRITE BLOCK FINISHED"); // add trace trailer uid[0] = 0xff; @@ -2067,25 +2069,25 @@ int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) { // MIFARE nested authentication. // //----------------------------------------------------------------------------- -void MifareNested(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) { // 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 - uint8_t targetBlockNo = blockNo + 1; - uint8_t targetKeyType = keyType; 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[3][10]; - int nvectorcount[3] = {10, 10, 10}; + 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}; @@ -2093,10 +2095,13 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) 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(); @@ -2121,17 +2126,17 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) } if(!iso14443a_select_card(uid, NULL, &cuid)) { - Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) { - Dbprintf("Auth1 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 error"); break; }; if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2)) { - Dbprintf("Auth2 error"); + if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error"); break; }; @@ -2145,24 +2150,24 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) davg += i; if (dmin > i) dmin = i; if (dmax < i) dmax = i; -// Dbprintf("r=%d nt1=%08x nt2=%08x distance=%d", rtr, nt1, nt2, 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; - Dbprintf("distance: min=%d max=%d avg=%d", dmin, dmax, davg); + if (MF_DBGLEVEL >= 3) Dbprintf("distance: min=%d max=%d avg=%d", dmin, dmax, davg); LED_B_OFF(); - tracing = true; +// ------------------------------------------------------------------------------------------------- LED_C_ON(); // get crypted nonces for target sector - for (rtr = 0; rtr < 2; rtr++) { -// Dbprintf("------------------------------"); + for (rtr = 0; rtr < NS_RETRIES_GETNONCE; rtr++) { + if (MF_DBGLEVEL >= 4) Dbprintf("------------------------------"); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); SpinDelay(100); @@ -2174,47 +2179,24 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) } if(!iso14443a_select_card(uid, NULL, &cuid)) { - Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) { - Dbprintf("Auth1 error"); + 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) { - Dbprintf("Auth2 error len=%d", len); + if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error len=%d", len); break; }; nt2 = bytes_to_num(receivedAnswer, 4); -// Dbprintf("r=%d nt1=%08x nt2enc=%08x nt2par=%08x", rtr, nt1, nt2, par); - -// ----------------------- test -/* uint32_t d_nt, d_ks1, d_ks2, d_ks3, reader_challenge; - byte_t ar[4]; - - ar[0] = 0x55; - ar[1] = 0x41; - ar[2] = 0x49; - ar[3] = 0x92; - - crypto1_destroy(pcs); - crypto1_create(pcs, ui64Key); - - // decrypt nt with help of new key - d_nt = crypto1_word(pcs, nt2 ^ cuid, 1) ^ nt2; - - reader_challenge = d_nt;//(uint32_t)bytes_to_num(ar, 4); - d_ks1 = crypto1_word(pcs, reader_challenge, 0); - d_ks2 = crypto1_word(pcs, 0, 0); - d_ks3 = crypto1_word(pcs, 0,0); - - Dbprintf("TST: ks1=%08x nt=%08x", d_ks1, d_nt);*/ -// ----------------------- test + 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++) { @@ -2223,45 +2205,48 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) } ncount = 0; - for (m = dmin - 10; m < dmax + 10; m++) { + for (m = dmin - NS_TOLERANCE; m < dmax + NS_TOLERANCE; m++) { nttest = prng_successor(nt1, m); ks1 = nt2 ^ nttest; -//-------------------------------------- test -/* if (nttest == d_nt){ - Dbprintf("nttest=d_nt! m=%d ks1=%08x nttest=%08x", m, ks1, nttest); - }*/ -//-------------------------------------- test if (valid_nonce(nttest, nt2, ks1, par_array) && (ncount < 11)){ - nvector[2][ncount].nt = nttest; - nvector[2][ncount].ks1 = ks1; + nvector[NES_MAX_INFO][ncount].nt = nttest; + nvector[NES_MAX_INFO][ncount].ks1 = ks1; ncount++; - nvectorcount[2] = ncount; - -// Dbprintf("valid m=%d ks1=%08x nttest=%08x", m, ks1, nttest); + 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[2] != 0) { - m = 2; - if (nvectorcount[2] < nvectorcount[1]) m = 1; - if (nvectorcount[2] < nvectorcount[0]) m = 0; - if (m != 2) { - for (i = 0; i < nvectorcount[m]; i++) { - nvector[m][i] = nvector[2][i]; + 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; } - nvectorcount[m] = nvectorcount[2]; + + 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]; } } - -// Dbprintf("vector count: 1=%d 2=%d 3=%d", nvectorcount[0], nvectorcount[1], nvectorcount[2]); } LED_C_OFF(); - // ----------------------------- crypto1 destroy crypto1_destroy(pcs); @@ -2273,7 +2258,9 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) uid[3] = 0xff; LogTrace(uid, 4, 0, 0, TRUE); - for (i = 0; i < 2; i++) { + 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; @@ -2307,13 +2294,93 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); LED_B_OFF(); - DbpString("NESTED FINISHED"); + if (MF_DBGLEVEL >= 4) DbpString("NESTED FINISHED"); // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); -// tracing = TRUE; + + 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 + uid[0] = 0xff; + uid[1] = 0xff; + uid[2] = 0xff; + uid[3] = 0xff; + 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; } //----------------------------------------------------------------------------- diff --git a/armsrc/iso14443a.h b/armsrc/iso14443a.h index 7b5444fbf..ba86acc52 100644 --- a/armsrc/iso14443a.h +++ b/armsrc/iso14443a.h @@ -1,7 +1,20 @@ +//----------------------------------------------------------------------------- +// 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 __ISO14443A_H #define __ISO14443A_H #include "common.h" + typedef struct nestedVector { uint32_t nt, ks1; } nestedVector; extern byte_t oddparity (const byte_t bt); diff --git a/armsrc/mifareutil.c b/armsrc/mifareutil.c index 1f8a4d175..53e785f5b 100644 --- a/armsrc/mifareutil.c +++ b/armsrc/mifareutil.c @@ -19,6 +19,8 @@ #include "crapto1.h" #include "mifareutil.h" +int MF_DBGLEVEL = MF_DBG_ALL; + uint8_t* mifare_get_bigbufptr(void) { return (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes } @@ -96,7 +98,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN // Transmit MIFARE_CLASSIC_AUTH len = mifare_sendcmd_short(pcs, isNested, 0x60 + (keyType & 0x01), blockNo, receivedAnswer); -// Dbprintf("rand nonce len: %x", len); + if (MF_DBGLEVEL >= 4) Dbprintf("rand nonce len: %x", len); if (len != 4) return 1; ar[0] = 0x55; @@ -123,7 +125,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN } // some statistic - if (!ntptr) + if (!ntptr && (MF_DBGLEVEL >= 3)) Dbprintf("auth uid: %08x nt: %08x", uid, nt); // save Nt @@ -156,7 +158,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN len = ReaderReceive(receivedAnswer); if (!len) { - Dbprintf("Authentication failed. Card timeout."); + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Card timeout."); return 2; } @@ -164,7 +166,7 @@ int mifare_classic_authex(struct Crypto1State *pcs, uint32_t uid, uint8_t blockN ntpp = prng_successor(nt, 32) ^ crypto1_word(pcs, 0,0); if (ntpp != bytes_to_num(tmp4, 4)) { - Dbprintf("Authentication failed. Error card response."); + if (MF_DBGLEVEL >= 1) Dbprintf("Authentication failed. Error card response."); return 3; } @@ -182,18 +184,18 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo // command MIFARE_CLASSIC_READBLOCK len = mifare_sendcmd_short(pcs, 1, 0x30, blockNo, receivedAnswer); if (len == 1) { - Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } if (len != 18) { - Dbprintf("Cmd Error: card timeout. len: %x", len); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: card timeout. len: %x", len); return 2; } memcpy(bt, receivedAnswer + 16, 2); AppendCrc14443a(receivedAnswer, 16); if (bt[0] != receivedAnswer[16] || bt[1] != receivedAnswer[17]) { - Dbprintf("Cmd CRC response error."); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd CRC response error."); return 3; } @@ -216,7 +218,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl len = mifare_sendcmd_short(pcs, 1, 0xA0, blockNo, receivedAnswer); if ((len != 1) || (receivedAnswer[0] != 0x0A)) { // 0x0a - ACK - Dbprintf("Cmd Error: %02x", receivedAnswer[0]); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd Error: %02x", receivedAnswer[0]); return 1; } @@ -241,7 +243,7 @@ int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t bl res |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedAnswer[0], i)) << i; if ((len != 1) || (res != 0x0A)) { - Dbprintf("Cmd send data2 Error: %02x", res); + if (MF_DBGLEVEL >= 1) Dbprintf("Cmd send data2 Error: %02x", res); return 2; } @@ -258,7 +260,7 @@ int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid) len = mifare_sendcmd_short(pcs, 1, 0x50, 0x00, receivedAnswer); if (len != 0) { - Dbprintf("halt error. response len: %x", len); + if (MF_DBGLEVEL >= 1) Dbprintf("halt error. response len: %x", len); return 1; } diff --git a/armsrc/mifareutil.h b/armsrc/mifareutil.h index 715dfe63c..9a909a355 100644 --- a/armsrc/mifareutil.h +++ b/armsrc/mifareutil.h @@ -8,6 +8,8 @@ //----------------------------------------------------------------------------- // code for work with mifare cards. //----------------------------------------------------------------------------- +#ifndef __MIFAREUTIL_H +#define __MIFAREUTIL_H #define CRYPT_NONE 0 #define CRYPT_ALL 1 @@ -15,6 +17,22 @@ #define AUTH_FIRST 0 #define AUTH_NESTED 2 +// debug +// 0 - no debug messages 1 - error messages 2 - all messages 4 - extended debug mode +#define MF_DBG_NONE 0 +#define MF_DBG_ERROR 1 +#define MF_DBG_ALL 2 +#define MF_DBG_EXTENDED 4 + +extern int MF_DBGLEVEL; + +//mifare nested +#define MEM_CHUNK 10000 +#define TRY_KEYS 50 +#define NS_TOLERANCE 10 // [distance avg-value, distance avg+value] +#define NS_RETRIES_GETNONCE 15 +#define NES_MAX_INFO 5 + //mifare emulate states #define MFEMUL_NOFIELD 0 #define MFEMUL_IDLE 1 @@ -37,3 +55,4 @@ int mifare_classic_readblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blo int mifare_classic_writeblock(struct Crypto1State *pcs, uint32_t uid, uint8_t blockNo, uint8_t *blockData); int mifare_classic_halt(struct Crypto1State *pcs, uint32_t uid); +#endif \ No newline at end of file diff --git a/client/Makefile b/client/Makefile index aa0fb61f5..cf647c38a 100644 --- a/client/Makefile +++ b/client/Makefile @@ -43,6 +43,7 @@ CMDSRCS = \ nonce2key/crapto1.c\ nonce2key/crypto1.c\ nonce2key/nonce2key.c\ + mifarehost.c\ crc16.c \ iso14443crc.c \ iso15693tools.c \ diff --git a/client/cmdhf14a.c b/client/cmdhf14a.c index 46cfbebe3..f2774a16a 100644 --- a/client/cmdhf14a.c +++ b/client/cmdhf14a.c @@ -12,7 +12,8 @@ #include #include #include -#include +#include +#include #include "util.h" #include "iso14443crc.h" #include "data.h" @@ -24,6 +25,7 @@ #include "cmdmain.h" #include "nonce2key/nonce2key.h" #include "nonce2key/crapto1.h" +#include "mifarehost.h" static int CmdHelp(const char *Cmd); @@ -165,13 +167,18 @@ int CmdHF14AMifare(const char *Cmd) uint32_t nt = 0; uint64_t par_list = 0, ks_list = 0, r_key = 0; uint8_t isOK = 0; + uint8_t keyBlock[6] = {0,0,0,0,0,0}; - UsbCommand c = {CMD_READER_MIFARE, {strtol(Cmd, NULL, 0), 0, 0}}; + if (param_getchar(Cmd, 0) && param_gethex(Cmd, 0, keyBlock, 8)) { + PrintAndLog("Nt must include 8 HEX symbols"); + return 1; + } + + UsbCommand c = {CMD_READER_MIFARE, {(uint32_t)bytes_to_num(keyBlock, 4), 0, 0}}; SendCommand(&c); //flush queue - while (kbhit()) getchar(); - while (WaitForResponseTimeout(CMD_ACK, 500) != NULL) ; + while (ukbhit()) getchar(); // message printf("-------------------------------------------------------------------------\n"); @@ -183,7 +190,7 @@ int CmdHF14AMifare(const char *Cmd) // wait cycle while (true) { printf("."); - if (kbhit()) { + if (ukbhit()) { getchar(); printf("\naborted via keyboard!\n"); break; @@ -211,79 +218,52 @@ int CmdHF14AMifare(const char *Cmd) // execute original function from util nonce2key if (nonce2key(uid, nt, par_list, ks_list, &r_key)) return 2; - printf("-------------------------------------------------------------------------\n"); + printf("------------------------------------------------------------------\n"); PrintAndLog("Key found:%012llx \n", r_key); + + num_to_bytes(r_key, 6, keyBlock); + isOK = mfCheckKeys(0, 0, 1, keyBlock, &r_key); + if (!isOK) + PrintAndLog("Found valid key:%012llx", r_key); + else + PrintAndLog("Found invalid key. ("); + return 0; } int CmdHF14AMfWrBl(const char *Cmd) { - int i, temp; uint8_t blockNo = 0; uint8_t keyType = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - const char *cmdp = Cmd; - const char *cmdpe = Cmd; + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf 14 mfwrbl "); - PrintAndLog(" sample: hf 14a mfwrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F"); + PrintAndLog(" sample: hf 14a mfwrbl 0 A FFFFFFFFFFFF 000102030405060708090A0B0C0D0E0F"); return 0; } - PrintAndLog("l: %s", Cmd); - - // skip spaces - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - blockNo = strtol(cmdp, NULL, 0) & 0xff; - - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - if (*cmdp != 'A' && *cmdp != 'a') { - keyType = 1; + + blockNo = param_get8(Cmd, 0); + cmdp = param_getchar(Cmd, 1); + if (cmdp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; } - - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - - // next value here:cmdpe - cmdpe = cmdp; - while (*cmdpe!=' ' && *cmdpe!='\t') cmdpe++; - while (*cmdpe==' ' || *cmdpe=='\t') cmdpe++; - - if ((int)cmdpe - (int)cmdp != 13) { - PrintAndLog("Length of key must be 12 hex symbols"); - return 0; + if (cmdp != 'A' && cmdp != 'a') keyType = 1; + if (param_gethex(Cmd, 2, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; } - - for(i = 0; i < 6; i++) { - sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp); - key[i] = temp & 0xff; - cmdp++; - cmdp++; - } - - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - - if (strlen(cmdp) != 32) { - PrintAndLog("Length of block data must be 32 hex symbols"); - return 0; + if (param_gethex(Cmd, 3, bldata, 32)) { + PrintAndLog("Block data must include 32 HEX symbols"); + return 1; } - - for(i = 0; i < 16; i++) { - sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp); - bldata[i] = temp & 0xff; - cmdp++; - cmdp++; - } - PrintAndLog(" block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6)); - PrintAndLog(" data: %s", sprint_hex(bldata, 16)); + PrintAndLog("--block no:%02x key type:%02x key:%s", blockNo, keyType, sprint_hex(key, 6)); + PrintAndLog("--data: %s", sprint_hex(bldata, 16)); UsbCommand c = {CMD_MIFARE_WRITEBL, {blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); @@ -304,47 +284,31 @@ int CmdHF14AMfWrBl(const char *Cmd) int CmdHF14AMfRdBl(const char *Cmd) { - int i, temp; uint8_t blockNo = 0; uint8_t keyType = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - const char *cmdp = Cmd; + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf 14 mfrdbl "); - PrintAndLog(" sample: hf 14a mfrdbl 0 A FFFFFFFFFFFF "); + PrintAndLog(" sample: hf 14a mfrdbl 0 A FFFFFFFFFFFF "); return 0; } - // skip spaces - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - blockNo = strtol(cmdp, NULL, 0) & 0xff; - - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - if (*cmdp != 'A' && *cmdp != 'a') { - keyType = 1; + blockNo = param_get8(Cmd, 0); + cmdp = param_getchar(Cmd, 1); + if (cmdp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; } - - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - - if (strlen(cmdp) != 12) { - PrintAndLog("Length of key must be 12 hex symbols"); - return 0; + if (cmdp != 'A' && cmdp != 'a') keyType = 1; + if (param_gethex(Cmd, 2, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; } - - for(i = 0; i < 6; i++) { - sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp); - key[i] = temp & 0xff; - cmdp++; - cmdp++; - } - PrintAndLog(" block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); + PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); UsbCommand c = {CMD_MIFARE_READBL, {blockNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); @@ -355,7 +319,10 @@ int CmdHF14AMfRdBl(const char *Cmd) uint8_t isOK = resp->arg[0] & 0xff; uint8_t * data = resp->d.asBytes; - PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16)); + if (isOK) + PrintAndLog("isOk:%02x data:%s", isOK, sprint_hex(data, 16)); + else + PrintAndLog("isOk:%02x", isOK); } else { PrintAndLog("Command execute timeout"); } @@ -365,47 +332,38 @@ int CmdHF14AMfRdBl(const char *Cmd) int CmdHF14AMfRdSc(const char *Cmd) { - int i, temp; + int i; uint8_t sectorNo = 0; uint8_t keyType = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - const char *cmdp = Cmd; + uint8_t isOK = 0; + uint8_t * data = NULL; + char cmdp = 0x00; if (strlen(Cmd)<3) { PrintAndLog("Usage: hf 14 mfrdsc "); - PrintAndLog(" sample: hf 14a mfrdsc 0 A FFFFFFFFFFFF "); + PrintAndLog(" sample: hf 14a mfrdsc 0 A FFFFFFFFFFFF "); return 0; } - // skip spaces - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - sectorNo = strtol(cmdp, NULL, 0) & 0xff; - - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - if (*cmdp != 'A' && *cmdp != 'a') { - keyType = 1; + sectorNo = param_get8(Cmd, 0); + if (sectorNo > 63) { + PrintAndLog("Sector number must be less than 64"); + return 1; } - - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - - if (strlen(cmdp) != 12) { - PrintAndLog("Length of key must be 12 hex symbols"); - return 0; + cmdp = param_getchar(Cmd, 1); + if (cmdp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; } - - for(i = 0; i < 6; i++) { - sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp); - key[i] = temp & 0xff; - cmdp++; - cmdp++; - } - PrintAndLog(" sector no:%02x key type:%02x key:%s ", sectorNo, keyType, sprint_hex(key, 6)); + if (cmdp != 'A' && cmdp != 'a') keyType = 1; + if (param_gethex(Cmd, 2, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; + } + PrintAndLog("--sector no:%02x key type:%02x key:%s ", sectorNo, keyType, sprint_hex(key, 6)); UsbCommand c = {CMD_MIFARE_READSC, {sectorNo, keyType, 0}}; memcpy(c.d.asBytes, key, 6); @@ -414,13 +372,14 @@ int CmdHF14AMfRdSc(const char *Cmd) PrintAndLog(" "); if (resp != NULL) { - uint8_t isOK = resp->arg[0] & 0xff; - uint8_t * data = resp->d.asBytes; + isOK = resp->arg[0] & 0xff; + data = resp->d.asBytes; PrintAndLog("isOk:%02x", isOK); - for (i = 0; i < 2; i++) { - PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); - } + if (isOK) + for (i = 0; i < 2; i++) { + PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); + } } else { PrintAndLog("Command1 execute timeout"); } @@ -430,10 +389,12 @@ int CmdHF14AMfRdSc(const char *Cmd) PrintAndLog(" "); if (resp != NULL) { - uint8_t * data = resp->d.asBytes; + isOK = resp->arg[0] & 0xff; + data = resp->d.asBytes; - for (i = 0; i < 2; i++) { - PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); + if (isOK) + for (i = 0; i < 2; i++) { + PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); } } else { PrintAndLog("Command2 execute timeout"); @@ -444,115 +405,207 @@ int CmdHF14AMfRdSc(const char *Cmd) int CmdHF14AMfNested(const char *Cmd) { - int i, temp, len; - uint8_t sectorNo = 0; + int i, j, res, iterations; + sector * e_sector = NULL; + uint8_t blockNo = 0; uint8_t keyType = 0; + uint8_t trgBlockNo = 0; + uint8_t trgKeyType = 0; + uint8_t blDiff = 0; + int SectorsCnt = 0; uint8_t key[6] = {0, 0, 0, 0, 0, 0}; - uint8_t isEOF; - uint8_t * data; - uint32_t uid; - fnVector * vector = NULL; - int lenVector = 0; - UsbCommand * resp = NULL; + uint8_t keyBlock[16 * 6]; + uint64_t key64 = 0; - const char *cmdp = Cmd; + char cmdp, ctmp; if (strlen(Cmd)<3) { - PrintAndLog("Usage: hf 14a nested "); - PrintAndLog(" sample: hf 14a nested 0 A FFFFFFFFFFFF "); + PrintAndLog("Usage:"); + PrintAndLog(" all sectors: hf 14a nested "); + PrintAndLog(" one sector: hf 14a nested o "); + PrintAndLog(" "); + PrintAndLog("card memory - 1 - 1K, 2 - 2K, 4 - 4K, - 1K"); + PrintAndLog(" "); + PrintAndLog(" sample1: hf 14a nested 1 0 A FFFFFFFFFFFF "); + PrintAndLog(" sample2: hf 14a nested o 0 A FFFFFFFFFFFF 4 A"); return 0; } - // skip spaces - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - sectorNo = strtol(cmdp, NULL, 0) & 0xff; + cmdp = param_getchar(Cmd, 0); + blockNo = param_get8(Cmd, 1); + ctmp = param_getchar(Cmd, 2); + if (ctmp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') keyType = 1; + if (param_gethex(Cmd, 3, key, 12)) { + PrintAndLog("Key must include 12 HEX symbols"); + return 1; + } - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - if (*cmdp != 'A' && *cmdp != 'a') { - keyType = 1; + if (cmdp =='o' || cmdp == 'O') { + cmdp = 'o'; + trgBlockNo = param_get8(Cmd, 4); + ctmp = param_getchar(Cmd, 5); + if (ctmp == 0x00) { + PrintAndLog("Target key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1; + } else { + switch (cmdp) { + case '1': SectorsCnt = 16; break; + case '2': SectorsCnt = 32; break; + case '4': SectorsCnt = 64; break; + default: SectorsCnt = 16; + } + } + + PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6)); + if (cmdp == 'o') + PrintAndLog("--target block no:%02x target key type:%02x ", trgBlockNo, trgKeyType); + + if (cmdp == 'o') { + if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) { + PrintAndLog("Nested error."); + return 2; + } + + for (i = 0; i < 16; i++) { + PrintAndLog("cnt=%d key= %s", i, sprint_hex(keyBlock + i * 6, 6)); + } + + // test keys + res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64); + if (res) + res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64); + if (!res) + PrintAndLog("Found valid key:%012llx", key64); + else + PrintAndLog("No valid key found"); + } else // ------------------------------------ multiple sectors working + { + blDiff = blockNo % 4; + PrintAndLog("Block shift=%d", blDiff); + e_sector = calloc(SectorsCnt, sizeof(sector)); + if (e_sector == NULL) return 1; + + //test current key 4 sectors + memcpy(keyBlock, key, 6); + num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 1 * 6)); + num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 2 * 6)); + num_to_bytes(0xffffffffffff, 6, (uint8_t*)(keyBlock + 3 * 6)); + num_to_bytes(0x000000000000, 6, (uint8_t*)(keyBlock + 4 * 6)); + num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6)); + + PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt); + for (i = 0; i < SectorsCnt; i++) { + for (j = 0; j < 2; j++) { + if (e_sector[i].foundKey[j]) continue; + + res = mfCheckKeys(i * 4 + blDiff, j, 6, keyBlock, &key64); + + if (!res) { + e_sector[i].Key[j] = key64; + e_sector[i].foundKey[j] = 1; + } + } + } + + + // nested sectors + iterations = 0; + PrintAndLog("nested..."); + for (i = 0; i < NESTED_SECTOR_RETRY; i++) { + for (trgBlockNo = blDiff; trgBlockNo < SectorsCnt * 4; trgBlockNo = trgBlockNo + 4) + for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) { + if (e_sector[trgBlockNo / 4].foundKey[trgKeyType]) continue; + if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) continue; + + iterations++; + + //try keys from nested + res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64); + if (res) + res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64); + if (!res) { + PrintAndLog("Found valid key:%012llx", key64); + e_sector[trgBlockNo / 4].foundKey[trgKeyType] = 1; + e_sector[trgBlockNo / 4].Key[trgKeyType] = key64; + } + } + } + + PrintAndLog("Iterations count: %d", iterations); + //print them + PrintAndLog("|---|----------------|---|----------------|---|"); + PrintAndLog("|blk|key A |res|key B |res|"); + PrintAndLog("|---|----------------|---|----------------|---|"); + for (i = 0; i < SectorsCnt; i++) { + PrintAndLog("|%03d| %012llx | %d | %012llx | %d |", i, + e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]); + } + PrintAndLog("|---|----------------|---|----------------|---|"); + + free(e_sector); } - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; + return 0; +} - if (strlen(cmdp) != 12) { - PrintAndLog("Length of key must be 12 hex symbols"); +int CmdHF14AMfChk(const char *Cmd) +{ + int i, res; + int keycnt = 0; + char ctmp = 0x00; + uint8_t blockNo = 0; + uint8_t keyType = 0; + uint8_t keyBlock[8 * 6]; + uint64_t key64 = 0; + + memset(keyBlock, 0x00, sizeof(keyBlock)); + + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf 14a chk []"); + PrintAndLog(" sample: hf 14a chk 0 A FFFFFFFFFFFF a0a1a2a3a4a5 b01b2b3b4b5 "); return 0; - } - - for(i = 0; i < 6; i++) { - sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp); - key[i] = temp & 0xff; - cmdp++; - cmdp++; } - PrintAndLog(" sector no:%02x key type:%02x key:%s ", sectorNo, keyType, sprint_hex(key, 6)); - - // flush queue - while (WaitForResponseTimeout(CMD_ACK, 500) != NULL) ; - UsbCommand c = {CMD_MIFARE_NESTED, {sectorNo, keyType, 0}}; - memcpy(c.d.asBytes, key, 6); - SendCommand(&c); + blockNo = param_get8(Cmd, 0); + ctmp = param_getchar(Cmd, 1); + if (ctmp == 0x00) { + PrintAndLog("Key type must be A or B"); + return 1; + } + if (ctmp != 'A' && ctmp != 'a') keyType = 1; + + for (i = 0; i < 6; i++) { + if (!isxdigit(param_getchar(Cmd, 2 + i))) break; - PrintAndLog("\n"); - printf("-------------------------------------------------------------------------\n"); - - // wait cycle - while (true) { - printf("."); - if (kbhit()) { - getchar(); - printf("\naborted via keyboard!\n"); - break; - } - - resp = WaitForResponseTimeout(CMD_ACK, 1500); - - if (resp != NULL) { - isEOF = resp->arg[0] & 0xff; - data = resp->d.asBytes; - - PrintAndLog("isEOF:%02x", isEOF); - for (i = 0; i < 2; i++) { - PrintAndLog("data:%s", sprint_hex(data + i * 16, 16)); - } - if (isEOF) break; - - len = resp->arg[1] & 0xff; - if (len == 0) continue; - - memcpy(&uid, resp->d.asBytes, 4); - PrintAndLog("uid:%08x len=%d trgbl=%d trgkey=%d", uid, len, resp->arg[2] & 0xff, (resp->arg[2] >> 8) & 0xff); - - vector = (fnVector *) realloc((void *)vector, (lenVector + len) * sizeof(fnVector) + 200); - if (vector == NULL) { - PrintAndLog("Memory allocation error for fnVector. len: %d bytes: %d", lenVector + len, (lenVector + len) * sizeof(fnVector)); - break; - } - - for (i = 0; i < len; i++) { - vector[lenVector + i].blockNo = resp->arg[2] & 0xff; - vector[lenVector + i].keyType = (resp->arg[2] >> 8) & 0xff; - vector[lenVector + i].uid = uid; - - memcpy(&vector[lenVector + i].nt, (void *)(resp->d.asBytes + 8 + i * 8 + 0), 4); - memcpy(&vector[lenVector + i].ks1, (void *)(resp->d.asBytes + 8 + i * 8 + 4), 4); - - PrintAndLog("i=%d nt:%08x ks1:%08x", i, vector[lenVector + i].nt, vector[lenVector + i].ks1); - } - - lenVector += len; + if (param_gethex(Cmd, 2 + i, keyBlock + 6 * i, 12)) { + PrintAndLog("Key[%d] must include 12 HEX symbols", i); + return 1; } + keycnt = i + 1; } + if (keycnt == 0) { + PrintAndLog("There is must be at least one key"); + return 1; + } + + PrintAndLog("--block no:%02x key type:%02x key count:%d ", blockNo, keyType, keycnt); - - // finalize - free(vector); + res = mfCheckKeys(blockNo, keyType, keycnt, keyBlock, &key64); + if (res !=1) { + if (!res) + PrintAndLog("isOk:%02x valid key:%012llx", 1, key64); + else + PrintAndLog("isOk:%02x", 0); + } else { + PrintAndLog("Command execute timeout"); + } return 0; } @@ -654,6 +707,7 @@ static command_t CommandTable[] = {"mfrdsc", CmdHF14AMfRdSc, 0, "Read MIFARE classic sector"}, {"mfwrbl", CmdHF14AMfWrBl, 0, "Write MIFARE classic block"}, {"nested", CmdHF14AMfNested, 0, "Test nested authentication"}, + {"chk", CmdHF14AMfChk, 0, "Test block up to 8 keys"}, {"mfsim", CmdHF14AMf1kSim, 0, "Simulate MIFARE 1k card - NOT WORKING!!!"}, {"reader", CmdHF14AReader, 0, "Act like an ISO14443 Type A reader"}, {"sim", CmdHF14ASim, 0, " -- Fake ISO 14443a tag"}, @@ -663,6 +717,10 @@ static command_t CommandTable[] = int CmdHF14A(const char *Cmd) { + // flush + while (WaitForResponseTimeout(CMD_ACK, 500) != NULL) ; + + // parse CmdsParse(CommandTable, Cmd); return 0; } diff --git a/client/cmdhf14a.h b/client/cmdhf14a.h index fdb8b959a..56329bed1 100644 --- a/client/cmdhf14a.h +++ b/client/cmdhf14a.h @@ -12,8 +12,6 @@ #ifndef CMDHF14A_H__ #define CMDHF14A_H__ -typedef struct fnVector { uint8_t blockNo, keyType; uint32_t uid, nt, ks1; } fnVector; - int CmdHF14A(const char *Cmd); int CmdHF14AList(const char *Cmd); diff --git a/client/cmdmain.c b/client/cmdmain.c index c27d84061..8f4618c96 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -63,7 +63,7 @@ UsbCommand * WaitForResponseTimeout(uint32_t response_type, uint32_t ms_timeout) msleep(10); // XXX ugh } - // There was evil BUG + // There was an evil BUG memcpy(¤t_response_user, ¤t_response, sizeof(UsbCommand)); ret = ¤t_response_user; diff --git a/client/mifarehost.c b/client/mifarehost.c new file mode 100644 index 000000000..aab1ae333 --- /dev/null +++ b/client/mifarehost.c @@ -0,0 +1,197 @@ +// Merlok, 2011 +// people from mifare@nethemba.com, 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. +//----------------------------------------------------------------------------- +// High frequency ISO14443A commands +//----------------------------------------------------------------------------- + +#include +#include +#include "mifarehost.h" + + +int compar_int(const void * a, const void * b) { + return (*(uint64_t*)b - *(uint64_t*)a); +} + +// Compare countKeys structure +int compar_special_int(const void * a, const void * b) { + return (((countKeys *)b)->count - ((countKeys *)a)->count); +} + +countKeys * uniqsort(uint64_t * possibleKeys, uint32_t size) { + int i, j = 0; + int count = 0; + countKeys *our_counts; + + qsort(possibleKeys, size, sizeof (uint64_t), compar_int); + + our_counts = calloc(size, sizeof(countKeys)); + if (our_counts == NULL) { + PrintAndLog("Memory allocation error for our_counts"); + return NULL; + } + + for (i = 0; i < size; i++) { + if (possibleKeys[i+1] == possibleKeys[i]) { + count++; + } else { + our_counts[j].key = possibleKeys[i]; + our_counts[j].count = count; + j++; + count=0; + } + } + qsort(our_counts, j, sizeof(countKeys), compar_special_int); + return (our_counts); +} + +int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t * key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t * resultKeys) +{ + int i, m, len; + uint8_t isEOF; + uint32_t uid; + fnVector * vector = NULL; + countKeys *ck; + int lenVector = 0; + UsbCommand * resp = NULL; + + memset(resultKeys, 0x00, 16 * 6); + + // flush queue + while (WaitForResponseTimeout(CMD_ACK, 500) != NULL) ; + + UsbCommand c = {CMD_MIFARE_NESTED, {blockNo, keyType, trgBlockNo + trgKeyType * 0x100}}; + memcpy(c.d.asBytes, key, 6); + SendCommand(&c); + + PrintAndLog("\n"); + + // wait cycle + while (true) { + printf("."); + if (ukbhit()) { + getchar(); + printf("\naborted via keyboard!\n"); + break; + } + + resp = WaitForResponseTimeout(CMD_ACK, 1500); + + if (resp != NULL) { + isEOF = resp->arg[0] & 0xff; + + if (isEOF) break; + + len = resp->arg[1] & 0xff; + if (len == 0) continue; + + memcpy(&uid, resp->d.asBytes, 4); + PrintAndLog("uid:%08x len=%d trgbl=%d trgkey=%x", uid, len, resp->arg[2] & 0xff, (resp->arg[2] >> 8) & 0xff); + vector = (fnVector *) realloc((void *)vector, (lenVector + len) * sizeof(fnVector) + 200); + if (vector == NULL) { + PrintAndLog("Memory allocation error for fnVector. len: %d bytes: %d", lenVector + len, (lenVector + len) * sizeof(fnVector)); + break; + } + + for (i = 0; i < len; i++) { + vector[lenVector + i].blockNo = resp->arg[2] & 0xff; + vector[lenVector + i].keyType = (resp->arg[2] >> 8) & 0xff; + vector[lenVector + i].uid = uid; + + memcpy(&vector[lenVector + i].nt, (void *)(resp->d.asBytes + 8 + i * 8 + 0), 4); + memcpy(&vector[lenVector + i].ks1, (void *)(resp->d.asBytes + 8 + i * 8 + 4), 4); + } + + lenVector += len; + } + } + + if (!lenVector) { + PrintAndLog("Got 0 keys from proxmark."); + return 1; + } + printf("------------------------------------------------------------------\n"); + + // calc keys + struct Crypto1State* revstate = NULL; + struct Crypto1State* revstate_start = NULL; + uint64_t lfsr; + int kcount = 0; + pKeys *pk; + + if ((pk = (void *) malloc(sizeof(pKeys))) == NULL) return 1; + memset(pk, 0x00, sizeof(pKeys)); + + for (m = 0; m < lenVector; m++) { + // And finally recover the first 32 bits of the key + revstate = lfsr_recovery32(vector[m].ks1, vector[m].nt ^ vector[m].uid); + if (revstate_start == NULL) revstate_start = revstate; + + while ((revstate->odd != 0x0) || (revstate->even != 0x0)) { + lfsr_rollback_word(revstate, vector[m].nt ^ vector[m].uid, 0); + crypto1_get_lfsr(revstate, &lfsr); + + // Allocate a new space for keys + if (((kcount % MEM_CHUNK) == 0) || (kcount >= pk->size)) { + pk->size += MEM_CHUNK; +//fprintf(stdout, "New chunk by %d, sizeof %d\n", kcount, pk->size * sizeof(uint64_t)); + pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t)); + if (pk->possibleKeys == NULL) { + PrintAndLog("Memory allocation error for pk->possibleKeys"); + return 1; + } + } + pk->possibleKeys[kcount] = lfsr; + kcount++; + revstate++; + } + free(revstate_start); + revstate_start = NULL; + + } + + // Truncate + if (kcount != 0) { + pk->size = --kcount; + if ((pk->possibleKeys = (uint64_t *) realloc((void *)pk->possibleKeys, pk->size * sizeof(uint64_t))) == NULL) { + PrintAndLog("Memory allocation error for pk->possibleKeys"); + return 1; + } + } + + PrintAndLog("Total keys count:%d", kcount); + ck = uniqsort(pk->possibleKeys, pk->size); + + // fill key array + for (i = 0; i < 16 ; i++) { + num_to_bytes(ck[i].key, 6, (uint8_t*)(resultKeys + i * 6)); + } + + // finalize + free(pk->possibleKeys); + free(pk); + free(ck); + free(vector); + + return 0; +} + +int mfCheckKeys (uint8_t blockNo, uint8_t keyType, uint8_t keycnt, uint8_t * keyBlock, uint64_t * key){ + *key = 0; + + UsbCommand c = {CMD_MIFARE_CHKKEYS, {blockNo, keyType, keycnt}}; + memcpy(c.d.asBytes, keyBlock, 6 * keycnt); + + SendCommand(&c); + + UsbCommand * resp = WaitForResponseTimeout(CMD_ACK, 3000); + + if (resp == NULL) return 1; + if ((resp->arg[0] & 0xff) != 0x01) return 2; + *key = bytes_to_num(resp->d.asBytes, 6); + return 0; +} diff --git a/client/mifarehost.h b/client/mifarehost.h new file mode 100644 index 000000000..ec1117e83 --- /dev/null +++ b/client/mifarehost.h @@ -0,0 +1,46 @@ +// Merlok, 2011 +// people from mifare@nethemba.com, 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. +//----------------------------------------------------------------------------- +// High frequency ISO14443A commands +//----------------------------------------------------------------------------- + +#include +#include +#include +#include +#include "common.h" +#include "cmdmain.h" +#include "ui.h" +#include "data.h" +#include "proxusb.h" +#include "util.h" +#include "nonce2key/nonce2key.h" +#include "nonce2key/crapto1.h" + +#define MEM_CHUNK 1000000 +#define NESTED_SECTOR_RETRY 10 + +typedef struct fnVector { uint8_t blockNo, keyType; uint32_t uid, nt, ks1; } fnVector; + +typedef struct { + uint64_t Key[2]; + int foundKey[2]; +} sector; + +typedef struct { + uint64_t *possibleKeys; + uint32_t size; +} pKeys; + +typedef struct { + uint64_t key; + int count; +} countKeys; + +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); + diff --git a/client/nonce2key/nonce2key.h b/client/nonce2key/nonce2key.h index dd0701465..c195d9742 100644 --- a/client/nonce2key/nonce2key.h +++ b/client/nonce2key/nonce2key.h @@ -10,10 +10,15 @@ // MIFARE Darkside hack //----------------------------------------------------------------------------- -#include "crapto1.h" +#ifndef __NONCE2KEY_H +#define __NONCE2KEY_H + #include #include +#include "crapto1.h" typedef unsigned char byte_t; -int nonce2key(uint32_t uid, uint32_t nt, uint64_t par_info, uint64_t ks_info, uint64_t * key); \ No newline at end of file +int nonce2key(uint32_t uid, uint32_t nt, uint64_t par_info, uint64_t ks_info, uint64_t * key); + +#endif diff --git a/client/util.c b/client/util.c index d691eefc4..8e7ef01b1 100644 --- a/client/util.c +++ b/client/util.c @@ -8,8 +8,45 @@ // utilities //----------------------------------------------------------------------------- +#include +#include +#include +#include #include "util.h" +#ifdef __linux__ +int ukbhit(void) +{ + int cnt = 0; + int error; + static struct termios Otty, Ntty; + + + tcgetattr( 0, &Otty); + Ntty = Otty; + + Ntty.c_iflag = 0; /* input mode */ + Ntty.c_oflag = 0; /* output mode */ + Ntty.c_lflag &= ~ICANON; /* raw mode */ + Ntty.c_cc[VMIN] = CMIN; /* minimum time to wait */ + Ntty.c_cc[VTIME] = CTIME; /* minimum characters to wait for */ + + if (0 == (error = tcsetattr(0, TCSANOW, &Ntty))) { + error += ioctl(0, FIONREAD, &cnt); + error += tcsetattr(0, TCSANOW, &Otty); + } + + return ( error == 0 ? cnt : -1 ); +} + +#else +#include +int ukbhit(void) { + return kbhit(); +} +#endif + + void print_hex(const uint8_t * data, const size_t len) { size_t i; @@ -49,3 +86,105 @@ uint64_t bytes_to_num(uint8_t* src, size_t len) } return num; } + +// ------------------------------------------------------------------------- +// line - param line +// bg, en - symbol numbers in param line of beginning an ending parameter +// paramnum - param number (from 0) +// ------------------------------------------------------------------------- +int param_getptr(const char *line, int *bg, int *en, int paramnum) +{ + int i; + int len = strlen(line); + + *bg = 0; + *en = 0; + + // skip spaces + while (line[*bg] ==' ' || line[*bg]=='\t') (*bg)++; + if (*bg >= len) { + return 1; + } + + for (i = 0; i < paramnum; i++) { + while (line[*bg]!=' ' && line[*bg]!='\t' && line[*bg] != '\0') (*bg)++; + while (line[*bg]==' ' || line[*bg]=='\t') (*bg)++; + + if (line[*bg] == '\0') return 1; + } + + *en = *bg; + while (line[*en] != ' ' && line[*en] != '\t' && line[*en] != '\0') (*en)++; + + (*en)--; + + return 0; +} + +char param_getchar(const char *line, int paramnum) +{ + int bg, en; + + if (param_getptr(line, &bg, &en, paramnum)) return 0x00; + + return line[bg]; +} + +uint8_t param_get8(const char *line, int paramnum) +{ + return param_get8ex(line, paramnum, 10, 0); +} + +uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base) +{ + int bg, en; + + if (!param_getptr(line, &bg, &en, paramnum)) + return strtol(&line[bg], NULL, base) & 0xff; + else + return deflt; +} + +uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base) +{ + int bg, en; + + if (!param_getptr(line, &bg, &en, paramnum)) + return strtol(&line[bg], NULL, base); + else + return deflt; +} + +uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base) +{ + int bg, en; + + if (!param_getptr(line, &bg, &en, paramnum)) + return strtol(&line[bg], NULL, base); + else + return deflt; + + return 0; +} + +int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt) +{ + int bg, en, temp, i; + + if (hexcnt % 2) + return 1; + + if (param_getptr(line, &bg, &en, paramnum)) return 1; + + if (en - bg + 1 != hexcnt) + return 1; + + for(i = 0; i < hexcnt; i += 2) { + if (!(isxdigit(line[bg + i]) && isxdigit(line[bg + i + 1])) ) return 1; + + sscanf((char[]){line[bg + i], line[bg + i + 1], 0}, "%X", &temp); + data[i / 2] = temp & 0xff; + } + + return 0; +} diff --git a/client/util.h b/client/util.h index 2362cbf4e..1ecf2f0af 100644 --- a/client/util.h +++ b/client/util.h @@ -11,7 +11,17 @@ #include #include +int ukbhit(void); + void print_hex(const uint8_t * data, const size_t len); char * sprint_hex(const uint8_t * data, const size_t len); + void num_to_bytes(uint64_t n, size_t len, uint8_t* dest); uint64_t bytes_to_num(uint8_t* src, size_t len); + +char param_getchar(const char *line, int paramnum); +uint8_t param_get8(const char *line, int paramnum); +uint8_t param_get8ex(const char *line, int paramnum, int deflt, int base); +uint32_t param_get32ex(const char *line, int paramnum, int deflt, int base); +uint64_t param_get64ex(const char *line, int paramnum, int deflt, int base); +int param_gethex(const char *line, int paramnum, uint8_t * data, int hexcnt); diff --git a/include/usb_cmd.h b/include/usb_cmd.h index b36ea5dd9..f4793cfc8 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -95,6 +95,7 @@ typedef struct { #define CMD_MIFARE_READBL 0x0391 #define CMD_MIFARE_READSC 0x0393 #define CMD_MIFARE_WRITEBL 0x0394 +#define CMD_MIFARE_CHKKEYS 0x0395 #define CMD_SNOOP_ICLASS 0x0392 // For measurements of the antenna tuning