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