From f397b5cc874ac7d658173199d92c30f3f717a300 Mon Sep 17 00:00:00 2001 From: "Merlokbr@gmail.com" Date: Tue, 7 Jun 2011 12:35:52 +0000 Subject: [PATCH] 1. fixed hf 14a mifare. added functionality to ignore one Nt 2. completed hf 14a nested 3. added hf 14a chk to check keys 5. added check keys to hf 14a mifare and hf 14a nested 6. added debug level to mifare commands 7. small bugs and improvements --- armsrc/appmain.c | 3 + armsrc/apps.h | 3 +- armsrc/iso14443a.c | 243 +++++++++++------- armsrc/iso14443a.h | 13 + armsrc/mifareutil.c | 22 +- armsrc/mifareutil.h | 19 ++ client/Makefile | 1 + client/cmdhf14a.c | 472 ++++++++++++++++++++--------------- client/cmdhf14a.h | 2 - client/cmdmain.c | 2 +- client/mifarehost.c | 197 +++++++++++++++ client/mifarehost.h | 46 ++++ client/nonce2key/nonce2key.h | 9 +- client/util.c | 139 +++++++++++ client/util.h | 10 + include/usb_cmd.h | 1 + 16 files changed, 871 insertions(+), 311 deletions(-) create mode 100644 client/mifarehost.c create mode 100644 client/mifarehost.h diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 8be02778..49718ee8 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 e60fc924..322f2674 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 b64a1942..9e1eea54 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) { + 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[2][i]; + nvector[m][i] = nvector[NES_MAX_INFO][i]; } - nvectorcount[m] = nvectorcount[2]; + 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 7b5444fb..ba86acc5 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 1f8a4d17..53e785f5 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 715dfe63..9a909a35 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 aa0fb61f..cf647c38 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 46cfbebe..f2774a16 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; - } - // 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; + blockNo = param_get8(Cmd, 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++; - } - - // 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 (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 < 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)); + if (param_gethex(Cmd, 3, bldata, 32)) { + PrintAndLog("Block data must include 32 HEX symbols"); + return 1; + } + 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; - - // next value - while (*cmdp!=' ' && *cmdp!='\t') cmdp++; - while (*cmdp==' ' || *cmdp=='\t') cmdp++; - if (*cmdp != 'A' && *cmdp != 'a') { - keyType = 1; + 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; } - - // 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 (ctmp != 'A' && ctmp != 'a') keyType = 1; + if (param_gethex(Cmd, 3, 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(" sector no:%02x key type:%02x key:%s ", sectorNo, keyType, sprint_hex(key, 6)); - - // flush queue - while (WaitForResponseTimeout(CMD_ACK, 500) != NULL) ; + 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; + } + } - UsbCommand c = {CMD_MIFARE_NESTED, {sectorNo, keyType, 0}}; - memcpy(c.d.asBytes, key, 6); - SendCommand(&c); + 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); - PrintAndLog("\n"); - printf("-------------------------------------------------------------------------\n"); + if (cmdp == 'o') { + if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) { + PrintAndLog("Nested error."); + return 2; + } - // wait cycle - while (true) { - printf("."); - if (kbhit()) { - getchar(); - printf("\naborted via keyboard!\n"); - break; + 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; + } + } } - resp = WaitForResponseTimeout(CMD_ACK, 1500); + 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); + } - if (resp != NULL) { - isEOF = resp->arg[0] & 0xff; - data = resp->d.asBytes; + return 0; +} - 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; +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; - 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); + memset(keyBlock, 0x00, sizeof(keyBlock)); - PrintAndLog("i=%d nt:%08x ks1:%08x", i, vector[lenVector + i].nt, vector[lenVector + i].ks1); - } + if (strlen(Cmd)<3) { + PrintAndLog("Usage: hf 14a chk []"); + PrintAndLog(" sample: hf 14a chk 0 A FFFFFFFFFFFF a0a1a2a3a4a5 b01b2b3b4b5 "); + return 0; + } + + 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; - 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 fdb8b959..56329bed 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 c27d8406..8f4618c9 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 00000000..aab1ae33 --- /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 00000000..ec1117e8 --- /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 dd070146..c195d974 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 d691eefc..8e7ef01b 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 2362cbf4..1ecf2f0a 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 b36ea5dd..f4793cfc 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 -- 2.39.5