+
+ } else {
+ PrintAndLog("Undefined simtype %d", simType);
+ usage_hf_iclass_sim();
+ return 0;
+ }
+
+ return 0;
+}
+
+
+int HFiClassReader(bool loop, bool verbose) {
+
+ bool tagFound = false;
+ UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE | FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC | FLAG_ICLASS_READER_AA} };
+ UsbCommand resp;
+
+ while (!ukbhit()) {
+ SendCommand(&c);
+ if (WaitForResponseTimeout(CMD_ACK,&resp, 4500)) {
+ uint8_t readStatus = resp.arg[0] & 0xff;
+ uint8_t *data = resp.d.asBytes;
+
+ // no tag found
+ if (readStatus == 0 && !loop) {
+ // abort
+ if (verbose) PrintAndLog("Quitting...");
+ DropField();
+ return 0;
+ }
+
+ if (readStatus & FLAG_ICLASS_READER_CSN) {
+ PrintAndLog(" CSN: %s",sprint_hex(data,8));
+ tagFound = true;
+ }
+ if (readStatus & FLAG_ICLASS_READER_CC) {
+ PrintAndLog(" CC: %s",sprint_hex(data+16,8));
+ }
+ if (readStatus & FLAG_ICLASS_READER_CONF) {
+ printIclassDumpInfo(data);
+ }
+ if (readStatus & FLAG_ICLASS_READER_AA) {
+ bool legacy = true;
+ PrintAndLog(" AppIA: %s",sprint_hex(data+8*5,8));
+ for (int i = 0; i<8; i++) {
+ if (data[8*5+i] != 0xFF) {
+ legacy = false;
+ }
+ }
+ PrintAndLog(" : Possible iClass %s",(legacy) ? "(legacy tag)" : "(NOT legacy tag)");
+ }
+
+ if (tagFound && !loop) return 1;
+ } else {
+ if (verbose) PrintAndLog("Command execute timeout");
+ }
+ if (!loop) break;
+ }
+
+ DropField();
+ return 0;
+}
+
+
+static void usage_hf_iclass_reader(void) {
+ PrintAndLogEx(NORMAL, "Act as a Iclass reader. Look for iClass tags until Enter or the pm3 button is pressed\n");
+ PrintAndLogEx(NORMAL, "Usage: hf iclass reader [h] [1]\n");
+ PrintAndLogEx(NORMAL, "Options:");
+ PrintAndLogEx(NORMAL, " h This help text");
+ PrintAndLogEx(NORMAL, " 1 read only 1 tag");
+ PrintAndLogEx(NORMAL, "Examples:");
+ PrintAndLogEx(NORMAL, " hf iclass reader 1");
+}
+
+
+static int CmdHFiClassReader(const char *Cmd) {
+ char cmdp = tolower(param_getchar(Cmd, 0));
+ if (cmdp == 'h') {
+ usage_hf_iclass_reader();
+ return 0;
+ }
+ bool findone = (cmdp == '1') ? false : true;
+ return HFiClassReader(findone, true);
+}
+
+
+static void usage_hf_iclass_eload(void) {
+ PrintAndLog("Loads iclass tag-dump into emulator memory on device");
+ PrintAndLog("Usage: hf iclass eload f <filename>");
+ PrintAndLog("");
+ PrintAndLog("Example: hf iclass eload f iclass_tagdump-aa162d30f8ff12f1.bin");
+}
+
+
+static int CmdHFiClassELoad(const char *Cmd) {
+
+ char opt = param_getchar(Cmd, 0);
+ if (strlen(Cmd)<1 || opt == 'h') {
+ usage_hf_iclass_eload();
+ return 0;
+ }
+
+ //File handling and reading
+ FILE *f;
+ char filename[FILE_PATH_SIZE];
+ if (opt == 'f' && param_getstr(Cmd, 1, filename, sizeof(filename)) > 0) {
+ f = fopen(filename, "rb");
+ } else {
+ usage_hf_iclass_eload();
+ return 0;
+ }
+
+ if (!f) {
+ PrintAndLog("Failed to read from file '%s'", filename);
+ return 1;
+ }
+
+ fseek(f, 0, SEEK_END);
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ if (fsize < 0) {
+ PrintAndLog("Error, when getting filesize");
+ fclose(f);
+ return 1;
+ }
+
+ uint8_t *dump = malloc(fsize);
+
+ size_t bytes_read = fread(dump, 1, fsize, f);
+ fclose(f);
+
+ printIclassDumpInfo(dump);
+ //Validate
+
+ if (bytes_read < fsize) {
+ prnlog("Error, could only read %d bytes (should be %d)",bytes_read, fsize );
+ free(dump);
+ return 1;
+ }
+ //Send to device
+ uint32_t bytes_sent = 0;
+ uint32_t bytes_remaining = bytes_read;
+
+ while (bytes_remaining > 0) {
+ uint32_t bytes_in_packet = MIN(USB_CMD_DATA_SIZE, bytes_remaining);
+ UsbCommand c = {CMD_ICLASS_EML_MEMSET, {bytes_sent,bytes_in_packet,0}};
+ memcpy(c.d.asBytes, dump+bytes_sent, bytes_in_packet);
+ SendCommand(&c);
+ bytes_remaining -= bytes_in_packet;
+ bytes_sent += bytes_in_packet;
+ }
+ free(dump);
+ PrintAndLog("Sent %d bytes of data to device emulator memory", bytes_sent);
+ return 0;
+}
+
+
+static int readKeyfile(const char *filename, size_t len, uint8_t* buffer) {
+ FILE *f = fopen(filename, "rb");
+ if(!f) {
+ PrintAndLog("Failed to read from file '%s'", filename);
+ return 1;
+ }
+ fseek(f, 0, SEEK_END);
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ size_t bytes_read = fread(buffer, 1, len, f);
+ fclose(f);
+ if(fsize != len)
+ {
+ PrintAndLog("Warning, file size is %d, expected %d", fsize, len);
+ return 1;
+ }
+ if(bytes_read != len)
+ {
+ PrintAndLog("Warning, could only read %d bytes, expected %d" ,bytes_read, len);
+ return 1;
+ }
+ return 0;
+}
+
+
+static void usage_hf_iclass_decrypt(void) {
+ PrintAndLog("Usage: hf iclass decrypt f <tagdump>");
+ PrintAndLog("");
+ PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
+ PrintAndLog("in the working directory. The file should be 16 bytes binary data");
+ PrintAndLog("");
+ PrintAndLog("example: hf iclass decrypt f tagdump_12312342343.bin");
+ PrintAndLog("");
+ PrintAndLog("OBS! This is pretty stupid implementation, it tries to decrypt every block after block 6. ");
+ PrintAndLog("Correct behaviour would be to decrypt only the application areas where the key is valid,");
+ PrintAndLog("which is defined by the configuration block.");
+}
+
+
+static int CmdHFiClassDecrypt(const char *Cmd) {
+ uint8_t key[16] = { 0 };
+ if(readKeyfile("iclass_decryptionkey.bin", 16, key))
+ {
+ usage_hf_iclass_decrypt();
+ return 1;
+ }
+ PrintAndLog("Decryption file found... ");
+ char opt = param_getchar(Cmd, 0);
+ if (strlen(Cmd)<1 || opt == 'h') {
+ usage_hf_iclass_decrypt();
+ return 0;
+ }
+
+ //Open the tagdump-file
+ FILE *f;
+ char filename[FILE_PATH_SIZE];
+ if(opt == 'f' && param_getstr(Cmd, 1, filename, sizeof(filename)) > 0) {
+ f = fopen(filename, "rb");
+ if ( f == NULL ) {
+ PrintAndLog("Could not find file %s", filename);
+ return 1;
+ }
+ } else {
+ usage_hf_iclass_decrypt();
+ return 0;
+ }
+
+ fseek(f, 0, SEEK_END);
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+ uint8_t enc_dump[8] = {0};
+ uint8_t *decrypted = malloc(fsize);
+ mbedtls_des3_context ctx = { {0} };
+ mbedtls_des3_set2key_dec( &ctx, key);
+ size_t bytes_read = fread(enc_dump, 1, 8, f);
+
+ //Use the first block (CSN) for filename
+ char outfilename[FILE_PATH_SIZE] = { 0 };
+ snprintf(outfilename,FILE_PATH_SIZE,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x-decrypted",
+ enc_dump[0],enc_dump[1],enc_dump[2],enc_dump[3],
+ enc_dump[4],enc_dump[5],enc_dump[6],enc_dump[7]);
+
+ size_t blocknum =0;
+ while(bytes_read == 8)
+ {
+ if(blocknum < 7)
+ {
+ memcpy(decrypted+(blocknum*8), enc_dump, 8);
+ }else{
+ mbedtls_des3_crypt_ecb(&ctx, enc_dump,decrypted +(blocknum*8) );
+ }
+ printvar("decrypted block", decrypted +(blocknum*8), 8);
+ bytes_read = fread(enc_dump, 1, 8, f);
+ blocknum++;
+ }
+ fclose(f);
+
+ saveFile(outfilename,"bin", decrypted, blocknum*8);
+ free(decrypted);
+ return 0;
+}
+
+
+static void usage_hf_iclass_encrypt(void) {
+ PrintAndLog("Usage: hf iclass encrypt <BlockData>");
+ PrintAndLog("");
+ PrintAndLog("OBS! In order to use this function, the file 'iclass_decryptionkey.bin' must reside");
+ PrintAndLog("in the working directory. The file should be 16 bytes binary data");
+ PrintAndLog("");
+ PrintAndLog("example: hf iclass encrypt 0102030405060708");
+ PrintAndLog("");
+}
+
+
+static int iClassEncryptBlkData(uint8_t *blkData) {
+ uint8_t key[16] = { 0 };
+ if(readKeyfile("iclass_decryptionkey.bin", 16, key))
+ {
+ usage_hf_iclass_encrypt();
+ return 1;
+ }
+ PrintAndLog("Decryption file found... ");
+
+ uint8_t encryptedData[16];
+ uint8_t *encrypted = encryptedData;
+ mbedtls_des3_context ctx = { {0} };
+ mbedtls_des3_set2key_enc( &ctx, key);
+
+ mbedtls_des3_crypt_ecb(&ctx, blkData,encrypted);
+ //printvar("decrypted block", decrypted, 8);
+ memcpy(blkData,encrypted,8);
+
+ return 1;
+}
+
+
+static int CmdHFiClassEncryptBlk(const char *Cmd) {
+ uint8_t blkData[8] = {0};
+ char opt = param_getchar(Cmd, 0);
+ if (strlen(Cmd)<1 || opt == 'h') {
+ usage_hf_iclass_encrypt();
+ return 0;
+ }
+ //get the bytes to encrypt
+ if (param_gethex(Cmd, 0, blkData, 16)) {
+ PrintAndLog("BlockData must include 16 HEX symbols");
+ return 0;
+ }
+ if (!iClassEncryptBlkData(blkData)) return 0;
+ printvar("encrypted block", blkData, 8);
+ return 1;
+}
+
+
+static void Calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t MAC[4]) {
+ uint8_t WB[9];
+ WB[0] = blockno;
+ memcpy(WB+1, data, 8);
+ doMAC_N(WB, sizeof(WB), div_key, MAC);
+ //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]);
+}
+
+
+static bool iClass_select(uint8_t *CSN, bool verbose, bool cleartrace, bool init) {
+
+ UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_CSN}};
+ if (init) c.arg[0] |= FLAG_ICLASS_READER_INIT;
+ if (cleartrace) c.arg[0] |= FLAG_ICLASS_READER_CLEARTRACE;
+
+ UsbCommand resp;
+ clearCommandBuffer();
+ SendCommand(&c);
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
+ PrintAndLog("Command execute timeout");
+ return false;
+ }
+
+ uint8_t isOK = resp.arg[0] & 0xff;
+ uint8_t *data = resp.d.asBytes;
+
+ if (isOK & FLAG_ICLASS_READER_CSN) {
+ memcpy(CSN, data, 8);
+ if (verbose) PrintAndLog("CSN: %s", sprint_hex(CSN, 8));
+ } else {
+ PrintAndLog("Failed to select card! Aborting");
+ return false;
+ }
+ return true;
+}
+
+
+static void HFiClassCalcDivKey(uint8_t *CSN, uint8_t *KEY, uint8_t *div_key, bool elite){
+ uint8_t keytable[128] = {0};
+ uint8_t key_index[8] = {0};
+ if (elite) {
+ uint8_t key_sel[8] = { 0 };
+ uint8_t key_sel_p[8] = { 0 };
+ hash2(KEY, keytable);
+ hash1(CSN, key_index);
+ for(uint8_t i = 0; i < 8 ; i++)
+ key_sel[i] = keytable[key_index[i]] & 0xFF;
+
+ //Permute from iclass format to standard format
+ permutekey_rev(key_sel, key_sel_p);
+ diversifyKey(CSN, key_sel_p, div_key);
+ } else {
+ diversifyKey(CSN, KEY, div_key);
+ }
+}
+
+
+static bool iClass_authenticate(uint8_t *CSN, uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose) {
+
+ //get div_key
+ if (rawkey || replay)
+ memcpy(div_key, KEY, 8);
+ else
+ HFiClassCalcDivKey(CSN, KEY, div_key, elite);
+
+ char keytypetext[23] = "legacy diversified key";
+ if (rawkey) {
+ strcpy(keytypetext, "raw key");
+ } else if (replay) {
+ strcpy(keytypetext, "replayed NR/MAC");
+ } else if (elite) {
+ strcpy(keytypetext, "Elite diversified key");
+ }
+
+ if (verbose) PrintAndLog("Authenticating with %s: %s", keytypetext, sprint_hex(div_key, 8));
+
+ UsbCommand resp;
+ UsbCommand d = {CMD_ICLASS_READCHECK, {2, use_credit_key, 0}};
+
+ clearCommandBuffer();
+ SendCommand(&d);
+
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
+ if (verbose) PrintAndLog("Auth Command (READCHECK[2]) execute timeout");
+ return false;
+ }
+ bool isOK = resp.arg[0];
+ if (!isOK) {
+ if (verbose) PrintAndLog("Couldn't get Card Challenge");
+ return false;
+ }
+
+ if (replay) {
+ memcpy(MAC, KEY+4, 4);
+ } else {
+ uint8_t CCNR[12];
+ memcpy(CCNR, resp.d.asBytes, 8);
+ memset(CCNR+8, 0x00, 4); // default NR = {0, 0, 0, 0}
+ doMAC(CCNR, div_key, MAC);
+ }
+
+ d.cmd = CMD_ICLASS_CHECK;
+ if (replay) {
+ memcpy(d.d.asBytes, KEY, 8);
+ } else {
+ memset(d.d.asBytes, 0x00, 4); // default NR = {0, 0, 0, 0}
+ memcpy(d.d.asBytes+4, MAC, 4);
+ }
+ clearCommandBuffer();
+ SendCommand(&d);
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
+ if (verbose) PrintAndLog("Auth Command (CHECK) execute timeout");
+ return false;
+ }
+ isOK = resp.arg[0];
+ if (!isOK) {
+ if (verbose) PrintAndLog("Authentication error");
+ return false;
+ }
+ return true;
+}
+
+
+static void usage_hf_iclass_dump(void) {
+ PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r|n\n");
+ PrintAndLog("Options:");
+ PrintAndLog(" f <filename> : specify a filename to save dump to");
+ PrintAndLog(" k <Key> : *Debit Key (AA1) as 16 hex symbols (8 bytes) or 1 hex to select key from memory");
+ PrintAndLog(" c <CreditKey>: Credit Key (AA2) as 16 hex symbols (8 bytes) or 1 hex to select key from memory");
+ PrintAndLog(" e : If 'e' is specified, the keys are interpreted as Elite");
+ PrintAndLog(" Custom Keys (KCus), which can be obtained via reader-attack");
+ PrintAndLog(" See 'hf iclass sim 2'. This key should be on iclass-format");
+ PrintAndLog(" r : If 'r' is specified, keys are interpreted as raw blocks 3/4");
+ PrintAndLog(" n : If 'n' is specified, keys are interpreted as NR/MAC pairs which can be obtained by 'hf iclass snoop'");
+ PrintAndLog(" NOTE: * = required");
+ PrintAndLog("Samples:");
+ PrintAndLog(" hf iclass dump k 001122334455667B");
+ PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B");
+ PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA e");
+}
+
+
+static void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t endblock, size_t filesize) {
+ uint8_t mem_config;
+ memcpy(&mem_config, iclass_dump + 13,1);
+ uint8_t maxmemcount;
+ uint8_t filemaxblock = filesize / 8;
+ if (mem_config & 0x80)
+ maxmemcount = 255;
+ else
+ maxmemcount = 31;
+ //PrintAndLog ("endblock: %d, filesize: %d, maxmemcount: %d, filemaxblock: %d", endblock,filesize, maxmemcount, filemaxblock);
+
+ if (startblock == 0)
+ startblock = 6;
+ if ((endblock > maxmemcount) || (endblock == 0))
+ endblock = maxmemcount;
+
+ // remember endblock need to relate to zero-index arrays.
+ if (endblock > filemaxblock-1)
+ endblock = filemaxblock;
+
+ int i = startblock;
+ printf("------+--+-------------------------+\n");
+ while (i <= endblock) {
+ uint8_t *blk = iclass_dump + (i * 8);
+ printf("Block |%02X| %s|\n", i, sprint_hex(blk, 8) );
+ i++;
+ }
+ printf("------+--+-------------------------+\n");
+}
+
+
+static int CmdHFiClassReader_Dump(const char *Cmd) {
+
+ uint8_t MAC[4] = {0x00,0x00,0x00,0x00};
+ uint8_t div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t c_div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t blockno = 0;
+ uint8_t AA1_maxBlk = 0;
+ uint8_t maxBlk = 31;
+ uint8_t app_areas = 1;
+ uint8_t kb = 2;
+ uint8_t KEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t CreditKEY[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t keyNbr = 0;
+ uint8_t dataLen = 0;
+ uint8_t fileNameLen = 0;
+ char filename[FILE_PATH_SIZE]={0};
+ char tempStr[50] = {0};
+ bool have_debit_key = false;
+ bool have_credit_key = false;
+ bool use_credit_key = false;
+ bool elite = false;
+ bool rawkey = false;
+ bool NRMAC_replay = false;
+ bool errors = false;
+ bool verbose = false;
+ uint8_t cmdp = 0;
+
+ while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
+ switch(param_getchar(Cmd, cmdp)) {
+ case 'h':
+ case 'H':
+ usage_hf_iclass_dump();
+ return 0;
+ case 'c':
+ case 'C':
+ have_credit_key = true;
+ dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
+ if (dataLen == 16) {
+ errors = param_gethex(tempStr, 0, CreditKEY, dataLen);
+ } else if (dataLen == 1) {
+ keyNbr = param_get8(Cmd, cmdp+1);
+ if (keyNbr < ICLASS_KEYS_MAX) {
+ memcpy(CreditKEY, iClass_Key_Table[keyNbr], 8);
+ } else {
+ PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
+ errors = true;
+ }
+ } else {
+ PrintAndLog("\nERROR: Credit Key is incorrect length\n");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'e':
+ case 'E':
+ elite = true;
+ cmdp++;
+ break;
+ case 'f':
+ case 'F':
+ fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename));
+ if (fileNameLen < 1) {
+ PrintAndLog("No filename found after f");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'k':
+ case 'K':
+ have_debit_key = true;
+ dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
+ if (dataLen == 16) {
+ errors = param_gethex(tempStr, 0, KEY, dataLen);
+ } else if (dataLen == 1) {
+ keyNbr = param_get8(Cmd, cmdp+1);
+ if (keyNbr < ICLASS_KEYS_MAX) {
+ memcpy(KEY, iClass_Key_Table[keyNbr], 8);
+ } else {
+ PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
+ errors = true;
+ }
+ } else {
+ PrintAndLog("\nERROR: Credit Key is incorrect length\n");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'r':
+ case 'R':
+ rawkey = true;
+ cmdp++;
+ break;
+ case 'n':
+ case 'N':
+ NRMAC_replay = true;
+ cmdp++;
+ break;
+ case 'v':
+ case 'V':
+ verbose = true;
+ cmdp++;
+ break;
+ default:
+ PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
+ errors = true;
+ break;
+ }
+ }
+
+ if (elite + rawkey + NRMAC_replay > 1) {
+ PrintAndLog("You cannot combine the 'e', 'r', and 'n' options\n");
+ errors = true;
+ }
+
+ if (errors || cmdp < 2) {
+ usage_hf_iclass_dump();
+ return 0;
+ }
+
+ // if only credit key is given: try for AA1 as well (not for iclass but for some picopass this will work)
+ if (!have_debit_key && have_credit_key) {
+ use_credit_key = true;
+ memcpy(KEY, CreditKEY, 8);
+ }
+
+ // clear trace and get first 3 blocks
+ UsbCommand c = {CMD_READER_ICLASS, {FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE | FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC}};
+ UsbCommand resp;
+ uint8_t tag_data[256*8];
+
+ clearCommandBuffer();
+ SendCommand(&c);
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
+ PrintAndLog("Command execute timeout");
+ DropField();
+ return 0;
+ }
+
+ uint8_t readStatus = resp.arg[0] & 0xff;
+ uint8_t *data = resp.d.asBytes;
+ uint8_t status_mask = FLAG_ICLASS_READER_CSN | FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_CC;
+
+ if (readStatus != status_mask) {
+ PrintAndLog("No tag found ...");
+ return 0;
+ } else {
+ memcpy(tag_data, data, 8*3);
+ if (verbose) PrintAndLog("CSN: %s", sprint_hex(tag_data, 8));
+ AA1_maxBlk = data[8];
+ getMemConfig(data[13], data[12], &maxBlk, &app_areas, &kb);
+ // large memory - not able to dump pages currently
+ if (AA1_maxBlk > maxBlk) AA1_maxBlk = maxBlk;
+ }
+
+ // authenticate with debit key (or credit key if we have no debit key) and get div_key - later store in dump block 3
+ if (!iClass_authenticate(tag_data, KEY, MAC, div_key, use_credit_key, elite, rawkey, NRMAC_replay, verbose)){
+ DropField();
+ return 0;
+ }
+
+ // read AA1
+ UsbCommand w = {CMD_ICLASS_DUMP};
+ uint32_t blocksRead = 0;
+ for (blockno = 3; blockno <= AA1_maxBlk; blockno += blocksRead) {
+ w.arg[0] = blockno;
+ w.arg[1] = AA1_maxBlk - blockno + 1;
+ clearCommandBuffer();
+ SendCommand(&w);
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
+ PrintAndLog("Command execute time-out 1");
+ DropField();
+ return 1;
+ }
+ blocksRead = resp.arg[1];
+ bool isOK = resp.arg[0];
+ if (!isOK) {
+ PrintAndLog("Reading AA1 block failed");
+ DropField();
+ return 0;
+ }
+ memcpy(tag_data + blockno*8, resp.d.asBytes, blocksRead*8);
+ }
+
+ // do we still need to read more blocks (AA2 enabled)?
+ if (have_credit_key && maxBlk > AA1_maxBlk) {
+ if (!use_credit_key) {
+ //turn off hf field before authenticating with different key
+ DropField();
+ // AA2 authenticate credit key and git c_div_key - later store in dump block 4
+ uint8_t CSN[8];
+ if (!iClass_select(CSN, verbose, false, true) || !iClass_authenticate(CSN, CreditKEY, MAC, c_div_key, true, false, false, NRMAC_replay, verbose)){
+ DropField();
+ return 0;
+ }
+ }
+ for ( ; blockno <= maxBlk; blockno += blocksRead) {
+ w.arg[0] = blockno;
+ w.arg[1] = maxBlk - blockno + 1;
+ clearCommandBuffer();
+ SendCommand(&w);
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
+ PrintAndLog("Command execute time-out 1");
+ DropField();
+ return 1;
+ }
+ blocksRead = resp.arg[1];
+ bool isOK = resp.arg[0];
+ if (!isOK) {
+ PrintAndLog("Reading AA2 block failed");
+ DropField();
+ return 0;
+ }
+ memcpy(tag_data + blockno*8, resp.d.asBytes, blocksRead*8);
+ }
+ }
+
+ DropField();
+
+ // add diversified keys to dump
+ if (have_debit_key) {
+ memcpy(tag_data + 3*8, div_key, 8);
+ } else {
+ memset(tag_data + 3*8, 0xff, 8);
+ }
+ if (have_credit_key) {
+ memcpy(tag_data + 4*8, c_div_key, 8);
+ } else {
+ memset(tag_data + 4*8, 0xff, 8);
+ }
+
+ // print the dump
+ printf("------+--+-------------------------+\n");
+ printf("CSN |00| %s|\n",sprint_hex(tag_data, 8));
+ printIclassDumpContents(tag_data, 1, blockno-1, blockno*8);
+
+ if (filename[0] == 0) {
+ snprintf(filename, FILE_PATH_SIZE,"iclass_tagdump-%02x%02x%02x%02x%02x%02x%02x%02x",
+ tag_data[0],tag_data[1],tag_data[2],tag_data[3],
+ tag_data[4],tag_data[5],tag_data[6],tag_data[7]);
+ }
+
+ // save the dump to .bin file
+ PrintAndLog("Saving dump file - %d blocks read", blockno);
+ saveFile(filename, "bin", tag_data, blockno*8);
+ return 1;
+}
+
+
+static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool NRMAC_replay, bool verbose) {
+
+ uint8_t MAC[4] = {0x00,0x00,0x00,0x00};
+ uint8_t div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t CSN[8];
+
+ if (!iClass_select(CSN, verbose, true, true) || !iClass_authenticate(CSN, KEY, MAC, div_key, use_credit_key, elite, rawkey, NRMAC_replay, verbose)) {
+ DropField();
+ return 0;
+ }
+
+ UsbCommand resp;
+
+ Calc_wb_mac(blockno, bldata, div_key, MAC);
+
+ UsbCommand w = {CMD_ICLASS_WRITEBLOCK, {blockno}};
+ memcpy(w.d.asBytes, bldata, 8);
+ memcpy(w.d.asBytes + 8, MAC, 4);
+
+ clearCommandBuffer();
+ SendCommand(&w);
+ if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
+ PrintAndLog("Write Command execute timeout");
+ DropField();
+ return 0;
+ }
+ bool isOK = resp.arg[0];
+ if (!isOK) {
+ PrintAndLog("Write Block Failed");
+ DropField();
+ return 0;
+ }
+
+ PrintAndLog("Write Block Successful");
+ return 1;
+}
+
+
+static void usage_hf_iclass_writeblock(void) {
+ PrintAndLog("Options:");
+ PrintAndLog(" b <Block> : The block number as 2 hex symbols");
+ PrintAndLog(" d <data> : Set the Data to write as 16 hex symbols");
+ PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
+ PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
+ PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
+ PrintAndLog(" r : If 'r' is specified, no computations applied to key");
+ PrintAndLog("Samples:");
+ PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA k 001122334455667B");
+ PrintAndLog(" hf iclass writeblk b 1B d AAAAAAAAAAAAAAAA k 001122334455667B c");
+ PrintAndLog(" hf iclass writeblk b 0A d AAAAAAAAAAAAAAAA n 0");
+}
+
+
+static int CmdHFiClass_WriteBlock(const char *Cmd) {
+ uint8_t blockno=0;
+ uint8_t bldata[8]={0,0,0,0,0,0,0,0};
+ uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t keyNbr = 0;
+ uint8_t dataLen = 0;
+ char tempStr[50] = {0};
+ bool use_credit_key = false;
+ bool elite = false;
+ bool rawkey = false;
+ bool errors = false;
+ uint8_t cmdp = 0;
+
+ while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
+ switch(param_getchar(Cmd, cmdp)) {
+ case 'h':
+ case 'H':
+ usage_hf_iclass_writeblock();
+ return 0;
+ case 'b':
+ case 'B':
+ if (param_gethex(Cmd, cmdp+1, &blockno, 2)) {
+ PrintAndLog("Block No must include 2 HEX symbols\n");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'c':
+ case 'C':
+ use_credit_key = true;
+ cmdp++;
+ break;
+ case 'd':
+ case 'D':
+ if (param_gethex(Cmd, cmdp+1, bldata, 16)) {
+ PrintAndLog("Data must include 16 HEX symbols\n");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'e':
+ case 'E':
+ elite = true;
+ cmdp++;
+ break;
+ case 'k':
+ case 'K':
+ dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
+ if (dataLen == 16) {
+ errors = param_gethex(tempStr, 0, KEY, dataLen);
+ } else if (dataLen == 1) {
+ keyNbr = param_get8(Cmd, cmdp+1);
+ if (keyNbr < ICLASS_KEYS_MAX) {
+ memcpy(KEY, iClass_Key_Table[keyNbr], 8);
+ } else {
+ PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
+ errors = true;
+ }
+ } else {
+ PrintAndLog("\nERROR: Credit Key is incorrect length\n");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'r':
+ case 'R':
+ rawkey = true;
+ cmdp++;
+ break;
+ default:
+ PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
+ errors = true;
+ break;
+ }
+ if (errors) {
+ usage_hf_iclass_writeblock();
+ return 0;
+ }
+ }
+
+ if (elite && rawkey) {
+ PrintAndLog("You cannot combine the 'e' and 'r' options\n");
+ errors = true;
+ }
+
+ if (cmdp < 6) {
+ usage_hf_iclass_writeblock();
+ return 0;
+ }
+ int ans = WriteBlock(blockno, bldata, KEY, use_credit_key, elite, rawkey, false, true);
+ DropField();
+ return ans;
+}
+
+
+static void usage_hf_iclass_clone(void) {
+ PrintAndLog("Usage: hf iclass clone f <tagfile.bin> b <first block> l <last block> k <KEY> c e|r");
+ PrintAndLog("Options:");
+ PrintAndLog(" f <filename>: specify a filename to clone from");
+ PrintAndLog(" b <Block> : The first block to clone as 2 hex symbols");
+ PrintAndLog(" l <Last Blk>: Set the Data to write as 16 hex symbols");
+ PrintAndLog(" k <Key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
+ PrintAndLog(" c : If 'c' is specified, the key set is assumed to be the credit key\n");
+ PrintAndLog(" e : If 'e' is specified, elite computations applied to key");
+ PrintAndLog(" r : If 'r' is specified, no computations applied to key");
+ PrintAndLog("Samples:");
+ PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 1A k 1122334455667788 e");
+ PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 05 l 19 k 0");
+ PrintAndLog(" hf iclass clone f iclass_tagdump-121345.bin b 06 l 19 k 0 e");
+}
+
+
+static int CmdHFiClassCloneTag(const char *Cmd) {
+ char filename[FILE_PATH_SIZE] = {0};
+ char tempStr[50]={0};
+ uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t keyNbr = 0;
+ uint8_t fileNameLen = 0;
+ uint8_t startblock = 0;
+ uint8_t endblock = 0;
+ uint8_t dataLen = 0;
+ bool use_credit_key = false;
+ bool elite = false;
+ bool rawkey = false;
+ bool errors = false;
+ uint8_t cmdp = 0;
+
+ while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
+ switch(param_getchar(Cmd, cmdp)) {
+ case 'h':
+ case 'H':
+ usage_hf_iclass_clone();
+ return 0;
+ case 'b':
+ case 'B':
+ if (param_gethex(Cmd, cmdp+1, &startblock, 2)) {
+ PrintAndLog("Start Block No must include 2 HEX symbols\n");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'c':
+ case 'C':
+ use_credit_key = true;
+ cmdp++;
+ break;
+ case 'e':
+ case 'E':
+ elite = true;
+ cmdp++;
+ break;
+ case 'f':
+ case 'F':
+ fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename));
+ if (fileNameLen < 1) {
+ PrintAndLog("No filename found after f");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'k':
+ case 'K':
+ dataLen = param_getstr(Cmd, cmdp+1, tempStr, sizeof(tempStr));
+ if (dataLen == 16) {
+ errors = param_gethex(tempStr, 0, KEY, dataLen);
+ } else if (dataLen == 1) {
+ keyNbr = param_get8(Cmd, cmdp+1);
+ if (keyNbr < ICLASS_KEYS_MAX) {
+ memcpy(KEY, iClass_Key_Table[keyNbr], 8);
+ } else {
+ PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
+ errors = true;
+ }
+ } else {
+ PrintAndLog("\nERROR: Credit Key is incorrect length\n");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'l':
+ case 'L':
+ if (param_gethex(Cmd, cmdp+1, &endblock, 2)) {
+ PrintAndLog("Start Block No must include 2 HEX symbols\n");
+ errors = true;
+ }
+ cmdp += 2;
+ break;
+ case 'r':
+ case 'R':
+ rawkey = true;
+ cmdp++;
+ break;
+ default:
+ PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
+ errors = true;
+ break;
+ }
+ if (errors) {
+ usage_hf_iclass_clone();
+ return 0;
+ }
+ }
+
+ if (cmdp < 8) {
+ usage_hf_iclass_clone();
+ return 0;
+ }
+
+ FILE *f;
+
+ iclass_block_t tag_data[USB_CMD_DATA_SIZE/12];
+
+ if ((endblock-startblock+1)*12 > USB_CMD_DATA_SIZE) {
+ PrintAndLog("Trying to write too many blocks at once. Max: %d", USB_CMD_DATA_SIZE/8);
+ }
+ // file handling and reading
+ f = fopen(filename,"rb");
+ if (!f) {
+ PrintAndLog("Failed to read from file '%s'", filename);
+ return 1;
+ }
+
+ if (startblock<5) {
+ PrintAndLog("You cannot write key blocks this way. yet... make your start block > 4");
+ fclose(f);
+ return 0;
+ }
+ // now read data from the file from block 6 --- 19
+ // ok we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data
+ // 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,
+ // else we have to create a share memory
+ int i;
+ fseek(f, startblock*8, SEEK_SET);
+ if (fread(tag_data, sizeof(iclass_block_t), endblock - startblock + 1, f) == 0 ) {
+ PrintAndLog("File reading error.");
+ fclose(f);
+ return 2;
+ }
+
+ uint8_t MAC[4]={0x00,0x00,0x00,0x00};
+ uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t CSN[8];
+
+ if (!iClass_select(CSN, true, false, false) || !iClass_authenticate(CSN, KEY, MAC, div_key, use_credit_key, elite, rawkey, false, true)) {
+ DropField();
+ return 0;
+ }
+
+ UsbCommand w = {CMD_ICLASS_CLONE, {startblock, endblock}};
+ uint8_t *ptr;
+ // calculate all mac for every the block we will write
+ for (i = startblock; i <= endblock; i++){
+ Calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC);
+ // usb command d start pointer = d + (i - 6) * 12
+ // memcpy(pointer,tag_data[i - 6],8) 8 bytes
+ // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes;
+ // next one
+ ptr = w.d.asBytes + (i - startblock) * 12;
+ memcpy(ptr, &(tag_data[i - startblock].d[0]), 8);
+ memcpy(ptr + 8,MAC, 4);
+ }
+ uint8_t p[12];
+ for (i = 0; i <= endblock - startblock;i++){
+ memcpy(p,w.d.asBytes + (i * 12),12);
+ printf("Block |%02x|",i + startblock);
+ 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]);
+ printf(" MAC |%02x%02x%02x%02x|\n",p[8],p[9],p[10],p[11]);
+ }
+
+ UsbCommand resp;
+ SendCommand(&w);
+ if (!WaitForResponseTimeout(CMD_ACK,&resp,4500))
+ {
+ PrintAndLog("Command execute timeout");
+ DropField();
+ return 0;
+ }
+ return 1;
+}
+
+
+static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool NRMAC_replay, bool verbose, bool auth) {
+
+ uint8_t MAC[4]={0x00,0x00,0x00,0x00};
+ uint8_t div_key[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+ uint8_t CSN[8];
+
+ if (!iClass_select(CSN, verbose, true, true)) {
+ DropField();
+ return 0;
+ }
+
+ if (auth) {
+ if (!iClass_authenticate(CSN, KEY, MAC, div_key, (keyType==0x18), elite, rawkey, NRMAC_replay, verbose)) {
+ DropField();
+ return 0;
+ }