/*
- * (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"
-/* variables */
+int asciidump(unsigned char *data,int len) {
+ int i;
-struct gemtag_handle {
- struct usb_dev_handle *handle;
-};
+ for(i=0;i<len;i++)
+ if((data[i]>0x19)&&(data[i]<0x7f)) printf("%c",data[i]);
+ else printf(".");
+ //printf("\n");
-/* functions */
+ return 0;
+}
+
+int hexdump(unsigned char *data,int len) {
+ int i;
+
+ for(i=0;i<len;i++) printf("%02x ",data[i]);
+ //printf("\n");
-struct usb_device *find_device(unsigned short vendor, unsigned short device) {
+ return 0;
+}
+
+struct usb_device *find_device(unsigned short vendor,unsigned short device) {
struct usb_bus *bus;
struct usb_device *dev;
return NULL;
}
+u_int16_t gemtag_calc_crc(unsigned char *data,u_int16_t len) {
+
+ u_int16_t crc_polynom;
+ u_int16_t crc_preset;
+ u_int16_t crc;
+ int i,j;
+
+ crc_polynom=0x8408;
+ crc_preset=0xffff;
+ crc=0xffff;
+
+ for(i=0;i<len;i++) {
+ crc^=data[i];
+ for(j=0;j<8;j++) {
+ if(crc&0x0001)
+ crc=(crc>>1)^crc_polynom;
+ else
+ crc=(crc>>1);
+ }
+ }
+ return crc;
+}
+
+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 crc,*crcptr;
+ int i,ret,size,rest;
+
+ txhdr=(struct gemtag_cmd_hdr *)txbuf;
+ rxhdr=(struct gemtag_cmd_hdr *)rxbuf;
+
+ txhdr->start=0xa5;
+ txhdr->seq=++(gh->seq);
+ txhdr->cmd=cmd;
+ txhdr->len=tx_len;
+ size=sizeof(struct gemtag_cmd_hdr);
+ memcpy(txbuf+size,tx,tx_len);
+ size+=tx_len;
+
+ /* crc check */
+ if(gh->caps&GEMTAG_CAP_CRC) {
+ crcptr=(u_int16_t *)(txbuf+size);
+ crc=gemtag_calc_crc(txbuf,size);
+ //*crcptr=(crc>>8)|(crc<<8);
+ *crcptr=crc;
+ size+=2;
+ }
+
+ /* usb write */
+ 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 interrupt write");
+ return ret;
+ }
+
+ /* usb read */
+ ret=usb_interrupt_read(gh->handle,0x81,rxbuf,32,0);
+ if(ret<=0) {
+ perror("usb interrupt read");
+ return ret;
+ }
+ 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;
+
+ /* 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 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));
memset(gh,0,sizeof(struct gemtag_handle));
- numconf=gemtag->descriptor.bNumConfigurations;
- printf("found gemtag, %u configurations\n",numconf);
- for(i=0;i<numconf;i++) {
- numint=gemtag->config[i].bNumInterfaces;
- printf("config %u [nr %u] has %u interfaces\n",
- i,gemtag->config[i].bConfigurationValue,
- numint);
- for(j=0;j<numint;j++) {
- printf("config %u interface %u has %u altsettings\n",
- i,j,gemtag->config[i].interface[j].num_altsetting);
- }
- }
-
gh->handle=usb_open(gemtag);
if(!gh->handle)
goto out_free;
+ 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;
+ }
+ printf("set configuration 1, ");
+
+ if(usb_claim_interface(gh->handle,0)) {
+ perror("claim interface");
+ goto out_free;
+ }
+ printf("claimed interface 0\n");
+
+ /*
+ if(usb_set_altinterface(gh->handle,0))
+ perror("set alt interface");
+ printf("activated alt setting 0\n");
+ */
+
+ return gh;
+
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]=GEMTAG_PICC_AUTHENT1A; /* 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_write16(struct gemtag_handle *gh,int sector,unsigned char *data) {
+
+ unsigned char buf[32];
+ int ret,len;
+
+ buf[0]=GEMTAG_PICC_WRITE16;
+ buf[1]=sector;
+ memcpy(buf+2,data,16);
+ ret=gemtag_transceive(gh,GEMTAG_CMD_COMMON_WRITE,buf,18,buf,&len);
+
+ return ret;
+}
+
+int gemtag_select_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,ret;
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_select_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]);
+ i=0;
+ while(!gemtag_auth_mifare_key(gh,key6,i)) {
+ gemtag_read16(gh,i,buf);
+ printf("%02x: ",i);
+ hexdump(buf,16);
+ printf(" | ");
+ asciidump(buf,16);
+ printf("\n");
+ i+=1;
+ }
+ printf("\n");
+
+ /* try to write some data
+ printf("write some data to the 5th sector:\n");
+ for(i=0;i<16;i++) buf[i]=i;
+ i=4;
+ ret=gemtag_write16(gh,i,buf);
+ printf("return = %d\n",ret);
+ gemtag_read16(gh,i,buf);
+ printf("%02x: ",i);
+ hexdump(buf,16);
+ printf("\n");
+ */
+
+ gemtag_close(gh);
+
+ return 0;
}