+int CmdHF14AMfNested(const char *Cmd)
+{
+ int i, j, res, iterations;
+ sector * e_sector = NULL;
+ uint8_t blockNo = 0;
+ uint8_t keyType = 0;
+ uint8_t trgBlockNo = 0;
+ uint8_t trgKeyType = 0;
+ uint8_t blDiff = 0;
+ int SectorsCnt = 0;
+ uint8_t key[6] = {0, 0, 0, 0, 0, 0};
+ uint8_t keyBlock[16 * 6];
+ uint64_t key64 = 0;
+
+ char cmdp, ctmp;
+
+ if (strlen(Cmd)<3) {
+ PrintAndLog("Usage:");
+ PrintAndLog(" all sectors: hf 14a nested <card memory> <block number> <key A/B> <key (12 hex symbols)>");
+ PrintAndLog(" one sector: hf 14a nested o <block number> <key A/B> <key (12 hex symbols)>");
+ PrintAndLog(" <target block number> <target key A/B>");
+ PrintAndLog("card memory - 1 - 1K, 2 - 2K, 4 - 4K, <other> - 1K");
+ PrintAndLog(" ");
+ PrintAndLog(" sample1: hf 14a nested 1 0 A FFFFFFFFFFFF ");
+ PrintAndLog(" sample2: hf 14a nested o 0 A FFFFFFFFFFFF 4 A");
+ return 0;
+ }
+
+ cmdp = param_getchar(Cmd, 0);
+ blockNo = param_get8(Cmd, 1);
+ ctmp = param_getchar(Cmd, 2);
+ if (ctmp == 0x00) {
+ PrintAndLog("Key type must be A or B");
+ return 1;
+ }
+ if (ctmp != 'A' && ctmp != 'a') keyType = 1;
+ if (param_gethex(Cmd, 3, key, 12)) {
+ PrintAndLog("Key must include 12 HEX symbols");
+ return 1;
+ }
+
+ if (cmdp =='o' || cmdp == 'O') {
+ cmdp = 'o';
+ trgBlockNo = param_get8(Cmd, 4);
+ ctmp = param_getchar(Cmd, 5);
+ if (ctmp == 0x00) {
+ PrintAndLog("Target key type must be A or B");
+ return 1;
+ }
+ if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1;
+ } else {
+ switch (cmdp) {
+ case '1': SectorsCnt = 16; break;
+ case '2': SectorsCnt = 32; break;
+ case '4': SectorsCnt = 64; break;
+ default: SectorsCnt = 16;
+ }
+ }
+
+ PrintAndLog("--block no:%02x key type:%02x key:%s ", blockNo, keyType, sprint_hex(key, 6));
+ if (cmdp == 'o')
+ PrintAndLog("--target block no:%02x target key type:%02x ", trgBlockNo, trgKeyType);
+
+ if (cmdp == 'o') {
+ if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) {
+ PrintAndLog("Nested error.");
+ return 2;
+ }
+
+ for (i = 0; i < 16; i++) {
+ PrintAndLog("cnt=%d key= %s", i, sprint_hex(keyBlock + i * 6, 6));
+ }
+
+ // test keys
+ res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64);
+ if (res)
+ res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64);
+ if (!res)
+ PrintAndLog("Found valid key:%012llx", key64);
+ else
+ PrintAndLog("No valid key found");
+ } else // ------------------------------------ multiple sectors working
+ {
+ blDiff = blockNo % 4;
+ PrintAndLog("Block shift=%d", blDiff);
+ e_sector = calloc(SectorsCnt, sizeof(sector));
+ if (e_sector == NULL) return 1;
+
+ //test current key 4 sectors
+ memcpy(keyBlock, key, 6);
+ num_to_bytes(0xa0a1a2a3a4a5, 6, (uint8_t*)(keyBlock + 1 * 6));
+ num_to_bytes(0xb0b1b2b3b4b5, 6, (uint8_t*)(keyBlock + 2 * 6));
+ num_to_bytes(0xffffffffffff, 6, (uint8_t*)(keyBlock + 3 * 6));
+ num_to_bytes(0x000000000000, 6, (uint8_t*)(keyBlock + 4 * 6));
+ num_to_bytes(0xaabbccddeeff, 6, (uint8_t*)(keyBlock + 5 * 6));
+
+ PrintAndLog("Testing known keys. Sector count=%d", SectorsCnt);
+ for (i = 0; i < SectorsCnt; i++) {
+ for (j = 0; j < 2; j++) {
+ if (e_sector[i].foundKey[j]) continue;
+
+ res = mfCheckKeys(i * 4 + blDiff, j, 6, keyBlock, &key64);
+
+ if (!res) {
+ e_sector[i].Key[j] = key64;
+ e_sector[i].foundKey[j] = 1;
+ }
+ }
+ }
+
+
+ // nested sectors
+ iterations = 0;
+ PrintAndLog("nested...");
+ for (i = 0; i < NESTED_SECTOR_RETRY; i++) {
+ for (trgBlockNo = blDiff; trgBlockNo < SectorsCnt * 4; trgBlockNo = trgBlockNo + 4)
+ for (trgKeyType = 0; trgKeyType < 2; trgKeyType++) {
+ if (e_sector[trgBlockNo / 4].foundKey[trgKeyType]) continue;
+ if (mfnested(blockNo, keyType, key, trgBlockNo, trgKeyType, keyBlock)) continue;
+
+ iterations++;
+
+ //try keys from nested
+ res = mfCheckKeys(trgBlockNo, trgKeyType, 8, keyBlock, &key64);
+ if (res)
+ res = mfCheckKeys(trgBlockNo, trgKeyType, 8, &keyBlock[6 * 8], &key64);
+ if (!res) {
+ PrintAndLog("Found valid key:%012llx", key64);
+ e_sector[trgBlockNo / 4].foundKey[trgKeyType] = 1;
+ e_sector[trgBlockNo / 4].Key[trgKeyType] = key64;
+ }
+ }
+ }
+
+ PrintAndLog("Iterations count: %d", iterations);
+ //print them
+ PrintAndLog("|---|----------------|---|----------------|---|");
+ PrintAndLog("|blk|key A |res|key B |res|");
+ PrintAndLog("|---|----------------|---|----------------|---|");
+ for (i = 0; i < SectorsCnt; i++) {
+ PrintAndLog("|%03d| %012llx | %d | %012llx | %d |", i,
+ e_sector[i].Key[0], e_sector[i].foundKey[0], e_sector[i].Key[1], e_sector[i].foundKey[1]);
+ }
+ PrintAndLog("|---|----------------|---|----------------|---|");
+
+ free(e_sector);
+ }
+
+ return 0;
+}
+
+int CmdHF14AMfChk(const char *Cmd)
+{
+ int i, res;
+ int keycnt = 0;
+ char ctmp = 0x00;
+ uint8_t blockNo = 0;
+ uint8_t keyType = 0;
+ uint8_t keyBlock[8 * 6];
+ uint64_t key64 = 0;
+
+ memset(keyBlock, 0x00, sizeof(keyBlock));
+
+ if (strlen(Cmd)<3) {
+ PrintAndLog("Usage: hf 14a chk <block number> <key A/B> [<key (12 hex symbols)>]");
+ PrintAndLog(" sample: hf 14a chk 0 A FFFFFFFFFFFF a0a1a2a3a4a5 b01b2b3b4b5 ");
+ return 0;
+ }
+
+ blockNo = param_get8(Cmd, 0);
+ ctmp = param_getchar(Cmd, 1);
+ if (ctmp == 0x00) {
+ PrintAndLog("Key type must be A or B");
+ return 1;
+ }
+ if (ctmp != 'A' && ctmp != 'a') keyType = 1;
+
+ for (i = 0; i < 6; i++) {
+ if (!isxdigit(param_getchar(Cmd, 2 + i))) break;
+
+ if (param_gethex(Cmd, 2 + i, keyBlock + 6 * i, 12)) {
+ PrintAndLog("Key[%d] must include 12 HEX symbols", i);
+ return 1;
+ }
+ keycnt = i + 1;
+ }
+
+ if (keycnt == 0) {
+ PrintAndLog("There is must be at least one key");
+ return 1;
+ }
+
+ PrintAndLog("--block no:%02x key type:%02x key count:%d ", blockNo, keyType, keycnt);
+
+ res = mfCheckKeys(blockNo, keyType, keycnt, keyBlock, &key64);
+ if (res !=1) {
+ if (!res)
+ PrintAndLog("isOk:%02x valid key:%012llx", 1, key64);
+ else
+ PrintAndLog("isOk:%02x", 0);
+ } else {
+ PrintAndLog("Command execute timeout");
+ }
+
+ return 0;
+}
+
+int CmdHF14AMf1kSim(const char *Cmd)
+{
+ int i, temp;
+ uint8_t uid[4] = {0, 0, 0, 0};
+
+ const char *cmdp = Cmd;
+
+
+ if (strlen(Cmd)<3) {
+ PrintAndLog("Usage: hf 14a mfsim <uid (8 hex symbols)>");
+ PrintAndLog(" sample: hf 14a mfsim 0a0a0a0a ");
+ return 0;
+ }
+
+ // skip spaces
+ while (*cmdp==' ' || *cmdp=='\t') cmdp++;
+
+ if (strlen(cmdp) != 8) {
+ PrintAndLog("Length of UID must be 8 hex symbols");
+ return 0;
+ }
+
+ for(i = 0; i < 4; i++) {
+ sscanf((char[]){cmdp[0],cmdp[1],0},"%X",&temp);
+ uid[i] = temp & 0xff;
+ cmdp++;
+ cmdp++;
+ }
+ PrintAndLog(" uid:%s ", sprint_hex(uid, 4));
+
+ UsbCommand c = {CMD_SIMULATE_MIFARE_CARD, {0, 0, 0}};
+ memcpy(c.d.asBytes, uid, 6);
+ SendCommand(&c);
+
+ return 0;
+}
+
+
+int CmdHF14AReader(const char *Cmd)
+{
+ UsbCommand c = {CMD_READER_ISO_14443a, {ISO14A_CONNECT, 0, 0}};
+ SendCommand(&c);
+ UsbCommand * resp = WaitForResponse(CMD_ACK);
+ uint8_t * uid = resp->d.asBytes;
+ iso14a_card_select_t * card = uid + 12;
+
+ if(resp->arg[0] == 0) {
+ PrintAndLog("iso14443a card select failed");
+ return 0;
+ }
+
+ PrintAndLog("ATQA : %02x %02x", card->atqa[0], card->atqa[1]);
+ PrintAndLog(" UID : %s", sprint_hex(uid, 12));
+ PrintAndLog(" SAK : %02x [%d]", card->sak, resp->arg[0]);
+ if(resp->arg[0] == 1)
+ PrintAndLog(" ATS : %s", sprint_hex(card->ats, card->ats_len));
+ else
+ PrintAndLog("proprietary non-iso14443a card found, RATS not supported");
+
+ return resp->arg[0];
+}
+