1 //-----------------------------------------------------------------------------
2 // Copyright (C) 2010 iZsh <izsh at fail0verflow.com>, Hagen Fritsch
3 // Copyright (C) 2011 Gerhard de Koning Gans
4 // Copyright (C) 2014 Midnitesnake & Andy Davies & Martin Holst Swende
6 // This code is licensed to you under the terms of the GNU GPL, version 2 or,
7 // at your option, any later version. See the LICENSE.txt file for the text of
9 //-----------------------------------------------------------------------------
10 // High frequency iClass commands
11 //-----------------------------------------------------------------------------
17 #include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
19 #include "proxmark3.h"
21 #include "cmdparser.h"
22 #include "cmdhficlass.h"
23 #include "../include/common.h"
26 #include "loclass/des.h"
27 #include "loclass/cipherutils.h"
28 #include "loclass/cipher.h"
29 #include "loclass/ikeys.h"
30 #include "loclass/elite_crack.h"
31 #include "loclass/fileutils.h"
33 static int CmdHelp(const char *Cmd
);
35 int xorbits_8(uint8_t val
)
37 uint8_t res
= val
^ (val
>> 1); //1st pass
38 res
= res
^ (res
>> 1); // 2nd pass
39 res
= res
^ (res
>> 2); // 3rd pass
40 res
= res
^ (res
>> 4); // 4th pass
44 int CmdHFiClassList(const char *Cmd
)
47 bool ShowWaitCycles
= false;
48 char param
= param_getchar(Cmd
, 0);
51 PrintAndLog("List data in trace buffer.");
52 PrintAndLog("Usage: hf iclass list");
53 PrintAndLog("h - help");
54 PrintAndLog("sample: hf iclass list");
58 uint8_t got
[TRACE_BUFFER_SIZE
];
59 GetFromBigBuf(got
,sizeof(got
),0);
60 WaitForResponse(CMD_ACK
,NULL
);
62 PrintAndLog("Recorded Activity");
64 PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
65 PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
67 PrintAndLog(" Start | End | Src | Data");
68 PrintAndLog("-----------|-----------|-----|--------");
71 uint32_t first_timestamp
= 0;
77 uint32_t EndOfTransmissionTimestamp
= 0;
80 for( i
=0; i
< TRACE_BUFFER_SIZE
;)
82 //First 32 bits contain
84 // timestamp (remaining)
87 timestamp
= *((uint32_t *)(got
+i
));
88 parityBits
= *((uint32_t *)(got
+i
+4));
91 uint32_t next_timestamp
= (*((uint32_t *)(got
+i
+9))) & 0x7fffffff;
93 tagToReader
= timestamp
& 0x80000000;
94 timestamp
&= 0x7fffffff;
97 first_timestamp
= timestamp
;
100 // Break and stick with current result idf buffer was not completely full
101 if (frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[2] == 0x44 && frame
[3] == 0x44) break;
103 char line
[1000] = "";
105 if(len
)//We have some data to display
109 for(j
= 0; j
< len
; j
++)
111 oddparity
= 0x01 ^ xorbits_8(frame
[j
] & 0xFF);
113 if (tagToReader
&& (oddparity
!= ((parityBits
>> (len
- j
- 1)) & 0x01))) {
114 sprintf(line
+(j
*4), "%02x! ", frame
[j
]);
116 sprintf(line
+(j
*4), "%02x ", frame
[j
]);
121 if (ShowWaitCycles
) {
122 sprintf(line
, "fdt (Frame Delay Time): %d", (next_timestamp
- timestamp
));
131 if(!tagToReader
&& len
== 4) {
132 // Rough guess that this is a command from the reader
133 // For iClass the command byte is not part of the CRC
134 ComputeCrc14443(CRC_ICLASS
, &frame
[1], len
-3, &b1
, &b2
);
137 // For other data.. CRC might not be applicable (UPDATE commands etc.)
138 ComputeCrc14443(CRC_ICLASS
, frame
, len
-2, &b1
, &b2
);
141 if (b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
142 crc
= (tagToReader
& (len
< 8)) ? "" : " !crc";
147 EndOfTransmissionTimestamp
= (*((uint32_t *)(got
+i
))) & 0x7fffffff;
149 // Not implemented for iclass on the ARM-side
150 //if (!ShowWaitCycles) i += 9;
152 PrintAndLog(" %9d | %9d | %s | %s %s",
153 (timestamp
- first_timestamp
),
154 (EndOfTransmissionTimestamp
- first_timestamp
),
155 (len
?(tagToReader
? "Tag" : "Rdr"):" "),
161 int CmdHFiClassListOld(const char *Cmd
)
164 GetFromBigBuf(got
,sizeof(got
),0);
166 PrintAndLog("recorded activity:");
167 PrintAndLog(" ETU :rssi: who bytes");
168 PrintAndLog("---------+----+----+-----------");
179 int timestamp
= *((uint32_t *)(got
+i
));
180 if (timestamp
& 0x80000000) {
181 timestamp
&= 0x7fffffff;
190 int parityBits
= *((uint32_t *)(got
+i
+4));
191 // 4 bytes of additional information...
192 // maximum of 32 additional parity bit information
195 // at each quarter bit period we can send power level (16 levels)
196 // or each half bit period in 256 levels.
204 if (i
+ len
>= 1900) {
208 uint8_t *frame
= (got
+i
+9);
210 // Break and stick with current result if buffer was not completely full
211 if (frame
[0] == 0x44 && frame
[1] == 0x44 && frame
[3] == 0x44) { break; }
213 char line
[1000] = "";
215 for (j
= 0; j
< len
; j
++) {
216 int oddparity
= 0x01;
220 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
223 //if((parityBits >> (len - j - 1)) & 0x01) {
224 if (isResponse
&& (oddparity
!= ((parityBits
>> (len
- j
- 1)) & 0x01))) {
225 sprintf(line
+(j
*4), "%02x! ", frame
[j
]);
228 sprintf(line
+(j
*4), "%02x ", frame
[j
]);
236 for (j
= 0; j
< (len
- 1); j
++) {
237 // gives problems... search for the reason..
238 /*if(frame[j] == 0xAA) {
241 crc = "[1] Two drops close after each other";
244 crc = "[2] Potential SOC with a drop in second half of bitperiod";
247 crc = "[3] Segment Z after segment X is not possible";
250 crc = "[4] Parity bit of a fully received byte was wrong";
253 crc = "[?] Unknown error";
260 if (strlen(crc
)==0) {
261 if(!isResponse
&& len
== 4) {
262 // Rough guess that this is a command from the reader
263 // For iClass the command byte is not part of the CRC
264 ComputeCrc14443(CRC_ICLASS
, &frame
[1], len
-3, &b1
, &b2
);
267 // For other data.. CRC might not be applicable (UPDATE commands etc.)
268 ComputeCrc14443(CRC_ICLASS
, frame
, len
-2, &b1
, &b2
);
270 //printf("%1x %1x",(unsigned)b1,(unsigned)b2);
271 if (b1
!= frame
[len
-2] || b2
!= frame
[len
-1]) {
272 crc
= (isResponse
& (len
< 8)) ? "" : " !crc";
281 char metricString
[100];
283 sprintf(metricString
, "%3d", metric
);
285 strcpy(metricString
, " ");
288 PrintAndLog(" +%7d: %s: %s %s %s",
289 (prev
< 0 ? 0 : (timestamp
- prev
)),
291 (isResponse
? "TAG" : " "), line
, crc
);
299 int CmdHFiClassSnoop(const char *Cmd
)
301 UsbCommand c
= {CMD_SNOOP_ICLASS
};
306 int CmdHFiClassSim(const char *Cmd
)
309 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
312 PrintAndLog("Usage: hf iclass sim [0 <CSN>] | x");
313 PrintAndLog(" options");
314 PrintAndLog(" 0 <CSN> simulate the given CSN");
315 PrintAndLog(" 1 simulate default CSN");
316 PrintAndLog(" 2 iterate CSNs, gather MACs");
317 PrintAndLog(" sample: hf iclass sim 0 031FEC8AF7FF12E0");
318 PrintAndLog(" sample: hf iclass sim 2");
322 simType
= param_get8(Cmd
, 0);
326 if (param_gethex(Cmd
, 1, CSN
, 16)) {
327 PrintAndLog("A CSN should consist of 16 HEX symbols");
330 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
335 PrintAndLog("Undefined simptype %d", simType
);
338 uint8_t numberOfCSNs
=0;
342 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,NUM_CSNS
}};
343 UsbCommand resp
= {0};
345 /*uint8_t csns[8 * NUM_CSNS] = {
346 0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 ,
347 0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 ,
348 0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 ,
349 0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 ,
350 0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 ,
351 0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 ,
352 0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 ,
353 0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 };
356 uint8_t csns
[8*NUM_CSNS
] = {
357 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
358 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
359 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
360 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
361 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
362 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
363 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
364 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
365 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
366 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
367 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
368 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
369 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
370 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
371 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
373 memcpy(c
.d
.asBytes
, csns
, 8*NUM_CSNS
);
376 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
377 PrintAndLog("Command timed out");
381 uint8_t num_mac_responses
= resp
.arg
[1];
382 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
, NUM_CSNS
);
384 size_t datalen
= NUM_CSNS
*24;
386 * Now, time to dump to file. We'll use this format:
387 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
388 * So, it should wind up as
391 * The returndata from the pm3 is on the following format
392 * <4 byte NR><4 byte MAC>
393 * CC are all zeroes, CSN is the same as was sent in
395 void* dump
= malloc(datalen
);
396 memset(dump
,0,datalen
);//<-- Need zeroes for the CC-field
398 for(i
= 0 ; i
< NUM_CSNS
; i
++)
400 memcpy(dump
+i
*24, csns
+i
*8,8); //CSN
401 //8 zero bytes here...
402 //Then comes NR_MAC (eight bytes from the response)
403 memcpy(dump
+i
*24+16,resp
.d
.asBytes
+i
*8,8);
406 /** Now, save to dumpfile **/
407 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
411 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,numberOfCSNs
}};
412 memcpy(c
.d
.asBytes
, CSN
, 8);
419 int CmdHFiClassReader(const char *Cmd
)
421 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
425 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
426 uint8_t isOK
= resp
.arg
[0] & 0xff;
427 uint8_t * data
= resp
.d
.asBytes
;
429 PrintAndLog("isOk:%02x", isOK
);
433 PrintAndLog("CSN: %s",sprint_hex(data
,8));
437 PrintAndLog("CC: %s",sprint_hex(data
+8,8));
439 PrintAndLog("No CC obtained");
442 PrintAndLog("Command execute timeout");
449 int CmdHFiClassReader_Replay(const char *Cmd
)
451 uint8_t readerType
= 0;
452 uint8_t MAC
[4]={0x00, 0x00, 0x00, 0x00};
455 PrintAndLog("Usage: hf iclass replay <MAC>");
456 PrintAndLog(" sample: hf iclass replay 00112233");
460 if (param_gethex(Cmd
, 0, MAC
, 8)) {
461 PrintAndLog("MAC must include 8 HEX symbols");
465 UsbCommand c
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
466 memcpy(c
.d
.asBytes
, MAC
, 4);
472 int CmdHFiClassReader_Dump(const char *Cmd
)
474 uint8_t readerType
= 0;
475 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
476 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
477 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
478 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
479 //uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
480 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
481 uint8_t keytable
[128] = {0};
487 PrintAndLog("Usage: hf iclass dump <Key> [e]");
488 PrintAndLog(" Key - A 16 byte master key");
489 PrintAndLog(" e - If 'e' is specified, the key is interpreted as the 16 byte");
490 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
491 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
492 PrintAndLog(" sample: hf iclass dump 0011223344556677");
498 if (param_gethex(Cmd
, 0, KEY
, 16))
500 PrintAndLog("KEY must include 16 HEX symbols");
504 if (param_getchar(Cmd
, 1) == 'e')
506 PrintAndLog("Elite switch on");
510 hash2(KEY
, keytable
);
511 printarr_human_readable("keytable", keytable
, 128);
516 uint8_t key_sel
[8] = {0};
517 uint8_t key_sel_p
[8] = { 0 };
519 //HACK -- Below is for testing without access to a tag
520 uint8_t fake_dummy_test
= false;
523 uint8_t xdata
[16] = {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0, //CSN from http://www.proxmark.org/forum/viewtopic.php?pid=11230#p11230
524 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; // Just a random CC. Would be good to add a real testcase here
525 memcpy(resp
.d
.asBytes
,xdata
, 16);
532 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
533 c
.arg
[0] = FLAG_ICLASS_READER_ONLY_ONCE
;
539 if (fake_dummy_test
|| WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
540 uint8_t isOK
= resp
.arg
[0] & 0xff;
541 uint8_t * data
= resp
.d
.asBytes
;
544 memcpy(CCNR
,data
+8,8);
546 PrintAndLog("isOk:%02x", isOK
);
550 PrintAndLog("CSN: %s",sprint_hex(CSN
,8));
556 //Get the key index (hash1)
557 uint8_t key_index
[8] = {0};
559 hash1(CSN
, key_index
);
560 printvar("hash1", key_index
,8);
561 for(i
= 0; i
< 8 ; i
++)
562 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
563 PrintAndLog("Pre-fortified 'permuted' HS key that would be needed by an iclass reader to talk to above CSN:");
564 printvar("k_sel", key_sel
,8);
565 //Permute from iclass format to standard format
566 permutekey_rev(key_sel
,key_sel_p
);
567 used_key
= key_sel_p
;
569 //Perhaps this should also be permuted to std format?
570 // Something like the code below? I have no std system
571 // to test this with /Martin
573 //uint8_t key_sel_p[8] = { 0 };
574 //permutekey_rev(KEY,key_sel_p);
575 //used_key = key_sel_p;
581 PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
582 printvar("Used key",used_key
,8);
583 diversifyKey(CSN
,used_key
, div_key
);
584 PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
585 printvar("Div key", div_key
, 8);
586 printvar("CC_NR:",CCNR
,12);
587 doMAC(CCNR
,12,div_key
, MAC
);
588 printvar("MAC", MAC
, 4);
590 UsbCommand d
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
591 memcpy(d
.d
.asBytes
, MAC
, 4);
592 if(!fake_dummy_test
) SendCommand(&d
);
595 PrintAndLog("Failed to obtain CC! Aborting");
598 PrintAndLog("Command execute timeout");
604 int CmdHFiClass_iso14443A_write(const char *Cmd
)
606 uint8_t readerType
= 0;
607 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
608 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
609 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
610 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
611 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
614 uint8_t bldata
[8]={0};
618 PrintAndLog("Usage: hf iclass write <Key> <Block> <Data>");
619 PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA");
623 if (param_gethex(Cmd
, 0, KEY
, 16))
625 PrintAndLog("KEY must include 16 HEX symbols");
629 blockNo
= param_get8(Cmd
, 1);
632 PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!");
635 if (param_gethex(Cmd
, 2, bldata
, 8))
637 PrintAndLog("Block data must include 8 HEX symbols");
641 UsbCommand c
= {CMD_ICLASS_ISO14443A_WRITE
, {0}};
645 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
646 uint8_t isOK
= resp
.arg
[0] & 0xff;
647 uint8_t * data
= resp
.d
.asBytes
;
650 memcpy(CCNR
,data
+8,8);
651 PrintAndLog("DEBUG: %s",sprint_hex(CSN
,8));
652 PrintAndLog("DEBUG: %s",sprint_hex(CCNR
,8));
653 PrintAndLog("isOk:%02x", isOK
);
655 PrintAndLog("Command execute timeout");
658 diversifyKey(CSN
,KEY
, div_key
);
660 PrintAndLog("Div Key: %s",sprint_hex(div_key
,8));
661 doMAC(CCNR
, 12,div_key
, MAC
);
663 UsbCommand c2
= {CMD_ICLASS_ISO14443A_WRITE
, {readerType
,blockNo
}};
664 memcpy(c2
.d
.asBytes
, bldata
, 8);
665 memcpy(c2
.d
.asBytes
+8, MAC
, 4);
668 if (WaitForResponseTimeout(CMD_ACK
,&resp
,1500)) {
669 uint8_t isOK
= resp
.arg
[0] & 0xff;
670 uint8_t * data
= resp
.d
.asBytes
;
673 PrintAndLog("isOk:%02x data:%s", isOK
, sprint_hex(data
, 4));
675 PrintAndLog("isOk:%02x", isOK
);
677 PrintAndLog("Command execute timeout");
683 static command_t CommandTable
[] =
685 {"help", CmdHelp
, 1, "This help"},
686 {"list", CmdHFiClassList
, 0, "List iClass history"},
687 {"snoop", CmdHFiClassSnoop
, 0, "Eavesdrop iClass communication"},
688 {"sim", CmdHFiClassSim
, 0, "Simulate iClass tag"},
689 {"reader",CmdHFiClassReader
, 0, "Read an iClass tag"},
690 {"replay",CmdHFiClassReader_Replay
, 0, "Read an iClass tag via Reply Attack"},
691 {"dump", CmdHFiClassReader_Dump
, 0, "Authenticate and Dump iClass tag"},
692 {"write", CmdHFiClass_iso14443A_write
, 0, "Authenticate and Write iClass block"},
693 {"replay", CmdHFiClassReader_Replay
, 0, "Read an iClass tag via Reply Attack"},
694 {"dump", CmdHFiClassReader_Dump
, 0, "Authenticate and Dump iClass tag"},
695 {"write", CmdHFiClass_iso14443A_write
, 0, "Authenticate and Write iClass block"},
696 {NULL
, NULL
, 0, NULL
}
699 int CmdHFiClass(const char *Cmd
)
701 CmdsParse(CommandTable
, Cmd
);
705 int CmdHelp(const char *Cmd
)
707 CmdsHelp(CommandTable
);