mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
@@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file.
|
||||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Changed `hf iclass info` - now uses CSN values based checks (@antiklesys)
|
||||
- Changed `hf iclass dump` - now uses default AA1 key when called without a key or key index (@iceman1001)
|
||||
- Renamed `hf iclass trbl` to `hf iclass tear` (@iceman1001)
|
||||
- Changed `hw tearoff` - the device side message is now debug log controlled (@iceman1001)
|
||||
|
||||
+1
-1
@@ -121,7 +121,7 @@ void BigBuf_Clear_ext(bool verbose) {
|
||||
memset(BigBuf, 0, s_bigbuf_size);
|
||||
clear_trace();
|
||||
if (verbose) {
|
||||
Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size);
|
||||
if (g_dbglevel >= DBG_ERROR) Dbprintf("Buffer cleared (%i bytes)", s_bigbuf_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-16
@@ -99,6 +99,7 @@ int tearoff_hook(void) {
|
||||
if (g_tearoff_enabled) {
|
||||
if (g_tearoff_delay_us == 0) {
|
||||
Dbprintf(_RED_("No tear-off delay configured!"));
|
||||
g_tearoff_enabled = false;
|
||||
return PM3_SUCCESS; // SUCCESS = the hook didn't do anything
|
||||
}
|
||||
SpinDelayUsPrecision(g_tearoff_delay_us);
|
||||
@@ -254,7 +255,7 @@ static uint32_t MeasureAntennaTuningLfData(void) {
|
||||
void print_stack_usage(void) {
|
||||
for (uint32_t *p = _stack_start; ; ++p) {
|
||||
if (*p != 0xdeadbeef) {
|
||||
Dbprintf(" Max stack usage......... %d / %d bytes", (uint32_t)_stack_end - (uint32_t)p, (uint32_t)_stack_end - (uint32_t)_stack_start);
|
||||
Dbprintf(" Max stack usage..... %d / %d bytes", (uint32_t)_stack_end - (uint32_t)p, (uint32_t)_stack_end - (uint32_t)_stack_start);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -365,7 +366,7 @@ static void print_debug_level(void) {
|
||||
sprintf(dbglvlstr, "extended");
|
||||
break;
|
||||
}
|
||||
Dbprintf(" Debug log level......... %d ( " _YELLOW_("%s")" )", g_dbglevel, dbglvlstr);
|
||||
Dbprintf(" Debug log level..... %d ( " _YELLOW_("%s")" )", g_dbglevel, dbglvlstr);
|
||||
}
|
||||
|
||||
// measure the Connection Speed by sending SpeedTestBufferSize bytes to client and measuring the elapsed time.
|
||||
@@ -421,11 +422,11 @@ static void SendStatus(uint32_t wait) {
|
||||
print_debug_level();
|
||||
|
||||
tosend_t *ts = get_tosend();
|
||||
Dbprintf(" ToSendMax............... %d", ts->max);
|
||||
Dbprintf(" ToSend BUFFERSIZE....... %d", TOSEND_BUFFER_SIZE);
|
||||
Dbprintf(" ToSendMax........... %d", ts->max);
|
||||
Dbprintf(" ToSend BUFFERSIZE... %d", TOSEND_BUFFER_SIZE);
|
||||
while ((AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINRDY) == 0); // Wait for MAINF value to become available...
|
||||
uint16_t mainf = AT91C_BASE_PMC->PMC_MCFR & AT91C_CKGR_MAINF; // Get # main clocks within 16 slow clocks
|
||||
Dbprintf(" Slow clock.............. %d Hz", (16 * MAINCK) / mainf);
|
||||
Dbprintf(" Slow clock.......... %d Hz", (16 * MAINCK) / mainf);
|
||||
uint32_t delta_time = 0;
|
||||
uint32_t start_time = GetTickCount();
|
||||
#define SLCK_CHECK_MS 50
|
||||
@@ -449,10 +450,11 @@ static void SendStatus(uint32_t wait) {
|
||||
} else {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
Dbprintf(" Mifare.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, MF_KEYS_FILE);
|
||||
Dbprintf(" Mifare... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, MF_KEYS_FILE);
|
||||
} else {
|
||||
Dbprintf(" Mifare.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, MF_KEYS_FILE);
|
||||
Dbprintf(" Mifare... "_RED_("%u")" keys - "_RED_("%s"), num, MF_KEYS_FILE);
|
||||
}
|
||||
|
||||
if (exists_in_spiffs(T55XX_KEYS_FILE)) {
|
||||
@@ -460,10 +462,11 @@ static void SendStatus(uint32_t wait) {
|
||||
} else {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
Dbprintf(" T55xx................... "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, T55XX_KEYS_FILE);
|
||||
Dbprintf(" T55xx.... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, T55XX_KEYS_FILE);
|
||||
} else {
|
||||
Dbprintf(" T55xx................... "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, T55XX_KEYS_FILE);
|
||||
Dbprintf(" T55xx.... "_RED_("%u")" keys - "_RED_("%s"), num, T55XX_KEYS_FILE);
|
||||
}
|
||||
|
||||
if (exists_in_spiffs(ICLASS_KEYS_FILE)) {
|
||||
@@ -471,10 +474,11 @@ static void SendStatus(uint32_t wait) {
|
||||
} else {
|
||||
num = 0;
|
||||
}
|
||||
|
||||
if (num > 0) {
|
||||
Dbprintf(" iClass.................. "_YELLOW_("%u")" keys (spiffs: "_GREEN_("%s")")", num, ICLASS_KEYS_FILE);
|
||||
Dbprintf(" iClass... "_YELLOW_("%u")" keys - "_GREEN_("%s"), num, ICLASS_KEYS_FILE);
|
||||
} else {
|
||||
Dbprintf(" iClass.................. "_RED_("%u")" keys (spiffs: "_RED_("%s")")", num, ICLASS_KEYS_FILE);
|
||||
Dbprintf(" iClass... "_RED_("%u")" keys - "_RED_("%s"), num, ICLASS_KEYS_FILE);
|
||||
}
|
||||
#endif
|
||||
DbpString("");
|
||||
@@ -2354,7 +2358,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
|
||||
uint16_t available;
|
||||
uint16_t pre_available = 0;
|
||||
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
|
||||
uint8_t *dest = BigBuf_calloc(USART_FIFOLEN);
|
||||
uint32_t wait = payload->waittime;
|
||||
|
||||
StartTicks();
|
||||
@@ -2398,7 +2402,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
|
||||
uint16_t available;
|
||||
uint16_t pre_available = 0;
|
||||
uint8_t *dest = BigBuf_malloc(USART_FIFOLEN);
|
||||
uint8_t *dest = BigBuf_calloc(USART_FIFOLEN);
|
||||
uint32_t wait = payload->waittime;
|
||||
|
||||
StartTicks();
|
||||
@@ -2694,7 +2698,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
|
||||
uint32_t size = packet->oldarg[1];
|
||||
|
||||
uint8_t *buff = BigBuf_malloc(size);
|
||||
uint8_t *buff = BigBuf_calloc(size);
|
||||
if (buff == NULL) {
|
||||
if (g_dbglevel >= DBG_DEBUG) Dbprintf("Failed to allocate memory");
|
||||
// Trigger a finish downloading signal with an PM3_EMALLOC
|
||||
@@ -2899,7 +2903,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
case CMD_FLASHMEM_DOWNLOAD: {
|
||||
|
||||
LED_B_ON();
|
||||
uint8_t *mem = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||
uint8_t *mem = BigBuf_calloc(PM3_CMD_DATA_SIZE);
|
||||
uint32_t startidx = packet->oldarg[0];
|
||||
uint32_t numofbytes = packet->oldarg[1];
|
||||
// arg0 = startindex
|
||||
@@ -2931,7 +2935,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||
case CMD_FLASHMEM_INFO: {
|
||||
|
||||
LED_B_ON();
|
||||
rdv40_validation_t *info = (rdv40_validation_t *)BigBuf_malloc(sizeof(rdv40_validation_t));
|
||||
rdv40_validation_t *info = (rdv40_validation_t *)BigBuf_calloc(sizeof(rdv40_validation_t));
|
||||
|
||||
bool isok = Flash_ReadData(FLASH_MEM_SIGNATURE_OFFSET_P(spi_flash_pages64k), info->signature, FLASH_MEM_SIGNATURE_LEN);
|
||||
|
||||
|
||||
+1
-1
@@ -748,7 +748,7 @@ void em4x50_chk(const char *filename, bool ledcontrol) {
|
||||
uint16_t pwd_count = 0;
|
||||
uint32_t size = size_in_spiffs(filename);
|
||||
pwd_count = size / 4;
|
||||
uint8_t *pwds = BigBuf_malloc(size);
|
||||
uint8_t *pwds = BigBuf_calloc(size);
|
||||
|
||||
rdv40_spiffs_read_as_filetype(filename, pwds, size, RDV40_SPIFFS_SAFETY_SAFE);
|
||||
|
||||
|
||||
+2
-2
@@ -857,7 +857,7 @@ void SmartCardRaw(const smart_card_raw_t *p) {
|
||||
LED_D_ON();
|
||||
|
||||
uint16_t len = 0;
|
||||
uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||
uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
// check if alloacted...
|
||||
smartcard_command_t flags = p->flags;
|
||||
|
||||
@@ -937,7 +937,7 @@ void SmartCardUpgrade(uint64_t arg0) {
|
||||
bool isOK = true;
|
||||
uint16_t length = arg0, pos = 0;
|
||||
const uint8_t *fwdata = BigBuf_get_addr();
|
||||
uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE);
|
||||
uint8_t *verfiydata = BigBuf_calloc(I2C_BLOCK_SIZE);
|
||||
|
||||
while (length) {
|
||||
|
||||
|
||||
+1
-1
@@ -40,7 +40,7 @@ static void SmartCardDirectSend(uint8_t prepend, const smart_card_raw_t *p, uint
|
||||
LED_D_ON();
|
||||
|
||||
uint16_t len = 0;
|
||||
uint8_t *resp = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||
uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
resp[0] = prepend;
|
||||
// check if alloacted...
|
||||
smartcard_command_t flags = p->flags;
|
||||
|
||||
+18
-18
@@ -399,40 +399,40 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) {
|
||||
int trace_data_size;
|
||||
|
||||
// Respond SOF -- takes 1 bytes
|
||||
uint8_t *resp_sof = BigBuf_malloc(1);
|
||||
uint8_t resp_sof[1] = {0};
|
||||
int resp_sof_len;
|
||||
|
||||
// Anticollision CSN (rotated CSN)
|
||||
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
|
||||
uint8_t *resp_anticoll = BigBuf_malloc(22);
|
||||
uint8_t *resp_anticoll = BigBuf_calloc(22);
|
||||
int resp_anticoll_len;
|
||||
|
||||
// CSN (block 0)
|
||||
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
|
||||
uint8_t *resp_csn = BigBuf_malloc(22);
|
||||
uint8_t *resp_csn = BigBuf_calloc(22);
|
||||
int resp_csn_len;
|
||||
|
||||
// configuration (blk 1) PICOPASS 2ks
|
||||
uint8_t *resp_conf = BigBuf_malloc(22);
|
||||
uint8_t *resp_conf = BigBuf_calloc(22);
|
||||
int resp_conf_len;
|
||||
|
||||
// e-Purse (blk 2)
|
||||
// 18: Takes 2 bytes for SOF/EOF and 8 * 2 = 16 bytes (2 bytes/bit)
|
||||
uint8_t *resp_cc = BigBuf_malloc(18);
|
||||
uint8_t *resp_cc = BigBuf_calloc(18);
|
||||
int resp_cc_len;
|
||||
|
||||
// Kd, Kc (blocks 3 and 4). Cannot be read. Always respond with 0xff bytes only
|
||||
uint8_t *resp_ff = BigBuf_malloc(22);
|
||||
uint8_t *resp_ff = BigBuf_calloc(22);
|
||||
int resp_ff_len;
|
||||
uint8_t ff_data[10] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00};
|
||||
AddCrc(ff_data, 8);
|
||||
|
||||
// Application Issuer Area (blk 5)
|
||||
uint8_t *resp_aia = BigBuf_malloc(22);
|
||||
uint8_t *resp_aia = BigBuf_calloc(22);
|
||||
int resp_aia_len;
|
||||
|
||||
// receive command
|
||||
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
|
||||
uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
|
||||
|
||||
// Prepare card messages
|
||||
tosend_t *ts = get_tosend();
|
||||
@@ -474,11 +474,11 @@ int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf) {
|
||||
|
||||
//This is used for responding to READ-block commands or other data which is dynamically generated
|
||||
//First the 'trace'-data, not encoded for FPGA
|
||||
uint8_t *data_generic_trace = BigBuf_malloc(34); // 32 bytes data + 2byte CRC is max tag answer
|
||||
uint8_t *data_generic_trace = BigBuf_calloc(34); // 32 bytes data + 2byte CRC is max tag answer
|
||||
|
||||
//Then storage for the modulated data
|
||||
//Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes)
|
||||
uint8_t *data_response = BigBuf_malloc((34 * 2) + 3);
|
||||
uint8_t *data_response = BigBuf_calloc((34 * 2) + 3);
|
||||
|
||||
enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE;
|
||||
|
||||
@@ -942,29 +942,29 @@ int do_iclass_simulation_nonsec(void) {
|
||||
int trace_data_size = 0;
|
||||
|
||||
// Respond SOF -- takes 1 bytes
|
||||
uint8_t *resp_sof = BigBuf_malloc(2);
|
||||
uint8_t resp_sof[2] = { 0 };
|
||||
int resp_sof_len;
|
||||
|
||||
// Anticollision CSN (rotated CSN)
|
||||
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
|
||||
uint8_t *resp_anticoll = BigBuf_malloc(28);
|
||||
uint8_t *resp_anticoll = BigBuf_calloc(28);
|
||||
int resp_anticoll_len;
|
||||
|
||||
// CSN
|
||||
// 22: Takes 2 bytes for SOF/EOF and 10 * 2 = 20 bytes (2 bytes/byte)
|
||||
uint8_t *resp_csn = BigBuf_malloc(28);
|
||||
uint8_t *resp_csn = BigBuf_calloc(28);
|
||||
int resp_csn_len;
|
||||
|
||||
// configuration (blk 1) PICOPASS 2ks
|
||||
uint8_t *resp_conf = BigBuf_malloc(28);
|
||||
uint8_t *resp_conf = BigBuf_calloc(28);
|
||||
int resp_conf_len;
|
||||
|
||||
// Application Issuer Area (blk 5)
|
||||
uint8_t *resp_aia = BigBuf_malloc(28);
|
||||
uint8_t *resp_aia = BigBuf_calloc(28);
|
||||
int resp_aia_len;
|
||||
|
||||
// receive command
|
||||
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
|
||||
uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
|
||||
|
||||
// Prepare card messages
|
||||
tosend_t *ts = get_tosend();
|
||||
@@ -997,11 +997,11 @@ int do_iclass_simulation_nonsec(void) {
|
||||
|
||||
//This is used for responding to READ-block commands or other data which is dynamically generated
|
||||
//First the 'trace'-data, not encoded for FPGA
|
||||
uint8_t *data_generic_trace = BigBuf_malloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer
|
||||
uint8_t *data_generic_trace = BigBuf_calloc(32 + 2); // 32 bytes data + 2byte CRC is max tag answer
|
||||
|
||||
//Then storage for the modulated data
|
||||
//Each bit is doubled when modulated for FPGA, and we also have SOF and EOF (2 bytes)
|
||||
uint8_t *data_response = BigBuf_malloc((32 + 2) * 2 + 2);
|
||||
uint8_t *data_response = BigBuf_calloc((32 + 2) * 2 + 2);
|
||||
|
||||
enum { IDLE, ACTIVATED, SELECTED, HALTED } chip_state = IDLE;
|
||||
|
||||
|
||||
+15
-17
@@ -190,35 +190,35 @@ struct Crypto1State crypto1_state = {0, 0};
|
||||
|
||||
void printHf14aConfig(void) {
|
||||
DbpString(_CYAN_("HF 14a config"));
|
||||
Dbprintf(" [a] Anticol override.............. %s%s%s",
|
||||
Dbprintf(" [a] Anticol override........... %s%s%s",
|
||||
(hf14aconfig.forceanticol == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forceanticol == 1) ? _RED_("force") " ( always do anticol )" : "",
|
||||
(hf14aconfig.forceanticol == 2) ? _RED_("skip") " ( always skip anticol )" : ""
|
||||
);
|
||||
Dbprintf(" [b] BCC override.................. %s%s%s",
|
||||
Dbprintf(" [b] BCC override............... %s%s%s",
|
||||
(hf14aconfig.forcebcc == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forcebcc == 1) ? _RED_("fix") " ( fix bad BCC )" : "",
|
||||
(hf14aconfig.forcebcc == 2) ? _RED_("ignore") " ( ignore bad BCC, always use card BCC )" : ""
|
||||
);
|
||||
Dbprintf(" [2] CL2 override.................. %s%s%s",
|
||||
Dbprintf(" [2] CL2 override............... %s%s%s",
|
||||
(hf14aconfig.forcecl2 == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forcecl2 == 1) ? _RED_("force") " ( always do CL2 )" : "",
|
||||
(hf14aconfig.forcecl2 == 2) ? _RED_("skip") " ( always skip CL2 )" : ""
|
||||
);
|
||||
Dbprintf(" [3] CL3 override.................. %s%s%s",
|
||||
Dbprintf(" [3] CL3 override............... %s%s%s",
|
||||
(hf14aconfig.forcecl3 == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forcecl3 == 1) ? _RED_("force") " ( always do CL3 )" : "",
|
||||
(hf14aconfig.forcecl3 == 2) ? _RED_("skip") " ( always skip CL3 )" : ""
|
||||
);
|
||||
Dbprintf(" [r] RATS override................. %s%s%s",
|
||||
Dbprintf(" [r] RATS override.............. %s%s%s",
|
||||
(hf14aconfig.forcerats == 0) ? _GREEN_("std") " ( follow standard )" : "",
|
||||
(hf14aconfig.forcerats == 1) ? _RED_("force") " ( always do RATS )" : "",
|
||||
(hf14aconfig.forcerats == 2) ? _RED_("skip") " ( always skip RATS )" : ""
|
||||
);
|
||||
Dbprintf(" [m] Magsafe polling............... %s",
|
||||
Dbprintf(" [m] Magsafe polling............ %s",
|
||||
(hf14aconfig.magsafe == 1) ? _GREEN_("enabled") : _YELLOW_("disabled")
|
||||
);
|
||||
Dbprintf(" [p] Polling loop annotation....... %s %*D",
|
||||
Dbprintf(" [p] Polling loop annotation.... %s %*D",
|
||||
(hf14aconfig.polling_loop_annotation.frame_length <= 0) ? _YELLOW_("disabled") : _GREEN_("enabled"),
|
||||
hf14aconfig.polling_loop_annotation.frame_length,
|
||||
hf14aconfig.polling_loop_annotation.frame,
|
||||
@@ -805,12 +805,12 @@ void RAMFUNC SniffIso14443a(uint8_t param) {
|
||||
set_tracing(true);
|
||||
|
||||
// The command (reader -> tag) that we're receiving.
|
||||
uint8_t *receivedCmd = BigBuf_malloc(MAX_FRAME_SIZE);
|
||||
uint8_t *receivedCmdPar = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
|
||||
uint8_t *receivedCmdPar = BigBuf_calloc(MAX_PARITY_SIZE);
|
||||
|
||||
// The response (tag -> reader) that we're receiving.
|
||||
uint8_t *receivedResp = BigBuf_malloc(MAX_FRAME_SIZE);
|
||||
uint8_t *receivedRespPar = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *receivedResp = BigBuf_calloc(MAX_FRAME_SIZE);
|
||||
uint8_t *receivedRespPar = BigBuf_calloc(MAX_PARITY_SIZE);
|
||||
|
||||
uint8_t previous_data = 0;
|
||||
int maxDataLen = 0, dataLen;
|
||||
@@ -2683,9 +2683,9 @@ void iso14443a_antifuzz(uint32_t flags) {
|
||||
int len = 0;
|
||||
|
||||
// allocate buffers:
|
||||
uint8_t *received = BigBuf_malloc(MAX_FRAME_SIZE);
|
||||
uint8_t *receivedPar = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *resp = BigBuf_malloc(20);
|
||||
uint8_t *received = BigBuf_calloc(MAX_FRAME_SIZE);
|
||||
uint8_t *receivedPar = BigBuf_calloc(MAX_PARITY_SIZE);
|
||||
uint8_t *resp = BigBuf_calloc(20);
|
||||
|
||||
memset(received, 0x00, MAX_FRAME_SIZE);
|
||||
memset(received, 0x00, MAX_PARITY_SIZE);
|
||||
@@ -4070,9 +4070,7 @@ void DetectNACKbug(void) {
|
||||
// i = number of authentications sent. Not always 256, since we are trying to sync but close to it.
|
||||
FpgaDisableTracing();
|
||||
|
||||
uint8_t *data = BigBuf_malloc(4);
|
||||
data[0] = isOK;
|
||||
data[1] = num_nacks;
|
||||
uint8_t data[4] = {isOK, num_nacks, 0, 0};
|
||||
num_to_bytes(i, 2, data + 2);
|
||||
reply_ng(CMD_HF_MIFARE_NACK_DETECT, status, data, 4);
|
||||
|
||||
|
||||
+9
-8
@@ -221,10 +221,11 @@ out:
|
||||
int sam_get_version(void) {
|
||||
int res = PM3_SUCCESS;
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("start sam_get_version");
|
||||
}
|
||||
|
||||
uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||
uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
uint16_t response_len = ISO7816_MAX_FRAME;
|
||||
|
||||
uint8_t payload[] = {
|
||||
@@ -252,8 +253,9 @@ int sam_get_version(void) {
|
||||
// 82 01
|
||||
// 01
|
||||
// 90 00
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("end sam_get_version");
|
||||
}
|
||||
|
||||
if (response[5] != 0xbd) {
|
||||
Dbprintf("Invalid SAM response");
|
||||
@@ -289,8 +291,9 @@ error:
|
||||
out:
|
||||
BigBuf_free();
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("end sam_get_version");
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -350,12 +353,10 @@ void sam_append_asn1_node(const uint8_t *root, const uint8_t *node, uint8_t type
|
||||
}
|
||||
|
||||
void sam_send_ack(void) {
|
||||
uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||
uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
uint16_t response_len = ISO7816_MAX_FRAME;
|
||||
|
||||
uint8_t payload[] = {
|
||||
0xa0, 0
|
||||
};
|
||||
uint8_t payload[] = { 0xa0, 0 };
|
||||
uint16_t payload_len = sizeof(payload);
|
||||
|
||||
sam_send_payload(
|
||||
|
||||
@@ -46,11 +46,12 @@
|
||||
*/
|
||||
static int sam_send_request_iso15(const uint8_t *const request, const uint8_t request_len, uint8_t *response, uint8_t *response_len, const bool shallow_mod, const bool break_on_nr_mac, const bool prevent_epurse_update) {
|
||||
int res = PM3_SUCCESS;
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("start sam_send_request_iso14a");
|
||||
}
|
||||
|
||||
uint8_t *buf1 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||
uint8_t *buf2 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||
uint8_t *buf1 = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
uint8_t *buf2 = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
if (buf1 == NULL || buf2 == NULL) {
|
||||
res = PM3_EMALLOC;
|
||||
goto out;
|
||||
@@ -255,10 +256,10 @@ out:
|
||||
*/
|
||||
static int sam_set_card_detected_picopass(const picopass_hdr_t *card_select) {
|
||||
int res = PM3_SUCCESS;
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("start sam_set_card_detected");
|
||||
|
||||
uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||
}
|
||||
uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
uint16_t response_len = ISO7816_MAX_FRAME;
|
||||
|
||||
// a0 12
|
||||
@@ -314,8 +315,9 @@ error:
|
||||
out:
|
||||
BigBuf_free();
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("end sam_set_card_detected");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
+6
-4
@@ -51,13 +51,14 @@
|
||||
*/
|
||||
static int sam_set_card_detected_seos(iso14a_card_select_t *card_select) {
|
||||
int res = PM3_SUCCESS;
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("start sam_set_card_detected");
|
||||
}
|
||||
|
||||
uint8_t *request = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||
uint8_t *request = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
uint16_t request_len = ISO7816_MAX_FRAME;
|
||||
|
||||
uint8_t *response = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||
uint8_t *response = BigBuf_calloc(ISO7816_MAX_FRAME);
|
||||
uint16_t response_len = ISO7816_MAX_FRAME;
|
||||
|
||||
const uint8_t payload[] = {
|
||||
@@ -107,8 +108,9 @@ error:
|
||||
out:
|
||||
BigBuf_free();
|
||||
|
||||
if (g_dbglevel >= DBG_DEBUG)
|
||||
if (g_dbglevel >= DBG_DEBUG) {
|
||||
DbpString("end sam_set_card_detected");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -312,7 +312,7 @@ static int is_valid_filename(const char *filename) {
|
||||
*/
|
||||
static void copy_in_spiffs(const char *src, const char *dst) {
|
||||
uint32_t size = size_in_spiffs(src);
|
||||
uint8_t *mem = BigBuf_malloc(size);
|
||||
uint8_t *mem = BigBuf_calloc(size);
|
||||
read_from_spiffs(src, (uint8_t *)mem, size);
|
||||
write_to_spiffs(dst, (uint8_t *)mem, size);
|
||||
}
|
||||
|
||||
@@ -914,7 +914,7 @@ int CmdHF14ASim(const char *Cmd) {
|
||||
bool keypress = kbd_enter_pressed();
|
||||
while (keypress == false) {
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0)
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false)
|
||||
continue;
|
||||
|
||||
if (resp.status != PM3_SUCCESS)
|
||||
@@ -4037,7 +4037,7 @@ int CmdHF14AAIDSim(const char *Cmd) {
|
||||
bool keypress = kbd_enter_pressed();
|
||||
while (keypress == false) {
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == 0) {
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_SIMULATE, &resp, 1500) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1411,7 +1411,7 @@ static bool HF14B_ask_ct_reader(bool verbose) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool HF14B_picopass_reader(bool verbose, bool info) {
|
||||
static bool HF14B_picopass_reader(bool verbose) {
|
||||
|
||||
iso14b_raw_cmd_t packet = {
|
||||
.flags = (ISO14B_CONNECT | ISO14B_SELECT_PICOPASS | ISO14B_DISCONNECT),
|
||||
@@ -1437,10 +1437,8 @@ bool HF14B_picopass_reader(bool verbose, bool info) {
|
||||
return false;
|
||||
}
|
||||
memcpy(card, resp.data.asBytes, sizeof(picopass_hdr_t));
|
||||
if (info) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn)));
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "iCLASS / Picopass CSN: " _GREEN_("%s"), sprint_hex(card->csn, sizeof(card->csn)));
|
||||
free(card);
|
||||
return true;
|
||||
}
|
||||
@@ -3038,7 +3036,6 @@ int infoHF14B(bool verbose, bool do_aid_search) {
|
||||
// get and print general info about all known 14b chips
|
||||
int readHF14B(bool loop, bool verbose, bool read_plot) {
|
||||
bool found = false;
|
||||
bool info = true;
|
||||
int res = PM3_SUCCESS;
|
||||
do {
|
||||
found = false;
|
||||
@@ -3054,7 +3051,7 @@ int readHF14B(bool loop, bool verbose, bool read_plot) {
|
||||
goto plot;
|
||||
|
||||
// Picopass
|
||||
found |= HF14B_picopass_reader(verbose, info);
|
||||
found |= HF14B_picopass_reader(verbose);
|
||||
if (found)
|
||||
goto plot;
|
||||
|
||||
|
||||
@@ -31,6 +31,5 @@ int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card);
|
||||
|
||||
int infoHF14B(bool verbose, bool do_aid_search);
|
||||
int readHF14B(bool loop, bool verbose, bool read_plot);
|
||||
bool HF14B_picopass_reader(bool verbose, bool info);
|
||||
|
||||
#endif
|
||||
|
||||
+150
-64
@@ -40,7 +40,6 @@
|
||||
#include "crypto/asn1utils.h" // ASN1 decoder
|
||||
#include "preferences.h"
|
||||
#include "generator.h"
|
||||
#include "cmdhf14b.h"
|
||||
#include "cmdhw.h"
|
||||
#include "hidsio.h"
|
||||
|
||||
@@ -584,14 +583,14 @@ static void fuse_config(const picopass_hdr_t *hdr) {
|
||||
|
||||
uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]);
|
||||
|
||||
PrintAndLogEx(INFO, " Raw... " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8));
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses);
|
||||
PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8));
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " ( %3u )............. app limit", hdr->conf.app_limit, hdr->conf.app_limit);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas);
|
||||
PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses);
|
||||
|
||||
uint8_t fuses = hdr->conf.fuses;
|
||||
|
||||
@@ -1467,8 +1466,9 @@ static void iclass_decode_credentials(uint8_t *data) {
|
||||
bool has_values = (memcmp(b7, empty, PICOPASS_BLOCK_SIZE) != 0) && (memcmp(b7, zeros, PICOPASS_BLOCK_SIZE) != 0);
|
||||
if (has_values && encryption == None) {
|
||||
|
||||
// todo: remove preamble/sentinel
|
||||
PrintAndLogEx(INFO, "------------------------ " _CYAN_("Block 7 decoder") " --------------------------");
|
||||
|
||||
// todo: remove preamble/sentinel
|
||||
if (has_new_pacs) {
|
||||
iclass_decode_credentials_new_pacs(b7);
|
||||
} else {
|
||||
@@ -1487,9 +1487,6 @@ static void iclass_decode_credentials(uint8_t *data) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
decode_wiegand(top, mid, bot, 0);
|
||||
}
|
||||
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "No unencrypted legacy credential found");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1950,7 +1947,7 @@ static int CmdHFiClassDump(const char *Cmd) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (credit_key_len > 0 && credit_key_nr >= 0) {
|
||||
PrintAndLogEx(ERR, "Please specify credit key or index, not both");
|
||||
return PM3_EINVARG;
|
||||
@@ -2267,7 +2264,7 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *macdata
|
||||
SendCommandNG(CMD_HF_ICLASS_WRITEBL, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == 0) {
|
||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_WRITEBL, &resp, 2000) == false) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
@@ -2401,14 +2398,13 @@ static int CmdHFiClassCreditEpurse(const char *Cmd) {
|
||||
"Credit the epurse on an iCLASS tag. The provided key must be the credit key.\n"
|
||||
"The first two bytes of the epurse are the debit value (big endian) and may be any value except FFFF.\n"
|
||||
"The remaining two bytes of the epurse are the credit value and must be smaller than the previous value.",
|
||||
"hf iclass creditepurse -d FEFFFFFF -k 001122334455667B\n"
|
||||
"hf iclass creditepurse -d FEFFFFFF --ki 0");
|
||||
"hf iclass creditepurse --ki 0 -d FEFFFEFF");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str0("k", "key", "<hex>", "Credit key as 8 hex bytes"),
|
||||
arg_int0(NULL, "ki", "<dec>", "Key index to select key from memory 'hf iclass managekeys'"),
|
||||
arg_str1("d", "data", "<hex>", "data to write as 8 hex bytes"),
|
||||
arg_str1("d", "data", "<hex>", "data to write as 4 hex bytes"),
|
||||
arg_lit0(NULL, "elite", "elite computations applied to key"),
|
||||
arg_lit0(NULL, "raw", "no computations applied to key"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
@@ -2493,7 +2489,7 @@ static int CmdHFiClassCreditEpurse(const char *Cmd) {
|
||||
PacketResponseNG resp;
|
||||
|
||||
int isok;
|
||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_CREDIT_EPURSE, &resp, 2000) == 0) {
|
||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_CREDIT_EPURSE, &resp, 2000) == false) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution time out");
|
||||
isok = PM3_ETIMEOUT;
|
||||
} else if (resp.status != PM3_SUCCESS) {
|
||||
@@ -2675,7 +2671,7 @@ static int CmdHFiClassRestore(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ICLASS_RESTORE, (uint8_t *)payload, payload_size);
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == 0) {
|
||||
if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == false) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
DropField();
|
||||
free(payload);
|
||||
@@ -2921,7 +2917,7 @@ static void iclass_cmp_print(uint8_t *b1, uint8_t *b2, const char *header1, cons
|
||||
strcat(line1, header1);
|
||||
strcat(line2, header2);
|
||||
|
||||
for (uint8_t i = 0; i < PICOPASS_BLOCK_SIZE; i++ ) {
|
||||
for (uint8_t i = 0; i < PICOPASS_BLOCK_SIZE; i++) {
|
||||
|
||||
int l1 = strlen(line1);
|
||||
int l2 = strlen(line2);
|
||||
@@ -2961,7 +2957,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
CLIParserInit(&ctx, "hf iclass tear",
|
||||
"Tear off an iCLASS tag block\n"
|
||||
"e-purse usually 300-500us to trigger the erase phase\n"
|
||||
"also seen 1800-2100us on some cards\n",
|
||||
"also seen 1800-2100us on some cards\n"
|
||||
"Make sure you know the target card credit key. Typical `--ki 1` or `--ki 3`\n",
|
||||
"hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA -k 001122334455667B -s 300 -e 600\n"
|
||||
"hf iclass tear --blk 10 -d AAAAAAAAAAAAAAAA --ki 0 -s 300 -e 600\n"
|
||||
"hf iclass tear --blk 2 -d fdffffffffffffff --ki 1 --credit -s 400 -e 500"
|
||||
@@ -3011,7 +3008,8 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
bool verbose = arg_get_lit(ctx, 10);
|
||||
bool shallow_mod = arg_get_lit(ctx, 11);
|
||||
|
||||
int tearoff_start = arg_get_int_def(ctx, 12, 5000);
|
||||
int tearoff_start = arg_get_int_def(ctx, 12, 100);
|
||||
int tearoff_original_start = tearoff_start; // save original start value for later use
|
||||
int tearoff_increment = arg_get_int_def(ctx, 13, 10);
|
||||
int tearoff_end = arg_get_int_def(ctx, 14, tearoff_start + tearoff_increment + 500);
|
||||
int tearoff_loop = arg_get_int_def(ctx, 15, 1);
|
||||
@@ -3034,18 +3032,19 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
PrintAndLogEx(ERR, "Key is incorrect length");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
|
||||
} else if (key_nr >= 0) {
|
||||
|
||||
if (key_nr >= 0) {
|
||||
if (key_nr < ICLASS_KEYS_MAX) {
|
||||
auth = true;
|
||||
memcpy(key, iClass_Key_Table[key_nr], 8);
|
||||
PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex(iClass_Key_Table[key_nr], 8));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), key_nr, sprint_hex_inrow(iClass_Key_Table[key_nr], 8));
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Key number is invalid");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (data_len != 8) {
|
||||
@@ -3059,17 +3058,22 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
}
|
||||
|
||||
if (tearoff_end <= tearoff_start) {
|
||||
PrintAndLogEx(ERR, "Tearoff end delay must be bigger than the start delay.");
|
||||
PrintAndLogEx(ERR, "Tearoff end delay must be larger than the start delay");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (tearoff_start < 0 || tearoff_end <= 0) {
|
||||
PrintAndLogEx(ERR, "Tearoff start/end delays should be bigger than 0.");
|
||||
if (tearoff_start <= 0) {
|
||||
PrintAndLogEx(ERR, "Tearoff_start delays must be larger than 0");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (tearoff_end <= 0) {
|
||||
PrintAndLogEx(ERR, "Tearoff_end delays must be larger than 0");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if ((use_replay + rawkey + elite) > 1) {
|
||||
PrintAndLogEx(ERR, "Can not use a combo of 'elite', 'raw', 'nr'");
|
||||
PrintAndLogEx(ERR, "Can not use a combo of `--elite`, `--raw`, `--nr`");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
@@ -3087,6 +3091,10 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
PrintAndLogEx(SUCCESS, "No key supplied. Trying no authentication read/writes");
|
||||
}
|
||||
|
||||
if (tearoff_loop > 1) {
|
||||
PrintAndLogEx(SUCCESS, _YELLOW_("%u") " attempts / tearoff", tearoff_loop);
|
||||
}
|
||||
|
||||
if (tearoff_sleep) {
|
||||
PrintAndLogEx(SUCCESS, "Using " _YELLOW_("%u") " ms delay between attempts", tearoff_sleep);
|
||||
}
|
||||
@@ -3129,7 +3137,14 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
auth = false;
|
||||
}
|
||||
|
||||
//perform initial read here, repeat if failed or 00s
|
||||
if (pagemap == 0x0) {
|
||||
PrintAndLogEx(WARNING, _RED_("No auth possible. Read only if RA is enabled"));
|
||||
goto out;
|
||||
}
|
||||
|
||||
bool read_auth = auth;
|
||||
|
||||
// perform initial read here, repeat if failed or 00s
|
||||
uint8_t data_read_orig[8] = {0};
|
||||
uint8_t ff_data[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
bool first_read = false;
|
||||
@@ -3149,6 +3164,9 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
reread = false;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Original block data... " _CYAN_("%s"), sprint_hex_inrow(data_read_orig, sizeof(data_read_orig)));
|
||||
PrintAndLogEx(SUCCESS, "New data to write..... " _YELLOW_("%s"), sprint_hex_inrow(data, sizeof(data)));
|
||||
PrintAndLogEx(SUCCESS, "Target block.......... " _YELLOW_("%u") " / " _YELLOW_("0x%02x"), blockno, blockno);
|
||||
// turn off Device side debug messages
|
||||
uint8_t dbg_curr = DBG_NONE;
|
||||
if (getDeviceDebugLevel(&dbg_curr) != PM3_SUCCESS) {
|
||||
@@ -3159,11 +3177,16 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
return PM3_EFAILED;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Starting tear off against block " _YELLOW_("%u") " / " _YELLOW_("0x%02x"), blockno, blockno);
|
||||
PrintAndLogEx(INFO, "");
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to abort");
|
||||
// clear trace log
|
||||
SendCommandNG(CMD_BUFF_CLEAR, NULL, 0);
|
||||
|
||||
while (tearoff_start <= tearoff_end && read_ok == false) {
|
||||
PrintAndLogEx(INFO, "---------------------------------------");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("<Enter>") " to exit");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--------------- " _CYAN_("start") " -----------------\n");
|
||||
// Main loop
|
||||
while ((tearoff_start <= tearoff_end) && (read_ok == false)) {
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
PrintAndLogEx(WARNING, "\naborted via keyboard.");
|
||||
@@ -3174,7 +3197,7 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
// set tear off trigger
|
||||
clearCommandBuffer();
|
||||
tearoff_params_t params = {
|
||||
.delay_us = tearoff_start,
|
||||
.delay_us = (tearoff_start & 0xFFFF),
|
||||
.on = true,
|
||||
.off = false
|
||||
};
|
||||
@@ -3186,18 +3209,22 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
// write
|
||||
// don't check the return value. As a tear-off occurred, the write failed.
|
||||
//PrintAndLogEx(NORMAL, "\r" NOLF);
|
||||
PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%d")" / "_YELLOW_("%d")" us", tearoff_start, tearoff_end);
|
||||
iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, verbose, auth, shallow_mod);
|
||||
if (tearoff_loop > 1) {
|
||||
PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us - "_YELLOW_("%3u")" loops", params.delay_us, (tearoff_end & 0xFFFF), loop_count + 1);
|
||||
} else {
|
||||
PrintAndLogEx(INPLACE, " Tear off delay "_YELLOW_("%u")" / "_YELLOW_("%d")" us", params.delay_us, (tearoff_end & 0xFFFF));
|
||||
}
|
||||
|
||||
//read the data back
|
||||
// write block - don't check the return value. As a tear-off occurred, the write failed.
|
||||
// when tear off is enabled, the return code will always be PM3_ETEAROFF
|
||||
iclass_write_block(blockno, data, mac, key, use_credit_key, elite, rawkey, use_replay, false, auth, shallow_mod);
|
||||
|
||||
// read the data back
|
||||
uint8_t data_read[8] = {0};
|
||||
first_read = false;
|
||||
reread = false;
|
||||
bool decrease = false;
|
||||
|
||||
int readcount = 0;
|
||||
while (first_read == false) {
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
@@ -3206,7 +3233,12 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, auth, shallow_mod, data_read, false);
|
||||
// skip authentication for config and e-purse blocks (1,2)
|
||||
if (blockno < 3) {
|
||||
read_auth = false;
|
||||
}
|
||||
|
||||
res = iclass_read_block_ex(key, blockno, keyType, elite, rawkey, use_replay, verbose, read_auth, shallow_mod, data_read, false);
|
||||
if (res == PM3_SUCCESS && !reread) {
|
||||
if (memcmp(data_read, zeros, 8) == 0) {
|
||||
reread = true;
|
||||
@@ -3220,10 +3252,21 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
} else if (res != PM3_SUCCESS) {
|
||||
decrease = true;
|
||||
}
|
||||
if (readcount >= 10){
|
||||
PrintAndLogEx(WARNING, "\n"_RED_("Read failed too many times, giving up"));
|
||||
isok = PM3_EFAILED;
|
||||
goto out;
|
||||
}
|
||||
readcount++;
|
||||
}
|
||||
|
||||
if (decrease && tearoff_start > 0) { // if there was an error reading repeat the tearoff with the same delay
|
||||
// if there was an error reading repeat the tearoff with the same delay
|
||||
if (decrease && (tearoff_start > tearoff_increment) && (tearoff_start >= tearoff_original_start)) {
|
||||
tearoff_start -= tearoff_increment;
|
||||
if(verbose){
|
||||
PrintAndLogEx(INFO, " -> Read failed, retearing with "_CYAN_("%u")" us", tearoff_start);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool tear_success = true;
|
||||
@@ -3233,46 +3276,86 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
tear_success = false;
|
||||
}
|
||||
|
||||
if ((tear_success == false) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) { // tearoff succeeded (partially)
|
||||
if ((tear_success == false) && (memcmp(data_read, zeros, 8) != 0) && (memcmp(data_read, data_read_orig, 8) != 0)) {
|
||||
|
||||
// tearoff succeeded (partially)
|
||||
|
||||
expected_values = false;
|
||||
|
||||
if (memcmp(data_read, ff_data, 8) == 0 && memcmp(data_read_orig, ff_data, 8) != 0) {
|
||||
erase_phase = true;
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, _BLUE_("Erase phase hit: ALL ONES"));
|
||||
PrintAndLogEx(SUCCESS, _CYAN_("Erase phase hit... ALL ONES"));
|
||||
iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: ");
|
||||
} else {
|
||||
|
||||
if (erase_phase) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, _MAGENTA_("Tearing! Write Phase (post erase)"));
|
||||
PrintAndLogEx(SUCCESS, _MAGENTA_("Tearing! Write phase (post erase)"));
|
||||
iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: ");
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, _CYAN_("Tearing! (unknown phase)"));
|
||||
PrintAndLogEx(SUCCESS, _CYAN_("Tearing! unknown phase"));
|
||||
iclass_cmp_print(data_read_orig, data_read, "Original: ", "Read: ");
|
||||
}
|
||||
}
|
||||
|
||||
bool goto_out = false;
|
||||
if (blockno == 2) {
|
||||
if (memcmp(data_read, ff_data, 8) == 0 && memcmp(data_read_orig, ff_data, 8) != 0) {
|
||||
PrintAndLogEx(SUCCESS, "E-purse has been teared ( %s )", _GREEN_("ok"));
|
||||
PrintAndLogEx(HINT, "Hint: try `hf iclass creditepurse -d FEFFFEFF --ki 1`");
|
||||
PrintAndLogEx(HINT, "Hint: try `hf iclass wrbl -d 'FFFFFFFF FFFF FEFF' --blk 2 --ki 1 --credit`");
|
||||
isok = PM3_SUCCESS;
|
||||
goto_out = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (blockno == 1) {
|
||||
if (data_read[0] != data_read_orig[0]) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Application limit changed, from %u to %u", data_read_orig[0], data_read[0]);
|
||||
PrintAndLogEx(SUCCESS, "Application limit changed, from "_YELLOW_("%u")" to "_YELLOW_("%u"), data_read_orig[0], data_read[0]);
|
||||
isok = PM3_SUCCESS;
|
||||
goto out;
|
||||
goto_out = true;
|
||||
}
|
||||
|
||||
if (data_read[7] != data_read_orig[7]) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "Fuse changed, from %02x to %02x", data_read_orig[7], data_read[7]);
|
||||
PrintAndLogEx(SUCCESS, "Fuse changed, from "_YELLOW_("%02x")" to "_YELLOW_("%02x"), data_read_orig[7], data_read[7]);
|
||||
|
||||
const char *flag_names[8] = {
|
||||
"RA",
|
||||
"Fprod0",
|
||||
"Fprod1",
|
||||
"Crypt0 (*1)",
|
||||
"Crypt1 (*0)",
|
||||
"Coding0",
|
||||
"Coding1",
|
||||
"Fpers (*1)"
|
||||
};
|
||||
PrintAndLogEx(INFO, _YELLOW_("%-10s %-10s %-10s"), "Fuse", "Original", "Changed");
|
||||
PrintAndLogEx(INFO, "---------------------------------------");
|
||||
for (int i = 7; i >= 0; --i) {
|
||||
int bit1 = (data_read_orig[7] >> i) & 1;
|
||||
int bit2 = (data_read[7] >> i) & 1;
|
||||
PrintAndLogEx(INFO, "%-11s %-10d %-10d", flag_names[i], bit1, bit2);
|
||||
}
|
||||
|
||||
isok = PM3_SUCCESS;
|
||||
goto_out = true;
|
||||
}
|
||||
|
||||
// if more OTP bits set..
|
||||
if (data_read[1] > data_read_orig[1] ||
|
||||
data_read[2] > data_read_orig[2]) {
|
||||
PrintAndLogEx(SUCCESS, "More OTP bits got set!!!");
|
||||
isok = PM3_SUCCESS;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
} else { // tearoff did not succeed
|
||||
// PrintAndLogEx(INFO, "Expected: %s", sprint_hex_inrow(data, sizeof(data)));
|
||||
// PrintAndLogEx(INFO, "Read: %s", sprint_hex_inrow(data_read, sizeof(data_read)));
|
||||
if (goto_out) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (tear_success) { // tearoff succeeded with expected values
|
||||
@@ -3282,9 +3365,9 @@ static int CmdHFiClass_TearBlock(const char *Cmd) {
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "Read: " _GREEN_("%s") " %s"
|
||||
, sprint_hex_inrow(data_read, sizeof(data_read)),
|
||||
(expected_values) ? _GREEN_(" -> Expected values!") : ""
|
||||
);
|
||||
, sprint_hex_inrow(data_read, sizeof(data_read)),
|
||||
(expected_values) ? _GREEN_(" -> Expected values!") : ""
|
||||
);
|
||||
}
|
||||
|
||||
loop_count++;
|
||||
@@ -3315,6 +3398,8 @@ out:
|
||||
};
|
||||
handle_tearoff(¶ms, false);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "Done!");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
clearCommandBuffer();
|
||||
return isok;
|
||||
}
|
||||
@@ -5842,7 +5927,7 @@ int info_iclass(bool shallow_mod) {
|
||||
} else {
|
||||
|
||||
if ((r->status & FLAG_ICLASS_CC) == FLAG_ICLASS_CC) {
|
||||
PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
|
||||
PrintAndLogEx(SUCCESS, "E-purse: %s card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse)));
|
||||
}
|
||||
|
||||
if (memcmp(hdr->key_d, zeros, sizeof(zeros))) {
|
||||
@@ -5899,10 +5984,10 @@ int info_iclass(bool shallow_mod) {
|
||||
uint8_t cardtype = get_mem_config(hdr);
|
||||
PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]);
|
||||
|
||||
if (HF14B_picopass_reader(false, false)) {
|
||||
PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("Old Silicon (14b support)"));
|
||||
} else {
|
||||
if (memcmp(hdr->csn + 4, "\xFE\xFF\x12\xE0", 4) == 0) {
|
||||
PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("NEW Silicon (No 14b support)"));
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, " Card chip.... "_YELLOW_("Old Silicon (14b support)"));
|
||||
}
|
||||
if (legacy) {
|
||||
|
||||
@@ -5941,5 +6026,6 @@ int info_iclass(bool shallow_mod) {
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ static int lto_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint16
|
||||
SendCommandMIX(CMD_HF_ISO14443A_READER, arg0, arg1, 0, cmd, len);
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
+313
-7
@@ -48,6 +48,301 @@
|
||||
#include "mifare/mifarehost.h"
|
||||
#include "crypto/originality.h"
|
||||
|
||||
|
||||
// Defines for Saflok parsing
|
||||
#define SAFLOK_YEAR_OFFSET 1980
|
||||
#define SAFLOK_BASIC_ACCESS_BYTE_NUM 17
|
||||
#define SAFLOK_KEY_LENGTH 6
|
||||
#define SAFLOK_UID_LENGTH 4 // Matches Mifare 4-byte UID
|
||||
#define SAFLOK_MAGIC_TABLE_SIZE 192
|
||||
#define SAFLOK_CHECK_SECTOR 1
|
||||
|
||||
typedef struct {
|
||||
uint64_t a;
|
||||
uint64_t b;
|
||||
} MfClassicKeyPair;
|
||||
|
||||
|
||||
// Structure for Saflok key levels
|
||||
typedef struct {
|
||||
uint8_t level_num;
|
||||
const char *level_name;
|
||||
} SaflokKeyLevel;
|
||||
|
||||
// Static array for Saflok key levels
|
||||
static const SaflokKeyLevel saflok_key_levels[] = {
|
||||
{1, "Guest Key"},
|
||||
{2, "Connectors"},
|
||||
{3, "Suite"},
|
||||
{4, "Limited Use"},
|
||||
{5, "Failsafe"},
|
||||
{6, "Inhibit"},
|
||||
{7, "Pool/Meeting Master"},
|
||||
{8, "Housekeeping"},
|
||||
{9, "Floor Key"},
|
||||
{10, "Section Key"},
|
||||
{11, "Rooms Master"},
|
||||
{12, "Grand Master"},
|
||||
{13, "Emergency"},
|
||||
{14, "Electronic Lockout"},
|
||||
{15, "Secondary Programming Key (SPK)"},
|
||||
{16, "Primary Programming Key (PPK)"},
|
||||
};
|
||||
|
||||
// Lookup table for Saflok decryption
|
||||
static const uint8_t saflok_c_aDecode[256] = {
|
||||
0xEA, 0x0D, 0xD9, 0x74, 0x4E, 0x28, 0xFD, 0xBA, 0x7B, 0x98, 0x87, 0x78, 0xDD, 0x8D, 0xB5,
|
||||
0x1A, 0x0E, 0x30, 0xF3, 0x2F, 0x6A, 0x3B, 0xAC, 0x09, 0xB9, 0x20, 0x6E, 0x5B, 0x2B, 0xB6,
|
||||
0x21, 0xAA, 0x17, 0x44, 0x5A, 0x54, 0x57, 0xBE, 0x0A, 0x52, 0x67, 0xC9, 0x50, 0x35, 0xF5,
|
||||
0x41, 0xA0, 0x94, 0x60, 0xFE, 0x24, 0xA2, 0x36, 0xEF, 0x1E, 0x6B, 0xF7, 0x9C, 0x69, 0xDA,
|
||||
0x9B, 0x6F, 0xAD, 0xD8, 0xFB, 0x97, 0x62, 0x5F, 0x1F, 0x38, 0xC2, 0xD7, 0x71, 0x31, 0xF0,
|
||||
0x13, 0xEE, 0x0F, 0xA3, 0xA7, 0x1C, 0xD5, 0x11, 0x4C, 0x45, 0x2C, 0x04, 0xDB, 0xA6, 0x2E,
|
||||
0xF8, 0x64, 0x9A, 0xB8, 0x53, 0x66, 0xDC, 0x7A, 0x5D, 0x03, 0x07, 0x80, 0x37, 0xFF, 0xFC,
|
||||
0x06, 0xBC, 0x26, 0xC0, 0x95, 0x4A, 0xF1, 0x51, 0x2D, 0x22, 0x18, 0x01, 0x79, 0x5E, 0x76,
|
||||
0x1D, 0x7F, 0x14, 0xE3, 0x9E, 0x8A, 0xBB, 0x34, 0xBF, 0xF4, 0xAB, 0x48, 0x63, 0x55, 0x3E,
|
||||
0x56, 0x8C, 0xD1, 0x12, 0xED, 0xC3, 0x49, 0x8E, 0x92, 0x9D, 0xCA, 0xB1, 0xE5, 0xCE, 0x4D,
|
||||
0x3F, 0xFA, 0x73, 0x05, 0xE0, 0x4B, 0x93, 0xB2, 0xCB, 0x08, 0xE1, 0x96, 0x19, 0x3D, 0x83,
|
||||
0x39, 0x75, 0xEC, 0xD6, 0x3C, 0xD0, 0x70, 0x81, 0x16, 0x29, 0x15, 0x6C, 0xC7, 0xE7, 0xE2,
|
||||
0xF6, 0xB7, 0xE8, 0x25, 0x6D, 0x3A, 0xE6, 0xC8, 0x99, 0x46, 0xB0, 0x85, 0x02, 0x61, 0x1B,
|
||||
0x8B, 0xB3, 0x9F, 0x0B, 0x2A, 0xA8, 0x77, 0x10, 0xC1, 0x88, 0xCC, 0xA4, 0xDE, 0x43, 0x58,
|
||||
0x23, 0xB4, 0xA1, 0xA5, 0x5C, 0xAE, 0xA9, 0x7E, 0x42, 0x40, 0x90, 0xD2, 0xE9, 0x84, 0xCF,
|
||||
0xE4, 0xEB, 0x47, 0x4F, 0x82, 0xD4, 0xC5, 0x8F, 0xCD, 0xD3, 0x86, 0x00, 0x59, 0xDF, 0xF2,
|
||||
0x0C, 0x7C, 0xC6, 0xBD, 0xF9, 0x7D, 0xC4, 0x91, 0x27, 0x89, 0x32, 0x72, 0x33, 0x65, 0x68,
|
||||
0xAF
|
||||
};
|
||||
|
||||
// Function to decrypt Saflok card data
|
||||
static void DecryptSaflokCardData(
|
||||
const uint8_t strCard[SAFLOK_BASIC_ACCESS_BYTE_NUM],
|
||||
// int length, // length is always SAFLOK_BASIC_ACCESS_BYTE_NUM
|
||||
uint8_t decryptedCard[SAFLOK_BASIC_ACCESS_BYTE_NUM]) {
|
||||
int i;
|
||||
int num;
|
||||
int num2;
|
||||
int num3;
|
||||
int num4;
|
||||
int b = 0;
|
||||
int b2 = 0;
|
||||
|
||||
for (i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM; i++) {
|
||||
num = saflok_c_aDecode[strCard[i]] - (i + 1);
|
||||
if (num < 0) num += 256;
|
||||
decryptedCard[i] = num;
|
||||
}
|
||||
|
||||
b = decryptedCard[10];
|
||||
b2 = b & 1;
|
||||
|
||||
for (num2 = SAFLOK_BASIC_ACCESS_BYTE_NUM; num2 > 0; num2--) {
|
||||
b = decryptedCard[num2 - 1];
|
||||
for (num3 = 8; num3 > 0; num3--) {
|
||||
num4 = num2 + num3;
|
||||
if (num4 > SAFLOK_BASIC_ACCESS_BYTE_NUM) num4 -= SAFLOK_BASIC_ACCESS_BYTE_NUM;
|
||||
int b3 = decryptedCard[num4 - 1];
|
||||
int b4 = (b3 & 0x80) >> 7;
|
||||
b3 = ((b3 << 1) & 0xFF) | b2;
|
||||
b2 = (b & 0x80) >> 7;
|
||||
b = ((b << 1) & 0xFF) | b4;
|
||||
decryptedCard[num4 - 1] = b3;
|
||||
}
|
||||
decryptedCard[num2 - 1] = b;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to calculate Saflok checksum
|
||||
static uint8_t CalculateCheckSum(uint8_t data[SAFLOK_BASIC_ACCESS_BYTE_NUM]) {
|
||||
int sum = 0;
|
||||
for (int i = 0; i < SAFLOK_BASIC_ACCESS_BYTE_NUM - 1; i++) {
|
||||
sum += data[i];
|
||||
}
|
||||
sum = 255 - (sum & 0xFF);
|
||||
return sum & 0xFF;
|
||||
}
|
||||
|
||||
// Function to parse and print Saflok data
|
||||
static void ParseAndPrintSaflokData(const sector_t* sector0_info, const sector_t* sector1_info) {
|
||||
(void)sector1_info; // Not directly used for payload parsing currently
|
||||
|
||||
if (!sector0_info) {
|
||||
PrintAndLogEx(WARNING, "Saflok: Sector 0 information not available for parsing.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t key_bytes_for_s0[MIFARE_KEY_SIZE];
|
||||
uint8_t key_type_for_s0; // CORRECTED: Was MifareKeyType, now uint8_t
|
||||
bool s0_key_found = false;
|
||||
|
||||
// Prioritize Key A for Sector 0 if available
|
||||
if (sector0_info->foundKey[MF_KEY_A]) {
|
||||
num_to_bytes(sector0_info->Key[MF_KEY_A], MIFARE_KEY_SIZE, key_bytes_for_s0);
|
||||
key_type_for_s0 = MF_KEY_A; // MF_KEY_A is typically #define'd as 0x60
|
||||
s0_key_found = true;
|
||||
PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key A for reading blocks.");
|
||||
} else if (sector0_info->foundKey[MF_KEY_B]) { // Fallback to Key B for Sector 0
|
||||
num_to_bytes(sector0_info->Key[MF_KEY_B], MIFARE_KEY_SIZE, key_bytes_for_s0);
|
||||
key_type_for_s0 = MF_KEY_B; // MF_KEY_B is typically #define'd as 0x61
|
||||
s0_key_found = true;
|
||||
PrintAndLogEx(DEBUG, "Saflok: Using Sector 0 Key B for reading blocks.");
|
||||
}
|
||||
|
||||
if (!s0_key_found) {
|
||||
PrintAndLogEx(WARNING, "Saflok: No known keys for Sector 0. Cannot read blocks 1 & 2 for parsing.");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t block1_content[MFBLOCK_SIZE];
|
||||
uint8_t block2_content[MFBLOCK_SIZE];
|
||||
|
||||
// Read absolute block 1 (data block within sector 0)
|
||||
if (mf_read_block(1, key_type_for_s0, key_bytes_for_s0, block1_content) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 1 using Sector 0 %s key.", (key_type_for_s0 == MF_KEY_A) ? "A" : "B");
|
||||
return;
|
||||
}
|
||||
PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 1.");
|
||||
|
||||
// Read absolute block 2 (data block within sector 0)
|
||||
if (mf_read_block(2, key_type_for_s0, key_bytes_for_s0, block2_content) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(WARNING, "Saflok: Failed to read card Block 2 using Sector 0 %s key.", (key_type_for_s0 == MF_KEY_A) ? "A" : "B");
|
||||
return;
|
||||
}
|
||||
PrintAndLogEx(DEBUG, "Saflok: Successfully read card Block 2.");
|
||||
|
||||
uint8_t basicAccess[SAFLOK_BASIC_ACCESS_BYTE_NUM];
|
||||
uint8_t decodedBA[SAFLOK_BASIC_ACCESS_BYTE_NUM];
|
||||
|
||||
memcpy(basicAccess, block1_content, 16); // 16 bytes from Block 1
|
||||
memcpy(basicAccess + 16, block2_content, 1); // 1 byte from Block 2
|
||||
|
||||
DecryptSaflokCardData(basicAccess, decodedBA);
|
||||
|
||||
|
||||
// Byte 0: Key level, LED warning bit, and subgroup functions
|
||||
uint8_t key_level = (decodedBA[0] & 0xF0) >> 4;
|
||||
uint8_t led_warning = (decodedBA[0] & 0x08) >> 3;
|
||||
|
||||
// Byte 1: Key ID
|
||||
uint8_t key_id = decodedBA[1];
|
||||
|
||||
// Byte 2 & 3: KeyRecord, including OpeningKey flag
|
||||
uint8_t key_record_high = decodedBA[2] & 0x7F;
|
||||
uint8_t opening_key = (decodedBA[2] & 0x80) >> 7;
|
||||
uint16_t key_record = (key_record_high << 8) | decodedBA[3];
|
||||
|
||||
// Byte 5 & 6: EncryptSequence + Combination
|
||||
uint16_t sequence_combination_number = ((decodedBA[5] & 0x0F) << 8) | decodedBA[6];
|
||||
|
||||
// Byte 7: OverrideDeadbolt and Days
|
||||
uint8_t override_deadbolt = (decodedBA[7] & 0x80) >> 7;
|
||||
uint8_t restricted_weekday = decodedBA[7] & 0x7F;
|
||||
|
||||
// Weekday names array
|
||||
static const char *weekdays[] = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"};
|
||||
|
||||
// Buffer to store the resulting string (sufficient size for all weekdays)
|
||||
char restricted_weekday_string[128] = {0};
|
||||
int restricted_count = 0;
|
||||
|
||||
// Check each bit from Monday to Sunday
|
||||
for (int i = 0; i < 7; i++) {
|
||||
if (restricted_weekday & (0b01000000 >> i)) {
|
||||
// If the bit is set, append the corresponding weekday to the buffer
|
||||
if (restricted_count > 0) {
|
||||
strcat(restricted_weekday_string, ", ");
|
||||
}
|
||||
strcat(restricted_weekday_string, weekdays[i]);
|
||||
restricted_count++;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine if all weekdays are restricted
|
||||
if (restricted_weekday == 0b01111100) {
|
||||
strcpy(restricted_weekday_string, "weekdays");
|
||||
}
|
||||
// If there are specific restricted days
|
||||
else if (restricted_weekday == 0b00000011) {
|
||||
strcpy(restricted_weekday_string, "weekends");
|
||||
}
|
||||
// If no weekdays are restricted
|
||||
else if (restricted_weekday == 0) {
|
||||
strcpy(restricted_weekday_string, "none");
|
||||
}
|
||||
|
||||
// Bytes 14-15: Property number and part of creation year
|
||||
uint8_t creation_year_high_bits = (decodedBA[14] & 0xF0);
|
||||
uint16_t property_id = ((decodedBA[14] & 0x0F) << 8) | decodedBA[15];
|
||||
|
||||
// Bytes 11-13: Creation date since SAFLOK_YEAR_OFFSET Jan 1st
|
||||
uint16_t creation_year = (((decodedBA[11] & 0xF0) >> 4) + SAFLOK_YEAR_OFFSET) | creation_year_high_bits;
|
||||
uint8_t creation_month = decodedBA[11] & 0x0F;
|
||||
uint8_t creation_day = (decodedBA[12] >> 3) & 0x1F;
|
||||
uint8_t creation_hour = ((decodedBA[12] & 0x07) << 2) | ((decodedBA[13] & 0xC0) >> 6);
|
||||
uint8_t creation_minute = decodedBA[13] & 0x3F;
|
||||
|
||||
// Bytes 8-10: Expiry interval / absolute time components
|
||||
uint8_t interval_year_val = (decodedBA[8] >> 4);
|
||||
uint8_t interval_month_val = decodedBA[8] & 0x0F;
|
||||
uint8_t interval_day_val = (decodedBA[9] >> 3) & 0x1F;
|
||||
uint8_t expiry_hour = ((decodedBA[9] & 0x07) << 2) | ((decodedBA[10] & 0xC0) >> 6);
|
||||
uint8_t expiry_minute = decodedBA[10] & 0x3F;
|
||||
|
||||
uint16_t expire_year = creation_year + interval_year_val;
|
||||
uint8_t expire_month = creation_month + interval_month_val;
|
||||
uint8_t expire_day = creation_day + interval_day_val;
|
||||
|
||||
// Handle month rollover for expiration
|
||||
while (expire_month > 12) {
|
||||
expire_month -= 12;
|
||||
expire_year++;
|
||||
}
|
||||
|
||||
// Handle day rollover for expiration
|
||||
static const uint8_t days_in_month_lookup[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; // 1-indexed month
|
||||
if (expire_month > 0 && expire_month <= 12) {
|
||||
while (true) {
|
||||
uint8_t max_days = days_in_month_lookup[expire_month];
|
||||
if (expire_month == 2 && (expire_year % 4 == 0 && (expire_year % 100 != 0 || expire_year % 400 == 0))) {
|
||||
max_days = 29; // Leap year
|
||||
}
|
||||
if (expire_day <= max_days) {
|
||||
break;
|
||||
}
|
||||
if (max_days == 0) { // Should not happen with valid month
|
||||
PrintAndLogEx(WARNING, "Saflok: Invalid day/month for expiration rollover calculation.");
|
||||
break;
|
||||
}
|
||||
expire_day -= max_days;
|
||||
expire_month++;
|
||||
if (expire_month > 12) {
|
||||
expire_month = 1;
|
||||
expire_year++;
|
||||
}
|
||||
}
|
||||
} else if (expire_month != 0) { // Allow 0 if it signifies no expiration or error
|
||||
PrintAndLogEx(WARNING, "Saflok: Invalid expiration month (%u) before day rollover.", expire_month);
|
||||
}
|
||||
|
||||
uint8_t checksum = decodedBA[16];
|
||||
uint8_t checksum_calculated = CalculateCheckSum(decodedBA);
|
||||
bool checksum_valid = (checksum_calculated == checksum);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Saflok Details"));
|
||||
PrintAndLogEx(SUCCESS, "Key Level: %u (%s)", saflok_key_levels[key_level].level_num, saflok_key_levels[key_level].level_name);
|
||||
PrintAndLogEx(SUCCESS, "LED Warning: %s", led_warning ? "Yes" : "No");
|
||||
PrintAndLogEx(SUCCESS, "Key ID: %u (0x%02X)", key_id, key_id);
|
||||
PrintAndLogEx(SUCCESS, "Key Record: %u (0x%04X)", key_record, key_record);
|
||||
PrintAndLogEx(SUCCESS, "Opening Key: %s", opening_key ? "Yes" : "No");
|
||||
PrintAndLogEx(SUCCESS, "Sequence Number & Combination: %u (0x%02X)", sequence_combination_number, sequence_combination_number);
|
||||
PrintAndLogEx(SUCCESS, "Override Deadbolt: %s", override_deadbolt ? "Yes" : "No");
|
||||
PrintAndLogEx(SUCCESS, "Restricted Weekdays: %s", restricted_weekday_string);
|
||||
PrintAndLogEx(SUCCESS, "Property ID: %u (0x%04X)", property_id, property_id);
|
||||
PrintAndLogEx(SUCCESS, "Creation Date: %04u-%02u-%02u %02u:%02u", creation_year, creation_month, creation_day, creation_hour, creation_minute);
|
||||
PrintAndLogEx(SUCCESS, "Expiration Date: %04u-%02u-%02u %02u:%02u", expire_year, expire_month, expire_day, expiry_hour, expiry_minute);
|
||||
PrintAndLogEx(SUCCESS, "Checksum Valid: %s", checksum_valid ? "Yes" : "No");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
/*
|
||||
@@ -1915,9 +2210,13 @@ static int CmdHF14AMfNested(const char *Cmd) { //TODO: single mode broken? can't
|
||||
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue;
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (resp.status != PM3_SUCCESS) continue;
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t *data = resp.data.asBytes;
|
||||
key64 = bytes_to_num(data + 10, 6);
|
||||
@@ -4005,9 +4304,13 @@ static int CmdHF14AMfChk(const char *Cmd) {
|
||||
SendCommandNG(CMD_HF_MIFARE_READBL, (uint8_t *)&payload, sizeof(mf_readblock_t));
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500)) continue;
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_READBL, &resp, 1500) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (resp.status != PM3_SUCCESS) continue;
|
||||
if (resp.status != PM3_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint8_t *data = resp.data.asBytes;
|
||||
key64 = bytes_to_num(data + 10, MIFARE_KEY_SIZE);
|
||||
@@ -4070,7 +4373,7 @@ out:
|
||||
// Disable fast mode and send a dummy command to make it effective
|
||||
g_conn.block_after_ACK = false;
|
||||
SendCommandNG(CMD_PING, NULL, 0);
|
||||
if (!WaitForResponseTimeout(CMD_PING, NULL, 1000)) {
|
||||
if (WaitForResponseTimeout(CMD_PING, NULL, 1000) == false) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
@@ -6176,7 +6479,9 @@ static int CmdHF14AMfice(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFARE_ACQ_NONCES, blockNo + keyType * 0x100, trgBlockNo + trgKeyType * 0x100, flags, NULL, 0);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 3000)) goto out;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 3000) == false) {
|
||||
goto out;
|
||||
}
|
||||
if (resp.oldarg[0]) goto out;
|
||||
|
||||
uint32_t items = resp.oldarg[2];
|
||||
@@ -9879,8 +10184,9 @@ static int CmdHF14AMfInfo(const char *Cmd) {
|
||||
PrintAndLogEx(SUCCESS, "unknown");
|
||||
}
|
||||
|
||||
if (e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) {
|
||||
if (keycnt > 1 && e_sector != NULL && e_sector[1].foundKey[MF_KEY_A] && (e_sector[1].Key[MF_KEY_A] == 0x2A2C13CC242A)) {
|
||||
PrintAndLogEx(SUCCESS, "dormakaba Saflok detected");
|
||||
ParseAndPrintSaflokData(&e_sector[0], &e_sector[1]);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
@@ -4628,7 +4628,7 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
||||
|
||||
// we be getting ACK that we are silently ignoring here..
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000)) {
|
||||
if (WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000) == false) {
|
||||
PrintAndLogEx(WARNING, "Failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
@@ -4649,11 +4649,13 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
||||
got_post = true;
|
||||
}
|
||||
}
|
||||
if (! got_post) {
|
||||
|
||||
if (!got_post) {
|
||||
PrintAndLogEx(FAILED, "Failed to read block BEFORE");
|
||||
error_retries++;
|
||||
continue; // try again
|
||||
}
|
||||
|
||||
error_retries = 0;
|
||||
char prestr[20] = {0};
|
||||
snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre)));
|
||||
@@ -4936,7 +4938,7 @@ static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
PacketResponseNG resp;
|
||||
SendCommandNG(CMD_HF_MFU_COUNTER_TEAROFF, (uint8_t*)&payload, sizeof(payload));
|
||||
if (!WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000)) {
|
||||
if (WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000) == false) {
|
||||
PrintAndLogEx(WARNING, "\ntear off command failed");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -664,7 +664,7 @@ static int CmdHFTexkomReader(const char *Cmd) {
|
||||
SendCommandNG(CMD_HF_ACQ_RAW_ADC, (uint8_t *)&samplesCount, sizeof(uint32_t));
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500)) {
|
||||
if (WaitForResponseTimeout(CMD_HF_ACQ_RAW_ADC, &resp, 2500) == false) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user