X-Git-Url: https://git.zerfleddert.de/cgi-bin/gitweb.cgi/proxmark3-svn/blobdiff_plain/3cec706139a331d4405db6a7d71e17e0a1573c20..refs/heads/master:/armsrc/pcf7931.c diff --git a/armsrc/pcf7931.c b/armsrc/pcf7931.c index 73f18768..2fae74cc 100644 --- a/armsrc/pcf7931.c +++ b/armsrc/pcf7931.c @@ -1,36 +1,34 @@ #include "proxmark3.h" #include "apps.h" +#include "usb_cdc.h" #include "lfsampling.h" #include "pcf7931.h" +#include "util.h" #include "string.h" +#include "fpgaloader.h" #define T0_PCF 8 //period for the pcf7931 in us #define ALLOC 16 -#define abs(x) ( ((x)<0) ? -(x) : (x) ) -#define max(x,y) ( x 18000 ) + if (GraphTraceLen > 18000) GraphTraceLen = 18000; - - + int i, j, lastval, bitidx, half_switch; int clock = 64; int tolerance = clock / 8; int pmc, block_done; int lc, warnings = 0; - int num_blocks = 0; + size_t num_blocks = 0; int lmin=128, lmax=128; uint8_t dir; //clear read buffer - BigBuf_Clear_keep_EM(void); + BigBuf_Clear_keep_EM(); LFSetupFPGAForADC(95, true); DoAcquisition_default(0, true); @@ -41,17 +39,16 @@ int DemodPCF7931(uint8_t **outBlocks) { i = 2; /* Find first local max/min */ - if(dest[1] > dest[0]) { + if(dest[1] > dest[0]) { while(i < GraphTraceLen) { - if( !(dest[i] > dest[i-1]) && dest[i] > lmax) + if( !(dest[i] > dest[i-1]) && dest[i] > lmax) break; i++; } dir = 0; - } - else { + } else { while(i < GraphTraceLen) { - if( !(dest[i] < dest[i-1]) && dest[i] < lmin) + if( !(dest[i] < dest[i-1]) && dest[i] < lmin) break; i++; } @@ -63,16 +60,14 @@ int DemodPCF7931(uint8_t **outBlocks) { pmc = 0; block_done = 0; - for (bitidx = 0; i < GraphTraceLen; i++) - { - if ( (dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin)) - { + for (bitidx = 0; i < GraphTraceLen; i++) { + if ((dest[i-1] > dest[i] && dir == 1 && dest[i] > lmax) || (dest[i-1] < dest[i] && dir == 0 && dest[i] < lmin)) { lc = i - lastval; lastval = i; // Switch depending on lc length: // Tolerance is 1/8 of clock rate (arbitrary) - if (abs(lc-clock/4) < tolerance) { + if (ABS(lc-clock/4) < tolerance) { // 16T0 if((i - pmc) == lc) { /* 16T0 was previous one */ /* It's a PMC ! */ @@ -80,11 +75,10 @@ int DemodPCF7931(uint8_t **outBlocks) { lastval = i; pmc = 0; block_done = 1; - } - else { + } else { pmc = i; } - } else if (abs(lc-clock/2) < tolerance) { + } else if (ABS(lc-clock/2) < tolerance) { // 32TO if((i - pmc) == lc) { /* 16T0 was previous one */ /* It's a PMC ! */ @@ -92,21 +86,18 @@ int DemodPCF7931(uint8_t **outBlocks) { lastval = i; pmc = 0; block_done = 1; - } - else if(half_switch == 1) { - bits[bitidx++] = 0; + } else if(half_switch == 1) { + bits[bitidx++] = 0; half_switch = 0; } else half_switch++; - } else if (abs(lc-clock) < tolerance) { + } else if (ABS(lc-clock) < tolerance) { // 64TO - bits[bitidx++] = 1; + bits[bitidx++] = 1; } else { // Error - warnings++; - if (warnings > 10) - { + if (++warnings > 10) { Dbprintf("Error: too many detection errors, aborting."); return 0; } @@ -114,16 +105,17 @@ int DemodPCF7931(uint8_t **outBlocks) { if(block_done == 1) { if(bitidx == 128) { - for(j=0; j<16; j++) { - blocks[num_blocks][j] = 128*bits[j*8+7]+ - 64*bits[j*8+6]+ - 32*bits[j*8+5]+ - 16*bits[j*8+4]+ - 8*bits[j*8+3]+ - 4*bits[j*8+2]+ - 2*bits[j*8+1]+ - bits[j*8]; - + for(j = 0; j < 16; ++j) { + blocks[num_blocks][j] = + 128 * bits[j*8 + 7]+ + 64 * bits[j*8 + 6] + + 32 * bits[j*8 + 5] + + 16 * bits[j*8 + 4] + + 8 * bits[j*8 + 3] + + 4 * bits[j*8 + 2] + + 2 * bits[j*8 + 1] + + bits[j*8] + ; } num_blocks++; } @@ -132,272 +124,357 @@ int DemodPCF7931(uint8_t **outBlocks) { half_switch = 0; } if(i < GraphTraceLen) - dir =(dest[i-1] > dest[i]) ? 0 : 1; + dir = (dest[i-1] > dest[i]) ? 0 : 1; } if(bitidx==255) bitidx=0; warnings = 0; if(num_blocks == 4) break; } - memcpy(outBlocks, blocks, 16*num_blocks); + memcpy(outBlocks, blocks, 16 * num_blocks); return num_blocks; } -int IsBlock0PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if((memcmp(Block, "\x00\x00\x00\x00\x00\x00\x00\x01", 8) == 0) && memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) // PAC enabled - return 1; - if((memcmp(Block+9, "\x00\x00\x00\x00\x00\x00\x00", 7) == 0) && Block[7] == 0) // PAC disabled, can it *really* happen ? - return 1; - return 0; +bool IsBlock0PCF7931(uint8_t *block) { + // assuming all RFU bits are set to 0 + // if PAC is enabled password is set to 0 + if (block[7] == 0x01) + { + if (!memcmp(block, "\x00\x00\x00\x00\x00\x00\x00", 7) && !memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) + return true; + } + else if (block[7] == 0x00) + { + if (!memcmp(block+9, "\x00\x00\x00\x00\x00\x00\x00", 7)) + return true; + } + return false; } -int IsBlock1PCF7931(uint8_t *Block) { - // Assume RFU means 0 :) - if(Block[10] == 0 && Block[11] == 0 && Block[12] == 0 && Block[13] == 0) - if((Block[14] & 0x7f) <= 9 && Block[15] <= 9) - return 1; +bool IsBlock1PCF7931(uint8_t *block) { + // assuming all RFU bits are set to 0 - return 0; + uint8_t rb1 = block[14] & 0x80; + uint8_t rfb = block[14] & 0x7f; + uint8_t rlb = block[15]; + + if (block[10] == 0 && block[11] == 0 && block[12] == 0 && block[13] == 0) + // block 1 is sent only if (RLB >= 1 && RFB <= 1) or RB1 enabled + if(rfb <= rlb && rfb <= 9 && rlb <= 9 && ((rfb <= 1 && rlb >= 1) || rb1)) + return true; + + return false; } void ReadPCF7931() { - uint8_t Blocks[8][17]; - uint8_t tmpBlocks[4][16]; - int i, j, ind, ind2, n; - int num_blocks = 0; - int max_blocks = 8; - int ident = 0; - int error = 0; - int tries = 0; + int found_blocks = 0; // successfully read blocks + int max_blocks = 8; // readable blocks + uint8_t memory_blocks[8][17]; // PCF content + + uint8_t single_blocks[8][17]; // PFC blocks with unknown position + int single_blocks_cnt = 0; + + size_t n = 0; // transmitted blocks + uint8_t tmp_blocks[4][16]; // temporary read buffer + + uint8_t found_0_1 = 0; // flag: blocks 0 and 1 were found + int errors = 0; // error counter + int tries = 0; // tries counter + + memset(memory_blocks, 0, 8*17*sizeof(uint8_t)); + memset(single_blocks, 0, 8*17*sizeof(uint8_t)); - memset(Blocks, 0, 8*17*sizeof(uint8_t)); + int i = 0, j = 0; do { - memset(tmpBlocks, 0, 4*16*sizeof(uint8_t)); - n = DemodPCF7931((uint8_t**)tmpBlocks); + i = 0; + + memset(tmp_blocks, 0, 4*16*sizeof(uint8_t)); + n = DemodPCF7931((uint8_t**)tmp_blocks); if(!n) - error++; - if(error==10 && num_blocks == 0) { + ++errors; + + // exit if no block is received + if (errors >= 10 && found_blocks == 0 && single_blocks_cnt == 0) { Dbprintf("Error, no tag or bad tag"); return; } - else if (tries==20 || error==10) { + + // exit if too many errors during reading + if (tries > 50 && (2*errors > tries)) { Dbprintf("Error reading the tag"); Dbprintf("Here is the partial content"); goto end; } - for(i=0; i= 0; ind--,ind2--) { - if(ind2 < 0) - ind2 = max_blocks; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } - } - for(ind=i+1,ind2=j+1; ind < n; ind++,ind2++) { - if(ind2 > max_blocks) - ind2 = 0; - if(!Blocks[ind2][ALLOC]) { // Block ind2 not already found - // Dbprintf("Tmp %d -> Block %d", ind, ind2); - memcpy(Blocks[ind2], tmpBlocks[ind], 16); - Blocks[ind2][ALLOC] = 1; - num_blocks++; - if(num_blocks == max_blocks) goto end; - } + + Dbprintf("(dbg) got %d blocks (%d/%d found) (%d tries, %d errors)", n, found_blocks, (max_blocks == 0 ? found_blocks : max_blocks), tries, errors); + for (i = 0; i < n; ++i) + { + print_result("got consecutive blocks", tmp_blocks[i], 16); + } + + i = 0; + if(!found_0_1) { + while (i < n - 1) { + if (IsBlock0PCF7931(tmp_blocks[i]) && IsBlock1PCF7931(tmp_blocks[i+1])) { + found_0_1 = 1; + memcpy(memory_blocks[0], tmp_blocks[i], 16); + memcpy(memory_blocks[1], tmp_blocks[i+1], 16); + memory_blocks[0][ALLOC] = memory_blocks[1][ALLOC] = 1; + // block 1 tells how many blocks are going to be sent + max_blocks = MAX((memory_blocks[1][14] & 0x7f), memory_blocks[1][15]) + 1; + found_blocks = 2; + + Dbprintf("Found blocks 0 and 1. PCF is transmitting %d blocks.", max_blocks); + + // handle the following blocks + for (j = i + 2; j < n; ++j) { + memcpy(memory_blocks[found_blocks], tmp_blocks[j], 16); + memory_blocks[found_blocks][ALLOC] = 1; + ++found_blocks; + } + break; + } + ++i; + } + } else { + // Trying to re-order blocks + // Look for identical block in memory blocks + while (i < n-1) { + // skip all zeroes blocks + if (memcmp(tmp_blocks[i], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { + for (j = 1; j < max_blocks - 1; ++j) { + if (!memcmp(tmp_blocks[i], memory_blocks[j], 16) && !memory_blocks[j+1][ALLOC]) { + memcpy(memory_blocks[j+1], tmp_blocks[i+1], 16); + memory_blocks[j+1][ALLOC] = 1; + if (++found_blocks >= max_blocks) goto end; + } + } + } + if (memcmp(tmp_blocks[i+1], "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16)) { + for (j = 0; j < max_blocks; ++j) { + if (!memcmp(tmp_blocks[i+1], memory_blocks[j], 16) && !memory_blocks[(j == 0 ? max_blocks : j) -1][ALLOC]) { + if (j == 0) { + memcpy(memory_blocks[max_blocks - 1], tmp_blocks[i], 16); + memory_blocks[max_blocks - 1][ALLOC] = 1; + } else { + memcpy(memory_blocks[j-1], tmp_blocks[i], 16); + memory_blocks[j-1][ALLOC] = 1; } + if (++found_blocks >= max_blocks) goto end; } } } + ++i; } } - tries++; - if (BUTTON_PRESS()) return; - } while (num_blocks != max_blocks); + ++tries; + if (BUTTON_PRESS()) { + Dbprintf("Button pressed, stopping."); + goto end; + } + } + while (found_blocks < max_blocks); + end: Dbprintf("-----------------------------------------"); Dbprintf("Memory content:"); Dbprintf("-----------------------------------------"); - for(i=0; i", i); } Dbprintf("-----------------------------------------"); + if (found_blocks < max_blocks) { + Dbprintf("-----------------------------------------"); + Dbprintf("Blocks with unknown position:"); + Dbprintf("-----------------------------------------"); + for (i = 0; i < single_blocks_cnt; ++i) + print_result("Block", single_blocks[i], 16); + + Dbprintf("-----------------------------------------"); + } cmd_send(CMD_ACK,0,0,0,0,0); } - -/* 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) -{ - +static void RealWritePCF7931(uint8_t *pass, 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); - + // password (on 56 bits) + AddBytePCF7931(pass[0], tab, l, p); + AddBytePCF7931(pass[1], tab, l, p); + AddBytePCF7931(pass[2], tab, l, p); + AddBytePCF7931(pass[3], tab, l, p); + AddBytePCF7931(pass[4], tab, l, p); + AddBytePCF7931(pass[5], tab, l, p); + AddBytePCF7931(pass[6], 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){ + for (u = 0; tab[u] != 0; ++u) + if(tab[u] > 0xFFFF) { tab[u] -= 0xFFFF; comp = 0; } - } } SendCmdPCF7931(tab); } +void BruteForcePCF7931(uint64_t password, uint8_t tries, uint16_t init_delay, int32_t l, int32_t p) { + uint8_t i = 0; + uint8_t pass_array[7]; + + while (password < 0x00FFFFFFFFFFFFFF) { + if (BUTTON_PRESS()) { + Dbprintf("Button pressed, stopping bruteforce ..."); + return; + } + + num_to_bytes(password, 7, pass_array); + + Dbprintf("Trying: %02x %02x %02x %02x %02x %02x %02x ...", + pass_array[0], + pass_array[1], + pass_array[2], + pass_array[3], + pass_array[4], + pass_array[5], + pass_array[6]); + + for (i = 0; i < tries; ++i) + RealWritePCF7931 + ( + pass_array, + init_delay, + l, + p, + 0, + 7, + 0x01 + ); + + ++password; + } +} + +/* 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) { + Dbprintf("Initialization delay : %d us", init_delay); + Dbprintf("Offsets : %d us on the low pulses width, %d us on the low pulses positions", l, p); + Dbprintf("Password (LSB first on each byte): %02x %02x %02x %02x %02x %02x %02x", pass1, pass2, pass3, pass4, pass5, pass6, pass7); + Dbprintf("Block address : %02x", address); + Dbprintf("Byte address : %02x", byte); + Dbprintf("Data : %02x", data); + + uint8_t password[7] = {pass1, pass2, pass3, pass4, pass5, pass6, pass7}; + + RealWritePCF7931 (password, init_delay, l, p, address, byte, data); +} + /* Send a trame to a PCF7931 tags * @param tab : array of the data frame */ -void SendCmdPCF7931(uint32_t * tab){ +void SendCmdPCF7931(uint32_t * tab) { uint16_t u=0; uint16_t tempo=0; - Dbprintf("SENDING DATA FRAME..."); + Dbprintf("Sending data frame ..."); FpgaDownloadAndGo(FPGA_BITSTREAM_LF); - FpgaSendCommand(FPGA_CMD_SET_DIVISOR, 95); //125Khz - FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_PASSTHRU ); LED_A_ON(); @@ -414,60 +491,46 @@ void SendCmdPCF7931(uint32_t * tab){ 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){ - - + for (u = 0; tab[u] != 0; u += 3) { // modulate antenna HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u]){ + while(tempo != tab[u]) tempo = AT91C_BASE_TC0->TC_CV; - } // stop modulating antenna LOW(GPIO_SSC_DOUT); - while(tempo != tab[u+1]){ + while(tempo != tab[u+1]) tempo = AT91C_BASE_TC0->TC_CV; - } - // modulate antenna HIGH(GPIO_SSC_DOUT); - while(tempo != tab[u+2]){ + 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)"); + DbpString("Data frame sent (multiple sends may be needed)"); LED(0xFFFF, 1000); } -/* Add a byte for building the data frame of PCF7931 tags +/* 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){ - +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<