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
)
46 bool ShowWaitCycles
= false;
47 char param
= param_getchar(Cmd
, 0);
50 PrintAndLog("List data in trace buffer.");
51 PrintAndLog("Usage: hf iclass list");
52 PrintAndLog("h - help");
53 PrintAndLog("sample: hf iclass list");
57 // for the time being. Need better Bigbuf handling.
58 #define TRACE_SIZE 3000
60 uint8_t trace
[TRACE_SIZE
];
61 GetFromBigBuf(trace
, TRACE_SIZE
, 0);
62 WaitForResponse(CMD_ACK
,NULL
);
64 PrintAndLog("Recorded Activity");
66 PrintAndLog("Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
67 PrintAndLog("All times are in carrier periods (1/13.56Mhz)");
69 PrintAndLog(" Start | End | Src | Data (! denotes parity error) | CRC ");
70 PrintAndLog("-----------|-----------|-----|-----------------------------------------------------------------------");
72 uint16_t tracepos
= 0;
78 uint32_t first_timestamp
;
79 uint32_t EndOfTransmissionTimestamp
;
83 if(tracepos
>= TRACE_SIZE
) {
87 timestamp
= *((uint32_t *)(trace
+ tracepos
));
89 first_timestamp
= timestamp
;
92 // Break and stick with current result if buffer was not completely full
93 if (timestamp
== 0x44444444) break;
96 duration
= *((uint16_t *)(trace
+ tracepos
));
98 data_len
= *((uint16_t *)(trace
+ tracepos
));
101 if (data_len
& 0x8000) {
108 parity_len
= (data_len
-1)/8 + 1;
110 if (tracepos
+ data_len
+ parity_len
>= TRACE_SIZE
) {
114 uint8_t *frame
= trace
+ tracepos
;
115 tracepos
+= data_len
;
116 uint8_t *parityBytes
= trace
+ tracepos
;
117 tracepos
+= parity_len
;
120 for (int j
= 0; j
< data_len
; j
++) {
121 int oddparity
= 0x01;
125 oddparity
^= (((frame
[j
] & 0xFF) >> k
) & 0x01);
128 uint8_t parityBits
= parityBytes
[j
>>3];
129 if (isResponse
&& (oddparity
!= ((parityBits
>> (7-(j
&0x0007))) & 0x01))) {
130 sprintf(line
[j
/16]+((j
%16)*4), "%02x! ", frame
[j
]);
132 sprintf(line
[j
/16]+((j
%16)*4), "%02x ", frame
[j
]);
140 if(!isResponse
&& data_len
== 4 ) {
141 // Rough guess that this is a command from the reader
142 // For iClass the command byte is not part of the CRC
143 ComputeCrc14443(CRC_ICLASS
, &frame
[1], data_len
-3, &b1
, &b2
);
144 if (b1
!= frame
[data_len
-2] || b2
!= frame
[data_len
-1]) {
149 // For other data.. CRC might not be applicable (UPDATE commands etc.)
150 ComputeCrc14443(CRC_ICLASS
, frame
, data_len
-2, &b1
, &b2
);
151 if (b1
!= frame
[data_len
-2] || b2
!= frame
[data_len
-1]) {
157 EndOfTransmissionTimestamp
= timestamp
+ duration
;
159 int num_lines
= (data_len
- 1)/16 + 1;
160 for (int j
= 0; j
< num_lines
; j
++) {
162 PrintAndLog(" %9d | %9d | %s | %-64s| %s",
163 (timestamp
- first_timestamp
),
164 (EndOfTransmissionTimestamp
- first_timestamp
),
165 (isResponse
? "Tag" : "Rdr"),
167 (j
== num_lines
-1)?crc
:"");
169 PrintAndLog(" | | | %-64s| %s",
171 (j
== num_lines
-1)?crc
:"");
175 bool next_isResponse
= *((uint16_t *)(trace
+ tracepos
+ 6)) & 0x8000;
177 if (ShowWaitCycles
&& !isResponse
&& next_isResponse
) {
178 uint32_t next_timestamp
= *((uint32_t *)(trace
+ tracepos
));
179 if (next_timestamp
!= 0x44444444) {
180 PrintAndLog(" %9d | %9d | %s | fdt (Frame Delay Time): %d",
181 (EndOfTransmissionTimestamp
- first_timestamp
),
182 (next_timestamp
- first_timestamp
),
184 (next_timestamp
- EndOfTransmissionTimestamp
));
193 int CmdHFiClassSnoop(const char *Cmd
)
195 UsbCommand c
= {CMD_SNOOP_ICLASS
};
200 int CmdHFiClassSim(const char *Cmd
)
203 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
206 PrintAndLog("Usage: hf iclass sim [0 <CSN>] | x");
207 PrintAndLog(" options");
208 PrintAndLog(" 0 <CSN> simulate the given CSN");
209 PrintAndLog(" 1 simulate default CSN");
210 PrintAndLog(" 2 iterate CSNs, gather MACs");
211 PrintAndLog(" sample: hf iclass sim 0 031FEC8AF7FF12E0");
212 PrintAndLog(" sample: hf iclass sim 2");
216 simType
= param_get8(Cmd
, 0);
220 if (param_gethex(Cmd
, 1, CSN
, 16)) {
221 PrintAndLog("A CSN should consist of 16 HEX symbols");
224 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
229 PrintAndLog("Undefined simptype %d", simType
);
232 uint8_t numberOfCSNs
=0;
236 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,NUM_CSNS
}};
237 UsbCommand resp
= {0};
239 /*uint8_t csns[8 * NUM_CSNS] = {
240 0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 ,
241 0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 ,
242 0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 ,
243 0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 ,
244 0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 ,
245 0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 ,
246 0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 ,
247 0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 };
250 uint8_t csns
[8*NUM_CSNS
] = {
251 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
252 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
253 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
254 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
255 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
256 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
257 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
258 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
259 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
260 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
261 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
262 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
263 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
264 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
265 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
267 memcpy(c
.d
.asBytes
, csns
, 8*NUM_CSNS
);
270 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
271 PrintAndLog("Command timed out");
275 uint8_t num_mac_responses
= resp
.arg
[1];
276 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
, NUM_CSNS
);
278 size_t datalen
= NUM_CSNS
*24;
280 * Now, time to dump to file. We'll use this format:
281 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
282 * So, it should wind up as
285 * The returndata from the pm3 is on the following format
286 * <4 byte NR><4 byte MAC>
287 * CC are all zeroes, CSN is the same as was sent in
289 void* dump
= malloc(datalen
);
290 memset(dump
,0,datalen
);//<-- Need zeroes for the CC-field
292 for(i
= 0 ; i
< NUM_CSNS
; i
++)
294 memcpy(dump
+i
*24, csns
+i
*8,8); //CSN
295 //8 zero bytes here...
296 //Then comes NR_MAC (eight bytes from the response)
297 memcpy(dump
+i
*24+16,resp
.d
.asBytes
+i
*8,8);
300 /** Now, save to dumpfile **/
301 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
305 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,numberOfCSNs
}};
306 memcpy(c
.d
.asBytes
, CSN
, 8);
313 int CmdHFiClassReader(const char *Cmd
)
315 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
319 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
320 uint8_t isOK
= resp
.arg
[0] & 0xff;
321 uint8_t * data
= resp
.d
.asBytes
;
323 PrintAndLog("isOk:%02x", isOK
);
327 PrintAndLog("CSN: %s",sprint_hex(data
,8));
331 PrintAndLog("CC: %s",sprint_hex(data
+8,8));
333 PrintAndLog("No CC obtained");
336 PrintAndLog("Command execute timeout");
343 int CmdHFiClassReader_Replay(const char *Cmd
)
345 uint8_t readerType
= 0;
346 uint8_t MAC
[4]={0x00, 0x00, 0x00, 0x00};
349 PrintAndLog("Usage: hf iclass replay <MAC>");
350 PrintAndLog(" sample: hf iclass replay 00112233");
354 if (param_gethex(Cmd
, 0, MAC
, 8)) {
355 PrintAndLog("MAC must include 8 HEX symbols");
359 UsbCommand c
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
360 memcpy(c
.d
.asBytes
, MAC
, 4);
366 int CmdHFiClassReader_Dump(const char *Cmd
)
368 uint8_t readerType
= 0;
369 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
370 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
371 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
372 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
373 //uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
374 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
375 uint8_t keytable
[128] = {0};
381 PrintAndLog("Usage: hf iclass dump <Key> [e]");
382 PrintAndLog(" Key - A 16 byte master key");
383 PrintAndLog(" e - If 'e' is specified, the key is interpreted as the 16 byte");
384 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
385 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
386 PrintAndLog(" sample: hf iclass dump 0011223344556677");
392 if (param_gethex(Cmd
, 0, KEY
, 16))
394 PrintAndLog("KEY must include 16 HEX symbols");
398 if (param_getchar(Cmd
, 1) == 'e')
400 PrintAndLog("Elite switch on");
404 hash2(KEY
, keytable
);
405 printarr_human_readable("keytable", keytable
, 128);
410 uint8_t key_sel
[8] = {0};
411 uint8_t key_sel_p
[8] = { 0 };
413 //HACK -- Below is for testing without access to a tag
414 uint8_t fake_dummy_test
= false;
417 uint8_t xdata
[16] = {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0, //CSN from http://www.proxmark.org/forum/viewtopic.php?pid=11230#p11230
418 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; // Just a random CC. Would be good to add a real testcase here
419 memcpy(resp
.d
.asBytes
,xdata
, 16);
426 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
427 c
.arg
[0] = FLAG_ICLASS_READER_ONLY_ONCE
;
433 if (fake_dummy_test
|| WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
434 uint8_t isOK
= resp
.arg
[0] & 0xff;
435 uint8_t * data
= resp
.d
.asBytes
;
438 memcpy(CCNR
,data
+8,8);
440 PrintAndLog("isOk:%02x", isOK
);
444 PrintAndLog("CSN: %s",sprint_hex(CSN
,8));
450 //Get the key index (hash1)
451 uint8_t key_index
[8] = {0};
453 hash1(CSN
, key_index
);
454 printvar("hash1", key_index
,8);
455 for(i
= 0; i
< 8 ; i
++)
456 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
457 PrintAndLog("Pre-fortified 'permuted' HS key that would be needed by an iclass reader to talk to above CSN:");
458 printvar("k_sel", key_sel
,8);
459 //Permute from iclass format to standard format
460 permutekey_rev(key_sel
,key_sel_p
);
461 used_key
= key_sel_p
;
463 //Perhaps this should also be permuted to std format?
464 // Something like the code below? I have no std system
465 // to test this with /Martin
467 //uint8_t key_sel_p[8] = { 0 };
468 //permutekey_rev(KEY,key_sel_p);
469 //used_key = key_sel_p;
475 PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
476 printvar("Used key",used_key
,8);
477 diversifyKey(CSN
,used_key
, div_key
);
478 PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
479 printvar("Div key", div_key
, 8);
480 printvar("CC_NR:",CCNR
,12);
481 doMAC(CCNR
,12,div_key
, MAC
);
482 printvar("MAC", MAC
, 4);
484 UsbCommand d
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
485 memcpy(d
.d
.asBytes
, MAC
, 4);
486 if(!fake_dummy_test
) SendCommand(&d
);
489 PrintAndLog("Failed to obtain CC! Aborting");
492 PrintAndLog("Command execute timeout");
498 int CmdHFiClass_iso14443A_write(const char *Cmd
)
500 uint8_t readerType
= 0;
501 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
502 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
503 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
504 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
505 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
508 uint8_t bldata
[8]={0};
512 PrintAndLog("Usage: hf iclass write <Key> <Block> <Data>");
513 PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA");
517 if (param_gethex(Cmd
, 0, KEY
, 16))
519 PrintAndLog("KEY must include 16 HEX symbols");
523 blockNo
= param_get8(Cmd
, 1);
526 PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!");
529 if (param_gethex(Cmd
, 2, bldata
, 8))
531 PrintAndLog("Block data must include 8 HEX symbols");
535 UsbCommand c
= {CMD_ICLASS_ISO14443A_WRITE
, {0}};
539 if (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);
545 PrintAndLog("DEBUG: %s",sprint_hex(CSN
,8));
546 PrintAndLog("DEBUG: %s",sprint_hex(CCNR
,8));
547 PrintAndLog("isOk:%02x", isOK
);
549 PrintAndLog("Command execute timeout");
552 diversifyKey(CSN
,KEY
, div_key
);
554 PrintAndLog("Div Key: %s",sprint_hex(div_key
,8));
555 doMAC(CCNR
, 12,div_key
, MAC
);
557 UsbCommand c2
= {CMD_ICLASS_ISO14443A_WRITE
, {readerType
,blockNo
}};
558 memcpy(c2
.d
.asBytes
, bldata
, 8);
559 memcpy(c2
.d
.asBytes
+8, MAC
, 4);
562 if (WaitForResponseTimeout(CMD_ACK
,&resp
,1500)) {
563 uint8_t isOK
= resp
.arg
[0] & 0xff;
564 uint8_t * data
= resp
.d
.asBytes
;
567 PrintAndLog("isOk:%02x data:%s", isOK
, sprint_hex(data
, 4));
569 PrintAndLog("isOk:%02x", isOK
);
571 PrintAndLog("Command execute timeout");
577 static command_t CommandTable
[] =
579 {"help", CmdHelp
, 1, "This help"},
580 {"list", CmdHFiClassList
, 0, "List iClass history"},
581 {"snoop", CmdHFiClassSnoop
, 0, "Eavesdrop iClass communication"},
582 {"sim", CmdHFiClassSim
, 0, "Simulate iClass tag"},
583 {"reader",CmdHFiClassReader
, 0, "Read an iClass tag"},
584 {"replay",CmdHFiClassReader_Replay
, 0, "Read an iClass tag via Reply Attack"},
585 {"dump", CmdHFiClassReader_Dump
, 0, "Authenticate and Dump iClass tag"},
586 {"write", CmdHFiClass_iso14443A_write
, 0, "Authenticate and Write iClass block"},
587 {"replay", CmdHFiClassReader_Replay
, 0, "Read an iClass tag via Reply Attack"},
588 {"dump", CmdHFiClassReader_Dump
, 0, "Authenticate and Dump iClass tag"},
589 {"write", CmdHFiClass_iso14443A_write
, 0, "Authenticate and Write iClass block"},
590 {NULL
, NULL
, 0, NULL
}
593 int CmdHFiClass(const char *Cmd
)
595 CmdsParse(CommandTable
, Cmd
);
599 int CmdHelp(const char *Cmd
)
601 CmdsHelp(CommandTable
);