]> git.zerfleddert.de Git - proxmark3-svn/blame - client/cmdhf15.c
typofixes in ISO15693 getUID head comment
[proxmark3-svn] / client / cmdhf15.c
CommitLineData
a553f267 1//-----------------------------------------------------------------------------
2// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
9455b51c 3// Modified 2010 by <adrian -at- atrox.at>
a553f267 4//
5// This code is licensed to you under the terms of the GNU GPL, version 2 or,
6// at your option, any later version. See the LICENSE.txt file for the text of
7// the license.
8//-----------------------------------------------------------------------------
9// High frequency ISO15693 commands
10//-----------------------------------------------------------------------------
9455b51c 11// There are three basic operation modes, depending on which device (proxmark/pc)
12// the signal processing, (de)modulation, transmission protocol and logic is done.
13// Mode 1:
14// All steps are done on the proxmark, the output of the commands is returned via
15// USB-debug-print commands.
16// Mode 2:
17// The protocol is done on the PC, passing only Iso15693 data frames via USB. This
18// allows direct communication with a tag on command level
19// Mode 3:
20// The proxmark just samples the antenna and passes this "analog" data via USB to
21// the client. Signal Processing & decoding is done on the pc. This is the slowest
22// variant, but offers the possibility to analyze the waveforms directly.
a553f267 23
7fe9b0b7 24#include <stdio.h>
25#include <stdlib.h>
26#include <string.h>
27#include <stdint.h>
28#include "proxusb.h"
29#include "data.h"
30#include "graph.h"
31#include "ui.h"
32#include "cmdparser.h"
33#include "cmdhf15.h"
9455b51c 34#include "iso15693tools.h"
35#include "cmdmain.h"
36
37#define FrameSOF Iso15693FrameSOF
38#define Logic0 Iso15693Logic0
39#define Logic1 Iso15693Logic1
40#define FrameEOF Iso15693FrameEOF
41
42#define Crc(data,datalen) Iso15693Crc(data,datalen)
43#define AddCrc(data,datalen) Iso15693AddCrc(data,datalen)
44#define sprintUID(target,uid) Iso15693sprintUID(target,uid)
7fe9b0b7 45
46static int CmdHelp(const char *Cmd);
47
9455b51c 48// structure and database for uid -> tagtype lookups
49typedef struct {
50 uint64_t uid;
51 int mask; // how many MSB bits used
52 char* desc;
53} productName;
54
55
56const productName uidmapping[] = {
c71e7235 57 { 0xE001000000000000LL, 16, "Motorola" },
58 { 0xE002000000000000LL, 16, "ST Microelectronics" },
59 { 0xE003000000000000LL, 16, "Hitachi" },
60 { 0xE004000000000000LL, 16, "Philips" },
61 { 0xE004010000000000LL, 24, "Philips; IC SL2 ICS20" },
62 { 0xE005000000000000LL, 16, "Infineon" },
63 { 0xE005400000000000LL, 24, "Infineon; 56x32bit" },
64 { 0xE006000000000000LL, 16, "Cylinc" },
9455b51c 65 { 0xE007000000000000LL, 16, "Texas Instrument; " },
66 { 0xE007000000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Inlay; 64x32bit" },
67 { 0xE007100000000000LL, 20, "Texas Instrument; Tag-it HF-I Plus Chip; 64x32bit" },
68 { 0xE007C00000000000LL, 23, "Texas Instrument; Tag-it HF-I Standard; 8x32bit" },
69 { 0xE007C40000000000LL, 23, "Texas Instrument; Tag-it HF-I Pro; 8x23bit; password" },
c71e7235 70 { 0xE008000000000000LL, 16, "Fujitsu" },
71 { 0xE009000000000000LL, 16, "Matsushita" },
72 { 0xE00A000000000000LL, 16, "NEC" },
73 { 0xE00B000000000000LL, 16, "Oki Electric" },
74 { 0xE00C000000000000LL, 16, "Toshiba" },
75 { 0xE00D000000000000LL, 16, "Mitsubishi" },
76 { 0xE00E000000000000LL, 16, "Samsung" },
77 { 0xE00F000000000000LL, 16, "Hyundai" },
78 { 0xE010000000000000LL, 16, "LG-Semiconductors" },
79 { 0xE012000000000000LL, 16, "HID Corporation" },
9455b51c 80 { 0xE016000000000000LL, 16, "EM-Marin SA (Skidata)" },
81 { 0xE016040000000000LL, 24, "EM-Marin SA (Skidata Keycard-eco); no memory" },
82 { 0xE016100000000000LL, 24, "EM-Marin SA (Skidata); EM4135; 36x64bit start page 13" },
83 { 0,0,"no tag-info available" } // must be the last entry
84};
85
86
e4da8ed0 87// fast method to just read the UID of a tag (collission detection not supported)
88// *buf should be large enough to fit the 64bit uid
9455b51c 89// returns 1 if suceeded
90int getUID(uint8_t *buf)
7fe9b0b7 91{
9455b51c 92 UsbCommand *r;
93 uint8_t *recv;
94 UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
95 uint8_t *req=c.d.asBytes;
96 int reqlen=0;
97
98 for (int retry=0;retry<3; retry++) { // don't give up the at the first try
99
100 req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
101 ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
102 req[1]=ISO15_CMD_INVENTORY;
103 req[2]=0; // mask length
104 reqlen=AddCrc(req,3);
105 c.arg[0]=reqlen;
106
107 SendCommand(&c);
108
109 r=WaitForResponseTimeout(CMD_ACK,1000);
110
111 if (r!=NULL) {
112 recv = r->d.asBytes;
113 if (r->arg[0]>=12 && ISO15_CRC_CHECK==Crc(recv,12)) {
114 memcpy(buf,&recv[2],8);
115 return 1;
116 }
117 }
118 } // retry
119 return 0;
120}
121
122
7fe9b0b7 123
9455b51c 124// get a product description based on the UID
125// uid[8] tag uid
126// returns description of the best match
127static char* getTagInfo(uint8_t *uid) {
31b6e9af 128 uint64_t myuid,mask;
9455b51c 129 int i=0, best=-1;
130 memcpy(&myuid,uid,sizeof(uint64_t));
131 while (uidmapping[i].mask>0) {
132 mask=(~0LL) <<(64-uidmapping[i].mask);
133 if ((myuid & mask) == uidmapping[i].uid) {
134 if (best==-1) {
135 best=i;
136 } else {
137 if (uidmapping[i].mask>uidmapping[best].mask) {
138 best=i;
139 }
140 }
141 }
142 i++;
143 }
7fe9b0b7 144
9455b51c 145 if (best>=0) return uidmapping[best].desc;
146
147 return uidmapping[i].desc;
7fe9b0b7 148}
149
9455b51c 150
b4a9d841 151// return a clear-text message to an errorcode
9455b51c 152static char* TagErrorStr(uint8_t error) {
b4a9d841 153 switch (error) {
154 case 0x01: return "The command is not supported";
155 case 0x02: return "The command is not recognised";
156 case 0x03: return "The option is not supported.";
157 case 0x0f: return "Unknown error.";
158 case 0x10: return "The specified block is not available (doesn’t exist).";
159 case 0x11: return "The specified block is already -locked and thus cannot be locked again";
160 case 0x12: return "The specified block is locked and its content cannot be changed.";
161 case 0x13: return "The specified block was not successfully programmed.";
162 case 0x14: return "The specified block was not successfully locked.";
163 default: return "Reserved for Future Use or Custom command error.";
164 }
9455b51c 165}
166
167
168// Mode 3
7fe9b0b7 169int CmdHF15Demod(const char *Cmd)
170{
9455b51c 171 // The sampling rate is 106.353 ksps/s, for T = 18.8 us
172
173 int i, j;
174 int max = 0, maxPos = 0;
175
176 int skip = 4;
177
178 if (GraphTraceLen < 1000) return 0;
179
180 // First, correlate for SOF
181 for (i = 0; i < 100; i++) {
182 int corr = 0;
183 for (j = 0; j < arraylen(FrameSOF); j += skip) {
184 corr += FrameSOF[j] * GraphBuffer[i + (j / skip)];
185 }
186 if (corr > max) {
187 max = corr;
188 maxPos = i;
189 }
190 }
191 PrintAndLog("SOF at %d, correlation %d", maxPos,
192 max / (arraylen(FrameSOF) / skip));
193
194 i = maxPos + arraylen(FrameSOF) / skip;
195 int k = 0;
196 uint8_t outBuf[20];
197 memset(outBuf, 0, sizeof(outBuf));
198 uint8_t mask = 0x01;
199 for (;;) {
200 int corr0 = 0, corr1 = 0, corrEOF = 0;
201 for (j = 0; j < arraylen(Logic0); j += skip) {
202 corr0 += Logic0[j] * GraphBuffer[i + (j / skip)];
203 }
204 for (j = 0; j < arraylen(Logic1); j += skip) {
205 corr1 += Logic1[j] * GraphBuffer[i + (j / skip)];
206 }
207 for (j = 0; j < arraylen(FrameEOF); j += skip) {
208 corrEOF += FrameEOF[j] * GraphBuffer[i + (j / skip)];
209 }
210 // Even things out by the length of the target waveform.
211 corr0 *= 4;
212 corr1 *= 4;
213
214 if (corrEOF > corr1 && corrEOF > corr0) {
215 PrintAndLog("EOF at %d", i);
216 break;
217 } else if (corr1 > corr0) {
218 i += arraylen(Logic1) / skip;
219 outBuf[k] |= mask;
220 } else {
221 i += arraylen(Logic0) / skip;
222 }
223 mask <<= 1;
224 if (mask == 0) {
225 k++;
226 mask = 0x01;
227 }
228 if ((i + (int)arraylen(FrameEOF)) >= GraphTraceLen) {
229 PrintAndLog("ran off end!");
230 break;
231 }
232 }
233 if (mask != 0x01) {
234 PrintAndLog("error, uneven octet! (discard extra bits!)");
235 PrintAndLog(" mask=%02x", mask);
236 }
237 PrintAndLog("%d octets", k);
238
239 for (i = 0; i < k; i++) {
240 PrintAndLog("# %2d: %02x ", i, outBuf[i]);
241 }
242 PrintAndLog("CRC=%04x", Iso15693Crc(outBuf, k - 2));
243 return 0;
7fe9b0b7 244}
245
9455b51c 246
247
248// * Acquire Samples as Reader (enables carrier, sends inquiry)
7fe9b0b7 249int CmdHF15Read(const char *Cmd)
250{
9455b51c 251 UsbCommand c = {CMD_ACQUIRE_RAW_ADC_SAMPLES_ISO_15693};
252 SendCommand(&c);
253 return 0;
254}
255
256// Record Activity without enabeling carrier
257int CmdHF15Record(const char *Cmd)
258{
259 UsbCommand c = {CMD_RECORD_RAW_ADC_SAMPLES_ISO_15693};
260 SendCommand(&c);
261 return 0;
7fe9b0b7 262}
263
264int CmdHF15Reader(const char *Cmd)
265{
9455b51c 266 UsbCommand c = {CMD_READER_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}};
267 SendCommand(&c);
268 return 0;
7fe9b0b7 269}
270
9455b51c 271// Simulation is still not working very good
7fe9b0b7 272int CmdHF15Sim(const char *Cmd)
273{
9455b51c 274 UsbCommand c = {CMD_SIMTAG_ISO_15693, {strtol(Cmd, NULL, 0), 0, 0}};
275 SendCommand(&c);
276 return 0;
7fe9b0b7 277}
278
9455b51c 279// finds the AFI (Application Family Idendifier) of a card, by trying all values
280// (There is no standard way of reading the AFI, allthough some tags support this)
281int CmdHF15Afi(const char *Cmd)
7fe9b0b7 282{
9455b51c 283 UsbCommand c = {CMD_ISO_15693_FIND_AFI, {strtol(Cmd, NULL, 0), 0, 0}};
284 SendCommand(&c);
285 return 0;
286}
287
288// Reads all memory pages
289int CmdHF15DumpMem(const char*Cmd) {
290 UsbCommand *r;
291 uint8_t uid[8];
292 uint8_t *recv=NULL;
293 UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
294 uint8_t *req=c.d.asBytes;
295 int reqlen=0;
296 int blocknum=0;
297 char output[80];
298
299 if (!getUID(uid)) {
300 PrintAndLog("No Tag found.");
301 return 0;
302 }
303
304 PrintAndLog("Reading memory from tag UID=%s",sprintUID(NULL,uid));
305 PrintAndLog("Tag Info: %s",getTagInfo(uid));
306
307 for (int retry=0; retry<5; retry++) {
308
309 req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
310 ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
311 req[1]=ISO15_CMD_READ;
312 memcpy(&req[2],uid,8);
313 req[10]=blocknum;
314 reqlen=AddCrc(req,11);
315 c.arg[0]=reqlen;
316
317 SendCommand(&c);
318
319 r=WaitForResponseTimeout(CMD_ACK,1000);
320
321 if (r!=NULL) {
322 recv = r->d.asBytes;
323 if (ISO15_CRC_CHECK==Crc(recv,r->arg[0])) {
324 if (!(recv[0] & ISO15_RES_ERROR)) {
325 retry=0;
326 *output=0; // reset outputstring
327 sprintf(output, "Block %2i ",blocknum);
328 for ( int i=1; i<r->arg[0]-2; i++) { // data in hex
329 sprintf(output+strlen(output),"%02hX ",recv[i]);
330 }
331 strcat(output," ");
332 for ( int i=1; i<r->arg[0]-2; i++) { // data in cleaned ascii
333 sprintf(output+strlen(output),"%c",(recv[i]>31 && recv[i]<127)?recv[i]:'.');
334 }
335 PrintAndLog("%s",output);
336 blocknum++;
337 // PrintAndLog("bn=%i",blocknum);
338 } else {
b4a9d841 339 PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1]));
9455b51c 340 return 0;
341 }
342 } // else PrintAndLog("crc");
343 } // else PrintAndLog("r null");
344
345 } // retry
346 if (r && r->arg[0]<3)
347 PrintAndLog("Lost Connection");
348 else if (r && ISO15_CRC_CHECK!=Crc(r->d.asBytes,r->arg[0]))
349 PrintAndLog("CRC Failed");
350 else
b4a9d841 351 PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1]));
9455b51c 352 return 0;
353}
354
355
356// "HF 15" interface
357
358static command_t CommandTable15[] =
359{
360 {"help", CmdHF15Help, 1, "This help"},
361 {"demod", CmdHF15Demod, 1, "Demodulate ISO15693 from tag"},
362 {"read", CmdHF15Read, 0, "Read HF tag (ISO 15693)"},
363 {"record", CmdHF15Record, 0, "Record Samples (ISO 15693)"}, // atrox
364 {"reader", CmdHF15Reader, 0, "Act like an ISO15693 reader"},
365 {"sim", CmdHF15Sim, 0, "Fake an ISO15693 tag"},
366 {"cmd", CmdHF15Cmd, 0, "Send direct commands to ISO15693 tag"},
367 {"findafi", CmdHF15Afi, 0, "Brute force AFI of an ISO15693 tag"},
368 {"dumpmemory", CmdHF15DumpMem, 0, "Read all memory pages of an ISO15693 tag"},
369 {NULL, NULL, 0, NULL}
7fe9b0b7 370};
371
372int CmdHF15(const char *Cmd)
373{
9455b51c 374 CmdsParse(CommandTable15, Cmd);
375 return 0;
7fe9b0b7 376}
377
9455b51c 378int CmdHF15Help(const char *Cmd)
7fe9b0b7 379{
9455b51c 380 CmdsHelp(CommandTable15);
381 return 0;
7fe9b0b7 382}
9455b51c 383
384
385// "HF 15 Cmd" Interface
386// Allows direct communication with the tag on command level
387
388int CmdHF15CmdInquiry(const char *Cmd)
389{
390 UsbCommand *r;
391 uint8_t *recv;
392 UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
393 uint8_t *req=c.d.asBytes;
394 int reqlen=0;
395
396 req[0]= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
397 ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
398 req[1]=ISO15_CMD_INVENTORY;
399 req[2]=0; // mask length
400 reqlen=AddCrc(req,3);
401 c.arg[0]=reqlen;
402
403 SendCommand(&c);
404
405 r=WaitForResponseTimeout(CMD_ACK,1000);
406
407 if (r!=NULL) {
408 if (r->arg[0]>=12) {
409 recv = r->d.asBytes;
410 PrintAndLog("UID=%s",sprintUID(NULL,&recv[2]));
411 PrintAndLog("Tag Info: %s",getTagInfo(&recv[2]));
412 } else {
413 PrintAndLog("Response to short, just %i bytes. No tag?\n",r->arg[0]);
414 }
415 } else {
416 PrintAndLog("timeout.");
417 }
418 return 0;
419}
420
421
422// Turns debugging on(1)/off(0)
423int CmdHF15CmdDebug( const char *cmd) {
424 int debug=atoi(cmd);
425 if (strlen(cmd)<1) {
426 PrintAndLog("Usage: hf 15 cmd debug <0/1>");
427 PrintAndLog(" 0..no debugging output 1..turn debugging on");
428 return 0;
429 }
430
431 UsbCommand c = {CMD_ISO_15693_DEBUG, {debug, 0, 0}};
432 SendCommand(&c);
433 return 0;
434}
435
436
437int CmdHF15CmdRaw (const char *cmd) {
438 UsbCommand *r;
439 uint8_t *recv;
440 UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
441 int reply=1;
442 int fast=1;
443 int crc=0;
444 char buf[5]="";
445 int i=0;
446 uint8_t data[100];
447 unsigned int datalen=0, temp;
448
449
450 if (strlen(cmd)<3) {
451 PrintAndLog("Usage: hf 15 cmd raw [-r] [-2] [-c] <0A 0B 0C ... hex>");
452 PrintAndLog(" -r do not read response");
453 PrintAndLog(" -2 use slower '1 out of 256' mode");
454 PrintAndLog(" -c calculate and append CRC");
455 PrintAndLog(" Tip: turn on debugging for verbose output");
456 return 0;
457 }
458
459 // strip
460 while (*cmd==' ' || *cmd=='\t') cmd++;
461
462 while (cmd[i]!='\0') {
463 if (cmd[i]==' ' || cmd[i]=='\t') { i++; continue; }
464 if (cmd[i]=='-') {
465 switch (cmd[i+1]) {
466 case 'r':
467 case 'R':
468 reply=0;
469 break;
470 case '2':
471 fast=0;
472 break;
473 case 'c':
474 case 'C':
475 crc=1;
476 break;
477 default:
478 PrintAndLog("Invalid option");
479 return 0;
480 }
481 i+=2;
482 continue;
483 }
484 if ((cmd[i]>='0' && cmd[i]<='9') ||
485 (cmd[i]>='a' && cmd[i]<='f') ||
486 (cmd[i]>='A' && cmd[i]<='F') ) {
487 buf[strlen(buf)+1]=0;
488 buf[strlen(buf)]=cmd[i];
489 i++;
490
491 if (strlen(buf)>=2) {
492 sscanf(buf,"%x",&temp);
493 data[datalen]=(uint8_t)(temp & 0xff);
494 datalen++;
495 *buf=0;
496 }
497 continue;
498 }
499 PrintAndLog("Invalid char on input");
500 return 0;
501 }
502 if (crc) datalen=AddCrc(data,datalen);
503
504 c.arg[0]=datalen;
505 c.arg[1]=fast;
506 c.arg[2]=reply;
507 memcpy(c.d.asBytes,data,datalen);
508
509 SendCommand(&c);
510
511 if (reply) {
512 r=WaitForResponseTimeout(CMD_ACK,1000);
513
514 if (r!=NULL) {
515 recv = r->d.asBytes;
516 PrintAndLog("received %i octets",r->arg[0]);
517 // TODO: output
518 } else {
519 PrintAndLog("timeout while waiting for reply.");
520 }
521
522 } // if reply
523 return 0;
524}
525
526
527int prepareHF15Cmd(char **cmd, UsbCommand *c, uint8_t iso15cmd[], int iso15cmdlen) {
528 int temp;
529 uint8_t *req=c->d.asBytes, uid[8];
530 uint32_t reqlen=0;
531
532 // strip
533 while (**cmd==' ' || **cmd=='\t') (*cmd)++;
534
535 if (strstr(*cmd,"-2")==*cmd) {
536 c->arg[1]=0; // quse 1of256
537 (*cmd)+=2;
538 }
539
540 // strip
541 while (**cmd==' ' || **cmd=='\t') (*cmd)++;
542
543 if (strstr(*cmd,"-o")==*cmd) {
544 req[reqlen]=ISO15_REQ_OPTION;
545 (*cmd)+=2;
546 }
547
548 // strip
549 while (**cmd==' ' || **cmd=='\t') (*cmd)++;
550
551 switch (**cmd) {
552 case 0:
553 PrintAndLog("missing addr");
554 return 0;
555 break;
556 case 's':
557 case 'S':
558 // you must have selected the tag earlier
559 req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
560 ISO15_REQ_NONINVENTORY | ISO15_REQ_SELECT;
561 memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
562 reqlen+=iso15cmdlen;
563 break;
564 case 'u':
565 case 'U':
566 // unaddressed mode may not be supported by all vendors
567 req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
568 ISO15_REQ_NONINVENTORY;
569 memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
570 reqlen+=iso15cmdlen;
571 break;
572 case '*':
573 req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
574 ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
575 memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
576 reqlen+=iso15cmdlen;
577 if (!getUID(uid)) {
578 PrintAndLog("No Tag found");
579 return 0;
580 }
581 memcpy(req+reqlen,uid,8);
582 PrintAndLog("Detected UID %s",sprintUID(NULL,uid));
583 reqlen+=8;
584 break;
585 default:
586 req[reqlen++]|= ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH |
587 ISO15_REQ_NONINVENTORY | ISO15_REQ_ADDRESS;
588 memcpy(&req[reqlen],&iso15cmd[0],iso15cmdlen);
589 reqlen+=iso15cmdlen;
590
591/* sscanf(cmd,"%hX%hX%hX%hX%hX%hX%hX%hX",
592 (short unsigned int *)&uid[7],(short unsigned int *)&uid[6],
593 (short unsigned int *)&uid[5],(short unsigned int *)&uid[4],
594 (short unsigned int *)&uid[3],(short unsigned int *)&uid[2],
595 (short unsigned int *)&uid[1],(short unsigned int *)&uid[0]); */
596 for (int i=0;i<8 && (*cmd)[i*2] && (*cmd)[i*2+1];i++) { // parse UID
597 sscanf((char[]){(*cmd)[i*2],(*cmd)[i*2+1],0},"%X",&temp);
598 uid[7-i]=temp&0xff;
599 }
600
601 PrintAndLog("Using UID %s",sprintUID(NULL,uid));
602 memcpy(&req[reqlen],&uid[0],8);
603 reqlen+=8;
604 }
605 // skip to next space
606 while (**cmd!=' ' && **cmd!='\t') (*cmd)++;
607 // skip over the space
608 while (**cmd==' ' || **cmd=='\t') (*cmd)++;
609
610 c->arg[0]=reqlen;
611 return 1;
612}
613
614
615
616int CmdHF15CmdRead(const char *Cmd) {
617 UsbCommand *r;
618 uint8_t *recv;
619 UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
620 uint8_t *req=c.d.asBytes;
621 int reqlen=0, pagenum;
622 char cmdbuf[100];
623 char *cmd=cmdbuf;
624 char output[100]="";
625
626 strncpy(cmd,Cmd,99);
627
628 // usage:
629 if (strlen(cmd)<3) {
630 PrintAndLog("Usage: hf 15 cmd read [options] <uid|s|*> <page#>");
631 PrintAndLog(" options:");
632 PrintAndLog(" -2 use slower '1 out of 256' mode");
633 PrintAndLog(" uid (either): ");
634 PrintAndLog(" <8B hex> full UID eg E011223344556677");
635 PrintAndLog(" s selected tag");
636 PrintAndLog(" u unaddressed mode");
637 PrintAndLog(" * scan for tag");
638 PrintAndLog(" page#: page number 0-255");
639 return 0;
640 }
641
642 prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_READ},1);
643 reqlen=c.arg[0];
644
645 pagenum=strtol(cmd,NULL,0);
646 /*if (pagenum<0) {
647 PrintAndLog("invalid pagenum");
648 return 0;
649 } */
650
651 req[reqlen++]=(uint8_t)pagenum;
652
653 reqlen=AddCrc(req,reqlen);
654
655 c.arg[0]=reqlen;
656
657 SendCommand(&c);
658
659 r=WaitForResponseTimeout(CMD_ACK,1000);
660
661 if (r!=NULL && r->arg[0]>2) {
662 recv = r->d.asBytes;
663 if (ISO15_CRC_CHECK==Crc(recv,r->arg[0])) {
664 if (!(recv[0] & ISO15_RES_ERROR)) {
665 *output=0; // reset outputstring
666 //sprintf(output, "Block %2i ",blocknum);
667 for ( int i=1; i<r->arg[0]-2; i++) {
668 sprintf(output+strlen(output),"%02hX ",recv[i]);
669 }
670 strcat(output," ");
671 for ( int i=2; i<r->arg[0]-2; i++) {
672 sprintf(output+strlen(output),"%c",recv[i]>31 || recv[i]<127?recv[i]:'.');
673 }
674 PrintAndLog("%s",output);
675 } else {
b4a9d841 676 PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1]));
9455b51c 677 }
678 } else {
679 PrintAndLog("CRC failed");
680 }
681 } else {
682 PrintAndLog("no answer");
683 }
684
685 return 0;
686}
687
688
689int CmdHF15CmdWrite(const char *Cmd) {
690 UsbCommand *r;
691 uint8_t *recv;
692 UsbCommand c = {CMD_ISO_15693_COMMAND, {0, 1, 1}}; // len,speed,recv?
693 uint8_t *req=c.d.asBytes;
694 int reqlen=0, pagenum, temp;
695 char cmdbuf[100];
696 char *cmd=cmdbuf;
697 char *cmd2;
698
699 strncpy(cmd,Cmd,99);
700
701 // usage:
702 if (strlen(cmd)<3) {
703 PrintAndLog("Usage: hf 15 cmd write [options] <uid|s|*> <page#> <hexdata>");
704 PrintAndLog(" options:");
705 PrintAndLog(" -2 use slower '1 out of 256' mode");
706 PrintAndLog(" -o set OPTION Flag (needed for TI)");
707 PrintAndLog(" uid (either): ");
708 PrintAndLog(" <8B hex> full UID eg E011223344556677");
709 PrintAndLog(" s selected tag");
710 PrintAndLog(" u unaddressed mode");
711 PrintAndLog(" * scan for tag");
712 PrintAndLog(" page#: page number 0-255");
713 PrintAndLog(" hexdata: data to be written eg AA BB CC DD");
714 return 0;
715 }
716
717 prepareHF15Cmd(&cmd, &c,(uint8_t[]){ISO15_CMD_WRITE},1);
718 reqlen=c.arg[0];
719
720 // *cmd -> page num ; *cmd2 -> data
721 cmd2=cmd;
722 while (*cmd2!=' ' && *cmd2!='\t' && *cmd2) cmd2++;
723 *cmd2=0;
724 cmd2++;
725
726 pagenum=strtol(cmd,NULL,0);
727 /*if (pagenum<0) {
728 PrintAndLog("invalid pagenum");
729 return 0;
730 } */
731 req[reqlen++]=(uint8_t)pagenum;
732
733
734 while (cmd2[0] && cmd2[1]) { // hexdata, read by 2 hexchars
735 if (*cmd2==' ') {
736 cmd2++;
737 continue;
738 }
739 sscanf((char[]){cmd2[0],cmd2[1],0},"%X",&temp);
740 req[reqlen++]=temp & 0xff;
741 cmd2+=2;
742 }
743
744 reqlen=AddCrc(req,reqlen);
745
746 c.arg[0]=reqlen;
747
748 SendCommand(&c);
749
750 r=WaitForResponseTimeout(CMD_ACK,2000);
751
752 if (r!=NULL && r->arg[0]>2) {
753 recv = r->d.asBytes;
754 if (ISO15_CRC_CHECK==Crc(recv,r->arg[0])) {
755 if (!(recv[0] & ISO15_RES_ERROR)) {
756 PrintAndLog("OK");
757 } else {
b4a9d841 758 PrintAndLog("Tag returned Error %i: %s",recv[1],TagErrorStr(recv[1]));
9455b51c 759 }
760 } else {
761 PrintAndLog("CRC failed");
762 }
763 } else {
764 PrintAndLog("no answer");
765 }
766
767 return 0;
768}
769
770
771
772static command_t CommandTable15Cmd[] =
773{
774 {"help", CmdHF15CmdHelp, 1, "This Help"},
775 {"inquiry", CmdHF15CmdInquiry, 0, "Search for tags in range"},
776 /*
777 {"select", CmdHF15CmdSelect, 0, "Select an tag with a specific UID for further commands"},
778 */
779 {"read", CmdHF15CmdRead, 0, "Read a block"},
780 {"write", CmdHF15CmdWrite, 0, "Write a block"},
781/*
782 {"readmulti",CmdHF15CmdReadmulti, 0, "Reads multiple Blocks"},
783*/
784 {"raw", CmdHF15CmdRaw, 0, "Send raw hex data to tag"},
785 {"debug", CmdHF15CmdDebug, 0, "Turn debugging on/off"},
786 {NULL, NULL, 0, NULL}
787};
788
789int CmdHF15Cmd(const char *Cmd)
790{
791 CmdsParse(CommandTable15Cmd, Cmd);
792 return 0;
793}
794
795int CmdHF15CmdHelp(const char *Cmd)
796{
797 CmdsHelp(CommandTable15Cmd);
798 return 0;
799}
800
Impressum, Datenschutz