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 #define ICLASS_CMD_ACTALL 0x0A
45 #define ICLASS_CMD_IDENTIFY 0x0C
46 #define ICLASS_CMD_READ 0x0C
48 #define ICLASS_CMD_SELECT 0x81
49 #define ICLASS_CMD_PAGESEL 0x84
50 #define ICLASS_CMD_READCHECK 0x88
51 #define ICLASS_CMD_CHECK 0x05
52 #define ICLASS_CMD_SOF 0x0F
53 #define ICLASS_CMD_HALT 0x00
56 void explain(char *exp
, size_t size
, uint8_t* cmd
, uint8_t cmdsize
)
59 if(cmdsize
> 1 && cmd
[0] == ICLASS_CMD_READ
)
61 snprintf(exp
,size
,"READ(%d)",cmd
[1]);
67 case ICLASS_CMD_ACTALL
: snprintf(exp
,size
,"ACTALL"); break;
68 case ICLASS_CMD_IDENTIFY
: snprintf(exp
,size
,"IDENTIFY"); break;
69 case ICLASS_CMD_SELECT
: snprintf(exp
,size
,"SELECT"); break;
70 case ICLASS_CMD_PAGESEL
: snprintf(exp
,size
,"PAGESEL"); break;
71 case ICLASS_CMD_READCHECK
: snprintf(exp
,size
,"READCHECK"); break;
72 case ICLASS_CMD_CHECK
: snprintf(exp
,size
,"CHECK"); break;
73 case ICLASS_CMD_SOF
: snprintf(exp
,size
,"SOF"); break;
74 case ICLASS_CMD_HALT
: snprintf(exp
,size
,"HALT"); break;
75 default: snprintf(exp
,size
,"?"); break;
80 int CmdHFiClassList(const char *Cmd
)
82 PrintAndLog("Deprecated command, use 'hf list iclass' instead");
86 int CmdHFiClassSnoop(const char *Cmd
)
88 UsbCommand c
= {CMD_SNOOP_ICLASS
};
93 int CmdHFiClassSim(const char *Cmd
)
96 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
99 PrintAndLog("Usage: hf iclass sim [0 <CSN>] | x");
100 PrintAndLog(" options");
101 PrintAndLog(" 0 <CSN> simulate the given CSN");
102 PrintAndLog(" 1 simulate default CSN");
103 PrintAndLog(" 2 iterate CSNs, gather MACs");
104 PrintAndLog(" sample: hf iclass sim 0 031FEC8AF7FF12E0");
105 PrintAndLog(" sample: hf iclass sim 2");
109 simType
= param_get8(Cmd
, 0);
113 if (param_gethex(Cmd
, 1, CSN
, 16)) {
114 PrintAndLog("A CSN should consist of 16 HEX symbols");
117 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
122 PrintAndLog("Undefined simptype %d", simType
);
125 uint8_t numberOfCSNs
=0;
129 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,NUM_CSNS
}};
130 UsbCommand resp
= {0};
132 /*uint8_t csns[8 * NUM_CSNS] = {
133 0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 ,
134 0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 ,
135 0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 ,
136 0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 ,
137 0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 ,
138 0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 ,
139 0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 ,
140 0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 };
143 uint8_t csns
[8*NUM_CSNS
] = {
144 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
145 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
146 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
147 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
148 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
149 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
150 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
151 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
152 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
153 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
154 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
155 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
156 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
157 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
158 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
160 memcpy(c
.d
.asBytes
, csns
, 8*NUM_CSNS
);
163 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
164 PrintAndLog("Command timed out");
168 uint8_t num_mac_responses
= resp
.arg
[1];
169 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
, NUM_CSNS
);
171 size_t datalen
= NUM_CSNS
*24;
173 * Now, time to dump to file. We'll use this format:
174 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
175 * So, it should wind up as
178 * The returndata from the pm3 is on the following format
179 * <4 byte NR><4 byte MAC>
180 * CC are all zeroes, CSN is the same as was sent in
182 void* dump
= malloc(datalen
);
183 memset(dump
,0,datalen
);//<-- Need zeroes for the CC-field
185 for(i
= 0 ; i
< NUM_CSNS
; i
++)
187 memcpy(dump
+i
*24, csns
+i
*8,8); //CSN
188 //8 zero bytes here...
189 //Then comes NR_MAC (eight bytes from the response)
190 memcpy(dump
+i
*24+16,resp
.d
.asBytes
+i
*8,8);
193 /** Now, save to dumpfile **/
194 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
198 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,numberOfCSNs
}};
199 memcpy(c
.d
.asBytes
, CSN
, 8);
206 int CmdHFiClassReader(const char *Cmd
)
208 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
212 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
213 uint8_t isOK
= resp
.arg
[0] & 0xff;
214 uint8_t * data
= resp
.d
.asBytes
;
216 PrintAndLog("isOk:%02x", isOK
);
219 PrintAndLog("Quitting...");
224 PrintAndLog("CSN: %s",sprint_hex(data
,8));
228 PrintAndLog("CC: %s",sprint_hex(data
+8,8));
230 PrintAndLog("No CC obtained");
233 PrintAndLog("Command execute timeout");
240 int CmdHFiClassReader_Replay(const char *Cmd
)
242 uint8_t readerType
= 0;
243 uint8_t MAC
[4]={0x00, 0x00, 0x00, 0x00};
246 PrintAndLog("Usage: hf iclass replay <MAC>");
247 PrintAndLog(" sample: hf iclass replay 00112233");
251 if (param_gethex(Cmd
, 0, MAC
, 8)) {
252 PrintAndLog("MAC must include 8 HEX symbols");
256 UsbCommand c
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
257 memcpy(c
.d
.asBytes
, MAC
, 4);
263 int CmdHFiClassReader_Dump(const char *Cmd
)
265 uint8_t readerType
= 0;
266 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
267 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
268 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
269 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
270 //uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
271 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
272 uint8_t keytable
[128] = {0};
278 PrintAndLog("Usage: hf iclass dump <Key> [e]");
279 PrintAndLog(" Key - A 16 byte master key");
280 PrintAndLog(" e - If 'e' is specified, the key is interpreted as the 16 byte");
281 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
282 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
283 PrintAndLog(" sample: hf iclass dump 0011223344556677");
289 if (param_gethex(Cmd
, 0, KEY
, 16))
291 PrintAndLog("KEY must include 16 HEX symbols");
295 if (param_getchar(Cmd
, 1) == 'e')
297 PrintAndLog("Elite switch on");
301 hash2(KEY
, keytable
);
302 printarr_human_readable("keytable", keytable
, 128);
307 uint8_t key_sel
[8] = {0};
308 uint8_t key_sel_p
[8] = { 0 };
310 //HACK -- Below is for testing without access to a tag
311 uint8_t fake_dummy_test
= false;
314 uint8_t xdata
[16] = {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0, //CSN from http://www.proxmark.org/forum/viewtopic.php?pid=11230#p11230
315 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; // Just a random CC. Would be good to add a real testcase here
316 memcpy(resp
.d
.asBytes
,xdata
, 16);
323 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
324 c
.arg
[0] = FLAG_ICLASS_READER_ONLY_ONCE
| FLAG_ICLASS_READER_GET_CC
;
330 if (fake_dummy_test
|| WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
331 uint8_t isOK
= resp
.arg
[0] & 0xff;
332 uint8_t * data
= resp
.d
.asBytes
;
335 memcpy(CCNR
,data
+8,8);
337 PrintAndLog("isOk:%02x", isOK
);
341 PrintAndLog("CSN: %s",sprint_hex(CSN
,8));
347 //Get the key index (hash1)
348 uint8_t key_index
[8] = {0};
350 hash1(CSN
, key_index
);
351 printvar("hash1", key_index
,8);
352 for(i
= 0; i
< 8 ; i
++)
353 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
354 PrintAndLog("Pre-fortified 'permuted' HS key that would be needed by an iclass reader to talk to above CSN:");
355 printvar("k_sel", key_sel
,8);
356 //Permute from iclass format to standard format
357 permutekey_rev(key_sel
,key_sel_p
);
358 used_key
= key_sel_p
;
360 //Perhaps this should also be permuted to std format?
361 // Something like the code below? I have no std system
362 // to test this with /Martin
364 //uint8_t key_sel_p[8] = { 0 };
365 //permutekey_rev(KEY,key_sel_p);
366 //used_key = key_sel_p;
372 PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
373 printvar("Used key",used_key
,8);
374 diversifyKey(CSN
,used_key
, div_key
);
375 PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
376 printvar("Div key", div_key
, 8);
377 printvar("CC_NR:",CCNR
,12);
378 doMAC(CCNR
,12,div_key
, MAC
);
379 printvar("MAC", MAC
, 4);
381 UsbCommand d
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
382 memcpy(d
.d
.asBytes
, MAC
, 4);
383 if(!fake_dummy_test
) SendCommand(&d
);
386 PrintAndLog("Failed to obtain CC! Aborting");
389 PrintAndLog("Command execute timeout");
395 int CmdHFiClass_iso14443A_write(const char *Cmd
)
397 uint8_t readerType
= 0;
398 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
399 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
400 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
401 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
402 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
405 uint8_t bldata
[8]={0};
409 PrintAndLog("Usage: hf iclass write <Key> <Block> <Data>");
410 PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA");
414 if (param_gethex(Cmd
, 0, KEY
, 16))
416 PrintAndLog("KEY must include 16 HEX symbols");
420 blockNo
= param_get8(Cmd
, 1);
423 PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!");
426 if (param_gethex(Cmd
, 2, bldata
, 8))
428 PrintAndLog("Block data must include 8 HEX symbols");
432 UsbCommand c
= {CMD_ICLASS_ISO14443A_WRITE
, {0}};
436 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
437 uint8_t isOK
= resp
.arg
[0] & 0xff;
438 uint8_t * data
= resp
.d
.asBytes
;
441 memcpy(CCNR
,data
+8,8);
442 PrintAndLog("DEBUG: %s",sprint_hex(CSN
,8));
443 PrintAndLog("DEBUG: %s",sprint_hex(CCNR
,8));
444 PrintAndLog("isOk:%02x", isOK
);
446 PrintAndLog("Command execute timeout");
449 diversifyKey(CSN
,KEY
, div_key
);
451 PrintAndLog("Div Key: %s",sprint_hex(div_key
,8));
452 doMAC(CCNR
, 12,div_key
, MAC
);
454 UsbCommand c2
= {CMD_ICLASS_ISO14443A_WRITE
, {readerType
,blockNo
}};
455 memcpy(c2
.d
.asBytes
, bldata
, 8);
456 memcpy(c2
.d
.asBytes
+8, MAC
, 4);
459 if (WaitForResponseTimeout(CMD_ACK
,&resp
,1500)) {
460 uint8_t isOK
= resp
.arg
[0] & 0xff;
461 uint8_t * data
= resp
.d
.asBytes
;
464 PrintAndLog("isOk:%02x data:%s", isOK
, sprint_hex(data
, 4));
466 PrintAndLog("isOk:%02x", isOK
);
468 PrintAndLog("Command execute timeout");
474 static command_t CommandTable
[] =
476 {"help", CmdHelp
, 1, "This help"},
477 {"list", CmdHFiClassList
, 0, "[Deprecated] List iClass history"},
478 {"snoop", CmdHFiClassSnoop
, 0, "Eavesdrop iClass communication"},
479 {"sim", CmdHFiClassSim
, 0, "Simulate iClass tag"},
480 {"reader",CmdHFiClassReader
, 0, "Read an iClass tag"},
481 {"replay", CmdHFiClassReader_Replay
, 0, "Read an iClass tag via Reply Attack"},
482 {"dump", CmdHFiClassReader_Dump
, 0, "Authenticate and Dump iClass tag"},
483 {"write", CmdHFiClass_iso14443A_write
, 0, "Authenticate and Write iClass block"},
484 {NULL
, NULL
, 0, NULL
}
487 int CmdHFiClass(const char *Cmd
)
489 CmdsParse(CommandTable
, Cmd
);
493 int CmdHelp(const char *Cmd
)
495 CmdsHelp(CommandTable
);