]> git.zerfleddert.de Git - proxmark3-svn/commitdiff
put legic back in the system and add rumpletux's fast legic / prng code from forum
authoradam@algroup.co.uk <adam@algroup.co.uk@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Fri, 5 Feb 2010 08:18:02 +0000 (08:18 +0000)
committeradam@algroup.co.uk <adam@algroup.co.uk@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Fri, 5 Feb 2010 08:18:02 +0000 (08:18 +0000)
armsrc/Makefile
armsrc/appmain.c
armsrc/legicrf.c
armsrc/legicrf.h
client/cmdhf.c
client/cmdhflegic.c
common/legic_prng.c [new file with mode: 0644]
include/legic_prng.h [new file with mode: 0644]

index a6b2fcc801887827986653b19e0f883f1860bb94..47f8c73d2c6266512c0554316d047aa64c74fb5d 100644 (file)
@@ -28,6 +28,7 @@ ARMSRC = fpgaloader.c \
        crc16.c \\r
        $(SRC_ISO14443a) \\r
        $(SRC_ISO14443b) \\r
+        legic_prng.c \\r
        crc.c\r
 \r
 # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC\r
index e5cd16b74389e22322c1070fb8415bcee788e055..b231cae1e27b1623eb734b886aed489efe5986e7 100644 (file)
@@ -602,8 +602,8 @@ void UsbPacketReceived(BYTE *packet, int len)
 #endif\r
 \r
                case CMD_READER_LEGIC_RF:\r
-                       LegicRfReader();\r
-                       break;\r
+                       LegicRfReader(c->arg[0], c->arg[1]);\r
+                       break;
 \r
 #ifdef WITH_ISO15693\r
                case CMD_SIMTAG_ISO_15693:\r
index 86c0c3604f1b6074e1f07f0aaf74d367b12910b7..3f3dfbe573deedaabe2dd1ab07db21226869fa91 100644 (file)
 #include "unistd.h"
 #include "stdint.h"
 
+#include "legic_prng.h"
+#include "crc.h"
+
 static struct legic_frame {
        int bits;
        uint16_t data;
 } current_frame;
+
+static crc_t legic_crc;
+
 AT91PS_TC timer;
 
 static void setup_timer(void)
@@ -43,7 +49,7 @@ static void setup_timer(void)
 /* Send a frame in reader mode, the FPGA must have been set up by
  * LegicRfReader
  */
-static void frame_send_rwd(uint16_t data, int bits)
+static void frame_send_rwd(uint32_t data, int bits)
 {
        /* Start clock */
        timer->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
@@ -55,8 +61,8 @@ static void frame_send_rwd(uint16_t data, int bits)
                int pause_end = starttime + RWD_TIME_PAUSE, bit_end;
                int bit = data & 1;
                data = data >> 1;
-               
-               if(bit) {
+
+               if(bit ^ legic_prng_get_bit()) {
                        bit_end = starttime + RWD_TIME_1;
                } else {
                        bit_end = starttime + RWD_TIME_0;
@@ -67,6 +73,8 @@ static void frame_send_rwd(uint16_t data, int bits)
                AT91C_BASE_PIOA->PIO_CODR = GPIO_SSC_DOUT;
                while(timer->TC_CV < pause_end) ;
                AT91C_BASE_PIOA->PIO_SODR = GPIO_SSC_DOUT;
+               legic_prng_forward(1); /* bit duration is longest. use this time to forward the lfsr */
+               
                while(timer->TC_CV < bit_end) ;
        }
        
@@ -104,7 +112,7 @@ static void frame_send_rwd(uint16_t data, int bits)
  * the range is severely reduced (and you'll probably also need a good antenna).
  * So this should be fixed some time in the future for a proper receiver. 
  */
-static void frame_receive_rwd(struct legic_frame * const f, int bits)
+static void frame_receive_rwd(struct legic_frame * const f, int bits, int crypt)
 {
        uint16_t the_bit = 1;  /* Use a bitmask to save on shifts */
        uint16_t data=0;
@@ -118,11 +126,25 @@ static void frame_receive_rwd(struct legic_frame * const f, int bits)
        AT91C_BASE_PIOA->PIO_ODR = GPIO_SSC_DIN;
        AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DIN;
 
+       /* we have some time now, precompute the cipher
+         * since we cannot compute it on the fly while reading */
+       legic_prng_forward(2);
+
+       if(crypt)
+       {
+               for(i=0; i<bits; i++) {
+                       data |= legic_prng_get_bit() << i;
+                       legic_prng_forward(1);
+               }
+       }
+
        while(timer->TC_CV < next_bit_at) ;
+
        next_bit_at += TAG_TIME_BIT;
        
        for(i=0; i<bits; i++) {
                edges = 0;
+
                while(timer->TC_CV < next_bit_at) {
                        int level = (AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN);
                        if(level != old_level)
@@ -132,10 +154,9 @@ static void frame_receive_rwd(struct legic_frame * const f, int bits)
                next_bit_at += TAG_TIME_BIT;
                
                if(edges > 20 && edges < 60) { /* expected are 42 edges */
-                       data |= the_bit;
+                       data ^= the_bit;
                }
-               
-               
+
                the_bit <<= 1;
        }
        
@@ -153,33 +174,29 @@ static void frame_clean(struct legic_frame * const f)
        f->bits = 0;
 }
 
-static uint16_t perform_setup_phase_rwd(void)
+static uint16_t perform_setup_phase_rwd(int iv)
 {
        
        /* Switch on carrier and let the tag charge for 1ms */
        AT91C_BASE_PIOA->PIO_SODR = GPIO_SSC_DOUT;
        SpinDelay(1);
        
-       frame_send_rwd(0x55, 7);
+       legic_prng_init(0); /* no keystream yet */
+       frame_send_rwd(iv, 7);
+        legic_prng_init(iv);
+       
        frame_clean(&current_frame);
-       frame_receive_rwd(&current_frame, 6);
+       frame_receive_rwd(&current_frame, 6, 1);
+       legic_prng_forward(1); /* we wait anyways */
        while(timer->TC_CV < 387) ; /* ~ 258us */
-       frame_send_rwd(0x019, 6);
-       
-       return current_frame.data ^ 0x26;
-}
+       frame_send_rwd(0x19, 6);
 
-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();
+       if(current_frame.data != 0x1d)
+               Dbprintf("probably don't know how to deal with %x card", current_frame.data);
+       return current_frame.data;
 }
 
-void LegicRfReader(void)
-{
+static void LegicCommonInit(void) {
        SetAdcMuxFor(GPIO_MUXSEL_HIPKD);
        FpgaSetupSsc();
        FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER_TX);
@@ -191,62 +208,67 @@ void LegicRfReader(void)
        
        setup_timer();
        
-       memset(BigBuf, 0, 1024);
+       crc_init(&legic_crc, 4, 0x19 >> 1, 0x5, 0);
+}
+
+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);
        
-       int byte_index = 0, card_size = 0, command_size = 0;
-       uint16_t command_obfuscation = 0x57, response_obfuscation = 0;
-       uint16_t tag_type = perform_setup_phase_rwd();
-       switch_off_tag_rwd();
+       WDT_HIT();
+}
+/* calculate crc for a legic command */
+static int LegicCRC(int byte_index, int value) {
+       crc_clear(&legic_crc);
+       crc_update(&legic_crc, 1, 1); /* CMD_READ */
+       crc_update(&legic_crc, byte_index, 8);
+       crc_update(&legic_crc, value, 8);
+       return crc_finish(&legic_crc);
+}
+
+int legic_read_byte(int byte_index) {
+       int byte;
+
+       legic_prng_forward(4); /* we wait anyways */
+       while(timer->TC_CV < 387) ; /* ~ 258us + 100us*delay */
+
+       frame_send_rwd(1 | (byte_index << 1), 9);
+       frame_clean(&current_frame);
+
+       frame_receive_rwd(&current_frame, 12, 1);
+
+       byte = current_frame.data & 0xff;
+       if( LegicCRC(byte_index, byte) != (current_frame.data >> 8) )
+               Dbprintf("!!! crc mismatch: expected %x but got %x !!!", LegicCRC(byte_index, current_frame.data & 0xff), current_frame.data >> 8);
+
+       return byte;
+}
+
+/* legic_write_byte() is not included, however it's trivial to implement
+ * and here are some hints on what remains to be done:
+ *
+ *  * assemble a write_cmd_frame with crc and send it
+ *  * wait until the tag sends back an ACK ('1' bit unencrypted)
+ *  * forward the prng based on the timing
+ */
+
+
+void LegicRfReader(int offset, int bytes) {
+       int byte_index=0;
        
-       int error = 0;
-       switch(tag_type) {
-       case 0x1d:
-               DbpString("MIM 256 card found, reading card ...");
-               command_size = 9;
-               card_size = 256;
-               response_obfuscation = 0x52;
-               break;
-       case 0x3d:
-               DbpString("MIM 1024 card found, reading card ...");
-               command_size = 11;
-               card_size = 1024;
-               response_obfuscation = 0xd4;
-               break;
-       default:
-               DbpString("No or unknown card found, aborting");
-               error = 1;
-               break;
-       }
+       LegicCommonInit();
+
+       memset(BigBuf, 0, 256);
        
-       LED_B_ON();
-       while(!BUTTON_PRESS() && (byte_index<card_size)) {
-               if(perform_setup_phase_rwd() != tag_type) {
-                       DbpString("Card removed, aborting");
-                       switch_off_tag_rwd();
-                       error=1;
-                       break;
-               }
-               
-               while(timer->TC_CV < 387) ; /* ~ 258us */
-               frame_send_rwd(command_obfuscation ^ (byte_index<<1), command_size);
-               frame_clean(&current_frame);
-               frame_receive_rwd(&current_frame, 8);
-               ((uint8_t*)BigBuf)[byte_index] = (current_frame.data ^ response_obfuscation) & 0xff;
-               
-               switch_off_tag_rwd();
-               
-               WDT_HIT();
+       DbpString("setting up legic card");
+       perform_setup_phase_rwd(0x55);
+
+       while(byte_index < bytes) {
+               ((uint8_t*)BigBuf)[byte_index] = legic_read_byte(byte_index+offset);
                byte_index++;
-               if(byte_index & 0x04) LED_C_ON(); else LED_C_OFF();
-       }
-       LED_B_OFF();
-       LED_C_OFF();
-       
-       if(!error) {
-               if(card_size == 256) {
-                       DbpString("Card read, use hexsamples 256 to view results");
-               } else if(card_size == 1024) {
-                       DbpString("Card read, use hexsamples 1024 to view results");
-               }
        }
+       switch_off_tag_rwd();
+       Dbprintf("Card read, use 'data hexsamples %d' to view results", (bytes+7) & ~7);
 }
index 0c9e69d98c1f89a77f4de93363fb09160d4962b5..2215db04f244487ad2b26d9565ad12fc839ff642 100644 (file)
@@ -8,6 +8,5 @@
 #define LEGICRF_H_
 
 extern void LegicRfSimulate(void);
-extern void LegicRfReader(void);
-
+extern void LegicRfReader(int bytes, int offset);
 #endif /* LEGICRF_H_ */
index fc82a50d9ecfc3c154c8d3b08e33587dd18a859d..36a9eca504e78ccdc915693eb462b3d73b5c59f0 100644 (file)
@@ -25,6 +25,7 @@ static command_t CommandTable[] =
   {"14b",         CmdHF14B,         1, "{ ISO14443B RFIDs... }"},
   {"15",          CmdHF15,          1, "{ ISO15693 RFIDs... }"},
   {"tune",        CmdHFTune,        0, "Continuously measure HF antenna tuning"},
+  {"legic",       CmdHFLegic,       0, "{ LEGIC RFIDs... }"},
   {NULL, NULL, 0, NULL}
 };
 
index 62ff942820004ad6ada453d4c577afd5fae3b00e..e2229a730475ef22344bb50a88849cd9d42e9362 100644 (file)
@@ -1,3 +1,5 @@
+#include <stdio.h>
+#include <string.h>
 #include "proxusb.h"
 #include "cmdparser.h"
 #include "cmdhflegic.h"
@@ -6,7 +8,11 @@ static int CmdHelp(const char *Cmd);
 
 int CmdLegicRFRead(const char *Cmd)
 {
-  UsbCommand c = {CMD_READER_LEGIC_RF};
+  int byte_count=0,offset=0;
+  sscanf(Cmd, "%i %i", &offset, &byte_count);
+  if(byte_count == 0) byte_count = 256;
+  if(byte_count + offset > 256) byte_count = 256 - offset;
+  UsbCommand c={CMD_READER_LEGIC_RF, {offset, byte_count, 0}};
   SendCommand(&c);
   return 0;
 }
@@ -14,7 +20,7 @@ int CmdLegicRFRead(const char *Cmd)
 static command_t CommandTable[] = 
 {
   {"help",        CmdHelp,        1, "This help"},
-  {"reader",      CmdLegicRFRead, 0, "Start the LEGIC RF reader"},
+  {"reader",      CmdLegicRFRead, 0, "[offset [length]] -- read bytes from a LEGIC card"},
   {NULL, NULL, 0, NULL}
 };
 
diff --git a/common/legic_prng.c b/common/legic_prng.c
new file mode 100644 (file)
index 0000000..ee8e0dc
--- /dev/null
@@ -0,0 +1,41 @@
+#include "legic_prng.h"
+/* legic's obfuscation function */
+
+struct lfsr {
+  uint8_t a;
+  uint8_t b;
+} lfsr;
+
+void legic_prng_init(uint8_t init) {
+  lfsr.a = init;
+  if(init == 0) /* hack to get a always 0 keystream */
+    lfsr.b = 0;
+  else
+    lfsr.b = (init << 1) | 1;
+}
+
+void legic_prng_forward(int count) {
+  uint8_t tmp;
+  while(count--) {
+    tmp  =  lfsr.a & 1;
+    tmp ^= (lfsr.a & 0x40) >> 6;
+    
+    lfsr.a >>= 1;
+    lfsr.a |= tmp << 6;
+    
+    tmp  =  lfsr.b & 1;
+    tmp ^= (lfsr.b & 4) >> 2;
+    tmp  = ~tmp;
+    tmp ^= (lfsr.b & 8) >> 3;
+    tmp  = ~tmp;
+    tmp ^= (lfsr.b & 0x80) >> 7;
+    
+    lfsr.b >>= 1;
+    lfsr.b |= tmp << 7;
+  }
+}
+
+uint8_t legic_prng_get_bit() {
+  uint8_t idx = 7-((lfsr.a & 4) | ((lfsr.a & 8) >> 2) | ((lfsr.a & 0x10) >> 4));
+  return ((lfsr.b >> idx) & 1);
+}
diff --git a/include/legic_prng.h b/include/legic_prng.h
new file mode 100644 (file)
index 0000000..edcf49c
--- /dev/null
@@ -0,0 +1,5 @@
+#include "unistd.h"
+#include "stdint.h"
+extern void legic_prng_init(uint8_t init);
+extern void legic_prng_forward(int count);
+extern uint8_t legic_prng_get_bit();
Impressum, Datenschutz