CHG: merged the forum user @jason 's fixes to LEGIC. *UNTESTED*

CHG: changed the CRC implementations.
This commit is contained in:
iceman1001 2016-07-28 21:41:44 +02:00
parent 83dad64b91
commit 3e134b4c20
16 changed files with 1368 additions and 163 deletions

View file

@ -1058,6 +1058,10 @@ void UsbPacketReceived(uint8_t *packet, int len)
LegicRfWriter(c->arg[1], c->arg[0]); LegicRfWriter(c->arg[1], c->arg[0]);
break; break;
case CMD_RAW_WRITER_LEGIC_RF:
LegicRfRawWriter(c->arg[0], c->arg[1]);
break;
case CMD_READER_LEGIC_RF: case CMD_READER_LEGIC_RF:
LegicRfReader(c->arg[0], c->arg[1]); LegicRfReader(c->arg[0], c->arg[1]);
break; break;

View file

@ -325,12 +325,11 @@ static void LegicCommonInit(void) {
crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0); crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0);
} }
/* Switch off carrier, make sure tag is reset */
static void switch_off_tag_rwd(void) static void switch_off_tag_rwd(void)
{ {
/* Switch off carrier, make sure tag is reset */
AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT; AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT;
SpinDelay(10); SpinDelay(10);
WDT_HIT(); WDT_HIT();
} }
/* calculate crc for a legic command */ /* calculate crc for a legic command */
@ -372,11 +371,12 @@ int legic_read_byte(int byte_index, int cmd_sz) {
* * wait until the tag sends back an ACK ('1' bit unencrypted) * * wait until the tag sends back an ACK ('1' bit unencrypted)
* * forward the prng based on the timing * * 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) { int legic_write_byte(int byte, int addr, int addr_sz) {
//do not write UID, CRC, DCF //do not write UID, CRC
if(addr <= 0x06) if(addr <= 0x04) {
return 0; return 0;
}
//== send write command ============================== //== send write command ==============================
crc_clear(&legic_crc); crc_clear(&legic_crc);
crc_update(&legic_crc, 0, 1); /* CMD_WRITE */ crc_update(&legic_crc, 0, 1); /* CMD_WRITE */
@ -390,10 +390,13 @@ int legic_write_byte(int byte, int addr, int addr_sz) {
|(0x00 <<0)); //CMD = W |(0x00 <<0)); //CMD = W
uint32_t cmd_sz = addr_sz+1+8+4; //crc+data+cmd 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 */ while(timer->TC_CV < 387) ; /* ~ 258us */
frame_send_rwd(cmd, cmd_sz); 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 ==================================== //== wait for ack ====================================
int t, old_level=0, edges=0; int t, old_level=0, edges=0;
int next_bit_at =0; int next_bit_at =0;
@ -413,7 +416,7 @@ int legic_write_byte(int byte, int addr, int addr_sz) {
int c = t/TAG_TIME_BIT; int c = t/TAG_TIME_BIT;
timer->TC_CCR = AT91C_TC_SWTRG; timer->TC_CCR = AT91C_TC_SWTRG;
while(timer->TC_CV > 1) ; /* Wait till the clock has reset */ while(timer->TC_CV > 1) ; /* Wait till the clock has reset */
legic_prng_forward(c); legic_prng_forward(c-1);
return 0; return 0;
} }
} }
@ -423,6 +426,11 @@ int legic_write_byte(int byte, int addr, int addr_sz) {
} }
int LegicRfReader(int offset, int bytes) { 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; int byte_index=0, cmd_sz=0, card_sz=0;
LegicCommonInit(); LegicCommonInit();
@ -434,6 +442,11 @@ int LegicRfReader(int offset, int bytes) {
uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV); uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
switch_off_tag_rwd(); //we lose to mutch time with dprintf switch_off_tag_rwd(); //we lose to mutch time with dprintf
switch(tag_type) { switch(tag_type) {
case 0x0d:
DbpString("MIM22 card found, reading card ...");
cmd_sz = 6;
card_sz = 22;
break;
case 0x1d: case 0x1d:
DbpString("MIM256 card found, reading card ..."); DbpString("MIM256 card found, reading card ...");
cmd_sz = 9; cmd_sz = 9;
@ -479,6 +492,47 @@ int LegicRfReader(int offset, int bytes) {
return 0; 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) { void LegicRfWriter(int bytes, int offset) {
int byte_index=0, addr_sz=0; int byte_index=0, addr_sz=0;
uint8_t *BigBuf = BigBuf_get_addr(); uint8_t *BigBuf = BigBuf_get_addr();
@ -489,6 +543,14 @@ void LegicRfWriter(int bytes, int offset) {
uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV); uint32_t tag_type = perform_setup_phase_rwd(SESSION_IV);
switch_off_tag_rwd(); switch_off_tag_rwd();
switch(tag_type) { 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: case 0x1d:
if(offset+bytes > 0x100) { if(offset+bytes > 0x100) {
Dbprintf("Error: can not write to 0x%03.3x on MIM256", offset+bytes); Dbprintf("Error: can not write to 0x%03.3x on MIM256", offset+bytes);
@ -510,11 +572,27 @@ void LegicRfWriter(int bytes, int offset) {
return; return;
} }
#if 1
LED_B_ON(); LED_B_ON();
perform_setup_phase_rwd(SESSION_IV); perform_setup_phase_rwd(SESSION_IV);
legic_prng_forward(2);
while(byte_index < bytes) { 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()) { if((r != 0) || BUTTON_PRESS()) {
Dbprintf("operation aborted @ 0x%03.3x", byte_index); Dbprintf("operation aborted @ 0x%03.3x", byte_index);
switch_off_tag_rwd(); switch_off_tag_rwd();
@ -522,6 +600,76 @@ void LegicRfWriter(int bytes, int offset) {
LED_C_OFF(); LED_C_OFF();
return; 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(); WDT_HIT();
byte_index++; byte_index++;
if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF(); if(byte_index & 0x10) LED_C_ON(); else LED_C_OFF();
@ -756,3 +904,757 @@ void LegicRfSimulate(int phase, int frame, int reqresp)
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(&current_frame);
//frame_receive_rwd(&current_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);
}

View file

@ -14,5 +14,9 @@
extern void LegicRfSimulate(int phase, int frame, int reqresp); extern void LegicRfSimulate(int phase, int frame, int reqresp);
extern int LegicRfReader(int bytes, int offset); extern int LegicRfReader(int bytes, int offset);
extern void LegicRfWriter(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 */ #endif /* __LEGICRF_H */

View file

@ -14,6 +14,10 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include "common.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 BYTEx(x, n) (((x) >> (n * 8)) & 0xff )
@ -27,9 +31,17 @@
#define BUTTON_DOUBLE_CLICK -2 #define BUTTON_DOUBLE_CLICK -2
#define BUTTON_ERROR -99 #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); void print_result(char *name, uint8_t *buf, size_t len);
size_t nbytes(size_t nbits); size_t nbytes(size_t nbits);
uint32_t SwapBits(uint32_t value, int nrbits); 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); void num_to_bytes(uint64_t n, size_t len, uint8_t* dest);
uint64_t bytes_to_num(uint8_t* src, size_t len); uint64_t bytes_to_num(uint8_t* src, size_t len);
void rol(uint8_t *data, const size_t len); void rol(uint8_t *data, const size_t len);
@ -52,6 +64,7 @@ uint32_t RAMFUNC GetCountUS();
//uint32_t RAMFUNC GetDeltaCountUS(); //uint32_t RAMFUNC GetDeltaCountUS();
void StartCountSspClk(); void StartCountSspClk();
void ResetSspClk(void);
uint32_t RAMFUNC GetCountSspClk(); uint32_t RAMFUNC GetCountSspClk();
#endif #endif

View file

@ -7,27 +7,21 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// High frequency Legic commands // 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 "cmdhflegic.h"
#include "cmdmain.h"
#include "util.h"
#include "crc.h"
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
int usage_legic_calccrc8(void){ 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("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("Options :");
PrintAndLog(" <hexbytes> : hex bytes in a string"); PrintAndLog(" b <hexbytes> : hex bytes");
PrintAndLog(" u <uidcrc> : MCC hexbyte");
PrintAndLog(""); 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; return 0;
} }
@ -64,8 +58,10 @@ int CmdLegicDecode(const char *Cmd) {
int crc = 0; int crc = 0;
int wrp = 0; int wrp = 0;
int wrc = 0; int wrc = 0;
uint8_t data_buf[1024]; // receiver buffer, should be 1024.. uint8_t data_buf[1052]; // receiver buffer, should be 1024..
char token_type[4]; char token_type[5];
int dcf;
int bIsSegmented = 0;
// download EML memory, where the "legic read" command puts the data. // download EML memory, where the "legic read" command puts the data.
GetEMLFromBigBuf(data_buf, sizeof(data_buf), 0); GetEMLFromBigBuf(data_buf, sizeof(data_buf), 0);
@ -89,71 +85,120 @@ int CmdLegicDecode(const char *Cmd) {
(calc_crc == crc) ? "OK":"Fail" (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) { switch (data_buf[5] & 0x7f) {
case 0x00 ... 0x2f: case 0x00 ... 0x2f:
strncpy(token_type, "IAM",sizeof(token_type)); strncpy(token_type, "IAM",sizeof(token_type));
fl = (0x2f - (data_buf[5] & 0x7f)) + 1;
break; break;
case 0x30 ... 0x6f: case 0x30 ... 0x6f:
strncpy(token_type, "SAM",sizeof(token_type)); strncpy(token_type, "SAM",sizeof(token_type));
fl = (0x6f - (data_buf[5] & 0x7f)) + 1;
break; break;
case 0x70 ... 0x7f: case 0x70 ... 0x7f:
strncpy(token_type, "GAM",sizeof(token_type)); strncpy(token_type, "GAM",sizeof(token_type));
break; fl = (0x7f - (data_buf[5] & 0x7f)) + 1;
default:
strncpy(token_type, "???",sizeof(token_type));
break; break;
} }
stamp_len = 0xfc - data_buf[6]; 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[5],
data_buf[6], data_buf[6],
token_type, token_type,
(data_buf[5]&0x80)>>7, (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]&0x0f,
(data_buf[7]&0x70)>>4, (data_buf[7]&0x70)>>4,
(data_buf[7]&0x80)>>7, (data_buf[7]&0x80)>>7,
data_buf[7],
data_buf[8] 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("Remaining Header Area");
PrintAndLog("%s", sprint_hex(data_buf+9, 13)); PrintAndLog("%s", sprint_hex(data_buf+9, 13));
}
}
}
uint8_t segCrcBytes[8] = {0x00}; uint8_t segCrcBytes[8] = {0x00};
uint32_t segCalcCRC = 0; uint32_t segCalcCRC = 0;
uint32_t segCRC = 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); // Data card?
if(dcf <= 60000) {
return 0;
PrintAndLog("\nADF: User Area"); PrintAndLog("\nADF: User Area");
PrintAndLog("------------------------------------------------------"); PrintAndLog("------------------------------------------------------");
if(bIsSegmented) {
// Data start point on segmented cards
i = 22; i = 22;
// 64 potential segements
// how to detect there is no segments?!? // decode segments
for ( segmentNum=0; segmentNum<64; segmentNum++ ) { for (segmentNum=1; segmentNum < 128; segmentNum++ )
{
segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc); segment_len = ((data_buf[i+1]^crc)&0x0f) * 256 + (data_buf[i]^crc);
segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4; segment_flag = ((data_buf[i+1]^crc)&0xf0)>>4;
wrp = (data_buf[i+2]^crc); wrp = (data_buf[i+2]^crc);
wrc = ((data_buf[i+3]^crc)&0x70)>>4; wrc = ((data_buf[i+3]^crc)&0x70)>>4;
@ -198,11 +243,10 @@ int CmdLegicDecode(const char *Cmd) {
PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc); PrintAndLog("WRC protected area: (I %d | K %d| WRC %d)", i, k, wrc);
PrintAndLog("\nrow | data"); PrintAndLog("\nrow | data");
PrintAndLog("-----+------------------------------------------------"); PrintAndLog("-----+------------------------------------------------");
// de-xor? if not zero, assume it needs xoring.
if ( isXored) { for ( k=i; k < (i+wrc); ++k)
for ( k=i; k < wrc; ++k)
data_buf[k] ^= crc; data_buf[k] ^= crc;
}
print_hex_break( data_buf+i, wrc, 16); print_hex_break( data_buf+i, wrc, 16);
i += wrc; i += wrc;
@ -213,16 +257,14 @@ int CmdLegicDecode(const char *Cmd) {
PrintAndLog("\nrow | data"); PrintAndLog("\nrow | data");
PrintAndLog("-----+------------------------------------------------"); PrintAndLog("-----+------------------------------------------------");
if (isXored) { for (k=i; k < (i+wrp_len); ++k)
for (k=i; k < wrp_len; ++k)
data_buf[k] ^= crc; data_buf[k] ^= crc;
}
print_hex_break( data_buf+i, wrp_len, 16); print_hex_break( data_buf+i, wrp_len, 16);
i += wrp_len; 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 ) 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("Card ID: %2X%02X%02X", data_buf[i-4]^crc, data_buf[i-3]^crc, data_buf[i-2]^crc);
} }
@ -230,10 +272,9 @@ int CmdLegicDecode(const char *Cmd) {
PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len); PrintAndLog("Remaining segment payload: (I %d | K %d | Remain LEN %d)", i, k, remain_seg_payload_len);
PrintAndLog("\nrow | data"); PrintAndLog("\nrow | data");
PrintAndLog("-----+------------------------------------------------"); 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; data_buf[k] ^= crc;
}
print_hex_break( data_buf+i, remain_seg_payload_len, 16); print_hex_break( data_buf+i, remain_seg_payload_len, 16);
@ -245,6 +286,56 @@ int CmdLegicDecode(const char *Cmd) {
if (segment_flag & 0x8) return 0; if (segment_flag & 0x8) return 0;
} // end for loop } // 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;
} }
@ -417,8 +508,37 @@ int CmdLegicRfWrite(const char *Cmd) {
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) { 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]); int res = sscanf(Cmd, " 0x%"llx" 0x%"llx" 0x%"llx, &cmd.arg[0], &cmd.arg[1], &cmd.arg[2]);
if(res != 3) { if(res != 3) {
PrintAndLog("Please specify the offset, length and value as two hex strings"); PrintAndLog("Please specify the offset, length and value as two hex strings");
@ -427,12 +547,12 @@ int CmdLegicRfFill(const char *Cmd) {
int i; int i;
UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}}; UsbCommand c = {CMD_DOWNLOADED_SIM_SAMPLES_125K, {0, 0, 0}};
for(i = 0; i < 48; i++) { memcpy(c.d.asBytes, cmd.arg[2], 48);
c.d.asBytes[i] = cmd.arg[2];
}
for(i = 0; i < 22; i++) { for(i = 0; i < 22; i++) {
c.arg[0] = i*48; c.arg[0] = i*48;
clearCommandBuffer();
SendCommand(&c); SendCommand(&c);
WaitForResponse(CMD_ACK, NULL); WaitForResponse(CMD_ACK, NULL);
} }
@ -443,20 +563,64 @@ int CmdLegicRfFill(const char *Cmd) {
int CmdLegicCalcCrc8(const char *Cmd){ int CmdLegicCalcCrc8(const char *Cmd){
int len = strlen(Cmd); uint8_t *data;
if ( len & 1 ) return usage_legic_calccrc8(); uint8_t cmdp = 0, uidcrc = 0, type=0;
bool errors = false;
int len = 0;
// add 1 for null terminator. while(param_getchar(Cmd, cmdp) != 0x00) {
uint8_t *data = malloc(len+1); switch(param_getchar(Cmd, cmdp)) {
if ( data == NULL ) return 1; 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;
if (param_gethex(Cmd, 0, data, len )) { len >>= 1;
free(data); 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(); return usage_legic_calccrc8();
} }
uint32_t checksum = CRC8Legic(data, len/2); switch (type){
PrintAndLog("Bytes: %s || CRC8: %X", sprint_hex(data, len/2), checksum ); case 16:
PrintAndLog("LEGIC CRC16: %X", CRC16Legic(data, len, uidcrc));
break;
default:
PrintAndLog("LEGIC CRC8: %X", CRC8Legic(data, len) );
break;
}
free(data); free(data);
return 0; return 0;
} }
@ -469,6 +633,7 @@ static command_t CommandTable[] = {
{"load", CmdLegicLoad, 0, "<filename> -- Restore samples"}, {"load", CmdLegicLoad, 0, "<filename> -- Restore samples"},
{"sim", CmdLegicRfSim, 0, "[phase drift [frame drift [req/resp drift]]] Start tag simulator (use after load or read)"}, {"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)"}, {"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"}, {"fill", CmdLegicRfFill, 0, "<offset> <length> <value> -- Fill/Write tag with constant value"},
{"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"}, {"crc8", CmdLegicCalcCrc8, 1, "Calculate Legic CRC8 over given hexbytes"},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}

View file

@ -11,6 +11,16 @@
#ifndef CMDHFLEGIC_H__ #ifndef CMDHFLEGIC_H__
#define 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 CmdHFLegic(const char *Cmd);
int CmdLegicRFRead(const char *Cmd); int CmdLegicRFRead(const char *Cmd);
@ -19,9 +29,12 @@ int CmdLegicLoad(const char *Cmd);
int CmdLegicSave(const char *Cmd); int CmdLegicSave(const char *Cmd);
int CmdLegicRfSim(const char *Cmd); int CmdLegicRfSim(const char *Cmd);
int CmdLegicRfWrite(const char *Cmd); int CmdLegicRfWrite(const char *Cmd);
int CmdLegicRfRawWrite(const char *Cmd);
int CmdLegicRfFill(const char *Cmd); int CmdLegicRfFill(const char *Cmd);
int CmdLegicCalcCrc8(const char *Cmd); int CmdLegicCalcCrc8(const char *Cmd);
int usage_legic_calccrc8(void); int usage_legic_calccrc8(void);
int usage_legic_load(void);
int usage_legic_read(void);
#endif #endif

View file

@ -9,15 +9,13 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "util.h" #include "util.h"
#include "proxmark3.h"
#define MAX_BIN_BREAK_LENGTH (3072+384+1) #define MAX_BIN_BREAK_LENGTH (3072+384+1)
#ifndef _WIN32 #ifndef _WIN32
#include <termios.h> #include <termios.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
int ukbhit(void) int ukbhit(void) {
{
int cnt = 0; int cnt = 0;
int error; int error;
static struct termios Otty, Ntty; static struct termios Otty, Ntty;
@ -554,3 +552,19 @@ uint32_t SwapBits(uint32_t value, int nrbits) {
} }
return newvalue; return newvalue;
} }
/*
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;
}

View file

@ -15,7 +15,11 @@
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include "data.h" //for FILE_PATH_SIZE #include "data.h" //for FILE_PATH_SIZE
#include "proxmark3.h"
#ifndef BITMASK
# define BITMASK(X) (1 << (X))
#endif
#ifndef ROTR #ifndef ROTR
# define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n)))) # define ROTR(x,n) (((uintmax_t)(x) >> (n)) | ((uintmax_t)(x) << ((sizeof(x) * 8) - (n))))
#endif #endif
@ -30,6 +34,10 @@
((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \ ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
(((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
#endif #endif
#ifndef BSWAP_16
# define BSWAP_16(x) ((( ((x) & 0xFF00 ) >> 8))| ( (((x) & 0x00FF) << 8)))
#endif
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
#define EVEN 0 #define EVEN 0
@ -94,3 +102,4 @@ uint32_t le32toh (uint8_t *data);
uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits); uint32_t PackBits(uint8_t start, uint8_t len, uint8_t* bits);
void rol(uint8_t *data, const size_t len); void rol(uint8_t *data, const size_t len);
uint32_t SwapBits(uint32_t value, int nrbits); uint32_t SwapBits(uint32_t value, int nrbits);
uint32_t reflect(uint32_t v, int b);

View file

@ -1,6 +1,6 @@
#include "bucketsort.h" #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, uint32_t* const ostart, uint32_t* const ostop,
bucket_info_t *bucket_info, bucket_array_t bucket) bucket_info_t *bucket_info, bucket_array_t bucket)
{ {

View file

@ -1,7 +1,9 @@
#ifndef BUCKETSORT_H__ #ifndef BUCKETSORT_H__
#define BUCKETSORT_H__ #define BUCKETSORT_H__
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
typedef struct bucket { typedef struct bucket {
uint32_t *head; uint32_t *head;
uint32_t *bp; uint32_t *bp;

View file

@ -5,66 +5,136 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Generic CRC calculation code. // Generic CRC calculation code.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// the Check value below in the comments is CRC of the string '123456789'
//
#include "crc.h" #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->order = order;
crc->topbit = BITMASK( order-1 );
crc->polynom = polynom; crc->polynom = polynom;
crc->initial_value = initial_value; crc->initial_value = initial_value;
crc->final_xor = final_xor; crc->final_xor = final_xor;
crc->mask = (1L<<order)-1; crc->mask = (1L<<order)-1;
crc->refin = FALSE;
crc->refout = FALSE;
crc_clear(crc); crc_clear(crc);
} }
void crc_update(crc_t *crc, uint32_t data, int data_width) void crc_clear(crc_t *crc) {
{
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; crc->state = crc->initial_value & crc->mask;
if (crc->refin)
crc->state = reflect(crc->state, crc->order);
} }
uint32_t crc_finish(crc_t *crc) void crc_update(crc_t *crc, uint32_t indata, int data_width){
{
return ( crc->state ^ crc->final_xor ) & crc->mask; //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);
}
} }
//credits to iceman 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;
}
/*
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
);
}
*/
// 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) { uint32_t CRC8Maxim(uint8_t *buff, size_t size) {
crc_t crc; crc_t crc;
crc_init(&crc, 9, 0x8c, 0x00, 0x00); crc_init_ref(&crc, 8, 0x31, 0, 0, TRUE, TRUE);
crc_clear(&crc); for ( int i=0; i < size; ++i)
for (size_t i=0; i < size; ++i)
crc_update(&crc, buff[i], 8); crc_update(&crc, buff[i], 8);
return crc_finish(&crc); return crc_finish(&crc);
} }
//credits to iceman
// 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) { uint32_t CRC8Legic(uint8_t *buff, size_t size) {
// Poly 0x63, reversed poly 0xC6, Init 0x55, Final 0x00
crc_t crc; crc_t crc;
crc_init(&crc, 8, 0xC6, 0x55, 0); crc_init_ref(&crc, 8, 0x63, 0x55, 0, TRUE, TRUE);
crc_clear(&crc);
for ( int i = 0; i < size; ++i) for ( int i = 0; i < size; ++i)
crc_update(&crc, buff[i], 8); crc_update(&crc, buff[i], 8);
return SwapBits(crc_finish(&crc), 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);
}
// 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) {
#define CRC16_POLY_LEGIC 0xB400
//uint8_t initial = reflect(uidcrc, 8);
uint16_t initial = uidcrc;
initial |= initial << 8;
crc_t crc;
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 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);
}

View file

@ -9,8 +9,10 @@
#ifndef __CRC_H #ifndef __CRC_H
#define __CRC_H #define __CRC_H
#include <stdint.h> #include <stdint.h> //uint32+
#include <stdbool.h> //bool
#include <stddef.h> #include <stddef.h>
#include "util.h" // reflect, bswap_16
typedef struct crc { typedef struct crc {
uint32_t state; uint32_t state;
@ -19,13 +21,25 @@ typedef struct crc {
uint32_t initial_value; uint32_t initial_value;
uint32_t final_xor; uint32_t final_xor;
uint32_t mask; uint32_t mask;
int topbit;
bool refin; /* Parameter: Reflect input bytes? */
bool refout; /* Parameter: Reflect output CRC? */
} crc_t; } 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 /* 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. * 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(). */ * 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); 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 /* Update the crc state. data is the data of length data_width bits (only the
* data_width lower-most bits are used). * data_width lower-most bits are used).
*/ */
@ -40,9 +54,24 @@ extern uint32_t crc_finish(crc_t *crc);
// Calculate CRC-8/Maxim checksum // Calculate CRC-8/Maxim checksum
uint32_t CRC8Maxim(uint8_t *buff, size_t size); 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 // Calculate CRC-8/Legic checksum
uint32_t CRC8Legic(uint8_t *buff, size_t size); 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 */ /* Static initialization of a crc structure */
#define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \ #define CRC_INITIALIZER(_order, _polynom, _initial_value, _final_xor) { \
.state = ((_initial_value) & ((1L<<(_order))-1)), \ .state = ((_initial_value) & ((1L<<(_order))-1)), \
@ -50,6 +79,9 @@ uint32_t CRC8Legic(uint8_t *buff, size_t size);
.polynom = (_polynom), \ .polynom = (_polynom), \
.initial_value = (_initial_value), \ .initial_value = (_initial_value), \
.final_xor = (_final_xor), \ .final_xor = (_final_xor), \
.mask = ((1L<<(_order))-1) } .mask = ((1L<<(_order))-1) \
.refin = FALSE, \
.refout = FALSE \
}
#endif /* __CRC_H */ #endif /* __CRC_H */

View file

@ -9,11 +9,9 @@
#include "crc16.h" #include "crc16.h"
#define CRC16_POLY_CCITT 0x1021 #define CRC16_POLY_CCITT 0x1021
#define CRC16_POLY 0x8408 #define CRC16_POLY 0x8408
#define CRC16_POLY_LEGIC 0xB400
unsigned short update_crc16( unsigned short crc, unsigned char c ) uint16_t update_crc16( uint16_t crc, unsigned char c ) {
{ uint16_t i, v, tcrc = 0;
unsigned short i, v, tcrc = 0;
v = (crc ^ c) & 0xff; v = (crc ^ c) & 0xff;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
@ -29,8 +27,8 @@ uint16_t crc16(uint8_t const *message, int length, uint16_t remainder, uint16_t
if (length == 0) if (length == 0)
return (~remainder); return (~remainder);
for (int byte = 0; byte < length; ++byte) { for (uint32_t i = 0; i < length; ++i) {
remainder ^= (message[byte] << 8); remainder ^= (message[i] << 8);
for (uint8_t bit = 8; bit > 0; --bit) { for (uint8_t bit = 8; bit > 0; --bit) {
if (remainder & 0x8000) { if (remainder & 0x8000) {
remainder = (remainder << 1) ^ polynomial; remainder = (remainder << 1) ^ polynomial;
@ -47,25 +45,6 @@ uint16_t crc16_ccitt(uint8_t const *message, int length) {
} }
uint16_t crc16_ccitt_kermit(uint8_t const *message, int length) { uint16_t crc16_ccitt_kermit(uint8_t const *message, int length) {
return bit_reverse_uint16(crc16(message, length, 0x0000, CRC16_POLY_CCITT)); uint16_t val = crc16(message, length, 0x0000, CRC16_POLY_CCITT);
} return SwapBits(val, 16);
//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;
} }

View file

@ -5,14 +5,14 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// CRC16 // CRC16
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include <stdint.h>
#ifndef __CRC16_H #ifndef __CRC16_H
#define __CRC16_H #define __CRC16_H
#include <stdint.h>
#include "util.h"
unsigned short update_crc16(unsigned short crc, unsigned char c); 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(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(uint8_t const *message, int length);
uint16_t crc16_ccitt_kermit(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 #endif

View file

@ -74,9 +74,7 @@ const uint64_t crc64_table[] = {
void crc64 (const uint8_t *data, const size_t len, uint64_t *crc) { void crc64 (const uint8_t *data, const size_t len, uint64_t *crc) {
for (size_t i = 0; i < len; i++) for (size_t i = 0; i < len; i++) {
{
//uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff;
uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff; uint8_t tableIndex = (((uint8_t)(*crc >> 56)) ^ data[i]) & 0xff;
*crc = crc64_table[tableIndex] ^ (*crc << 8); *crc = crc64_table[tableIndex] ^ (*crc << 8);
} }