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 #define ICLASS_CMD_ACTALL 0x0A
46 #define ICLASS_CMD_IDENTIFY 0x0C
47 #define ICLASS_CMD_READ 0x0C
49 #define ICLASS_CMD_SELECT 0x81
50 #define ICLASS_CMD_PAGESEL 0x84
51 #define ICLASS_CMD_READCHECK 0x88
52 #define ICLASS_CMD_CHECK 0x05
53 #define ICLASS_CMD_SOF 0x0F
54 #define ICLASS_CMD_HALT 0x00
57 void explain(char *exp
, size_t size
, uint8_t* cmd
, uint8_t cmdsize
)
60 if(cmdsize
> 1 && cmd
[0] == ICLASS_CMD_READ
)
62 snprintf(exp
,size
,"READ(%d)",cmd
[1]);
68 case ICLASS_CMD_ACTALL
: snprintf(exp
,size
,"ACTALL"); break;
69 case ICLASS_CMD_IDENTIFY
: snprintf(exp
,size
,"IDENTIFY"); break;
70 case ICLASS_CMD_SELECT
: snprintf(exp
,size
,"SELECT"); break;
71 case ICLASS_CMD_PAGESEL
: snprintf(exp
,size
,"PAGESEL"); break;
72 case ICLASS_CMD_READCHECK
: snprintf(exp
,size
,"READCHECK"); break;
73 case ICLASS_CMD_CHECK
: snprintf(exp
,size
,"CHECK"); break;
74 case ICLASS_CMD_SOF
: snprintf(exp
,size
,"SOF"); break;
75 case ICLASS_CMD_HALT
: snprintf(exp
,size
,"HALT"); break;
76 default: snprintf(exp
,size
,"?"); break;
81 int CmdHFiClassList(const char *Cmd
)
83 PrintAndLog("Deprecated command, use 'hf list iclass' instead");
87 int CmdHFiClassSnoop(const char *Cmd
)
89 UsbCommand c
= {CMD_SNOOP_ICLASS
};
94 int CmdHFiClassSim(const char *Cmd
)
97 uint8_t CSN
[8] = {0, 0, 0, 0, 0, 0, 0, 0};
100 PrintAndLog("Usage: hf iclass sim [0 <CSN>] | x");
101 PrintAndLog(" options");
102 PrintAndLog(" 0 <CSN> simulate the given CSN");
103 PrintAndLog(" 1 simulate default CSN");
104 PrintAndLog(" 2 iterate CSNs, gather MACs");
105 PrintAndLog(" sample: hf iclass sim 0 031FEC8AF7FF12E0");
106 PrintAndLog(" sample: hf iclass sim 2");
110 simType
= param_get8(Cmd
, 0);
114 if (param_gethex(Cmd
, 1, CSN
, 16)) {
115 PrintAndLog("A CSN should consist of 16 HEX symbols");
118 PrintAndLog("--simtype:%02x csn:%s", simType
, sprint_hex(CSN
, 8));
123 PrintAndLog("Undefined simptype %d", simType
);
126 uint8_t numberOfCSNs
=0;
130 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,NUM_CSNS
}};
131 UsbCommand resp
= {0};
133 /*uint8_t csns[8 * NUM_CSNS] = {
134 0x00,0x0B,0x0F,0xFF,0xF7,0xFF,0x12,0xE0 ,
135 0x00,0x13,0x94,0x7e,0x76,0xff,0x12,0xe0 ,
136 0x2a,0x99,0xac,0x79,0xec,0xff,0x12,0xe0 ,
137 0x17,0x12,0x01,0xfd,0xf7,0xff,0x12,0xe0 ,
138 0xcd,0x56,0x01,0x7c,0x6f,0xff,0x12,0xe0 ,
139 0x4b,0x5e,0x0b,0x72,0xef,0xff,0x12,0xe0 ,
140 0x00,0x73,0xd8,0x75,0x58,0xff,0x12,0xe0 ,
141 0x0c,0x90,0x32,0xf3,0x5d,0xff,0x12,0xe0 };
144 uint8_t csns
[8*NUM_CSNS
] = {
145 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
146 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
147 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
148 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
149 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
150 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
151 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
152 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
153 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
154 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
155 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
156 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
157 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
158 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
159 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
161 memcpy(c
.d
.asBytes
, csns
, 8*NUM_CSNS
);
164 if (!WaitForResponseTimeout(CMD_ACK
, &resp
, -1)) {
165 PrintAndLog("Command timed out");
169 uint8_t num_mac_responses
= resp
.arg
[1];
170 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses
,NUM_CSNS
);
172 size_t datalen
= NUM_CSNS
*24;
174 * Now, time to dump to file. We'll use this format:
175 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
176 * So, it should wind up as
179 * The returndata from the pm3 is on the following format
180 * <4 byte NR><4 byte MAC>
181 * CC are all zeroes, CSN is the same as was sent in
183 void* dump
= malloc(datalen
);
184 memset(dump
,0,datalen
);//<-- Need zeroes for the CC-field
186 for(i
= 0 ; i
< NUM_CSNS
; i
++)
188 memcpy(dump
+i
*24, csns
+i
*8,8); //CSN
189 //8 zero bytes here...
190 //Then comes NR_MAC (eight bytes from the response)
191 memcpy(dump
+i
*24+16,resp
.d
.asBytes
+i
*8,8);
194 /** Now, save to dumpfile **/
195 saveFile("iclass_mac_attack", "bin", dump
,datalen
);
199 UsbCommand c
= {CMD_SIMULATE_TAG_ICLASS
, {simType
,numberOfCSNs
}};
200 memcpy(c
.d
.asBytes
, CSN
, 8);
207 int CmdHFiClassReader(const char *Cmd
)
209 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
213 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
214 uint8_t isOK
= resp
.arg
[0] & 0xff;
215 uint8_t * data
= resp
.d
.asBytes
;
217 PrintAndLog("isOk:%02x", isOK
);
220 PrintAndLog("Quitting...");
225 PrintAndLog("CSN: %s",sprint_hex(data
,8));
229 PrintAndLog("CC: %s",sprint_hex(data
+8,8));
231 PrintAndLog("No CC obtained");
234 PrintAndLog("Command execute timeout");
241 int CmdHFiClassReader_Replay(const char *Cmd
)
243 uint8_t readerType
= 0;
244 uint8_t MAC
[4]={0x00, 0x00, 0x00, 0x00};
247 PrintAndLog("Usage: hf iclass replay <MAC>");
248 PrintAndLog(" sample: hf iclass replay 00112233");
252 if (param_gethex(Cmd
, 0, MAC
, 8)) {
253 PrintAndLog("MAC must include 8 HEX symbols");
257 UsbCommand c
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
258 memcpy(c
.d
.asBytes
, MAC
, 4);
264 int CmdHFiClassReader_Dump(const char *Cmd
)
266 uint8_t readerType
= 0;
267 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
268 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
269 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
270 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
271 //uint8_t CC_temp[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
272 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
273 uint8_t keytable
[128] = {0};
279 PrintAndLog("Usage: hf iclass dump <Key> [e]");
280 PrintAndLog(" Key - A 16 byte master key");
281 PrintAndLog(" e - If 'e' is specified, the key is interpreted as the 16 byte");
282 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
283 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
284 PrintAndLog(" sample: hf iclass dump 0011223344556677");
290 if (param_gethex(Cmd
, 0, KEY
, 16))
292 PrintAndLog("KEY must include 16 HEX symbols");
296 if (param_getchar(Cmd
, 1) == 'e')
298 PrintAndLog("Elite switch on");
302 hash2(KEY
, keytable
);
303 printarr_human_readable("keytable", keytable
, 128);
308 uint8_t key_sel
[8] = {0};
309 uint8_t key_sel_p
[8] = { 0 };
311 //HACK -- Below is for testing without access to a tag
312 uint8_t fake_dummy_test
= false;
315 uint8_t xdata
[16] = {0x01,0x02,0x03,0x04,0xF7,0xFF,0x12,0xE0, //CSN from http://www.proxmark.org/forum/viewtopic.php?pid=11230#p11230
316 0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; // Just a random CC. Would be good to add a real testcase here
317 memcpy(resp
.d
.asBytes
,xdata
, 16);
324 UsbCommand c
= {CMD_READER_ICLASS
, {0}};
325 c
.arg
[0] = FLAG_ICLASS_READER_ONLY_ONCE
| FLAG_ICLASS_READER_GET_CC
;
331 if (fake_dummy_test
|| WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
332 uint8_t isOK
= resp
.arg
[0] & 0xff;
333 uint8_t * data
= resp
.d
.asBytes
;
336 memcpy(CCNR
,data
+8,8);
338 PrintAndLog("isOk:%02x", isOK
);
342 PrintAndLog("CSN: %s",sprint_hex(CSN
,8));
348 //Get the key index (hash1)
349 uint8_t key_index
[8] = {0};
351 hash1(CSN
, key_index
);
352 printvar("hash1", key_index
,8);
353 for(i
= 0; i
< 8 ; i
++)
354 key_sel
[i
] = keytable
[key_index
[i
]] & 0xFF;
355 PrintAndLog("Pre-fortified 'permuted' HS key that would be needed by an iclass reader to talk to above CSN:");
356 printvar("k_sel", key_sel
,8);
357 //Permute from iclass format to standard format
358 permutekey_rev(key_sel
,key_sel_p
);
359 used_key
= key_sel_p
;
361 //Perhaps this should also be permuted to std format?
362 // Something like the code below? I have no std system
363 // to test this with /Martin
365 //uint8_t key_sel_p[8] = { 0 };
366 //permutekey_rev(KEY,key_sel_p);
367 //used_key = key_sel_p;
373 PrintAndLog("Pre-fortified key that would be needed by the OmniKey reader to talk to above CSN:");
374 printvar("Used key",used_key
,8);
375 diversifyKey(CSN
,used_key
, div_key
);
376 PrintAndLog("Hash0, a.k.a diversified key, that is computed using Ksel and stored in the card (Block 3):");
377 printvar("Div key", div_key
, 8);
378 printvar("CC_NR:",CCNR
,12);
379 doMAC(CCNR
,12,div_key
, MAC
);
380 printvar("MAC", MAC
, 4);
382 UsbCommand d
= {CMD_READER_ICLASS_REPLAY
, {readerType
}};
383 memcpy(d
.d
.asBytes
, MAC
, 4);
384 if(!fake_dummy_test
) SendCommand(&d
);
387 PrintAndLog("Failed to obtain CC! Aborting");
390 PrintAndLog("Command execute timeout");
396 int CmdHFiClass_iso14443A_write(const char *Cmd
)
398 uint8_t readerType
= 0;
399 uint8_t MAC
[4]={0x00,0x00,0x00,0x00};
400 uint8_t KEY
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
401 uint8_t CSN
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
402 uint8_t CCNR
[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
403 uint8_t div_key
[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
406 uint8_t bldata
[8]={0};
410 PrintAndLog("Usage: hf iclass write <Key> <Block> <Data>");
411 PrintAndLog(" sample: hf iclass write 0011223344556677 10 AAAAAAAAAAAAAAAA");
415 if (param_gethex(Cmd
, 0, KEY
, 16))
417 PrintAndLog("KEY must include 16 HEX symbols");
421 blockNo
= param_get8(Cmd
, 1);
424 PrintAndLog("Error: Maximum number of blocks is 32 for iClass 2K Cards!");
427 if (param_gethex(Cmd
, 2, bldata
, 8))
429 PrintAndLog("Block data must include 8 HEX symbols");
433 UsbCommand c
= {CMD_ICLASS_ISO14443A_WRITE
, {0}};
437 if (WaitForResponseTimeout(CMD_ACK
,&resp
,4500)) {
438 uint8_t isOK
= resp
.arg
[0] & 0xff;
439 uint8_t * data
= resp
.d
.asBytes
;
442 memcpy(CCNR
,data
+8,8);
443 PrintAndLog("DEBUG: %s",sprint_hex(CSN
,8));
444 PrintAndLog("DEBUG: %s",sprint_hex(CCNR
,8));
445 PrintAndLog("isOk:%02x", isOK
);
447 PrintAndLog("Command execute timeout");
450 diversifyKey(CSN
,KEY
, div_key
);
452 PrintAndLog("Div Key: %s",sprint_hex(div_key
,8));
453 doMAC(CCNR
, 12,div_key
, MAC
);
455 UsbCommand c2
= {CMD_ICLASS_ISO14443A_WRITE
, {readerType
,blockNo
}};
456 memcpy(c2
.d
.asBytes
, bldata
, 8);
457 memcpy(c2
.d
.asBytes
+8, MAC
, 4);
460 if (WaitForResponseTimeout(CMD_ACK
,&resp
,1500)) {
461 uint8_t isOK
= resp
.arg
[0] & 0xff;
462 uint8_t * data
= resp
.d
.asBytes
;
465 PrintAndLog("isOk:%02x data:%s", isOK
, sprint_hex(data
, 4));
467 PrintAndLog("isOk:%02x", isOK
);
469 PrintAndLog("Command execute timeout");
475 static command_t CommandTable
[] =
477 {"help", CmdHelp
, 1, "This help"},
478 {"list", CmdHFiClassList
, 0, "[Deprecated] List iClass history"},
479 {"snoop", CmdHFiClassSnoop
, 0, "Eavesdrop iClass communication"},
480 {"sim", CmdHFiClassSim
, 0, "Simulate iClass tag"},
481 {"reader",CmdHFiClassReader
, 0, "Read an iClass tag"},
482 {"replay",CmdHFiClassReader_Replay
, 0, "Read an iClass tag via Reply Attack"},
483 {"dump", CmdHFiClassReader_Dump
, 0, "Authenticate and Dump iClass tag"},
484 {"write", CmdHFiClass_iso14443A_write
, 0, "Authenticate and Write iClass block"},
485 {NULL
, NULL
, 0, NULL
}
488 int CmdHFiClass(const char *Cmd
)
490 CmdsParse(CommandTable
, Cmd
);
494 int CmdHelp(const char *Cmd
)
496 CmdsHelp(CommandTable
);