modified hf 14a apdu to report back when extending time and also added a possibililty to interrupt the extension loop with button press or usb commad. A bunch of minor textual changes

This commit is contained in:
iceman1001 2025-03-20 19:58:13 +01:00
commit b4cc21c68f
19 changed files with 99 additions and 57 deletions

View file

@ -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 14a apdu` - now can be interrupted and dynamically adds time (@iceman1001)
- Changed `trace list -t` - shortend the hitag types (@iceman1001)
- Added Be-Tech identification (@iceman1001)
- Added `lf em 410x clone --htu` clone EM410x ID to Hitag µ/8265 (@douniwan5788)

View file

@ -113,26 +113,26 @@ static em4x70_tag_t g_tag = { 0 };
// on the tag sending the header, and then receive a number of bits from the tag:
//
// #define EM4X70_COMMAND_ID 0x01 // 0b0001 --> 0b001'1
// Tag: [LIW] [Header][ID₃₁..ID₀][LIW]
// Tag: [LIW] [Header][ID31..ID0][LIW]
// Reader: [RM][Command]
// Bits Sent: RM + 4 bits
// Bits Recv: Header + 32 bits
//
// #define EM4X70_COMMAND_UM1 0x02 // 0b0010 --> 0b010'1
// Tag: [LIW] [Header][LB₁, LB₀, UM1₂₉..UM1₀][LIW]
// Tag: [LIW] [Header][LB1, LB0, UM129..UM10][LIW]
// Reader: [RM][Command]
// Bits Sent: RM + 4 bits
// Bits Recv: Header + 32 bits
//
// #define EM4X70_COMMAND_UM2 0x07 // 0b0111 --> 0b111'1
// Tag: [LIW] [Header][UM2₆₃..UM2₀][LIW]
// Tag: [LIW] [Header][UM263..UM20][LIW]
// Reader: [RM][Command]
// Bits Sent: RM + 4 bits
// Bits Recv: Header + 64 bits
//
// #define EM4X70_COMMAND_AUTH 0x03 // 0b0011 --> 0b011'0
// Tag: [LIW] [Header][g(RN)₁₉..RN₀][LIW]
// Reader: [RM][Command][N₅₅..N₀][0000000][f(RN)₂₇..f(RN)₀]
// Tag: [LIW] [Header][g(RN)19..RN0][LIW]
// Reader: [RM][Command][N55..N0][0000000][f(RN)27..f(RN)0]
// Bits Sent: RM + 95 bits
// Bits Recv: Header + 20 bits
//
@ -143,8 +143,8 @@ static em4x70_tag_t g_tag = { 0 };
// receive a number of bits from the tag:
//
// #define EM4X70_COMMAND_PIN 0x04 // 0b0100 --> 0b100'1
// Tag: [LIW] .. [ACK] .. [Header][ID₃₁..ID₀][LIW]
// Reader: [RM][Command][ID₃₁..ID₀][Pin₃₁..Pin₀] .. ..
// Tag: [LIW] .. [ACK] .. [Header][ID31..ID0][LIW]
// Reader: [RM][Command][ID31..ID0][Pin31..Pin0] .. ..
// Bits Sent: RM + 68 bits
// Bits Recv: Header + 32 bits
//
@ -156,7 +156,7 @@ static em4x70_tag_t g_tag = { 0 };
//
// #define EM4X70_COMMAND_WRITE 0x05 // 0b0101 --> 0b101'0
// Tag: [LIW] .. [ACK] .. [ACK][LIW]
// Reader: [RM][Command][A₃..A₀,Ap][Data5x5] .. ..
// Reader: [RM][Command][A3..A0,Ap][Data5x5] .. ..
// Bits Sent: RM + 34 bits
// Bits Recv: !!!!!!!! NONE !!!!!!!!
//
@ -958,7 +958,7 @@ static bool create_legacy_em4x70_bitstream_for_cmd_auth(em4x70_command_bitstream
uint8_t cmd = 0x6u; // HACK - always sent with cmd parity
result = result && add_nibble_to_bitstream(s, cmd, false);
// Reader: [RM][0][Command][N₅₅..N₀][0000000][f(RN)₂₇..f(RN)₀]
// Reader: [RM][0][Command][N55..N0][0000000][f(RN)27..f(RN)0]
//
// ----> HACK <----- : [ 0 ] == extra bit of zero (!?)
// Command is 4 bits : [ 1 .. 4 ] <---- HACK: Always sent with command parity

View file

@ -2079,13 +2079,16 @@ static void TransmitFor14443a(const uint8_t *cmd, uint16_t len, uint32_t *timing
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD);
if (timing) {
if (*timing == 0) // Measure time
if (*timing == 0) { // Measure time
*timing = (GetCountSspClk() + 8) & 0xfffffff8;
else
} else {
PrepareDelayedTransfer(*timing & 0x00000007); // Delay transfer (fine tuning - up to 7 MF clock ticks)
}
while (GetCountSspClk() < (*timing & 0xfffffff8)) {}; // Delay transfer (multiple of 8 MF clock ticks)
LastTimeProxToAirStart = *timing;
} else {
uint32_t ThisTransferTime = 0;
@ -3131,27 +3134,41 @@ int iso14_apdu(uint8_t *cmd, uint16_t cmd_len, bool send_chaining, void *data, u
return 0; // DATA LINK ERROR
}
uint32_t save_iso14a_timeout = iso14a_get_timeout();
// S-Block WTX
while (len && ((data_bytes[0] & 0xF2) == 0xF2)) {
uint32_t save_iso14a_timeout = iso14a_get_timeout();
// temporarily increase timeout
iso14a_set_timeout(MAX((data_bytes[1] & 0x3f) * save_iso14a_timeout, MAX_ISO14A_TIMEOUT));
// Transmit WTX back
if (BUTTON_PRESS() || data_available()) {
BigBuf_free();
return -3;
}
// Inform client of WTX of timeout in ms
// 38ms == MAX_ISO14A_TIMEOUT
send_wtx(38);
// byte1 - WTXM [1..59]. command FWT=FWT*WTXM
data_bytes[1] = data_bytes[1] & 0x3f; // 2 high bits mandatory set to 0b
// now need to fix CRC.
data_bytes[1] &= 0x3F; // 2 high bits mandatory set to 0b
// temporarily increase timeout
// field cycles, 1/1356000
// MAX_ISO14A_TIMEOUT == 524288 / 13560000
// typically 8192 / 13560000
iso14a_set_timeout(MAX(data_bytes[1] * save_iso14a_timeout, MAX_ISO14A_TIMEOUT));
// Transmit WTX back
AddCrc14A(data_bytes, len - 2);
// transmit S-Block
ReaderTransmit(data_bytes, len, NULL);
// retrieve the result again (with increased timeout)
data_bytes[0] = 0x00;
len = ReaderReceive(data, data_len, parity_array);
data_bytes = data;
// restore timeout
iso14a_set_timeout(save_iso14a_timeout);
len = ReaderReceive(data_bytes, data_len, parity_array);
}
// restore timeout
iso14a_set_timeout(save_iso14a_timeout);
// if we received an I- or R(ACK)-Block with a block number equal to the
// current block number, toggle the current block number
if (len >= 3 // PCB+CRC = 3 bytes
@ -3252,6 +3269,9 @@ void ReaderIso14443a(PacketCommandNG *c) {
}
if ((param & ISO14A_APDU) == ISO14A_APDU) {
FpgaDisableTracing();
uint8_t res = 0;
arg0 = iso14_apdu(
cmd,
@ -3261,7 +3281,6 @@ void ReaderIso14443a(PacketCommandNG *c) {
sizeof(buf),
&res
);
FpgaDisableTracing();
reply_mix(CMD_ACK, arg0, res, 0, buf, sizeof(buf));
}
@ -3382,8 +3401,9 @@ void ReaderIso14443a(PacketCommandNG *c) {
}
}
CMD_DONE:
if ((param & ISO14A_REQUEST_TRIGGER) == ISO14A_REQUEST_TRIGGER)
if ((param & ISO14A_REQUEST_TRIGGER) == ISO14A_REQUEST_TRIGGER) {
iso14a_set_trigger(false);
}
if ((param & ISO14A_SET_TIMEOUT) == ISO14A_SET_TIMEOUT) {
iso14a_set_timeout(save_iso14a_timeout);

View file

@ -60,8 +60,8 @@ end
-- waits for answer from pm3 device
local function checkCommand(response)
if not response then
print("Timeout while waiting for response. Increase TIMEOUT in hf_mf_keycheck.lua to wait longer")
return nil, "Timeout while waiting for device to respond"
print("timeout while waiting for reply. Increase TIMEOUT in hf_mf_keycheck.lua to wait longer")
return nil, "timeout while waiting for reply"
end
if response.Status == PM3_SUCCESS then

View file

@ -185,9 +185,7 @@ static uint16_t calcXORchecksum(uint8_t *bytes, uint8_t len, uint32_t mask) {
return 0xFF - calcSumByteXor(bytes, len, mask);
}
//2148050707DB0A0E000001C4000000
// measuring LFSR maximum length
static int CmdAnalyseLfsr(const char *Cmd) {
CLIParserContext *ctx;

View file

@ -2253,7 +2253,7 @@ static int CmdTimeScale(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_dbl1(NULL, "sr", "<float>", "sets timescale factor according to sampling rate"),
arg_str0("u", "unit", "<string>", "time unit to display (max 10 chars)"),
arg_str0("u", "unit", "<str>", "time unit to display (max 10 chars)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);

View file

@ -336,7 +336,7 @@ int CmdHFTune(const char *Cmd) {
uint8_t mode[] = {1};
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
if (WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000) == false) {
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF initialization, aborting");
PrintAndLogEx(WARNING, "timeout while waiting for Proxmark HF initialization, aborting");
return PM3_ETIMEOUT;
}
@ -359,7 +359,7 @@ int CmdHFTune(const char *Cmd) {
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
if (WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000) == false) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF measure, aborting");
PrintAndLogEx(WARNING, "timeout while waiting for Proxmark HF measure, aborting");
break;
}
@ -386,7 +386,7 @@ int CmdHFTune(const char *Cmd) {
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_HF, mode, sizeof(mode));
if (WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_HF, &resp, 1000) == false) {
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark HF shutdown, aborting");
PrintAndLogEx(WARNING, "timeout while waiting for Proxmark HF shutdown, aborting");
return PM3_ETIMEOUT;
}
PrintAndLogEx(NORMAL, "\x1b%c[2K\r", 30);

View file

@ -1280,6 +1280,11 @@ static int CmdExchangeAPDU(bool chainingin, const uint8_t *datain, int datainlen
return PM3_EAPDU_FAIL;
}
// Button pressed / user cancelled
if (iLen == -3) {
PrintAndLogEx(DEBUG, "ERR: APDU: User aborted");
return PM3_EAPDU_FAIL;
}
return PM3_SUCCESS;
}

View file

@ -1358,7 +1358,7 @@ static int CmdConnect(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("p", "port", NULL, "Serial port to connect to, else retry the last used one"),
arg_str0("p", "port", "<str>", "Serial port to connect to, else retry the last used one"),
arg_u64_0("b", "baud", "<dec>", "Baudrate"),
arg_param_end
};

View file

@ -178,7 +178,7 @@ static int CmdLFTune(const char *Cmd) {
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_LF, params, sizeof(params));
if (WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000) == false) {
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark LF initialization, aborting");
PrintAndLogEx(WARNING, "timeout while waiting for Proxmark LF initialization, aborting");
return PM3_ETIMEOUT;
}
@ -202,7 +202,7 @@ static int CmdLFTune(const char *Cmd) {
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_LF, params, sizeof(params));
if (WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000) == false) {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark LF measure, aborting");
PrintAndLogEx(WARNING, "timeout while waiting for Proxmark LF measure, aborting");
break;
}
@ -229,7 +229,7 @@ static int CmdLFTune(const char *Cmd) {
params[0] = 3;
SendCommandNG(CMD_MEASURE_ANTENNA_TUNING_LF, params, sizeof(params));
if (WaitForResponseTimeout(CMD_MEASURE_ANTENNA_TUNING_LF, &resp, 1000) == false) {
PrintAndLogEx(WARNING, "Timeout while waiting for Proxmark LF shutdown, aborting");
PrintAndLogEx(WARNING, "timeout while waiting for Proxmark LF shutdown, aborting");
return PM3_ETIMEOUT;
}

View file

@ -1696,7 +1696,7 @@ int CmdEM4x05Chk(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("f", "file", "<fn>", "loads a default keys dictionary file <*.dic>"),
arg_str0("e", "em", "<EM4100>", "try the calculated password from some cloners based on EM4100 ID"),
arg_str0("e", "em", "<pwd>", "try the calculated password from some cloners based on EM4100 ID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);

View file

@ -863,7 +863,7 @@ static int CmdEM4x50Dump(const char *Cmd) {
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, EM4X50_TIMEOUT_CMD) == false) {
PrintAndLogEx(WARNING, "Timeout while waiting for reply");
PrintAndLogEx(WARNING, "timeout while waiting for reply");
return PM3_ETIMEOUT;
}
@ -1091,7 +1091,7 @@ static int CmdEM4x50Wipe(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_WRITEPWD, (uint8_t *)&etd, sizeof(etd));
if (WaitForResponseTimeout(CMD_LF_EM4X50_WRITEPWD, &resp, EM4X50_TIMEOUT_CMD) == false) {
PrintAndLogEx(WARNING, "Timeout while waiting for reply");
PrintAndLogEx(WARNING, "timeout while waiting for reply");
return PM3_ETIMEOUT;
}

View file

@ -510,20 +510,23 @@ int getGuardBits(uint8_t xorKey, uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8
rawbytes[3] = 0;
// add wiegand to rawbytes
for (i = 0; i < 5; ++i)
for (i = 0; i < 5; ++i) {
rawbytes[i + 4] = bytebits_to_byte(pre + (i * 8), 8);
}
PrintAndLogEx(DEBUG, " WIE | %s", sprint_hex(rawbytes, sizeof(rawbytes)));
// XOR (only works on wiegand stuff)
for (i = 1; i < sizeof(rawbytes); ++i)
for (i = 1; i < sizeof(rawbytes); ++i) {
rawbytes[i] ^= xorKey ;
}
PrintAndLogEx(DEBUG, " XOR | %s", sprint_hex(rawbytes, sizeof(rawbytes)));
// convert rawbytes to bits in pre
for (i = 0; i < sizeof(rawbytes); ++i)
for (i = 0; i < sizeof(rawbytes); ++i) {
num_to_bytebitsLSBF(rawbytes[i], 8, pre + (i * 8));
}
PrintAndLogEx(DEBUG, " Raw | %s", sprint_hex(rawbytes, sizeof(rawbytes)));
PrintAndLogEx(DEBUG, " Raw | %s", sprint_bytebits_bin(pre, 96));

View file

@ -366,7 +366,12 @@ static void hitags_config_print(hitags_config_t config) {
static int CmdLFHitagSRead(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hitag hts rdbl",
"Read Hitag S memory.\n\n"
"Read Hitag S memory\n"
" Response protocol modes:\n"
" 0 - Standard 00110\n"
" 1 - Advanced 11000\n"
" 2 - Advanced 11001\n"
" 3 - Fast Advanced 11010 (def)\n\n"
" Crypto mode: \n"
" - key format ISK high + ISK low\n"
" - default key 4F4E4D494B52 (ONMIKR)\n\n"
@ -385,7 +390,7 @@ static int CmdLFHitagSRead(const char *Cmd) {
arg_str0(NULL, "nrar", "<hex>", "nonce / answer writer, 8 hex bytes"),
arg_lit0(NULL, "crypto", "crypto mode"),
arg_str0("k", "key", "<hex>", "pwd or key, 4 or 6 hex bytes"),
arg_int0("m", "mode", "<dec>", "response protocol mode. 0 (Standard 00110), 1 (Advanced 11000), 2 (Advanced 11001), 3 (Fast Advanced 11010) (def: 3)"),
arg_int0("m", "mode", "<0|1|2|3>", "response protocol mode (def 3)"),
arg_int0("p", "page", "<dec>", "page address to read from"),
arg_int0("c", "count", "<dec>", "how many pages to read. '0' reads all pages up to the end page (def: 1)"),
arg_param_end

View file

@ -483,7 +483,7 @@ static int CmdUsartTX(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str1("d", "data", NULL, "string to send"),
arg_str1("d", "data", "<str>", "string to send"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -568,7 +568,7 @@ static int CmdUsartTXRX(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_u64_0("t", "timeout", "<dec>", "timeout in ms, default is 1000 ms"),
arg_str1("d", "data", NULL, "string to send"),
arg_str1("d", "data", "<str>", "string to send"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);

View file

@ -1041,8 +1041,9 @@ bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms
}
// Add delay depending on the communication channel & speed
if (ms_timeout != (size_t) - 1)
if (ms_timeout != (size_t) - 1) {
ms_timeout += communication_delay();
}
__atomic_store_n(&timeout_start_time, msclock(), __ATOMIC_SEQ_CST);
@ -1055,6 +1056,7 @@ bool WaitForResponseTimeoutW(uint32_t cmd, PacketResponseNG *response, size_t ms
}
while (getReply(response)) {
if (cmd == CMD_UNKNOWN || response->cmd == cmd) {
return true;
}

View file

@ -74,22 +74,25 @@ int preferences_load(void) {
setDefaultPath(spTrace, "");
// default save path
if (get_my_user_directory() != NULL) // should return path to .proxmark3 folder
if (get_my_user_directory() != NULL) { // should return path to .proxmark3 folder
setDefaultPath(spDefault, get_my_user_directory());
else
} else {
setDefaultPath(spDefault, ".");
}
// default dump path
if (get_my_user_directory() != NULL) // should return path to .proxmark3 folder
if (get_my_user_directory() != NULL) { // should return path to .proxmark3 folder
setDefaultPath(spDump, get_my_user_directory());
else
} else {
setDefaultPath(spDump, ".");
}
// default dump path
if (get_my_user_directory() != NULL) // should return path to .proxmark3 folder
if (get_my_user_directory() != NULL) {// should return path to .proxmark3 folder
setDefaultPath(spTrace, get_my_user_directory());
else
} else {
setDefaultPath(spTrace, ".");
}
if (g_session.incognito) {
PrintAndLogEx(INFO, "No preferences file will be loaded");

View file

@ -1332,8 +1332,9 @@ int main(int argc, char *argv[]) {
// This will allow the command line to override the settings.json values
preferences_load();
// quick patch for debug level
if (! debug_mode_forced)
if (! debug_mode_forced) {
g_debugMode = g_session.client_debug_level;
}
// settings_save ();
// End Settings

View file

@ -362,8 +362,9 @@ serial_port uart_open(const char *pcPortName, uint32_t speed, bool slient) {
// Freshly available port can take a while before getting permission to access it. Up to 600ms on my machine...
for (uint8_t i = 0; i < 10; i++) {
sp->fd = open(pcPortName, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if (sp->fd != -1 || errno != EACCES)
if (sp->fd != -1 || errno != EACCES) {
break;
}
msleep(100);
}
if (sp->fd == -1) {
@ -450,6 +451,7 @@ serial_port uart_open(const char *pcPortName, uint32_t speed, bool slient) {
void uart_close(const serial_port sp) {
serial_port_unix_t_t *spu = (serial_port_unix_t_t *)sp;
msleep(100);
tcflush(spu->fd, TCIOFLUSH);
tcsetattr(spu->fd, TCSANOW, &(spu->tiOld));
struct flock fl;
@ -711,14 +713,16 @@ bool uart_set_speed(serial_port sp, const uint32_t uiPortSpeed) {
};
struct termios ti;
if (tcgetattr(spu->fd, &ti) == -1)
if (tcgetattr(spu->fd, &ti) == -1) {
return false;
}
// Set port speed (Input and Output)
cfsetispeed(&ti, stPortSpeed);
cfsetospeed(&ti, stPortSpeed);
// flush
msleep(100);
tcflush(spu->fd, TCIOFLUSH);
bool result = tcsetattr(spu->fd, TCSANOW, &ti) != -1;