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 "proxusb.h"
20 #include "proxmark3.h"
22 #include "cmdparser.h"
23 #include "cmdhficlass.h"
27 #include "loclass/des.h"
28 #include "loclass/cipherutils.h"
29 #include "loclass/cipher.h"
30 #include "loclass/ikeys.h"
31 #include "loclass/elite_crack.h"
32 #include "loclass/fileutils.h"
34 static int CmdHelp(const char *Cmd
);
36 int xorbits_8(uint8_t val
)
38 uint8_t res
= val
^ (val
>> 1); //1st pass
39 res
= res
^ (res
>> 1); // 2nd pass
40 res
= res
^ (res
>> 2); // 3rd pass
41 res
= res
^ (res
>> 4); // 4th pass
45 void explain(char *exp
, size_t size
, uint8_t* cmd
, uint8_t cmdsize
)
50 case 0x0a: snprintf(exp
,size
,"WUP"); break;
51 case 0x0f: snprintf(exp
,size
,"SOF"); break;
52 case 0x0c: snprintf(exp
,size
,"Read config"); break;
53 case 0x81: snprintf(exp
,size
,"SELECT"); break;
54 case 0x88: snprintf(exp
,size
,"Read E-purse (CC)"); break;
55 case 0x05: snprintf(exp
,size
,"Reader challenge"); break;
56 case 0x00: snprintf(exp
,size
,"End"); break;
57 default: snprintf(exp
,size
,"?"); break;
62 int CmdHFiClassList(const char *Cmd
)
64 bool ShowWaitCycles
= false;
65 char param
= param_getchar(Cmd
, 0);
68 PrintAndLog("List data in trace buffer.");
69 PrintAndLog("Usage: hf iclass list");
70 PrintAndLog("h - help");
71 PrintAndLog("sample: hf iclass list");
75 // for the time being. Need better Bigbuf handling.
76 #define TRACE_SIZE 3000
78 uint8_t trace
[TRACE_SIZE
];
79 GetFromBigBuf(trace
, TRACE_SIZE
, 0);
80 WaitForResponse(CMD_ACK
, NULL
);
82 PrintAndLog("Recorded Activity");
84 PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
85 PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
87 PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC | Explanation|");
88 PrintAndLog("-----------|-----------|-----|-------------------------------------------------------------------------------------");
90 uint16_t tracepos
= 0;
96 uint32_t first_timestamp
;
97 uint32_t EndOfTransmissionTimestamp
;
98 char explanation
[20] = {0};
101 if(tracepos
>= TRACE_SIZE
) {
105 timestamp
= *((uint32_t *)(trace
+ tracepos
));
107 first_timestamp
= timestamp
;
110 // Break and stick with current result if buffer was not completely full
111 if (timestamp
== 0x44444444) break;
114 duration
= *((uint16_t *)(trace
+ tracepos
));
116 data_len
= *((uint16_t *)(trace
+ tracepos
));
119 if (data_len
& 0x8000) {
126 parity_len
= (data_len
-1)/8 + 1;
128 if (tracepos
+ data_len
+ parity_len
>= TRACE_SIZE
) {
132 uint8_t *frame
= trace
+ tracepos
;
133 tracepos
+= data_len
;
134 uint8_t *parityBytes
= trace
+ tracepos
;
135 tracepos
+= parity_len
;
138 for (int j
= 0; j
< data_len
; j
++) {
139 int oddparity
= 0x01;
143 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
146 uint8_t parityBits
= parityBytes
[j
>>3];
147 if (isResponse
&& (oddparity
!= ((parityBits
>> (7-(j
&0x0007))) & 0x01))) {
148 sprintf(line
[j
/16]+((j
%16)*4), "%02x! ", frame
[j
]);
150 sprintf(line
[j
/16]+((j
%16)*4), "%02x ", frame
[j
]);
158 if(!isResponse
&& data_len
== 4 ) {
159 // Rough guess that this is a command from the reader
160 // For iClass the command byte is not part of the CRC
161 ComputeCrc14443(CRC_ICLASS
, &frame
[1], data_len
-3, &b1
, &b2
);
162 if (b1
!= frame
[data_len
-2] || b2
!= frame
[data_len
-1]) {
167 // For other data.. CRC might not be applicable (UPDATE commands etc.)
168 ComputeCrc14443(CRC_ICLASS
, frame
, data_len
-2, &b1
, &b2
);
169 if (b1
!= frame
[data_len
-2] || b2
!= frame
[data_len
-1]) {
175 EndOfTransmissionTimestamp
= timestamp
+ duration
;
176 explain(explanation
,sizeof(explanation
),frame
,data_len
);
177 int num_lines
= (data_len
- 1)/16 + 1;
178 for (int j
= 0; j
< num_lines
; j
++) {
180 PrintAndLog(" %9d | %9d | %s | %-64s| %s| %s",
181 (timestamp
- first_timestamp
),
182 (EndOfTransmissionTimestamp
- first_timestamp
),
183 (isResponse
? "Tag" : "Rdr"),
185 (j
== num_lines
-1)?crc
:" ",
188 PrintAndLog(" | | | %-64s| %s",
190 (j
== num_lines
-1)?crc
:" ");
194 bool next_isResponse
= *((uint16_t *)(trace
+ tracepos
+ 6)) & 0x8000;
196 if (ShowWaitCycles
&& !isResponse
&& next_isResponse
) {
197 uint32_t next_timestamp
= *((uint32_t *)(trace
+ tracepos
));
198 if (next_timestamp
!= 0x44444444) {
199 PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d",
200 (EndOfTransmissionTimestamp
- first_timestamp
),
201 (next_timestamp
- first_timestamp
),
203 (next_timestamp
- EndOfTransmissionTimestamp
));
212 int CmdHFiClassSnoop(const char *Cmd
)
214 UsbCommand c
= {CMD_SNOOP_ICLASS
};
219 int CmdHFiClassSim(const char *Cmd
)
222 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
225 PrintAndLog("Usage: hf iclass sim [0 <CSN>] | x");
226 PrintAndLog(" options");
227 PrintAndLog(" 0 <CSN> simulate the given CSN");
228 PrintAndLog(" 1 simulate default CSN");
229 PrintAndLog(" 2 iterate CSNs, gather MACs");
230 PrintAndLog(" sample: hf iclass sim 0 031FEC8AF7FF12E0");
231 PrintAndLog(" sample: hf iclass sim 2");
235 simType
= param_get8(Cmd
, 0);
239 if (param_gethex(Cmd
, 1, CSN
, 16)) {
240 PrintAndLog("A CSN should consist of 16 HEX symbols");
243 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
248 PrintAndLog("Undefined simptype %d", simType
);
251 uint8_t numberOfCSNs
=0;
255 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,NUM_CSNS
}};
256 UsbCommand resp
= {0};
258 /*uint8_t csns[8 * NUM_CSNS] = {
259 0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 ,
260 0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 ,
261 0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 ,
262 0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 ,
263 0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 ,
264 0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 ,
265 0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 ,
266 0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 };
269 uint8_t csns
[8*NUM_CSNS
] = {
270 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
271 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
272 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
273 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
274 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
275 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
276 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
277 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
278 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
279 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
280 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
281 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
282 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
283 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
284 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
286 memcpy(c
.d
.asBytes
, csns
, 8*NUM_CSNS
);
289 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
290 PrintAndLog("Command timed out");
294 uint8_t num_mac_responses
= resp
.arg
[1];
295 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
,NUM_CSNS
);
297 size_t datalen
= NUM_CSNS
*24;
299 * Now, time to dump to file. We'll use this format:
300 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
301 * So, it should wind up as
304 * The returndata from the pm3 is on the following format
305 * <4 byte NR><4 byte MAC>
306 * CC are all zeroes, CSN is the same as was sent in
308 void* dump
= malloc(datalen
);
309 memset(dump
,0,datalen
);//<-- Need zeroes for the CC-field
311 for(i
= 0 ; i
< NUM_CSNS
; i
++)
313 memcpy(dump
+i
*24, csns
+i
*8,8); //CSN
314 //8 zero bytes here...
315 //Then comes NR_MAC (eight bytes from the response)
316 memcpy(dump
+i
*24+16,resp
.d
.asBytes
+i
*8,8);
319 /** Now, save to dumpfile **/
320 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
324 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,numberOfCSNs
}};
325 memcpy(c
.d
.asBytes
, CSN
, 8);
332 int CmdHFiClassReader(const char *Cmd
)
334 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
338 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
339 uint8_t isOK
= resp
.arg
[0] & 0xff;
340 uint8_t * data
= resp
.d
.asBytes
;
342 PrintAndLog("isOk:%02x", isOK
);
345 PrintAndLog("Quitting...");
350 PrintAndLog("CSN: %s",sprint_hex(data
,8));
354 PrintAndLog("CC: %s",sprint_hex(data
+8,8));
356 PrintAndLog("No CC obtained");
359 PrintAndLog("Command execute timeout");
366 int CmdHFiClassReader_Replay(const char *Cmd
)
368 uint8_t readerType
= 0;
369 uint8_t MAC
[4]={0x00, 0x00, 0x00, 0x00};
372 PrintAndLog("Usage: hf iclass replay <MAC>");
373 PrintAndLog(" sample: hf iclass replay 00112233");
377 if (param_gethex(Cmd
, 0, MAC
, 8)) {
378 PrintAndLog("MAC must include 8 HEX symbols");
382 UsbCommand c
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
383 memcpy(c
.d
.asBytes
, MAC
, 4);
389 int CmdHFiClassReader_Dump(const char *Cmd
)
391 uint8_t readerType
= 0;
392 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
393 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
394 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
395 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
396 //uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
397 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
398 uint8_t keytable
[128] = {0};
404 PrintAndLog("Usage: hf iclass dump <Key> [e]");
405 PrintAndLog(" Key - A 16 byte master key");
406 PrintAndLog(" e - If 'e' is specified, the key is interpreted as the 16 byte");
407 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
408 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
409 PrintAndLog(" sample: hf iclass dump 0011223344556677");
415 if (param_gethex(Cmd
, 0, KEY
, 16))
417 PrintAndLog("KEY must include 16 HEX symbols");
421 if (param_getchar(Cmd
, 1) == 'e')
423 PrintAndLog("Elite switch on");
427 hash2(KEY
, keytable
);
428 printarr_human_readable("keytable", keytable
, 128);
433 uint8_t key_sel
[8] = {0};
434 uint8_t key_sel_p
[8] = { 0 };
436 //HACK -- Below is for testing without access to a tag
437 uint8_t fake_dummy_test
= false;
440 uint8_t xdata
[16] = {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0, //CSN from http://www.proxmark.org/forum/viewtopic.php?pid=11230#p11230
441 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; // Just a random CC. Would be good to add a real testcase here
442 memcpy(resp
.d
.asBytes
,xdata
, 16);
449 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
450 c
.arg
[0] = FLAG_ICLASS_READER_ONLY_ONCE
;
456 if (fake_dummy_test
|| WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
457 uint8_t isOK
= resp
.arg
[0] & 0xff;
458 uint8_t * data
= resp
.d
.asBytes
;
461 memcpy(CCNR
,data
+8,8);
463 PrintAndLog("isOk:%02x", isOK
);
467 PrintAndLog("CSN: %s",sprint_hex(CSN
,8));
473 //Get the key index (hash1)
474 uint8_t key_index
[8] = {0};
476 hash1(CSN
, key_index
);
477 printvar("hash1", key_index
,8);
478 for(i
= 0; i
< 8 ; i
++)
479 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
480 PrintAndLog("Pre-fortified 'permuted' HS key that would be needed by an iclass reader to talk to above CSN:");
481 printvar("k_sel", key_sel
,8);
482 //Permute from iclass format to standard format
483 permutekey_rev(key_sel
,key_sel_p
);
484 used_key
= key_sel_p
;
486 //Perhaps this should also be permuted to std format?
487 // Something like the code below? I have no std system
488 // to test this with /Martin
490 //uint8_t key_sel_p[8] = { 0 };
491 //permutekey_rev(KEY,key_sel_p);
492 //used_key = key_sel_p;
498 PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
499 printvar("Used key",used_key
,8);
500 diversifyKey(CSN
,used_key
, div_key
);
501 PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
502 printvar("Div key", div_key
, 8);
503 printvar("CC_NR:",CCNR
,12);
504 doMAC(CCNR
,12,div_key
, MAC
);
505 printvar("MAC", MAC
, 4);
507 UsbCommand d
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
508 memcpy(d
.d
.asBytes
, MAC
, 4);
509 if(!fake_dummy_test
) SendCommand(&d
);
512 PrintAndLog("Failed to obtain CC! Aborting");
515 PrintAndLog("Command execute timeout");
521 int CmdHFiClass_iso14443A_write(const char *Cmd
)
523 uint8_t readerType
= 0;
524 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
525 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
526 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
527 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
528 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
531 uint8_t bldata
[8]={0};
535 PrintAndLog("Usage: hf iclass write <Key> <Block> <Data>");
536 PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA");
540 if (param_gethex(Cmd
, 0, KEY
, 16))
542 PrintAndLog("KEY must include 16 HEX symbols");
546 blockNo
= param_get8(Cmd
, 1);
549 PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!");
552 if (param_gethex(Cmd
, 2, bldata
, 8))
554 PrintAndLog("Block data must include 8 HEX symbols");
558 UsbCommand c
= {CMD_ICLASS_ISO14443A_WRITE
, {0}};
562 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
563 uint8_t isOK
= resp
.arg
[0] & 0xff;
564 uint8_t * data
= resp
.d
.asBytes
;
567 memcpy(CCNR
,data
+8,8);
568 PrintAndLog("DEBUG: %s",sprint_hex(CSN
,8));
569 PrintAndLog("DEBUG: %s",sprint_hex(CCNR
,8));
570 PrintAndLog("isOk:%02x", isOK
);
572 PrintAndLog("Command execute timeout");
575 diversifyKey(CSN
,KEY
, div_key
);
577 PrintAndLog("Div Key: %s",sprint_hex(div_key
,8));
578 doMAC(CCNR
, 12,div_key
, MAC
);
580 UsbCommand c2
= {CMD_ICLASS_ISO14443A_WRITE
, {readerType
,blockNo
}};
581 memcpy(c2
.d
.asBytes
, bldata
, 8);
582 memcpy(c2
.d
.asBytes
+8, MAC
, 4);
585 if (WaitForResponseTimeout(CMD_ACK
,&resp
,1500)) {
586 uint8_t isOK
= resp
.arg
[0] & 0xff;
587 uint8_t * data
= resp
.d
.asBytes
;
590 PrintAndLog("isOk:%02x data:%s", isOK
, sprint_hex(data
, 4));
592 PrintAndLog("isOk:%02x", isOK
);
594 PrintAndLog("Command execute timeout");
600 static command_t CommandTable
[] =
602 {"help", CmdHelp
, 1, "This help"},
603 {"list", CmdHFiClassList
, 0, "List iClass history"},
604 {"snoop", CmdHFiClassSnoop
, 0, "Eavesdrop iClass communication"},
605 {"sim", CmdHFiClassSim
, 0, "Simulate iClass tag"},
606 {"reader",CmdHFiClassReader
, 0, "Read an iClass tag"},
607 {"replay",CmdHFiClassReader_Replay
, 0, "Read an iClass tag via Reply Attack"},
608 {"dump", CmdHFiClassReader_Dump
, 0, "Authenticate and Dump iClass tag"},
609 {"write", CmdHFiClass_iso14443A_write
, 0, "Authenticate and Write iClass block"},
610 {NULL
, NULL
, 0, NULL
}
613 int CmdHFiClass(const char *Cmd
)
615 CmdsParse(CommandTable
, Cmd
);
619 int CmdHelp(const char *Cmd
)
621 CmdsHelp(CommandTable
);