mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2026-05-12 11:18:11 -07:00
+1
-1
@@ -23,7 +23,7 @@ APP_CFLAGS = $(PLATFORM_DEFS) \
|
||||
-DON_DEVICE \
|
||||
-fno-strict-aliasing -ffunction-sections -fdata-sections
|
||||
|
||||
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c
|
||||
SRC_LF = lfops.c lfsampling.c pcf7931.c lfdemod.c lfadc.c
|
||||
SRC_ISO15693 = iso15693.c iso15693tools.c
|
||||
SRC_ISO14443a = iso14443a.c mifareutil.c mifarecmd.c epa.c mifaresim.c
|
||||
#UNUSED: mifaresniff.c desfire_crypto.c
|
||||
|
||||
+746
-524
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Kevin Sheldrake <kev@headhacking.com>, Aug 2018
|
||||
//
|
||||
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
|
||||
// at your option, any later version. See the LICENSE.txt file for the text of
|
||||
// the license.
|
||||
//-----------------------------------------------------------------------------
|
||||
// Definitions hitag2 attack functions
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool hitag2_crack(uint8_t *response, uint8_t *nrarhex);
|
||||
bool hitag2crack_find_valid_e_cmd(uint8_t e_cmd[], uint8_t nrar[]);
|
||||
bool hitag2crack_find_e_page0_cmd(uint8_t keybits[], uint8_t e_firstcmd[], uint8_t nrar[], uint8_t uid[]);
|
||||
bool hitag2crack_test_e_p0cmd(uint8_t *keybits, uint8_t *nrar, uint8_t *e_cmd, uint8_t *uid, uint8_t *e_uid);
|
||||
void hitag2crack_xor(uint8_t *target, uint8_t *source, uint8_t *pad, unsigned int len);
|
||||
bool hitag2crack_read_page(uint8_t *responsestr, uint8_t pagenum, uint8_t *nrar, uint8_t *keybits);
|
||||
bool hitag2crack_send_e_cmd(uint8_t *responsestr, uint8_t *nrar, uint8_t *cmd, int len);
|
||||
bool hitag2crack_tx_rx(uint8_t *responsestr, uint8_t *msg, int len, int state, bool reset);
|
||||
|
||||
bool hitag2crack_rng_init(uint8_t *response, uint8_t *input);
|
||||
bool hitag2crack_decrypt_hex(uint8_t *response, uint8_t *hex);
|
||||
bool hitag2crack_decrypt_bin(uint8_t *response, uint8_t *hex);
|
||||
bool hitag2crack_encrypt_hex(uint8_t *response, uint8_t *hex);
|
||||
bool hitag2crack_encrypt_bin(uint8_t *response, uint8_t *hex);
|
||||
|
||||
bool hitag2_keystream(uint8_t *response, uint8_t *nrarhex);
|
||||
bool hitag2crack_send_auth(uint8_t *nrar);
|
||||
bool hitag2crack_consume_keystream(uint8_t *keybits, int kslen, int *ksoffset, uint8_t *nrar);
|
||||
bool hitag2crack_extend_keystream(uint8_t *keybits, int *kslen, int ksoffset, uint8_t *nrar, uint8_t *uid);
|
||||
|
||||
bool hitag2_reader(uint8_t *response, uint8_t *key, bool interactive);
|
||||
+26
-9
@@ -22,7 +22,7 @@
|
||||
// as a counting signal. TIMER_CLOCK3 = MCK/32, MCK is running at 48 MHz, so the timer is running at 48/32 = 1500 kHz
|
||||
// Carrier period (T0) have duration of 8 microseconds (us), which is 1/125000 per second (125 kHz frequency)
|
||||
// T0 = timer/carrier = 1500kHz/125kHz = 1500000/125000 = 6
|
||||
#define T0 3
|
||||
//#define HITAG_T0 3
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// Global variables
|
||||
@@ -52,16 +52,28 @@ size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
|
||||
volatile uint8_t adc_val;
|
||||
//uint8_t avg_peak = 140, avg_through = 96;
|
||||
uint8_t avg_peak = 130, avg_through = 106;
|
||||
int16_t checked = 0;
|
||||
|
||||
while (true) {
|
||||
|
||||
// only every 1000th times, in order to save time when collecting samples.
|
||||
if (checked == 1000) {
|
||||
if (BUTTON_PRESS() || data_available()) {
|
||||
checked = -1;
|
||||
break;
|
||||
} else {
|
||||
checked = 0;
|
||||
}
|
||||
}
|
||||
++checked;
|
||||
|
||||
while (!BUTTON_PRESS()) {
|
||||
// Watchdog hit
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
adc_val = AT91C_BASE_SSC->SSC_RHR;
|
||||
periods++;
|
||||
|
||||
if (logging) logSample(adc_val, 1, 8, 0);
|
||||
if (logging) logSampleSimple(adc_val);
|
||||
|
||||
// Only test field changes if state of adc values matter
|
||||
if (!wait) {
|
||||
@@ -91,7 +103,7 @@ size_t lf_count_edge_periods_ex(size_t max, bool wait, bool detect_gap) {
|
||||
if (periods == max) return 0;
|
||||
}
|
||||
}
|
||||
if (logging) logSample(255, 1, 8, 0);
|
||||
if (logging) logSampleSimple(0xFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -143,7 +155,11 @@ void lf_init(bool reader) {
|
||||
FpgaSetupSsc();
|
||||
|
||||
// When in reader mode, give the field a bit of time to settle.
|
||||
if (reader) SpinDelay(50);
|
||||
// 313T0 = 313 * 8us = 2504us = 2.5ms Hitag2 tags needs to be fully powered.
|
||||
if (reader) {
|
||||
// 50 ms
|
||||
SpinDelay(50);
|
||||
}
|
||||
|
||||
// Steal this pin from the SSP (SPI communication channel with fpga) and use it to control the modulation
|
||||
AT91C_BASE_PIOA->PIO_PER = GPIO_SSC_DOUT;
|
||||
@@ -168,7 +184,9 @@ void lf_init(bool reader) {
|
||||
AT91C_BASE_TC1->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
|
||||
// Prepare data trace
|
||||
if (logging) initSampleBuffer(NULL);
|
||||
uint32_t bufsize = 20000;
|
||||
|
||||
if (logging) initSampleBuffer(&bufsize);
|
||||
|
||||
}
|
||||
|
||||
@@ -204,14 +222,13 @@ size_t lf_detect_field_drop(size_t max) {
|
||||
}
|
||||
++checked;
|
||||
|
||||
// Watchdog hit
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
periods++;
|
||||
adc_val = AT91C_BASE_SSC->SSC_RHR;
|
||||
|
||||
if (logging) logSample(adc_val, 1, 8, 0);
|
||||
if (logging) logSampleSimple(adc_val);
|
||||
|
||||
if (adc_val == 0) {
|
||||
rising_edge = false;
|
||||
|
||||
+19
-6
@@ -93,6 +93,7 @@ sample_config *getSamplingConfig() {
|
||||
void pushBit(BitstreamOut *stream, uint8_t bit) {
|
||||
int bytepos = stream->position >> 3; // divide by 8
|
||||
int bitpos = stream->position & 7;
|
||||
*(stream->buffer + bytepos) &= ~(1 << (7 - bitpos));
|
||||
*(stream->buffer + bytepos) |= (bit > 0) << (7 - bitpos);
|
||||
stream->position++;
|
||||
stream->numbits++;
|
||||
@@ -106,17 +107,25 @@ sampling_t samples = {0, 0, 0, 0};
|
||||
|
||||
void initSampleBuffer(uint32_t *sample_size) {
|
||||
|
||||
BigBuf_free();
|
||||
// We can't erase the buffer now, it would drastically delay the acquisition
|
||||
// BigBuf_Clear_ext(false);
|
||||
|
||||
if (sample_size == NULL || *sample_size == 0) {
|
||||
*sample_size = BigBuf_max_traceLen();
|
||||
} else {
|
||||
*sample_size = MIN(*sample_size, BigBuf_max_traceLen());
|
||||
}
|
||||
|
||||
// use a bitstream to handle the output
|
||||
data.buffer = BigBuf_get_addr();
|
||||
data.buffer = BigBuf_get_addr();
|
||||
|
||||
// We can't erase the buffer now, it would drastically delay the acquisition
|
||||
// memset(data.buffer, 0, *sample_size);
|
||||
// memset(data.buffer, 0, *sample_size);
|
||||
} else {
|
||||
*sample_size = MIN(*sample_size, BigBuf_max_traceLen());
|
||||
|
||||
data.buffer = BigBuf_malloc(*sample_size);
|
||||
|
||||
// We can't erase the buffer now, it would drastically delay the acquisition
|
||||
// memset(data.buffer, 0, *sample_size);
|
||||
}
|
||||
|
||||
//
|
||||
samples.dec_counter = 0;
|
||||
@@ -129,6 +138,10 @@ uint32_t getSampleCounter() {
|
||||
return samples.total_saved;
|
||||
}
|
||||
|
||||
void logSampleSimple(uint8_t sample) {
|
||||
logSample(sample, config.decimation, config.bits_per_sample, config.averaging);
|
||||
}
|
||||
|
||||
void logSample(uint8_t sample, uint8_t decimation, uint8_t bits_per_sample, bool avg) {
|
||||
|
||||
if (!data.buffer) return;
|
||||
|
||||
@@ -70,6 +70,7 @@ uint32_t DoAcquisition_config(bool verbose, uint32_t sample_size);
|
||||
* Refactoring of lf sampling buffer
|
||||
*/
|
||||
void initSampleBuffer(uint32_t *sample_size);
|
||||
void logSampleSimple(uint8_t sample);
|
||||
void logSample(uint8_t sample, uint8_t decimation, uint8_t bits_per_sample, bool avg);
|
||||
uint32_t getSampleCounter();
|
||||
|
||||
|
||||
+69
-60
@@ -314,11 +314,69 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen) {
|
||||
|
||||
int ret_val = PM3_SUCCESS;
|
||||
|
||||
// We want to mount before multiple operation so the lazy writes/append will not
|
||||
// trigger a mount + umount each loop iteration (lazy ops device side)
|
||||
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
|
||||
|
||||
// Send to device
|
||||
uint32_t bytes_sent = 0;
|
||||
uint32_t bytes_remaining = datalen;
|
||||
uint32_t append = 0;
|
||||
|
||||
// fast push mode
|
||||
conn.block_after_ACK = true;
|
||||
|
||||
while (bytes_remaining > 0) {
|
||||
uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
char fdata[32 + bytes_in_packet];
|
||||
memset(fdata, 0, sizeof(fdata));
|
||||
memcpy(fdata, destfn, 32);
|
||||
memcpy(fdata + 32, data + bytes_sent, bytes_in_packet);
|
||||
|
||||
if (bytes_sent > 0)
|
||||
append = 1;
|
||||
|
||||
SendCommandOLD(CMD_SPIFFS_WRITE, append, bytes_in_packet, 0, fdata, 32 + bytes_in_packet);
|
||||
|
||||
bytes_remaining -= bytes_in_packet;
|
||||
bytes_sent += bytes_in_packet;
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
ret_val = PM3_ETIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||
if (!isok) {
|
||||
PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent);
|
||||
ret_val = PM3_EFLASH;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// turn off fast push mode
|
||||
conn.block_after_ACK = false;
|
||||
|
||||
// We want to unmount after these to set things back to normal but more than this
|
||||
// unmouting ensure that SPIFFS CACHES are all flushed so our file is actually written on memory
|
||||
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
|
||||
|
||||
uint32_t append = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
char destfilename[32] = {0};
|
||||
uint8_t destfilename[32] = {0};
|
||||
bool errors = false;
|
||||
uint8_t cmdp = 0;
|
||||
|
||||
@@ -334,8 +392,8 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'o':
|
||||
param_getstr(Cmd, cmdp + 1, destfilename, 32);
|
||||
if (strlen(destfilename) == 0) {
|
||||
param_getstr(Cmd, cmdp + 1, (char*)destfilename, 32);
|
||||
if (strlen((char*)destfilename) == 0) {
|
||||
PrintAndLogEx(FAILED, "Destination Filename missing or invalid");
|
||||
errors = true;
|
||||
}
|
||||
@@ -362,63 +420,14 @@ static int CmdFlashMemSpiFFSLoad(const char *Cmd) {
|
||||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
// We want to mount before multiple operation so the lazy writes/append will not
|
||||
// trigger a mount + umount each loop iteration (lazy ops device side)
|
||||
SendCommandNG(CMD_SPIFFS_MOUNT, NULL, 0);
|
||||
|
||||
// Send to device
|
||||
uint32_t bytes_sent = 0;
|
||||
uint32_t bytes_remaining = datalen;
|
||||
|
||||
// fast push mode
|
||||
conn.block_after_ACK = true;
|
||||
|
||||
// SendCommandMIX(CMD_SPIFFS_COPY, 0, 0, 0, (uint8_t *)data, 65);
|
||||
|
||||
while (bytes_remaining > 0) {
|
||||
uint32_t bytes_in_packet = MIN(FLASH_MEM_BLOCK_SIZE, bytes_remaining);
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
char fdata[32 + bytes_in_packet];
|
||||
memset(fdata, 0, sizeof(fdata));
|
||||
memcpy(fdata, destfilename, 32);
|
||||
memcpy(fdata + 32, data + bytes_sent, bytes_in_packet);
|
||||
// sprintf(fdata, "%s%s", destfilename, data + bytes_sent);
|
||||
|
||||
if (bytes_sent > 0)
|
||||
append = 1;
|
||||
|
||||
SendCommandOLD(CMD_SPIFFS_WRITE, append, bytes_in_packet, 0, fdata, 32 + bytes_in_packet);
|
||||
|
||||
bytes_remaining -= bytes_in_packet;
|
||||
bytes_sent += bytes_in_packet;
|
||||
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
conn.block_after_ACK = false;
|
||||
free(data);
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||
if (!isok) {
|
||||
conn.block_after_ACK = false;
|
||||
PrintAndLogEx(FAILED, "Flash write fail [offset %u]", bytes_sent);
|
||||
free(data);
|
||||
return PM3_EFLASH;
|
||||
}
|
||||
}
|
||||
|
||||
conn.block_after_ACK = false;
|
||||
res = flashmem_spiffs_load(destfilename, data, datalen);
|
||||
|
||||
free(data);
|
||||
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename);
|
||||
|
||||
// We want to unmount after these to set things back to normal but more than this
|
||||
// unmouting ensure that SPIFFS CACHES are all flushed so our file is actually written on memory
|
||||
SendCommandNG(CMD_SPIFFS_UNMOUNT, NULL, 0);
|
||||
return PM3_SUCCESS;
|
||||
|
||||
if ( res == PM3_SUCCESS )
|
||||
PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu") "bytes to file "_GREEN_("%s"), datalen, destfilename);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
||||
@@ -14,5 +14,6 @@
|
||||
#include "common.h"
|
||||
|
||||
int CmdFlashMemSpiFFS(const char *Cmd);
|
||||
int flashmem_spiffs_load(uint8_t *destfn, uint8_t *data, size_t datalen);
|
||||
|
||||
#endif
|
||||
|
||||
+5
-7
@@ -85,8 +85,6 @@ int CmdHFSearch(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_hf_search();
|
||||
|
||||
PrintAndLogEx(INFO, "Checking for known tags...");
|
||||
|
||||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, "Searching for ThinFilm tag...");
|
||||
if (IfPm3NfcBarcode()) {
|
||||
@@ -170,9 +168,8 @@ int CmdHFSearch(const char *Cmd) {
|
||||
}
|
||||
|
||||
PROMPT_CLEARLINE;
|
||||
PrintAndLogEx(INPLACE, "done");
|
||||
PrintAndLogEx(INPLACE, _RED_("No known/supported 13.56 MHz tags found"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(FAILED, _RED_("No known/supported 13.56 MHz tags found"));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
@@ -272,15 +269,16 @@ static command_t CommandTable[] = {
|
||||
{"15", CmdHF15, AlwaysAvailable, "{ ISO15693 RFIDs... }"},
|
||||
{"epa", CmdHFEPA, AlwaysAvailable, "{ German Identification Card... }"},
|
||||
{"felica", CmdHFFelica, AlwaysAvailable, "{ ISO18092 / Felica RFIDs... }"},
|
||||
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"},
|
||||
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
||||
{"iclass", CmdHFiClass, AlwaysAvailable, "{ ICLASS RFIDs... }"},
|
||||
{"legic", CmdHFLegic, AlwaysAvailable, "{ LEGIC RFIDs... }"},
|
||||
{"lto", CmdHFLTO, AlwaysAvailable, "{ LTO Cartridge Memory RFIDs... }"},
|
||||
{"mf", CmdHFMF, AlwaysAvailable, "{ MIFARE RFIDs... }"},
|
||||
{"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"},
|
||||
{"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"},
|
||||
{"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"},
|
||||
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
||||
{"fido", CmdHFFido, AlwaysAvailable, "{ FIDO and FIDO2 authenticators... }"},
|
||||
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
||||
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
||||
{"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"},
|
||||
{"plot", CmdHFPlot, IfPm3Hfplot, "Plot signal"},
|
||||
{"tune", CmdHFTune, IfPm3Present, "Continuously measure HF antenna tuning"},
|
||||
|
||||
@@ -2805,6 +2805,7 @@ int readIclass(bool loop, bool verbose) {
|
||||
FLAG_ICLASS_READER_CONF | FLAG_ICLASS_READER_ONLY_ONCE |
|
||||
FLAG_ICLASS_READER_ONE_TRY;
|
||||
|
||||
uint32_t res = PM3_ETIMEOUT;
|
||||
// loop in client not device - else on windows have a communication error
|
||||
while (!kbd_enter_pressed()) {
|
||||
|
||||
@@ -2876,6 +2877,6 @@ int readIclass(bool loop, bool verbose) {
|
||||
if (!loop) break;
|
||||
}
|
||||
DropField();
|
||||
return PM3_SUCCESS;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -1101,10 +1101,10 @@ void annotateLTO(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||
snprintf(exp, size, "REQ Standard");
|
||||
break;
|
||||
case LTO_SELECT:
|
||||
snprintf(exp, size, "SELECT");
|
||||
break;
|
||||
case LTO_SELECT_1:
|
||||
snprintf(exp, size, "SELECT_1");
|
||||
if (cmd[1] == 0x70)
|
||||
snprintf(exp, size, "SELECT_UID-2");
|
||||
else if (cmd[1] == 0x20)
|
||||
snprintf(exp, size, "SELECT");
|
||||
break;
|
||||
case LTO_REQ_ALL:
|
||||
snprintf(exp, size, "REQ All");
|
||||
|
||||
+26
-18
@@ -42,9 +42,17 @@ static void lto_switch_on_field(void) {
|
||||
}
|
||||
|
||||
// send a raw LTO-CM command, returns the length of the response (0 in case of error)
|
||||
static int lto_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint16_t *response_len, bool verbose) {
|
||||
static int lto_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint16_t *response_len, bool addcrc, bool verbose) {
|
||||
|
||||
SendCommandOLD(CMD_HF_ISO14443A_READER, ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS, len, 0, cmd, len);
|
||||
uint64_t arg0 = ISO14A_RAW | ISO14A_NO_DISCONNECT | ISO14A_NO_RATS;
|
||||
uint32_t arg1 = (len == 1) ? (7 << 16) : 0;
|
||||
arg1 |= len;
|
||||
|
||||
if (addcrc) {
|
||||
arg0 |= ISO14A_APPEND_CRC;
|
||||
}
|
||||
|
||||
SendCommandOLD(CMD_HF_ISO14443A_READER, arg0, arg1, 0, cmd, len);
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
@@ -55,7 +63,6 @@ static int lto_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint16
|
||||
if (resp.oldarg[0] == *response_len) {
|
||||
*response_len = resp.oldarg[0];
|
||||
|
||||
PrintAndLogEx(INFO, "%s", sprint_hex(resp.data.asBytes, *response_len));
|
||||
if (*response_len > 0) {
|
||||
memcpy(response, resp.data.asBytes, *response_len);
|
||||
}
|
||||
@@ -66,7 +73,6 @@ static int lto_send_cmd_raw(uint8_t *cmd, uint8_t len, uint8_t *response, uint16
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// select a LTO-CM tag. Send WUPA and RID.
|
||||
static int lto_select(uint8_t *id_response, uint8_t id_len, bool verbose) {
|
||||
// Todo: implement anticollision
|
||||
@@ -75,26 +81,27 @@ static int lto_select(uint8_t *id_response, uint8_t id_len, bool verbose) {
|
||||
uint16_t resp_len;
|
||||
uint8_t wupa_cmd[] = {LTO_REQ_STANDARD};
|
||||
uint8_t select_cmd[] = {LTO_SELECT, 0x20};
|
||||
uint8_t select_1_cmd[] = {LTO_SELECT_1, 0x70, 0, 0, 0, 0, 0};
|
||||
uint8_t select_1_cmd[] = {LTO_SELECT, 0x70, 0, 0, 0, 0, 0};
|
||||
|
||||
lto_switch_on_field();
|
||||
|
||||
resp_len = 2;
|
||||
int status = lto_send_cmd_raw(wupa_cmd, sizeof(wupa_cmd), resp, &resp_len, verbose);
|
||||
int status = lto_send_cmd_raw(wupa_cmd, sizeof(wupa_cmd), resp, &resp_len, false, verbose);
|
||||
if (status == PM3_ETIMEOUT || status == PM3_ESOFT) {
|
||||
lto_switch_off_field();
|
||||
return PM3_ESOFT; // WUPA failed
|
||||
}
|
||||
|
||||
resp_len = id_len;
|
||||
status = lto_send_cmd_raw(select_cmd, sizeof(select_cmd), id_response, &resp_len, verbose);
|
||||
status = lto_send_cmd_raw(select_cmd, sizeof(select_cmd), id_response, &resp_len, false, verbose);
|
||||
if (status == PM3_ETIMEOUT || status == PM3_ESOFT) {
|
||||
lto_switch_off_field();
|
||||
return PM3_EWRONGANSVER; // SELECT failed
|
||||
}
|
||||
|
||||
memcpy(select_1_cmd + 2, id_response, sizeof(select_1_cmd) - 2);
|
||||
resp_len = 1;
|
||||
status = lto_send_cmd_raw(select_1_cmd, sizeof(select_1_cmd), resp, &resp_len, verbose);
|
||||
status = lto_send_cmd_raw(select_1_cmd, sizeof(select_1_cmd), resp, &resp_len, true, verbose);
|
||||
if (status == PM3_ETIMEOUT || status == PM3_ESOFT || resp[0] != 0x0A) {
|
||||
lto_switch_off_field();
|
||||
return PM3_EWRONGANSVER; // SELECT failed
|
||||
@@ -104,7 +111,6 @@ static int lto_select(uint8_t *id_response, uint8_t id_len, bool verbose) {
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int CmdHfLTOInfo(const char *Cmd) {
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
@@ -126,7 +132,7 @@ static int CmdHfLTOInfo(const char *Cmd) {
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
return infoLTO(true);
|
||||
return infoLTO(false);
|
||||
}
|
||||
|
||||
int infoLTO(bool verbose) {
|
||||
@@ -134,18 +140,20 @@ int infoLTO(bool verbose) {
|
||||
clearCommandBuffer();
|
||||
|
||||
uint8_t serial_number[5];
|
||||
uint8_t serial_len = 0;
|
||||
|
||||
uint8_t serial_len = sizeof(serial_number);
|
||||
int ret_val = lto_select(serial_number, serial_len, verbose);
|
||||
|
||||
lto_switch_off_field();
|
||||
/*
|
||||
|
||||
-- "hf 14a raw -a -p -b 7 45"
|
||||
-- "hf 14a raw -c -p 9320"
|
||||
-- "hf 14a raw -c -p 9370%s", serial_number
|
||||
-- "disconnect"
|
||||
if (ret_val == PM3_SUCCESS) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " UID : " _YELLOW_("%s"), sprint_hex_inrow(serial_number, sizeof(serial_number)));
|
||||
PrintAndLogEx(SUCCESS, "TYPE : ");
|
||||
// todo: add printing of all configuration
|
||||
} else {
|
||||
if (verbose) PrintAndLogEx(WARNING, "LTO-CM card select failed");
|
||||
}
|
||||
|
||||
/* read block:
|
||||
|
||||
SendCommandNG(CMD_HF_THINFILM_READ, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
|
||||
+14
-14
@@ -339,7 +339,7 @@ int CmdLFCommandRead(const char *Cmd) {
|
||||
// bitbang mode
|
||||
if (payload.delay == 0) {
|
||||
if (payload.zeros < 7 || payload.ones < 7) {
|
||||
PrintAndLogEx(WARNING, "Warning periods cannot be less than 7us in bit bang mode");
|
||||
PrintAndLogEx(WARNING, "warning periods cannot be less than 7us in bit bang mode");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
}
|
||||
@@ -347,15 +347,14 @@ int CmdLFCommandRead(const char *Cmd) {
|
||||
//Validations
|
||||
if (errors || cmdp == 0) return usage_lf_cmdread();
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Sending");
|
||||
PrintAndLogEx(SUCCESS, "sending");
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_MOD_THEN_ACQ_RAW_ADC, (uint8_t *)&payload, 8 + datalen);
|
||||
|
||||
printf("\n");
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
||||
uint8_t i = 10;
|
||||
// 20sec wait loop
|
||||
while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
@@ -365,15 +364,15 @@ int CmdLFCommandRead(const char *Cmd) {
|
||||
|
||||
if (resp.status == PM3_SUCCESS) {
|
||||
if (i) {
|
||||
PrintAndLogEx(SUCCESS, "Downloading response signal data");
|
||||
getSamples(0, false);
|
||||
PrintAndLogEx(SUCCESS, "downloading response signal data");
|
||||
getSamples(0, true);
|
||||
return PM3_SUCCESS;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(WARNING, "Command failed.");
|
||||
PrintAndLogEx(WARNING, "command failed.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
@@ -1214,17 +1213,18 @@ int CmdLFfind(const char *Cmd) {
|
||||
|
||||
// only run these tests if device is online
|
||||
if (isOnline) {
|
||||
|
||||
if (IfPm3Hitag()) {
|
||||
if (readHitagUid()) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Hitag") "found!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
// only run if graphbuffer is just noise as it should be for hitag
|
||||
// The improved noise detection will find Cotag.
|
||||
if (getSignalProperties()->isnoise) {
|
||||
|
||||
if (IfPm3Hitag()) {
|
||||
if (readHitagUid()) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Hitag") "found!");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
if (readMotorolaUid()) {
|
||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Motorola FlexPass ID") "found!");
|
||||
return PM3_SUCCESS;
|
||||
|
||||
+78
-35
@@ -18,6 +18,7 @@
|
||||
#include "commonutil.h"
|
||||
#include "hitag.h"
|
||||
#include "fileutils.h" // savefile
|
||||
#include "protocols.h" // defines
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
@@ -35,7 +36,7 @@ static int usage_hitag_sniff(void) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf hitag sniff");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hitag_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Simulate " _YELLOW_("Hitag2 / HitagS")" transponder");
|
||||
@@ -49,7 +50,7 @@ static int usage_hitag_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf hitag sim 2 b lf-hitag-dump");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hitag_info(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: lf hitag info [h] p <pwd>");
|
||||
@@ -58,7 +59,7 @@ static int usage_hitag_info(void) {
|
||||
PrintAndLogEx(NORMAL, " p <pwd> password");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf hitag info");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
/*
|
||||
static int usage_hitag_dump(void) {
|
||||
@@ -71,7 +72,7 @@ static int usage_hitag_dump(void) {
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf hitag dump f mydump");
|
||||
PrintAndLogEx(NORMAL, " lf hitag dump p 4D494B52 f mydump");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
*/
|
||||
static int usage_hitag_reader(void) {
|
||||
@@ -85,12 +86,12 @@ static int usage_hitag_reader(void) {
|
||||
PrintAndLogEx(NORMAL, " Hitag1 (1*)");
|
||||
PrintAndLogEx(NORMAL, " Not implemented");
|
||||
PrintAndLogEx(NORMAL, " Hitag2 (2*)");
|
||||
PrintAndLogEx(NORMAL, " 21 <password> Read all pages, password mode. Default: 4D494B52 (\"MIKR\")");
|
||||
PrintAndLogEx(NORMAL, " 21 <password> Read all pages, password mode. Default: " _YELLOW_("4D494B52") "(\"MIKR\")");
|
||||
PrintAndLogEx(NORMAL, " 22 <nr> <ar> Read all pages, challenge mode");
|
||||
PrintAndLogEx(NORMAL, " 23 <key> Read all pages, crypto mode. Key format: ISK high + ISK low. Default: 4F4E4D494B52 (\"ONMIKR\")");
|
||||
PrintAndLogEx(NORMAL, " 23 <key> Read all pages, crypto mode. Key format: ISK high + ISK low. Default: " _YELLOW_("4F4E4D494B52") "(\"ONMIKR\")");
|
||||
PrintAndLogEx(NORMAL, " 25 Test recorded authentications");
|
||||
PrintAndLogEx(NORMAL, " 26 Just read UID");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hitag_writer(void) {
|
||||
PrintAndLogEx(NORMAL, "Hitag writer functions");
|
||||
@@ -106,7 +107,7 @@ static int usage_hitag_writer(void) {
|
||||
PrintAndLogEx(NORMAL, " 24 <key> <page> <byte0...byte3> Write page, crypto mode. Key format: ISK high + ISK low.");
|
||||
PrintAndLogEx(NORMAL, " Default: 4F4E4D494B52 (\"ONMIKR\"). Set key=0 for no auth");
|
||||
PrintAndLogEx(NORMAL, " 27 <password> <page> <byte0...byte3> Write page, password mode. Default: 4D494B52 (\"MIKR\")");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hitag_checkchallenges(void) {
|
||||
PrintAndLogEx(NORMAL, "Check challenges, load a file with save hitag crypto challenges and test them all.");
|
||||
@@ -119,19 +120,19 @@ static int usage_hitag_checkchallenges(void) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf hitag cc f lf-hitag-challenges");
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFHitagList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("hitag");
|
||||
return 0;
|
||||
CmdTraceList("hitag2");
|
||||
return PM3_SUCCESS;
|
||||
|
||||
/*
|
||||
uint8_t *got = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
|
||||
if (!got) {
|
||||
PrintAndLogEx(WARNING, "Cannot allocate memory for trace");
|
||||
return 2;
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
// Query for the actual size of the trace
|
||||
@@ -139,7 +140,7 @@ static int CmdLFHitagList(const char *Cmd) {
|
||||
if (!GetFromDevice(BIG_BUF, got, PM3_CMD_DATA_SIZE, 0, NULL, 0, &response, 2500, false)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
free(got);
|
||||
return 2;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
uint16_t traceLen = response.arg[2];
|
||||
@@ -148,13 +149,13 @@ static int CmdLFHitagList(const char *Cmd) {
|
||||
if (p == NULL) {
|
||||
PrintAndLogEx(WARNING, "Cannot allocate memory for trace");
|
||||
free(got);
|
||||
return 2;
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
got = p;
|
||||
if (!GetFromDevice(BIG_BUF, got, traceLen, 0, NULL, 0, NULL, 2500, false)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
free(got);
|
||||
return 2;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +252,7 @@ static int CmdLFHitagList(const char *Cmd) {
|
||||
}
|
||||
|
||||
free(got);
|
||||
return 0;
|
||||
return PM3_SUCCES;
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -262,7 +263,7 @@ static int CmdLFHitagSniff(const char *Cmd) {
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_HITAG_SNIFF, NULL, 0);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFHitagSim(const char *Cmd) {
|
||||
@@ -343,7 +344,7 @@ static int CmdLFHitagSim(const char *Cmd) {
|
||||
}
|
||||
|
||||
free(data);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static void printHitagConfiguration(uint8_t config) {
|
||||
@@ -483,21 +484,20 @@ static int CmdLFHitagInfo(const char *Cmd) {
|
||||
// read UID
|
||||
uint32_t uid = 0;
|
||||
if (getHitagUid(&uid) == false)
|
||||
return 1;
|
||||
return PM3_ESOFT;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "UID: %08X", uid);
|
||||
PrintAndLogEx(SUCCESS, "UID: " _YELLOW_("%08X"), uid);
|
||||
|
||||
// how to detemine Hitag types?
|
||||
// read block3, get configuration byte.
|
||||
PrintAndLogEx(FAILED, _RED_("TODO: This is a hardcoded example!"));
|
||||
|
||||
// common configurations.
|
||||
printHitagConfiguration(0x06);
|
||||
// printHitagConfiguration(0x06);
|
||||
//printHitagConfiguration( 0x0E );
|
||||
//printHitagConfiguration( 0x02 );
|
||||
//printHitagConfiguration( 0x00 );
|
||||
//printHitagConfiguration( 0x04 );
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// TODO: iceman
|
||||
@@ -550,21 +550,22 @@ static int CmdLFHitagReader(const char *Cmd) {
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandOLD(cmd, htf, 0, 0, &htd, sizeof(htd));
|
||||
SendCommandMIX(cmd, htf, 0, 0, &htd, sizeof(htd));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return 1;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (resp.oldarg[0] == false) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag failed");
|
||||
return 1;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint32_t id = bytes_to_num(resp.data.asBytes, 4);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Valid Hitag2 tag found - UID: %08x", id);
|
||||
PrintAndLogEx(SUCCESS, " UID: " _YELLOW_("%08x"), id);
|
||||
|
||||
if (htf != RHT2F_UID_ONLY) {
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Dumping tag memory...");
|
||||
@@ -575,6 +576,8 @@ static int CmdLFHitagReader(const char *Cmd) {
|
||||
fnameptr += sprintf(fnameptr, "lf-hitag-");
|
||||
FillFileNameByUID(fnameptr, data, "-dump", 4);
|
||||
|
||||
|
||||
|
||||
saveFile(filename, ".bin", data, 48);
|
||||
saveFileEML(filename, data, 48, 4);
|
||||
saveFileJSON(filename, jsfHitag, data, 48);
|
||||
@@ -582,7 +585,7 @@ static int CmdLFHitagReader(const char *Cmd) {
|
||||
// block3, 1 byte
|
||||
printHitagConfiguration(data[4 * 3]);
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFHitagCheckChallenges(const char *Cmd) {
|
||||
@@ -631,7 +634,7 @@ static int CmdLFHitagCheckChallenges(const char *Cmd) {
|
||||
SendCommandMIX(CMD_LF_HITAGS_TEST_TRACES, 0, 0, 0, NULL, 0);
|
||||
|
||||
free(data);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdLFHitagWriter(const char *Cmd) {
|
||||
@@ -675,14 +678,14 @@ static int CmdLFHitagWriter(const char *Cmd) {
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_ACK, &resp, 4000)) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return 1;
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (resp.oldarg[0] == false) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - hitag write failed");
|
||||
return 1;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -692,10 +695,50 @@ static int CmdLFHitagDump(const char *Cmd) {
|
||||
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_hitag_dump();
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
*/
|
||||
|
||||
// Annotate HITAG protocol
|
||||
void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||
}
|
||||
|
||||
void annotateHitag2(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||
|
||||
uint8_t cmdbits = (cmd[0] & 0xC0) >> 6;
|
||||
|
||||
if (cmdsize == 1) {
|
||||
if (cmdbits == HITAG2_START_AUTH) {
|
||||
snprintf(exp, size, "START AUTH");
|
||||
return;
|
||||
}
|
||||
if (cmdbits == HITAG2_HALT) {
|
||||
snprintf(exp, size, "HALT");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (cmdsize == 2) {
|
||||
if (cmdbits == HITAG2_START_AUTH) {
|
||||
// C 1 C 0
|
||||
// 1100 0 00 1 1100 000
|
||||
uint8_t page = (cmd[0] & 0x38) >> 3;
|
||||
uint8_t inv_page = ((cmd[0] & 0x1) << 2) | ((cmd[1] & 0xC0) >> 6);
|
||||
snprintf(exp, size, "READ page(%x) %x", page, inv_page);
|
||||
return;
|
||||
}
|
||||
if (cmdbits == HITAG2_WRITE_PAGE) {
|
||||
uint8_t page = (cmd[0] & 0x38) >> 3;
|
||||
uint8_t inv_page = ((cmd[0] & 0x1) << 2) | ((cmd[1] & 0xC0) >> 6);
|
||||
snprintf(exp, size, "WRITE page(%x) %x", page, inv_page);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void annotateHitagS(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help" },
|
||||
{"list", CmdLFHitagList, IfPm3Hitag, "List Hitag trace history" },
|
||||
@@ -711,7 +754,7 @@ static command_t CommandTable[] = {
|
||||
static int CmdHelp(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdsHelp(CommandTable);
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdLFHitag(const char *Cmd) {
|
||||
@@ -720,5 +763,5 @@ int CmdLFHitag(const char *Cmd) {
|
||||
}
|
||||
|
||||
int readHitagUid(void) {
|
||||
return CmdLFHitagReader("26") == 0;
|
||||
return (CmdLFHitagReader("26") == PM3_SUCCESS);
|
||||
}
|
||||
|
||||
+3
-1
@@ -16,5 +16,7 @@
|
||||
int CmdLFHitag(const char *Cmd);
|
||||
|
||||
int readHitagUid(void);
|
||||
|
||||
void annotateHitag1(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||
void annotateHitag2(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||
void annotateHitagS(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize);
|
||||
#endif
|
||||
|
||||
+35
-18
@@ -17,6 +17,7 @@
|
||||
#include "cmdhflist.h" // annotations
|
||||
#include "comms.h" // for sending cmds to device. GetFromBigBuf
|
||||
#include "fileutils.h" // for saveFile
|
||||
#include "cmdlfhitag.h" // annotate hitag
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
@@ -45,7 +46,9 @@ static int usage_trace_list() {
|
||||
PrintAndLogEx(NORMAL, " iclass - interpret data as iclass communications");
|
||||
PrintAndLogEx(NORMAL, " legic - interpret data as LEGIC communications");
|
||||
PrintAndLogEx(NORMAL, " felica - interpret data as ISO18092 / FeliCa communications");
|
||||
PrintAndLogEx(NORMAL, " hitag - interpret data as Hitag2 / HitagS communications");
|
||||
PrintAndLogEx(NORMAL, " hitag1 - interpret data as Hitag1 communications");
|
||||
PrintAndLogEx(NORMAL, " hitag2 - interpret data as Hitag2 communications");
|
||||
PrintAndLogEx(NORMAL, " hitags - interpret data as HitagS communications");
|
||||
PrintAndLogEx(NORMAL, " lto - interpret data as LTO-CM communications");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
@@ -281,7 +284,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||
crcStatus = iso15693_CRC_check(frame, data_len);
|
||||
break;
|
||||
case ISO_7816_4:
|
||||
case PROTO_HITAG:
|
||||
case PROTO_HITAG1:
|
||||
case PROTO_HITAG2:
|
||||
case PROTO_HITAGS:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -301,7 +306,9 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||
&& protocol != ISO_15693
|
||||
&& protocol != ICLASS
|
||||
&& protocol != ISO_7816_4
|
||||
&& protocol != PROTO_HITAG
|
||||
&& protocol != PROTO_HITAG1
|
||||
&& protocol != PROTO_HITAG2
|
||||
&& protocol != PROTO_HITAGS
|
||||
&& protocol != THINFILM
|
||||
&& protocol != FELICA
|
||||
&& protocol != LTO
|
||||
@@ -385,6 +392,15 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||
case LTO:
|
||||
annotateLTO(explanation, sizeof(explanation), frame, data_len);
|
||||
break;
|
||||
case PROTO_HITAG1:
|
||||
annotateHitag1(explanation, sizeof(explanation), frame, data_len);
|
||||
break;
|
||||
case PROTO_HITAG2:
|
||||
annotateHitag2(explanation, sizeof(explanation), frame, data_len);
|
||||
break;
|
||||
case PROTO_HITAGS:
|
||||
annotateHitagS(explanation, sizeof(explanation), frame, data_len);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -593,7 +609,9 @@ int CmdTraceList(const char *Cmd) {
|
||||
else if (strcmp(type, "15") == 0) protocol = ISO_15693;
|
||||
else if (strcmp(type, "felica") == 0) protocol = FELICA;
|
||||
else if (strcmp(type, "mf") == 0) protocol = PROTO_MIFARE;
|
||||
else if (strcmp(type, "hitag") == 0) protocol = PROTO_HITAG;
|
||||
else if (strcmp(type, "hitag1") == 0) protocol = PROTO_HITAG1;
|
||||
else if (strcmp(type, "hitag2") == 0) protocol = PROTO_HITAG2;
|
||||
else if (strcmp(type, "hitags") == 0) protocol = PROTO_HITAGS;
|
||||
else if (strcmp(type, "thinfilm") == 0) protocol = THINFILM;
|
||||
else if (strcmp(type, "lto") == 0) protocol = LTO;
|
||||
else if (strcmp(type, "raw") == 0) protocol = -1; //No crc, no annotations
|
||||
@@ -644,8 +662,7 @@ int CmdTraceList(const char *Cmd) {
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Recorded Activity (TraceLen = %lu bytes)", traceLen);
|
||||
PrintAndLogEx(INFO, "");
|
||||
PrintAndLogEx(SUCCESS, "Recorded activity (trace len = " _YELLOW_("%lu") "bytes)", traceLen);
|
||||
|
||||
/*
|
||||
if (protocol == FELICA) {
|
||||
@@ -657,27 +674,27 @@ int CmdTraceList(const char *Cmd) {
|
||||
tracepos = printHexLine(tracepos, traceLen, trace, protocol);
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "Start = Start of Start Bit, End = End of last modulation. Src = Source of Transfer");
|
||||
PrintAndLogEx(INFO, _YELLOW_("Start") "= Start of Start Bit, " _YELLOW_("End") "= End of last modulation. " _YELLOW_("Src") "= Source of Transfer");
|
||||
if (protocol == ISO_14443A || protocol == PROTO_MIFARE || protocol == MFDES || protocol == TOPAZ || protocol == LTO)
|
||||
PrintAndLogEx(NORMAL, "ISO14443A - All times are in carrier periods (1/13.56MHz)");
|
||||
PrintAndLogEx(INFO, "ISO14443A - All times are in carrier periods (1/13.56MHz)");
|
||||
if (protocol == THINFILM)
|
||||
PrintAndLogEx(NORMAL, "Thinfilm - All times are in carrier periods (1/13.56MHz)");
|
||||
PrintAndLogEx(INFO, "Thinfilm - All times are in carrier periods (1/13.56MHz)");
|
||||
if (protocol == ICLASS)
|
||||
PrintAndLogEx(NORMAL, "iClass - Timings are not as accurate");
|
||||
PrintAndLogEx(INFO, "iClass - Timings are not as accurate");
|
||||
if (protocol == LEGIC)
|
||||
PrintAndLogEx(NORMAL, "LEGIC - Reader Mode: Timings are in ticks (1us == 1.5ticks)\n"
|
||||
PrintAndLogEx(INFO, "LEGIC - Reader Mode: Timings are in ticks (1us == 1.5ticks)\n"
|
||||
" Tag Mode: Timings are in sub carrier periods (1/212 kHz == 4.7us)");
|
||||
if (protocol == ISO_14443B)
|
||||
PrintAndLogEx(NORMAL, "ISO14443B"); // Timings ?
|
||||
PrintAndLogEx(INFO, "ISO14443B"); // Timings ?
|
||||
if (protocol == ISO_15693)
|
||||
PrintAndLogEx(NORMAL, "ISO15693 - Timings are not as accurate");
|
||||
PrintAndLogEx(INFO, "ISO15693 - Timings are not as accurate");
|
||||
if (protocol == ISO_7816_4)
|
||||
PrintAndLogEx(NORMAL, "ISO7816-4 / Smartcard - Timings N/A yet");
|
||||
if (protocol == PROTO_HITAG)
|
||||
PrintAndLogEx(NORMAL, "Hitag2 / HitagS - Timings in ETU (8us)");
|
||||
PrintAndLogEx(INFO, "ISO7816-4 / Smartcard - Timings N/A yet");
|
||||
if (protocol == PROTO_HITAG1 || protocol == PROTO_HITAG2 || protocol == PROTO_HITAGS)
|
||||
PrintAndLogEx(INFO, "Hitag1 / Hitag2 / HitagS - Timings in ETU (8us)");
|
||||
if (protocol == FELICA)
|
||||
PrintAndLogEx(NORMAL, "ISO18092 / FeliCa - Timings are not as accurate");
|
||||
|
||||
PrintAndLogEx(INFO, "ISO18092 / FeliCa - Timings are not as accurate");
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, " Start | End | Src | Data (! denotes parity error) | CRC | Annotation");
|
||||
PrintAndLogEx(NORMAL, "------------+------------+-----+-------------------------------------------------------------------------+-----+--------------------");
|
||||
|
||||
+39
-16
@@ -125,15 +125,16 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "found " _YELLOW_("%u") "candidate key%s\n", keycount, (keycount > 1) ? "s." : ".");
|
||||
PrintAndLogEx(SUCCESS, "found " _YELLOW_("%u") "candidate key%s", keycount, (keycount > 1) ? "s." : ".");
|
||||
|
||||
*key = UINT64_C(-1);
|
||||
uint8_t keyBlock[PM3_CMD_DATA_SIZE];
|
||||
uint32_t max_keys = KEYS_IN_BLOCK;
|
||||
for (uint32_t i = 0; i < keycount; i += max_keys) {
|
||||
|
||||
uint32_t size = keycount - i > max_keys ? max_keys : keycount - i;
|
||||
for (uint32_t j = 0; j < size; j++) {
|
||||
uint8_t size = keycount - i > max_keys ? max_keys : keycount - i;
|
||||
register uint8_t j;
|
||||
for (j = 0; j < size; j++) {
|
||||
if (par_list == 0) {
|
||||
num_to_bytes(last_keylist[i * max_keys + j], 6, keyBlock + (j * 6));
|
||||
} else {
|
||||
@@ -159,6 +160,7 @@ int mfDarkside(uint8_t blockno, uint8_t key_type, uint64_t *key) {
|
||||
free(keylist);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int mfCheckKeys(uint8_t blockNo, uint8_t keyType, bool clear_trace, uint8_t keycnt, uint8_t *keyBlock, uint64_t *key) {
|
||||
*key = -1;
|
||||
clearCommandBuffer();
|
||||
@@ -308,7 +310,7 @@ int mfKeyBrute(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint64_t *resultk
|
||||
}
|
||||
|
||||
// Compare 16 Bits out of cryptostate
|
||||
static int Compare16Bits(const void *a, const void *b) {
|
||||
inline static int Compare16Bits(const void *a, const void *b) {
|
||||
if ((*(uint64_t *)b & 0x00ff000000ff0000) == (*(uint64_t *)a & 0x00ff000000ff0000)) return 0;
|
||||
if ((*(uint64_t *)b & 0x00ff000000ff0000) > (*(uint64_t *)a & 0x00ff000000ff0000)) return 1;
|
||||
return -1;
|
||||
@@ -330,13 +332,14 @@ __attribute__((force_align_arg_pointer))
|
||||
|
||||
statelist->len = p1 - statelist->head.slhead;
|
||||
statelist->tail.sltail = --p1;
|
||||
|
||||
qsort(statelist->head.slhead, statelist->len, sizeof(uint64_t), Compare16Bits);
|
||||
|
||||
return statelist->head.slhead;
|
||||
}
|
||||
|
||||
int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey, bool calibrate) {
|
||||
uint16_t i;
|
||||
|
||||
uint32_t uid;
|
||||
StateList_t statelists[2];
|
||||
struct Crypto1State *p1, *p2, *p3, *p4;
|
||||
@@ -385,7 +388,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||
|
||||
memcpy(&uid, package->cuid, sizeof(package->cuid));
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
for (uint8_t i = 0; i < 2; i++) {
|
||||
statelists[i].blockNo = package->block;
|
||||
statelists[i].keyType = package->keytype;
|
||||
statelists[i].uid = uid;
|
||||
@@ -402,11 +405,11 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||
pthread_t thread_id[2];
|
||||
|
||||
// create and run worker threads
|
||||
for (i = 0; i < 2; i++)
|
||||
for (uint8_t i = 0; i < 2; i++)
|
||||
pthread_create(thread_id + i, NULL, nested_worker_thread, &statelists[i]);
|
||||
|
||||
// wait for threads to terminate:
|
||||
for (i = 0; i < 2; i++)
|
||||
for (uint8_t i = 0; i < 2; i++)
|
||||
pthread_join(thread_id[i], (void *)&statelists[i].head.slhead);
|
||||
|
||||
// the first 16 Bits of the cryptostate already contain part of our key.
|
||||
@@ -457,6 +460,8 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||
uint32_t keycnt = statelists[0].len;
|
||||
if (keycnt == 0) goto out;
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Found " _YELLOW_("%u") "candidate keys", keycnt);
|
||||
|
||||
memset(resultKey, 0, 6);
|
||||
uint64_t key64 = -1;
|
||||
|
||||
@@ -464,11 +469,14 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||
uint32_t max_keys = keycnt > KEYS_IN_BLOCK ? KEYS_IN_BLOCK : keycnt;
|
||||
uint8_t keyBlock[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
|
||||
for (i = 0; i < keycnt; i += max_keys) {
|
||||
uint64_t start_time = msclock();
|
||||
|
||||
int size = keycnt - i > max_keys ? max_keys : keycnt - i;
|
||||
for (uint32_t i = 0; i < keycnt; i += max_keys) {
|
||||
|
||||
for (int j = 0; j < size; j++) {
|
||||
uint8_t size = keycnt - i > max_keys ? max_keys : keycnt - i;
|
||||
|
||||
register uint8_t j;
|
||||
for (j = 0; j < size; j++) {
|
||||
crypto1_get_lfsr(statelists[0].head.slhead + i, &key64);
|
||||
num_to_bytes(key64, 6, keyBlock + j * 6);
|
||||
}
|
||||
@@ -485,6 +493,13 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
||||
);
|
||||
return -5;
|
||||
}
|
||||
|
||||
float bruteforce_per_second = (float)KEYS_IN_BLOCK / (float)(msclock() - start_time) * 1000.0;
|
||||
start_time = msclock();
|
||||
|
||||
if ( i + 1 % 10 == 0)
|
||||
PrintAndLogEx(INFO, " %8d keys left | %5.1f keys/sec | worst case %6.1f seconds remaining", keycnt - i, bruteforce_per_second, (keycnt-i) / bruteforce_per_second);
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -499,7 +514,7 @@ out:
|
||||
}
|
||||
|
||||
int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo, uint8_t trgKeyType, uint8_t *resultKey) {
|
||||
uint16_t i;
|
||||
|
||||
uint32_t uid;
|
||||
StateList_t statelists[1];
|
||||
struct Crypto1State *p1, *p3;
|
||||
@@ -589,16 +604,18 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||
uint32_t max_keys_slice = keycnt > KEYS_IN_BLOCK ? KEYS_IN_BLOCK : keycnt;
|
||||
uint8_t keyBlock[PM3_CMD_DATA_SIZE] = {0x00};
|
||||
|
||||
for (i = 0; i < keycnt; i += max_keys_slice) {
|
||||
uint64_t start_time = msclock();
|
||||
for (uint32_t i = 0; i < keycnt; i += max_keys_slice) {
|
||||
|
||||
PrintAndLogEx(INFO, "Testing %u / %u ", i, keycnt);
|
||||
// PrintAndLogEx(INFO, "Testing %u / %u ", i, keycnt);
|
||||
|
||||
key64 = 0;
|
||||
|
||||
int size = keycnt - i > max_keys_slice ? max_keys_slice : keycnt - i;
|
||||
uint8_t size = keycnt - i > max_keys_slice ? max_keys_slice : keycnt - i;
|
||||
|
||||
// copy x keys to device.
|
||||
for (int j = 0; j < size; j++) {
|
||||
register uint8_t j;
|
||||
for (j = 0; j < size; j++) {
|
||||
crypto1_get_lfsr(statelists[0].head.slhead + i + j, &key64);
|
||||
num_to_bytes(key64, 6, keyBlock + j * 6);
|
||||
}
|
||||
@@ -617,6 +634,12 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
||||
);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
float bruteforce_per_second = (float)KEYS_IN_BLOCK / (float)(msclock() - start_time) * 1000.0;
|
||||
start_time = msclock();
|
||||
|
||||
if ( i+1 % 10 == 0)
|
||||
PrintAndLogEx(INFO, " %8d keys left | %5.1f keys/sec | worst case %6.1f seconds remaining", keycnt - i, bruteforce_per_second, (keycnt-i) / bruteforce_per_second);
|
||||
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
@@ -21,6 +21,8 @@ typedef enum {
|
||||
RHTSF_KEY = 02,
|
||||
WHTSF_CHALLENGE = 03,
|
||||
WHTSF_KEY = 04,
|
||||
RHT1F_PLAIN = 11,
|
||||
RHT1F_AUTHENTICATE = 12,
|
||||
RHT2F_PASSWORD = 21,
|
||||
RHT2F_AUTHENTICATE = 22,
|
||||
RHT2F_CRYPTO = 23,
|
||||
@@ -44,8 +46,17 @@ typedef struct {
|
||||
uint8_t data[4];
|
||||
} PACKED rht2d_crypto;
|
||||
|
||||
typedef struct {
|
||||
bool key_no;
|
||||
uint8_t logdata_0[4];
|
||||
uint8_t logdata_1[4];
|
||||
uint8_t nonce[4];
|
||||
uint8_t key[4];
|
||||
} PACKED rht1d_authenticate;
|
||||
|
||||
typedef union {
|
||||
rht2d_password pwd;
|
||||
rht1d_authenticate ht1auth;
|
||||
rht2d_authenticate auth;
|
||||
rht2d_crypto crypto;
|
||||
} hitag_data;
|
||||
|
||||
+14
-7
@@ -305,9 +305,11 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
||||
#define ISO_15693 7
|
||||
#define FELICA 8
|
||||
#define PROTO_MIFARE 9
|
||||
#define PROTO_HITAG 10
|
||||
#define PROTO_HITAG1 10
|
||||
#define THINFILM 11
|
||||
#define LTO 12
|
||||
#define PROTO_HITAG2 13
|
||||
#define PROTO_HITAGS 14
|
||||
|
||||
//-- Picopass fuses
|
||||
#define FUSE_FPERS 0x80
|
||||
@@ -588,12 +590,18 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
||||
#define HITAG1_HALT 0x70 // left 4 bits only, followed by 8 bits (dummy) page and 8 bits CRC
|
||||
|
||||
// HITAG2 commands
|
||||
#define HITAG2_START_AUTH 0xC0 // left 5 bits only
|
||||
#define HITAG2_READ_PAGE 0xC0 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||
#define HITAG2_READ_PAGE_INVERTED 0x44 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||
#define HITAG2_WRITE_PAGE 0x82 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||
#define HITAG2_HALT 0x00 // left 5 bits only
|
||||
#define HITAG2_START_AUTH 0x3 // left 5 bits only
|
||||
#define HITAG2_HALT 0x0 // left 5 bits only
|
||||
|
||||
#define HITAG2_READ_PAGE 0x3 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||
#define HITAG2_READ_PAGE_INVERTED 0x1 // page number in bits 5 to 3, page number inverted in bit 0 and following 2 bits
|
||||
#define HITAG2_WRITE_PAGE 0x2 // page number in bits 5 to 3, page number
|
||||
|
||||
|
||||
// HITAG S commands
|
||||
#define HITAGS_QUIET 0x70
|
||||
//inverted in bit 0 and following 2 bits
|
||||
#define HITAGS_WRITE_BLOCK 0x90
|
||||
|
||||
// LTO-CM commands
|
||||
#define LTO_REQ_STANDARD 0x45
|
||||
@@ -602,7 +610,6 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
||||
#define LTO_READBLOCK 0x30
|
||||
#define LTO_READBLOCK_CONT 0x80
|
||||
#define LTO_SELECT 0x93
|
||||
#define LTO_SELECT_1 0x97
|
||||
#define LTO_WRITEWORD 0xB0 // write 2 bytes (word)
|
||||
#define LTO_WRITEBLOCK 0xA0
|
||||
#define LTO_HALT 0x50
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user