CHG: changed the CRC implementations.
LegicRfWriter(c->arg[1], c->arg[0]);
break;
+ case CMD_RAW_WRITER_LEGIC_RF:
+ LegicRfRawWriter(c->arg[0], c->arg[1]);
+ break;
+
case CMD_READER_LEGIC_RF:
LegicRfReader(c->arg[0], c->arg[1]);
break;
crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0);
}
+/* Switch off carrier, make sure tag is reset */
static void switch_off_tag_rwd(void)
{
- /* Switch off carrier, make sure tag is reset */
AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT;
SpinDelay(10);
-
WDT_HIT();
}
/* calculate crc for a legic command */
* * wait until the tag sends back an ACK ('1' bit unencrypted)
* * forward the prng based on the timing
*/
+//int legic_write_byte(int byte, int addr, int addr_sz, int PrngCorrection) {
int legic_write_byte(int byte, int addr, int addr_sz) {
- //do not write UID, CRC, DCF
- if(addr <= 0x06)
+ //do not write UID, CRC
+ if(addr <= 0x04) {
return 0;
-
+ }
//== send write command ==============================
crc_clear(&legic_crc);
crc_update(&legic_crc, 0, 1); /* CMD_WRITE */
|(0x00 <<0)); //CMD = W
uint32_t cmd_sz = addr_sz+1+8+4; //crc+data+cmd
- legic_prng_forward(2); /* we wait anyways */
+ legic_prng_forward(4); /* we wait anyways */
while(timer->TC_CV < 387) ; /* ~ 258us */
frame_send_rwd(cmd, cmd_sz);
+ AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_DIN;
+ AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN;
+
//== wait for ack ====================================
int t, old_level=0, edges=0;
int next_bit_at =0;
int c = t/TAG_TIME_BIT;
timer->TC_CCR = AT91C_TC_SWTRG;
while(timer->TC_CV > 1) ; /* Wait till the clock has reset */
- legic_prng_forward(c);
+ legic_prng_forward(c-1);
return 0;
}
}
}
int LegicRfReader(int offset, int bytes) {
+
+ // ice_legic_setup();
+ // ice_legic_select_card();
+ // return 0;
+
int byte_index=0, cmd_sz=0, card_sz=0;
LegicCommonInit();
uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
switch_off_tag_rwd(); //we lose to mutch time with dprintf
switch(tag_type) {
+ case 0x0d:
+ DbpString("MIM22 card found, reading card ...");
+ cmd_sz = 6;
+ card_sz = 22;
+ break;
case 0x1d:
- DbpString("MIM 256 card found, reading card ...");
+ DbpString("MIM256 card found, reading card ...");
cmd_sz = 9;
card_sz = 256;
break;
case 0x3d:
- DbpString("MIM 1024 card found, reading card ...");
+ DbpString("MIM1024 card found, reading card ...");
cmd_sz = 11;
card_sz = 1024;
break;
BigBuf[byte_index] = r;
WDT_HIT();
byte_index++;
- if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
+ if (byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
}
LED_B_OFF();
LED_C_OFF();
return 0;
}
+/*int _LegicRfWriter(int bytes, int offset, int addr_sz, uint8_t *BigBuf, int RoundBruteforceValue) {
+ int byte_index=0;
+
+ LED_B_ON();
+ perform_setup_phase_rwd(SESSION_IV);
+ //legic_prng_forward(2);
+ while(byte_index < bytes) {
+ int r;
+
+ //check if the DCF should be changed
+ if ( (offset == 0x05) && (bytes == 0x02) ) {
+ //write DCF in reverse order (addr 0x06 before 0x05)
+ r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz, RoundBruteforceValue);
+ //legic_prng_forward(1);
+ if(r == 0) {
+ byte_index++;
+ r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz, RoundBruteforceValue);
+ }
+ //legic_prng_forward(1);
+ }
+ else {
+ r = legic_write_byte(BigBuf[byte_index+offset], byte_index+offset, addr_sz, RoundBruteforceValue);
+ }
+ if((r != 0) || BUTTON_PRESS()) {
+ Dbprintf("operation aborted @ 0x%03.3x", byte_index);
+ switch_off_tag_rwd();
+ LED_B_OFF();
+ LED_C_OFF();
+ return -1;
+ }
+
+ WDT_HIT();
+ byte_index++;
+ if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
+ }
+ LED_B_OFF();
+ LED_C_OFF();
+ DbpString("write successful");
+ return 0;
+}*/
+
void LegicRfWriter(int bytes, int offset) {
int byte_index=0, addr_sz=0;
uint8_t *BigBuf = BigBuf_get_addr();
uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
switch_off_tag_rwd();
switch(tag_type) {
+ case 0x0d:
+ if(offset+bytes > 22) {
+ Dbprintf("Error: can not write to 0x%03.3x on MIM22", offset+bytes);
+ return;
+ }
+ addr_sz = 5;
+ Dbprintf("MIM22 card found, writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes);
+ break;
case 0x1d:
if(offset+bytes > 0x100) {
- Dbprintf("Error: can not write to 0x%03.3x on MIM 256", offset+bytes);
+ Dbprintf("Error: can not write to 0x%03.3x on MIM256", offset+bytes);
return;
}
addr_sz = 8;
- Dbprintf("MIM 256 card found, writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes);
+ Dbprintf("MIM256 card found, writing 0x%02.2x - 0x%02.2x ...", offset, offset+bytes);
break;
case 0x3d:
if(offset+bytes > 0x400) {
- Dbprintf("Error: can not write to 0x%03.3x on MIM 1024", offset+bytes);
+ Dbprintf("Error: can not write to 0x%03.3x on MIM1024", offset+bytes);
return;
}
addr_sz = 10;
- Dbprintf("MIM 1024 card found, writing 0x%03.3x - 0x%03.3x ...", offset, offset+bytes);
+ Dbprintf("MIM1024 card found, writing 0x%03.3x - 0x%03.3x ...", offset, offset+bytes);
break;
default:
Dbprintf("No or unknown card found, aborting");
return;
}
+#if 1
LED_B_ON();
perform_setup_phase_rwd(SESSION_IV);
- legic_prng_forward(2);
+
while(byte_index < bytes) {
- int r = legic_write_byte(BigBuf[byte_index+offset], byte_index+offset, addr_sz);
+ int r;
+
+ //check if the DCF should be changed
+ if ( ((byte_index+offset) == 0x05) && (bytes >= 0x02) ) {
+ //write DCF in reverse order (addr 0x06 before 0x05)
+ r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz);
+
+ // write second byte on success...
+ if(r == 0) {
+ byte_index++;
+ r = legic_write_byte(BigBuf[(0x06-byte_index)], (0x06-byte_index), addr_sz);
+ }
+ }
+ else {
+ r = legic_write_byte(BigBuf[byte_index+offset], byte_index+offset, addr_sz);
+ }
if((r != 0) || BUTTON_PRESS()) {
Dbprintf("operation aborted @ 0x%03.3x", byte_index);
switch_off_tag_rwd();
LED_C_OFF();
return;
}
+
+ WDT_HIT();
+ byte_index++;
+ if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
+ }
+ LED_B_OFF();
+ LED_C_OFF();
+ DbpString("write successful");
+#else
+ for(byte_index = -2; byte_index < 200; byte_index++)
+ {
+ Dbprintf("+ Try RndValue %d...", byte_index);
+ if(_LegicRfWriter(bytes, offset, addr_sz, BigBuf, byte_index) == 0)
+ break;
+ }
+#endif
+
+}
+
+void LegicRfRawWriter(int offset, int byte) {
+ int byte_index=0, addr_sz=0;
+
+ LegicCommonInit();
+
+ DbpString("setting up legic card");
+ uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
+ switch_off_tag_rwd();
+ switch(tag_type) {
+ case 0x0d:
+ if(offset > 22) {
+ Dbprintf("Error: can not write to 0x%03.3x on MIM22", offset);
+ return;
+ }
+ addr_sz = 5;
+ Dbprintf("MIM22 card found, writing at addr 0x%02.2x - value 0x%02.2x ...", offset, byte);
+ break;
+ case 0x1d:
+ if(offset > 0x100) {
+ Dbprintf("Error: can not write to 0x%03.3x on MIM256", offset);
+ return;
+ }
+ addr_sz = 8;
+ Dbprintf("MIM256 card found, writing at addr 0x%02.2x - value 0x%02.2x ...", offset, byte);
+ break;
+ case 0x3d:
+ if(offset > 0x400) {
+ Dbprintf("Error: can not write to 0x%03.3x on MIM1024", offset);
+ return;
+ }
+ addr_sz = 10;
+ Dbprintf("MIM1024 card found, writing at addr 0x%03.3x - value 0x%03.3x ...", offset, byte);
+ break;
+ default:
+ Dbprintf("No or unknown card found, aborting");
+ return;
+ }
+ Dbprintf("integer value: %d offset: %d addr_sz: %d", byte, offset, addr_sz);
+ LED_B_ON();
+ perform_setup_phase_rwd(SESSION_IV);
+ //legic_prng_forward(2);
+
+ int r = legic_write_byte(byte, offset, addr_sz);
+
+ if((r != 0) || BUTTON_PRESS()) {
+ Dbprintf("operation aborted @ 0x%03.3x (%1d)", byte_index, r);
+ switch_off_tag_rwd();
+ LED_B_OFF();
+ LED_C_OFF();
+ return;
+
WDT_HIT();
byte_index++;
if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
LED_C_OFF();
}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// Code up a string of octets at layer 2 (including CRC, we don't generate
+// that here) so that they can be transmitted to the reader. Doesn't transmit
+// them yet, just leaves them ready to send in ToSend[].
+//-----------------------------------------------------------------------------
+// static void CodeLegicAsTag(const uint8_t *cmd, int len)
+// {
+ // int i;
+
+ // ToSendReset();
+
+ // // Transmit a burst of ones, as the initial thing that lets the
+ // // reader get phase sync. This (TR1) must be > 80/fs, per spec,
+ // // but tag that I've tried (a Paypass) exceeds that by a fair bit,
+ // // so I will too.
+ // for(i = 0; i < 20; i++) {
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // }
+
+ // // Send SOF.
+ // for(i = 0; i < 10; i++) {
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // }
+ // for(i = 0; i < 2; i++) {
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // }
+
+ // for(i = 0; i < len; i++) {
+ // int j;
+ // uint8_t b = cmd[i];
+
+ // // Start bit
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+
+ // // Data bits
+ // for(j = 0; j < 8; j++) {
+ // if(b & 1) {
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // } else {
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // }
+ // b >>= 1;
+ // }
+
+ // // Stop bit
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // }
+
+ // // Send EOF.
+ // for(i = 0; i < 10; i++) {
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // ToSendStuffBit(0);
+ // }
+ // for(i = 0; i < 2; i++) {
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // ToSendStuffBit(1);
+ // }
+
+ // // Convert from last byte pos to length
+ // ToSendMax++;
+// }
+
+//-----------------------------------------------------------------------------
+// The software UART that receives commands from the reader, and its state
+// variables.
+//-----------------------------------------------------------------------------
+static struct {
+ enum {
+ STATE_UNSYNCD,
+ STATE_GOT_FALLING_EDGE_OF_SOF,
+ STATE_AWAITING_START_BIT,
+ STATE_RECEIVING_DATA
+ } state;
+ uint16_t shiftReg;
+ int bitCnt;
+ int byteCnt;
+ int byteCntMax;
+ int posCnt;
+ uint8_t *output;
+} Uart;
+
+/* Receive & handle a bit coming from the reader.
+ *
+ * This function is called 4 times per bit (every 2 subcarrier cycles).
+ * Subcarrier frequency fs is 212kHz, 1/fs = 4,72us, i.e. function is called every 9,44us
+ *
+ * LED handling:
+ * LED A -> ON once we have received the SOF and are expecting the rest.
+ * LED A -> OFF once we have received EOF or are in error state or unsynced
+ *
+ * Returns: true if we received a EOF
+ * false if we are still waiting for some more
+ */
+// static RAMFUNC int HandleLegicUartBit(uint8_t bit)
+// {
+ // switch(Uart.state) {
+ // case STATE_UNSYNCD:
+ // if(!bit) {
+ // // we went low, so this could be the beginning of an SOF
+ // Uart.state = STATE_GOT_FALLING_EDGE_OF_SOF;
+ // Uart.posCnt = 0;
+ // Uart.bitCnt = 0;
+ // }
+ // break;
+
+ // case STATE_GOT_FALLING_EDGE_OF_SOF:
+ // Uart.posCnt++;
+ // if(Uart.posCnt == 2) { // sample every 4 1/fs in the middle of a bit
+ // if(bit) {
+ // if(Uart.bitCnt > 9) {
+ // // we've seen enough consecutive
+ // // zeros that it's a valid SOF
+ // Uart.posCnt = 0;
+ // Uart.byteCnt = 0;
+ // Uart.state = STATE_AWAITING_START_BIT;
+ // LED_A_ON(); // Indicate we got a valid SOF
+ // } else {
+ // // didn't stay down long enough
+ // // before going high, error
+ // Uart.state = STATE_UNSYNCD;
+ // }
+ // } else {
+ // // do nothing, keep waiting
+ // }
+ // Uart.bitCnt++;
+ // }
+ // if(Uart.posCnt >= 4) Uart.posCnt = 0;
+ // if(Uart.bitCnt > 12) {
+ // // Give up if we see too many zeros without
+ // // a one, too.
+ // LED_A_OFF();
+ // Uart.state = STATE_UNSYNCD;
+ // }
+ // break;
+
+ // case STATE_AWAITING_START_BIT:
+ // Uart.posCnt++;
+ // if(bit) {
+ // if(Uart.posCnt > 50/2) { // max 57us between characters = 49 1/fs, max 3 etus after low phase of SOF = 24 1/fs
+ // // stayed high for too long between
+ // // characters, error
+ // Uart.state = STATE_UNSYNCD;
+ // }
+ // } else {
+ // // falling edge, this starts the data byte
+ // Uart.posCnt = 0;
+ // Uart.bitCnt = 0;
+ // Uart.shiftReg = 0;
+ // Uart.state = STATE_RECEIVING_DATA;
+ // }
+ // break;
+
+ // case STATE_RECEIVING_DATA:
+ // Uart.posCnt++;
+ // if(Uart.posCnt == 2) {
+ // // time to sample a bit
+ // Uart.shiftReg >>= 1;
+ // if(bit) {
+ // Uart.shiftReg |= 0x200;
+ // }
+ // Uart.bitCnt++;
+ // }
+ // if(Uart.posCnt >= 4) {
+ // Uart.posCnt = 0;
+ // }
+ // if(Uart.bitCnt == 10) {
+ // if((Uart.shiftReg & 0x200) && !(Uart.shiftReg & 0x001))
+ // {
+ // // this is a data byte, with correct
+ // // start and stop bits
+ // Uart.output[Uart.byteCnt] = (Uart.shiftReg >> 1) & 0xff;
+ // Uart.byteCnt++;
+
+ // if(Uart.byteCnt >= Uart.byteCntMax) {
+ // // Buffer overflowed, give up
+ // LED_A_OFF();
+ // Uart.state = STATE_UNSYNCD;
+ // } else {
+ // // so get the next byte now
+ // Uart.posCnt = 0;
+ // Uart.state = STATE_AWAITING_START_BIT;
+ // }
+ // } else if (Uart.shiftReg == 0x000) {
+ // // this is an EOF byte
+ // LED_A_OFF(); // Finished receiving
+ // Uart.state = STATE_UNSYNCD;
+ // if (Uart.byteCnt != 0) {
+ // return TRUE;
+ // }
+ // } else {
+ // // this is an error
+ // LED_A_OFF();
+ // Uart.state = STATE_UNSYNCD;
+ // }
+ // }
+ // break;
+
+ // default:
+ // LED_A_OFF();
+ // Uart.state = STATE_UNSYNCD;
+ // break;
+ // }
+
+ // return FALSE;
+// }
+
+
+static void UartReset()
+{
+ Uart.byteCntMax = MAX_FRAME_SIZE;
+ Uart.state = STATE_UNSYNCD;
+ Uart.byteCnt = 0;
+ Uart.bitCnt = 0;
+ Uart.posCnt = 0;
+ memset(Uart.output, 0x00, MAX_FRAME_SIZE);
+}
+
+// static void UartInit(uint8_t *data)
+// {
+ // Uart.output = data;
+ // UartReset();
+// }
+
+//=============================================================================
+// An LEGIC reader. We take layer two commands, code them
+// appropriately, and then send them to the tag. We then listen for the
+// tag's response, which we leave in the buffer to be demodulated on the
+// PC side.
+//=============================================================================
+
+static struct {
+ enum {
+ DEMOD_UNSYNCD,
+ DEMOD_PHASE_REF_TRAINING,
+ DEMOD_AWAITING_FALLING_EDGE_OF_SOF,
+ DEMOD_GOT_FALLING_EDGE_OF_SOF,
+ DEMOD_AWAITING_START_BIT,
+ DEMOD_RECEIVING_DATA
+ } state;
+ int bitCount;
+ int posCount;
+ int thisBit;
+ uint16_t shiftReg;
+ uint8_t *output;
+ int len;
+ int sumI;
+ int sumQ;
+} Demod;
+
+/*
+ * Handles reception of a bit from the tag
+ *
+ * This function is called 2 times per bit (every 4 subcarrier cycles).
+ * Subcarrier frequency fs is 212kHz, 1/fs = 4,72us, i.e. function is called every 9,44us
+ *
+ * LED handling:
+ * LED C -> ON once we have received the SOF and are expecting the rest.
+ * LED C -> OFF once we have received EOF or are unsynced
+ *
+ * Returns: true if we received a EOF
+ * false if we are still waiting for some more
+ *
+ */
+
+ #ifndef SUBCARRIER_DETECT_THRESHOLD
+ # define SUBCARRIER_DETECT_THRESHOLD 8
+ #endif
+
+ // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
+#ifndef CHECK_FOR_SUBCARRIER
+# define CHECK_FOR_SUBCARRIER() { v = MAX(ai, aq) + MIN(halfci, halfcq); }
+#endif
+
+// The soft decision on the bit uses an estimate of just the
+// quadrant of the reference angle, not the exact angle.
+// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
+#define MAKE_SOFT_DECISION() { \
+ if(Demod.sumI > 0) \
+ v = ci; \
+ else \
+ v = -ci; \
+ \
+ if(Demod.sumQ > 0) \
+ v += cq; \
+ else \
+ v -= cq; \
+ \
+ }
+
+static RAMFUNC int HandleLegicSamplesDemod(int ci, int cq)
+{
+ int v = 0;
+ int ai = ABS(ci);
+ int aq = ABS(cq);
+ int halfci = (ai >> 1);
+ int halfcq = (aq >> 1);
+
+ switch(Demod.state) {
+ case DEMOD_UNSYNCD:
+
+ CHECK_FOR_SUBCARRIER()
+
+ if(v > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
+ Demod.state = DEMOD_PHASE_REF_TRAINING;
+ Demod.sumI = ci;
+ Demod.sumQ = cq;
+ Demod.posCount = 1;
+ }
+ break;
+
+ case DEMOD_PHASE_REF_TRAINING:
+ if(Demod.posCount < 8) {
+
+ CHECK_FOR_SUBCARRIER()
+
+ if (v > SUBCARRIER_DETECT_THRESHOLD) {
+ // set the reference phase (will code a logic '1') by averaging over 32 1/fs.
+ // note: synchronization time > 80 1/fs
+ Demod.sumI += ci;
+ Demod.sumQ += cq;
+ ++Demod.posCount;
+ } else {
+ // subcarrier lost
+ Demod.state = DEMOD_UNSYNCD;
+ }
+ } else {
+ Demod.state = DEMOD_AWAITING_FALLING_EDGE_OF_SOF;
+ }
+ break;
+
+ case DEMOD_AWAITING_FALLING_EDGE_OF_SOF:
+
+ MAKE_SOFT_DECISION()
+
+ //Dbprintf("ICE: %d %d %d %d %d", v, Demod.sumI, Demod.sumQ, ci, cq );
+ // logic '0' detected
+ if (v <= 0) {
+
+ Demod.state = DEMOD_GOT_FALLING_EDGE_OF_SOF;
+
+ // start of SOF sequence
+ Demod.posCount = 0;
+ } else {
+ // maximum length of TR1 = 200 1/fs
+ if(Demod.posCount > 25*2) Demod.state = DEMOD_UNSYNCD;
+ }
+ ++Demod.posCount;
+ break;
+
+ case DEMOD_GOT_FALLING_EDGE_OF_SOF:
+ ++Demod.posCount;
+
+ MAKE_SOFT_DECISION()
+
+ if(v > 0) {
+ // low phase of SOF too short (< 9 etu). Note: spec is >= 10, but FPGA tends to "smear" edges
+ if(Demod.posCount < 10*2) {
+ Demod.state = DEMOD_UNSYNCD;
+ } else {
+ LED_C_ON(); // Got SOF
+ Demod.state = DEMOD_AWAITING_START_BIT;
+ Demod.posCount = 0;
+ Demod.len = 0;
+ }
+ } else {
+ // low phase of SOF too long (> 12 etu)
+ if(Demod.posCount > 13*2) {
+ Demod.state = DEMOD_UNSYNCD;
+ LED_C_OFF();
+ }
+ }
+ break;
+
+ case DEMOD_AWAITING_START_BIT:
+ ++Demod.posCount;
+
+ MAKE_SOFT_DECISION()
+
+ if(v > 0) {
+ // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
+ if(Demod.posCount > 3*2) {
+ Demod.state = DEMOD_UNSYNCD;
+ LED_C_OFF();
+ }
+ } else {
+ // start bit detected
+ Demod.bitCount = 0;
+ Demod.posCount = 1; // this was the first half
+ Demod.thisBit = v;
+ Demod.shiftReg = 0;
+ Demod.state = DEMOD_RECEIVING_DATA;
+ }
+ break;
+
+ case DEMOD_RECEIVING_DATA:
+
+ MAKE_SOFT_DECISION()
+
+ if(Demod.posCount == 0) {
+ // first half of bit
+ Demod.thisBit = v;
+ Demod.posCount = 1;
+ } else {
+ // second half of bit
+ Demod.thisBit += v;
+ Demod.shiftReg >>= 1;
+ // logic '1'
+ if(Demod.thisBit > 0)
+ Demod.shiftReg |= 0x200;
+
+ ++Demod.bitCount;
+
+ if(Demod.bitCount == 10) {
+
+ uint16_t s = Demod.shiftReg;
+
+ if((s & 0x200) && !(s & 0x001)) {
+ // stop bit == '1', start bit == '0'
+ uint8_t b = (s >> 1);
+ Demod.output[Demod.len] = b;
+ ++Demod.len;
+ Demod.state = DEMOD_AWAITING_START_BIT;
+ } else {
+ Demod.state = DEMOD_UNSYNCD;
+ LED_C_OFF();
+
+ if(s == 0x000) {
+ // This is EOF (start, stop and all data bits == '0'
+ return TRUE;
+ }
+ }
+ }
+ Demod.posCount = 0;
+ }
+ break;
+
+ default:
+ Demod.state = DEMOD_UNSYNCD;
+ LED_C_OFF();
+ break;
+ }
+ return FALSE;
+}
+
+// Clear out the state of the "UART" that receives from the tag.
+static void DemodReset() {
+ Demod.len = 0;
+ Demod.state = DEMOD_UNSYNCD;
+ Demod.posCount = 0;
+ Demod.sumI = 0;
+ Demod.sumQ = 0;
+ Demod.bitCount = 0;
+ Demod.thisBit = 0;
+ Demod.shiftReg = 0;
+ memset(Demod.output, 0x00, MAX_FRAME_SIZE);
+}
+
+static void DemodInit(uint8_t *data) {
+ Demod.output = data;
+ DemodReset();
+}
+
+/*
+ * Demodulate the samples we received from the tag, also log to tracebuffer
+ * quiet: set to 'TRUE' to disable debug output
+ */
+ #define LEGIC_DMA_BUFFER_SIZE 256
+static void GetSamplesForLegicDemod(int n, bool quiet)
+{
+ int max = 0;
+ bool gotFrame = FALSE;
+ int lastRxCounter = LEGIC_DMA_BUFFER_SIZE;
+ int ci, cq, samples = 0;
+
+ BigBuf_free();
+
+ // And put the FPGA in the appropriate mode
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_RX_XCORR | FPGA_HF_READER_RX_XCORR_QUARTER_FREQ);
+
+ // The response (tag -> reader) that we're receiving.
+ // Set up the demodulator for tag -> reader responses.
+ DemodInit(BigBuf_malloc(MAX_FRAME_SIZE));
+
+ // The DMA buffer, used to stream samples from the FPGA
+ int8_t *dmaBuf = (int8_t*) BigBuf_malloc(LEGIC_DMA_BUFFER_SIZE);
+ int8_t *upTo = dmaBuf;
+
+ // Setup and start DMA.
+ if ( !FpgaSetupSscDma((uint8_t*) dmaBuf, LEGIC_DMA_BUFFER_SIZE) ){
+ if (MF_DBGLEVEL > 1) Dbprintf("FpgaSetupSscDma failed. Exiting");
+ return;
+ }
+
+ // Signal field is ON with the appropriate LED:
+ LED_D_ON();
+ for(;;) {
+ int behindBy = lastRxCounter - AT91C_BASE_PDC_SSC->PDC_RCR;
+ if(behindBy > max) max = behindBy;
+
+ while(((lastRxCounter-AT91C_BASE_PDC_SSC->PDC_RCR) & (LEGIC_DMA_BUFFER_SIZE-1)) > 2) {
+ ci = upTo[0];
+ cq = upTo[1];
+ upTo += 2;
+ if(upTo >= dmaBuf + LEGIC_DMA_BUFFER_SIZE) {
+ upTo = dmaBuf;
+ AT91C_BASE_PDC_SSC->PDC_RNPR = (uint32_t) upTo;
+ AT91C_BASE_PDC_SSC->PDC_RNCR = LEGIC_DMA_BUFFER_SIZE;
+ }
+ lastRxCounter -= 2;
+ if(lastRxCounter <= 0)
+ lastRxCounter = LEGIC_DMA_BUFFER_SIZE;
+
+ samples += 2;
+
+ gotFrame = HandleLegicSamplesDemod(ci , cq );
+ if ( gotFrame )
+ break;
+ }
+
+ if(samples > n || gotFrame)
+ break;
+ }
+
+ FpgaDisableSscDma();
+
+ if (!quiet && Demod.len == 0) {
+ Dbprintf("max behindby = %d, samples = %d, gotFrame = %d, Demod.len = %d, Demod.sumI = %d, Demod.sumQ = %d",
+ max,
+ samples,
+ gotFrame,
+ Demod.len,
+ Demod.sumI,
+ Demod.sumQ
+ );
+ }
+
+ //Tracing
+ if (Demod.len > 0) {
+ uint8_t parity[MAX_PARITY_SIZE] = {0x00};
+ LogTrace(Demod.output, Demod.len, 0, 0, parity, FALSE);
+ }
+}
+//-----------------------------------------------------------------------------
+// Transmit the command (to the tag) that was placed in ToSend[].
+//-----------------------------------------------------------------------------
+static void TransmitForLegic(void)
+{
+ int c;
+
+ FpgaSetupSsc();
+
+ while(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY))
+ AT91C_BASE_SSC->SSC_THR = 0xff;
+
+ // Signal field is ON with the appropriate Red LED
+ LED_D_ON();
+
+ // Signal we are transmitting with the Green LED
+ LED_B_ON();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
+
+ for(c = 0; c < 10;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = 0xff;
+ c++;
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
+
+ c = 0;
+ for(;;) {
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
+ AT91C_BASE_SSC->SSC_THR = ToSend[c];
+ legic_prng_forward(1); // forward the lfsr
+ c++;
+ if(c >= ToSendMax) {
+ break;
+ }
+ }
+ if(AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
+ volatile uint32_t r = AT91C_BASE_SSC->SSC_RHR;
+ (void)r;
+ }
+ WDT_HIT();
+ }
+ LED_B_OFF();
+}
+
+
+//-----------------------------------------------------------------------------
+// Code a layer 2 command (string of octets, including CRC) into ToSend[],
+// so that it is ready to transmit to the tag using TransmitForLegic().
+//-----------------------------------------------------------------------------
+static void CodeLegicBitsAsReader(const uint8_t *cmd, int bits)
+{
+ int i, j;
+ uint8_t b;
+
+ ToSendReset();
+
+ // Send SOF
+ for(i = 0; i < 7; i++) {
+ ToSendStuffBit(1);
+ }
+
+ for(i = 0; i < bits; i++) {
+ // Start bit
+ ToSendStuffBit(0);
+
+ // Data bits
+ b = cmd[i];
+ for(j = 0; j < 8; j++) {
+ if(b & 1) {
+ ToSendStuffBit(1);
+ } else {
+ ToSendStuffBit(0);
+ }
+ b >>= 1;
+ }
+ }
+
+ // Convert from last character reference to length
+ ++ToSendMax;
+}
+
+/**
+ Convenience function to encode, transmit and trace Legic comms
+ **/
+static void CodeAndTransmitLegicAsReader(const uint8_t *cmd, int bits)
+{
+ CodeLegicBitsAsReader(cmd, bits);
+ TransmitForLegic();
+ if (tracing) {
+ uint8_t parity[1] = {0x00};
+ LogTrace(cmd, bits, 0, 0, parity, TRUE);
+ }
+}
+
+int ice_legic_select_card()
+{
+ //int cmd_size=0, card_size=0;
+ uint8_t wakeup[] = { 0x7F};
+ uint8_t getid[] = {0x19};
+
+ legic_prng_init(SESSION_IV);
+
+ // first, wake up the tag, 7bits
+ CodeAndTransmitLegicAsReader(wakeup, 7);
+
+ GetSamplesForLegicDemod(1000, TRUE);
+
+ // frame_clean(¤t_frame);
+ //frame_receive_rwd(¤t_frame, 6, 1);
+
+ legic_prng_forward(1); /* we wait anyways */
+
+ //while(timer->TC_CV < 387) ; /* ~ 258us */
+ //frame_send_rwd(0x19, 6);
+ CodeAndTransmitLegicAsReader(getid, sizeof(getid));
+ GetSamplesForLegicDemod(1000, TRUE);
+
+ //if (Demod.len < 14) return 2;
+ Dbprintf("CARD TYPE: %02x LEN: %d", Demod.output[0], Demod.len);
+
+ switch(Demod.output[0]) {
+ case 0x1d:
+ DbpString("MIM 256 card found");
+ // cmd_size = 9;
+ // card_size = 256;
+ break;
+ case 0x3d:
+ DbpString("MIM 1024 card found");
+ // cmd_size = 11;
+ // card_size = 1024;
+ break;
+ default:
+ return -1;
+ }
+
+ // if(bytes == -1)
+ // bytes = card_size;
+
+ // if(bytes + offset >= card_size)
+ // bytes = card_size - offset;
+
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
+ set_tracing(FALSE);
+ return 1;
+}
+
+// Set up LEGIC communication
+void ice_legic_setup() {
+
+ // standard things.
+ FpgaDownloadAndGo(FPGA_BITSTREAM_HF);
+ BigBuf_free(); BigBuf_Clear_ext(false);
+ clear_trace();
+ set_tracing(TRUE);
+ DemodReset();
+ UartReset();
+
+ // Set up the synchronous serial port
+ FpgaSetupSsc();
+
+ // connect Demodulated Signal to ADC:
+ SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
+
+ // Signal field is on with the appropriate LED
+ LED_D_ON();
+ FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX | FPGA_HF_READER_TX_SHALLOW_MOD);
+ SpinDelay(200);
+ // Start the timer
+ //StartCountSspClk();
+
+ // initalize CRC
+ crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0);
+
+ // initalize prng
+ legic_prng_init(0);
+}
\ No newline at end of file
extern void LegicRfSimulate(int phase, int frame, int reqresp);
extern int LegicRfReader(int bytes, int offset);
extern void LegicRfWriter(int bytes, int offset);
+extern void LegicRfRawWriter(int offset, int bytes);
+
+int ice_legic_select_card();
+void ice_legic_setup();
#endif /* __LEGICRF_H */
#include <stddef.h>
#include <stdint.h>
#include "common.h"
+#include "string.h"
+#include "apps.h"
+#include "BigBuf.h"
+#include "proxmark3.h"
#define BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
#define BUTTON_DOUBLE_CLICK -2
#define BUTTON_ERROR -99
+#ifndef BSWAP_16
+# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8)))
+#endif
+#ifndef BITMASK
+# define BITMASK(X) (1 << (X))
+#endif
+
void print_result(char *name, uint8_t *buf, size_t len);
size_t nbytes(size_t nbits);
uint32_t SwapBits(uint32_t value, int nrbits);
+uint32_t reflect(uint32_t v, int b);
void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len);
void rol(uint8_t *data, const size_t len);
//uint32_t RAMFUNC GetDeltaCountUS();
void StartCountSspClk();
+void ResetSspClk(void);
uint32_t RAMFUNC GetCountSspClk();
#endif
//-----------------------------------------------------------------------------
// High frequency Legic commands
//-----------------------------------------------------------------------------
-
-#include <stdio.h>
-#include <string.h>
-#include "proxmark3.h"
-#include "data.h"
-#include "ui.h"
-#include "cmdparser.h"
#include "cmdhflegic.h"
-#include "cmdmain.h"
-#include "util.h"
-#include "crc.h"
+
static int CmdHelp(const char *Cmd);
int usage_legic_calccrc8(void){
- PrintAndLog("Calculates the legic crc8 on the input hexbytes.");
+ PrintAndLog("Calculates the legic crc8/crc16 on the input hexbytes.");
PrintAndLog("There must be an even number of hexsymbols as input.");
- PrintAndLog("Usage: hf legic crc8 <hexbytes>");
+ PrintAndLog("Usage: hf legic crc8 [h] b <hexbytes> u <uidcrc>");
PrintAndLog("Options :");
- PrintAndLog(" <hexbytes> : hex bytes in a string");
+ PrintAndLog(" b <hexbytes> : hex bytes");
+ PrintAndLog(" u <uidcrc> : MCC hexbyte");
PrintAndLog("");
- PrintAndLog("Sample : hf legic crc8 deadbeef1122");
+ PrintAndLog("Samples :");
+ PrintAndLog(" hf legic crc8 b deadbeef1122");
+ PrintAndLog(" hf legic crc8 b deadbeef1122 u 9A");
return 0;
}
int crc = 0;
int wrp = 0;
int wrc = 0;
- uint8_t data_buf[1024]; // receiver buffer, should be 1024..
- char token_type[4];
+ uint8_t data_buf[1052]; // receiver buffer, should be 1024..
+ char token_type[5];
+ int dcf;
+ int bIsSegmented = 0;
// download EML memory, where the "legic read" command puts the data.
GetEMLFromBigBuf(data_buf, sizeof(data_buf), 0);
(calc_crc == crc) ? "OK":"Fail"
);
+
+ token_type[0] = 0;
+ dcf = ((int)data_buf[6] << 8) | (int)data_buf[5];
+
+ // New unwritten media?
+ if(dcf == 0xFFFF) {
+
+ PrintAndLog("DCF: %d (%02x %02x), Token Type=NM (New Media)",
+ dcf,
+ data_buf[5],
+ data_buf[6]
+ );
+
+ } else if(dcf > 60000) { // Master token?
+
+ int fl = 0;
+
+ if(data_buf[6] == 0xec) {
+ strncpy(token_type, "XAM", sizeof(token_type));
+ fl = 1;
+ stamp_len = 0x0c - (data_buf[5] >> 4);
+ } else {
switch (data_buf[5] & 0x7f) {
case 0x00 ... 0x2f:
strncpy(token_type, "IAM",sizeof(token_type));
+ fl = (0x2f - (data_buf[5] & 0x7f)) + 1;
break;
case 0x30 ... 0x6f:
strncpy(token_type, "SAM",sizeof(token_type));
+ fl = (0x6f - (data_buf[5] & 0x7f)) + 1;
break;
case 0x70 ... 0x7f:
strncpy(token_type, "GAM",sizeof(token_type));
- break;
- default:
- strncpy(token_type, "???",sizeof(token_type));
+ fl = (0x7f - (data_buf[5] & 0x7f)) + 1;
break;
}
stamp_len = 0xfc - data_buf[6];
+ }
- PrintAndLog("DCF: %02x %02x, Token Type=%s (OLE=%01u), Stamp len=%02u",
+ PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u), OL=%02u, FL=%02u",
+ dcf,
data_buf[5],
data_buf[6],
token_type,
(data_buf[5]&0x80)>>7,
- stamp_len
+ stamp_len,
+ fl
);
- PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, raw=%02x, SSC=%02x",
+ } else { // Is IM(-S) type of card...
+
+ if(data_buf[7] == 0x9F && data_buf[8] == 0xFF) {
+ bIsSegmented = 1;
+ strncpy(token_type, "IM-S", sizeof(token_type));
+ } else {
+ strncpy(token_type, "IM", sizeof(token_type));
+ }
+
+ PrintAndLog("DCF: %d (%02x %02x), Token Type=%s (OLE=%01u)",
+ dcf,
+ data_buf[5],
+ data_buf[6],
+ token_type,
+ (data_buf[5]&0x80)>>7
+ );
+ }
+
+ // Makes no sence to show this on blank media...
+ if(dcf != 0xFFFF) {
+
+ if(bIsSegmented) {
+ PrintAndLog("WRP=%02u, WRC=%01u, RD=%01u, SSC=%02x",
data_buf[7]&0x0f,
(data_buf[7]&0x70)>>4,
(data_buf[7]&0x80)>>7,
- data_buf[7],
data_buf[8]
);
+ }
+ // Header area is only available on IM-S cards, on master tokens this data is the master token data itself
+ if(bIsSegmented || dcf > 60000) {
+ if(dcf > 60000) {
+ PrintAndLog("Master token data");
+ PrintAndLog("%s", sprint_hex(data_buf+8, 14));
+ } else {
PrintAndLog("Remaining Header Area");
PrintAndLog("%s", sprint_hex(data_buf+9, 13));
+ }
+ }
+ }
+
uint8_t segCrcBytes[8] = {0x00};
uint32_t segCalcCRC = 0;
uint32_t segCRC = 0;
- // see if user area is xored or just zeros.
- int numOfZeros = 0;
- for (int index=22; index < 256; ++index){
- if ( data_buf[index] == 0x00 )
- ++numOfZeros;
- }
- // if possible zeros is less then 60%, lets assume data is xored
- // 256 - 22 (header) = 234
- // 1024 - 22 (header) = 1002
- int isXored = (numOfZeros*100/stamp_len) < 50;
- PrintAndLog("is data xored? %d ( %d %)", isXored, (numOfZeros*100/stamp_len));
- print_hex_break( data_buf, 33, 16);
-
- return 0;
+ // Data card?
+ if(dcf <= 60000) {
PrintAndLog("\nADF: User Area");
PrintAndLog("------------------------------------------------------");
+
+ if(bIsSegmented) {
+
+ // Data start point on segmented cards
i = 22;
- // 64 potential segements
- // how to detect there is no segments?!?
- for ( segmentNum=0; segmentNum<64; segmentNum++ ) {
+
+ // decode segments
+ for (segmentNum=1; segmentNum < 128; segmentNum++ )
+ {
segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc);
segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4;
-
wrp = (data_buf[i+2]^crc);
wrc = ((data_buf[i+3]^crc)&0x70)>>4;
PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
PrintAndLog("\nrow | data");
PrintAndLog("-----+------------------------------------------------");
- // de-xor? if not zero, assume it needs xoring.
- if ( isXored) {
- for ( k=i; k < wrc; ++k)
+
+ for ( k=i; k < (i+wrc); ++k)
data_buf[k] ^= crc;
- }
+
print_hex_break( data_buf+i, wrc, 16);
i += wrc;
PrintAndLog("\nrow | data");
PrintAndLog("-----+------------------------------------------------");
- if (isXored) {
- for (k=i; k < wrp_len; ++k)
+ for (k=i; k < (i+wrp_len); ++k)
data_buf[k] ^= crc;
- }
print_hex_break( data_buf+i, wrp_len, 16);
i += wrp_len;
- // does this one work?
+ // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
if( wrp_len == 8 )
PrintAndLog("Card ID: %2X%02X%02X", data_buf[i-4]^crc, data_buf[i-3]^crc, data_buf[i-2]^crc);
}
PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
PrintAndLog("\nrow | data");
PrintAndLog("-----+------------------------------------------------");
- if ( isXored ) {
- for ( k=i; k < remain_seg_payload_len; ++k)
+
+ for ( k=i; k < (i+remain_seg_payload_len); ++k)
data_buf[k] ^= crc;
- }
print_hex_break( data_buf+i, remain_seg_payload_len, 16);
if (segment_flag & 0x8) return 0;
} // end for loop
+
+ } else {
+
+ // Data start point on unsegmented cards
+ i = 8;
+
+ wrp = data_buf[7] & 0x0F;
+ wrc = (data_buf[7] & 0x07) >> 4;
+
+ bool hasWRC = (wrc > 0);
+ bool hasWRP = (wrp > wrc);
+ int wrp_len = (wrp - wrc);
+ int remain_seg_payload_len = (1024 - 22 - wrp); // Any chance to get physical card size here!?
+
+ PrintAndLog("Unsegmented card - WRP: %02u, WRC: %02u, RD: %01u",
+ wrp,
+ wrc,
+ (data_buf[7] & 0x80) >> 7
+ );
+
+ if ( hasWRC ) {
+ PrintAndLog("WRC protected area: (I %d | WRC %d)", i, wrc);
+ PrintAndLog("\nrow | data");
+ PrintAndLog("-----+------------------------------------------------");
+ print_hex_break( data_buf+i, wrc, 16);
+ i += wrc;
+ }
+
+ if ( hasWRP ) {
+ PrintAndLog("Remaining write protected area: (I %d | WRC %d | WRP %d | WRP_LEN %d)", i, wrc, wrp, wrp_len);
+ PrintAndLog("\nrow | data");
+ PrintAndLog("-----+------------------------------------------------");
+ print_hex_break( data_buf+i, wrp_len, 16);
+ i += wrp_len;
+
+ // does this one work? (Answer: Only if KGH/BGH is used with BCD encoded card number! So maybe this will show just garbage...)
+ if( wrp_len == 8 )
+ PrintAndLog("Card ID: %2X%02X%02X", data_buf[i-4], data_buf[i-3], data_buf[i-2]);
+ }
+
+ PrintAndLog("Remaining segment payload: (I %d | Remain LEN %d)", i, remain_seg_payload_len);
+ PrintAndLog("\nrow | data");
+ PrintAndLog("-----+------------------------------------------------");
+ print_hex_break( data_buf+i, remain_seg_payload_len, 16);
+ i += remain_seg_payload_len;
+
+ PrintAndLog("-----+------------------------------------------------\n");
+ }
+ }
+
return 0;
}
return 0;
}
+//TODO: write a help text (iceman)
+int CmdLegicRfRawWrite(const char *Cmd) {
+ char answer;
+ UsbCommand c = { CMD_RAW_WRITER_LEGIC_RF, {0,0,0} };
+ int res = sscanf(Cmd, " 0x%"llx" 0x%"llx, &c.arg[0], &c.arg[1]);
+ if(res != 2) {
+ PrintAndLog("Please specify the offset and value as two hex strings");
+ return -1;
+ }
+
+ if (c.arg[0] == 0x05 || c.arg[0] == 0x06) {
+ PrintAndLog("############# DANGER !! #############");
+ PrintAndLog("# changing the DCF is irreversible #");
+ PrintAndLog("#####################################");
+ PrintAndLog("do youe really want to continue? y(es) n(o)");
+ scanf(" %c", &answer);
+ if (answer == 'y' || answer == 'Y') {
+ SendCommand(&c);
+ return 0;
+ }
+ return -1;
+ }
+
+ clearCommandBuffer();
+ SendCommand(&c);
+ return 0;
+}
+
+//TODO: write a help text (iceman)
int CmdLegicRfFill(const char *Cmd) {
- UsbCommand cmd = {CMD_WRITER_LEGIC_RF};
+ UsbCommand cmd = {CMD_WRITER_LEGIC_RF, {0,0,0} };
int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
if(res != 3) {
PrintAndLog("Please specify the offset, length and value as two hex strings");
int i;
UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
- for(i = 0; i < 48; i++) {
- c.d.asBytes[i] = cmd.arg[2];
- }
-
+ memcpy(c.d.asBytes, cmd.arg[2], 48);
+
for(i = 0; i < 22; i++) {
c.arg[0] = i*48;
+
+ clearCommandBuffer();
SendCommand(&c);
- WaitForResponse(CMD_ACK,NULL);
+ WaitForResponse(CMD_ACK, NULL);
}
clearCommandBuffer();
SendCommand(&cmd);
int CmdLegicCalcCrc8(const char *Cmd){
- int len = strlen(Cmd);
- if ( len & 1 ) return usage_legic_calccrc8();
+ uint8_t *data;
+ uint8_t cmdp = 0, uidcrc = 0, type=0;
+ bool errors = false;
+ int len = 0;
- // add 1 for null terminator.
- uint8_t *data = malloc(len+1);
- if ( data == NULL ) return 1;
-
- if (param_gethex(Cmd, 0, data, len )) {
- free(data);
- return usage_legic_calccrc8();
+ while(param_getchar(Cmd, cmdp) != 0x00) {
+ switch(param_getchar(Cmd, cmdp)) {
+ case 'b':
+ case 'B':
+ data = malloc(len);
+ if ( data == NULL ) {
+ PrintAndLog("Can't allocate memory. exiting");
+ errors = true;
+ break;
+ }
+ param_gethex_ex(Cmd, cmdp+1, data, &len);
+ // if odd symbols, (hexbyte must be two symbols)
+ if ( len & 1 ) errors = true;
+
+ len >>= 1;
+ cmdp += 2;
+ break;
+ case 'u':
+ case 'U':
+ uidcrc = param_get8ex(Cmd, cmdp+1, 0, 16);
+ cmdp += 2;
+ break;
+ case 'c':
+ case 'C':
+ type = param_get8ex(Cmd, cmdp+1, 0, 10);
+ cmdp += 2;
+ break;
+ case 'h':
+ case 'H':
+ errors = true;
+ break;
+ default:
+ PrintAndLog("Unknown parameter '%c'", param_getchar(Cmd, cmdp));
+ errors = true;
+ break;
+ }
+ if (errors) break;
+ }
+ //Validations
+ if (errors){
+ if (data != NULL) free(data);
+ return usage_legic_calccrc8();
+ }
+
+ switch (type){
+ case 16:
+ PrintAndLog("LEGIC CRC16: %X", CRC16Legic(data, len, uidcrc));
+ break;
+ default:
+ PrintAndLog("LEGIC CRC8: %X", CRC8Legic(data, len) );
+ break;
}
- uint32_t checksum = CRC8Legic(data, len/2);
- PrintAndLog("Bytes: %s || CRC8: %X", sprint_hex(data, len/2), checksum );
free(data);
return 0;
}
{"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
{"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"},
{"write", CmdLegicRfWrite,0, "<offset> <length> -- Write sample buffer (user after load or read)"},
+ {"writeRaw",CmdLegicRfRawWrite, 0, "<address> <value> -- Write direct to address"},
{"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
{"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
{NULL, NULL, 0, NULL}
#ifndef CMDHFLEGIC_H__
#define CMDHFLEGIC_H__
+#include <stdio.h>
+#include <string.h>
+#include "proxmark3.h"
+#include "data.h"
+#include "ui.h"
+#include "cmdparser.h"
+#include "cmdmain.h"
+#include "util.h"
+#include "crc.h"
+
int CmdHFLegic(const char *Cmd);
int CmdLegicRFRead(const char *Cmd);
int CmdLegicSave(const char *Cmd);
int CmdLegicRfSim(const char *Cmd);
int CmdLegicRfWrite(const char *Cmd);
+int CmdLegicRfRawWrite(const char *Cmd);
int CmdLegicRfFill(const char *Cmd);
int CmdLegicCalcCrc8(const char *Cmd);
int usage_legic_calccrc8(void);
+int usage_legic_load(void);
+int usage_legic_read(void);
#endif
//-----------------------------------------------------------------------------
#include "util.h"
-#include "proxmark3.h"
#define MAX_BIN_BREAK_LENGTH (3072+384+1)
#ifndef _WIN32
#include <termios.h>
#include <sys/ioctl.h>
-int ukbhit(void)
-{
+int ukbhit(void) {
int cnt = 0;
int error;
static struct termios Otty, Ntty;
newvalue ^= ((value >> i) & 1) << (nrbits - 1 - i);
}
return newvalue;
-}
\ No newline at end of file
+}
+/*
+ ref http://www.csm.ornl.gov/~dunigan/crc.html
+ Returns the value v with the bottom b [0,32] bits reflected.
+ Example: reflect(0x3e23L,3) == 0x3e26
+*/
+uint32_t reflect(uint32_t v, int b) {
+ uint32_t t = v;
+ for ( int i = 0; i < b; ++i) {
+ if (t & 1)
+ v |= BITMASK((b-1)-i);
+ else
+ v &= ~BITMASK((b-1)-i);
+ t>>=1;
+ }
+ return v;
+}
#include <ctype.h>
#include <time.h>
#include "data.h" //for FILE_PATH_SIZE
+#include "proxmark3.h"
+#ifndef BITMASK
+# define BITMASK(X) (1 << (X))
+#endif
#ifndef ROTR
# define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n))))
#endif
# define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef BSWAP_32
-#define BSWAP_32(x) \
+# define BSWAP_32(x) \
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
#endif
+#ifndef BSWAP_16
+# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8)))
+#endif
+
#define TRUE 1
#define FALSE 0
#define EVEN 0
uint32_t le32toh (uint8_t *data);
uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits);
void rol(uint8_t *data, const size_t len);
-uint32_t SwapBits(uint32_t value, int nrbits);
\ No newline at end of file
+uint32_t SwapBits(uint32_t value, int nrbits);
+uint32_t reflect(uint32_t v, int b);
\ No newline at end of file
#include "bucketsort.h"
-void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop,
+extern void bucket_sort_intersect(uint32_t* const estart, uint32_t* const estop,
uint32_t* const ostart, uint32_t* const ostop,
bucket_info_t *bucket_info, bucket_array_t bucket)
{
#ifndef BUCKETSORT_H__
#define BUCKETSORT_H__
+
#include <stdint.h>
#include <stdlib.h>
+
typedef struct bucket {
uint32_t *head;
uint32_t *bp;
//-----------------------------------------------------------------------------
// Generic CRC calculation code.
//-----------------------------------------------------------------------------
+// the Check value below in the comments is CRC of the string '123456789'
+//
#include "crc.h"
-#include "util.h"
-#include <stdint.h>
-#include <stddef.h>
-void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor)
-{
+void crc_init_ref(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor, bool refin, bool refout) {
+ crc_init(crc, order, polynom, initial_value, final_xor);
+ crc->refin = refin;
+ crc->refout = refout;
+ crc_clear(crc);
+}
+
+void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor) {
crc->order = order;
+ crc->topbit = BITMASK( order-1 );
crc->polynom = polynom;
crc->initial_value = initial_value;
crc->final_xor = final_xor;
crc->mask = (1L<<order)-1;
+ crc->refin = FALSE;
+ crc->refout = FALSE;
crc_clear(crc);
}
-void crc_update(crc_t *crc, uint32_t data, int data_width)
-{
- for( int i=0; i < data_width; i++) {
- int oldstate = crc->state;
- crc->state = crc->state >> 1;
- if( (oldstate^data) & 1 ) {
- crc->state ^= crc->polynom;
- }
- data >>= 1;
+void crc_clear(crc_t *crc) {
+ crc->state = crc->initial_value & crc->mask;
+ if (crc->refin)
+ crc->state = reflect(crc->state, crc->order);
+}
+
+void crc_update(crc_t *crc, uint32_t indata, int data_width){
+
+ //reflected
+ if (crc->refin) indata = reflect(indata, data_width);
+
+ // Bring the next byte into the remainder.
+ crc->state ^= indata << (crc->order - data_width);
+
+ for( uint8_t bit = data_width; bit > 0; --bit) {
+ // Try to divide the current data bit.
+ if (crc->state & crc->topbit)
+ crc->state = (crc->state << 1) ^ crc->polynom;
+ else
+ crc->state = (crc->state << 1);
}
}
-void crc_clear(crc_t *crc)
-{
- crc->state = crc->initial_value & crc->mask;
+uint32_t crc_finish(crc_t *crc) {
+ uint32_t val = crc->state;
+ if (crc->refout) val = reflect(val, crc->order);
+ return ( val ^ crc->final_xor ) & crc->mask;
}
-uint32_t crc_finish(crc_t *crc)
-{
- return ( crc->state ^ crc->final_xor ) & crc->mask;
+/*
+static void print_crc(crc_t *crc) {
+ printf(" Order %d\n Poly %x\n Init %x\n Final %x\n Mask %x\n topbit %x\n RefIn %s\n RefOut %s\n State %x\n",
+ crc->order,
+ crc->polynom,
+ crc->initial_value,
+ crc->final_xor,
+ crc->mask,
+ crc->topbit,
+ (crc->refin) ? "TRUE":"FALSE",
+ (crc->refout) ? "TRUE":"FALSE",
+ crc->state
+ );
}
+*/
-//credits to iceman
+// width=8 poly=0x31 init=0x00 refin=true refout=true xorout=0x00 check=0xA1 name="CRC-8/MAXIM"
uint32_t CRC8Maxim(uint8_t *buff, size_t size) {
crc_t crc;
- crc_init(&crc, 9, 0x8c, 0x00, 0x00);
- crc_clear(&crc);
+ crc_init_ref(&crc, 8, 0x31, 0, 0, TRUE, TRUE);
+ for ( int i=0; i < size; ++i)
+ crc_update(&crc, buff[i], 8);
+ return crc_finish(&crc);
+}
+
- for (size_t i=0; i < size; ++i)
+// width=4 poly=0xC, reversed poly=0x7 init=0x5 refin=true refout=true xorout=0x0000 check= name="CRC-4/LEGIC"
+// width=8 poly=0x63, reversed poly=0x8D init=0x55 refin=true refout=true xorout=0x0000 check=0xC6 name="CRC-8/LEGIC"
+// the CRC needs to be reversed before returned.
+uint32_t CRC8Legic(uint8_t *buff, size_t size) {
+ crc_t crc;
+ crc_init_ref(&crc, 8, 0x63, 0x55, 0, TRUE, TRUE);
+ for ( int i = 0; i < size; ++i)
crc_update(&crc, buff[i], 8);
+ return reflect(crc_finish(&crc), 8);
+}
+// credits to marshmellow
+// width=8 poly=0xA3, reversed poly=0x8B, init=0xB0 refin=true refout=true xorout=0x00 check=0x28 name="CRC-8/JA"
+uint32_t CRC8ja(uint8_t *buff, size_t size) {
+ crc_t crc;
+ crc_init_ref(&crc, 8, 0xA3, 0x42, 0x00, TRUE, TRUE);
+ for ( int i=0; i < size; ++i)
+ crc_update(&crc, buff[i], 8);
return crc_finish(&crc);
+ //return reflect(crc_finish(&crc), 8);
}
-//credits to iceman
-uint32_t CRC8Legic(uint8_t *buff, size_t size) {
+// This CRC-16 is used in Legic Advant systems.
+// width=8 poly=0xB400, reversed poly=0x init=depends refin=true refout=true xorout=0x0000 check= name="CRC-16/LEGIC"
+uint32_t CRC16Legic(uint8_t *buff, size_t size, uint8_t uidcrc) {
- // Poly 0x63, reversed poly 0xC6, Init 0x55, Final 0x00
+ #define CRC16_POLY_LEGIC 0xB400
+ //uint8_t initial = reflect(uidcrc, 8);
+ uint16_t initial = uidcrc;
+ initial |= initial << 8;
crc_t crc;
- crc_init(&crc, 8, 0xC6, 0x55, 0);
- crc_clear(&crc);
-
- for ( int i = 0; i < size; ++i)
+ crc_init_ref(&crc, 16, CRC16_POLY_LEGIC, initial, 0, TRUE, TRUE);
+ for ( int i=0; i < size; ++i)
crc_update(&crc, buff[i], 8);
- return SwapBits(crc_finish(&crc), 8);
+ return reflect(crc_finish(&crc), 16);
}
+//w=16 poly=0x3d65 init=0x0000 refin=true refout=true xorout=0xffff check=0xea82 name="CRC-16/DNP"
+uint32_t CRC16_DNP(uint8_t *buff, size_t size) {
+ crc_t crc;
+ crc_init_ref(&crc, 16, 0x3d65, 0, 0xffff, TRUE, TRUE);
+ for ( int i=0; i < size; ++i)
+ crc_update(&crc, buff[i], 8);
+
+ return BSWAP_16(crc_finish(&crc));
+}
+//width=16 poly=0x1021 init=0x1d0f refin=false refout=false xorout=0x0000 check=0xe5cc name="CRC-16/AUG-CCITT"
+uint32_t CRC16_CCITT(uint8_t *buff, size_t size) {
+ crc_t crc;
+ crc_init(&crc, 16, 0x1021, 0x1d0f, 0);
+ for ( int i=0; i < size; ++i)
+ crc_update(&crc, buff[i], 8);
+ return crc_finish(&crc);
+}
\ No newline at end of file
#ifndef __CRC_H
#define __CRC_H
-#include <stdint.h>
+#include <stdint.h> //uint32+
+#include <stdbool.h> //bool
#include <stddef.h>
+#include "util.h" // reflect, bswap_16
typedef struct crc {
uint32_t state;
uint32_t initial_value;
uint32_t final_xor;
uint32_t mask;
+ int topbit;
+ bool refin; /* Parameter: Reflect input bytes? */
+ bool refout; /* Parameter: Reflect output CRC? */
} crc_t;
+/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32
+ * polynom is the CRC polynom. initial_value is the initial value of a clean state.
+ * final_xor is XORed onto the state before returning it from crc_result().
+ * refin is the setting for reversing (bitwise) the bytes during crc
+ * refot is the setting for reversing (bitwise) the crc byte before returning it.
+ */
+extern void crc_init_ref(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor, bool refin, bool refout);
+
/* Initialize a crc structure. order is the order of the polynom, e.g. 32 for a CRC-32
* polynom is the CRC polynom. initial_value is the initial value of a clean state.
* final_xor is XORed onto the state before returning it from crc_result(). */
extern void crc_init(crc_t *crc, int order, uint32_t polynom, uint32_t initial_value, uint32_t final_xor);
+
/* Update the crc state. data is the data of length data_width bits (only the
* data_width lower-most bits are used).
*/
// Calculate CRC-8/Maxim checksum
uint32_t CRC8Maxim(uint8_t *buff, size_t size);
+// Calculate CRC-4/Legic checksum
+uint32_t CRC4Legic(uint8_t *buff, size_t size);
+
// Calculate CRC-8/Legic checksum
uint32_t CRC8Legic(uint8_t *buff, size_t size);
+// Calculate CRC-16/Legic checksum
+// the initial_value is based on the previous legic_Crc8 of the UID.
+// ie: uidcrc = 0x78 then initial_value == 0x7878
+uint32_t CRC16Legic(uint8_t *buff, size_t size, uint8_t uidcrc);
+
+// Calculate CRC-8/ja checksum
+uint32_t CRC8ja(uint8_t *buff, size_t size);
+
+// test crc 16.
+uint32_t CRC16_DNP(uint8_t *buff, size_t size);
+
+
/* Static initialization of a crc structure */
#define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \
.state = ((_initial_value) & ((1L<<(_order))-1)), \
.polynom = (_polynom), \
.initial_value = (_initial_value), \
.final_xor = (_final_xor), \
- .mask = ((1L<<(_order))-1) }
+ .mask = ((1L<<(_order))-1) \
+ .refin = FALSE, \
+ .refout = FALSE \
+ }
#endif /* __CRC_H */
#include "crc16.h"
#define CRC16_POLY_CCITT 0x1021
#define CRC16_POLY 0x8408
-#define CRC16_POLY_LEGIC 0xB400
-unsigned short update_crc16( unsigned short crc, unsigned char c )
-{
- unsigned short i, v, tcrc = 0;
+uint16_t update_crc16( uint16_t crc, unsigned char c ) {
+ uint16_t i, v, tcrc = 0;
v = (crc ^ c) & 0xff;
for (i = 0; i < 8; i++) {
if (length == 0)
return (~remainder);
- for (int byte = 0; byte < length; ++byte) {
- remainder ^= (message[byte] << 8);
+ for (uint32_t i = 0; i < length; ++i) {
+ remainder ^= (message[i] << 8);
for (uint8_t bit = 8; bit > 0; --bit) {
if (remainder & 0x8000) {
remainder = (remainder << 1) ^ polynomial;
}
uint16_t crc16_ccitt_kermit(uint8_t const *message, int length) {
- return bit_reverse_uint16(crc16(message, length, 0x0000, CRC16_POLY_CCITT));
-}
-
-//ICEMAN: not working yet,
-// This CRC-16 is used in Legic Advant systems.
-uint16_t crc16_legic(uint8_t const *message, int length, uint16_t inital) {
- return crc16(message, length, inital, CRC16_POLY_LEGIC);
-}
-
-uint16_t bit_reverse_uint16 (uint16_t value) {
- const uint16_t mask0 = 0x5555;
- const uint16_t mask1 = 0x3333;
- const uint16_t mask2 = 0x0F0F;
- const uint16_t mask3 = 0x00FF;
-
- value = (((~mask0) & value) >> 1) | ((mask0 & value) << 1);
- value = (((~mask1) & value) >> 2) | ((mask1 & value) << 2);
- value = (((~mask2) & value) >> 4) | ((mask2 & value) << 4);
- value = (((~mask3) & value) >> 8) | ((mask3 & value) << 8);
-
- return value;
+ uint16_t val = crc16(message, length, 0x0000, CRC16_POLY_CCITT);
+ return SwapBits(val, 16);
}
//-----------------------------------------------------------------------------
// CRC16
//-----------------------------------------------------------------------------
-#include <stdint.h>
-
#ifndef __CRC16_H
#define __CRC16_H
+
+#include <stdint.h>
+#include "util.h"
+
unsigned short update_crc16(unsigned short crc, unsigned char c);
uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t polynomial);
uint16_t crc16_ccitt(uint8_t const *message, int length);
uint16_t crc16_ccitt_kermit(uint8_t const *message, int length);
-uint16_t crc16_legic(uint8_t const *message, int length, uint16_t inital);
-uint16_t bit_reverse_uint16 (uint16_t value);
#endif
#ifndef __CRC32_H
#define __CRC32_H
-void crc32 (const uint8_t *data, const size_t len, uint8_t *crc);
-void crc32_append (uint8_t *data, const size_t len);
+void crc32 (const uint8_t *data, const size_t len, uint8_t *crc);
+void crc32_append (uint8_t *data, const size_t len);
#endif
void crc64 (const uint8_t *data, const size_t len, uint64_t *crc) {
- for (size_t i = 0; i < len; i++)
- {
- //uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff;
+ for (size_t i = 0; i < len; i++) {
uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff;
*crc = crc64_table[tableIndex] ^ (*crc << 8);
}