mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-03-17 18:50:32 +08:00
chg: tried making the reselect more stable.
chg: 'hf iclass readblk' chg: 'hf iclass writeblk' chg: 'hf iclass dump' chg: 'hf iclass clone' all commands now has 'v' verbose parameter for more detailed output.
This commit is contained in:
parent
6a9ddf6e69
commit
6605d92fbb
2 changed files with 160 additions and 125 deletions
|
@ -1819,13 +1819,22 @@ void setupIclassReader() {
|
|||
}
|
||||
|
||||
bool sendCmdGetResponseWithRetries(uint8_t* command, size_t cmdsize, uint8_t* resp, uint8_t expected_size, uint8_t retries) {
|
||||
uint8_t got_n = 0;
|
||||
while (retries-- > 0) {
|
||||
|
||||
ReaderTransmitIClass(command, cmdsize);
|
||||
|
||||
//iceman - if received size is bigger than expected, we smash the stack here
|
||||
// since its called with fixed sized arrays
|
||||
if (expected_size == ReaderReceiveIClass(resp))
|
||||
got_n = ReaderReceiveIClass(resp);
|
||||
|
||||
// 0xBB is the internal debug separator byte..
|
||||
if ( expected_size != got_n|| (resp[0] == 0xBB || resp[7] == 0xBB || resp[2] == 0xBB)) {
|
||||
//try again
|
||||
continue;
|
||||
}
|
||||
|
||||
if (got_n == expected_size)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -1854,8 +1863,7 @@ uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) {
|
|||
|
||||
// Send act_all
|
||||
ReaderTransmitIClass_ext(act_all, 1, 330+160);
|
||||
|
||||
// Card present?
|
||||
// Card present?
|
||||
if (!ReaderReceiveIClass(resp)) return read_status;//Fail
|
||||
|
||||
//Send Identify
|
||||
|
@ -1872,7 +1880,7 @@ uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) {
|
|||
ReaderTransmitIClass(select, sizeof(select));
|
||||
|
||||
//We expect a 10-byte response here, 8 byte CSN and 2 byte CRC
|
||||
len = ReaderReceiveIClass(resp);
|
||||
len = ReaderReceiveIClass(resp);
|
||||
if (len != 10) return read_status;//Fail
|
||||
|
||||
//Success - level 1, we got CSN
|
||||
|
@ -1883,13 +1891,18 @@ uint8_t handshakeIclassTag_ext(uint8_t *card_data, bool use_credit_key) {
|
|||
read_status = 1;
|
||||
|
||||
// Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
|
||||
ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
|
||||
if (ReaderReceiveIClass(resp) == 8) {
|
||||
//Save CC (e-purse) in response data
|
||||
memcpy(card_data+8, resp, 8);
|
||||
read_status++;
|
||||
}
|
||||
|
||||
// ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc));
|
||||
// if (ReaderReceiveIClass(resp) == 8) {
|
||||
// //Save CC (e-purse) in response data
|
||||
// memcpy(card_data+8, resp, 8);
|
||||
// read_status++;
|
||||
// }
|
||||
bool isOK = sendCmdGetResponseWithRetries(readcheck_cc, sizeof(readcheck_cc), resp, 8, 3);
|
||||
if (!isOK) return read_status;
|
||||
|
||||
//Save CC (e-purse) in response data
|
||||
memcpy(card_data+8, resp, 8);
|
||||
read_status++;
|
||||
return read_status;
|
||||
}
|
||||
uint8_t handshakeIclassTag(uint8_t *card_data){
|
||||
|
@ -2279,22 +2292,23 @@ out:
|
|||
}
|
||||
|
||||
// Tries to read block.
|
||||
// retries 5times.
|
||||
// retries 10times.
|
||||
bool iClass_ReadBlock(uint8_t blockNo, uint8_t *data, uint8_t len) {
|
||||
//uint8_t resp[] = BigBuf_malloc(len);
|
||||
uint8_t resp[20];
|
||||
uint8_t cmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockNo, 0x00, 0x00}; //0x88, 0x00 // can i use 0C?
|
||||
uint8_t resp[10];
|
||||
uint8_t cmd[] = {ICLASS_CMD_READ_OR_IDENTIFY, blockNo, 0x00, 0x00};
|
||||
AddCrc( cmd+1, 1 );
|
||||
bool isOK = sendCmdGetResponseWithRetries(cmd, sizeof(cmd), resp, len, 5);
|
||||
// expect size 10, retry 5times
|
||||
bool isOK = sendCmdGetResponseWithRetries(cmd, sizeof(cmd), resp, 10, 5);
|
||||
memcpy(data, resp, len);
|
||||
return isOK;
|
||||
}
|
||||
|
||||
// turn off afterwards
|
||||
// readblock 8 + 2. only want 8.
|
||||
void iClass_ReadBlk(uint8_t blockno) {
|
||||
uint8_t data[] = {0,0,0,0,0,0,0,0,0,0};
|
||||
bool isOK = iClass_ReadBlock(blockno, data, sizeof(data));
|
||||
cmd_send(CMD_ACK, isOK, 0, 0, data, 8);
|
||||
cmd_send(CMD_ACK, isOK, 0, 0, data, sizeof(data));
|
||||
switch_off();
|
||||
}
|
||||
|
||||
|
@ -2307,7 +2321,7 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) {
|
|||
BigBuf_free();
|
||||
uint8_t *dataout = BigBuf_malloc(255*8);
|
||||
if (dataout == NULL){
|
||||
DbpString("out of memory");
|
||||
DbpString("[!] out of memory");
|
||||
OnError(1);
|
||||
return;
|
||||
}
|
||||
|
@ -2321,7 +2335,7 @@ void iClass_Dump(uint8_t blockno, uint8_t numblks) {
|
|||
if (!isOK || (blockdata[0] == 0xBB || blockdata[7] == 0xBB || blockdata[2] == 0xBB)) { //try again
|
||||
isOK = iClass_ReadBlock(blockno + blkCnt, blockdata, sizeof(blockdata));
|
||||
if (!isOK) {
|
||||
Dbprintf("Block %02X failed to read", blkCnt + blockno);
|
||||
Dbprintf("[!] block %02X failed to read", blkCnt + blockno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2346,7 +2360,7 @@ bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) {
|
|||
//if response is not equal to write values
|
||||
if (memcmp(write + 2, resp, 8)) {
|
||||
|
||||
//if not programming key areas (note key blocks don't get programmed with actual key data it is xor data)
|
||||
//if not programming key areas (note key blocks don't get programmed with actual key data it is xor data)
|
||||
if (blockNo != 3 && blockNo != 4) {
|
||||
isOK = sendCmdGetResponseWithRetries(write, sizeof(write), resp, sizeof(resp), 5);
|
||||
}
|
||||
|
@ -2358,11 +2372,6 @@ bool iClass_WriteBlock_ext(uint8_t blockNo, uint8_t *data) {
|
|||
// turn off afterwards
|
||||
void iClass_WriteBlock(uint8_t blockNo, uint8_t *data) {
|
||||
bool isOK = iClass_WriteBlock_ext(blockNo, data);
|
||||
if (isOK)
|
||||
Dbprintf("Write block [%02x] successful", blockNo);
|
||||
else
|
||||
Dbprintf("Write block [%02x] failed", blockNo);
|
||||
|
||||
cmd_send(CMD_ACK,isOK,0,0,0,0);
|
||||
switch_off();
|
||||
}
|
||||
|
|
|
@ -76,16 +76,15 @@ int usage_hf_iclass_encrypt(void) {
|
|||
return 0;
|
||||
}
|
||||
int usage_hf_iclass_dump(void) {
|
||||
PrintAndLog("Usage: hf iclass dump f <fileName> k <Key> c <CreditKey> e|r\n");
|
||||
PrintAndLog("Usage: hf iclass dump f <fileName> k <key> c <creditkey> [e|r|v]\n");
|
||||
PrintAndLog("Options:");
|
||||
PrintAndLog(" f <filename> : specify a filename to save dump to");
|
||||
PrintAndLog(" k <Key> : *Access Key as 16 hex symbols or 1 hex to select key from memory");
|
||||
PrintAndLog(" c <CreditKey>: Credit Key as 16 hex symbols or 1 hex to select key from memory");
|
||||
PrintAndLog(" e : If 'e' is specified, the key is interpreted as the 16 byte");
|
||||
PrintAndLog(" Custom Key (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, the key is interpreted as raw block 3/4");
|
||||
PrintAndLog(" NOTE: * = required");
|
||||
PrintAndLog(" k <key> : <required> access Key as 16 hex symbols or 1 hex to select key from memory");
|
||||
PrintAndLog(" c <creditkey>: credit key as 16 hex symbols or 1 hex to select key from memory");
|
||||
PrintAndLog(" e : elite computations applied to key");
|
||||
PrintAndLog(" r : raw, the key is interpreted as raw block 3/4");
|
||||
PrintAndLog(" v : verbose output");
|
||||
PrintAndLog("");
|
||||
PrintAndLog("Samples:");
|
||||
PrintAndLog(" hf iclass dump k 001122334455667B");
|
||||
PrintAndLog(" hf iclass dump k AAAAAAAAAAAAAAAA c 001122334455667B");
|
||||
|
@ -109,28 +108,29 @@ int usage_hf_iclass_clone(void) {
|
|||
return 0;
|
||||
}
|
||||
int usage_hf_iclass_writeblock(void) {
|
||||
PrintAndLog("Usage: hf iclass writeblk b <Block> d <Data> k <Key> c e|r\n");
|
||||
PrintAndLog("Usage: hf iclass writeblk b <block> d <data> k <key> [c|e|r|v]\n");
|
||||
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(" 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 : credit key assumed\n");
|
||||
PrintAndLog(" e : elite computations applied to key");
|
||||
PrintAndLog(" r : raw, no computations applied to key");
|
||||
PrintAndLog(" v : verbose output");
|
||||
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"); # No reference to option `n` in implementation
|
||||
return 0;
|
||||
}
|
||||
int usage_hf_iclass_readblock(void) {
|
||||
PrintAndLog("Usage: hf iclass readblk b <Block> k <Key> c e|r\n");
|
||||
PrintAndLog("Usage: hf iclass readblk b <block> k <key> [c|e|r|v]\n");
|
||||
PrintAndLog("Options:");
|
||||
PrintAndLog(" b <Block> : The block number as 2 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(" b <block> : The block number as 2 hex symbols");
|
||||
PrintAndLog(" k <key> : Access Key as 16 hex symbols or 1 hex to select key from memory");
|
||||
PrintAndLog(" c : credit key assumed\n");
|
||||
PrintAndLog(" e : elite computations applied to key");
|
||||
PrintAndLog(" r : raw, no computations applied to key");
|
||||
PrintAndLog(" v : verbose output");
|
||||
PrintAndLog("Samples:");
|
||||
PrintAndLog(" hf iclass readblk b 06 k 0011223344556677");
|
||||
PrintAndLog(" hf iclass readblk b 1B k 0011223344556677 c");
|
||||
|
@ -270,7 +270,8 @@ int CmdHFiClassSniff(const char *Cmd) {
|
|||
|
||||
int CmdHFiClassSim(const char *Cmd) {
|
||||
|
||||
if (strlen(Cmd)<1) return usage_hf_iclass_sim();
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd)<1 || cmdp == 'H' || cmdp == 'h') return usage_hf_iclass_sim();
|
||||
|
||||
uint8_t simType = 0;
|
||||
uint8_t CSN[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
@ -508,7 +509,7 @@ int HFiClassReader(const char *Cmd, bool loop, bool verbose) {
|
|||
// no tag found or button pressed
|
||||
if( (readStatus == 0 && !loop) || readStatus == 0xFF) {
|
||||
// abort
|
||||
if (verbose) PrintAndLog("Quitting...");
|
||||
if (verbose) PrintAndLog("[-] Quitting...");
|
||||
return 0;
|
||||
}
|
||||
if( readStatus & FLAG_ICLASS_READER_CSN){
|
||||
|
@ -529,7 +530,7 @@ int HFiClassReader(const char *Cmd, bool loop, bool verbose) {
|
|||
|
||||
if (tagFound && !loop) return 1;
|
||||
} else {
|
||||
if (verbose) PrintAndLog("Command execute timeout");
|
||||
if (verbose) PrintAndLog("[!] command execute timeout");
|
||||
}
|
||||
if (!loop) break;
|
||||
}
|
||||
|
@ -544,13 +545,15 @@ int CmdHFiClassReader(const char *Cmd) {
|
|||
}
|
||||
|
||||
int CmdHFiClassReader_Replay(const char *Cmd) {
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
if (strlen(Cmd)<1 || cmdp == 'H' || cmdp == 'h') return usage_hf_iclass_replay();
|
||||
|
||||
uint8_t readerType = 0;
|
||||
uint8_t MAC[4]={0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
if (strlen(Cmd)<1) return usage_hf_iclass_replay();
|
||||
|
||||
uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
if (param_gethex(Cmd, 0, MAC, 8)) {
|
||||
PrintAndLog("MAC must include 8 HEX symbols");
|
||||
PrintAndLog("[-] MAC must include 8 HEX symbols");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -668,9 +671,9 @@ int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
if (strlen(Cmd)<1 || opt == 'h' || opt == 'H') return usage_hf_iclass_decrypt();
|
||||
|
||||
uint8_t key[16] = { 0 };
|
||||
if(readKeyfile("iclass_decryptionkey.bin", 16, key)) return usage_hf_iclass_decrypt();
|
||||
if (readKeyfile("iclass_decryptionkey.bin", 16, key)) return usage_hf_iclass_decrypt();
|
||||
|
||||
PrintAndLog("Decryption key loaded from file [ok]");
|
||||
PrintAndLog("[+] decryption key loaded from file");
|
||||
|
||||
//Open the tagdump-file
|
||||
FILE *f;
|
||||
|
@ -678,7 +681,7 @@ int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
if(opt == 'f' && param_getstr(Cmd, 1, filename, sizeof(filename)) > 0) {
|
||||
f = fopen(filename, "rb");
|
||||
if (!f) {
|
||||
PrintAndLog("Could not find file %s", filename);
|
||||
PrintAndLog("[!] could not find file %s", filename);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
|
@ -690,7 +693,7 @@ int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if ( fsize < 0 ) {
|
||||
PrintAndLog("Error, when getting filesize");
|
||||
PrintAndLog("[!] error, when getting filesize");
|
||||
fclose(f);
|
||||
return 2;
|
||||
}
|
||||
|
@ -700,7 +703,7 @@ int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
size_t bytes_read = fread(decrypted, 1, fsize, f);
|
||||
fclose(f);
|
||||
if ( bytes_read == 0) {
|
||||
PrintAndLog("File reading error");
|
||||
PrintAndLog("[!] file reading error");
|
||||
free(decrypted);
|
||||
return 3;
|
||||
}
|
||||
|
@ -736,12 +739,10 @@ int CmdHFiClassDecrypt(const char *Cmd) {
|
|||
if(blocknum > 6 && memcmp(enc_dump, empty, 8) != 0 ) {
|
||||
des3_crypt_ecb(&ctx, enc_dump, decrypted + idx );
|
||||
}
|
||||
//printvar("decrypted block", decrypted + idx, 8);
|
||||
}
|
||||
|
||||
saveFile(outfilename, "bin", decrypted, fsize);
|
||||
free(decrypted);
|
||||
|
||||
free(decrypted);
|
||||
printIclassDumpContents(decrypted, 1, (fsize/8), fsize);
|
||||
return 0;
|
||||
}
|
||||
|
@ -752,14 +753,13 @@ static int iClassEncryptBlkData(uint8_t *blkData) {
|
|||
usage_hf_iclass_encrypt();
|
||||
return 1;
|
||||
}
|
||||
PrintAndLog("Decryption file found... ");
|
||||
PrintAndLog("[+] decryption file found");
|
||||
uint8_t encryptedData[16];
|
||||
uint8_t *encrypted = encryptedData;
|
||||
des3_context ctx = { DES_DECRYPT ,{ 0 } };
|
||||
des3_set2key_enc( &ctx, key);
|
||||
|
||||
des3_crypt_ecb(&ctx, blkData,encrypted);
|
||||
//printvar("decrypted block", decrypted, 8);
|
||||
memcpy(blkData,encrypted,8);
|
||||
return 1;
|
||||
}
|
||||
|
@ -798,7 +798,7 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool v
|
|||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
|
||||
PrintAndLog("Command execute timeout");
|
||||
PrintAndLog("[!] command execute timeout");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -810,12 +810,13 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool use_credit_key, bool v
|
|||
if (CCNR != NULL)
|
||||
memcpy(CCNR, data+16, 8);
|
||||
|
||||
if (isOK > 0) {
|
||||
if (verbose) PrintAndLog("CCNR: %s MISSING NCN", sprint_hex(CCNR, 8));
|
||||
if (isOK > 0 && verbose) {
|
||||
PrintAndLog("[+] CSN | %s", sprint_hex(CSN, 8));
|
||||
PrintAndLog("[+] CCNR | %s", sprint_hex(CCNR, 8));
|
||||
}
|
||||
|
||||
if (isOK <= 1){
|
||||
PrintAndLog("(%d) Failed to obtain CC! Aborting...", isOK);
|
||||
PrintAndLog("[-] (%d) Failed to obtain CC! Aborting...", isOK);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -825,16 +826,17 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u
|
|||
uint8_t CSN[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
uint8_t CCNR[12] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
|
||||
if (!select_only(CSN, CCNR, use_credit_key, verbose))
|
||||
if (!select_only(CSN, CCNR, use_credit_key, verbose)) {
|
||||
if (verbose) PrintAndLog("[-] selecting tag failed");
|
||||
return false;
|
||||
|
||||
}
|
||||
//get div_key
|
||||
if (rawkey)
|
||||
memcpy(div_key, KEY, 8);
|
||||
else
|
||||
HFiClassCalcDivKey(CSN, KEY, div_key, elite);
|
||||
|
||||
if (verbose) PrintAndLog("Authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8) );
|
||||
if (verbose) PrintAndLog("[+] authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8) );
|
||||
|
||||
doMAC(CCNR, div_key, MAC);
|
||||
UsbCommand resp;
|
||||
|
@ -843,12 +845,12 @@ static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool u
|
|||
clearCommandBuffer();
|
||||
SendCommand(&d);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
|
||||
if (verbose) PrintAndLog("Auth Command execute timeout");
|
||||
if (verbose) PrintAndLog("[-] auth command execute timeout");
|
||||
return false;
|
||||
}
|
||||
uint8_t isOK = resp.arg[0] & 0xFF;
|
||||
if (!isOK) {
|
||||
if (verbose) PrintAndLog("Authentication error");
|
||||
if (verbose) PrintAndLog("[-] authentication error");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -869,7 +871,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
uint8_t keyNbr = 0;
|
||||
uint8_t dataLen = 0;
|
||||
uint8_t fileNameLen = 0;
|
||||
char filename[FILE_PATH_SIZE]={0};
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
char tempStr[50] = {0};
|
||||
bool have_debit_key = false;
|
||||
bool have_credit_key = false;
|
||||
|
@ -877,6 +879,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
bool elite = false;
|
||||
bool rawkey = false;
|
||||
bool errors = false;
|
||||
bool verbose = false;
|
||||
uint8_t cmdp = 0;
|
||||
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
|
@ -895,11 +898,11 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
if (keyNbr < ICLASS_KEYS_MAX) {
|
||||
memcpy(CreditKEY, iClass_Key_Table[keyNbr], 8);
|
||||
} else {
|
||||
PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
|
||||
PrintAndLog("\n[!] ERROR: Credit KeyNbr is invalid\n");
|
||||
errors = true;
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("\nERROR: Credit Key is incorrect length\n");
|
||||
PrintAndLog("\n[!] ERROR: Credit Key is incorrect length\n");
|
||||
errors = true;
|
||||
}
|
||||
cmdp += 2;
|
||||
|
@ -913,7 +916,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
case 'F':
|
||||
fileNameLen = param_getstr(Cmd, cmdp+1, filename, sizeof(filename));
|
||||
if (fileNameLen < 1) {
|
||||
PrintAndLog("No filename found after f");
|
||||
PrintAndLog("[!] no filename found after f");
|
||||
errors = true;
|
||||
}
|
||||
cmdp += 2;
|
||||
|
@ -929,11 +932,11 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
if (keyNbr < ICLASS_KEYS_MAX) {
|
||||
memcpy(KEY, iClass_Key_Table[keyNbr], 8);
|
||||
} else {
|
||||
PrintAndLog("\nERROR: Credit KeyNbr is invalid\n");
|
||||
PrintAndLog("\n[!] ERROR: Credit KeyNbr is invalid\n");
|
||||
errors = true;
|
||||
}
|
||||
} else {
|
||||
PrintAndLog("\nERROR: Credit Key is incorrect length\n");
|
||||
PrintAndLog("\n[!] ERROR: Credit Key is incorrect length\n");
|
||||
errors = true;
|
||||
}
|
||||
cmdp += 2;
|
||||
|
@ -943,8 +946,13 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
rawkey = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
PrintAndLog("[!] Unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
|
@ -963,7 +971,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
SendCommand(&c);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
|
||||
PrintAndLog("Command execute timeout");
|
||||
PrintAndLog("[!] command execute timeout");
|
||||
DropField();
|
||||
return 0;
|
||||
}
|
||||
|
@ -971,7 +979,7 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
uint8_t * data = resp.d.asBytes;
|
||||
|
||||
if(readStatus == 0){
|
||||
PrintAndLog("No tag found...");
|
||||
PrintAndLog("[-] no tag found");
|
||||
DropField();
|
||||
return 0;
|
||||
}
|
||||
|
@ -986,9 +994,10 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
}
|
||||
DropField();
|
||||
// authenticate debit key and get div_key - later store in dump block 3
|
||||
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, false)){
|
||||
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)){
|
||||
//try twice - for some reason it sometimes fails the first time...
|
||||
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, false)){
|
||||
PrintAndLog("[+] retry to select card");
|
||||
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)){
|
||||
DropField();
|
||||
return 0;
|
||||
}
|
||||
|
@ -999,25 +1008,25 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
SendCommand(&w);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
|
||||
PrintAndLog("Command execute time-out 1");
|
||||
PrintAndLog("[!] command execute timeout 1");
|
||||
DropField();
|
||||
return 1;
|
||||
}
|
||||
uint32_t blocksRead = resp.arg[1];
|
||||
uint8_t isOK = resp.arg[0] & 0xff;
|
||||
if (!isOK && !blocksRead) {
|
||||
PrintAndLog("Read Block Failed");
|
||||
PrintAndLog("[!] read block failed");
|
||||
DropField();
|
||||
return 0;
|
||||
}
|
||||
uint32_t startindex = resp.arg[2];
|
||||
if (blocksRead*8 > sizeof(tag_data)-(blockno*8)) {
|
||||
PrintAndLog("Data exceeded Buffer size!");
|
||||
PrintAndLog("[-] data exceeded Buffer size!");
|
||||
blocksRead = (sizeof(tag_data)/8) - blockno;
|
||||
}
|
||||
// response ok - now get bigbuf content of the dump
|
||||
GetFromBigBuf(tag_data+(blockno*8), blocksRead*8, startindex);
|
||||
WaitForResponse(CMD_ACK,NULL);
|
||||
WaitForResponse(CMD_ACK, NULL);
|
||||
size_t gotBytes = blocksRead*8 + blockno*8;
|
||||
|
||||
// try AA2
|
||||
|
@ -1026,9 +1035,9 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
DropField();
|
||||
memset(MAC,0,4);
|
||||
// AA2 authenticate credit key and git c_div_key - later store in dump block 4
|
||||
if (!select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, false)){
|
||||
if (!select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, verbose)){
|
||||
//try twice - for some reason it sometimes fails the first time...
|
||||
if (!select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, false)){
|
||||
if (!select_and_auth(CreditKEY, MAC, c_div_key, true, elite, rawkey, verbose)){
|
||||
DropField();
|
||||
return 0;
|
||||
}
|
||||
|
@ -1041,28 +1050,28 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
clearCommandBuffer();
|
||||
SendCommand(&w);
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
|
||||
PrintAndLog("Command execute timeout 2");
|
||||
PrintAndLog("[!] command execute timeout 2");
|
||||
DropField();
|
||||
return 0;
|
||||
}
|
||||
uint8_t isOK = resp.arg[0] & 0xff;
|
||||
blocksRead = resp.arg[1];
|
||||
if (!isOK && !blocksRead) {
|
||||
PrintAndLog("Read Block Failed 2");
|
||||
PrintAndLog("[!] read block failed 2");
|
||||
DropField();
|
||||
return 0;
|
||||
}
|
||||
|
||||
startindex = resp.arg[2];
|
||||
if (blocksRead*8 > sizeof(tag_data)-gotBytes) {
|
||||
PrintAndLog("Data exceeded Buffer size!");
|
||||
if (blocksRead * 8 > sizeof(tag_data) - gotBytes) {
|
||||
PrintAndLog("[-] data exceeded buffer size!");
|
||||
blocksRead = (sizeof(tag_data) - gotBytes)/8;
|
||||
}
|
||||
// get dumped data from bigbuf
|
||||
GetFromBigBuf(tag_data+gotBytes, blocksRead*8, startindex);
|
||||
WaitForResponse(CMD_ACK,NULL);
|
||||
GetFromBigBuf(tag_data + gotBytes, blocksRead * 8, startindex);
|
||||
WaitForResponse(CMD_ACK, NULL);
|
||||
|
||||
gotBytes += blocksRead*8;
|
||||
gotBytes += blocksRead * 8;
|
||||
} else { //field is still on - turn it off...
|
||||
DropField();
|
||||
}
|
||||
|
@ -1083,14 +1092,14 @@ int CmdHFiClassReader_Dump(const char *Cmd) {
|
|||
}
|
||||
|
||||
// save the dump to .bin file
|
||||
PrintAndLog("Saving dump file - %d blocks read", gotBytes/8);
|
||||
PrintAndLog("[+] saving dump file - %d blocks read", gotBytes/8);
|
||||
saveFile(filename, "bin", tag_data, gotBytes);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, 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 MAC[4] = {0x00,0x00,0x00,0x00};
|
||||
uint8_t div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose))
|
||||
return 0;
|
||||
|
||||
|
@ -1103,23 +1112,22 @@ static int WriteBlock(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_c
|
|||
|
||||
clearCommandBuffer();
|
||||
SendCommand(&w);
|
||||
if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
|
||||
PrintAndLog("[!] Write Command execute timeout");
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
|
||||
if ( verbose ) PrintAndLog("[!] Write Command execute timeout");
|
||||
return 0;
|
||||
}
|
||||
uint8_t isOK = resp.arg[0] & 0xff;
|
||||
if (!isOK) {
|
||||
PrintAndLog("[!] Write Block Failed");
|
||||
return 0;
|
||||
}
|
||||
PrintAndLog("[+] Write Block Successful");
|
||||
return 1;
|
||||
if (isOK)
|
||||
PrintAndLog("[+] Write block successful");
|
||||
else
|
||||
PrintAndLog("[!] Write block failed");
|
||||
return isOK;
|
||||
}
|
||||
|
||||
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 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};
|
||||
|
@ -1127,6 +1135,7 @@ int CmdHFiClass_WriteBlock(const char *Cmd) {
|
|||
bool elite = false;
|
||||
bool rawkey = false;
|
||||
bool errors = false;
|
||||
bool verbose = false;
|
||||
uint8_t cmdp = 0;
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
|
@ -1183,6 +1192,11 @@ int CmdHFiClass_WriteBlock(const char *Cmd) {
|
|||
rawkey = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("[!] unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
|
@ -1191,15 +1205,15 @@ int CmdHFiClass_WriteBlock(const char *Cmd) {
|
|||
}
|
||||
if (errors || cmdp < 6) return usage_hf_iclass_writeblock();
|
||||
|
||||
int ans = WriteBlock(blockno, bldata, KEY, use_credit_key, elite, rawkey, true);
|
||||
int ans = WriteBlock(blockno, bldata, KEY, use_credit_key, elite, rawkey, verbose);
|
||||
DropField();
|
||||
return ans;
|
||||
}
|
||||
|
||||
int CmdHFiClassCloneTag(const char *Cmd) {
|
||||
char filename[FILE_PATH_SIZE] = { 0x00 };
|
||||
char tempStr[50]={0};
|
||||
uint8_t KEY[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
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;
|
||||
|
@ -1209,6 +1223,7 @@ int CmdHFiClassCloneTag(const char *Cmd) {
|
|||
bool elite = false;
|
||||
bool rawkey = false;
|
||||
bool errors = false;
|
||||
bool verbose = false;
|
||||
uint8_t cmdp = 0;
|
||||
while(param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch(param_getchar(Cmd, cmdp)) {
|
||||
|
@ -1274,6 +1289,11 @@ int CmdHFiClassCloneTag(const char *Cmd) {
|
|||
rawkey = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("[!] unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
|
@ -1307,18 +1327,18 @@ int CmdHFiClassCloneTag(const char *Cmd) {
|
|||
// 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);
|
||||
size_t bytes_read = fread(tag_data,sizeof(iclass_block_t),endblock - startblock + 1,f);
|
||||
fseek(f, startblock*8, SEEK_SET);
|
||||
size_t bytes_read = fread(tag_data, sizeof(iclass_block_t),endblock - startblock + 1, f);
|
||||
if ( bytes_read == 0){
|
||||
PrintAndLog("[!] File reading error.");
|
||||
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 MAC[4] = {0x00,0x00,0x00,0x00};
|
||||
uint8_t div_key[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
|
||||
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, true))
|
||||
if (!select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose))
|
||||
return 0;
|
||||
|
||||
UsbCommand w = {CMD_ICLASS_CLONE,{startblock,endblock}};
|
||||
|
@ -1344,8 +1364,8 @@ int CmdHFiClassCloneTag(const char *Cmd) {
|
|||
UsbCommand resp;
|
||||
clearCommandBuffer();
|
||||
SendCommand(&w);
|
||||
if (!WaitForResponseTimeout(CMD_ACK,&resp,4500)) {
|
||||
PrintAndLog("[!] Command execute timeout");
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4500)) {
|
||||
PrintAndLog("[!] command execute timeout");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -1381,7 +1401,7 @@ static int ReadBlock(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite,
|
|||
return 0;
|
||||
}
|
||||
//data read is stored in: resp.d.asBytes[0-15]
|
||||
PrintAndLog("Block %02X: %s\n", blockno, sprint_hex(resp.d.asBytes, 8));
|
||||
PrintAndLog("block %02X: %s\n", blockno, sprint_hex(resp.d.asBytes, 8));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -1396,6 +1416,7 @@ int CmdHFiClass_ReadBlock(const char *Cmd) {
|
|||
bool rawkey = false;
|
||||
bool errors = false;
|
||||
bool auth = false;
|
||||
bool verbose = false;
|
||||
uint8_t cmdp = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (param_getchar(Cmd, cmdp)) {
|
||||
|
@ -1445,6 +1466,11 @@ int CmdHFiClass_ReadBlock(const char *Cmd) {
|
|||
rawkey = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'v':
|
||||
case 'V':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLog("[!] unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
|
@ -1455,7 +1481,7 @@ int CmdHFiClass_ReadBlock(const char *Cmd) {
|
|||
|
||||
if (!auth)
|
||||
PrintAndLog("[-] warning: no authentication used with read, only a few specific blocks can be read accurately without authentication.");
|
||||
return ReadBlock(KEY, blockno, keyType, elite, rawkey, false, auth);
|
||||
return ReadBlock(KEY, blockno, keyType, elite, rawkey, verbose, auth);
|
||||
}
|
||||
|
||||
int CmdHFiClass_loclass(const char *Cmd) {
|
||||
|
@ -1512,7 +1538,7 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e
|
|||
printf("------+--+-------------------------+\n");
|
||||
while (i <= endblock){
|
||||
uint8_t *blk = iclass_dump + (i * 8);
|
||||
printf("Block |%02X| %s\n", i, sprint_hex_ascii(blk, 8) );
|
||||
printf(" |%02X| %s\n", i, sprint_hex_ascii(blk, 8) );
|
||||
i++;
|
||||
}
|
||||
printf("------+--+-------------------------+\n");
|
||||
|
|
Loading…
Reference in a new issue