basic stuff implemented, reading out mifare with std key 0xff
[rfid/librfid.git] / gemtag / gemtag.c
index 7a2e8ce..48dc427 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * (C) 2006 by Frank Zirkelbach <hackbard@hackdaworld.org>
+ *  (C) 2006 by Frank Zirkelbach <hackbard@hackdaworld.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 
 #include <usb.h>
 #include "gemtag.h"
 
+int asciidump(unsigned char *data,int len) {
+       int i;
+
+       for(i=0;i<len;i++)
+               if((data[i]>0x19)&&(data[i]<0x7f)) printf("%c",data[i]);
+               else printf("_");
+       //printf("\n");
+
+       return 0;
+}
+
 int hexdump(unsigned char *data,int len) {
        int i;
 
        for(i=0;i<len;i++) printf("%02x ",data[i]);
-       printf("\n");
+       //printf("\n");
 
        return 0;
 }
@@ -75,16 +86,16 @@ u_int16_t gemtag_calc_crc(unsigned char *data,u_int16_t len) {
        return crc;
 }
 
-int gemtag_transcieve(struct gemtag_handle *gh,unsigned char cmd,
-                         unsigned char *tx,unsigned int tx_len,
-                         unsigned char *rx,unsigned int *rx_len) {
+int gemtag_transceive(struct gemtag_handle *gh,unsigned char cmd,
+                      unsigned char *tx,unsigned int tx_len,
+                      unsigned char *rx,unsigned int *rx_len) {
 
        unsigned char txbuf[256];
        unsigned char rxbuf[256];
        struct gemtag_cmd_hdr *txhdr;
        struct gemtag_cmd_hdr *rxhdr;
-       u_int16_t *crcptr;
-       int ret,size;
+       u_int16_t crc,*crcptr;
+       int i,ret,size,rest;
 
        txhdr=(struct gemtag_cmd_hdr *)txbuf;
        rxhdr=(struct gemtag_cmd_hdr *)rxbuf;
@@ -92,71 +103,94 @@ int gemtag_transcieve(struct gemtag_handle *gh,unsigned char cmd,
        txhdr->start=0xa5;
        txhdr->seq=++(gh->seq);
        txhdr->cmd=cmd;
-       txhdr->len=htons(tx_len);
+       txhdr->len=tx_len;
        size=sizeof(struct gemtag_cmd_hdr);
        memcpy(txbuf+size,tx,tx_len);
+       size+=tx_len;
 
        /* crc check */
-       if(gh->capabilities&GEMTAG_CAP_CRC) {
-               size+=tx_len;
+       if(gh->caps&GEMTAG_CAP_CRC) {
                crcptr=(u_int16_t *)(txbuf+size);
-               *crcptr=htons(gemtag_calc_crc(txbuf,size));
+               crc=gemtag_calc_crc(txbuf,size);
+               //*crcptr=(crc>>8)|(crc<<8);
+               *crcptr=crc;
                size+=2;
        }
 
        /* usb write */
-       printf("-> ");
-       hexdump(txbuf,size);
-       if(usb_clear_halt(gh->handle,0x02))
-               perror("clear halt (out)");
-       ret=usb_bulk_write(gh->handle,0x02,txbuf,size,0);
+       if(gh->caps&GEMTAG_CAP_VERB_TRANSMIT) {
+               printf("(%02d) -> ",size);
+               hexdump(txbuf,size);
+       }
+       ret=usb_interrupt_write(gh->handle,0x02,txbuf,size,0);
        if(ret<=0) {
-               perror("usb bulk write");
+               perror("usb interrupt write");
                return ret;
        }
 
        /* usb read */
-       if(usb_clear_halt(gh->handle,0x81))
-               perror("clear halt (in)");
-       ret=usb_bulk_read(gh->handle,0x81,rxbuf,sizeof(rxbuf),0);
-       size=ret;
+       ret=usb_interrupt_read(gh->handle,0x81,rxbuf,32,0);
        if(ret<=0) {
-               perror("usb bulk read");
+               perror("usb interrupt read");
                return ret;
        }
-       printf("<- ");
-       hexdump(rxbuf,ret);
-       
-       if(rxhdr->seq!=txhdr->seq)
-               puts("transmitted/recieved sequence number do not match");
+       if(ret<5) {
+               if(gh->caps&GEMTAG_CAP_VERB_TRANSMIT)
+                       return -SHORT_ANSWER;
+       }
+
+       *rx_len=rxbuf[3]|(rxbuf[4]<<8);
+       size=*rx_len+sizeof(struct gemtag_cmd_hdr); 
+       if(gh->caps&GEMTAG_CAP_CRC) size+=2;
+
+       i=1;
+       rest=size-ret;
+       while(rest>=0) {
+               ret=usb_interrupt_read(gh->handle,0x81,rxbuf+i*32,32,0);
+               if(ret<=0) {
+                       perror("usb interrupt read (missing bytes)");
+                       return ret;
+               }
+               i++;
+               rest-=ret;
+       }
+
+       if(gh->caps&GEMTAG_CAP_VERB_TRANSMIT) {
+               printf("(%02d) <- ",size);
+               hexdump(rxbuf,size);
+       }
 
        /* crc check */
-       
+       if(gh->caps&GEMTAG_CAP_CRC) {
+               size-=2;
+               crcptr=(u_int16_t *)(rxbuf+size);
+               crc=gemtag_calc_crc(rxbuf,size);
+               if(((crc>>8)!=rxbuf[size+1])||((crc&0xff)!=rxbuf[size]))
+                       return -BAD_CRC;
+       }
+
+       /* check sequence number */     
+       if(rxhdr->seq!=txhdr->seq) return -SEQ_MISMATCH;
 
-       *rx_len=ntohs(rxhdr->len);
-       memcpy(rx,rxbuf+sizeof(struct gemtag_cmd_hdr),
-              ret-sizeof(struct gemtag_cmd_hdr)+2);
-       hexdump(rxbuf,ret+2);
+       /* check return code */
+       if(rxbuf[2]) return -CMD_FAILED;
+
+       memcpy(rx,rxbuf+sizeof(struct gemtag_cmd_hdr),*rx_len);
 
        return 0;
 }
 
 struct gemtag_handle *gemtag_open(void) {
        struct usb_device *gemtag;
-       unsigned char rbuf[16];
-       unsigned int rlen;
-       unsigned int i,numconf;
-       unsigned int j,numint;
-       unsigned int k,numalt;
+       unsigned int i;
        struct gemtag_handle *gh;
-
-       rlen=sizeof(rbuf);
+       char info[64];
 
        usb_init();
        usb_find_busses();
        usb_find_devices();
 
-       gemtag=find_device(USB_VENDOR_GEMTAG, USB_DEVICE_X501);
+       gemtag=find_device(USB_VENDOR_GEMTAG,USB_DEVICE_X501);
        if(!gemtag) return NULL;
 
        gh=malloc(sizeof(struct gemtag_handle));
@@ -164,51 +198,34 @@ struct gemtag_handle *gemtag_open(void) {
 
        memset(gh,0,sizeof(struct gemtag_handle));
 
-       numconf=gemtag->descriptor.bNumConfigurations;
-       printf("found gemtag (%02x/%02x), %u configuration(s)\n",
-              gemtag->descriptor.idVendor,
-              gemtag->descriptor.idProduct,numconf);
-       for(i=0;i<numconf;i++) {
-               numint=gemtag->config[i].bNumInterfaces;
-               printf("  config %u [nr %u] has %u interface(s)\n",
-                      i,gemtag->config[i].bConfigurationValue,
-                      numint);
-               for(j=0;j<numint;j++) {
-                       numalt=gemtag->config[i].interface[j].num_altsetting;
-                       printf("    interface %u has %u altsetting(s): ",
-                              j,numalt);
-                       for(k=0;k<numalt;k++)
-                               printf("%u ",
-               gemtag->config[i].interface[j].altsetting[k].bAlternateSetting);
-                       printf("\n");
-               }
-       }
-
        gh->handle=usb_open(gemtag);
        if(!gh->handle)
                goto out_free;
-       puts("usb_open successfull");
+
+       for(i=1;i<4;i++) {
+               memset(info,0,sizeof(info));
+               usb_get_string_simple(gh->handle,i,info,sizeof(info));
+               printf("%s ",info);
+       }
+       printf("opened successfully\n");
 
        if(usb_set_configuration(gh->handle,1)) {
                perror("set config");
                goto out_free;
        }
-       puts("configuration 1 successfully set");
+       printf("set configuration 1, ");
 
        if(usb_claim_interface(gh->handle,0)) {
                perror("claim interface");
                goto out_free;
        }
-       puts("interface 0 claimed");
-
-       while(usb_set_altinterface(gh->handle,0))
-               printf("trying to set alt interface\n");
-       puts("alt setting 0 selected");
+       printf("claimed interface 0\n");
 
-       gh->capabilities|=GEMTAG_CAP_CRC;
-
-       gemtag_transcieve(gh,GEMTAG_CMD_GET_FW_VERSION,
-                         NULL,0,rbuf,&rlen);
+       /*
+       if(usb_set_altinterface(gh->handle,0))
+               perror("set alt interface");
+       printf("activated alt setting 0\n");
+       */
 
        return gh;
 
@@ -216,13 +233,125 @@ out_free:
        free(gh);
        return NULL;
 }
+
+int gemtag_close(struct gemtag_handle *gh) {
+
+       if(gh->handle) usb_close(gh->handle);
+       if(gh) free(gh);
+
+       return 0;
+}
+
+int gemtag_transform_mifare_key(struct gemtag_handle *gh,
+                         unsigned char *key6,unsigned char *key12) {
+
+       unsigned int len;
+
+       gemtag_transceive(gh,GEMTAG_CMD_HOST_CODE_KEY,key6,6,key12,&len);
+
+       return 0;
+}
+
+int gemtag_auth_mifare_key(struct gemtag_handle *gh,
+                    unsigned char *key6,int sector) {
+
+       unsigned char key12[12];        
+       unsigned char buf[32];
+       unsigned int len,ret;
+
+       gemtag_transform_mifare_key(gh,key6,key12);
+                            
+       buf[0]=0x60; /* auth mode */
+       memcpy(buf+1,gh->serial,4);     /* sreial */
+       memcpy(buf+5,key12,12);         /* transformed key */
+       buf[17]=sector;                 /* sector */
+       ret=gemtag_transceive(gh,GEMTAG_CMD_PICC_AUTH_KEY,buf,18,
+                             buf,&len);
+       if(ret) return -AUTH_FAILED;
+
+       return 0;
+}
+
+int gemtag_read16(struct gemtag_handle *gh,int sector,
+                  unsigned char *data) {
+
+       unsigned char buf[32];
+       int len,ret;
+
+       buf[0]=sector;
+       ret=gemtag_transceive(gh,GEMTAG_CMD_PICC_READ,
+                             buf,1,data,&len);
+       if(ret) return -READ_FAILED;
+
+       return 0;
+}
+
+int gemtag_pick_picc(struct gemtag_handle *gh) {
+
+       unsigned char buf[16];
+       unsigned int len;
+       int ret;
+
+       buf[0]=GEMTAG_PICC_REQIDL;
+       ret=gemtag_transceive(gh,GEMTAG_CMD_PICC_REQUEST,buf,1,buf,&len);
+       if(ret) return -NO_PICC;
+
+       buf[0]=GEMTAG_PICC_STD_SELECT_CODE;
+       memset(buf+1,0,5);
+       ret=gemtag_transceive(gh,GEMTAG_CMD_PICC_CASC_ANTICOLL,buf,6,buf,&len);
+       if(ret) return -NO_PICC;
+       memcpy(gh->serial,buf,4);
+
+       buf[0]=GEMTAG_PICC_STD_SELECT_CODE;
+       memcpy(buf+1,gh->serial,4);
+       ret=gemtag_transceive(gh,GEMTAG_CMD_PICC_CASC_SELECT,buf,5,buf,&len);
+       if(ret) return -PICC_SELECT_ERROR;
+
+       return 0;
+}
        
 int main(int argc, char **argv) {
 
        struct gemtag_handle *gh;
+       unsigned char buf[256];
+       unsigned char key6[6];
+       int i;
 
        gh=gemtag_open();
 
-       return 1;
+       gh->caps|=GEMTAG_CAP_CRC;
+       //gh->caps|=GEMTAG_CAP_VERB_TRANSMIT;
+
+       /*
+       printf("Device:\n");
+       gemtag_transceive(gh,GEMTAG_CMD_GET_FW_VERSION,
+                         NULL,0,buf,&buflen);
+       asciidump(buf,buflen);
+       printf("\n");
+       */
+
+       if(gemtag_pick_picc(gh)) {
+               printf("no card found!\n");
+               return -NO_PICC;
+       }
+
+       memset(key6,0xff,6);
+       printf("\nreading sectors ... (serial: %02x %02x %02x %02x)\n\n",
+              gh->serial[3],gh->serial[2],gh->serial[1],gh->serial[0]);
+       for(i=0;i<256;i++) {
+               gemtag_auth_mifare_key(gh,key6,i);
+               if(!gemtag_read16(gh,i,buf)) {
+                       printf("%02x: ",i++);
+                       hexdump(buf,16);
+                       printf(" | ");
+                       asciidump(buf,16);
+                       printf("\n");
+               }
+               else return 0;
+       }
+
+       gemtag_close(gh);
+
+       return 0;
 }