]> git.zerfleddert.de Git - proxmark3-svn/blame_incremental - client/cmdhficlass.c
fix keyNbr entry error checking
[proxmark3-svn] / client / cmdhficlass.c
... / ...
CommitLineData
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
5//
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
8// the license.
9//-----------------------------------------------------------------------------
10// High frequency iClass commands
11//-----------------------------------------------------------------------------
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/stat.h>
17#include "iso14443crc.h" // Can also be used for iClass, using 0xE012 as CRC-type
18#include "data.h"
19#include "proxmark3.h"
20#include "ui.h"
21#include "cmdparser.h"
22#include "cmdhficlass.h"
23#include "common.h"
24#include "util.h"
25#include "cmdmain.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"
32#include "protocols.h"
33#include "usb_cmd.h"
34#include "cmdhfmfu.h"
35
36#define llX PRIx64
37
38static int CmdHelp(const char *Cmd);
39
40#define ICLASS_KEYS_MAX 8
41static uint8_t iClass_Key_Table[ICLASS_KEYS_MAX][8] = {
42 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
43 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
44 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
45 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
46 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
47 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
48 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 },
49 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }
50};
51
52typedef struct iclass_block {
53 uint8_t d[8];
54} iclass_block_t;
55
56int xorbits_8(uint8_t val) {
57 uint8_t res = val ^ (val >> 1); //1st pass
58 res = res ^ (res >> 1); // 2nd pass
59 res = res ^ (res >> 2); // 3rd pass
60 res = res ^ (res >> 4); // 4th pass
61 return res & 1;
62}
63
64int CmdHFiClassList(const char *Cmd) {
65 PrintAndLog("Deprecated command, use 'hf list iclass' instead");
66 return 0;
67}
68
69int CmdHFiClassSnoop(const char *Cmd) {
70 UsbCommand c = {CMD_SNOOP_ICLASS};
71 SendCommand(&c);
72 return 0;
73}
74
75int usage_hf_iclass_sim(void) {
76 PrintAndLog("Usage: hf iclass sim <option> [CSN]");
77 PrintAndLog(" options");
78 PrintAndLog(" 0 <CSN> simulate the given CSN");
79 PrintAndLog(" 1 simulate default CSN");
80 PrintAndLog(" 2 Reader-attack, gather reader responses to extract elite key");
81 PrintAndLog(" 3 Full simulation using emulator memory (see 'hf iclass eload')");
82 PrintAndLog(" example: hf iclass sim 0 031FEC8AF7FF12E0");
83 PrintAndLog(" example: hf iclass sim 2");
84 PrintAndLog(" example: hf iclass eload 'tagdump.bin'");
85 PrintAndLog(" hf iclass sim 3");
86 return 0;
87}
88
89#define NUM_CSNS 15
90int CmdHFiClassSim(const char *Cmd) {
91 uint8_t simType = 0;
92 uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0};
93
94 if (strlen(Cmd)<1) {
95 return usage_hf_iclass_sim();
96 }
97 simType = param_get8ex(Cmd, 0, 0, 10);
98
99 if(simType == 0)
100 {
101 if (param_gethex(Cmd, 1, CSN, 16)) {
102 PrintAndLog("A CSN should consist of 16 HEX symbols");
103 return usage_hf_iclass_sim();
104 }
105
106 PrintAndLog("--simtype:%02x csn:%s", simType, sprint_hex(CSN, 8));
107 }
108 if(simType > 3)
109 {
110 PrintAndLog("Undefined simptype %d", simType);
111 return usage_hf_iclass_sim();
112 }
113
114 uint8_t numberOfCSNs=0;
115 if(simType == 2)
116 {
117 UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,NUM_CSNS}};
118 UsbCommand resp = {0};
119
120 uint8_t csns[8*NUM_CSNS] = {
121 0x00, 0x0B, 0x0F, 0xFF, 0xF7, 0xFF, 0x12, 0xE0,
122 0x00, 0x04, 0x0E, 0x08, 0xF7, 0xFF, 0x12, 0xE0,
123 0x00, 0x09, 0x0D, 0x05, 0xF7, 0xFF, 0x12, 0xE0,
124 0x00, 0x0A, 0x0C, 0x06, 0xF7, 0xFF, 0x12, 0xE0,
125 0x00, 0x0F, 0x0B, 0x03, 0xF7, 0xFF, 0x12, 0xE0,
126 0x00, 0x08, 0x0A, 0x0C, 0xF7, 0xFF, 0x12, 0xE0,
127 0x00, 0x0D, 0x09, 0x09, 0xF7, 0xFF, 0x12, 0xE0,
128 0x00, 0x0E, 0x08, 0x0A, 0xF7, 0xFF, 0x12, 0xE0,
129 0x00, 0x03, 0x07, 0x17, 0xF7, 0xFF, 0x12, 0xE0,
130 0x00, 0x3C, 0x06, 0xE0, 0xF7, 0xFF, 0x12, 0xE0,
131 0x00, 0x01, 0x05, 0x1D, 0xF7, 0xFF, 0x12, 0xE0,
132 0x00, 0x02, 0x04, 0x1E, 0xF7, 0xFF, 0x12, 0xE0,
133 0x00, 0x07, 0x03, 0x1B, 0xF7, 0xFF, 0x12, 0xE0,
134 0x00, 0x00, 0x02, 0x24, 0xF7, 0xFF, 0x12, 0xE0,
135 0x00, 0x05, 0x01, 0x21, 0xF7, 0xFF, 0x12, 0xE0 };
136
137 memcpy(c.d.asBytes, csns, 8*NUM_CSNS);
138
139 SendCommand(&c);
140 if (!WaitForResponseTimeout(CMD_ACK, &resp, -1)) {
141 PrintAndLog("Command timed out");
142 return 0;
143 }
144
145 uint8_t num_mac_responses = resp.arg[1];
146 PrintAndLog("Mac responses: %d MACs obtained (should be %d)", num_mac_responses,NUM_CSNS);
147
148 size_t datalen = NUM_CSNS*24;
149 /*
150 * Now, time to dump to file. We'll use this format:
151 * <8-byte CSN><8-byte CC><4 byte NR><4 byte MAC>....
152 * So, it should wind up as
153 * 8 * 24 bytes.
154 *
155 * The returndata from the pm3 is on the following format
156 * <4 byte NR><4 byte MAC>
157 * CC are all zeroes, CSN is the same as was sent in
158 **/
159 void* dump = malloc(datalen);
160 memset(dump,0,datalen);//<-- Need zeroes for the CC-field
161 uint8_t i = 0;
162 for(i = 0 ; i < NUM_CSNS ; i++)
163 {
164 memcpy(dump+i*24, csns+i*8,8); //CSN
165 //8 zero bytes here...
166 //Then comes NR_MAC (eight bytes from the response)
167 memcpy(dump+i*24+16,resp.d.asBytes+i*8,8);
168
169 }
170 /** Now, save to dumpfile **/
171 saveFile("iclass_mac_attack", "bin", dump,datalen);
172 free(dump);
173 }else
174 {
175 UsbCommand c = {CMD_SIMULATE_TAG_ICLASS, {simType,numberOfCSNs}};
176 memcpy(c.d.asBytes, CSN, 8);
177 SendCommand(&c);
178 }
179
180 return 0;
181}
182
183int HFiClassReader(const char *Cmd, bool loop, bool verbose) {
184 bool tagFound = false;
185 UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_CSN|
186 FLAG_ICLASS_READER_CONF|FLAG_ICLASS_READER_AA}};
187 // loop in client not device - else on windows have a communication error
188 c.arg[0] |= FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_ONE_TRY;
189 UsbCommand resp;
190 while(!ukbhit()){
191 SendCommand(&c);
192 if (WaitForResponseTimeout(CMD_ACK,&resp, 4500)) {
193 uint8_t readStatus = resp.arg[0] & 0xff;
194 uint8_t *data = resp.d.asBytes;
195
196 if (verbose)
197 PrintAndLog("Readstatus:%02x", readStatus);
198 if( readStatus == 0){
199 //Aborted
200 if (verbose) PrintAndLog("Quitting...");
201 return 0;
202 }
203 if( readStatus & FLAG_ICLASS_READER_CSN){
204 PrintAndLog("CSN: %s",sprint_hex(data,8));
205 tagFound = true;
206 }
207 if( readStatus & FLAG_ICLASS_READER_CC) PrintAndLog("CC: %s",sprint_hex(data+16,8));
208 if( readStatus & FLAG_ICLASS_READER_CONF){
209 printIclassDumpInfo(data);
210 }
211 if (tagFound && !loop) return 1;
212 } else {
213 if (verbose) PrintAndLog("Command execute timeout");
214 }
215 if (!loop) break;
216 }
217 return 0;
218}
219
220int CmdHFiClassReader(const char *Cmd) {
221 return HFiClassReader(Cmd, true, true);
222}
223
224int CmdHFiClassReader_Replay(const char *Cmd) {
225 uint8_t readerType = 0;
226 uint8_t MAC[4]={0x00, 0x00, 0x00, 0x00};
227
228 if (strlen(Cmd)<1) {
229 PrintAndLog("Usage: hf iclass replay <MAC>");
230 PrintAndLog(" sample: hf iclass replay 00112233");
231 return 0;
232 }
233
234 if (param_gethex(Cmd, 0, MAC, 8)) {
235 PrintAndLog("MAC must include 8 HEX symbols");
236 return 1;
237 }
238
239 UsbCommand c = {CMD_READER_ICLASS_REPLAY, {readerType}};
240 memcpy(c.d.asBytes, MAC, 4);
241 SendCommand(&c);
242
243 return 0;
244}
245
246int iclassEmlSetMem(uint8_t *data, int blockNum, int blocksCount) {
247 UsbCommand c = {CMD_MIFARE_EML_MEMSET, {blockNum, blocksCount, 0}};
248 memcpy(c.d.asBytes, data, blocksCount * 16);
249 SendCommand(&c);
250 return 0;
251}
252
253int hf_iclass_eload_usage(void) {
254 PrintAndLog("Loads iclass tag-dump into emulator memory on device");
255 PrintAndLog("Usage: hf iclass eload f <filename>");
256 PrintAndLog("");
257 PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin");
258 return 0;
259}
260
261int CmdHFiClassELoad(const char *Cmd) {
262
263 char opt = param_getchar(Cmd, 0);
264 if (strlen(Cmd)<1 || opt == 'h')
265 return hf_iclass_eload_usage();
266
267 //File handling and reading
268 FILE *f;
269 char filename[FILE_PATH_SIZE];
270 if(opt == 'f' && param_getstr(Cmd, 1, filename) > 0)
271 {
272 f = fopen(filename, "rb");
273 }else{
274 return hf_iclass_eload_usage();
275 }
276
277 if(!f) {
278 PrintAndLog("Failed to read from file '%s'", filename);
279 return 1;
280 }
281
282 fseek(f, 0, SEEK_END);
283 long fsize = ftell(f);
284 fseek(f, 0, SEEK_SET);
285
286 if (fsize < 0) {
287 PrintAndLog("Error, when getting filesize");
288 fclose(f);
289 return 1;
290 }
291
292 uint8_t *dump = malloc(fsize);
293
294 size_t bytes_read = fread(dump, 1, fsize, f);
295 fclose(f);
296
297 printIclassDumpInfo(dump);
298 //Validate
299
300 if (bytes_read < fsize)
301 {
302 prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize );
303 free(dump);
304 return 1;
305 }
306 //Send to device
307 uint32_t bytes_sent = 0;
308 uint32_t bytes_remaining = bytes_read;
309
310 while(bytes_remaining > 0){
311 uint32_t bytes_in_packet = MIN(USB_CMD_DATA_SIZE, bytes_remaining);
312 UsbCommand c = {CMD_ICLASS_EML_MEMSET, {bytes_sent,bytes_in_packet,0}};
313 memcpy(c.d.asBytes, dump, bytes_in_packet);
314 SendCommand(&c);
315 bytes_remaining -= bytes_in_packet;
316 bytes_sent += bytes_in_packet;
317 }
318 free(dump);
319 PrintAndLog("Sent %d bytes of data to device emulator memory", bytes_sent);
320 return 0;
321}
322
323static int readKeyfile(const char *filename, size_t len, uint8_t* buffer) {
324 FILE *f = fopen(filename, "rb");
325 if(!f) {
326 PrintAndLog("Failed to read from file '%s'", filename);
327 return 1;
328 }
329 fseek(f, 0, SEEK_END);
330 long fsize = ftell(f);
331 fseek(f, 0, SEEK_SET);
332 size_t bytes_read = fread(buffer, 1, len, f);
333 fclose(f);
334 if(fsize != len)
335 {
336 PrintAndLog("Warning, file size is %d, expected %d", fsize, len);
337 return 1;
338 }
339 if(bytes_read != len)
340 {
341 PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read, len);
342 return 1;
343 }
344 return 0;
345}
346
347int usage_hf_iclass_decrypt(void) {
348 PrintAndLog("Usage: hf iclass decrypt f <tagdump>");
349 PrintAndLog("");
350 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
351 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
352 PrintAndLog("");
353 PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin");
354 PrintAndLog("");
355 PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. ");
356 PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,");
357 PrintAndLog("which is defined by the configuration block.");
358 return 1;
359}
360
361int CmdHFiClassDecrypt(const char *Cmd) {
362 uint8_t key[16] = { 0 };
363 if(readKeyfile("iclass_decryptionkey.bin", 16, key))
364 {
365 usage_hf_iclass_decrypt();
366 return 1;
367 }
368 PrintAndLog("Decryption file found... ");
369 char opt = param_getchar(Cmd, 0);
370 if (strlen(Cmd)<1 || opt == 'h')
371 return usage_hf_iclass_decrypt();
372
373 //Open the tagdump-file
374 FILE *f;
375 char filename[FILE_PATH_SIZE];
376 if(opt == 'f' && param_getstr(Cmd, 1, filename) > 0)
377 {
378 f = fopen(filename, "rb");
379 }else{
380 return usage_hf_iclass_decrypt();
381 }
382
383 fseek(f, 0, SEEK_END);
384 long fsize = ftell(f);
385 fseek(f, 0, SEEK_SET);
386 uint8_t enc_dump[8] = {0};
387 uint8_t *decrypted = malloc(fsize);
388 des3_context ctx = { DES_DECRYPT ,{ 0 } };
389 des3_set2key_dec( &ctx, key);
390 size_t bytes_read = fread(enc_dump, 1, 8, f);
391
392 //Use the first block (CSN) for filename
393 char outfilename[FILE_PATH_SIZE] = { 0 };
394 snprintf(outfilename,FILE_PATH_SIZE,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
395 enc_dump[0],enc_dump[1],enc_dump[2],enc_dump[3],
396 enc_dump[4],enc_dump[5],enc_dump[6],enc_dump[7]);
397
398 size_t blocknum =0;
399 while(bytes_read == 8)
400 {
401 if(blocknum < 7)
402 {
403 memcpy(decrypted+(blocknum*8), enc_dump, 8);
404 }else{
405 des3_crypt_ecb(&ctx, enc_dump,decrypted +(blocknum*8) );
406 }
407 printvar("decrypted block", decrypted +(blocknum*8), 8);
408 bytes_read = fread(enc_dump, 1, 8, f);
409 blocknum++;
410 }
411 fclose(f);
412
413 saveFile(outfilename,"bin", decrypted, blocknum*8);
414 free(decrypted);
415 return 0;
416}
417
418int usage_hf_iclass_encrypt(void) {
419 PrintAndLog("Usage: hf iclass encrypt <BlockData>");
420 PrintAndLog("");
421 PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
422 PrintAndLog("in the working directory. The file should be 16 bytes binary data");
423 PrintAndLog("");
424 PrintAndLog("example: hf iclass encrypt 0102030405060708");
425 PrintAndLog("");
426 return 0;
427}
428
429static int iClassEncryptBlkData(uint8_t *blkData) {
430 uint8_t key[16] = { 0 };
431 if(readKeyfile("iclass_decryptionkey.bin", 16, key))
432 {
433 usage_hf_iclass_encrypt();
434 return 1;
435 }
436 PrintAndLog("Decryption file found... ");
437
438 uint8_t encryptedData[16];
439 uint8_t *encrypted = encryptedData;
440 des3_context ctx = { DES_DECRYPT ,{ 0 } };
441 des3_set2key_enc( &ctx, key);
442
443 des3_crypt_ecb(&ctx, blkData,encrypted);
444 //printvar("decrypted block", decrypted, 8);
445 memcpy(blkData,encrypted,8);
446
447 return 1;
448}
449
450int CmdHFiClassEncryptBlk(const char *Cmd) {
451 uint8_t blkData[8] = {0};
452 char opt = param_getchar(Cmd, 0);
453 if (strlen(Cmd)<1 || opt == 'h')
454 return usage_hf_iclass_encrypt();
455
456 //get the bytes to encrypt
457 if (param_gethex(Cmd, 0, blkData, 16))
458 {
459 PrintAndLog("BlockData must include 16 HEX symbols");
460 return 0;
461 }
462 if (!iClassEncryptBlkData(blkData)) return 0;
463
464 printvar("encrypted block", blkData, 8);
465 return 1;
466}
467
468void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t MAC[4]) {
469 uint8_t WB[9];
470 WB[0] = blockno;
471 memcpy(WB + 1,data,8);
472 doMAC_N(WB,sizeof(WB),div_key,MAC);
473 //printf("Cal wb mac block [%02x][%02x%02x%02x%02x%02x%02x%02x%02x] : MAC [%02x%02x%02x%02x]",WB[0],WB[1],WB[2],WB[3],WB[4],WB[5],WB[6],WB[7],WB[8],MAC[0],MAC[1],MAC[2],MAC[3]);
474}
475
476static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool verbose) {
477 UsbCommand resp;
478
479 UsbCommand c = {CMD_READER_ICLASS, {0}};
480 c.arg[0] = FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_ONE_TRY;
481 if (use_credit_key)
482 c.arg[0] |= FLAG_ICLASS_READER_CEDITKEY;
483
484 clearCommandBuffer();
485 SendCommand(&c);
486 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
487 {
488 PrintAndLog("Command execute timeout");
489 return false;
490 }
491
492 uint8_t isOK = resp.arg[0] & 0xff;
493 uint8_t *data = resp.d.asBytes;
494
495 memcpy(CSN,data,8);
496 if (CCNR!=NULL)memcpy(CCNR,data+16,8);
497 if(isOK > 0)
498 {
499 if (verbose) PrintAndLog("CSN: %s",sprint_hex(CSN,8));
500 }
501 if(isOK <= 1){
502 PrintAndLog("Failed to obtain CC! Aborting");
503 return false;
504 }
505 return true;
506}
507
508static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool verbose) {
509 uint8_t CSN[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
510 uint8_t CCNR[12]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
511
512 if (!select_only(CSN, CCNR, use_credit_key, verbose))
513 return false;
514
515 //get div_key
516 if(rawkey)
517 memcpy(div_key, KEY, 8);
518 else
519 HFiClassCalcDivKey(CSN, KEY, div_key, elite);
520 PrintAndLog("Authing with %s: %02x%02x%02x%02x%02x%02x%02x%02x", rawkey ? "raw key" : "diversified key", div_key[0],div_key[1],div_key[2],div_key[3],div_key[4],div_key[5],div_key[6],div_key[7]);
521
522 doMAC(CCNR, div_key, MAC);
523 UsbCommand resp;
524 UsbCommand d = {CMD_ICLASS_AUTHENTICATION, {0}};
525 memcpy(d.d.asBytes, MAC, 4);
526 clearCommandBuffer();
527 SendCommand(&d);
528 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
529 {
530 PrintAndLog("Auth Command execute timeout");
531 return false;
532 }
533 uint8_t isOK = resp.arg[0] & 0xff;
534 if (!isOK) {
535 PrintAndLog("Authentication error");
536 return false;
537 }
538 return true;
539}
540
541int usage_hf_iclass_dump(void) {
542 PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r\n");
543 PrintAndLog("Options:");
544 PrintAndLog(" f <filename> : specify a filename to save dump to");
545 PrintAndLog(" k <Key> : *Access Key as 16 hex symbols or 1 hex to select key from memory");
546 PrintAndLog(" c <CreditKey>: Credit Key as 16 hex symbols or 1 hex to select key from memory");
547 PrintAndLog(" e : If 'e' is specified, the key is interpreted as the 16 byte");
548 PrintAndLog(" Custom Key (KCus), which can be obtained via reader-attack");
549 PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
550 PrintAndLog(" r : If 'r' is specified, the key is interpreted as raw block 3/4");
551 PrintAndLog(" NOTE: * = required");
552 PrintAndLog("Samples:");
553 PrintAndLog(" hf iclass dump k 001122334455667B");
554 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B");
555 PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA e");
556 return 0;
557}
558
559int CmdHFiClassReader_Dump(const char *Cmd) {
560
561 uint8_t MAC[4] = {0x00,0x00,0x00,0x00};
562 uint8_t div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
563 uint8_t c_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
564 uint8_t blockno = 0;
565 uint8_t numblks = 0;
566 uint8_t maxBlk = 31;
567 uint8_t app_areas = 1;
568 uint8_t kb = 2;
569 uint8_t KEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
570 uint8_t CreditKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
571 uint8_t keyNbr = 0;
572 uint8_t dataLen = 0;
573 uint8_t fileNameLen = 0;
574 char filename[FILE_PATH_SIZE]={0};
575 char tempStr[50] = {0};
576 bool have_debit_key = false;
577 bool have_credit_key = false;
578 bool use_credit_key = false;
579 bool elite = false;
580 bool rawkey = false;
581 bool errors = false;
582 uint8_t cmdp = 0;
583
584 while(param_getchar(Cmd, cmdp) != 0x00)
585 {
586 switch(param_getchar(Cmd, cmdp))
587 {
588 case 'h':
589 case 'H':
590 return usage_hf_iclass_dump();
591 case 'c':
592 case 'C':
593 have_credit_key = true;
594 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
595 if (dataLen == 16) {
596 errors = param_gethex(tempStr, 0, CreditKEY, dataLen);
597 } else if (dataLen == 1) {
598 keyNbr = param_get8(Cmd, cmdp+1);
599 if (keyNbr < ICLASS_KEYS_MAX) {
600 memcpy(CreditKEY, iClass_Key_Table[keyNbr], 8);
601 } else {
602 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
603 errors = true;
604 }
605 } else {
606 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
607 errors = true;
608 }
609 cmdp += 2;
610 break;
611 case 'e':
612 case 'E':
613 elite = true;
614 cmdp++;
615 break;
616 case 'f':
617 case 'F':
618 fileNameLen = param_getstr(Cmd, cmdp+1, filename);
619 if (fileNameLen < 1) {
620 PrintAndLog("No filename found after f");
621 errors = true;
622 }
623 cmdp += 2;
624 break;
625 case 'k':
626 case 'K':
627 have_debit_key = true;
628 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
629 if (dataLen == 16) {
630 errors = param_gethex(tempStr, 0, KEY, dataLen);
631 } else if (dataLen == 1) {
632 keyNbr = param_get8(Cmd, cmdp+1);
633 if (keyNbr < ICLASS_KEYS_MAX) {
634 memcpy(KEY, iClass_Key_Table[keyNbr], 8);
635 } else {
636 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
637 errors = true;
638 }
639 } else {
640 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
641 errors = true;
642 }
643 cmdp += 2;
644 break;
645 case 'r':
646 case 'R':
647 rawkey = true;
648 cmdp++;
649 break;
650 default:
651 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
652 errors = true;
653 break;
654 }
655 if(errors) return usage_hf_iclass_dump();
656 }
657
658 if (cmdp < 2) return usage_hf_iclass_dump();
659 // if no debit key given try credit key on AA1 (not for iclass but for some picopass this will work)
660 if (!have_debit_key && have_credit_key) use_credit_key = true;
661
662 //get config and first 3 blocks
663 UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_CSN |
664 FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_ONLY_ONCE | FLAG_ICLASS_READER_ONE_TRY}};
665 UsbCommand resp;
666 uint8_t tag_data[255*8];
667
668 clearCommandBuffer();
669 SendCommand(&c);
670 if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
671 PrintAndLog("Command execute timeout");
672 ul_switch_off_field();
673 return 0;
674 }
675 uint8_t readStatus = resp.arg[0] & 0xff;
676 uint8_t *data = resp.d.asBytes;
677
678 if(readStatus == 0){
679 PrintAndLog("No tag found...");
680 ul_switch_off_field();
681 return 0;
682 }
683 if( readStatus & (FLAG_ICLASS_READER_CSN|FLAG_ICLASS_READER_CONF|FLAG_ICLASS_READER_CC)){
684 memcpy(tag_data, data, 8*3);
685 blockno+=2; // 2 to force re-read of block 2 later. (seems to respond differently..)
686 numblks = data[8];
687 getMemConfig(data[13], data[12], &maxBlk, &app_areas, &kb);
688 // large memory - not able to dump pages currently
689 if (numblks > maxBlk) numblks = maxBlk;
690 }
691 ul_switch_off_field();
692 // authenticate debit key and get div_key - later store in dump block 3
693 if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, false)){
694 //try twice - for some reason it sometimes fails the first time...
695 if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, false)){
696 ul_switch_off_field();
697 return 0;
698 }
699 }
700
701 // begin dump
702 UsbCommand w = {CMD_ICLASS_DUMP, {blockno, numblks-blockno+1}};
703 clearCommandBuffer();
704 SendCommand(&w);
705 if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
706 PrintAndLog("Command execute time-out 1");
707 ul_switch_off_field();
708 return 1;
709 }
710 uint32_t blocksRead = resp.arg[1];
711 uint8_t isOK = resp.arg[0] & 0xff;
712 if (!isOK && !blocksRead) {
713 PrintAndLog("Read Block Failed");
714 ul_switch_off_field();
715 return 0;
716 }
717 uint32_t startindex = resp.arg[2];
718 if (blocksRead*8 > sizeof(tag_data)-(blockno*8)) {
719 PrintAndLog("Data exceeded Buffer size!");
720 blocksRead = (sizeof(tag_data)/8) - blockno;
721 }
722 // response ok - now get bigbuf content of the dump
723 GetFromBigBuf(tag_data+(blockno*8), blocksRead*8, startindex);
724 WaitForResponse(CMD_ACK,NULL);
725 size_t gotBytes = blocksRead*8 + blockno*8;
726
727 // try AA2
728 if (have_credit_key) {
729 //turn off hf field before authenticating with different key
730 ul_switch_off_field();
731 memset(MAC,0,4);
732 // AA2 authenticate credit key and git c_div_key - later store in dump block 4
733 if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false, false)){
734 //try twice - for some reason it sometimes fails the first time...
735 if (!select_and_auth(CreditKEY, MAC, c_div_key, true, false, false, false)){
736 ul_switch_off_field();
737 return 0;
738 }
739 }
740 // do we still need to read more block? (aa2 enabled?)
741 if (maxBlk > blockno+numblks+1) {
742 // setup dump and start
743 w.arg[0] = blockno + blocksRead;
744 w.arg[1] = maxBlk - (blockno + blocksRead);
745 clearCommandBuffer();
746 SendCommand(&w);
747 if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
748 PrintAndLog("Command execute timeout 2");
749 ul_switch_off_field();
750 return 0;
751 }
752 uint8_t isOK = resp.arg[0] & 0xff;
753 blocksRead = resp.arg[1];
754 if (!isOK && !blocksRead) {
755 PrintAndLog("Read Block Failed 2");
756 ul_switch_off_field();
757 return 0;
758 }
759
760 startindex = resp.arg[2];
761 if (blocksRead*8 > sizeof(tag_data)-gotBytes) {
762 PrintAndLog("Data exceeded Buffer size!");
763 blocksRead = (sizeof(tag_data) - gotBytes)/8;
764 }
765 // get dumped data from bigbuf
766 GetFromBigBuf(tag_data+gotBytes, blocksRead*8, startindex);
767 WaitForResponse(CMD_ACK,NULL);
768
769 gotBytes += blocksRead*8;
770 } else { //field is still on - turn it off...
771 ul_switch_off_field();
772 }
773 }
774
775 // add diversified keys to dump
776 if (have_debit_key) memcpy(tag_data+(3*8),div_key,8);
777 if (have_credit_key) memcpy(tag_data+(4*8),c_div_key,8);
778 // print the dump
779 printf("CSN |00| %02X %02X %02X %02X %02X %02X %02X %02X |\n",tag_data[0],tag_data[1],tag_data[2]
780 ,tag_data[3],tag_data[4],tag_data[5],tag_data[6],tag_data[7]);
781 printIclassDumpContents(tag_data, 1, (gotBytes/8)-1, gotBytes-8);
782
783 if (filename[0] == 0){
784 snprintf(filename, FILE_PATH_SIZE,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
785 tag_data[0],tag_data[1],tag_data[2],tag_data[3],
786 tag_data[4],tag_data[5],tag_data[6],tag_data[7]);
787 }
788
789 // save the dump to .bin file
790 PrintAndLog("Saving dump file - %d blocks read", gotBytes/8);
791 saveFile(filename, "bin", tag_data, gotBytes);
792 return 1;
793}
794
795static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool verbose) {
796 uint8_t MAC[4]={0x00,0x00,0x00,0x00};
797 uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
798 if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose))
799 return 0;
800
801 UsbCommand resp;
802
803 Calc_wb_mac(blockno,bldata,div_key,MAC);
804 UsbCommand w = {CMD_ICLASS_WRITEBLOCK, {blockno}};
805 memcpy(w.d.asBytes, bldata, 8);
806 memcpy(w.d.asBytes + 8, MAC, 4);
807
808 clearCommandBuffer();
809 SendCommand(&w);
810 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
811 {
812 PrintAndLog("Write Command execute timeout");
813 return 0;
814 }
815 uint8_t isOK = resp.arg[0] & 0xff;
816 if (!isOK) {
817 PrintAndLog("Write Block Failed");
818 return 0;
819 }
820 PrintAndLog("Write Block Successful");
821 return 1;
822}
823
824int usage_hf_iclass_writeblock(void) {
825 PrintAndLog("Options:");
826 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
827 PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols");
828 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
829 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
830 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
831 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
832 PrintAndLog("Samples:");
833 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA k 001122334455667B");
834 PrintAndLog(" hf iclass writeblk b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c");
835 PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA n 0");
836 return 0;
837}
838
839int CmdHFiClass_WriteBlock(const char *Cmd) {
840 uint8_t blockno=0;
841 uint8_t bldata[8]={0,0,0,0,0,0,0,0};
842 uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
843 uint8_t keyNbr = 0;
844 uint8_t dataLen = 0;
845 char tempStr[50] = {0};
846 bool use_credit_key = false;
847 bool elite = false;
848 bool rawkey= false;
849 bool errors = false;
850 uint8_t cmdp = 0;
851 while(param_getchar(Cmd, cmdp) != 0x00)
852 {
853 switch(param_getchar(Cmd, cmdp))
854 {
855 case 'h':
856 case 'H':
857 return usage_hf_iclass_writeblock();
858 case 'b':
859 case 'B':
860 if (param_gethex(Cmd, cmdp+1, &blockno, 2)) {
861 PrintAndLog("Block No must include 2 HEX symbols\n");
862 errors = true;
863 }
864 cmdp += 2;
865 break;
866 case 'c':
867 case 'C':
868 use_credit_key = true;
869 cmdp++;
870 break;
871 case 'd':
872 case 'D':
873 if (param_gethex(Cmd, cmdp+1, bldata, 16))
874 {
875 PrintAndLog("KEY must include 16 HEX symbols\n");
876 errors = true;
877 }
878 cmdp += 2;
879 break;
880 case 'e':
881 case 'E':
882 elite = true;
883 cmdp++;
884 break;
885 case 'k':
886 case 'K':
887 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
888 if (dataLen == 16) {
889 errors = param_gethex(tempStr, 0, KEY, dataLen);
890 } else if (dataLen == 1) {
891 keyNbr = param_get8(Cmd, cmdp+1);
892 if (keyNbr < ICLASS_KEYS_MAX) {
893 memcpy(KEY, iClass_Key_Table[keyNbr], 8);
894 } else {
895 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
896 errors = true;
897 }
898 } else {
899 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
900 errors = true;
901 }
902 cmdp += 2;
903 break;
904 case 'r':
905 case 'R':
906 rawkey = true;
907 cmdp++;
908 break;
909 default:
910 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
911 errors = true;
912 break;
913 }
914 if(errors) return usage_hf_iclass_writeblock();
915 }
916
917 if (cmdp < 6) return usage_hf_iclass_writeblock();
918 int ans = WriteBlock(blockno, bldata, KEY, use_credit_key, elite, rawkey, true);
919 ul_switch_off_field();
920 return ans;
921}
922
923int usage_hf_iclass_clone(void) {
924 PrintAndLog("Usage: hf iclass clone f <tagfile.bin> b <first block> l <last block> k <KEY> c e|r");
925 PrintAndLog("Options:");
926 PrintAndLog(" f <filename>: specify a filename to clone from");
927 PrintAndLog(" b <Block> : The first block to clone as 2 hex symbols");
928 PrintAndLog(" l <Last Blk>: Set the Data to write as 16 hex symbols");
929 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
930 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
931 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
932 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
933 PrintAndLog("Samples:");
934 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 1A k 1122334455667788 e");
935 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 05 l 19 k 0");
936 PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 19 k 0 e");
937 return -1;
938}
939
940int CmdHFiClassCloneTag(const char *Cmd) {
941 char filename[FILE_PATH_SIZE];
942 char tempStr[50]={0};
943 uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
944 uint8_t keyNbr = 0;
945 uint8_t fileNameLen = 0;
946 uint8_t startblock = 0;
947 uint8_t endblock = 0;
948 uint8_t dataLen = 0;
949 bool use_credit_key = false;
950 bool elite = false;
951 bool rawkey = false;
952 bool errors = false;
953 uint8_t cmdp = 0;
954 while(param_getchar(Cmd, cmdp) != 0x00)
955 {
956 switch(param_getchar(Cmd, cmdp))
957 {
958 case 'h':
959 case 'H':
960 return usage_hf_iclass_clone();
961 case 'b':
962 case 'B':
963 if (param_gethex(Cmd, cmdp+1, &startblock, 2)) {
964 PrintAndLog("Start Block No must include 2 HEX symbols\n");
965 errors = true;
966 }
967 cmdp += 2;
968 break;
969 case 'c':
970 case 'C':
971 use_credit_key = true;
972 cmdp++;
973 break;
974 case 'e':
975 case 'E':
976 elite = true;
977 cmdp++;
978 break;
979 case 'f':
980 case 'F':
981 fileNameLen = param_getstr(Cmd, cmdp+1, filename);
982 if (fileNameLen < 1) {
983 PrintAndLog("No filename found after f");
984 errors = true;
985 }
986 cmdp += 2;
987 break;
988 case 'k':
989 case 'K':
990 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
991 if (dataLen == 16) {
992 errors = param_gethex(tempStr, 0, KEY, dataLen);
993 } else if (dataLen == 1) {
994 keyNbr = param_get8(Cmd, cmdp+1);
995 if (keyNbr < ICLASS_KEYS_MAX) {
996 memcpy(KEY, iClass_Key_Table[keyNbr], 8);
997 } else {
998 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
999 errors = true;
1000 }
1001 } else {
1002 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1003 errors = true;
1004 }
1005 cmdp += 2;
1006 break;
1007 case 'l':
1008 case 'L':
1009 if (param_gethex(Cmd, cmdp+1, &endblock, 2)) {
1010 PrintAndLog("Start Block No must include 2 HEX symbols\n");
1011 errors = true;
1012 }
1013 cmdp += 2;
1014 break;
1015 case 'r':
1016 case 'R':
1017 rawkey = true;
1018 cmdp++;
1019 break;
1020 default:
1021 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
1022 errors = true;
1023 break;
1024 }
1025 if(errors) return usage_hf_iclass_clone();
1026 }
1027
1028 if (cmdp < 8) return usage_hf_iclass_clone();
1029
1030 FILE *f;
1031
1032 iclass_block_t tag_data[USB_CMD_DATA_SIZE/12];
1033
1034 if ((endblock-startblock+1)*12 > USB_CMD_DATA_SIZE) {
1035 PrintAndLog("Trying to write too many blocks at once. Max: %d", USB_CMD_DATA_SIZE/8);
1036 }
1037 // file handling and reading
1038 f = fopen(filename,"rb");
1039 if(!f) {
1040 PrintAndLog("Failed to read from file '%s'", filename);
1041 return 1;
1042 }
1043
1044 if (startblock<5) {
1045 PrintAndLog("You cannot write key blocks this way. yet... make your start block > 4");
1046 return 0;
1047 }
1048 // now read data from the file from block 6 --- 19
1049 // ok we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
1050 // then copy to usbcommand->asbytes; the max is 32 - 6 = 24 block 12 bytes each block 288 bytes then we can only accept to clone 21 blocks at the time,
1051 // else we have to create a share memory
1052 int i;
1053 fseek(f,startblock*8,SEEK_SET);
1054 if ( fread(tag_data,sizeof(iclass_block_t),endblock - startblock + 1,f) == 0 ) {
1055 PrintAndLog("File reading error.");
1056 fclose(f);
1057 return 2;
1058 }
1059
1060 uint8_t MAC[4]={0x00,0x00,0x00,0x00};
1061 uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1062
1063 if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, true))
1064 return 0;
1065
1066 UsbCommand w = {CMD_ICLASS_CLONE,{startblock,endblock}};
1067 uint8_t *ptr;
1068 // calculate all mac for every the block we will write
1069 for (i = startblock; i <= endblock; i++){
1070 Calc_wb_mac(i,tag_data[i - startblock].d,div_key,MAC);
1071 // usb command d start pointer = d + (i - 6) * 12
1072 // memcpy(pointer,tag_data[i - 6],8) 8 bytes
1073 // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
1074 // next one
1075 ptr = w.d.asBytes + (i - startblock) * 12;
1076 memcpy(ptr, &(tag_data[i - startblock].d[0]), 8);
1077 memcpy(ptr + 8,MAC, 4);
1078 }
1079 uint8_t p[12];
1080 for (i = 0; i <= endblock - startblock;i++){
1081 memcpy(p,w.d.asBytes + (i * 12),12);
1082 printf("Block |%02x|",i + startblock);
1083 printf(" %02x%02x%02x%02x%02x%02x%02x%02x |",p[0],p[1],p[2],p[3],p[4],p[5],p[6],p[7]);
1084 printf(" MAC |%02x%02x%02x%02x|\n",p[8],p[9],p[10],p[11]);
1085 }
1086 UsbCommand resp;
1087 SendCommand(&w);
1088 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
1089 {
1090 PrintAndLog("Command execute timeout");
1091 return 0;
1092 }
1093 return 1;
1094}
1095
1096static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose) {
1097 uint8_t MAC[4]={0x00,0x00,0x00,0x00};
1098 uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1099
1100 if (!select_and_auth(KEY, MAC, div_key, (keyType==0x18), elite, rawkey, verbose))
1101 return 0;
1102
1103 UsbCommand resp;
1104 UsbCommand w = {CMD_ICLASS_READBLOCK, {blockno}};
1105 clearCommandBuffer();
1106 SendCommand(&w);
1107 if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
1108 {
1109 PrintAndLog("Command execute timeout");
1110 return 0;
1111 }
1112 uint8_t isOK = resp.arg[0] & 0xff;
1113 if (!isOK) {
1114 PrintAndLog("Read Block Failed");
1115 return 0;
1116 }
1117 //data read is stored in: resp.d.asBytes[0-15]
1118 if (verbose) PrintAndLog("Block %02X: %s\n",blockno, sprint_hex(resp.d.asBytes,8));
1119 return 1;
1120}
1121
1122int usage_hf_iclass_readblock(void) {
1123 PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> c e|r\n");
1124 PrintAndLog("Options:");
1125 PrintAndLog(" b <Block> : The block number as 2 hex symbols");
1126 PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
1127 PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
1128 PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
1129 PrintAndLog(" r : If 'r' is specified, no computations applied to key");
1130 PrintAndLog("Samples:");
1131 PrintAndLog(" hf iclass readblk b 06 k 0011223344556677");
1132 PrintAndLog(" hf iclass readblk b 1B k 0011223344556677 c");
1133 PrintAndLog(" hf iclass readblk b 0A k 0");
1134 return 0;
1135}
1136
1137int CmdHFiClass_ReadBlock(const char *Cmd) {
1138 uint8_t blockno=0;
1139 uint8_t keyType = 0x88; //debit key
1140 uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1141 uint8_t keyNbr = 0;
1142 uint8_t dataLen = 0;
1143 char tempStr[50] = {0};
1144 bool elite = false;
1145 bool rawkey = false;
1146 bool errors = false;
1147 uint8_t cmdp = 0;
1148 while(param_getchar(Cmd, cmdp) != 0x00)
1149 {
1150 switch(param_getchar(Cmd, cmdp))
1151 {
1152 case 'h':
1153 case 'H':
1154 return usage_hf_iclass_readblock();
1155 case 'b':
1156 case 'B':
1157 if (param_gethex(Cmd, cmdp+1, &blockno, 2)) {
1158 PrintAndLog("Block No must include 2 HEX symbols\n");
1159 errors = true;
1160 }
1161 cmdp += 2;
1162 break;
1163 case 'c':
1164 case 'C':
1165 keyType = 0x18;
1166 cmdp++;
1167 break;
1168 case 'e':
1169 case 'E':
1170 elite = true;
1171 cmdp++;
1172 break;
1173 case 'k':
1174 case 'K':
1175 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
1176 if (dataLen == 16) {
1177 errors = param_gethex(tempStr, 0, KEY, dataLen);
1178 } else if (dataLen == 1) {
1179 keyNbr = param_get8(Cmd, cmdp+1);
1180 if (keyNbr < ICLASS_KEYS_MAX) {
1181 memcpy(KEY, iClass_Key_Table[keyNbr], 8);
1182 } else {
1183 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1184 errors = true;
1185 }
1186 } else {
1187 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1188 errors = true;
1189 }
1190 cmdp += 2;
1191 break;
1192 case 'r':
1193 case 'R':
1194 rawkey = true;
1195 cmdp++;
1196 break;
1197 default:
1198 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
1199 errors = true;
1200 break;
1201 }
1202 if(errors) return usage_hf_iclass_readblock();
1203 }
1204
1205 if (cmdp < 4) return usage_hf_iclass_readblock();
1206
1207 return ReadBlock(KEY, blockno, keyType, elite, rawkey, true);
1208}
1209
1210int CmdHFiClass_loclass(const char *Cmd) {
1211 char opt = param_getchar(Cmd, 0);
1212
1213 if (strlen(Cmd)<1 || opt == 'h') {
1214 PrintAndLog("Usage: hf iclass loclass [options]");
1215 PrintAndLog("Options:");
1216 PrintAndLog("h Show this help");
1217 PrintAndLog("t Perform self-test");
1218 PrintAndLog("f <filename> Bruteforce iclass dumpfile");
1219 PrintAndLog(" An iclass dumpfile is assumed to consist of an arbitrary number of");
1220 PrintAndLog(" malicious CSNs, and their protocol responses");
1221 PrintAndLog(" The the binary format of the file is expected to be as follows: ");
1222 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1223 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1224 PrintAndLog(" <8 byte CSN><8 byte CC><4 byte NR><4 byte MAC>");
1225 PrintAndLog(" ... totalling N*24 bytes");
1226 return 0;
1227 }
1228 char fileName[255] = {0};
1229 if(opt == 'f')
1230 {
1231 if(param_getstr(Cmd, 1, fileName) > 0)
1232 {
1233 return bruteforceFileNoKeys(fileName);
1234 }else
1235 {
1236 PrintAndLog("You must specify a filename");
1237 }
1238 }
1239 else if(opt == 't')
1240 {
1241 int errors = testCipherUtils();
1242 errors += testMAC();
1243 errors += doKeyTests(0);
1244 errors += testElite();
1245 if(errors)
1246 {
1247 prnlog("OBS! There were errors!!!");
1248 }
1249 return errors;
1250 }
1251
1252 return 0;
1253}
1254
1255void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) {
1256 uint8_t blockdata[8];
1257 uint8_t mem_config;
1258 memcpy(&mem_config, iclass_dump + 13,1);
1259 uint8_t maxmemcount;
1260 uint8_t filemaxblock = filesize / 8;
1261 if (mem_config & 0x80)
1262 maxmemcount = 255;
1263 else
1264 maxmemcount = 31;
1265 //PrintAndLog ("endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d", endblock,filesize, maxmemcount, filemaxblock);
1266
1267 if (startblock == 0)
1268 startblock = 6;
1269 if ((endblock > maxmemcount) || (endblock == 0))
1270 endblock = maxmemcount;
1271 if (endblock > filemaxblock)
1272 endblock = filemaxblock;
1273 int i = startblock;
1274 int j;
1275 while (i <= endblock){
1276 printf("Block |%02X| ",i);
1277 memcpy(blockdata,iclass_dump + (i * 8),8);
1278 for (j = 0;j < 8;j++)
1279 printf("%02X ",blockdata[j]);
1280 printf("|\n");
1281 i++;
1282 }
1283}
1284
1285int usage_hf_iclass_readtagfile() {
1286 PrintAndLog("Usage: hf iclass readtagfile <filename> [startblock] [endblock]");
1287 return 1;
1288}
1289
1290int CmdHFiClassReadTagFile(const char *Cmd) {
1291 int startblock = 0;
1292 int endblock = 0;
1293 char tempnum[5];
1294 FILE *f;
1295 char filename[FILE_PATH_SIZE];
1296 if (param_getstr(Cmd, 0, filename) < 1)
1297 return usage_hf_iclass_readtagfile();
1298 if (param_getstr(Cmd,1,(char *)&tempnum) < 1)
1299 startblock = 0;
1300 else
1301 sscanf(tempnum,"%d",&startblock);
1302
1303 if (param_getstr(Cmd,2,(char *)&tempnum) < 1)
1304 endblock = 0;
1305 else
1306 sscanf(tempnum,"%d",&endblock);
1307 // file handling and reading
1308 f = fopen(filename,"rb");
1309 if(!f) {
1310 PrintAndLog("Failed to read from file '%s'", filename);
1311 return 1;
1312 }
1313 fseek(f, 0, SEEK_END);
1314 long fsize = ftell(f);
1315 fseek(f, 0, SEEK_SET);
1316
1317 if ( fsize < 0 ) {
1318 PrintAndLog("Error, when getting filesize");
1319 fclose(f);
1320 return 1;
1321 }
1322
1323 uint8_t *dump = malloc(fsize);
1324
1325 size_t bytes_read = fread(dump, 1, fsize, f);
1326 fclose(f);
1327 uint8_t *csn = dump;
1328 printf("CSN [00] | %02X %02X %02X %02X %02X %02X %02X %02X |\n",csn[0],csn[1],csn[2],csn[3],csn[4],csn[5],csn[6],csn[7]);
1329 // printIclassDumpInfo(dump);
1330 printIclassDumpContents(dump,startblock,endblock,bytes_read);
1331 free(dump);
1332 return 0;
1333}
1334
1335/*
1336uint64_t xorcheck(uint64_t sdiv,uint64_t hdiv) {
1337 uint64_t new_div = 0x00;
1338 new_div ^= sdiv;
1339 new_div ^= hdiv;
1340 return new_div;
1341}
1342
1343uint64_t hexarray_to_uint64(uint8_t *key) {
1344 char temp[17];
1345 uint64_t uint_key;
1346 for (int i = 0;i < 8;i++)
1347 sprintf(&temp[(i *2)],"%02X",key[i]);
1348 temp[16] = '\0';
1349 if (sscanf(temp,"%016"llX,&uint_key) < 1)
1350 return 0;
1351 return uint_key;
1352}
1353*/
1354void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite){
1355 uint8_t keytable[128] = {0};
1356 uint8_t key_index[8] = {0};
1357 if (elite) {
1358 uint8_t key_sel[8] = { 0 };
1359 uint8_t key_sel_p[8] = { 0 };
1360 hash2(KEY, keytable);
1361 hash1(CSN, key_index);
1362 for(uint8_t i = 0; i < 8 ; i++)
1363 key_sel[i] = keytable[key_index[i]] & 0xFF;
1364
1365 //Permute from iclass format to standard format
1366 permutekey_rev(key_sel, key_sel_p);
1367 diversifyKey(CSN, key_sel_p, div_key);
1368 } else {
1369 diversifyKey(CSN, KEY, div_key);
1370 }
1371}
1372
1373//when told CSN, oldkey, newkey, if new key is elite (elite), and if old key was elite (oldElite)
1374//calculate and return xor_div_key (ready for a key write command)
1375//print all div_keys if verbose
1376static void HFiClassCalcNewKey(uint8_t *CSN, uint8_t *OLDKEY, uint8_t *NEWKEY, uint8_t *xor_div_key, bool elite, bool oldElite, bool verbose){
1377 uint8_t old_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1378 uint8_t new_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1379 //get old div key
1380 HFiClassCalcDivKey(CSN, OLDKEY, old_div_key, oldElite);
1381 //get new div key
1382 HFiClassCalcDivKey(CSN, NEWKEY, new_div_key, elite);
1383
1384 for (uint8_t i = 0; i < sizeof(old_div_key); i++){
1385 xor_div_key[i] = old_div_key[i] ^ new_div_key[i];
1386 }
1387 if (verbose) {
1388 printf("Old Div Key : %s\n",sprint_hex(old_div_key,8));
1389 printf("New Div Key : %s\n",sprint_hex(new_div_key,8));
1390 printf("Xor Div Key : %s\n",sprint_hex(xor_div_key,8));
1391 }
1392}
1393
1394int usage_hf_iclass_calc_newkey(void) {
1395 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1396 PrintAndLog("Usage: hf iclass calc_newkey o <Old key> n <New key> s [csn] e");
1397 PrintAndLog(" Options:");
1398 PrintAndLog(" o <oldkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1399 PrintAndLog(" n <newkey> : *specify a key as 16 hex symbols or a key number as 1 symbol");
1400 PrintAndLog(" s <csn> : specify a card Serial number to diversify the key (if omitted will attempt to read a csn)");
1401 PrintAndLog(" e : specify new key as elite calc");
1402 PrintAndLog(" ee : specify old and new key as elite calc");
1403 PrintAndLog("Samples:");
1404 PrintAndLog(" e key to e key given csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899 s deadbeafdeadbeaf ee");
1405 PrintAndLog(" std key to e key read csn: hf iclass calcnewkey o 1122334455667788 n 2233445566778899 e");
1406 PrintAndLog(" std to std read csn : hf iclass calcnewkey o 1122334455667788 n 2233445566778899");
1407 PrintAndLog("NOTE: * = required\n");
1408
1409 return 1;
1410}
1411
1412int CmdHFiClassCalcNewKey(const char *Cmd) {
1413 uint8_t OLDKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1414 uint8_t NEWKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1415 uint8_t xor_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1416 uint8_t CSN[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1417 uint8_t CCNR[12] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
1418 uint8_t keyNbr = 0;
1419 uint8_t dataLen = 0;
1420 char tempStr[50] = {0};
1421 bool givenCSN = false;
1422 bool oldElite = false;
1423 bool elite = false;
1424 bool errors = false;
1425 uint8_t cmdp = 0;
1426 while(param_getchar(Cmd, cmdp) != 0x00)
1427 {
1428 switch(param_getchar(Cmd, cmdp))
1429 {
1430 case 'h':
1431 case 'H':
1432 return usage_hf_iclass_calc_newkey();
1433 case 'e':
1434 case 'E':
1435 dataLen = param_getstr(Cmd, cmdp, tempStr);
1436 if (dataLen==2)
1437 oldElite = true;
1438 elite = true;
1439 cmdp++;
1440 break;
1441 case 'n':
1442 case 'N':
1443 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
1444 if (dataLen == 16) {
1445 errors = param_gethex(tempStr, 0, NEWKEY, dataLen);
1446 } else if (dataLen == 1) {
1447 keyNbr = param_get8(Cmd, cmdp+1);
1448 if (keyNbr < ICLASS_KEYS_MAX) {
1449 memcpy(NEWKEY, iClass_Key_Table[keyNbr], 8);
1450 } else {
1451 PrintAndLog("\nERROR: NewKey Nbr is invalid\n");
1452 errors = true;
1453 }
1454 } else {
1455 PrintAndLog("\nERROR: NewKey is incorrect length\n");
1456 errors = true;
1457 }
1458 cmdp += 2;
1459 break;
1460 case 'o':
1461 case 'O':
1462 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
1463 if (dataLen == 16) {
1464 errors = param_gethex(tempStr, 0, OLDKEY, dataLen);
1465 } else if (dataLen == 1) {
1466 keyNbr = param_get8(Cmd, cmdp+1);
1467 if (keyNbr < ICLASS_KEYS_MAX) {
1468 memcpy(OLDKEY, iClass_Key_Table[keyNbr], 8);
1469 } else {
1470 PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
1471 errors = true;
1472 }
1473 } else {
1474 PrintAndLog("\nERROR: Credit Key is incorrect length\n");
1475 errors = true;
1476 }
1477 cmdp += 2;
1478 break;
1479 case 's':
1480 case 'S':
1481 givenCSN = true;
1482 if (param_gethex(Cmd, cmdp+1, CSN, 16))
1483 return usage_hf_iclass_calc_newkey();
1484 cmdp += 2;
1485 break;
1486 default:
1487 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
1488 errors = true;
1489 break;
1490 }
1491 if(errors) return usage_hf_iclass_calc_newkey();
1492 }
1493
1494 if (cmdp < 4) return usage_hf_iclass_calc_newkey();
1495
1496 if (!givenCSN)
1497 if (!select_only(CSN, CCNR, false, true))
1498 return 0;
1499
1500 HFiClassCalcNewKey(CSN, OLDKEY, NEWKEY, xor_div_key, elite, oldElite, true);
1501 return 0;
1502}
1503
1504static int loadKeys(char *filename) {
1505 FILE *f;
1506 f = fopen(filename,"rb");
1507 if(!f) {
1508 PrintAndLog("Failed to read from file '%s'", filename);
1509 return 0;
1510 }
1511 fseek(f, 0, SEEK_END);
1512 long fsize = ftell(f);
1513 fseek(f, 0, SEEK_SET);
1514
1515 if ( fsize < 0 ) {
1516 PrintAndLog("Error, when getting filesize");
1517 fclose(f);
1518 return 1;
1519 }
1520
1521 uint8_t *dump = malloc(fsize);
1522
1523 size_t bytes_read = fread(dump, 1, fsize, f);
1524 fclose(f);
1525 if (bytes_read > ICLASS_KEYS_MAX * 8){
1526 PrintAndLog("File is too long to load - bytes: %u", bytes_read);
1527 free(dump);
1528 return 0;
1529 }
1530 uint8_t i = 0;
1531 for (; i < bytes_read/8; i++){
1532 memcpy(iClass_Key_Table[i],dump+(i*8),8);
1533 }
1534 free(dump);
1535 PrintAndLog("%u keys loaded", i);
1536 return 1;
1537}
1538
1539static int saveKeys(char *filename) {
1540 FILE *f;
1541 f = fopen(filename,"wb");
1542 if (f == NULL) {
1543 printf("error opening file %s\n",filename);
1544 return 0;
1545 }
1546 for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++){
1547 if (fwrite(iClass_Key_Table[i],8,1,f) != 1){
1548 PrintAndLog("save key failed to write to file: %s", filename);
1549 break;
1550 }
1551 }
1552 fclose(f);
1553 return 0;
1554}
1555
1556static int printKeys(void) {
1557 PrintAndLog("");
1558 for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++){
1559 PrintAndLog("%u: %s",i,sprint_hex(iClass_Key_Table[i],8));
1560 }
1561 PrintAndLog("");
1562 return 0;
1563}
1564
1565int usage_hf_iclass_managekeys(void) {
1566 PrintAndLog("HELP : Manage iClass Keys in client memory:\n");
1567 PrintAndLog("Usage: hf iclass managekeys n [keynbr] k [key] f [filename] s l p\n");
1568 PrintAndLog(" Options:");
1569 PrintAndLog(" n <keynbr> : specify the keyNbr to set in memory");
1570 PrintAndLog(" k <key> : set a key in memory");
1571 PrintAndLog(" f <filename>: specify a filename to use with load or save operations");
1572 PrintAndLog(" s : save keys in memory to file specified by filename");
1573 PrintAndLog(" l : load keys to memory from file specified by filename");
1574 PrintAndLog(" p : print keys loaded into memory\n");
1575 PrintAndLog("Samples:");
1576 PrintAndLog(" set key : hf iclass managekeys n 0 k 1122334455667788");
1577 PrintAndLog(" save key file: hf iclass managekeys f mykeys.bin s");
1578 PrintAndLog(" load key file: hf iclass managekeys f mykeys.bin l");
1579 PrintAndLog(" print keys : hf iclass managekeys p\n");
1580 return 0;
1581}
1582
1583int CmdHFiClassManageKeys(const char *Cmd) {
1584 uint8_t keyNbr = 0;
1585 uint8_t dataLen = 0;
1586 uint8_t KEY[8] = {0};
1587 char filename[FILE_PATH_SIZE];
1588 uint8_t fileNameLen = 0;
1589 bool errors = false;
1590 uint8_t operation = 0;
1591 char tempStr[20];
1592 uint8_t cmdp = 0;
1593
1594 while(param_getchar(Cmd, cmdp) != 0x00)
1595 {
1596 switch(param_getchar(Cmd, cmdp))
1597 {
1598 case 'h':
1599 case 'H':
1600 return usage_hf_iclass_managekeys();
1601 case 'f':
1602 case 'F':
1603 fileNameLen = param_getstr(Cmd, cmdp+1, filename);
1604 if (fileNameLen < 1) {
1605 PrintAndLog("No filename found after f");
1606 errors = true;
1607 }
1608 cmdp += 2;
1609 break;
1610 case 'n':
1611 case 'N':
1612 keyNbr = param_get8(Cmd, cmdp+1);
1613 if (keyNbr >= ICLASS_KEYS_MAX) {
1614 PrintAndLog("Invalid block number");
1615 errors = true;
1616 }
1617 cmdp += 2;
1618 break;
1619 case 'k':
1620 case 'K':
1621 operation += 3; //set key
1622 dataLen = param_getstr(Cmd, cmdp+1, tempStr);
1623 if (dataLen == 16) { //ul-c or ev1/ntag key length
1624 errors = param_gethex(tempStr, 0, KEY, dataLen);
1625 } else {
1626 PrintAndLog("\nERROR: Key is incorrect length\n");
1627 errors = true;
1628 }
1629 cmdp += 2;
1630 break;
1631 case 'p':
1632 case 'P':
1633 operation += 4; //print keys in memory
1634 cmdp++;
1635 break;
1636 case 'l':
1637 case 'L':
1638 operation += 5; //load keys from file
1639 cmdp++;
1640 break;
1641 case 's':
1642 case 'S':
1643 operation += 6; //save keys to file
1644 cmdp++;
1645 break;
1646 default:
1647 PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
1648 errors = true;
1649 break;
1650 }
1651 if(errors) return usage_hf_iclass_managekeys();
1652 }
1653 if (operation == 0){
1654 PrintAndLog("no operation specified (load, save, or print)\n");
1655 return usage_hf_iclass_managekeys();
1656 }
1657 if (operation > 6){
1658 PrintAndLog("Too many operations specified\n");
1659 return usage_hf_iclass_managekeys();
1660 }
1661 if (operation > 4 && fileNameLen == 0){
1662 PrintAndLog("You must enter a filename when loading or saving\n");
1663 return usage_hf_iclass_managekeys();
1664 }
1665
1666 switch (operation){
1667 case 3: memcpy(iClass_Key_Table[keyNbr], KEY, 8); return 1;
1668 case 4: return printKeys();
1669 case 5: return loadKeys(filename);
1670 case 6: return saveKeys(filename);
1671 break;
1672 }
1673 return 0;
1674}
1675
1676static command_t CommandTable[] =
1677{
1678 {"help", CmdHelp, 1, "This help"},
1679 {"calcnewkey", CmdHFiClassCalcNewKey, 1, "[options..] Calc Diversified keys (blocks 3 & 4) to write new keys"},
1680 {"clone", CmdHFiClassCloneTag, 0, "[options..] Authenticate and Clone from iClass bin file"},
1681 {"decrypt", CmdHFiClassDecrypt, 1, "[f <fname>] Decrypt tagdump" },
1682 {"dump", CmdHFiClassReader_Dump, 0, "[options..] Authenticate and Dump iClass tag's AA1"},
1683 {"eload", CmdHFiClassELoad, 0, "[f <fname>] (experimental) Load data into iClass emulator memory"},
1684 {"encryptblk", CmdHFiClassEncryptBlk, 1, "<BlockData> Encrypt given block data"},
1685 {"list", CmdHFiClassList, 0, " (Deprecated) List iClass history"},
1686 {"loclass", CmdHFiClass_loclass, 1, "[options..] Use loclass to perform bruteforce of reader attack dump"},
1687 {"managekeys", CmdHFiClassManageKeys, 1, "[options..] Manage the keys to use with iClass"},
1688 {"readblk", CmdHFiClass_ReadBlock, 0, "[options..] Authenticate and Read iClass block"},
1689 {"reader", CmdHFiClassReader, 0, " Read an iClass tag"},
1690 {"readtagfile", CmdHFiClassReadTagFile, 1, "[options..] Display Content from tagfile"},
1691 {"replay", CmdHFiClassReader_Replay, 0, "<mac> Read an iClass tag via Reply Attack"},
1692 {"sim", CmdHFiClassSim, 0, "[options..] Simulate iClass tag"},
1693 {"snoop", CmdHFiClassSnoop, 0, " Eavesdrop iClass communication"},
1694 {"writeblk", CmdHFiClass_WriteBlock, 0, "[options..] Authenticate and Write iClass block"},
1695 {NULL, NULL, 0, NULL}
1696};
1697
1698int CmdHFiClass(const char *Cmd)
1699{
1700 CmdsParse(CommandTable, Cmd);
1701 return 0;
1702}
1703
1704int CmdHelp(const char *Cmd)
1705{
1706 CmdsHelp(CommandTable);
1707 return 0;
1708}
Impressum, Datenschutz