add some rude code for pegoda mifare classic operation
[librfid] / pegoda / pegoda.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <unistd.h>
4 #include <string.h>
5 #include <errno.h>
6
7 #include <usb.h>
8
9 #define USB_VENDOR_PHILIPS      0x0742
10 #define USB_DEVICE_PEGODA       0xff01
11
12 /* header of a pegoda usb command packet */
13 struct pegoda_cmd_hdr {
14         u_int8_t seq;
15         u_int8_t cmd;
16         u_int16_t len;
17 };
18
19 enum {
20         PEGODA_CMD_WRITE_RC                     = 0x01,
21         PEGODA_CMD_READ_RC                      = 0x02,
22         PEGODA_CMD_EXCHANGE_BYTESTREAM          = 0x03,
23         PEGODA_CMD_WRITE_MULTIPLE               = 0x04,
24         PEGODA_CMD_READ_MULTIPLE                = 0x05,
25         
26         PEGODA_CMD_PCD_CONFIG                   = 0x10,
27         PEGODA_CMD_PICC_REQUEST                 = 0x11,
28         PEGODA_CMD_PICC_ANTICOLL                = 0x12,
29         PEGODA_CMD_PICC_SELECT                  = 0x13,
30         PEGODA_CMD_PICC_AUTH                    = 0x14,
31         PEGODA_CMD_PICC_AUTH_E2                 = 0x15,
32         PEGODA_CMD_LOAD_KEY_E2                  = 0x17,
33         PEGODA_CMD_PICC_AUTH_KEY                = 0x18,
34         PEGODA_CMD_PICC_READ                    = 0x19,
35         PEGODA_CMD_PICC_WRITE                   = 0x1a,
36         PEGODA_CMD_PICC_VALUE                   = 0x1b,
37         PEGODA_CMD_PICC_VALUE_DEBIT             = 0x1c,
38         PEGODA_CMD_PICC_HALT                    = 0x1d,
39         PEGODA_CMD_PICC_WRITE4                  = 0x1e,
40         PEGODA_CMD_PICC_COMMON_WRITE            = 0x1f,
41
42         PEGODA_CMD_PCD_RF_RESET                 = 0x21,
43         PEGODA_CMD_PCD_RESET                    = 0x21,
44         PEGODA_CMD_PCD_GET_SNR                  = 0x22,
45         PEGODA_CMD_PCD_READ_E2                  = 0x23,
46         PEGODA_CMD_PCD_SET_TMO                  = 0x27,
47         PEGODA_CMD_PICC_COMMON_READ             = 0x28,
48         PEGODA_CMD_ACTIVE_ANTENNA_MASTER        = 0x2a,
49         PEGODA_CMD_ACTIVE_ANTENNA_SLAVE         = 0x2b,
50
51         PEGODA_CMD_PICC_COMMON_REQUEST          = 0x40,
52         PEGODA_CMD_PICC_CASC_ANTICOLL           = 0x41,
53         PEGODA_CMD_PICC_CASC_SELECT             = 0x42,
54         PEGODA_CMD_PICC_ACTIVATE_IDLE           = 0x43,
55         PEGODA_CMD_ACTIVATE_WAKEUP              = 0x44,
56
57         PEGODA_CMD_PICC_ACTIVATE_WAKEUP         = 0x44,
58         PEGODA_CMD_PCD_SET_DEFAULT_ATTRIB       = 0x45,
59         PEGODA_CMD_PCD_SET_ATTRIB               = 0x46,
60         PEGODA_CMD_PCD_GET_ATTRIB               = 0x47,
61         PEGODA_CMD_PICC_EXCHANGE_BLOCK          = 0x48,
62         PEGODA_CMD_PICC_ACTIVATE_IDLE_LOOP      = 0x49,
63         PEGODA_CMD_PICC_ACTTIVATION             = 0x4a,
64
65
66         PEGODA_CMD_GET_FW_VERSION               = 0x63,
67         PEGODA_CMD_GET_RIC_VERSION              = 0x64,
68         PEGODA_CMD_ENABLE_DEBUG_PINS            = 0x65,
69 };
70
71 const char *
72 rfid_hexdump(const void *data, unsigned int len)
73 {
74         static char string[1024];
75         unsigned char *d = (unsigned char *) data;
76         unsigned int i, left;
77
78         string[0] = '\0';
79         left = sizeof(string);
80         for (i = 0; len--; i += 3) {
81                 if (i >= sizeof(string) -4)
82                         break;
83                 snprintf(string+i, 4, " %02x", *d++);
84         }
85         return string;
86 }
87
88
89 struct usb_device *find_device(u_int16_t vendor, u_int16_t device)
90 {
91         struct usb_bus *bus;
92
93         for (bus = usb_get_busses(); bus; bus = bus->next) {
94                 struct usb_device *dev;
95                 for (dev = bus->devices; dev; dev = dev->next) {
96                         printf("vend 0x%x dev 0x%x\n",
97                                 dev->descriptor.idVendor, dev->descriptor.idProduct);
98                         if (dev->descriptor.idVendor == vendor &&
99                             dev->descriptor.idProduct == device) {
100                                 return dev;
101                         }
102                 }
103         }
104         return NULL;
105 }
106
107 static unsigned char seq = 0x00;
108 static struct usb_dev_handle *pegoda_handle;
109
110 int pegoda_transcieve(u_int8_t cmd, unsigned char *tx, unsigned int tx_len,
111                       unsigned char *rx, unsigned int *rx_len)
112 {
113         unsigned char txbuf[256];
114         unsigned char rxbuf[256];
115         int rc;
116         unsigned int len_expected;
117         struct pegoda_cmd_hdr *hdr = txbuf;
118
119         hdr->seq = ++seq;
120         hdr->cmd = cmd;
121         hdr->len = htons(tx_len);
122         memcpy(txbuf + sizeof(*hdr), tx, tx_len);
123
124         printf("tx [%u]: %s\n", tx_len+sizeof(*hdr), rfid_hexdump(txbuf, tx_len + sizeof(*hdr)));
125         rc = usb_bulk_write(pegoda_handle, 0x02, (char *)txbuf,
126                             tx_len + sizeof(*hdr), 0);
127         if (rc < 0)
128                 return rc;
129
130         rc = usb_bulk_read(pegoda_handle, 0x81, (char *)rxbuf, sizeof(rxbuf), 0);
131         if (rc <= 0)
132                 return rc;
133
134         if (rc != 2) {
135                 fprintf(stderr, "unexpected: received %u bytes as length?\n");
136                 return -EIO;
137         }
138         printf("len [%u]: %s\n", rc, rfid_hexdump(rxbuf, rc));
139
140         len_expected = rxbuf[0];
141
142         if (len_expected > sizeof(rxbuf))
143                 return -EIO;
144
145         rc = usb_bulk_read(pegoda_handle, 0x81, (char *)rxbuf, len_expected, 0);
146         if (rc <= 0)
147                 return rc;
148         printf("rx [%u]: %s\n", rc, rfid_hexdump(rxbuf, rc));
149
150         memcpy(rx, rxbuf+1, rc-1);
151         *rx_len = rc - 1;
152
153         return 0;
154 }
155
156 /* Transform crypto1 key from generic 6byte into rc632 specific 12byte */
157 static int
158 rc632_mifare_transform_key(const u_int8_t *key6, u_int8_t *key12)
159 {
160         int i;
161         u_int8_t ln;
162         u_int8_t hn;
163
164         for (i = 0; i < 6; i++) {
165                 ln = key6[i] & 0x0f;
166                 hn = key6[i] >> 4;
167                 key12[i * 2 + 1] = (~ln << 4) | ln;
168                 key12[i * 2] = (~hn << 4) | hn;
169         }
170         return 0;
171 }
172
173
174 int main(int argc, char **argv)
175 {
176         struct usb_device *pegoda;
177         unsigned char buf[256];
178         unsigned char rbuf[256];
179         unsigned int rlen = sizeof(rbuf);
180         unsigned char snr[4];
181
182         usb_init();
183         usb_find_busses();
184         usb_find_devices();
185
186         pegoda = find_device(USB_VENDOR_PHILIPS, USB_DEVICE_PEGODA);
187
188         if (!pegoda)
189                 exit(2);
190
191         printf("found pegoda, %u configurations\n",
192                 pegoda->descriptor.bNumConfigurations);
193
194         printf("config 2 [nr %u] has %u interfaces\n",
195                 pegoda->config[1].bConfigurationValue,
196                 pegoda->config[1].bNumInterfaces);
197
198         printf("config 2 interface 0 has %u altsettings\n",
199                 pegoda->config[1].interface[0].num_altsetting);
200
201         pegoda_handle = usb_open(pegoda);
202         if (!pegoda_handle)
203                 exit(1);
204
205         if (usb_set_configuration(pegoda_handle, 2))
206                 exit(1);
207
208         printf("configuration 2 successfully set\n");
209
210         if (usb_claim_interface(pegoda_handle, 0))
211                 exit(1);
212
213         printf("interface 0 claimed\n");
214
215         if (usb_set_altinterface(pegoda_handle, 1))
216                 exit(1);
217
218         printf("alt setting 1 selected\n");
219
220         pegoda_transcieve(PEGODA_CMD_PCD_CONFIG, NULL, 0, rbuf, &rlen);
221
222         buf[0] = 0x26;
223         rlen = sizeof(rbuf);
224         pegoda_transcieve(PEGODA_CMD_PICC_COMMON_REQUEST, buf, 1, rbuf, &rlen);
225
226         buf[0] = 0x93;
227         memset(buf+1, 0, 5);
228         rlen = sizeof(rbuf);
229         pegoda_transcieve(PEGODA_CMD_PICC_CASC_ANTICOLL, buf, 6, rbuf, &rlen);
230
231         memcpy(snr, rbuf+3, 4);
232
233         buf[0] = 0x93;
234         memcpy(buf+1, snr, 4);
235         rlen = sizeof(rbuf);
236         pegoda_transcieve(PEGODA_CMD_PICC_CASC_SELECT, buf, 5, rbuf, &rlen);
237         
238         buf[0] = 0x60;
239 #if 0
240         buf[1] = 0x00;  /* key number */
241         buf[2] = 0x00;  /* sector */
242         rlen = sizeof(rbuf);
243         pegoda_transcieve(PEGODA_CMD_PICC_AUTH, buf, 3, rbuf, &rlen);
244 #else
245         memcpy(buf+1, snr, 4);
246         { 
247                 u_int8_t key6[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
248                 //u_int8_t key6[6] = { 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6 };
249                 u_int8_t key12[12];
250
251                 rc632_mifare_transform_key(key6, key12);
252
253                 memcpy(buf+5, key12, 12);
254                 buf[17] = 0x00; /* sector */
255         }
256         pegoda_transcieve(PEGODA_CMD_PICC_AUTH_KEY, buf, 18, rbuf, &rlen);
257 #endif
258
259         buf[0] = 0x00; /* sector */
260         pegoda_transcieve(PEGODA_CMD_PICC_READ, buf, 1, rbuf, &rlen);
261
262         exit(0);
263 }