mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-14 10:37:23 -07:00
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
This commit is contained in:
parent
50193c1e3e
commit
f397b5cc87
16 changed files with 877 additions and 317 deletions
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -43,6 +43,7 @@ CMDSRCS = \
|
|||
nonce2key/crapto1.c\
|
||||
nonce2key/crypto1.c\
|
||||
nonce2key/nonce2key.c\
|
||||
mifarehost.c\
|
||||
crc16.c \
|
||||
iso14443crc.c \
|
||||
iso15693tools.c \
|
||||
|
|
|
@ -12,7 +12,8 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <conio.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#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 <block number> <key A/B> <key (12 hex symbols)> <block data (32 hex symbols)>");
|
||||
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 <block number> <key A/B> <key (12 hex symbols)>");
|
||||
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 <sector number> <key A/B> <key (12 hex symbols)>");
|
||||
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 <sector number> <key A/B> <key (12 hex symbols)>");
|
||||
PrintAndLog(" sample: hf 14a nested 0 A FFFFFFFFFFFF ");
|
||||
PrintAndLog("Usage:");
|
||||
PrintAndLog(" all sectors: hf 14a nested <card memory> <block number> <key A/B> <key (12 hex symbols)>");
|
||||
PrintAndLog(" one sector: hf 14a nested o <block number> <key A/B> <key (12 hex symbols)>");
|
||||
PrintAndLog(" <target block number> <target key A/B>");
|
||||
PrintAndLog("card memory - 1 - 1K, 2 - 2K, 4 - 4K, <other> - 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 <block number> <key A/B> [<key (12 hex symbols)>]");
|
||||
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, "<UID> -- 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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
197
client/mifarehost.c
Normal file
197
client/mifarehost.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#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;
|
||||
}
|
46
client/mifarehost.h
Normal file
46
client/mifarehost.h
Normal file
|
@ -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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <conio.h>
|
||||
#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);
|
||||
|
|
@ -10,10 +10,15 @@
|
|||
// MIFARE Darkside hack
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "crapto1.h"
|
||||
#ifndef __NONCE2KEY_H
|
||||
#define __NONCE2KEY_H
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#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);
|
||||
int nonce2key(uint32_t uid, uint32_t nt, uint64_t par_info, uint64_t ks_info, uint64_t * key);
|
||||
|
||||
#endif
|
||||
|
|
139
client/util.c
139
client/util.c
|
@ -8,8 +8,45 @@
|
|||
// utilities
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#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 <conio.h>
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,17 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue