X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/20f9a2a1d54952ed15066c93490f0e8fb0d43b67..0a39986e01069b05b6463bae6f8141dc801df41a:/armsrc/iso14443a.c diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index bb280807..cc63093e 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1,4 +1,5 @@ //----------------------------------------------------------------------------- +// Merlok - June 2011 // Gerhard de Koning Gans - May 2008 // Hagen Fritsch - June 2010 // @@ -65,6 +66,9 @@ static const uint8_t OddByteParity[256] = { #define DMA_BUFFER_OFFSET 3160 #define DMA_BUFFER_SIZE 4096 #define TRACE_LENGTH 3000 +// card emulator memory +#define CARD_MEMORY 7260 +#define CARD_MEMORY_LEN 1024 uint8_t trigger = 0; void iso14a_set_trigger(int enable) { @@ -931,6 +935,7 @@ static int GetIso14443aCommandFromReader(uint8_t *received, int *len, int maxLen } } } +static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, int correctionNeeded); //----------------------------------------------------------------------------- // Main loop of simulated tag: receive commands from reader, decide what @@ -1179,8 +1184,13 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); } if(respLen <= 0) continue; + //---------------------------- + u = 0; + b = 0x00; + fdt_indicator = FALSE; - // Modulate Manchester + EmSendCmd14443aRaw(resp, respLen, receivedCmd[0] == 0x52); +/* // Modulate Manchester FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); AT91C_BASE_SSC->SSC_THR = 0x00; FpgaSetupSsc(); @@ -1212,7 +1222,7 @@ ComputeCrc14443(CRC_14443_A, response3a, 1, &response3a[1], &response3a[2]); break; } } - +*/ } Dbprintf("%x %x %x", happened, happened2, cmdsRecvd); @@ -1397,6 +1407,137 @@ void CodeIso14443aAsReaderPar(const uint8_t * cmd, int len, uint32_t dwParity) ToSendMax++; } +//----------------------------------------------------------------------------- +// Wait for commands from reader +// Stop when button is pressed (return 1) or field was gone (return 2) +// Or return 0 when command is captured +//----------------------------------------------------------------------------- +static int EmGetCmd(uint8_t *received, int *len, int maxLen) +{ + *len = 0; + + uint32_t timer = 0, vtime = 0; + int analogCnt = 0; + int analogAVG = 0; + + // Set FPGA mode to "simulated ISO 14443 tag", no modulation (listen + // only, since we are receiving, not transmitting). + // Signal field is off with the appropriate LED + LED_D_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + + // Set ADC to read field strength + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_SWRST; + AT91C_BASE_ADC->ADC_MR = + ADC_MODE_PRESCALE(32) | + ADC_MODE_STARTUP_TIME(16) | + ADC_MODE_SAMPLE_HOLD_TIME(8); + AT91C_BASE_ADC->ADC_CHER = ADC_CHANNEL(ADC_CHAN_HF); + // start ADC + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; + + // Now run a 'software UART' on the stream of incoming samples. + Uart.output = received; + Uart.byteCntMax = maxLen; + Uart.state = STATE_UNSYNCD; + + for(;;) { + WDT_HIT(); + + if (BUTTON_PRESS()) return 1; + + // test if the field exists + if (AT91C_BASE_ADC->ADC_SR & ADC_END_OF_CONVERSION(ADC_CHAN_HF)) { + analogCnt++; + analogAVG += AT91C_BASE_ADC->ADC_CDR[ADC_CHAN_HF]; + AT91C_BASE_ADC->ADC_CR = AT91C_ADC_START; + if (analogCnt >= 32) { + if ((33000 * (analogAVG / analogCnt) >> 10) < MF_MINFIELDV) { + vtime = GetTickCount(); + if (!timer) timer = vtime; + // 50ms no field --> card to idle state + if (vtime - timer > 50) return 2; + } else + if (timer) timer = 0; + analogCnt = 0; + analogAVG = 0; + } + } + // transmit none + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + AT91C_BASE_SSC->SSC_THR = 0x00; + } + // receive and test the miller decoding + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + if(MillerDecoding((b & 0xf0) >> 4)) { + *len = Uart.byteCnt; + if (tracing) LogTrace(received, *len, 0, GetParity(received, *len), TRUE); + return 0; + } + if(MillerDecoding(b & 0x0f)) { + *len = Uart.byteCnt; + if (tracing) LogTrace(received, *len, 0, GetParity(received, *len), TRUE); + return 0; + } + } + } +} + +static int EmSendCmd14443aRaw(uint8_t *resp, int respLen, int correctionNeeded) +{ + int i, u = 0; + uint8_t b = 0; + + // Modulate Manchester + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD); + AT91C_BASE_SSC->SSC_THR = 0x00; + FpgaSetupSsc(); + + // include correction bit + i = 1; + if((Uart.parityBits & 0x01) || correctionNeeded) { + // 1236, so correction bit needed + i = 0; + } + + // send cycle + for(;;) { + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { + volatile uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; + (void)b; + } + if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { + if(i > respLen) { + b = 0x00; + u++; + } else { + b = resp[i]; + i++; + } + AT91C_BASE_SSC->SSC_THR = b; + + if(u > 4) break; + } + if(BUTTON_PRESS()) { + break; + } + } + + return 0; +} + +static int EmSendCmdEx(uint8_t *resp, int respLen, int correctionNeeded){ + CodeIso14443aAsTag(resp, respLen); + int res = EmSendCmd14443aRaw(ToSend, ToSendMax, correctionNeeded); + if (tracing) LogTrace(resp, respLen, 0, GetParity(resp, respLen), FALSE); + return res; +} + +static int EmSendCmd(uint8_t *resp, int respLen){ + return EmSendCmdEx(resp, respLen, 0); +} + //----------------------------------------------------------------------------- // Wait a certain time for tag response // If a response is captured return TRUE @@ -1492,6 +1633,16 @@ int ReaderReceive(uint8_t* receivedAnswer) return Demod.len; } +int ReaderReceivePar(uint8_t* receivedAnswer, uint32_t * parptr) +{ + int samples = 0; + if (!GetIso14443aAnswerFromTag(receivedAnswer,160,&samples,0)) return FALSE; + if (tracing) LogTrace(receivedAnswer,Demod.len,samples,Demod.parityBits,FALSE); + *parptr = Demod.parityBits; + if(samples == 0) return FALSE; + return Demod.len; +} + /* performs iso14443a anticolision procedure * fills the uid pointer unless NULL * fills resp_data unless NULL */ @@ -1502,7 +1653,6 @@ int iso14443a_select_card(uint8_t * uid_ptr, iso14a_card_select_t * resp_data, u uint8_t rats[] = { 0xE0,0x80,0x00,0x00 }; // FSD=256, FSDI=8, CID=0 uint8_t* resp = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes - //uint8_t* uid = resp + 7; uint8_t sak = 0x04; // cascade uid int cascade_level = 0; @@ -1520,9 +1670,6 @@ int iso14443a_select_card(uint8_t * uid_ptr, iso14a_card_select_t * resp_data, u if(resp_data) memcpy(resp_data->atqa, resp, 2); - //ReaderTransmit(sel_all,sizeof(sel_all)); --- avoid duplicate SELECT request - //if(!ReaderReceive(uid)) return 0; - // OK we will select at least at cascade 1, lets see if first byte of UID was 0x88 in // which case we need to make a cascade 2 request and select - this is a long UID // While the UID is not complete, the 3nd bit (from the right) is set in the SAK. @@ -1668,11 +1815,11 @@ void ReaderMifare(uint32_t parameter) { // Mifare AUTH uint8_t mf_auth[] = { 0x60,0x00,0xf5,0x7b }; - uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; + uint8_t mf_nr_ar[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; - uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes - traceLen = 0; - tracing = false; + uint8_t* receivedAnswer = (((uint8_t *)BigBuf) + 3560); // was 3560 - tied to other size changes + traceLen = 0; + tracing = false; iso14443a_setup(); @@ -1680,89 +1827,108 @@ void ReaderMifare(uint32_t parameter) LED_B_OFF(); LED_C_OFF(); - byte_t nt_diff = 0; - LED_A_OFF(); - byte_t par = 0; - byte_t par_mask = 0xff; - byte_t par_low = 0; - int led_on = TRUE; - - tracing = FALSE; - byte_t nt[4]; - byte_t nt_attacked[4]; - byte_t par_list[8]; - byte_t ks_list[8]; - num_to_bytes(parameter,4,nt_attacked); - - while(TRUE) - { - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - SpinDelay(200); - FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + byte_t nt_diff = 0; + LED_A_OFF(); + byte_t par = 0; + byte_t par_mask = 0xff; + byte_t par_low = 0; + int led_on = TRUE; + uint8_t uid[8]; + uint32_t cuid; - // Test if the action was cancelled - if(BUTTON_PRESS()) { - break; - } + tracing = FALSE; + byte_t nt[4] = {0,0,0,0}; + 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_noattack); + int isOK = 0, isNULL = 0; + + while(TRUE) + { + LED_C_ON(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + LED_C_OFF(); + + // Test if the action was cancelled + if(BUTTON_PRESS()) { + break; + } - if(!iso14443a_select_card(NULL, NULL, NULL)) continue; + if(!iso14443a_select_card(uid, NULL, &cuid)) continue; - // Transmit MIFARE_CLASSIC_AUTH - ReaderTransmit(mf_auth,sizeof(mf_auth)); + // Transmit MIFARE_CLASSIC_AUTH + ReaderTransmit(mf_auth, sizeof(mf_auth)); - // Receive the (16 bit) "random" nonce - if (!ReaderReceive(receivedAnswer)) continue; - memcpy(nt,receivedAnswer,4); + // Receive the (16 bit) "random" nonce + if (!ReaderReceive(receivedAnswer)) continue; + memcpy(nt, receivedAnswer, 4); - // Transmit reader nonce and reader answer - ReaderTransmitPar(mf_nr_ar,sizeof(mf_nr_ar),par); + // Transmit reader nonce and reader answer + ReaderTransmitPar(mf_nr_ar, sizeof(mf_nr_ar),par); - // Receive 4 bit answer - if (ReaderReceive(receivedAnswer)) - { - if (nt_diff == 0) - { - LED_A_ON(); - memcpy(nt_attacked,nt,4); - par_mask = 0xf8; - par_low = par & 0x07; - } + // Receive 4 bit answer + if (ReaderReceive(receivedAnswer)) + { + if ( (parameter != 0) && (memcmp(nt, nt_noattack, 4) == 0) ) continue; - if (memcmp(nt,nt_attacked,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; - led_on = !led_on; - if(led_on) LED_B_ON(); else LED_B_OFF(); - par_list[nt_diff] = par; - ks_list[nt_diff] = receivedAnswer[0]^0x05; + if (nt_diff == 0) + { + LED_A_ON(); + memcpy(nt_attacked, nt, 4); + par_mask = 0xf8; + par_low = par & 0x07; + } - // Test if the information is complete - if (nt_diff == 0x07) break; + led_on = !led_on; + if(led_on) LED_B_ON(); else LED_B_OFF(); + par_list[nt_diff] = par; + ks_list[nt_diff] = receivedAnswer[0] ^ 0x05; - nt_diff = (nt_diff+1) & 0x07; - mf_nr_ar[3] = nt_diff << 5; - par = par_low; - } else { - if (nt_diff == 0) - { - par++; - } else { - par = (((par>>3)+1) << 3) | par_low; - } - } - } + // Test if the information is complete + if (nt_diff == 0x07) { + isOK = 1; + break; + } - LogTrace(nt,4,0,GetParity(nt,4),TRUE); - LogTrace(par_list,8,0,GetParity(par_list,8),TRUE); - LogTrace(ks_list,8,0,GetParity(ks_list,8),TRUE); + nt_diff = (nt_diff + 1) & 0x07; + mf_nr_ar[3] = nt_diff << 5; + par = par_low; + } else { + if (nt_diff == 0) + { + par++; + } else { + par = (((par >> 3) + 1) << 3) | par_low; + } + } + } - // Thats it... + LogTrace(nt, 4, 0, GetParity(nt, 4), TRUE); + LogTrace(par_list, 8, 0, GetParity(par_list, 8), TRUE); + LogTrace(ks_list, 8, 0, GetParity(ks_list, 8), TRUE); + + UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; + memcpy(ack.d.asBytes + 0, uid, 4); + memcpy(ack.d.asBytes + 4, nt, 4); + memcpy(ack.d.asBytes + 8, par_list, 8); + memcpy(ack.d.asBytes + 16, ks_list, 8); + + LED_B_ON(); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - tracing = TRUE; - - DbpString("COMMAND FINISHED"); - - Dbprintf("nt=%x", (int)nt[0]); + tracing = TRUE; + + if (MF_DBGLEVEL >= 1) DbpString("COMMAND mifare FINISHED"); } //----------------------------------------------------------------------------- @@ -1778,17 +1944,17 @@ void MifareReadBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) ui64Key = bytes_to_num(datain, 6); // variables - byte_t isOK = 0; - byte_t dataoutbuf[16]; - uint8_t uid[7]; + byte_t isOK = 0; + byte_t dataoutbuf[16]; + uint8_t uid[8]; uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; // clear trace - traceLen = 0; -// tracing = false; + traceLen = 0; +// tracing = false; iso14443a_setup(); @@ -1798,22 +1964,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, 0)) { - Dbprintf("Auth error"); + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; if(mifare_classic_readblock(pcs, cuid, blockNo, dataoutbuf)) { - 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; }; @@ -1824,21 +1990,21 @@ 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; uid[1] = 0xff; uid[2] = 0xff; uid[3] = 0xff; - LogTrace(uid, 4, 0, 0, TRUE); + LogTrace(uid, 4, 0, 0, TRUE); UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; memcpy(ack.d.asBytes, dataoutbuf, 16); LED_B_ON(); UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); + LED_B_OFF(); // Thats it... @@ -1861,17 +2027,17 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) ui64Key = bytes_to_num(datain, 6); // variables - byte_t isOK = 0; - byte_t dataoutbuf[16 * 4]; + byte_t isOK = 0; + byte_t dataoutbuf[16 * 4]; uint8_t uid[8]; uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; // clear trace - traceLen = 0; -// tracing = false; + traceLen = 0; +// tracing = false; iso14443a_setup(); @@ -1881,34 +2047,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, 0)) { - Dbprintf("Auth error"); + if(mifare_classic_auth(pcs, cuid, sectorNo * 4, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; if(mifare_classic_readblock(pcs, cuid, sectorNo * 4 + 0, dataoutbuf + 16 * 0)) { - 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; }; @@ -1919,14 +2085,14 @@ 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; uid[1] = 0xff; uid[2] = 0xff; uid[3] = 0xff; - LogTrace(uid, 4, 0, 0, TRUE); + LogTrace(uid, 4, 0, 0, TRUE); UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; memcpy(ack.d.asBytes, dataoutbuf, 16 * 2); @@ -1940,7 +2106,7 @@ void MifareReadSector(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); LED_B_OFF(); - // Thats it... + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); // tracing = TRUE; @@ -1953,25 +2119,25 @@ 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) { - // params + // params uint8_t blockNo = arg0; uint8_t keyType = arg1; uint64_t ui64Key = 0; - byte_t blockdata[16]; + byte_t blockdata[16]; ui64Key = bytes_to_num(datain, 6); memcpy(blockdata, datain + 10, 16); // variables - byte_t isOK = 0; + byte_t isOK = 0; uint8_t uid[8]; uint32_t cuid; - struct Crypto1State mpcs = {0, 0}; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; // clear trace - traceLen = 0; + traceLen = 0; // tracing = false; iso14443a_setup(); @@ -1981,23 +2147,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, 0)) { - Dbprintf("Auth error"); + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth error"); break; }; if(mifare_classic_writeblock(pcs, cuid, blockNo, blockdata)) { - 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; }; @@ -2008,14 +2174,14 @@ 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; uid[1] = 0xff; uid[2] = 0xff; uid[3] = 0xff; - LogTrace(uid, 4, 0, 0, TRUE); + LogTrace(uid, 4, 0, 0, TRUE); UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; @@ -2024,71 +2190,309 @@ void MifareWriteBlock(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) LED_B_OFF(); - // Thats it... + // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); // tracing = TRUE; } +// Return 1 if the nonce is invalid else return 0 +int valid_nonce(uint32_t Nt, uint32_t NtEnc, uint32_t Ks1, byte_t * parity) { + return ((oddparity((Nt >> 24) & 0xFF) == ((parity[0]) ^ oddparity((NtEnc >> 24) & 0xFF) ^ BIT(Ks1,16))) & \ + (oddparity((Nt >> 16) & 0xFF) == ((parity[1]) ^ oddparity((NtEnc >> 16) & 0xFF) ^ BIT(Ks1,8))) & \ + (oddparity((Nt >> 8) & 0xFF) == ((parity[2]) ^ oddparity((NtEnc >> 8) & 0xFF) ^ BIT(Ks1,0)))) ? 1 : 0; +} + + //----------------------------------------------------------------------------- // MIFARE nested authentication. // //----------------------------------------------------------------------------- -void MifareNested(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 + // 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 - byte_t isOK = 0; + int rtr, i, j, m, len; + int davg, dmin, dmax; uint8_t uid[8]; - uint32_t cuid; - uint8_t dataoutbuf[16]; - struct Crypto1State mpcs = {0, 0}; + uint32_t cuid, nt1, nt2, nttmp, nttest, par, ks1; + uint8_t par_array[4]; + nestedVector nvector[NES_MAX_INFO + 1][10]; + int nvectorcount[NES_MAX_INFO + 1]; + int ncount = 0; + UsbCommand ack = {CMD_ACK, {0, 0, 0}}; + struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; + uint8_t* receivedAnswer = mifare_get_bigbufptr(); + //init + for (i = 0; i < NES_MAX_INFO + 1; i++) nvectorcount[i] = 11; // 11 - empty block; + // clear trace - traceLen = 0; -// tracing = false; - + traceLen = 0; + tracing = false; + iso14443a_setup(); LED_A_ON(); - LED_B_OFF(); + LED_B_ON(); LED_C_OFF(); - while (true) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + davg = dmax = 0; + dmin = 2000; + + // test nonce distance + for (rtr = 0; rtr < 10; rtr++) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(100); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + // Test if the action was cancelled + if(BUTTON_PRESS()) { + break; + } + if(!iso14443a_select_card(uid, NULL, &cuid)) { - Dbprintf("Can't select card"); + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; - if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, 0)) { - Dbprintf("Auth error"); + if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 error"); break; }; - // nested authenticate block = (blockNo + 1) - if(mifare_classic_auth(pcs, (uint32_t)bytes_to_num(uid, 4), blockNo + 1, keyType, ui64Key, 1)) { - Dbprintf("Auth error"); + if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_NESTED, &nt2)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error"); + break; + }; + + nttmp = prng_successor(nt1, 500); + for (i = 501; i < 2000; i++) { + nttmp = prng_successor(nttmp, 1); + if (nttmp == nt2) break; + } + + if (i != 2000) { + davg += i; + if (dmin > i) dmin = i; + if (dmax < i) dmax = i; + if (MF_DBGLEVEL >= 4) Dbprintf("r=%d nt1=%08x nt2=%08x distance=%d", rtr, nt1, nt2, i); + } + } + + if (rtr == 0) return; + + davg = davg / rtr; + if (MF_DBGLEVEL >= 3) Dbprintf("distance: min=%d max=%d avg=%d", dmin, dmax, davg); + + LED_B_OFF(); + +// ------------------------------------------------------------------------------------------------- + + LED_C_ON(); + + // get crypted nonces for target sector + for (rtr = 0; rtr < NS_RETRIES_GETNONCE; rtr++) { + if (MF_DBGLEVEL >= 4) Dbprintf("------------------------------"); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(100); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + // Test if the action was cancelled + if(BUTTON_PRESS()) { + break; + } + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; - if(mifare_classic_readblock(pcs, (uint32_t)bytes_to_num(uid, 4), blockNo + 1, dataoutbuf)) { - Dbprintf("Read block error"); + if(mifare_classic_authex(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST, &nt1)) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth1 error"); + break; + }; + + // nested authentication + len = mifare_sendcmd_shortex(pcs, AUTH_NESTED, 0x60 + (targetKeyType & 0x01), targetBlockNo, receivedAnswer, &par); + if (len != 4) { + if (MF_DBGLEVEL >= 1) Dbprintf("Auth2 error len=%d", len); break; }; + + nt2 = bytes_to_num(receivedAnswer, 4); + if (MF_DBGLEVEL >= 4) Dbprintf("r=%d nt1=%08x nt2enc=%08x nt2par=%08x", rtr, nt1, nt2, par); + + // Parity validity check + for (i = 0; i < 4; i++) { + par_array[i] = (oddparity(receivedAnswer[i]) != ((par & 0x08) >> 3)); + par = par << 1; + } + + ncount = 0; + for (m = dmin - NS_TOLERANCE; m < dmax + NS_TOLERANCE; m++) { + nttest = prng_successor(nt1, m); + ks1 = nt2 ^ nttest; + + if (valid_nonce(nttest, nt2, ks1, par_array) && (ncount < 11)){ + + nvector[NES_MAX_INFO][ncount].nt = nttest; + nvector[NES_MAX_INFO][ncount].ks1 = ks1; + ncount++; + nvectorcount[NES_MAX_INFO] = ncount; + if (MF_DBGLEVEL >= 4) Dbprintf("valid m=%d ks1=%08x nttest=%08x", m, ks1, nttest); + } + + } + + // select vector with length less than got + if (nvectorcount[NES_MAX_INFO] != 0) { + m = NES_MAX_INFO; + + for (i = 0; i < NES_MAX_INFO; i++) + if (nvectorcount[i] > 10) { + m = i; + break; + } + + if (m == NES_MAX_INFO) + for (i = 0; i < NES_MAX_INFO; i++) + if (nvectorcount[NES_MAX_INFO] < nvectorcount[i]) { + m = i; + break; + } + + if (m != NES_MAX_INFO) { + for (i = 0; i < nvectorcount[m]; i++) { + nvector[m][i] = nvector[NES_MAX_INFO][i]; + } + nvectorcount[m] = nvectorcount[NES_MAX_INFO]; + } + } + } + + LED_C_OFF(); + + // ----------------------------- crypto1 destroy + crypto1_destroy(pcs); + + // add trace trailer + uid[0] = 0xff; + uid[1] = 0xff; + uid[2] = 0xff; + uid[3] = 0xff; + LogTrace(uid, 4, 0, 0, TRUE); + + for (i = 0; i < NES_MAX_INFO; i++) { + if (nvectorcount[i] > 10) continue; + + for (j = 0; j < nvectorcount[i]; j += 5) { + ncount = nvectorcount[i] - j; + if (ncount > 5) ncount = 5; + + ack.arg[0] = 0; // isEOF = 0 + ack.arg[1] = ncount; + ack.arg[2] = targetBlockNo + (targetKeyType * 0x100); + memset(ack.d.asBytes, 0x00, sizeof(ack.d.asBytes)); + + memcpy(ack.d.asBytes, &cuid, 4); + for (m = 0; m < ncount; m++) { + memcpy(ack.d.asBytes + 8 + m * 8 + 0, &nvector[i][m + j].nt, 4); + memcpy(ack.d.asBytes + 8 + m * 8 + 4, &nvector[i][m + j].ks1, 4); + } + + LED_B_ON(); + SpinDelay(100); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + } + } - if(mifare_classic_halt(pcs, (uint32_t)bytes_to_num(uid, 4))) { - Dbprintf("Halt error"); + // finalize list + ack.arg[0] = 1; // isEOF = 1 + ack.arg[1] = 0; + ack.arg[2] = 0; + memset(ack.d.asBytes, 0x00, sizeof(ack.d.asBytes)); + + LED_B_ON(); + SpinDelay(300); + UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); + LED_B_OFF(); + + if (MF_DBGLEVEL >= 4) DbpString("NESTED FINISHED"); + + // Thats it... + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + + tracing = TRUE; +} + +//----------------------------------------------------------------------------- +// MIFARE check keys. key count up to 8. +// +//----------------------------------------------------------------------------- +void MifareChkKeys(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) +{ + // params + uint8_t blockNo = arg0; + uint8_t keyType = arg1; + uint8_t keyCount = arg2; + uint64_t ui64Key = 0; + + // variables + int i; + byte_t isOK = 0; + uint8_t uid[8]; + uint32_t cuid; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + // clear debug level + int OLD_MF_DBGLEVEL = MF_DBGLEVEL; + MF_DBGLEVEL = MF_DBG_NONE; + + // clear trace + traceLen = 0; + tracing = TRUE; + + iso14443a_setup(); + + LED_A_ON(); + LED_B_OFF(); + LED_C_OFF(); + + SpinDelay(300); + for (i = 0; i < keyCount; i++) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(100); + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); + + if(!iso14443a_select_card(uid, NULL, &cuid)) { + if (OLD_MF_DBGLEVEL >= 1) Dbprintf("Can't select card"); break; }; + + ui64Key = bytes_to_num(datain + i * 6, 6); + if(mifare_classic_auth(pcs, cuid, blockNo, keyType, ui64Key, AUTH_FIRST)) { + continue; + }; isOK = 1; break; @@ -2097,27 +2501,26 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) // ----------------------------- crypto1 destroy crypto1_destroy(pcs); - DbpString("NESTED FINISHED"); - // add trace trailer uid[0] = 0xff; uid[1] = 0xff; uid[2] = 0xff; uid[3] = 0xff; - LogTrace(uid, 4, 0, 0, TRUE); + LogTrace(uid, 4, 0, 0, TRUE); UsbCommand ack = {CMD_ACK, {isOK, 0, 0}}; - memcpy(ack.d.asBytes, dataoutbuf, 16); + if (isOK) memcpy(ack.d.asBytes, datain + i * 6, 6); LED_B_ON(); UsbSendPacket((uint8_t *)&ack, sizeof(UsbCommand)); - LED_B_OFF(); + LED_B_OFF(); // Thats it... FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); -// tracing = TRUE; + // restore debug level + MF_DBGLEVEL = OLD_MF_DBGLEVEL; } //----------------------------------------------------------------------------- @@ -2126,4 +2529,273 @@ void MifareNested(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) //----------------------------------------------------------------------------- void Mifare1ksim(uint8_t arg0, uint8_t arg1, uint8_t arg2, uint8_t *datain) { + int cardSTATE = MFEMUL_NOFIELD; + int vHf = 0; // in mV + int res, i; + uint32_t timer = 0; + uint32_t selTimer = 0; + uint32_t authTimer = 0; + uint32_t par = 0; + int len = 0; + uint8_t bt; + uint8_t cardAUTHSC = 0; + uint8_t cardAUTHKEY = 0xff; // no authentication + uint32_t cuid = 0; + struct Crypto1State mpcs = {0, 0}; + struct Crypto1State *pcs; + pcs = &mpcs; + + uint64_t key64 = 0xffffffffffffULL; + + uint8_t* receivedCmd = mifare_get_bigbufptr(); + + static uint8_t rATQA[] = {0x04, 0x00}; // Mifare classic 1k + + static uint8_t rUIDBCC1[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; + static uint8_t rUIDBCC2[] = {0xde, 0xad, 0xbe, 0xaf, 0x62}; // !!! + + static uint8_t rSAK[] = {0x08, 0xb6, 0xdd}; + + static uint8_t rAUTH_NT[] = {0x1a, 0xac, 0xff, 0x4f}; + static uint8_t rAUTH_AT[] = {0x00, 0x00, 0x00, 0x00}; + static uint8_t cmdBuf[18]; + + // clear trace + traceLen = 0; + tracing = true; + +// -------------------------------------- test area + + // Authenticate response - nonce + uint8_t *resp1 = (((uint8_t *)BigBuf) + CARD_MEMORY); + int resp1Len; + uint8_t *resp2 = (((uint8_t *)BigBuf) + CARD_MEMORY + 200); + int resp2Len; + CodeIso14443aAsTag(rAUTH_NT, sizeof(rAUTH_NT)); + memcpy(resp1, ToSend, ToSendMax); resp1Len = ToSendMax; + + timer = GetTickCount(); + uint32_t nonce = bytes_to_num(rAUTH_NT, 4); + uint32_t rn_enc = 0x98d76b77; // !!!!!!!!!!!!!!!!! + uint32_t ans = 0; + cuid = bytes_to_num(rUIDBCC1, 4); + + crypto1_create(pcs, key64); + crypto1_word(pcs, cuid ^ nonce, 0); + crypto1_word(pcs, rn_enc , 1); + crypto1_word(pcs, 0, 0); + ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0); + num_to_bytes(ans, 4, rAUTH_AT); + CodeIso14443aAsTag(rAUTH_AT, sizeof(rAUTH_AT)); + memcpy(resp2, ToSend, ToSendMax); resp2Len = ToSendMax; + Dbprintf("crypto auth time: %d", GetTickCount() - timer); + +// -------------------------------------- END test area + + // We need to listen to the high-frequency, peak-detected path. + SetAdcMuxFor(GPIO_MUXSEL_HIPKD); + FpgaSetupSsc(); + + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_LISTEN); + SpinDelay(200); + +Dbprintf("--> start"); + while (true) { + WDT_HIT(); + + // find reader field + // Vref = 3300mV, and an 10:1 voltage divider on the input + // can measure voltages up to 33000 mV + if (cardSTATE == MFEMUL_NOFIELD) { + vHf = (33000 * AvgAdc(ADC_CHAN_HF)) >> 10; + if (vHf > MF_MINFIELDV) { + cardSTATE = MFEMUL_IDLE; + LED_A_ON(); + } + } + + if (cardSTATE != MFEMUL_NOFIELD) { + res = EmGetCmd(receivedCmd, &len, 100); + if (res == 2) { + cardSTATE = MFEMUL_NOFIELD; + LEDsoff(); + continue; + } + if(res) break; + } + + if(BUTTON_PRESS()) { + break; + } +// if (len) Dbprintf("len:%d cmd: %02x %02x %02x %02x", len, receivedCmd[0], receivedCmd[1], receivedCmd[2], receivedCmd[3]); + + if (len != 4 && cardSTATE != MFEMUL_NOFIELD) { // len != 4 <---- speed up the code 4 authentication + // REQ or WUP request in ANY state and WUP in HALTED state + if (len == 1 && ((receivedCmd[0] == 0x26 && cardSTATE != MFEMUL_HALTED) || receivedCmd[0] == 0x52)) { + selTimer = GetTickCount(); + EmSendCmdEx(rATQA, sizeof(rATQA), (receivedCmd[0] == 0x52)); + cardSTATE = MFEMUL_SELECT1; + + // init crypto block + LED_B_OFF(); + LED_C_OFF(); + crypto1_destroy(pcs); + cardAUTHKEY = 0xff; + } + } + + switch (cardSTATE) { + case MFEMUL_NOFIELD:{ + break; + } + case MFEMUL_HALTED:{ + break; + } + case MFEMUL_IDLE:{ + break; + } + case MFEMUL_SELECT1:{ + // select all + if (len == 2 && (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x20)) { + EmSendCmd(rUIDBCC1, sizeof(rUIDBCC1)); + + if (rUIDBCC1[0] == 0x88) { + cardSTATE = MFEMUL_SELECT2; + } + } + + // select card + if (len == 9 && + (receivedCmd[0] == 0x93 && receivedCmd[1] == 0x70 && memcmp(&receivedCmd[2], rUIDBCC1, 4) == 0)) { + EmSendCmd(rSAK, sizeof(rSAK)); + + cuid = bytes_to_num(rUIDBCC1, 4); + cardSTATE = MFEMUL_WORK; + LED_B_ON(); + Dbprintf("--> WORK. anticol1 time: %d", GetTickCount() - selTimer); + } + + break; + } + case MFEMUL_SELECT2:{ + EmSendCmd(rUIDBCC2, sizeof(rUIDBCC2)); + + cuid = bytes_to_num(rUIDBCC2, 4); + cardSTATE = MFEMUL_WORK; + LED_B_ON(); +Dbprintf("--> WORK. anticol2 time: %d", GetTickCount() - timer); + break; + } + case MFEMUL_AUTH1:{ + if (len == 8) { +timer = GetTickCount(); +// --------------------------------- + rn_enc = bytes_to_num(receivedCmd, 4); + crypto1_create(pcs, key64); + crypto1_word(pcs, cuid ^ nonce, 0); + crypto1_word(pcs, rn_enc , 1); + crypto1_word(pcs, 0, 0); + ans = prng_successor(nonce, 96) ^ crypto1_word(pcs, 0, 0); + num_to_bytes(ans, 4, rAUTH_AT); +// --------------------------------- + EmSendCmd(rAUTH_AT, sizeof(rAUTH_AT)); +// EmSendCmd14443aRaw(resp2, resp2Len, 0); + cardSTATE = MFEMUL_AUTH2; + } else { + cardSTATE = MFEMUL_IDLE; + LED_B_OFF(); + LED_C_OFF(); + } + if (cardSTATE != MFEMUL_AUTH2) break; + } + case MFEMUL_AUTH2:{ + // test auth info here... + + LED_C_ON(); + cardSTATE = MFEMUL_WORK; +Dbprintf("AUTH COMPLETED. sec=%d, key=%d time=%d a=%d", cardAUTHSC, cardAUTHKEY, GetTickCount() - authTimer, GetTickCount() - timer); + break; + } + case MFEMUL_WORK:{ + // auth + if (len == 4 && (receivedCmd[0] == 0x60 || receivedCmd[0] == 0x61)) { + authTimer = GetTickCount(); +// EmSendCmd(rAUTH_NT, sizeof(rAUTH_NT)); +//SpinDelayUs(30); + EmSendCmd14443aRaw(resp1, resp1Len, 0); +// crypto1_create(pcs, key64); +// if (cardAUTHKEY == 0xff) { // first auth +// crypto1_word(pcs, cuid ^ bytes_to_num(rAUTH_NT, 4), 0); // uid ^ nonce +// } else { // nested auth +// } + + cardAUTHSC = receivedCmd[1] / 4; // received block num + cardAUTHKEY = receivedCmd[0] - 0x60; + cardSTATE = MFEMUL_AUTH1; + break; + } + + if (len == 0) break; + + // decrypt seqence + if (cardAUTHKEY != 0xff){ + if (len != 1) { + for (i = 0; i < len; i++) + receivedCmd[i] = crypto1_byte(pcs, 0x00, 0) ^ receivedCmd[i]; + } else { + bt = 0; + for (i = 0; i < 4; i++) + bt |= (crypto1_bit(pcs, 0, 0) ^ BIT(receivedCmd[0], i)) << i; + + receivedCmd[0] = bt; + } + } + + // read block + if (len == 4 && receivedCmd[0] == 0x30) { + cmdBuf[0] = 0; + par = 0; +/* memcpy(cmdBuf, blockData, 16); + AppendCrc14443a(cmdBuf, 16); + + // crypto + par = 0; + for (i = 0; i < 18; i++) { + d_block_enc[pos] = crypto1_byte(pcs, 0x00, 0) ^ cmdBuf[pos]; + par = (par >> 1) | ( ((filter(pcs->odd) ^ oddparity(cmdBuf[pos])) & 0x01) * 0x20000 ); + } +*/ + //ReaderTransmitPar(d_block_enc, sizeof(d_block_enc), par); +Dbprintf("read block: %d", receivedCmd[1]); + break; + } + + // write block + if (len == 4 && receivedCmd[0] == 0xA0) { +Dbprintf("write block: %d", receivedCmd[1]); + break; + } + + // halt + if (len == 4 && (receivedCmd[0] == 0x50 && receivedCmd[1] == 0x00)) { + cardSTATE = MFEMUL_HALTED; + LED_B_OFF(); + LED_C_OFF(); + Dbprintf("--> HALTED. Selected time: %d ms", GetTickCount() - selTimer); + break; + } + break; + } + + } + + } + + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); + + // add trace trailer + LogTrace(rAUTH_NT, 4, 0, 0, TRUE); + + DbpString("Emulator stopped."); }