From: marshmellow42 Date: Wed, 7 Oct 2015 13:34:47 +0000 (-0400) Subject: Merge remote-tracking branch 'Proxmark/master' into iclass X-Git-Tag: v2.3.0~22^2~1 X-Git-Url: http://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/commitdiff_plain/c54dff4f4ac42536ebd6faf32c7a76ebffdaadae?hp=4ff341efff10cad8e063a73d67e9dab25b0cdf0f Merge remote-tracking branch 'Proxmark/master' into iclass Conflicts: CHANGELOG.md --- diff --git a/CHANGELOG.md b/CHANGELOG.md index dffe9a81..c5ccc8f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,11 +13,19 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac - `hf iclass encryptblk` - to encrypt a data block hex to prep for writing that block (marshmellow) - ISO14443a stand-alone operation with ARM CFLAG="WITH_ISO14443a_StandAlone". This code can read & emulate two banks of 14a tag UIDs and write to "magic" cards (Craig Young) - AWID26 command context added as 'lf awid' containing realtime demodulation as well as cloning/simulation based on tag numbers (Craig Young) +- Added 'hw status'. This command makes the ARM print out some runtime information. (holiman) +- Added 'hw ping'. This command just sends a usb packets and checks if the pm3 is responsive. Can be used to abort certain operations which supports abort over usb. (holiman) +- Added `data hex2bin` and `data bin2hex` for command line conversion between binary and hexadecimal (holiman) ### Changed +<<<<<<< HEAD - changed `lf config t ` to be 0 - 128 and will trigger on + or - threshold value (marshmellow) - `hf iclass dump` cli options - can now dump AA1 and AA2 with different keys in one run (does not go to muliple pages for the larger tags yet) +======= +- Revised workflow for StandAloneMode14a (Craig Young) +>>>>>>> Proxmark/master - EPA functions (`hf epa`) now support both ISO 14443-A and 14443-B cards (frederikmoellers) +- 'hw version' only talks to ARM at startup, after that the info is cached. (pwpiwi) ## [2.2.0][2015-07-12] diff --git a/armsrc/BigBuf.c b/armsrc/BigBuf.c index 510f7bef..a938d5c6 100644 --- a/armsrc/BigBuf.c +++ b/armsrc/BigBuf.c @@ -88,6 +88,16 @@ void BigBuf_free_keep_EM(void) } } +void BigBuf_print_status(void) +{ + Dbprintf("Memory"); + Dbprintf(" BIGBUF_SIZE.............%d", BIGBUF_SIZE); + Dbprintf(" BigBuf_hi .............%d", BigBuf_hi); + Dbprintf("Tracing"); + Dbprintf(" tracing ................%d", tracing); + Dbprintf(" traceLen ...............%d", traceLen); +} + // return the maximum trace length (i.e. the unallocated size of BigBuf) uint16_t BigBuf_max_traceLen(void) diff --git a/armsrc/BigBuf.h b/armsrc/BigBuf.h index 0e2f1744..05b4180e 100644 --- a/armsrc/BigBuf.h +++ b/armsrc/BigBuf.h @@ -28,7 +28,7 @@ extern void BigBuf_Clear(void); extern uint8_t *BigBuf_malloc(uint16_t); extern void BigBuf_free(void); extern void BigBuf_free_keep_EM(void); - +extern void BigBuf_print_status(void); extern uint16_t BigBuf_get_traceLen(void); extern void clear_trace(); extern void set_tracing(bool enable); diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 994bfa6c..48c9caef 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -25,6 +25,7 @@ #include #include "lfsampling.h" #include "BigBuf.h" +#include "mifareutil.h" #ifdef WITH_LCD #include "LCD.h" #endif @@ -298,6 +299,52 @@ void SendVersion(void) cmd_send(CMD_ACK, *(AT91C_DBGU_CIDR), text_and_rodata_section_size + compressed_data_section_size, 0, VersionString, strlen(VersionString)); } +// measure the USB Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time. +// Note: this mimics GetFromBigbuf(), i.e. we have the overhead of the UsbCommand structure included. +void printUSBSpeed(void) +{ + Dbprintf("USB Speed:"); + Dbprintf(" Sending USB packets to client..."); + + #define USB_SPEED_TEST_MIN_TIME 1500 // in milliseconds + uint8_t *test_data = BigBuf_get_addr(); + uint32_t end_time; + + uint32_t start_time = end_time = GetTickCount(); + uint32_t bytes_transferred = 0; + + LED_B_ON(); + while(end_time < start_time + USB_SPEED_TEST_MIN_TIME) { + cmd_send(CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K, 0, USB_CMD_DATA_SIZE, 0, test_data, USB_CMD_DATA_SIZE); + end_time = GetTickCount(); + bytes_transferred += USB_CMD_DATA_SIZE; + } + LED_B_OFF(); + + Dbprintf(" Time elapsed: %dms", end_time - start_time); + Dbprintf(" Bytes transferred: %d", bytes_transferred); + Dbprintf(" USB Transfer Speed PM3 -> Client = %d Bytes/s", + 1000 * bytes_transferred / (end_time - start_time)); + +} + +/** + * Prints runtime information about the PM3. +**/ +void SendStatus(void) +{ + BigBuf_print_status(); + Fpga_print_status(); + printConfig(); //LF Sampling config + printUSBSpeed(); + Dbprintf("Various"); + Dbprintf(" MF_DBGLEVEL......%d", MF_DBGLEVEL); + Dbprintf(" ToSendMax........%d",ToSendMax); + Dbprintf(" ToSendBit........%d",ToSendBit); + + cmd_send(CMD_ACK,1,0,0,0,0); +} + #if defined(WITH_ISO14443a_StandAlone) || defined(WITH_LF) #define OPTS 2 @@ -329,11 +376,14 @@ void StandAloneMode14a() FpgaDownloadAndGo(FPGA_BITSTREAM_HF); int selected = 0; - int playing = 0; + int playing = 0, iGotoRecord = 0, iGotoClone = 0; int cardRead[OPTS] = {0}; uint8_t readUID[10] = {0}; uint32_t uid_1st[OPTS]={0}; uint32_t uid_2nd[OPTS]={0}; + uint32_t uid_tmp1 = 0; + uint32_t uid_tmp2 = 0; + iso14a_card_select_t hi14a_card[OPTS]; LED(selected + 1, 0); @@ -341,24 +391,17 @@ void StandAloneMode14a() { usb_poll(); WDT_HIT(); - - // Was our button held down or pressed? - int button_pressed = BUTTON_HELD(1000); SpinDelay(300); - // Button was held for a second, begin recording - if (button_pressed > 0 && cardRead[selected] == 0) + if (iGotoRecord == 1 || cardRead[selected] == 0) { + iGotoRecord = 0; LEDsoff(); LED(selected + 1, 0); LED(LED_RED2, 0); // record Dbprintf("Enabling iso14443a reader mode for [Bank: %u]...", selected); - - // wait for button to be released - while(BUTTON_PRESS()) - WDT_HIT(); /* need this delay to prevent catching some weird data */ SpinDelay(500); /* Code for reading from 14a tag */ @@ -369,22 +412,54 @@ void StandAloneMode14a() for ( ; ; ) { WDT_HIT(); - if (!iso14443a_select_card(uid, NULL, &cuid)) + if (BUTTON_PRESS()) { + if (cardRead[selected]) { + Dbprintf("Button press detected -- replaying card in bank[%d]", selected); + break; + } + else if (cardRead[(selected+1)%OPTS]) { + Dbprintf("Button press detected but no card in bank[%d] so playing from bank[%d]", selected, (selected+1)%OPTS); + selected = (selected+1)%OPTS; + break; // playing = 1; + } + else { + Dbprintf("Button press detected but no stored tag to play. (Ignoring button)"); + SpinDelay(300); + } + } + if (!iso14443a_select_card(uid, &hi14a_card[selected], &cuid)) continue; else { Dbprintf("Read UID:"); Dbhexdump(10,uid,0); memcpy(readUID,uid,10*sizeof(uint8_t)); - uint8_t *dst = (uint8_t *)&uid_1st[selected]; + uint8_t *dst = (uint8_t *)&uid_tmp1; // Set UID byte order for (int i=0; i<4; i++) dst[i] = uid[3-i]; - dst = (uint8_t *)&uid_2nd[selected]; + dst = (uint8_t *)&uid_tmp2; for (int i=0; i<4; i++) dst[i] = uid[7-i]; - break; + if (uid_1st[(selected+1)%OPTS] == uid_tmp1 && uid_2nd[(selected+1)%OPTS] == uid_tmp2) { + Dbprintf("Card selected has same UID as what is stored in the other bank. Skipping."); + } + else { + if (uid_tmp2) { + Dbprintf("Bank[%d] received a 7-byte UID",selected); + uid_1st[selected] = (uid_tmp1)>>8; + uid_2nd[selected] = (uid_tmp1<<24) + (uid_tmp2>>8); + } + else { + Dbprintf("Bank[%d] received a 4-byte UID",selected); + uid_1st[selected] = uid_tmp1; + uid_2nd[selected] = uid_tmp2; + } + break; + } } } + Dbprintf("ATQA = %02X%02X",hi14a_card[selected].atqa[0],hi14a_card[selected].atqa[1]); + Dbprintf("SAK = %02X",hi14a_card[selected].sak); LEDsoff(); LED(LED_GREEN, 200); LED(LED_ORANGE, 200); @@ -393,101 +468,101 @@ void StandAloneMode14a() LEDsoff(); LED(selected + 1, 0); - // Finished recording - // If we were previously playing, set playing off - // so next button push begins playing what we recorded - playing = 0; + // Next state is replay: + playing = 1; cardRead[selected] = 1; - } - /* MF UID clone */ - else if (button_pressed > 0 && cardRead[selected] == 1) + /* MF Classic UID clone */ + else if (iGotoClone==1) { - LEDsoff(); - LED(selected + 1, 0); - LED(LED_ORANGE, 250); - + iGotoClone=0; + LEDsoff(); + LED(selected + 1, 0); + LED(LED_ORANGE, 250); - // record - Dbprintf("Preparing to Clone card [Bank: %x]; uid: %08x", selected, uid_1st[selected]); - // wait for button to be released - while(BUTTON_PRESS()) - { - // Delay cloning until card is in place - WDT_HIT(); - } - Dbprintf("Starting clone. [Bank: %u]", selected); - // need this delay to prevent catching some weird data - SpinDelay(500); - // Begin clone function here: - /* Example from client/mifarehost.c for commanding a block write for "magic Chinese" cards: - UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}}; - memcpy(c.d.asBytes, data, 16); - SendCommand(&c); - - Block read is similar: - UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}}; - We need to imitate that call with blockNo 0 to set a uid. - - The get and set commands are handled in this file: - // Work with "magic Chinese" card - case CMD_MIFARE_CSETBLOCK: - MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - break; - case CMD_MIFARE_CGETBLOCK: - MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); - // - break; - - mfCSetUID provides example logic for UID set workflow: - -Read block0 from card in field with MifareCGetBlock() - -Configure new values without replacing reserved bytes - memcpy(block0, uid, 4); // Copy UID bytes from byte array - // Mifare UID BCC - block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5 - Bytes 5-7 are reserved SAK and ATQA for mifare classic - -Use mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER) to write it - */ - uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}, testBlock0[16] = {0}; - // arg0 = Flags == CSETBLOCK_SINGLE_OPER=0x1F, arg1=returnSlot, arg2=blockNo - MifareCGetBlock(0x1F, 1, 0, oldBlock0); - Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0],oldBlock0[1],oldBlock0[2],oldBlock0[3]); - memcpy(newBlock0,oldBlock0,16); - // Copy uid_1st for bank (2nd is for longer UIDs not supported if classic) - - newBlock0[0] = uid_1st[selected]>>24; - newBlock0[1] = 0xFF & (uid_1st[selected]>>16); - newBlock0[2] = 0xFF & (uid_1st[selected]>>8); - newBlock0[3] = 0xFF & (uid_1st[selected]); - newBlock0[4] = newBlock0[0]^newBlock0[1]^newBlock0[2]^newBlock0[3]; - // arg0 = needWipe, arg1 = workFlags, arg2 = blockNo, datain - MifareCSetBlock(0, 0xFF,0, newBlock0); - MifareCGetBlock(0x1F, 1, 0, testBlock0); - if (memcmp(testBlock0,newBlock0,16)==0) - { - DbpString("Cloned successfull!"); - cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it - } - LEDsoff(); - LED(selected + 1, 0); - // Finished recording + // record + Dbprintf("Preparing to Clone card [Bank: %x]; uid: %08x", selected, uid_1st[selected]); - // If we were previously playing, set playing off - // so next button push begins playing what we recorded + // wait for button to be released + while(BUTTON_PRESS()) + { + // Delay cloning until card is in place + WDT_HIT(); + } + Dbprintf("Starting clone. [Bank: %u]", selected); + // need this delay to prevent catching some weird data + SpinDelay(500); + // Begin clone function here: + /* Example from client/mifarehost.c for commanding a block write for "magic Chinese" cards: + UsbCommand c = {CMD_MIFARE_CSETBLOCK, {wantWipe, params & (0xFE | (uid == NULL ? 0:1)), blockNo}}; + memcpy(c.d.asBytes, data, 16); + SendCommand(&c); + + Block read is similar: + UsbCommand c = {CMD_MIFARE_CGETBLOCK, {params, 0, blockNo}}; + We need to imitate that call with blockNo 0 to set a uid. + + The get and set commands are handled in this file: + // Work with "magic Chinese" card + case CMD_MIFARE_CSETBLOCK: + MifareCSetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; + case CMD_MIFARE_CGETBLOCK: + MifareCGetBlock(c->arg[0], c->arg[1], c->arg[2], c->d.asBytes); + break; + + mfCSetUID provides example logic for UID set workflow: + -Read block0 from card in field with MifareCGetBlock() + -Configure new values without replacing reserved bytes + memcpy(block0, uid, 4); // Copy UID bytes from byte array + // Mifare UID BCC + block0[4] = block0[0]^block0[1]^block0[2]^block0[3]; // BCC on byte 5 + Bytes 5-7 are reserved SAK and ATQA for mifare classic + -Use mfCSetBlock(0, block0, oldUID, wantWipe, CSETBLOCK_SINGLE_OPER) to write it + */ + uint8_t oldBlock0[16] = {0}, newBlock0[16] = {0}, testBlock0[16] = {0}; + // arg0 = Flags == CSETBLOCK_SINGLE_OPER=0x1F, arg1=returnSlot, arg2=blockNo + MifareCGetBlock(0x3F, 1, 0, oldBlock0); + if (oldBlock0[0] == 0 && oldBlock0[0] == oldBlock0[1] && oldBlock0[1] == oldBlock0[2] && oldBlock0[2] == oldBlock0[3]) { + Dbprintf("No changeable tag detected. Returning to replay mode for bank[%d]", selected); + playing = 1; + } + else { + Dbprintf("UID from target tag: %02X%02X%02X%02X", oldBlock0[0],oldBlock0[1],oldBlock0[2],oldBlock0[3]); + memcpy(newBlock0,oldBlock0,16); + // Copy uid_1st for bank (2nd is for longer UIDs not supported if classic) + + newBlock0[0] = uid_1st[selected]>>24; + newBlock0[1] = 0xFF & (uid_1st[selected]>>16); + newBlock0[2] = 0xFF & (uid_1st[selected]>>8); + newBlock0[3] = 0xFF & (uid_1st[selected]); + newBlock0[4] = newBlock0[0]^newBlock0[1]^newBlock0[2]^newBlock0[3]; + // arg0 = needWipe, arg1 = workFlags, arg2 = blockNo, datain + MifareCSetBlock(0, 0xFF,0, newBlock0); + MifareCGetBlock(0x3F, 1, 0, testBlock0); + if (memcmp(testBlock0,newBlock0,16)==0) + { + DbpString("Cloned successfull!"); + cardRead[selected] = 0; // Only if the card was cloned successfully should we clear it playing = 0; + iGotoRecord = 1; + selected = (selected+1) % OPTS; + } + else { + Dbprintf("Clone failed. Back to replay mode on bank[%d]", selected); + playing = 1; + } + } + LEDsoff(); + LED(selected + 1, 0); } // Change where to record (or begin playing) - else if (button_pressed && cardRead[selected]) + else if (playing==1) // button_pressed == BUTTON_SINGLE_CLICK && cardRead[selected]) { - // Next option if we were previously playing - if (playing) - selected = (selected + 1) % OPTS; - playing = !playing; - LEDsoff(); LED(selected + 1, 0); @@ -496,19 +571,45 @@ void StandAloneMode14a() { LED(LED_GREEN, 0); DbpString("Playing"); - while (!BUTTON_HELD(500)) { // Loop simulating tag until the button is held a half-sec + for ( ; ; ) { + WDT_HIT(); + int button_action = BUTTON_HELD(1000); + if (button_action == 0) { // No button action, proceed with sim + uint8_t data[512] = {0}; // in case there is a read command received we shouldn't break Dbprintf("Simulating ISO14443a tag with uid[0]: %08x, uid[1]: %08x [Bank: %u]", uid_1st[selected],uid_2nd[selected],selected); - SimulateIso14443aTag(1,uid_1st[selected],uid_2nd[selected],NULL); + if (hi14a_card[selected].sak == 8 && hi14a_card[selected].atqa[0] == 4 && hi14a_card[selected].atqa[1] == 0) { + DbpString("Mifare Classic"); + SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data); // Mifare Classic + } + else if (hi14a_card[selected].sak == 0 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 0) { + DbpString("Mifare Ultralight"); + SimulateIso14443aTag(2,uid_1st[selected],uid_2nd[selected],data); // Mifare Ultralight + } + else if (hi14a_card[selected].sak == 20 && hi14a_card[selected].atqa[0] == 0x44 && hi14a_card[selected].atqa[1] == 3) { + DbpString("Mifare DESFire"); + SimulateIso14443aTag(3,uid_1st[selected],uid_2nd[selected],data); // Mifare DESFire + } + else { + Dbprintf("Unrecognized tag type -- defaulting to Mifare Classic emulation"); + SimulateIso14443aTag(1,uid_1st[selected], uid_2nd[selected], data); + } + } + else if (button_action == BUTTON_SINGLE_CLICK) { + selected = (selected + 1) % OPTS; + Dbprintf("Done playing. Switching to record mode on bank %d",selected); + iGotoRecord = 1; + break; } - //cardRead[selected] = 1; - Dbprintf("Done playing [Bank: %u]",selected); + else if (button_action == BUTTON_HOLD) { + Dbprintf("Playtime over. Begin cloning..."); + iGotoClone = 1; + break; + } + WDT_HIT(); + } /* We pressed a button so ignore it here with a delay */ SpinDelay(300); - - // when done, we're done playing, move to next option - selected = (selected + 1) % OPTS; - playing = !playing; LEDsoff(); LED(selected + 1, 0); } @@ -886,6 +987,9 @@ void UsbPacketReceived(uint8_t *packet, int len) ReadPCF7931(); cmd_send(CMD_ACK,0,0,0,0,0); break; + case CMD_PCF7931_WRITE: + WritePCF7931(c->d.asDwords[0],c->d.asDwords[1],c->d.asDwords[2],c->d.asDwords[3],c->d.asDwords[4],c->d.asDwords[5],c->d.asDwords[6], c->d.asDwords[9], c->d.asDwords[7]-128,c->d.asDwords[8]-128, c->arg[0], c->arg[1], c->arg[2]); + break; case CMD_EM4X_READ_WORD: EM4xReadWord(c->arg[1], c->arg[2],c->d.asBytes[0]); break; @@ -1161,7 +1265,12 @@ void UsbPacketReceived(uint8_t *packet, int len) case CMD_VERSION: SendVersion(); break; - + case CMD_STATUS: + SendStatus(); + break; + case CMD_PING: + cmd_send(CMD_ACK,0,0,0,0,0); + break; #ifdef WITH_LCD case CMD_LCD_RESET: LCDReset(); diff --git a/armsrc/apps.h b/armsrc/apps.h index 63b2edc5..79c9da86 100644 --- a/armsrc/apps.h +++ b/armsrc/apps.h @@ -61,6 +61,7 @@ void AcquireRawAdcSamples125k(int divisor); void ModThenAcquireRawAdcSamples125k(int delay_off,int period_0,int period_1,uint8_t *command); void ReadTItag(void); void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc); + void AcquireTiType(void); void AcquireRawBitsTI(void); void SimulateTagLowFrequency(int period, int gap, int ledcontrol); @@ -85,6 +86,11 @@ int DemodPCF7931(uint8_t **outBlocks); int IsBlock0PCF7931(uint8_t *Block); int IsBlock1PCF7931(uint8_t *Block); void ReadPCF7931(); +void SendCmdPCF7931(uint32_t * tab); +bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p); +bool AddBitPCF7931(bool b, uint32_t * tab, int32_t l, int32_t p); +bool AddPatternPCF7931(uint32_t a, uint32_t b, uint32_t c, uint32_t * tab); +void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data); void EM4xReadWord(uint8_t Address, uint32_t Pwd, uint8_t PwdMode); void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode); diff --git a/armsrc/fpgaloader.c b/armsrc/fpgaloader.c index 16fed7c5..308dda8c 100644 --- a/armsrc/fpgaloader.c +++ b/armsrc/fpgaloader.c @@ -558,3 +558,11 @@ void SetAdcMuxFor(uint32_t whichGpio) HIGH(whichGpio); } + +void Fpga_print_status(void) +{ + Dbprintf("Fgpa"); + if(downloaded_bitstream == FPGA_BITSTREAM_HF) Dbprintf(" mode.............HF"); + else if(downloaded_bitstream == FPGA_BITSTREAM_LF) Dbprintf(" mode.............LF"); + else Dbprintf(" mode.............%d", downloaded_bitstream); +} diff --git a/armsrc/fpgaloader.h b/armsrc/fpgaloader.h index 0bad3809..52d6c677 100644 --- a/armsrc/fpgaloader.h +++ b/armsrc/fpgaloader.h @@ -17,6 +17,7 @@ void FpgaGatherVersion(int bitstream_version, char *dst, int len); void FpgaSetupSsc(void); void SetupSpi(int mode); bool FpgaSetupSscDma(uint8_t *buf, int len); +void Fpga_print_status(); #define FpgaDisableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTDIS; #define FpgaEnableSscDma(void) AT91C_BASE_PDC_SSC->PDC_PTCR = AT91C_PDC_RXTEN; void SetAdcMuxFor(uint32_t whichGpio); diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 5c7367a1..0431876e 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -1063,7 +1063,6 @@ void SimulateIso14443aTag(int tagType, int uid_1st, int uid_2nd, byte_t* data) LED_A_ON(); for(;;) { // Clean receive command buffer - if(!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) { DbpString("Button press"); break; @@ -2017,6 +2016,7 @@ void ReaderMifare(bool first_try) byte_t par_list[8] = {0x00}; byte_t ks_list[8] = {0x00}; + #define PRNG_SEQUENCE_LENGTH (1 << 16); static uint32_t sync_time; static uint32_t sync_cycles; int catch_up_cycles = 0; @@ -2027,7 +2027,7 @@ void ReaderMifare(bool first_try) if (first_try) { mf_nr_ar3 = 0; sync_time = GetCountSspClk() & 0xfffffff8; - sync_cycles = 65536; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the nonces). + sync_cycles = PRNG_SEQUENCE_LENGTH; // theory: Mifare Classic's random generator repeats every 2^16 cycles (and so do the tag nonces). nt_attacked = 0; nt = 0; par[0] = 0; @@ -2044,8 +2044,12 @@ void ReaderMifare(bool first_try) LED_C_OFF(); - #define DARKSIDE_MAX_TRIES 32 // number of tries to sync on PRNG cycle. Then give up. - uint16_t unsuccessfull_tries = 0; + #define MAX_UNEXPECTED_RANDOM 4 // maximum number of unexpected (i.e. real) random numbers when trying to sync. Then give up. + #define MAX_SYNC_TRIES 16 + uint16_t unexpected_random = 0; + uint16_t sync_tries = 0; + int16_t debug_info_nr = -1; + uint32_t debug_info[MAX_SYNC_TRIES]; for(uint16_t i = 0; TRUE; i++) { @@ -2063,16 +2067,20 @@ void ReaderMifare(bool first_try) continue; } - sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles; - catch_up_cycles = 0; + if (debug_info_nr == -1) { + sync_time = (sync_time & 0xfffffff8) + sync_cycles + catch_up_cycles; + catch_up_cycles = 0; - // if we missed the sync time already, advance to the next nonce repeat - while(GetCountSspClk() > sync_time) { - sync_time = (sync_time & 0xfffffff8) + sync_cycles; - } + // if we missed the sync time already, advance to the next nonce repeat + while(GetCountSspClk() > sync_time) { + sync_time = (sync_time & 0xfffffff8) + sync_cycles; + } - // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) - ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); + // Transmit MIFARE_CLASSIC_AUTH at synctime. Should result in returning the same tag nonce (== nt_attacked) + ReaderTransmit(mf_auth, sizeof(mf_auth), &sync_time); + } else { + ReaderTransmit(mf_auth, sizeof(mf_auth), NULL); + } // Receive the (4 Byte) "random" nonce if (!ReaderReceive(receivedAnswer, receivedAnswerPar)) { @@ -2090,19 +2098,32 @@ void ReaderMifare(bool first_try) int nt_distance = dist_nt(previous_nt, nt); if (nt_distance == 0) { nt_attacked = nt; - } - else { + } else { if (nt_distance == -99999) { // invalid nonce received - unsuccessfull_tries++; - if (!nt_attacked && unsuccessfull_tries > DARKSIDE_MAX_TRIES) { + unexpected_random++; + if (!nt_attacked && unexpected_random > MAX_UNEXPECTED_RANDOM) { isOK = -3; // Card has an unpredictable PRNG. Give up break; } else { continue; // continue trying... } } + if (++sync_tries > MAX_SYNC_TRIES) { + if (sync_tries > 2 * MAX_SYNC_TRIES) { + isOK = -4; // Card's PRNG runs at an unexpected frequency or resets unexpectedly + break; + } else { // continue for a while, just to collect some debug info + debug_info[++debug_info_nr] = nt_distance; + continue; + } + } sync_cycles = (sync_cycles - nt_distance); - if (MF_DBGLEVEL >= 3) Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles); + if (sync_cycles <= 0) { + sync_cycles += PRNG_SEQUENCE_LENGTH; + } + if (MF_DBGLEVEL >= 3) { + Dbprintf("calibrating in cycle %d. nt_distance=%d, Sync_cycles: %d\n", i, nt_distance, sync_cycles); + } continue; } } @@ -2173,6 +2194,14 @@ void ReaderMifare(bool first_try) mf_nr_ar[3] &= 0x1F; + + if (isOK == -4) { + if (MF_DBGLEVEL >= 3) { + for(uint16_t i = 0; i < MAX_SYNC_TRIES; i++) { + Dbprintf("collected debug info[%d] = %d\n", i, debug_info[i]); + } + } + } byte_t buf[28]; memcpy(buf + 0, uid, 4); diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 733bc953..d7f91c53 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -16,8 +16,7 @@ #include "string.h" #include "lfdemod.h" #include "lfsampling.h" -#include "usb_cdc.h" - +#include "usb_cdc.h" //test /** * Function to do a modulation and then get samples. @@ -214,6 +213,8 @@ void ReadTItag(void) } } + + void WriteTIbyte(uint8_t b) { int i = 0; @@ -310,11 +311,16 @@ void AcquireTiType(void) } } + + + // arguments: 64bit data split into 32bit idhi:idlo and optional 16bit crc // if crc provided, it will be written with the data verbatim (even if bogus) // if not provided a valid crc will be computed from the data and written. void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc) { + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); if(crc == 0) { crc = update_crc16(crc, (idlo)&0xff); @@ -1705,6 +1711,8 @@ int DemodPCF7931(uint8_t **outBlocks) { if(num_blocks == 4) break; } memcpy(outBlocks, Blocks, 16*num_blocks); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + return num_blocks; } @@ -1828,14 +1836,15 @@ void ReadPCF7931() { Dbprintf("Memory content:"); Dbprintf("-----------------------------------------"); for(i=0; i", i); } Dbprintf("-----------------------------------------"); + return ; } @@ -2058,3 +2067,261 @@ void EM4xWriteWord(uint32_t Data, uint8_t Address, uint32_t Pwd, uint8_t PwdMode FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); // field off LED_D_OFF(); } + + +#define T0_PCF 8 //period for the pcf7931 in us + +/* Write on a byte of a PCF7931 tag + * @param address : address of the block to write + @param byte : address of the byte to write + @param data : data to write + */ +void WritePCF7931(uint8_t pass1, uint8_t pass2, uint8_t pass3, uint8_t pass4, uint8_t pass5, uint8_t pass6, uint8_t pass7, uint16_t init_delay, int32_t l, int32_t p, uint8_t address, uint8_t byte, uint8_t data) +{ + + uint32_t tab[1024]={0}; // data times frame + uint32_t u = 0; + uint8_t parity = 0; + bool comp = 0; + + + //BUILD OF THE DATA FRAME + + //alimentation of the tag (time for initializing) + AddPatternPCF7931(init_delay, 0, 8192/2*T0_PCF, tab); + + //PMC + Dbprintf("Initialization delay : %d us", init_delay); + AddPatternPCF7931(8192/2*T0_PCF + 319*T0_PCF+70, 3*T0_PCF, 29*T0_PCF, tab); + + Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p); + + //password indication bit + AddBitPCF7931(1, tab, l, p); + + + //password (on 56 bits) + Dbprintf("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", pass1,pass2,pass3,pass4,pass5,pass6,pass7); + AddBytePCF7931(pass1, tab, l, p); + AddBytePCF7931(pass2, tab, l, p); + AddBytePCF7931(pass3, tab, l, p); + AddBytePCF7931(pass4, tab, l, p); + AddBytePCF7931(pass5, tab, l, p); + AddBytePCF7931(pass6, tab, l, p); + AddBytePCF7931(pass7, tab, l, p); + + + //programming mode (0 or 1) + AddBitPCF7931(0, tab, l, p); + + //block adress on 6 bits + Dbprintf("Block address : %02x", address); + for (u=0; u<6; u++) + { + if (address&(1< 0xFFFF){ + tab[u] -= 0xFFFF; + comp = 0; + } + } + } + + SendCmdPCF7931(tab); +} + + + +/* Send a trame to a PCF7931 tags + * @param tab : array of the data frame + */ + +void SendCmdPCF7931(uint32_t * tab){ + uint16_t u=0; + uint16_t tempo=0; + + Dbprintf("SENDING DATA FRAME..."); + + FpgaDownloadAndGo(FPGA_BITSTREAM_LF); + + FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz + + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU ); + + LED_A_ON(); + + // steal this pin from the SSP and use it to control the modulation + AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT; + AT91C_BASE_PIOA->PIO_OER = GPIO_SSC_DOUT; + + //initialization of the timer + AT91C_BASE_PMC->PMC_PCER |= (0x1 << 12) | (0x1 << 13) | (0x1 << 14); + AT91C_BASE_TCB->TCB_BMR = AT91C_TCB_TC0XC0S_NONE | AT91C_TCB_TC1XC1S_TIOA0 | AT91C_TCB_TC2XC2S_NONE; + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable + AT91C_BASE_TC0->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK; //clock at 48/32 MHz + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKEN; + AT91C_BASE_TCB->TCB_BCR = 1; + + + tempo = AT91C_BASE_TC0->TC_CV; + for(u=0;tab[u]!= 0;u+=3){ + + + // modulate antenna + HIGH(GPIO_SSC_DOUT); + while(tempo != tab[u]){ + tempo = AT91C_BASE_TC0->TC_CV; + } + + // stop modulating antenna + LOW(GPIO_SSC_DOUT); + while(tempo != tab[u+1]){ + tempo = AT91C_BASE_TC0->TC_CV; + } + + + // modulate antenna + HIGH(GPIO_SSC_DOUT); + while(tempo != tab[u+2]){ + tempo = AT91C_BASE_TC0->TC_CV; + } + + + } + + LED_A_OFF(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(200); + + + AT91C_BASE_TC0->TC_CCR = AT91C_TC_CLKDIS; // timer disable + DbpString("FINISH !"); + DbpString("(Could be usefull to send the same trame many times)"); + LED(0xFFFF, 1000); +} + + +/* Add a byte for building the data frame of PCF7931 tags + * @param b : byte to add + * @param tab : array of the data frame + * @param l : offset on low pulse width + * @param p : offset on low pulse positioning + */ + +bool AddBytePCF7931(uint8_t byte, uint32_t * tab, int32_t l, int32_t p){ + + uint32_t u; + for (u=0; u<8; u++) + { + if (byte&(1<RTTC_RTMR = AT91C_RTTC_RTTRST + 0x001D; // was 0x003B + // This timer is based on the slow clock. The slow clock frequency is between 22kHz and 40kHz. + // We can determine the actual slow clock frequency by looking at the Main Clock Frequency Register. + uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & 0xffff; // = 16 * main clock frequency (16MHz) / slow clock frequency + // set RealTimeCounter divider to count at 1kHz: + AT91C_BASE_RTTC->RTTC_RTMR = AT91C_RTTC_RTTRST | ((256000 + (mainf/2)) / mainf); + // note: worst case precision is approx 2.5% } /* diff --git a/client/cmddata.c b/client/cmddata.c index cb1c7cd4..22da1805 100644 --- a/client/cmddata.c +++ b/client/cmddata.c @@ -24,6 +24,7 @@ #include "usb_cmd.h" #include "crc.h" #include "crc16.h" +#include "loclass/cipherutils.h" uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; uint8_t g_debugMode=0; @@ -1943,26 +1944,14 @@ int CmdHpf(const char *Cmd) RepaintGraphWindow(); return 0; } -typedef struct { - uint8_t * buffer; - uint32_t numbits; - uint32_t position; -}BitstreamOut; -bool _headBit( BitstreamOut *stream) -{ - int bytepos = stream->position >> 3; // divide by 8 - int bitpos = (stream->position++) & 7; // mask out 00000111 - return (*(stream->buffer + bytepos) >> (7-bitpos)) & 1; -} - -uint8_t getByte(uint8_t bits_per_sample, BitstreamOut* b) +uint8_t getByte(uint8_t bits_per_sample, BitstreamIn* b) { int i; uint8_t val = 0; for(i =0 ; i < bits_per_sample; i++) { - val |= (_headBit(b) << (7-i)); + val |= (headBit(b) << (7-i)); } return val; } @@ -2002,7 +1991,7 @@ int getSamples(const char *Cmd, bool silent) if(bits_per_sample < 8) { PrintAndLog("Unpacking..."); - BitstreamOut bout = { got, bits_per_sample * n, 0}; + BitstreamIn bout = { got, bits_per_sample * n, 0}; int j =0; for (j = 0; j * bits_per_sample < n * 8 && j < n; j++) { uint8_t sample = getByte(bits_per_sample, &bout); @@ -2265,6 +2254,99 @@ int CmdZerocrossings(const char *Cmd) return 0; } +int usage_data_bin2hex(){ + PrintAndLog("Usage: data bin2hex "); + PrintAndLog(" This function will ignore all characters not 1 or 0 (but stop reading on whitespace)"); + return 0; +} + +/** + * @brief Utility for conversion via cmdline. + * @param Cmd + * @return + */ +int Cmdbin2hex(const char *Cmd) +{ + int bg =0, en =0; + if(param_getptr(Cmd, &bg, &en, 0)) + { + return usage_data_bin2hex(); + } + //Number of digits supplied as argument + size_t length = en - bg +1; + size_t bytelen = (length+7) / 8; + uint8_t* arr = (uint8_t *) malloc(bytelen); + memset(arr, 0, bytelen); + BitstreamOut bout = { arr, 0, 0 }; + + for(; bg <= en ;bg++) + { + char c = Cmd[bg]; + if( c == '1') pushBit(&bout, 1); + else if( c == '0') pushBit(&bout, 0); + else PrintAndLog("Ignoring '%c'", c); + } + + if(bout.numbits % 8 != 0) + { + printf("[padded with %d zeroes]\n", 8-(bout.numbits % 8)); + } + + //Uses printf instead of PrintAndLog since the latter + // adds linebreaks to each printout - this way was more convenient since we don't have to + // allocate a string and write to that first... + for(size_t x = 0; x < bytelen ; x++) + { + printf("%02X", arr[x]); + } + printf("\n"); + free(arr); + return 0; +} + +int usage_data_hex2bin(){ + + PrintAndLog("Usage: data bin2hex "); + PrintAndLog(" This function will ignore all non-hexadecimal characters (but stop reading on whitespace)"); + return 0; + +} + +int Cmdhex2bin(const char *Cmd) +{ + int bg =0, en =0; + if(param_getptr(Cmd, &bg, &en, 0)) + { + return usage_data_hex2bin(); + } + + + while(bg <= en ) + { + char x = Cmd[bg++]; + // capitalize + if (x >= 'a' && x <= 'f') + x -= 32; + // convert to numeric value + if (x >= '0' && x <= '9') + x -= '0'; + else if (x >= 'A' && x <= 'F') + x -= 'A' - 10; + else + continue; + + //Uses printf instead of PrintAndLog since the latter + // adds linebreaks to each printout - this way was more convenient since we don't have to + // allocate a string and write to that first... + + for(int i= 0 ; i < 4 ; ++i) + printf("%d",(x >> (3 - i)) & 1); + } + printf("\n"); + + return 0; +} + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, @@ -2273,6 +2355,7 @@ static command_t CommandTable[] = {"askgproxiidemod", CmdG_Prox_II_Demod, 1, "Demodulate a G Prox II tag from GraphBuffer"}, {"autocorr", CmdAutoCorr, 1, "[window length] [g] -- Autocorrelation over window - g to save back to GraphBuffer (overwrite)"}, {"biphaserawdecode",CmdBiphaseDecodeRaw,1, "[offset] [invert<0|1>] [maxErr] -- Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)"}, + {"bin2hex", Cmdbin2hex, 1, "bin2hex -- Converts binary to hexadecimal"}, {"bitsamples", CmdBitsamples, 0, "Get raw samples as bitstring"}, {"buffclear", CmdBuffClear, 1, "Clear sample buffer and graph window"}, {"dec", CmdDec, 1, "Decimate samples"}, @@ -2287,6 +2370,7 @@ static command_t CommandTable[] = {"getbitstream", CmdGetBitStream, 1, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"}, {"grid", CmdGrid, 1, " -- overlay grid on graph window, use zero value to turn off either"}, {"hexsamples", CmdHexsamples, 0, " [] -- Dump big buffer as hex bytes"}, + {"hex2bin", Cmdhex2bin, 1, "hex2bin -- Converts hexadecimal to binary"}, {"hide", CmdHide, 1, "Hide graph window"}, {"hpf", CmdHpf, 1, "Remove DC offset from trace"}, {"load", CmdLoad, 1, " -- Load trace (to graph window"}, diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index c4a0aeeb..304e9c9c 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -58,6 +58,7 @@ start: case -1 : PrintAndLog("Button pressed. Aborted.\n"); break; case -2 : PrintAndLog("Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests).\n"); break; case -3 : PrintAndLog("Card is not vulnerable to Darkside attack (its random number generator is not predictable).\n"); break; + case -4 : PrintAndLog("The card's random number generator is vulnerable but behaves somewhat weird (Mifare clone?). This needs to be fixed.\n"); break; default: ; } break; diff --git a/client/cmdhw.c b/client/cmdhw.c index 2b6f9518..33dc78ae 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -18,6 +18,7 @@ #include "cmdhw.h" #include "cmdmain.h" #include "cmddata.h" +#include "data.h" /* low-level hardware control */ @@ -405,33 +406,72 @@ int CmdTune(const char *Cmd) int CmdVersion(const char *Cmd) { + clearCommandBuffer(); UsbCommand c = {CMD_VERSION}; - UsbCommand resp = {0, {0, 0, 0}}; + static UsbCommand resp = {0, {0, 0, 0}}; - SendCommand(&c); - if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + if (resp.arg[0] == 0 && resp.arg[1] == 0) { // no cached information available + SendCommand(&c); + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + PrintAndLog("Prox/RFID mark3 RFID instrument"); + PrintAndLog((char*)resp.d.asBytes); + lookupChipID(resp.arg[0], resp.arg[1]); + } + } else { + PrintAndLog("[[[ Cached information ]]]\n"); PrintAndLog("Prox/RFID mark3 RFID instrument"); PrintAndLog((char*)resp.d.asBytes); lookupChipID(resp.arg[0], resp.arg[1]); + PrintAndLog(""); + } + return 0; +} + +int CmdStatus(const char *Cmd) +{ + uint8_t speed_test_buffer[USB_CMD_DATA_SIZE]; + sample_buf = speed_test_buffer; + + clearCommandBuffer(); + UsbCommand c = {CMD_STATUS}; + SendCommand(&c); + if (!WaitForResponseTimeout(CMD_ACK,&c,1900)) { + PrintAndLog("Status command failed. USB Speed Test timed out"); } + return 0; +} + +int CmdPing(const char *Cmd) +{ + clearCommandBuffer(); + UsbCommand resp; + UsbCommand c = {CMD_PING}; + SendCommand(&c); + if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) { + PrintAndLog("Ping successfull"); + }else{ + PrintAndLog("Ping failed"); + } return 0; } static command_t CommandTable[] = { - {"help", CmdHelp, 1, "This help"}, - {"detectreader", CmdDetectReader,0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"}, - {"fpgaoff", CmdFPGAOff, 0, "Set FPGA off"}, - {"lcd", CmdLCD, 0, " -- Send command/data to LCD"}, - {"lcdreset", CmdLCDReset, 0, "Hardware reset LCD"}, - {"readmem", CmdReadmem, 0, "[address] -- Read memory at decimal address from flash"}, - {"reset", CmdReset, 0, "Reset the Proxmark3"}, - {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"}, - {"setmux", CmdSetMux, 0, " -- Set the ADC mux to a specific value"}, - {"tune", CmdTune, 0, "Measure antenna tuning"}, - {"version", CmdVersion, 0, "Show version information about the connected Proxmark"}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, 1, "This help"}, + {"detectreader", CmdDetectReader,0, "['l'|'h'] -- Detect external reader field (option 'l' or 'h' to limit to LF or HF)"}, + {"fpgaoff", CmdFPGAOff, 0, "Set FPGA off"}, + {"lcd", CmdLCD, 0, " -- Send command/data to LCD"}, + {"lcdreset", CmdLCDReset, 0, "Hardware reset LCD"}, + {"readmem", CmdReadmem, 0, "[address] -- Read memory at decimal address from flash"}, + {"reset", CmdReset, 0, "Reset the Proxmark3"}, + {"setlfdivisor", CmdSetDivisor, 0, "<19 - 255> -- Drive LF antenna at 12Mhz/(divisor+1)"}, + {"setmux", CmdSetMux, 0, " -- Set the ADC mux to a specific value"}, + {"tune", CmdTune, 0, "Measure antenna tuning"}, + {"version", CmdVersion, 0, "Show version information about the connected Proxmark"}, + {"status", CmdStatus, 0, "Show runtime status information about the connected Proxmark"}, + {"ping", CmdPing, 0, "Test if the pm3 is responsive"}, + {NULL, NULL, 0, NULL} }; int CmdHW(const char *Cmd) diff --git a/client/cmdlfpcf7931.c b/client/cmdlfpcf7931.c index 0d8fb93d..b1e1ae9e 100644 --- a/client/cmdlfpcf7931.c +++ b/client/cmdlfpcf7931.c @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2012 Chalk -// +// 2015 Dake + // 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. @@ -21,6 +22,8 @@ static int CmdHelp(const char *Cmd); +struct pcf7931_config configPcf = {{0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF},17500,{0,0}}; + int CmdLFPCF7931Read(const char *Cmd) { UsbCommand c = {CMD_PCF7931_READ}; @@ -30,10 +33,93 @@ int CmdLFPCF7931Read(const char *Cmd) return 0; } +int CmdLFPCF7931Config(const char *Cmd) +{ + int res = 0; + res = sscanf(Cmd, "%02x %02x %02x %02x %02x %02x %02x %d %d %d", &configPcf.password[0], &configPcf.password[1], &configPcf.password[2], &configPcf.password[3], &configPcf.password[4], &configPcf.password[5], &configPcf.password[6], &configPcf.init_delay, &configPcf.offset[0], &configPcf.offset[1]); + + if (res >= 7 || res < 1){ + if(res == 7) configPcf.init_delay = 17500; //default value + + if(res<=8){ + configPcf.offset[0] = 0; //default value + configPcf.offset[1] = 0; //default value + } + + if(res < 1){ + PrintAndLog("Usage: [...] "); + PrintAndLog("The time offsets could be usefull to correct slew rate generated by the antenna."); + } + + PrintAndLog("Current configuration :"); + PrintAndLog("Password (LSB first on each byte) : %02x %02x %02x %02x %02x %02x %02x", configPcf.password[0], configPcf.password[1], configPcf.password[2], configPcf.password[3], configPcf.password[4], configPcf.password[5], configPcf.password[6]); + PrintAndLog("Tag initialization delay : %d us", configPcf.init_delay); + PrintAndLog("Offsets : %d us on the low pulses width, %d us on the low pulses positions", configPcf.offset[0], configPcf.offset[1]); + + return 0; + } + + //default values + configPcf.password[0] = 0xFF; + configPcf.password[1] = 0xFF; + configPcf.password[2] = 0xFF; + configPcf.password[3] = 0xFF; + configPcf.password[4] = 0xFF; + configPcf.password[5] = 0xFF; + configPcf.password[6] = 0xFF; + + configPcf.init_delay = 17500; + configPcf.offset[0] = 0; + configPcf.offset[1] = 0; + + PrintAndLog("Incorrect format"); + PrintAndLog("Examples of right usage : lf pcf7931 config 11 22 33 44 55 66 77 20000"); + PrintAndLog(" lf pcf7931 config FF FF FF FF FF FF FF 17500 -10 30"); + return 0; +} + + + +int CmdLFPCF7931Write(const char *Cmd) +{ + UsbCommand c = {CMD_PCF7931_WRITE}; + + int res = 0; + res = sscanf(Cmd, "%x %x %x", &c.arg[0], &c.arg[1], &c.arg[2]); + + if(res < 1) { + PrintAndLog("Please specify the block address in hex"); + return 0; + } + if (res == 1){ + PrintAndLog("Please specify the byte address in hex"); + return 0; + } + if(res == 2) { + PrintAndLog("Please specify the data in hex (1 byte)"); + return 0; + } + if(res == 3) { + uint8_t n=0; + for(n=0;n<7;n++) c.d.asDwords[n] = configPcf.password[n]; + c.d.asDwords[7] = (configPcf.offset[0]+128); + c.d.asDwords[8] = (configPcf.offset[1]+128); + c.d.asDwords[9] = configPcf.init_delay; + SendCommand(&c); + return 0; + } + + PrintAndLog("INCORRECT FORMAT"); + return 0; +} + + static command_t CommandTable[] = { {"help", CmdHelp, 1, "This help"}, {"read", CmdLFPCF7931Read, 1, "Read content of a PCF7931 transponder"}, + {"write", CmdLFPCF7931Write, 1, "Write data on a PCF7931 transponder. Usage : lf pcf7931 write "}, + {"config", CmdLFPCF7931Config, 1, "Configure the password, the tags initialization delay and time offsets (optional)"}, {NULL, NULL, 0, NULL} }; diff --git a/client/cmdlfpcf7931.h b/client/cmdlfpcf7931.h index ed60bc91..78eaff5d 100644 --- a/client/cmdlfpcf7931.h +++ b/client/cmdlfpcf7931.h @@ -1,6 +1,7 @@ //----------------------------------------------------------------------------- // Copyright (C) 2012 Chalk -// +// 2015 Dake + // 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. @@ -11,8 +12,18 @@ #ifndef CMDLFPCF7931_H__ #define CMDLFPCF7931_H__ +struct pcf7931_config{ + uint8_t password[7]; + uint16_t init_delay; + int16_t offset[2]; +}; + int CmdLFPCF7931(const char *Cmd); int CmdLFPCF7931Read(const char *Cmd); +int CmdLFPCF7931Write(const char *Cmd); + +int CmdLFPCF7931Config(const char *Cmd); + #endif diff --git a/client/cmdmain.c b/client/cmdmain.c index 512aa13c..deced558 100644 --- a/client/cmdmain.c +++ b/client/cmdmain.c @@ -97,8 +97,9 @@ void storeCommand(UsbCommand *command) memcpy(destination, command, sizeof(UsbCommand)); cmd_head = (cmd_head +1) % CMD_BUFFER_SIZE; //increment head and wrap - } + + /** * @brief getCommand gets a command from an internal circular buffer. * @param response location to write command @@ -117,9 +118,9 @@ int getCommand(UsbCommand* response) cmd_tail = (cmd_tail +1 ) % CMD_BUFFER_SIZE; return 1; - } + /** * Waits for a certain response type. This method waits for a maximum of * ms_timeout milliseconds for a specified response command. @@ -131,33 +132,34 @@ int getCommand(UsbCommand* response) */ bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) { - UsbCommand resp; + UsbCommand resp; - if (response == NULL) - response = &resp; - - - // Wait until the command is received - for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) { + if (response == NULL) { + response = &resp; + } + // Wait until the command is received + for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) { while(getCommand(response)) { - if(response->cmd == cmd){ - return true; - } - } - msleep(10); // XXX ugh - if (dm_seconds == 200) { // Two seconds elapsed - PrintAndLog("Waiting for a response from the proxmark..."); - PrintAndLog("Don't forget to cancel its operation first by pressing on the button"); - } + if(response->cmd == cmd){ + return true; + } + } + msleep(10); // XXX ugh + if (dm_seconds == 200) { // Two seconds elapsed + PrintAndLog("Waiting for a response from the proxmark..."); + PrintAndLog("Don't forget to cancel its operation first by pressing on the button"); + } } - return false; + return false; } + bool WaitForResponse(uint32_t cmd, UsbCommand* response) { return WaitForResponseTimeout(cmd,response,-1); } + //----------------------------------------------------------------------------- // Entry point into our code: called whenever the user types a command and // then presses Enter, which the full command line that they typed. @@ -166,6 +168,7 @@ void CommandReceived(char *Cmd) { CmdsParse(CommandTable, Cmd); } + //----------------------------------------------------------------------------- // Entry point into our code: called whenever we received a packet over USB // that we weren't necessarily expecting, for example a debug print. @@ -189,12 +192,13 @@ void UsbCommandReceived(UsbCommand *UC) case CMD_DOWNLOADED_RAW_ADC_SAMPLES_125K: { memcpy(sample_buf+(UC->arg[0]),UC->d.asBytes,UC->arg[1]); + return; } break; default: + storeCommand(UC); break; } - storeCommand(UC); } diff --git a/client/lualibs/commands.lua b/client/lualibs/commands.lua index 4e98bd28..5f34976f 100644 --- a/client/lualibs/commands.lua +++ b/client/lualibs/commands.lua @@ -20,7 +20,8 @@ local _commands = { CMD_BUFF_CLEAR = 0x0105, CMD_READ_MEM = 0x0106, CMD_VERSION = 0x0107, - + CMD_STATUS = 0x0108, + CMD_PING = 0x0109, --// For low-frequency tags CMD_READ_TI_TYPE = 0x0202, CMD_WRITE_TI_TYPE = 0x0203, diff --git a/client/scripts/mifare_autopwn.lua b/client/scripts/mifare_autopwn.lua index 9cc865f0..77f36ae4 100644 --- a/client/scripts/mifare_autopwn.lua +++ b/client/scripts/mifare_autopwn.lua @@ -112,6 +112,8 @@ function mfcrack_inner() return nil, "Card is not vulnerable to Darkside attack (doesn't send NACK on authentication requests). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." elseif isOK == 0xFFFFFFFD then return nil, "Card is not vulnerable to Darkside attack (its random number generator is not predictable). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." + elseif isOK == 0xFFFFFFFC then + return nil, "The card's random number generator is vulnerable but behaves somewhat weird (Mifare clone?). You can try 'script run mfkeys' or 'hf mf chk' to test various known keys." elseif isOK ~= 1 then return nil, "Error occurred" end diff --git a/client/util.h b/client/util.h index 19c34604..8bf4f388 100644 --- a/client/util.h +++ b/client/util.h @@ -47,6 +47,7 @@ char * printBits(size_t const size, void const * const ptr); uint8_t *SwapEndian64(const uint8_t *src, const size_t len, const uint8_t blockSize); char param_getchar(const char *line, int paramnum); +int param_getptr(const char *line, int *bg, int *en, 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); diff --git a/doc/RFID_Antenna-Basic-Form.stl b/doc/RFID_Antenna-Basic-Form.stl new file mode 100755 index 00000000..6679ae8b Binary files /dev/null and b/doc/RFID_Antenna-Basic-Form.stl differ diff --git a/doc/RFID_Antenna-With-Lanyard-Hook.stl b/doc/RFID_Antenna-With-Lanyard-Hook.stl new file mode 100755 index 00000000..62f5397a Binary files /dev/null and b/doc/RFID_Antenna-With-Lanyard-Hook.stl differ diff --git a/include/usb_cmd.h b/include/usb_cmd.h index 3afed7c3..0f649a69 100644 --- a/include/usb_cmd.h +++ b/include/usb_cmd.h @@ -60,6 +60,8 @@ typedef struct{ #define CMD_BUFF_CLEAR 0x0105 #define CMD_READ_MEM 0x0106 #define CMD_VERSION 0x0107 +#define CMD_STATUS 0x0108 +#define CMD_PING 0x0109 // For low-frequency tags #define CMD_READ_TI_TYPE 0x0202 @@ -85,6 +87,7 @@ typedef struct{ #define CMD_T55XX_WRITE_BLOCK 0x0215 #define CMD_T55XX_READ_TRACE 0x0216 #define CMD_PCF7931_READ 0x0217 +#define CMD_PCF7931_WRITE 0x0222 #define CMD_EM4X_READ_WORD 0x0218 #define CMD_EM4X_WRITE_WORD 0x0219 #define CMD_IO_DEMOD_FSK 0x021A @@ -97,6 +100,7 @@ typedef struct{ #define CMD_PSK_SIM_TAG 0x0220 #define CMD_AWID_DEMOD_FSK 0x0221 + /* CMD_SET_ADC_MUX: ext1 is 0 for lopkd, 1 for loraw, 2 for hipkd, 3 for hiraw */ // For the 13.56 MHz tags