mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-22 06:13:51 -07:00
Merge remote-tracking branch 'remotes/origin/master' into standalone-mfc-rewrite
This commit is contained in:
commit
bf86f3a84a
69 changed files with 1145 additions and 621 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -122,3 +122,7 @@ fpga_version_info.c
|
||||||
|
|
||||||
# docs
|
# docs
|
||||||
!doc/*.json
|
!doc/*.json
|
||||||
|
|
||||||
|
# local codeql
|
||||||
|
_codeql*
|
||||||
|
/codeql
|
|
@ -4,7 +4,12 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
||||||
|
|
||||||
## [unreleased][unreleased]
|
## [unreleased][unreleased]
|
||||||
- Changed standalone mode HF_MATTYRUN - support more card sizes, user dictionaries, improved emulation (@michaelroland)
|
- Changed standalone mode HF_MATTYRUN - support more card sizes, user dictionaries, improved emulation (@michaelroland)
|
||||||
- Added AIDs `002000` and `FF30FF` from Metrolinx Presto Card (@RunTheBot)
|
- Fixed wrong use of free() in desfire crypto on arm src, thanks @jlitewski! (@iceman1001)
|
||||||
|
- Added `lf em 4x70 calc` - calculate `frn`/`grn` for a given `key` + `rnd`
|
||||||
|
- Fixed `hf 15 dump` memory leaks (@jlitewski)
|
||||||
|
- Changed `hf search` - topaz is detect before ISO14443a and commented out WIP ICT code path (@iceman1001)
|
||||||
|
- Fixed `hf search` - where felica reader now doesnt timeout and give wrong response (@iceman1001)
|
||||||
|
- Fixed overflow in deps/jansson library (@iceman1001)
|
||||||
- Added `lf hitag crack2` - WIP. Trying to add the second attack vector against Hitag2 (@iceman1001)
|
- Added `lf hitag crack2` - WIP. Trying to add the second attack vector against Hitag2 (@iceman1001)
|
||||||
- Changed `hf 14b reader --plot` - made the anticollision signal trace download optional (@iceman1001)
|
- Changed `hf 14b reader --plot` - made the anticollision signal trace download optional (@iceman1001)
|
||||||
- Added `lf_hitag_crypto.trace` - trace file of a complete read out of a Hitag2 in crypto mode (@iceman1001)
|
- Added `lf_hitag_crypto.trace` - trace file of a complete read out of a Hitag2 in crypto mode (@iceman1001)
|
||||||
|
|
|
@ -48,7 +48,6 @@ void RunMod(void) {
|
||||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||||
|
|
||||||
const uint32_t high = 0x20; // LF high value is always 0x20 here
|
const uint32_t high = 0x20; // LF high value is always 0x20 here
|
||||||
uint32_t low = 0;
|
|
||||||
|
|
||||||
uint32_t fac = FACILITY_CODE, cardnum = 0;
|
uint32_t fac = FACILITY_CODE, cardnum = 0;
|
||||||
|
|
||||||
|
@ -80,7 +79,7 @@ void RunMod(void) {
|
||||||
if (BUTTON_HELD(1000) == BUTTON_HOLD) break; // long button press (>=1sec) exit
|
if (BUTTON_HELD(1000) == BUTTON_HOLD) break; // long button press (>=1sec) exit
|
||||||
|
|
||||||
// calculate the new LF low value including Card number, Facility code and checksum
|
// calculate the new LF low value including Card number, Facility code and checksum
|
||||||
low = (cardnum << 1) | (fac << 17);
|
uint32_t low = (cardnum << 1) | (fac << 17);
|
||||||
low |= oddparity32((low >> 1) & 0xFFF);
|
low |= oddparity32((low >> 1) & 0xFFF);
|
||||||
low |= evenparity32((low >> 13) & 0xFFF) << 25;
|
low |= evenparity32((low >> 13) & 0xFFF) << 25;
|
||||||
|
|
||||||
|
|
|
@ -101,9 +101,9 @@ void Dbhexdump(int len, const uint8_t *d, bool bAsci) {
|
||||||
d += 16;
|
d += 16;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}void print_result(const char *name, const uint8_t *d, size_t
|
||||||
|
|
||||||
void print_result(const char *name, const uint8_t *d, size_t n) {
|
n) {
|
||||||
|
|
||||||
const uint8_t *p = d;
|
const uint8_t *p = d;
|
||||||
uint16_t tmp = n & 0xFFF0;
|
uint16_t tmp = n & 0xFFF0;
|
||||||
|
@ -129,7 +129,7 @@ void print_result(const char *name, const uint8_t *d, size_t n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prints message and hexdump
|
// Prints message and hexdump
|
||||||
void print_dbg(char *msg, uint8_t *d, uint16_t n) {
|
void print_dbg(const char *msg, const uint8_t *d, uint16_t n) {
|
||||||
if (g_dbglevel == DBG_DEBUG) {
|
if (g_dbglevel == DBG_DEBUG) {
|
||||||
print_result(msg, d, n);
|
print_result(msg, d, n);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@ void DbpStringEx(uint32_t flags, const char *src, size_t srclen);
|
||||||
void Dbprintf(const char *fmt, ...);
|
void Dbprintf(const char *fmt, ...);
|
||||||
void DbprintfEx(uint32_t flags, const char *fmt, ...);
|
void DbprintfEx(uint32_t flags, const char *fmt, ...);
|
||||||
void Dbhexdump(int len, const uint8_t *d, bool bAsci);
|
void Dbhexdump(int len, const uint8_t *d, bool bAsci);
|
||||||
void print_result(const char *name, const uint8_t *buf, size_t len);
|
void print_result(const char *name, const uint8_t *d, size_t n);
|
||||||
void print_dbg(char *msg, uint8_t *d, uint16_t n);
|
void print_dbg(const char *msg, const uint8_t *d, uint16_t n);
|
||||||
//void PrintToSendBuffer(void);
|
//void PrintToSendBuffer(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -543,30 +543,35 @@ void *mifare_cryto_preprocess_data(desfiretag_t tag, void *data, size_t *nbytes,
|
||||||
|
|
||||||
void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes, int communication_settings) {
|
void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes, int communication_settings) {
|
||||||
void *res = data;
|
void *res = data;
|
||||||
void *edata = NULL;
|
|
||||||
uint8_t first_cmac_byte = 0x00;
|
uint8_t first_cmac_byte = 0x00;
|
||||||
|
|
||||||
desfirekey_t key = DESFIRE(tag)->session_key;
|
desfirekey_t key = DESFIRE(tag)->session_key;
|
||||||
|
|
||||||
if (!key)
|
if (!key) {
|
||||||
return data;
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
// Return directly if we just have a status code.
|
// Return directly if we just have a status code.
|
||||||
if (1 == *nbytes)
|
if (1 == *nbytes) {
|
||||||
return res;
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
switch (communication_settings & MDCM_MASK) {
|
switch (communication_settings & MDCM_MASK) {
|
||||||
case MDCM_PLAIN:
|
case MDCM_PLAIN: {
|
||||||
|
|
||||||
if (AS_LEGACY == DESFIRE(tag)->authentication_scheme)
|
if (AS_LEGACY == DESFIRE(tag)->authentication_scheme) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* pass through */
|
/* pass through */
|
||||||
case MDCM_MACED:
|
case MDCM_MACED: {
|
||||||
switch (DESFIRE(tag)->authentication_scheme) {
|
switch (DESFIRE(tag)->authentication_scheme) {
|
||||||
case AS_LEGACY:
|
case AS_LEGACY: {
|
||||||
if (communication_settings & MAC_VERIFY) {
|
|
||||||
|
if ((communication_settings & MAC_VERIFY) == MAC_VERIFY) {
|
||||||
|
|
||||||
*nbytes -= key_macing_length(key);
|
*nbytes -= key_macing_length(key);
|
||||||
|
|
||||||
if (*nbytes == 0) {
|
if (*nbytes == 0) {
|
||||||
*nbytes = -1;
|
*nbytes = -1;
|
||||||
res = NULL;
|
res = NULL;
|
||||||
|
@ -577,18 +582,17 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t edl = enciphered_data_length(tag, *nbytes - 1, communication_settings);
|
size_t edl = enciphered_data_length(tag, *nbytes - 1, communication_settings);
|
||||||
edata = BigBuf_malloc(edl);
|
uint8_t edata[edl];
|
||||||
|
memset(edata, 0, sizeof(edata));
|
||||||
memcpy(edata, data, *nbytes - 1);
|
memcpy(edata, data, *nbytes - 1);
|
||||||
memset((uint8_t *)edata + *nbytes - 1, 0, edl - *nbytes + 1);
|
|
||||||
|
|
||||||
mifare_cypher_blocks_chained(tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER);
|
mifare_cypher_blocks_chained(tag, NULL, NULL, edata, edl, MCD_SEND, MCO_ENCYPHER);
|
||||||
|
|
||||||
if (0 != memcmp((uint8_t *)data + *nbytes - 1, (uint8_t *)edata + edl - 8, 4)) {
|
if (0 != memcmp((uint8_t *)data + *nbytes - 1, edata + edl - 8, 4)) {
|
||||||
#ifdef WITH_DEBUG
|
#ifdef WITH_DEBUG
|
||||||
Dbprintf("MACing not verified");
|
Dbprintf("MACing not verified");
|
||||||
hexdump((uint8_t *)data + *nbytes - 1, key_macing_length(key), "Expect ", 0);
|
hexdump((uint8_t *)data + *nbytes - 1, key_macing_length(key), "Expect ", 0);
|
||||||
hexdump((uint8_t *)edata + edl - 8, key_macing_length(key), "Actual ", 0);
|
hexdump(edata + edl - 8, key_macing_length(key), "Actual ", 0);
|
||||||
#endif
|
#endif
|
||||||
DESFIRE(tag)->last_pcd_error = CRYPTO_ERROR;
|
DESFIRE(tag)->last_pcd_error = CRYPTO_ERROR;
|
||||||
*nbytes = -1;
|
*nbytes = -1;
|
||||||
|
@ -596,10 +600,16 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AS_NEW:
|
}
|
||||||
if (!(communication_settings & CMAC_COMMAND))
|
case AS_NEW: {
|
||||||
|
|
||||||
|
if ((communication_settings & CMAC_COMMAND) != CMAC_COMMAND) {
|
||||||
break;
|
break;
|
||||||
if (communication_settings & CMAC_VERIFY) {
|
}
|
||||||
|
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
if ((communication_settings & CMAC_VERIFY) == CMAC_VERIFY) {
|
||||||
if (*nbytes < 9) {
|
if (*nbytes < 9) {
|
||||||
*nbytes = -1;
|
*nbytes = -1;
|
||||||
res = NULL;
|
res = NULL;
|
||||||
|
@ -607,13 +617,16 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
}
|
}
|
||||||
first_cmac_byte = ((uint8_t *)data)[*nbytes - 9];
|
first_cmac_byte = ((uint8_t *)data)[*nbytes - 9];
|
||||||
((uint8_t *)data)[*nbytes - 9] = ((uint8_t *)data)[*nbytes - 1];
|
((uint8_t *)data)[*nbytes - 9] = ((uint8_t *)data)[*nbytes - 1];
|
||||||
|
|
||||||
|
n = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = (communication_settings & CMAC_VERIFY) ? 8 : 0;
|
|
||||||
cmac(key, DESFIRE(tag)->ivect, ((uint8_t *)data), *nbytes - n, DESFIRE(tag)->cmac);
|
cmac(key, DESFIRE(tag)->ivect, ((uint8_t *)data), *nbytes - n, DESFIRE(tag)->cmac);
|
||||||
|
|
||||||
if (communication_settings & CMAC_VERIFY) {
|
if ((communication_settings & CMAC_VERIFY) == CMAC_VERIFY) {
|
||||||
|
|
||||||
((uint8_t *)data)[*nbytes - 9] = first_cmac_byte;
|
((uint8_t *)data)[*nbytes - 9] = first_cmac_byte;
|
||||||
|
|
||||||
if (0 != memcmp(DESFIRE(tag)->cmac, (uint8_t *)data + *nbytes - 9, 8)) {
|
if (0 != memcmp(DESFIRE(tag)->cmac, (uint8_t *)data + *nbytes - 9, 8)) {
|
||||||
#ifdef WITH_DEBUG
|
#ifdef WITH_DEBUG
|
||||||
Dbprintf("CMAC NOT verified :-(");
|
Dbprintf("CMAC NOT verified :-(");
|
||||||
|
@ -629,11 +642,10 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
free(edata);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case MDCM_ENCIPHERED:
|
}
|
||||||
|
case MDCM_ENCIPHERED: {
|
||||||
(*nbytes)--;
|
(*nbytes)--;
|
||||||
bool verified = false;
|
bool verified = false;
|
||||||
int crc_pos = 0x00;
|
int crc_pos = 0x00;
|
||||||
|
@ -670,48 +682,50 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
* verified, and accumulating 0's in it should not change it.
|
* verified, and accumulating 0's in it should not change it.
|
||||||
*/
|
*/
|
||||||
switch (DESFIRE(tag)->authentication_scheme) {
|
switch (DESFIRE(tag)->authentication_scheme) {
|
||||||
case AS_LEGACY:
|
case AS_LEGACY: {
|
||||||
crc_pos = *nbytes - 8 - 1; // The CRC can be over two blocks
|
crc_pos = *nbytes - 8 - 1; // The CRC can be over two blocks
|
||||||
if (crc_pos < 0) {
|
if (crc_pos < 0) {
|
||||||
/* Single block */
|
crc_pos = 0; // Single block
|
||||||
crc_pos = 0;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case AS_NEW:
|
}
|
||||||
|
case AS_NEW: {
|
||||||
/* Move status between payload and CRC */
|
/* Move status between payload and CRC */
|
||||||
res = DESFIRE(tag)->crypto_buffer;
|
res = DESFIRE(tag)->crypto_buffer;
|
||||||
memcpy(res, data, *nbytes);
|
memcpy(res, data, *nbytes);
|
||||||
|
|
||||||
crc_pos = (*nbytes) - 16 - 3;
|
crc_pos = (*nbytes) - 16 - 3;
|
||||||
if (crc_pos < 0) {
|
if (crc_pos < 0) {
|
||||||
/* Single block */
|
crc_pos = 0; // Single block
|
||||||
crc_pos = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy((uint8_t *)res + crc_pos + 1, (uint8_t *)res + crc_pos, *nbytes - crc_pos);
|
memcpy((uint8_t *)res + crc_pos + 1, (uint8_t *)res + crc_pos, *nbytes - crc_pos);
|
||||||
((uint8_t *)res)[crc_pos] = 0x00;
|
((uint8_t *)res)[crc_pos] = 0x00;
|
||||||
crc_pos++;
|
crc_pos++;
|
||||||
*nbytes += 1;
|
*nbytes += 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint16_t crc_16 = 0x00;
|
uint16_t crc_16 = 0x00;
|
||||||
uint32_t crc = 0x00;
|
uint32_t crc = 0x00;
|
||||||
|
|
||||||
switch (DESFIRE(tag)->authentication_scheme) {
|
switch (DESFIRE(tag)->authentication_scheme) {
|
||||||
case AS_LEGACY:
|
case AS_LEGACY: {
|
||||||
AddCrc14A((uint8_t *)res, end_crc_pos);
|
AddCrc14A((uint8_t *)res, end_crc_pos);
|
||||||
end_crc_pos = crc_pos + 2;
|
end_crc_pos = crc_pos + 2;
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
crc = crc_16;
|
crc = crc_16;
|
||||||
break;
|
break;
|
||||||
case AS_NEW:
|
}
|
||||||
|
case AS_NEW: {
|
||||||
end_crc_pos = crc_pos + 4;
|
end_crc_pos = crc_pos + 4;
|
||||||
crc32_ex(res, end_crc_pos, (uint8_t *)&crc);
|
crc32_ex(res, end_crc_pos, (uint8_t *)&crc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!crc) {
|
}
|
||||||
|
|
||||||
|
if (crc == 0) {
|
||||||
verified = true;
|
verified = true;
|
||||||
for (int n = end_crc_pos; n < *nbytes - 1; n++) {
|
for (int n = end_crc_pos; n < *nbytes - 1; n++) {
|
||||||
uint8_t byte = ((uint8_t *)res)[n];
|
uint8_t byte = ((uint8_t *)res)[n];
|
||||||
|
@ -719,31 +733,40 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
verified = false;
|
verified = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verified) {
|
if (verified) {
|
||||||
|
|
||||||
*nbytes = crc_pos;
|
*nbytes = crc_pos;
|
||||||
|
|
||||||
switch (DESFIRE(tag)->authentication_scheme) {
|
switch (DESFIRE(tag)->authentication_scheme) {
|
||||||
case AS_LEGACY:
|
case AS_LEGACY: {
|
||||||
((uint8_t *)data)[(*nbytes)++] = 0x00;
|
((uint8_t *)data)[(*nbytes)++] = 0x00;
|
||||||
break;
|
break;
|
||||||
case AS_NEW:
|
}
|
||||||
|
case AS_NEW: {
|
||||||
/* The status byte was already before the CRC */
|
/* The status byte was already before the CRC */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
switch (DESFIRE(tag)->authentication_scheme) {
|
switch (DESFIRE(tag)->authentication_scheme) {
|
||||||
case AS_LEGACY:
|
case AS_LEGACY: {
|
||||||
break;
|
break;
|
||||||
case AS_NEW:
|
}
|
||||||
|
case AS_NEW: {
|
||||||
x = ((uint8_t *)res)[crc_pos - 1];
|
x = ((uint8_t *)res)[crc_pos - 1];
|
||||||
((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos];
|
((uint8_t *)res)[crc_pos - 1] = ((uint8_t *)res)[crc_pos];
|
||||||
((uint8_t *)res)[crc_pos] = x;
|
((uint8_t *)res)[crc_pos] = x;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
crc_pos++;
|
crc_pos++;
|
||||||
}
|
}
|
||||||
} while (!verified && (end_crc_pos < *nbytes));
|
|
||||||
|
|
||||||
if (!verified) {
|
} while (verified == false && (end_crc_pos < *nbytes));
|
||||||
|
|
||||||
|
if (verified == false) {
|
||||||
#ifdef WITH_DEBUG
|
#ifdef WITH_DEBUG
|
||||||
/* FIXME In some configurations, the file is transmitted PLAIN */
|
/* FIXME In some configurations, the file is transmitted PLAIN */
|
||||||
Dbprintf("CRC not verified in decyphered stream");
|
Dbprintf("CRC not verified in decyphered stream");
|
||||||
|
@ -752,14 +775,14 @@ void *mifare_cryto_postprocess_data(desfiretag_t tag, void *data, size_t *nbytes
|
||||||
*nbytes = -1;
|
*nbytes = -1;
|
||||||
res = NULL;
|
res = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
Dbprintf("Unknown communication settings");
|
Dbprintf("Unknown communication settings");
|
||||||
*nbytes = -1;
|
*nbytes = -1;
|
||||||
res = NULL;
|
res = NULL;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1255,7 +1255,11 @@ static int em4x50_sim_read_bit(void) {
|
||||||
int cycles = 0;
|
int cycles = 0;
|
||||||
int timeout = EM4X50_T_SIMULATION_TIMEOUT_READ;
|
int timeout = EM4X50_T_SIMULATION_TIMEOUT_READ;
|
||||||
|
|
||||||
while (cycles < EM4X50_T_TAG_FULL_PERIOD) {
|
// wait 16 cycles to make sure there is no field when reading a "0" bit
|
||||||
|
uint32_t waitval = GetTicks();
|
||||||
|
while(GetTicks() - waitval < EM4X50_T_TAG_QUARTER_PERIOD * CYCLES2TICKS);
|
||||||
|
|
||||||
|
while (cycles < EM4X50_T_TAG_THREE_QUARTER_PERIOD) {
|
||||||
|
|
||||||
// wait until reader field disappears
|
// wait until reader field disappears
|
||||||
while ((timeout--) && !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK));
|
while ((timeout--) && !(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_CLK));
|
||||||
|
|
|
@ -30,6 +30,8 @@ static em4x70_tag_t tag = { 0 };
|
||||||
// EM4170 requires a parity bit on commands, other variants do not.
|
// EM4170 requires a parity bit on commands, other variants do not.
|
||||||
static bool command_parity = true;
|
static bool command_parity = true;
|
||||||
|
|
||||||
|
|
||||||
|
#if 1 // Calculation of ticks for timing functions
|
||||||
// Conversion from Ticks to RF periods
|
// Conversion from Ticks to RF periods
|
||||||
// 1 us = 1.5 ticks
|
// 1 us = 1.5 ticks
|
||||||
// 1RF Period = 8us = 12 Ticks
|
// 1RF Period = 8us = 12 Ticks
|
||||||
|
@ -55,11 +57,15 @@ static bool command_parity = true;
|
||||||
|
|
||||||
#define EM4X70_COMMAND_RETRIES 5 // Attempts to send/read command
|
#define EM4X70_COMMAND_RETRIES 5 // Attempts to send/read command
|
||||||
#define EM4X70_MAX_RECEIVE_LENGTH 96 // Maximum bits to expect from any command
|
#define EM4X70_MAX_RECEIVE_LENGTH 96 // Maximum bits to expect from any command
|
||||||
|
#endif // Calculation of ticks for timing functions
|
||||||
|
|
||||||
|
#if 1 // EM4x70 Command IDs
|
||||||
/**
|
/**
|
||||||
* These IDs are from the EM4170 datasheet
|
* These IDs are from the EM4170 datasheet.
|
||||||
* Some versions of the chip require a
|
* Some versions of the chip require a
|
||||||
* (even) parity bit, others do not
|
* (even) parity bit, others do not.
|
||||||
|
* The command is thus stored only in the
|
||||||
|
* three least significant bits (mask 0x07).
|
||||||
*/
|
*/
|
||||||
#define EM4X70_COMMAND_ID 0x01
|
#define EM4X70_COMMAND_ID 0x01
|
||||||
#define EM4X70_COMMAND_UM1 0x02
|
#define EM4X70_COMMAND_UM1 0x02
|
||||||
|
@ -67,6 +73,7 @@ static bool command_parity = true;
|
||||||
#define EM4X70_COMMAND_PIN 0x04
|
#define EM4X70_COMMAND_PIN 0x04
|
||||||
#define EM4X70_COMMAND_WRITE 0x05
|
#define EM4X70_COMMAND_WRITE 0x05
|
||||||
#define EM4X70_COMMAND_UM2 0x07
|
#define EM4X70_COMMAND_UM2 0x07
|
||||||
|
#endif // EM4x70 Command IDs
|
||||||
|
|
||||||
// Constants used to determine high/low state of signal
|
// Constants used to determine high/low state of signal
|
||||||
#define EM4X70_NOISE_THRESHOLD 13 // May depend on noise in environment
|
#define EM4X70_NOISE_THRESHOLD 13 // May depend on noise in environment
|
||||||
|
@ -80,9 +87,9 @@ static bool command_parity = true;
|
||||||
#define IS_TIMEOUT(timeout_ticks) (GetTicks() > timeout_ticks)
|
#define IS_TIMEOUT(timeout_ticks) (GetTicks() > timeout_ticks)
|
||||||
#define TICKS_ELAPSED(start_ticks) (GetTicks() - start_ticks)
|
#define TICKS_ELAPSED(start_ticks) (GetTicks() - start_ticks)
|
||||||
|
|
||||||
static uint8_t bits2byte(const uint8_t *bits, int length);
|
static uint8_t encoded_bit_array_to_byte(const uint8_t *bits, int count_of_bits);
|
||||||
static void bits2bytes(const uint8_t *bits, int length, uint8_t *out);
|
static void encoded_bit_array_to_bytes(const uint8_t *bits, int count_of_bits, uint8_t *out);
|
||||||
static int em4x70_receive(uint8_t *bits, size_t length);
|
static int em4x70_receive(uint8_t *bits, size_t maximum_bits_to_read);
|
||||||
static bool find_listen_window(bool command);
|
static bool find_listen_window(bool command);
|
||||||
|
|
||||||
static void init_tag(void) {
|
static void init_tag(void) {
|
||||||
|
@ -207,9 +214,10 @@ static uint32_t get_pulse_length(edge_detection_t edge) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool check_pulse_length(uint32_t pl, uint32_t length) {
|
static bool check_pulse_length(uint32_t pulse_tick_length, uint32_t target_tick_length) {
|
||||||
// check if pulse length <pl> corresponds to given length <length>
|
// check if pulse tick length corresponds to target length (+/- tolerance)
|
||||||
return ((pl >= (length - EM4X70_T_TAG_TOLERANCE)) && (pl <= (length + EM4X70_T_TAG_TOLERANCE)));
|
return ((pulse_tick_length >= (target_tick_length - EM4X70_T_TAG_TOLERANCE)) &&
|
||||||
|
(pulse_tick_length <= (target_tick_length + EM4X70_T_TAG_TOLERANCE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void em4x70_send_bit(bool bit) {
|
static void em4x70_send_bit(bool bit) {
|
||||||
|
@ -344,7 +352,11 @@ static int authenticate(const uint8_t *rnd, const uint8_t *frnd, uint8_t *respon
|
||||||
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Auth failed");
|
if (g_dbglevel >= DBG_EXTENDED) Dbprintf("Auth failed");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
bits2bytes(grnd, 24, response);
|
// although only received 20 bits
|
||||||
|
// ask for 24 bits converted because
|
||||||
|
// this utility function requires
|
||||||
|
// decoding in multiples of 8 bits
|
||||||
|
encoded_bit_array_to_bytes(grnd, 24, response);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,12 +467,12 @@ static int send_pin(const uint32_t pin) {
|
||||||
WaitTicks(EM4X70_T_TAG_WEE);
|
WaitTicks(EM4X70_T_TAG_WEE);
|
||||||
// <-- Receive header + ID
|
// <-- Receive header + ID
|
||||||
uint8_t tag_id[EM4X70_MAX_RECEIVE_LENGTH];
|
uint8_t tag_id[EM4X70_MAX_RECEIVE_LENGTH];
|
||||||
int num = em4x70_receive(tag_id, 32);
|
int count_of_bits_received = em4x70_receive(tag_id, 32);
|
||||||
if (num < 32) {
|
if (count_of_bits_received < 32) {
|
||||||
Dbprintf("Invalid ID Received");
|
Dbprintf("Invalid ID Received");
|
||||||
return PM3_ESOFT;
|
return PM3_ESOFT;
|
||||||
}
|
}
|
||||||
bits2bytes(tag_id, num, &tag.data[4]);
|
encoded_bit_array_to_bytes(tag_id, count_of_bits_received, &tag.data[4]);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -537,36 +549,38 @@ static bool find_listen_window(bool command) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bits2bytes(const uint8_t *bits, int length, uint8_t *out) {
|
// *bits == array of bytes, each byte storing a single bit.
|
||||||
|
// *out == array of bytes, storing converted bits --> bytes.
|
||||||
|
//
|
||||||
|
// [in, bcount(count_of_bits) ] const uint8_t *bits
|
||||||
|
// [out, bcount(count_of_bits/8)] uint8_t *out
|
||||||
|
static void encoded_bit_array_to_bytes(const uint8_t *bits, int count_of_bits, uint8_t *out) {
|
||||||
|
|
||||||
if (length % 8 != 0) {
|
if (count_of_bits % 8 != 0) {
|
||||||
Dbprintf("Should have a multiple of 8 bits, was sent %d", length);
|
Dbprintf("Should have a multiple of 8 bits, was sent %d", count_of_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
int num_bytes = length / 8; // We should have a multiple of 8 here
|
int num_bytes = count_of_bits / 8; // We should have a multiple of 8 here
|
||||||
|
|
||||||
for (int i = 1; i <= num_bytes; i++) {
|
for (int i = 1; i <= num_bytes; i++) {
|
||||||
out[num_bytes - i] = bits2byte(bits, 8);
|
out[num_bytes - i] = encoded_bit_array_to_byte(bits, 8);
|
||||||
bits += 8;
|
bits += 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t bits2byte(const uint8_t *bits, int length) {
|
static uint8_t encoded_bit_array_to_byte(const uint8_t *bits, int count_of_bits) {
|
||||||
|
|
||||||
// converts <length> separate bits into a single "byte"
|
// converts <count_of_bits> separate bits into a single "byte"
|
||||||
uint8_t byte = 0;
|
uint8_t byte = 0;
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < count_of_bits; i++) {
|
||||||
|
|
||||||
byte |= bits[i];
|
|
||||||
|
|
||||||
if (i != length - 1)
|
|
||||||
byte <<= 1;
|
byte <<= 1;
|
||||||
|
byte |= bits[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return byte;
|
return byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool send_command_and_read(uint8_t command, uint8_t *bytes, size_t length) {
|
static bool send_command_and_read(uint8_t command, uint8_t *bytes, size_t expected_byte_count) {
|
||||||
|
|
||||||
int retries = EM4X70_COMMAND_RETRIES;
|
int retries = EM4X70_COMMAND_RETRIES;
|
||||||
while (retries) {
|
while (retries) {
|
||||||
|
@ -574,14 +588,14 @@ static bool send_command_and_read(uint8_t command, uint8_t *bytes, size_t length
|
||||||
|
|
||||||
if (find_listen_window(true)) {
|
if (find_listen_window(true)) {
|
||||||
uint8_t bits[EM4X70_MAX_RECEIVE_LENGTH] = {0};
|
uint8_t bits[EM4X70_MAX_RECEIVE_LENGTH] = {0};
|
||||||
size_t out_length_bits = length * 8;
|
size_t out_length_bits = expected_byte_count * 8;
|
||||||
em4x70_send_nibble(command, command_parity);
|
em4x70_send_nibble(command, command_parity);
|
||||||
int len = em4x70_receive(bits, out_length_bits);
|
int len = em4x70_receive(bits, out_length_bits);
|
||||||
if (len < out_length_bits) {
|
if (len < out_length_bits) {
|
||||||
Dbprintf("Invalid data received length: %d, expected %d", len, out_length_bits);
|
Dbprintf("Invalid data received length: %d, expected %d", len, out_length_bits);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
bits2bytes(bits, len, bytes);
|
encoded_bit_array_to_bytes(bits, len, bytes);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -629,7 +643,7 @@ static bool find_em4x70_tag(void) {
|
||||||
return find_listen_window(false);
|
return find_listen_window(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int em4x70_receive(uint8_t *bits, size_t length) {
|
static int em4x70_receive(uint8_t *bits, size_t maximum_bits_to_read) {
|
||||||
|
|
||||||
uint32_t pl;
|
uint32_t pl;
|
||||||
int bit_pos = 0;
|
int bit_pos = 0;
|
||||||
|
@ -667,7 +681,7 @@ static int em4x70_receive(uint8_t *bits, size_t length) {
|
||||||
|
|
||||||
// identify remaining bits based on pulse lengths
|
// identify remaining bits based on pulse lengths
|
||||||
// between listen windows only pulse lengths of 1, 1.5 and 2 are possible
|
// between listen windows only pulse lengths of 1, 1.5 and 2 are possible
|
||||||
while (bit_pos < length) {
|
while (bit_pos < maximum_bits_to_read) {
|
||||||
|
|
||||||
pl = get_pulse_length(edge);
|
pl = get_pulse_length(edge);
|
||||||
|
|
||||||
|
@ -681,13 +695,13 @@ static int em4x70_receive(uint8_t *bits, size_t length) {
|
||||||
// pulse length 1.5 -> 2 bits + flip edge detection
|
// pulse length 1.5 -> 2 bits + flip edge detection
|
||||||
if (edge == FALLING_EDGE) {
|
if (edge == FALLING_EDGE) {
|
||||||
bits[bit_pos++] = 0;
|
bits[bit_pos++] = 0;
|
||||||
if (bit_pos < length) {
|
if (bit_pos < maximum_bits_to_read) {
|
||||||
bits[bit_pos++] = 0;
|
bits[bit_pos++] = 0;
|
||||||
}
|
}
|
||||||
edge = RISING_EDGE;
|
edge = RISING_EDGE;
|
||||||
} else {
|
} else {
|
||||||
bits[bit_pos++] = 1;
|
bits[bit_pos++] = 1;
|
||||||
if (bit_pos < length) {
|
if (bit_pos < maximum_bits_to_read) {
|
||||||
bits[bit_pos++] = 1;
|
bits[bit_pos++] = 1;
|
||||||
}
|
}
|
||||||
edge = FALLING_EDGE;
|
edge = FALLING_EDGE;
|
||||||
|
@ -698,12 +712,12 @@ static int em4x70_receive(uint8_t *bits, size_t length) {
|
||||||
// pulse length of 2 -> two bits
|
// pulse length of 2 -> two bits
|
||||||
if (edge == FALLING_EDGE) {
|
if (edge == FALLING_EDGE) {
|
||||||
bits[bit_pos++] = 0;
|
bits[bit_pos++] = 0;
|
||||||
if (bit_pos < length) {
|
if (bit_pos < maximum_bits_to_read) {
|
||||||
bits[bit_pos++] = 1;
|
bits[bit_pos++] = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bits[bit_pos++] = 1;
|
bits[bit_pos++] = 1;
|
||||||
if (bit_pos < length) {
|
if (bit_pos < maximum_bits_to_read) {
|
||||||
bits[bit_pos++] = 0;
|
bits[bit_pos++] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,7 +239,7 @@ static uint8_t felica_select_card(felica_card_select_t *card) {
|
||||||
|
|
||||||
|
|
||||||
// We try 10 times, or if answer was received.
|
// We try 10 times, or if answer was received.
|
||||||
int len = 50;
|
int len = 25;
|
||||||
do {
|
do {
|
||||||
// end-of-reception response packet data, wait approx. 501μs
|
// end-of-reception response packet data, wait approx. 501μs
|
||||||
// end-of-transmission command packet data, wait approx. 197μs
|
// end-of-transmission command packet data, wait approx. 197μs
|
||||||
|
@ -544,16 +544,13 @@ void felica_sendraw(const PacketCommandNG *c) {
|
||||||
|
|
||||||
felica_command_t param = c->oldarg[0];
|
felica_command_t param = c->oldarg[0];
|
||||||
size_t len = c->oldarg[1] & 0xffff;
|
size_t len = c->oldarg[1] & 0xffff;
|
||||||
const uint8_t *cmd = c->data.asBytes;
|
|
||||||
uint32_t arg0;
|
uint32_t arg0;
|
||||||
|
|
||||||
felica_card_select_t card;
|
|
||||||
|
|
||||||
if ((param & FELICA_CONNECT) == FELICA_CONNECT) {
|
if ((param & FELICA_CONNECT) == FELICA_CONNECT) {
|
||||||
clear_trace();
|
clear_trace();
|
||||||
}
|
}
|
||||||
|
|
||||||
set_tracing(true);
|
set_tracing(true);
|
||||||
|
|
||||||
iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
iso18092_setup(FPGA_HF_ISO18092_FLAG_READER | FPGA_HF_ISO18092_FLAG_NOMOD);
|
||||||
|
|
||||||
if ((param & FELICA_CONNECT) == FELICA_CONNECT) {
|
if ((param & FELICA_CONNECT) == FELICA_CONNECT) {
|
||||||
|
@ -562,6 +559,7 @@ void felica_sendraw(const PacketCommandNG *c) {
|
||||||
// if failed selecting, turn off antenna and quite.
|
// if failed selecting, turn off antenna and quite.
|
||||||
if ((param & FELICA_NO_SELECT) != FELICA_NO_SELECT) {
|
if ((param & FELICA_NO_SELECT) != FELICA_NO_SELECT) {
|
||||||
|
|
||||||
|
felica_card_select_t card;
|
||||||
arg0 = felica_select_card(&card);
|
arg0 = felica_select_card(&card);
|
||||||
reply_mix(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t));
|
reply_mix(CMD_ACK, arg0, sizeof(card.uid), 0, &card, sizeof(felica_card_select_t));
|
||||||
if (arg0) {
|
if (arg0) {
|
||||||
|
@ -582,7 +580,7 @@ void felica_sendraw(const PacketCommandNG *c) {
|
||||||
buf[2] = len;
|
buf[2] = len;
|
||||||
|
|
||||||
// copy command
|
// copy command
|
||||||
memcpy(buf + 2, cmd, len);
|
memcpy(buf + 2, c->data.asBytes, len);
|
||||||
|
|
||||||
if ((param & FELICA_APPEND_CRC) == FELICA_APPEND_CRC) {
|
if ((param & FELICA_APPEND_CRC) == FELICA_APPEND_CRC) {
|
||||||
// Don't append crc on empty bytearray...
|
// Don't append crc on empty bytearray...
|
||||||
|
@ -631,7 +629,7 @@ void felica_sniff(uint32_t samplesToSkip, uint32_t triggersToSkip) {
|
||||||
int remFrames = (samplesToSkip) ? samplesToSkip : 0;
|
int remFrames = (samplesToSkip) ? samplesToSkip : 0;
|
||||||
int trigger_cnt = 0;
|
int trigger_cnt = 0;
|
||||||
uint32_t timeout = iso18092_get_timeout();
|
uint32_t timeout = iso18092_get_timeout();
|
||||||
bool isReaderFrame = true;
|
bool isReaderFrame;
|
||||||
|
|
||||||
uint8_t flip = 0;
|
uint8_t flip = 0;
|
||||||
uint16_t checker = 0;
|
uint16_t checker = 0;
|
||||||
|
@ -734,7 +732,7 @@ void felica_sim_lite(const uint8_t *uid) {
|
||||||
|
|
||||||
int retval = PM3_SUCCESS;
|
int retval = PM3_SUCCESS;
|
||||||
int curlen = 0;
|
int curlen = 0;
|
||||||
uint8_t *curresp = NULL;
|
const uint8_t *curresp = NULL;
|
||||||
bool listenmode = true;
|
bool listenmode = true;
|
||||||
// uint32_t frtm = GetCountSspClk();
|
// uint32_t frtm = GetCountSspClk();
|
||||||
|
|
||||||
|
@ -884,7 +882,7 @@ void felica_dump_lite_s(void) {
|
||||||
|
|
||||||
dest[cnt++] = liteblks[blknum];
|
dest[cnt++] = liteblks[blknum];
|
||||||
|
|
||||||
uint8_t *fb = FelicaFrame.framebytes;
|
const uint8_t *fb = FelicaFrame.framebytes;
|
||||||
dest[cnt++] = fb[12];
|
dest[cnt++] = fb[12];
|
||||||
dest[cnt++] = fb[13];
|
dest[cnt++] = fb[13];
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#define DBG if (g_dbglevel >= DBG_EXTENDED)
|
#define DBG if (g_dbglevel >= DBG_EXTENDED)
|
||||||
|
|
||||||
#include "hitag2.h"
|
#include "hitag2.h"
|
||||||
#include "hitag2_crypto.h"
|
#include "hitag2/hitag2_crypto.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "proxmark3_arm.h"
|
#include "proxmark3_arm.h"
|
||||||
#include "cmd.h"
|
#include "cmd.h"
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "hitag2_crack.h"
|
#include "hitag2_crack.h"
|
||||||
#include "hitag2_crypto.h"
|
#include "hitag2/hitag2_crypto.h"
|
||||||
#include "hitag2.h"
|
#include "hitag2.h"
|
||||||
#include "proxmark3_arm.h"
|
#include "proxmark3_arm.h"
|
||||||
#include "commonutil.h"
|
#include "commonutil.h"
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "commonutil.h"
|
#include "commonutil.h"
|
||||||
#include "hitag2_crypto.h"
|
#include "hitag2/hitag2_crypto.h"
|
||||||
#include "lfadc.h"
|
#include "lfadc.h"
|
||||||
#include "crc.h"
|
#include "crc.h"
|
||||||
|
|
||||||
|
@ -1090,7 +1090,7 @@ static void hitagS_receive_frame(uint8_t *rx, size_t sizeofrx, size_t *rxlen, ui
|
||||||
// Dbprintf("RX0 %i:%02X.. err:%i resptime:%i", *rxlen, rx[0], errorCount, *resptime);
|
// Dbprintf("RX0 %i:%02X.. err:%i resptime:%i", *rxlen, rx[0], errorCount, *resptime);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sendReceiveHitagS(uint8_t *tx, size_t txlen, uint8_t *rx, size_t sizeofrx, size_t *prxbits, int t_wait, bool ledcontrol, bool ac_seq) {
|
static void sendReceiveHitagS( const uint8_t *tx, size_t txlen, uint8_t *rx, size_t sizeofrx, size_t *prxbits, int t_wait, bool ledcontrol, bool ac_seq) {
|
||||||
|
|
||||||
LogTraceBits(tx, txlen, HITAG_T_WAIT_2, HITAG_T_WAIT_2, true);
|
LogTraceBits(tx, txlen, HITAG_T_WAIT_2, HITAG_T_WAIT_2, true);
|
||||||
|
|
||||||
|
@ -1557,7 +1557,7 @@ void WritePageHitagS(const lf_hitag_data_t *payload, bool ledcontrol) {
|
||||||
break;
|
break;
|
||||||
default: {
|
default: {
|
||||||
res = PM3_EINVARG;
|
res = PM3_EINVARG;
|
||||||
return;
|
goto write_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -764,7 +764,7 @@ bool sc_rx_bytes(uint8_t *dest, uint16_t *destlen, uint32_t wait) {
|
||||||
break;
|
break;
|
||||||
} else if (len == 1) {
|
} else if (len == 1) {
|
||||||
continue;
|
continue;
|
||||||
} else if (len <= 0) {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -937,7 +937,7 @@ void SmartCardUpgrade(uint64_t arg0) {
|
||||||
|
|
||||||
bool isOK = true;
|
bool isOK = true;
|
||||||
uint16_t length = arg0, pos = 0;
|
uint16_t length = arg0, pos = 0;
|
||||||
uint8_t *fwdata = BigBuf_get_addr();
|
const uint8_t *fwdata = BigBuf_get_addr();
|
||||||
uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE);
|
uint8_t *verfiydata = BigBuf_malloc(I2C_BLOCK_SIZE);
|
||||||
|
|
||||||
while (length) {
|
while (length) {
|
||||||
|
|
|
@ -68,6 +68,6 @@ void SmartCardUpgrade(uint64_t arg0);
|
||||||
void SmartCardSetBaud(uint64_t arg0);
|
void SmartCardSetBaud(uint64_t arg0);
|
||||||
void SmartCardSetClock(uint64_t arg0);
|
void SmartCardSetClock(uint64_t arg0);
|
||||||
void I2C_print_status(void);
|
void I2C_print_status(void);
|
||||||
int I2C_get_version(uint8_t *maj, uint8_t *min);
|
int I2C_get_version(uint8_t *major, uint8_t *minor);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -774,7 +774,7 @@ void SimulateIso14443bTag(const uint8_t *pupi) {
|
||||||
int cardSTATE = SIM_NOFIELD;
|
int cardSTATE = SIM_NOFIELD;
|
||||||
int vHf = 0; // in mV
|
int vHf = 0; // in mV
|
||||||
|
|
||||||
tosend_t *ts = get_tosend();
|
const tosend_t *ts = get_tosend();
|
||||||
|
|
||||||
uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
|
uint8_t *receivedCmd = BigBuf_calloc(MAX_FRAME_SIZE);
|
||||||
|
|
||||||
|
@ -1566,7 +1566,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len, bool framing) {
|
||||||
* Convenience function to encode, transmit and trace iso 14443b comms
|
* Convenience function to encode, transmit and trace iso 14443b comms
|
||||||
*/
|
*/
|
||||||
static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t *start_time, uint32_t *eof_time, bool framing) {
|
static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t *start_time, uint32_t *eof_time, bool framing) {
|
||||||
tosend_t *ts = get_tosend();
|
const tosend_t *ts = get_tosend();
|
||||||
CodeIso14443bAsReader(cmd, len, framing);
|
CodeIso14443bAsReader(cmd, len, framing);
|
||||||
TransmitFor14443b_AsReader(start_time);
|
TransmitFor14443b_AsReader(start_time);
|
||||||
if (g_trigger) LED_A_ON();
|
if (g_trigger) LED_A_ON();
|
||||||
|
@ -1582,7 +1582,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
|
||||||
/* Sends an APDU to the tag
|
/* Sends an APDU to the tag
|
||||||
* TODO: check CRC and preamble
|
* TODO: check CRC and preamble
|
||||||
*/
|
*/
|
||||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *response_byte, uint16_t *reponselen) {
|
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *response_byte, uint16_t *responselen) {
|
||||||
|
|
||||||
uint8_t real_cmd[msg_len + 4];
|
uint8_t real_cmd[msg_len + 4];
|
||||||
|
|
||||||
|
@ -1693,8 +1693,8 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reponselen) {
|
if (responselen) {
|
||||||
*reponselen = len;
|
*responselen = len;
|
||||||
}
|
}
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void iso14443b_setup(void);
|
void iso14443b_setup(void);
|
||||||
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res, uint16_t *responselen);
|
int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *response_byte, uint16_t *responselen);
|
||||||
|
|
||||||
int iso14443b_select_card(iso14b_card_select_t *card);
|
int iso14443b_select_card(iso14b_card_select_t *card);
|
||||||
|
|
||||||
|
|
|
@ -1009,7 +1009,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t dma_start_time = 0;
|
uint32_t dma_start_time = 0;
|
||||||
uint16_t *upTo = dma->buf;
|
const uint16_t *upTo = dma->buf;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
|
@ -1502,7 +1502,7 @@ int GetIso15693CommandFromReader(uint8_t *received, size_t max_len, uint32_t *eo
|
||||||
if (g_dbglevel > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting");
|
if (g_dbglevel > DBG_ERROR) Dbprintf("FpgaSetupSscDma failed. Exiting");
|
||||||
return -4;
|
return -4;
|
||||||
}
|
}
|
||||||
uint8_t *upTo = dma->buf;
|
const uint8_t *upTo = dma->buf;
|
||||||
|
|
||||||
uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8;
|
uint32_t dma_start_time = GetCountSspClk() & 0xfffffff8;
|
||||||
|
|
||||||
|
@ -1603,7 +1603,7 @@ void AcquireRawAdcSamplesIso15693(void) {
|
||||||
SpinDelay(250);
|
SpinDelay(250);
|
||||||
|
|
||||||
// Now send the command
|
// Now send the command
|
||||||
tosend_t *ts = get_tosend();
|
const tosend_t *ts = get_tosend();
|
||||||
|
|
||||||
uint32_t start_time = 0;
|
uint32_t start_time = 0;
|
||||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
|
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
|
||||||
|
@ -1681,7 +1681,7 @@ void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool icla
|
||||||
// Count of samples received so far, so that we can include timing
|
// Count of samples received so far, so that we can include timing
|
||||||
int samples = 0;
|
int samples = 0;
|
||||||
|
|
||||||
uint16_t *upTo = dma->buf;
|
const uint16_t *upTo = dma->buf;
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
|
@ -1902,7 +1902,7 @@ static void BuildIdentifyRequest(uint8_t *cmd) {
|
||||||
// If you do not need the answer use NULL for *recv[]
|
// If you do not need the answer use NULL for *recv[]
|
||||||
// return: length of received data
|
// return: length of received data
|
||||||
// logging enabled
|
// logging enabled
|
||||||
int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *recv,
|
int SendDataTag(const uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *recv,
|
||||||
uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, uint16_t *resp_len) {
|
uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, uint16_t *resp_len) {
|
||||||
|
|
||||||
if (init) {
|
if (init) {
|
||||||
|
@ -1918,7 +1918,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
|
||||||
CodeIso15693AsReader256(send, sendlen);
|
CodeIso15693AsReader256(send, sendlen);
|
||||||
}
|
}
|
||||||
|
|
||||||
tosend_t *ts = get_tosend();
|
const tosend_t *ts = get_tosend();
|
||||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
|
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
|
||||||
|
|
||||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occurred
|
||||||
|
@ -1941,7 +1941,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
|
||||||
int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, bool fsk, bool recv_speed, uint16_t *resp_len) {
|
int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, bool fsk, bool recv_speed, uint16_t *resp_len) {
|
||||||
|
|
||||||
CodeIso15693AsReaderEOF();
|
CodeIso15693AsReaderEOF();
|
||||||
tosend_t *ts = get_tosend();
|
const tosend_t *ts = get_tosend();
|
||||||
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
|
TransmitTo15693Tag(ts->buf, ts->max, &start_time, false);
|
||||||
uint32_t end_time = start_time + 32 * (8 * ts->max - 4); // subtract the 4 padding bits after EOF
|
uint32_t end_time = start_time + 32 * (8 * ts->max - 4); // subtract the 4 padding bits after EOF
|
||||||
LogTrace_ISO15693(NULL, 0, (start_time * 4), (end_time * 4), NULL, true);
|
LogTrace_ISO15693(NULL, 0, (start_time * 4), (end_time * 4), NULL, true);
|
||||||
|
@ -1959,9 +1959,9 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui
|
||||||
|
|
||||||
// Decodes a message from a tag and displays its metadata and content
|
// Decodes a message from a tag and displays its metadata and content
|
||||||
#define DBD15STATLEN 48
|
#define DBD15STATLEN 48
|
||||||
static void DbdecodeIso15693Answer(int len, uint8_t *d) {
|
static void DbdecodeIso15693Answer(int n, const uint8_t *d) {
|
||||||
|
|
||||||
if (len > 3) {
|
if (n > 3) {
|
||||||
|
|
||||||
char status[DBD15STATLEN + 1] = {0};
|
char status[DBD15STATLEN + 1] = {0};
|
||||||
|
|
||||||
|
@ -2007,7 +2007,7 @@ static void DbdecodeIso15693Answer(int len, uint8_t *d) {
|
||||||
strncat(status, "No error ", DBD15STATLEN - strlen(status));
|
strncat(status, "No error ", DBD15STATLEN - strlen(status));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckCrc15(d, len))
|
if (CheckCrc15(d, n))
|
||||||
strncat(status, "[+] crc ( " _GREEN_("ok") " )", DBD15STATLEN - strlen(status));
|
strncat(status, "[+] crc ( " _GREEN_("ok") " )", DBD15STATLEN - strlen(status));
|
||||||
else
|
else
|
||||||
strncat(status, "[!] crc ( " _RED_("fail") " )", DBD15STATLEN - strlen(status));
|
strncat(status, "[!] crc ( " _RED_("fail") " )", DBD15STATLEN - strlen(status));
|
||||||
|
@ -2127,7 +2127,7 @@ void EmlClearIso15693(void) {
|
||||||
|
|
||||||
// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
|
// Simulate an ISO15693 TAG, perform anti-collision and then print any reader commands
|
||||||
// all demodulation performed in arm rather than host. - greg
|
// all demodulation performed in arm rather than host. - greg
|
||||||
void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
void SimTagIso15693(const uint8_t *uid, uint8_t block_size) {
|
||||||
|
|
||||||
// free eventually allocated BigBuf memory
|
// free eventually allocated BigBuf memory
|
||||||
BigBuf_free_keep_EM();
|
BigBuf_free_keep_EM();
|
||||||
|
@ -2581,7 +2581,7 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
||||||
AddCrc15(recv, recvLen);
|
AddCrc15(recv, recvLen);
|
||||||
recvLen += 2;
|
recvLen += 2;
|
||||||
CodeIso15693AsTag(recv, recvLen);
|
CodeIso15693AsTag(recv, recvLen);
|
||||||
tosend_t *ts = get_tosend();
|
const tosend_t *ts = get_tosend();
|
||||||
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
|
uint32_t response_time = reader_eof_time + DELAY_ISO15693_VCD_TO_VICC_SIM;
|
||||||
|
|
||||||
if (tag->expectFsk) { // Not suppoted yet
|
if (tag->expectFsk) { // Not suppoted yet
|
||||||
|
@ -3028,7 +3028,7 @@ static uint32_t disable_privacy_15693_Slix(uint32_t start_time, uint32_t *eof_ti
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t set_pass_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, const uint8_t *password, uint8_t *uid) {
|
static uint32_t set_pass_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pass_id, const uint8_t *password, const uint8_t *uid) {
|
||||||
|
|
||||||
|
|
||||||
uint8_t rnd[2];
|
uint8_t rnd[2];
|
||||||
|
@ -3141,7 +3141,7 @@ static uint32_t enable_eas_15693_Slix(uint32_t start_time, uint32_t *eof_time, c
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pwd_id, const uint8_t *password, uint8_t *uid) {
|
static uint32_t write_password_15693_Slix(uint32_t start_time, uint32_t *eof_time, uint8_t pwd_id, const uint8_t *password, const uint8_t *uid) {
|
||||||
|
|
||||||
uint8_t new_pwd_cmd[] = { (ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS), ISO15693_WRITE_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, pwd_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
uint8_t new_pwd_cmd[] = { (ISO15_REQ_DATARATE_HIGH | ISO15_REQ_ADDRESS), ISO15693_WRITE_PASSWORD, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, pwd_id, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
|
|
@ -47,13 +47,13 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo
|
||||||
void AcquireRawAdcSamplesIso15693(void);
|
void AcquireRawAdcSamplesIso15693(void);
|
||||||
void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader
|
void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader
|
||||||
void EmlClearIso15693(void);
|
void EmlClearIso15693(void);
|
||||||
void SimTagIso15693(uint8_t *uid, uint8_t block_size); // simulate an ISO15693 tag
|
void SimTagIso15693(const uint8_t *uid, uint8_t block_size); // simulate an ISO15693 tag
|
||||||
void BruteforceIso15693Afi(uint32_t flags); // find an AFI of a tag
|
void BruteforceIso15693Afi(uint32_t flags); // find an AFI of a tag
|
||||||
void SendRawCommand15693(iso15_raw_cmd_t *packet); // send arbitrary commands from CLI
|
void SendRawCommand15693(iso15_raw_cmd_t *packet); // send arbitrary commands from CLI
|
||||||
|
|
||||||
void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool iclass);
|
void SniffIso15693(uint8_t jam_search_len, uint8_t *jam_search_string, bool iclass);
|
||||||
|
|
||||||
int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *recv,
|
int SendDataTag(const uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t *recv,
|
||||||
uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, uint16_t *resp_len);
|
uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, uint16_t *resp_len);
|
||||||
|
|
||||||
int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, bool fsk, bool recv_speed, uint16_t *resp_len);
|
int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, uint16_t timeout, uint32_t *eof_time, bool fsk, bool recv_speed, uint16_t *resp_len);
|
||||||
|
@ -68,5 +68,5 @@ void DisableEAS_AFISlixIso15693(const uint8_t *password, bool usepwd);
|
||||||
void EnableEAS_AFISlixIso15693(const uint8_t *password, bool usepwd);
|
void EnableEAS_AFISlixIso15693(const uint8_t *password, bool usepwd);
|
||||||
void PassProtextEASSlixIso15693(const uint8_t *password);
|
void PassProtextEASSlixIso15693(const uint8_t *password);
|
||||||
void PassProtectAFISlixIso15693(const uint8_t *password);
|
void PassProtectAFISlixIso15693(const uint8_t *password);
|
||||||
void WriteAFIIso15693(const uint8_t *password, bool usepwd, uint8_t *uid, bool use_uid, uint8_t afi);
|
void WriteAFIIso15693(const uint8_t *password, bool use_pwd, uint8_t *uid, bool use_uid, uint8_t afi);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -518,7 +518,7 @@ int ReadLF_realtime(bool reader_field) {
|
||||||
// Request USB transmission and change FIFO bank
|
// Request USB transmission and change FIFO bank
|
||||||
if (async_usb_write_requestWrite() == false) {
|
if (async_usb_write_requestWrite() == false) {
|
||||||
return_value = PM3_EIO;
|
return_value = PM3_EIO;
|
||||||
break;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset sample
|
// Reset sample
|
||||||
|
@ -535,10 +535,14 @@ int ReadLF_realtime(bool reader_field) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LED_D_OFF();
|
|
||||||
return_value = async_usb_write_stop();
|
return_value = async_usb_write_stop();
|
||||||
|
|
||||||
|
out:
|
||||||
|
LED_D_OFF();
|
||||||
|
|
||||||
// DoAcquisition() end
|
// DoAcquisition() end
|
||||||
|
|
||||||
StopTicks();
|
StopTicks();
|
||||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||||
return return_value;
|
return return_value;
|
||||||
|
|
|
@ -153,7 +153,7 @@ Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8
|
||||||
rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
|
rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
|
||||||
rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
|
rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
|
||||||
**/
|
**/
|
||||||
static void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) {
|
static void rk(const uint8_t *key, uint8_t n, uint8_t *outp_key) {
|
||||||
memcpy(outp_key, key, 8);
|
memcpy(outp_key, key, 8);
|
||||||
uint8_t j;
|
uint8_t j;
|
||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
|
|
127
armsrc/printf.c
127
armsrc/printf.c
|
@ -113,11 +113,14 @@ kvsprintf(char const *fmt, void *arg, int radix, va_list ap) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
padc = ' ';
|
padc = ' ';
|
||||||
width = 0;
|
width = 0;
|
||||||
|
|
||||||
while ((ch = (u_char) * fmt++) != '%' || stop) {
|
while ((ch = (u_char) * fmt++) != '%' || stop) {
|
||||||
PCHAR(ch);
|
PCHAR(ch);
|
||||||
if (ch == '\0')
|
if (ch == '\0') {
|
||||||
return (retval);
|
return (retval);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
percent = fmt - 1;
|
percent = fmt - 1;
|
||||||
qflag = 0;
|
qflag = 0;
|
||||||
lflag = 0;
|
lflag = 0;
|
||||||
|
@ -178,36 +181,43 @@ reswitch:
|
||||||
for (n = 0;; ++fmt) {
|
for (n = 0;; ++fmt) {
|
||||||
n = n * 10 + ch - '0';
|
n = n * 10 + ch - '0';
|
||||||
ch = *fmt;
|
ch = *fmt;
|
||||||
if (ch < '0' || ch > '9')
|
if (ch < '0' || ch > '9') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (dot)
|
}
|
||||||
|
if (dot) {
|
||||||
dwidth = n;
|
dwidth = n;
|
||||||
else
|
} else {
|
||||||
width = n;
|
width = n;
|
||||||
|
}
|
||||||
goto reswitch;
|
goto reswitch;
|
||||||
case 'b':
|
case 'b':
|
||||||
num = (u_int)va_arg(ap, int);
|
num = (u_int)va_arg(ap, int);
|
||||||
p = va_arg(ap, char *);
|
p = va_arg(ap, char *);
|
||||||
for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
|
for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;) {
|
||||||
PCHAR(*q--);
|
PCHAR(*q--);
|
||||||
|
}
|
||||||
|
|
||||||
if (num == 0)
|
if (num == 0) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
for (tmp = 0; *p;) {
|
for (tmp = 0; *p;) {
|
||||||
n = *p++;
|
n = *p++;
|
||||||
if (num & (1 << (n - 1))) {
|
if (num & (1 << (n - 1))) {
|
||||||
PCHAR(tmp ? ',' : '<');
|
PCHAR(tmp ? ',' : '<');
|
||||||
for (; (n = *p) > ' '; ++p)
|
for (; (n = *p) > ' '; ++p) {
|
||||||
PCHAR(n);
|
PCHAR(n);
|
||||||
tmp = 1;
|
|
||||||
} else
|
|
||||||
for (; *p > ' '; ++p)
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (tmp)
|
tmp = 1;
|
||||||
|
} else {
|
||||||
|
for (; *p > ' '; ++p) {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tmp) {
|
||||||
PCHAR('>');
|
PCHAR('>');
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
PCHAR(va_arg(ap, int));
|
PCHAR(va_arg(ap, int));
|
||||||
|
@ -215,16 +225,20 @@ reswitch:
|
||||||
case 'D':
|
case 'D':
|
||||||
up = va_arg(ap, u_char *);
|
up = va_arg(ap, u_char *);
|
||||||
p = va_arg(ap, char *);
|
p = va_arg(ap, char *);
|
||||||
if (!width)
|
if (!width) {
|
||||||
width = 16;
|
width = 16;
|
||||||
|
}
|
||||||
|
|
||||||
while (width--) {
|
while (width--) {
|
||||||
PCHAR(hex2ascii(*up >> 4));
|
PCHAR(hex2ascii(*up >> 4));
|
||||||
PCHAR(hex2ascii(*up & 0x0f));
|
PCHAR(hex2ascii(*up & 0x0f));
|
||||||
up++;
|
up++;
|
||||||
if (width)
|
if (width) {
|
||||||
for (q = p; *q; q++)
|
for (q = p; *q; q++) {
|
||||||
PCHAR(*q);
|
PCHAR(*q);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i':
|
case 'i':
|
||||||
|
@ -235,8 +249,9 @@ reswitch:
|
||||||
if (hflag) {
|
if (hflag) {
|
||||||
hflag = 0;
|
hflag = 0;
|
||||||
cflag = 1;
|
cflag = 1;
|
||||||
} else
|
} else {
|
||||||
hflag = 1;
|
hflag = 1;
|
||||||
|
}
|
||||||
goto reswitch;
|
goto reswitch;
|
||||||
case 'j':
|
case 'j':
|
||||||
jflag = 1;
|
jflag = 1;
|
||||||
|
@ -245,8 +260,9 @@ reswitch:
|
||||||
if (lflag) {
|
if (lflag) {
|
||||||
lflag = 0;
|
lflag = 0;
|
||||||
qflag = 1;
|
qflag = 1;
|
||||||
} else
|
} else {
|
||||||
lflag = 1;
|
lflag = 1;
|
||||||
|
}
|
||||||
goto reswitch;
|
goto reswitch;
|
||||||
case 'n':
|
case 'n':
|
||||||
if (jflag)
|
if (jflag)
|
||||||
|
@ -278,29 +294,38 @@ reswitch:
|
||||||
goto reswitch;
|
goto reswitch;
|
||||||
case 'r':
|
case 'r':
|
||||||
base = radix;
|
base = radix;
|
||||||
if (sign)
|
if (sign) {
|
||||||
goto handle_sign;
|
goto handle_sign;
|
||||||
|
}
|
||||||
goto handle_nosign;
|
goto handle_nosign;
|
||||||
case 's':
|
case 's':
|
||||||
p = va_arg(ap, char *);
|
p = va_arg(ap, char *);
|
||||||
if (p == NULL)
|
if (p == NULL) {
|
||||||
p = "(null)";
|
p = "(null)";
|
||||||
if (!dot)
|
}
|
||||||
|
|
||||||
|
if (!dot) {
|
||||||
n = strlen(p);
|
n = strlen(p);
|
||||||
else
|
} else {
|
||||||
for (n = 0; n < dwidth && p[n]; n++)
|
for (n = 0; n < dwidth && p[n]; n++) {};
|
||||||
continue;
|
}
|
||||||
|
|
||||||
width -= n;
|
width -= n;
|
||||||
|
|
||||||
if (!ladjust && width > 0)
|
if (!ladjust && width > 0) {
|
||||||
while (width--)
|
while (width--) {
|
||||||
PCHAR(padc);
|
PCHAR(padc);
|
||||||
while (n--)
|
}
|
||||||
|
}
|
||||||
|
while (n--) {
|
||||||
PCHAR(*p++);
|
PCHAR(*p++);
|
||||||
if (ladjust && width > 0)
|
}
|
||||||
while (width--)
|
|
||||||
|
if (ladjust && width > 0) {
|
||||||
|
while (width--) {
|
||||||
PCHAR(padc);
|
PCHAR(padc);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
tflag = 1;
|
tflag = 1;
|
||||||
|
@ -361,22 +386,31 @@ number:
|
||||||
neg = 1;
|
neg = 1;
|
||||||
num = -(intmax_t)num;
|
num = -(intmax_t)num;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = ksprintn(nbuf, num, base, &tmp, upper);
|
p = ksprintn(nbuf, num, base, &tmp, upper);
|
||||||
|
|
||||||
if (sharpflag && num != 0) {
|
if (sharpflag && num != 0) {
|
||||||
if (base == 8)
|
if (base == 8) {
|
||||||
tmp++;
|
tmp++;
|
||||||
else if (base == 16)
|
} else if (base == 16) {
|
||||||
tmp += 2;
|
tmp += 2;
|
||||||
}
|
}
|
||||||
if (neg)
|
}
|
||||||
tmp++;
|
|
||||||
|
|
||||||
if (!ladjust && padc != '0' && width
|
if (neg) {
|
||||||
&& (width -= tmp) > 0)
|
tmp++;
|
||||||
while (width--)
|
}
|
||||||
|
|
||||||
|
if (!ladjust && padc != '0' && width && (width -= tmp) > 0) {
|
||||||
|
while (width--) {
|
||||||
PCHAR(padc);
|
PCHAR(padc);
|
||||||
if (neg)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (neg) {
|
||||||
PCHAR('-');
|
PCHAR('-');
|
||||||
|
}
|
||||||
|
|
||||||
if (sharpflag && num != 0) {
|
if (sharpflag && num != 0) {
|
||||||
if (base == 8) {
|
if (base == 8) {
|
||||||
PCHAR('0');
|
PCHAR('0');
|
||||||
|
@ -385,21 +419,28 @@ number:
|
||||||
PCHAR('x');
|
PCHAR('x');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!ladjust && width && (width -= tmp) > 0)
|
|
||||||
while (width--)
|
|
||||||
PCHAR(padc);
|
|
||||||
|
|
||||||
while (*p)
|
if (!ladjust && width && (width -= tmp) > 0) {
|
||||||
|
while (width--) {
|
||||||
|
PCHAR(padc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*p) {
|
||||||
PCHAR(*p--);
|
PCHAR(*p--);
|
||||||
|
}
|
||||||
|
|
||||||
if (ladjust && width && (width -= tmp) > 0)
|
if (ladjust && width && (width -= tmp) > 0) {
|
||||||
while (width--)
|
while (width--) {
|
||||||
PCHAR(padc);
|
PCHAR(padc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
while (percent < fmt)
|
while (percent < fmt) {
|
||||||
PCHAR(*percent++);
|
PCHAR(*percent++);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Since we ignore an formatting argument it is no
|
* Since we ignore an formatting argument it is no
|
||||||
* longer safe to obey the remaining formatting
|
* longer safe to obey the remaining formatting
|
||||||
|
|
|
@ -85,7 +85,7 @@ static size_t us_rxfifo_high = 0;
|
||||||
|
|
||||||
static void usart_fill_rxfifo(void) {
|
static void usart_fill_rxfifo(void) {
|
||||||
|
|
||||||
uint16_t rxfifo_free = 0;
|
uint16_t rxfifo_free;
|
||||||
|
|
||||||
if (pUS1->US_RNCR == 0) { // One buffer got filled, backup buffer being used
|
if (pUS1->US_RNCR == 0) { // One buffer got filled, backup buffer being used
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ int hex2binarray(char *target, char *source) {
|
||||||
return hex2binarray_n(target, source, strlen(source));
|
return hex2binarray_n(target, source, strlen(source));
|
||||||
}
|
}
|
||||||
|
|
||||||
int hex2binarray_n(char *target, char *source, int sourcelen) {
|
int hex2binarray_n(char *target, const char *source, int sourcelen) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
// process 4 bits (1 hex digit) at a time
|
// process 4 bits (1 hex digit) at a time
|
||||||
|
|
|
@ -82,10 +82,10 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t nbytes(size_t nbits);
|
size_t nbytes(size_t nbits);
|
||||||
uint8_t hex2int(char hexchar);
|
uint8_t hex2int(char x);
|
||||||
|
|
||||||
int hex2binarray(char *target, char *source);
|
int hex2binarray(char *target, char *source);
|
||||||
int hex2binarray_n(char *target, char *source, int sourcelen);
|
int hex2binarray_n(char *target, const char *source, int sourcelen);
|
||||||
int binarray2hex(const uint8_t *bs, int bs_len, uint8_t *hex);
|
int binarray2hex(const uint8_t *bs, int bs_len, uint8_t *hex);
|
||||||
|
|
||||||
void LED(int led, int ms);
|
void LED(int led, int ms);
|
||||||
|
|
|
@ -296,9 +296,9 @@ static void UsbPacketReceived(uint8_t *packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// delay_loop(1) = 3.07us
|
// delay_loop(1) = 3.07us
|
||||||
static volatile uint32_t c;
|
static volatile uint32_t ccc;
|
||||||
static void __attribute__((optimize("O0"))) delay_loop(uint32_t delay) {
|
static void __attribute__((optimize("O0"))) delay_loop(uint32_t delay) {
|
||||||
for (c = delay * 2; c; c--) {};
|
for (ccc = delay * 2; ccc; ccc--) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void flash_mode(void) {
|
static void flash_mode(void) {
|
||||||
|
|
|
@ -54,7 +54,7 @@ typedef int (*get_func)(void *data);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
get_func get;
|
get_func get;
|
||||||
void *data;
|
void *data;
|
||||||
char buffer[5];
|
char buffer[7];
|
||||||
size_t buffer_pos;
|
size_t buffer_pos;
|
||||||
int state;
|
int state;
|
||||||
int line;
|
int line;
|
||||||
|
@ -179,11 +179,16 @@ static int stream_get(stream_t *stream, json_error_t *error) {
|
||||||
size_t i, count;
|
size_t i, count;
|
||||||
|
|
||||||
count = utf8_check_first(c);
|
count = utf8_check_first(c);
|
||||||
if (!count)
|
if (count == 0) {
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
// whatif count == 1 ?!?
|
||||||
|
|
||||||
assert(count >= 2);
|
assert(count >= 2);
|
||||||
|
assert(count <= 4);
|
||||||
|
|
||||||
|
// if count == 4 , i will become 5 and overflow.
|
||||||
for (i = 1; i < count; i++)
|
for (i = 1; i < count; i++)
|
||||||
stream->buffer[i] = stream->get(stream->data);
|
stream->buffer[i] = stream->get(stream->data);
|
||||||
|
|
||||||
|
|
|
@ -3681,8 +3681,9 @@ static int CmdTestSaveState8(const char *Cmd) {
|
||||||
|
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
size_t length = 64;
|
size_t length = (rand() % 256);
|
||||||
uint8_t *srcBuffer = (uint8_t*)calloc(length, sizeof(uint8_t));
|
PrintAndLogEx(DEBUG, "Testing with length = %llu", length);
|
||||||
|
uint8_t *srcBuffer = (uint8_t*)calloc(length + 1, sizeof(uint8_t));
|
||||||
|
|
||||||
//Set up the source buffer with random data
|
//Set up the source buffer with random data
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
|
@ -3690,7 +3691,7 @@ static int CmdTestSaveState8(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_savestate_t test8 = save_buffer8(srcBuffer, length);
|
buffer_savestate_t test8 = save_buffer8(srcBuffer, length);
|
||||||
PrintAndLogEx(DEBUG, "Save State created, length=%llu, type=%i", test8.bufferSize, test8.type);
|
PrintAndLogEx(DEBUG, "Save State created, length = %llu, padding = %i, type = %i", test8.bufferSize, test8.padding, test8.type);
|
||||||
|
|
||||||
test8.clock = rand();
|
test8.clock = rand();
|
||||||
test8.offset = rand();
|
test8.offset = rand();
|
||||||
|
@ -3700,14 +3701,13 @@ static int CmdTestSaveState8(const char *Cmd) {
|
||||||
size_t returnedLength = restore_buffer8(test8, destBuffer);
|
size_t returnedLength = restore_buffer8(test8, destBuffer);
|
||||||
|
|
||||||
if (returnedLength != length) {
|
if (returnedLength != length) {
|
||||||
PrintAndLogEx(FAILED, "Return Length != Buffer Length! Expected '%llu', got '%llu", g_DemodBufferLen, returnedLength);
|
PrintAndLogEx(DEBUG, _YELLOW_("Returned length != expected length!"));
|
||||||
free(srcBuffer);
|
PrintAndLogEx(WARNING, "Returned Length = %llu Buffer Length = %llu Expected = %llu", returnedLength, test8.bufferSize, length);
|
||||||
free(destBuffer);
|
} else {
|
||||||
return PM3_EFAILED;
|
|
||||||
}
|
|
||||||
PrintAndLogEx(DEBUG, _GREEN_("Lengths match!") "\n");
|
PrintAndLogEx(DEBUG, _GREEN_("Lengths match!") "\n");
|
||||||
|
}
|
||||||
|
|
||||||
for(size_t i = 0; i < length; i++) {
|
for (size_t i = 0; i < returnedLength; i++) {
|
||||||
if (srcBuffer[i] != destBuffer[i]) {
|
if (srcBuffer[i] != destBuffer[i]) {
|
||||||
PrintAndLogEx(FAILED, "Buffers don't match at index %lu!, Expected %i, got %i", i, srcBuffer[i], destBuffer[i]);
|
PrintAndLogEx(FAILED, "Buffers don't match at index %lu!, Expected %i, got %i", i, srcBuffer[i], destBuffer[i]);
|
||||||
free(srcBuffer);
|
free(srcBuffer);
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
int flashmem_spiffs_load(char *destfn, uint8_t *data, size_t datalen) {
|
int flashmem_spiffs_load(const char *destfn, const uint8_t *data, size_t datalen) {
|
||||||
|
|
||||||
int ret_val = PM3_SUCCESS;
|
int ret_val = PM3_SUCCESS;
|
||||||
|
|
||||||
|
@ -429,9 +429,14 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
|
||||||
PrintAndLogEx(HINT, "Use 'trace list -1 -t ...' to view, 'trace save -f ...' to save");
|
PrintAndLogEx(HINT, "Use 'trace list -1 -t ...' to view, 'trace save -f ...' to save");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dlen) {
|
|
||||||
|
if (dlen || slen) {
|
||||||
|
|
||||||
// save to file
|
// save to file
|
||||||
char fn[FILE_PATH_SIZE] = {0};
|
char fn[FILE_PATH_SIZE] = {0};
|
||||||
|
|
||||||
|
// prefer dest name
|
||||||
|
// else source name
|
||||||
if (dlen) {
|
if (dlen) {
|
||||||
strncpy(fn, dest, dlen);
|
strncpy(fn, dest, dlen);
|
||||||
} else {
|
} else {
|
||||||
|
@ -439,7 +444,7 @@ static int CmdFlashMemSpiFFSDump(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// set file extension
|
// set file extension
|
||||||
char *suffix = strchr(fn, '.');
|
const char *suffix = strchr(fn, '.');
|
||||||
if (suffix) {
|
if (suffix) {
|
||||||
saveFile(fn, suffix, dump, len);
|
saveFile(fn, suffix, dump, len);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
int CmdFlashMemSpiFFS(const char *Cmd);
|
int CmdFlashMemSpiFFS(const char *Cmd);
|
||||||
int flashmem_spiffs_load(char *destfn, uint8_t *data, size_t datalen);
|
int flashmem_spiffs_load(const char *destfn, const uint8_t *data, size_t datalen);
|
||||||
int flashmem_spiffs_download(char *fn, uint8_t fnlen, void **pdest, size_t *destlen);
|
int flashmem_spiffs_download(char *fn, uint8_t fnlen, void **pdest, size_t *destlen);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -95,6 +95,16 @@ int CmdHFSearch(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PROMPT_CLEARLINE;
|
||||||
|
PrintAndLogEx(INPLACE, " Searching for Topaz tag...");
|
||||||
|
if (IfPm3Iso14443a()) {
|
||||||
|
if (readTopazUid(false, false) == PM3_SUCCESS) {
|
||||||
|
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") " found\n");
|
||||||
|
success[TOPAZ] = true;
|
||||||
|
res = PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PROMPT_CLEARLINE;
|
PROMPT_CLEARLINE;
|
||||||
PrintAndLogEx(INPLACE, " Searching for LTO-CM tag...");
|
PrintAndLogEx(INPLACE, " Searching for LTO-CM tag...");
|
||||||
if (IfPm3Iso14443a()) {
|
if (IfPm3Iso14443a()) {
|
||||||
|
@ -119,6 +129,7 @@ int CmdHFSearch(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// ICT
|
// ICT
|
||||||
if (IfPm3Iso14443a()) {
|
if (IfPm3Iso14443a()) {
|
||||||
int sel_state = infoHF14A(false, false, false);
|
int sel_state = infoHF14A(false, false, false);
|
||||||
|
@ -131,6 +142,7 @@ int CmdHFSearch(const char *Cmd) {
|
||||||
infoHF14A4Applications(verbose);
|
infoHF14A4Applications(verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
PROMPT_CLEARLINE;
|
PROMPT_CLEARLINE;
|
||||||
PrintAndLogEx(INPLACE, " Searching for LEGIC tag...");
|
PrintAndLogEx(INPLACE, " Searching for LEGIC tag...");
|
||||||
|
@ -142,16 +154,6 @@ int CmdHFSearch(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PROMPT_CLEARLINE;
|
|
||||||
PrintAndLogEx(INPLACE, " Searching for Topaz tag...");
|
|
||||||
if (IfPm3Iso14443a()) {
|
|
||||||
if (readTopazUid(false, false) == PM3_SUCCESS) {
|
|
||||||
PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Topaz tag") " found\n");
|
|
||||||
success[TOPAZ] = true;
|
|
||||||
res = PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// texkom
|
// texkom
|
||||||
PROMPT_CLEARLINE;
|
PROMPT_CLEARLINE;
|
||||||
PrintAndLogEx(INPLACE, " Searching for TEXKOM tag...");
|
PrintAndLogEx(INPLACE, " Searching for TEXKOM tag...");
|
||||||
|
|
|
@ -863,7 +863,7 @@ int CmdHF14ASim(const char *Cmd) {
|
||||||
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK)
|
if ((flags & FLAG_NR_AR_ATTACK) != FLAG_NR_AR_ATTACK)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
nonces_t *data = (nonces_t *)resp.data.asBytes;
|
const nonces_t *data = (nonces_t *)resp.data.asBytes;
|
||||||
readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose);
|
readerAttack(k_sector, k_sectors_cnt, data[0], setEmulatorMem, verbose);
|
||||||
|
|
||||||
keypress = kbd_enter_pressed();
|
keypress = kbd_enter_pressed();
|
||||||
|
@ -1099,7 +1099,7 @@ int SelectCard14443A_4(bool disconnect, bool verbose, iso14a_card_select_t *card
|
||||||
return SelectCard14443A_4_WithParameters(disconnect, verbose, card, NULL);
|
return SelectCard14443A_4_WithParameters(disconnect, verbose, card, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) {
|
static int CmdExchangeAPDU(bool chainingin, const uint8_t *datain, int datainlen, bool activateField, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool *chainingout) {
|
||||||
*chainingout = false;
|
*chainingout = false;
|
||||||
|
|
||||||
size_t timeout = 1500;
|
size_t timeout = 1500;
|
||||||
|
@ -1158,7 +1158,7 @@ static int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
|
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, timeout)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, timeout)) {
|
||||||
uint8_t *recv = resp.data.asBytes;
|
const uint8_t *recv = resp.data.asBytes;
|
||||||
int iLen = resp.oldarg[0];
|
int iLen = resp.oldarg[0];
|
||||||
uint8_t res = resp.oldarg[1];
|
uint8_t res = resp.oldarg[1];
|
||||||
|
|
||||||
|
@ -1216,7 +1216,7 @@ static int CmdExchangeAPDU(bool chainingin, uint8_t *datain, int datainlen, bool
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
int ExchangeAPDU14a(const uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||||
*dataoutlen = 0;
|
*dataoutlen = 0;
|
||||||
bool chaining = false;
|
bool chaining = false;
|
||||||
int res;
|
int res;
|
||||||
|
@ -1519,7 +1519,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: allow to use reader command with both data and polling configuration
|
// TODO: allow to use reader command with both data and polling configuration
|
||||||
if (use_ecp | use_magsafe) {
|
if (use_ecp || use_magsafe) {
|
||||||
PrintAndLogEx(WARNING, "ECP and Magsafe not supported with this command at this moment. Instead use 'hf 14a reader -sk --ecp/--mag'");
|
PrintAndLogEx(WARNING, "ECP and Magsafe not supported with this command at this moment. Instead use 'hf 14a reader -sk --ecp/--mag'");
|
||||||
// flags |= ISO14A_USE_MAGSAFE;
|
// flags |= ISO14A_USE_MAGSAFE;
|
||||||
// flags |= ISO14A_USE_ECP;
|
// flags |= ISO14A_USE_ECP;
|
||||||
|
|
|
@ -66,7 +66,7 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search);
|
||||||
int infoHF14A4Applications(bool verbose);
|
int infoHF14A4Applications(bool verbose);
|
||||||
const char *getTagInfo(uint8_t uid);
|
const char *getTagInfo(uint8_t uid);
|
||||||
int Hf14443_4aGetCardData(iso14a_card_select_t *card);
|
int Hf14443_4aGetCardData(iso14a_card_select_t *card);
|
||||||
int ExchangeAPDU14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
int ExchangeAPDU14a(const uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||||
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode);
|
int ExchangeRAW14a(uint8_t *datain, int datainlen, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, bool silentMode);
|
||||||
|
|
||||||
iso14a_polling_parameters_t iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe);
|
iso14a_polling_parameters_t iso14a_get_polling_parameters(bool use_ecp, bool use_magsafe);
|
||||||
|
|
|
@ -416,7 +416,7 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
|
||||||
// get a product description based on the UID
|
// get a product description based on the UID
|
||||||
// uid[8] tag uid
|
// uid[8] tag uid
|
||||||
// returns description of the best match
|
// returns description of the best match
|
||||||
static const char *getTagInfo_15(uint8_t *uid) {
|
static const char *getTagInfo_15(const uint8_t *uid) {
|
||||||
if (uid == NULL) {
|
if (uid == NULL) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -473,6 +473,26 @@ static const char *TagErrorStr(uint8_t error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int iso15_error_handling_card_response(uint8_t *d, uint16_t n) {
|
||||||
|
if (check_crc(CRC_15693, d, n) == false) {
|
||||||
|
PrintAndLogEx(FAILED, "crc ( " _RED_("fail") " )");
|
||||||
|
return PM3_ECRC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((d[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) {
|
||||||
|
if (d[1] == 0x0F || d[1] == 0x10) {
|
||||||
|
return PM3_EOUTOFBOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintAndLogEx(ERR, "iso15693 card returned error %i: %s", d[0], TagErrorStr(d[0]));
|
||||||
|
return PM3_EWRONGANSWER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// fast method to just read the UID of a tag (collision detection not supported)
|
// fast method to just read the UID of a tag (collision detection not supported)
|
||||||
// *buf should be large enough to fit the 64bit uid
|
// *buf should be large enough to fit the 64bit uid
|
||||||
// returns 1 if succeeded
|
// returns 1 if succeeded
|
||||||
|
@ -714,7 +734,7 @@ static int CmdHF15Samples(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int NxpTestEAS(uint8_t *uid) {
|
static int NxpTestEAS(const uint8_t *uid) {
|
||||||
|
|
||||||
if (uid == NULL) {
|
if (uid == NULL) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
@ -1162,7 +1182,7 @@ static void hf15EmlClear(void) {
|
||||||
WaitForResponse(CMD_HF_ISO15693_EML_CLEAR, &resp);
|
WaitForResponse(CMD_HF_ISO15693_EML_CLEAR, &resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hf15EmlSetMem(uint8_t *data, uint16_t count, size_t offset) {
|
static int hf15EmlSetMem(const uint8_t *data, uint16_t count, size_t offset) {
|
||||||
struct p {
|
struct p {
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
uint16_t count;
|
uint16_t count;
|
||||||
|
@ -1212,13 +1232,14 @@ static int CmdHF15ELoad(const char *Cmd) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_read != sizeof(iso15_tag_t)) {
|
if (bytes_read == 0) {
|
||||||
PrintAndLogEx(FAILED, "Memory image is not matching tag structure.");
|
PrintAndLogEx(FAILED, "Memory image empty.");
|
||||||
free(tag);
|
free(tag);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (bytes_read == 0) {
|
|
||||||
PrintAndLogEx(FAILED, "Memory image empty.");
|
if (bytes_read != sizeof(iso15_tag_t)) {
|
||||||
|
PrintAndLogEx(FAILED, "Memory image is not matching tag structure.");
|
||||||
free(tag);
|
free(tag);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
@ -1335,7 +1356,7 @@ static void print_blocks_15693(iso15_tag_t *tag, bool dense_output) {
|
||||||
|
|
||||||
for (int i = 0; i < tag->pagesCount; i++) {
|
for (int i = 0; i < tag->pagesCount; i++) {
|
||||||
|
|
||||||
uint8_t *blk = d + (i * blocksize);
|
const uint8_t *blk = d + (i * blocksize);
|
||||||
|
|
||||||
// suppress repeating blocks, truncate as such that the first and last block with the same data is shown
|
// suppress repeating blocks, truncate as such that the first and last block with the same data is shown
|
||||||
// but the blocks in between are replaced with a single line of "......" if dense_output is enabled
|
// but the blocks in between are replaced with a single line of "......" if dense_output is enabled
|
||||||
|
@ -1830,6 +1851,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
iso15_tag_t *tag = (iso15_tag_t *)calloc(1, sizeof(iso15_tag_t));
|
iso15_tag_t *tag = (iso15_tag_t *)calloc(1, sizeof(iso15_tag_t));
|
||||||
if (tag == NULL) {
|
if (tag == NULL) {
|
||||||
PrintAndLogEx(FAILED, "failed to allocate memory");
|
PrintAndLogEx(FAILED, "failed to allocate memory");
|
||||||
|
free(packet);
|
||||||
return PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1844,6 +1866,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
PrintAndLogEx(INFO, "Using scan mode");
|
PrintAndLogEx(INFO, "Using scan mode");
|
||||||
if (getUID(verbose, false, uid) != PM3_SUCCESS) {
|
if (getUID(verbose, false, uid) != PM3_SUCCESS) {
|
||||||
free(packet);
|
free(packet);
|
||||||
|
free(tag);
|
||||||
PrintAndLogEx(WARNING, "no tag found");
|
PrintAndLogEx(WARNING, "no tag found");
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
@ -1873,18 +1896,27 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
|
if (WaitForResponseTimeout(CMD_HF_ISO15693_COMMAND, &resp, 2000) == false) {
|
||||||
PrintAndLogEx(DEBUG, "iso15693 timeout");
|
PrintAndLogEx(DEBUG, "iso15693 timeout");
|
||||||
|
free(packet);
|
||||||
|
free(tag);
|
||||||
return PM3_ETIMEOUT;
|
return PM3_ETIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (resp.length < 2) {
|
if (resp.length < 2) {
|
||||||
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", resp.length);
|
PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", resp.length);
|
||||||
|
free(packet);
|
||||||
|
free(tag);
|
||||||
return PM3_EWRONGANSWER;
|
return PM3_EWRONGANSWER;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *d = resp.data.asBytes;
|
uint8_t *d = resp.data.asBytes;
|
||||||
uint8_t dCpt = 10;
|
uint8_t dCpt = 10;
|
||||||
|
|
||||||
ISO15_ERROR_HANDLING_CARD_RESPONSE(d, resp.length);
|
int res = iso15_error_handling_card_response(d, resp.length);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
free(tag);
|
||||||
|
free(packet);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
memcpy(tag->uid, &d[2], 8);
|
memcpy(tag->uid, &d[2], 8);
|
||||||
|
|
||||||
|
@ -1991,6 +2023,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
if (no_save) {
|
if (no_save) {
|
||||||
PrintAndLogEx(INFO, "Called with no save option");
|
PrintAndLogEx(INFO, "Called with no save option");
|
||||||
PrintAndLogEx(NORMAL, "");
|
PrintAndLogEx(NORMAL, "");
|
||||||
|
free(tag);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2004,6 +2037,7 @@ static int CmdHF15Dump(const char *Cmd) {
|
||||||
|
|
||||||
pm3_save_dump(filename, (uint8_t *)tag, sizeof(iso15_tag_t), jsf15_v4);
|
pm3_save_dump(filename, (uint8_t *)tag, sizeof(iso15_tag_t), jsf15_v4);
|
||||||
|
|
||||||
|
free(tag);
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2436,7 +2470,7 @@ static int CmdHF15Readblock(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hf_15_write_blk(uint8_t *pm3flags, uint16_t flags, uint8_t *uid, bool fast, uint8_t blockno, uint8_t *data, uint8_t dlen) {
|
static int hf_15_write_blk(const uint8_t *pm3flags, uint16_t flags, const uint8_t *uid, bool fast, uint8_t blockno, const uint8_t *data, uint8_t dlen) {
|
||||||
|
|
||||||
// request to be sent to device/card
|
// request to be sent to device/card
|
||||||
// 2 + 8 + 1 + (4|8) + 2
|
// 2 + 8 + 1 + (4|8) + 2
|
||||||
|
@ -2660,13 +2694,14 @@ static int CmdHF15Restore(const char *Cmd) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_read != sizeof(iso15_tag_t)) {
|
if (bytes_read == 0) {
|
||||||
PrintAndLogEx(FAILED, "Memory image is not matching tag structure.");
|
PrintAndLogEx(FAILED, "Memory image empty.");
|
||||||
free(tag);
|
free(tag);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (bytes_read == 0) {
|
|
||||||
PrintAndLogEx(FAILED, "Memory image empty.");
|
if (bytes_read != sizeof(iso15_tag_t)) {
|
||||||
|
PrintAndLogEx(FAILED, "Memory image is not matching tag structure.");
|
||||||
free(tag);
|
free(tag);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
@ -2694,7 +2729,7 @@ static int CmdHF15Restore(const char *Cmd) {
|
||||||
size_t bytes = 0;
|
size_t bytes = 0;
|
||||||
uint16_t i = 0;
|
uint16_t i = 0;
|
||||||
uint8_t *data = calloc(tag->bytesPerPage, sizeof(uint8_t));
|
uint8_t *data = calloc(tag->bytesPerPage, sizeof(uint8_t));
|
||||||
uint32_t tried = 0;
|
uint32_t tried;
|
||||||
while (bytes < (tag->pagesCount * tag->bytesPerPage)) {
|
while (bytes < (tag->pagesCount * tag->bytesPerPage)) {
|
||||||
|
|
||||||
// copy over the data to the request
|
// copy over the data to the request
|
||||||
|
@ -3324,13 +3359,14 @@ static int CmdHF15View(const char *Cmd) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes_read != sizeof(iso15_tag_t)) {
|
if (bytes_read == 0) {
|
||||||
PrintAndLogEx(FAILED, "Memory image is not matching tag structure.");
|
PrintAndLogEx(FAILED, "Memory image empty.");
|
||||||
free(tag);
|
free(tag);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
if (bytes_read == 0) {
|
|
||||||
PrintAndLogEx(FAILED, "Memory image empty.");
|
if (bytes_read != sizeof(iso15_tag_t)) {
|
||||||
|
PrintAndLogEx(FAILED, "Memory image is not matching tag structure.");
|
||||||
free(tag);
|
free(tag);
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,13 +312,13 @@ static int CmdHFFelicaList(const char *Cmd) {
|
||||||
|
|
||||||
int read_felica_uid(bool loop, bool verbose) {
|
int read_felica_uid(bool loop, bool verbose) {
|
||||||
|
|
||||||
int res = PM3_SUCCESS;
|
int res = PM3_ETIMEOUT;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_FELICA_COMMAND, FELICA_CONNECT, 0, 0, NULL, 0);
|
SendCommandMIX(CMD_HF_FELICA_COMMAND, FELICA_CONNECT, 0, 0, NULL, 0);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
if (WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
|
||||||
|
|
||||||
uint8_t status = resp.oldarg[0] & 0xFF;
|
uint8_t status = resp.oldarg[0] & 0xFF;
|
||||||
|
|
||||||
|
@ -342,7 +342,10 @@ int read_felica_uid(bool loop, bool verbose) {
|
||||||
}
|
}
|
||||||
PrintAndLogEx(SUCCESS, "IDm: " _GREEN_("%s"), sprint_hex_inrow(card.IDm, sizeof(card.IDm)));
|
PrintAndLogEx(SUCCESS, "IDm: " _GREEN_("%s"), sprint_hex_inrow(card.IDm, sizeof(card.IDm)));
|
||||||
set_last_known_card(card);
|
set_last_known_card(card);
|
||||||
|
|
||||||
|
res = PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
} while (loop && kbd_enter_pressed() == false);
|
} while (loop && kbd_enter_pressed() == false);
|
||||||
|
|
||||||
DropField();
|
DropField();
|
||||||
|
|
|
@ -120,7 +120,7 @@ static int derive_app_key(uint8_t *uid, uint8_t *app_key) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Might miss payload..
|
// Might miss payload..
|
||||||
static int diversify_mifare_key(uint8_t *uid, uint8_t *app_key) {
|
static int diversify_mifare_key(const uint8_t *uid, uint8_t *app_key) {
|
||||||
if (uid == NULL || app_key == NULL) {
|
if (uid == NULL || app_key == NULL) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ static int diversify_mifare_key(uint8_t *uid, uint8_t *app_key) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decrypt_card_sector(uint8_t *uid, uint8_t *sector_data, uint8_t len, uint8_t *plain) {
|
static int decrypt_card_sector(uint8_t *uid, const uint8_t *sector_data, uint8_t len, uint8_t *plain) {
|
||||||
if (uid == NULL || sector_data == NULL || plain == NULL) {
|
if (uid == NULL || sector_data == NULL || plain == NULL) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,7 @@ static int derive_mifare_key_b(uint8_t *uid, uint8_t *app_key) {
|
||||||
return derive_mifare_key(uid, ICT_MIFARE_B_KEY, app_key);
|
return derive_mifare_key(uid, ICT_MIFARE_B_KEY, app_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decrypt_card_file(uint8_t *card_file, uint8_t len, uint8_t *plain) {
|
static int decrypt_card_file(const uint8_t *card_file, uint8_t len, uint8_t *plain) {
|
||||||
if (card_file == NULL || plain == NULL) {
|
if (card_file == NULL || plain == NULL) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,7 @@ static int decrypt_card_file(uint8_t *card_file, uint8_t len, uint8_t *plain) {
|
||||||
uint8_t input[ICT_FILE_SIZE];
|
uint8_t input[ICT_FILE_SIZE];
|
||||||
memcpy(input, card_file, len);
|
memcpy(input, card_file, len);
|
||||||
|
|
||||||
uint8_t key[AES_KEY_LEN];
|
uint8_t key[AES_KEY_LEN] = {0};
|
||||||
// memcpy(key, ICT_DESFIRE_FILEKEY, AES_KEY_LEN);
|
// memcpy(key, ICT_DESFIRE_FILEKEY, AES_KEY_LEN);
|
||||||
|
|
||||||
uint8_t iv[16] = {0};
|
uint8_t iv[16] = {0};
|
||||||
|
@ -230,7 +230,7 @@ static int decrypt_card_file(uint8_t *card_file, uint8_t len, uint8_t *plain) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int encrypt_card_file(uint8_t *card_file, uint8_t len, bool padding, uint8_t *enc) {
|
static int encrypt_card_file(const uint8_t *card_file, uint8_t len, bool padding, uint8_t *enc) {
|
||||||
|
|
||||||
if (len > ICT_FILE_SIZE) {
|
if (len > ICT_FILE_SIZE) {
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
@ -243,7 +243,7 @@ static int encrypt_card_file(uint8_t *card_file, uint8_t len, bool padding, uint
|
||||||
memset(input + len, 0x4C, 128 - len);
|
memset(input + len, 0x4C, 128 - len);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t key[AES_KEY_LEN];
|
uint8_t key[AES_KEY_LEN] = {0};
|
||||||
// memcpy(key, ICT_DESFIRE_FILEKEY, AES_KEY_LEN);
|
// memcpy(key, ICT_DESFIRE_FILEKEY, AES_KEY_LEN);
|
||||||
|
|
||||||
uint8_t iv[16] = {0};
|
uint8_t iv[16] = {0};
|
||||||
|
@ -262,7 +262,7 @@ static int encrypt_card_file(uint8_t *card_file, uint8_t len, bool padding, uint
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void itc_decode_card_blob(uint8_t *data, uint8_t card_type) {
|
static void itc_decode_card_blob(const uint8_t *data, uint8_t card_type) {
|
||||||
if (data == NULL) {
|
if (data == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3253,7 +3253,7 @@ int CmdHF14MfUTamper(const char *Cmd) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enable | disable | lock_msg) {
|
if (enable || disable || lock_msg) {
|
||||||
|
|
||||||
if (ul_select(&card) == false) {
|
if (ul_select(&card) == false) {
|
||||||
PrintAndLogEx(ERR, "Unable to select tag");
|
PrintAndLogEx(ERR, "Unable to select tag");
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
|
|
||||||
// NTAG424 commands currently implemented
|
// NTAG424 commands currently implemented
|
||||||
|
// icenam: should be able to use 14a / msdes to annotate NTAG424 communications
|
||||||
#define NTAG424_CMD_GET_FILE_SETTINGS 0xF5
|
#define NTAG424_CMD_GET_FILE_SETTINGS 0xF5
|
||||||
#define NTAG424_CMD_CHANGE_FILE_SETTINGS 0x5F
|
#define NTAG424_CMD_CHANGE_FILE_SETTINGS 0x5F
|
||||||
#define NTAG424_CMD_CHANGE_KEY 0xC4
|
#define NTAG424_CMD_CHANGE_KEY 0xC4
|
||||||
|
@ -280,7 +281,7 @@ static void ntag424_calc_receive_iv(ntag424_session_keys_t *session_keys, uint8_
|
||||||
aes_encode(zero_iv, session_keys->encryption, iv_clear, out_ivc, 16);
|
aes_encode(zero_iv, session_keys->encryption, iv_clear, out_ivc, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ntag424_calc_mac(ntag424_session_keys_t *session_keys, uint8_t command, uint8_t *data, uint8_t datalen, uint8_t *out_mac) {
|
static void ntag424_calc_mac(const ntag424_session_keys_t *session_keys, uint8_t command, const uint8_t *data, uint8_t datalen, uint8_t *out_mac) {
|
||||||
uint8_t mac_input_header[] = { command,
|
uint8_t mac_input_header[] = { command,
|
||||||
(uint8_t)session_keys->command_counter, (uint8_t)(session_keys->command_counter >> 8),
|
(uint8_t)session_keys->command_counter, (uint8_t)(session_keys->command_counter >> 8),
|
||||||
session_keys->ti[0], session_keys->ti[1], session_keys->ti[2], session_keys->ti[3]
|
session_keys->ti[0], session_keys->ti[1], session_keys->ti[2], session_keys->ti[3]
|
||||||
|
@ -445,7 +446,7 @@ static int ntag424_get_file_settings(uint8_t fileno, ntag424_file_settings_t *se
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ntag424_write_file_settings(uint8_t fileno, ntag424_file_settings_t *settings, ntag424_session_keys_t *session_keys) {
|
static int ntag424_write_file_settings(uint8_t fileno, const ntag424_file_settings_t *settings, ntag424_session_keys_t *session_keys) {
|
||||||
|
|
||||||
// ------- Convert file settings to the format for writing
|
// ------- Convert file settings to the format for writing
|
||||||
file_settings_write_t write_settings = {
|
file_settings_write_t write_settings = {
|
||||||
|
@ -807,7 +808,7 @@ static int ntag424_get_signature(uint8_t *signature_out) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ntag424_change_key(uint8_t keyno, uint8_t *new_key, uint8_t *old_key, uint8_t version, ntag424_session_keys_t *session_keys) {
|
static int ntag424_change_key(uint8_t keyno, const uint8_t *new_key, const uint8_t *old_key, uint8_t version, ntag424_session_keys_t *session_keys) {
|
||||||
// -------- Calculate xor and crc
|
// -------- Calculate xor and crc
|
||||||
uint8_t key[16] = {0};
|
uint8_t key[16] = {0};
|
||||||
uint8_t crc[4] = {0};
|
uint8_t crc[4] = {0};
|
||||||
|
@ -965,7 +966,7 @@ static int CmdHF_ntag424_auth(const char *Cmd) {
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
|
|
||||||
int keyno;
|
int keyno = 0;
|
||||||
uint8_t key[16] = {0};
|
uint8_t key[16] = {0};
|
||||||
if (ntag424_cli_get_auth_information(ctx, 1, 2, &keyno, key) != PM3_SUCCESS) {
|
if (ntag424_cli_get_auth_information(ctx, 1, 2, &keyno, key) != PM3_SUCCESS) {
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
@ -1019,7 +1020,7 @@ static int CmdHF_ntag424_read(const char *Cmd) {
|
||||||
|
|
||||||
int fileno = arg_get_int(ctx, 1);
|
int fileno = arg_get_int(ctx, 1);
|
||||||
|
|
||||||
int keyno;
|
int keyno = 0;
|
||||||
uint8_t key[16] = {0};
|
uint8_t key[16] = {0};
|
||||||
bool auth = (ntag424_cli_get_auth_information(ctx, 2, 3, &keyno, key) == PM3_SUCCESS);
|
bool auth = (ntag424_cli_get_auth_information(ctx, 2, 3, &keyno, key) == PM3_SUCCESS);
|
||||||
|
|
||||||
|
@ -1248,7 +1249,7 @@ static int CmdHF_ntag424_changefilesettings(const char *Cmd) {
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||||
int fileno = arg_get_int(ctx, 1);
|
int fileno = arg_get_int(ctx, 1);
|
||||||
|
|
||||||
int keyno;
|
int keyno = 0;
|
||||||
uint8_t key[16] = {0};
|
uint8_t key[16] = {0};
|
||||||
|
|
||||||
uint8_t has_options = 0;
|
uint8_t has_options = 0;
|
||||||
|
|
|
@ -164,10 +164,18 @@ typedef struct _em4x70_cmd_input_verify_auth_t {
|
||||||
ID48LIB_GRN grn;
|
ID48LIB_GRN grn;
|
||||||
} em4x70_cmd_input_verify_auth_t;
|
} em4x70_cmd_input_verify_auth_t;
|
||||||
|
|
||||||
static int CmdHelp(const char *Cmd);
|
typedef struct _em4x70_cmd_input_calculate_t {
|
||||||
|
ID48LIB_KEY key;
|
||||||
|
ID48LIB_NONCE rn;
|
||||||
|
} em4x70_cmd_input_calculate_t;
|
||||||
|
typedef struct _em4x70_cmd_output_calculate_t {
|
||||||
|
ID48LIB_FRN frn;
|
||||||
|
ID48LIB_GRN grn;
|
||||||
|
} em4x70_cmd_output_calculate_t;
|
||||||
|
|
||||||
|
|
||||||
static void fill_buffer_prng_bytes(void *buffer, size_t byte_count) {
|
static void fill_buffer_prng_bytes(void *buffer, size_t byte_count) {
|
||||||
if (byte_count <= 0) {
|
if (byte_count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,23 +439,8 @@ static int verify_auth_em4x70(const em4x70_cmd_input_verify_auth_t *opts) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// used by `lf search` and `search`, this is a quick test for EM4x70 tag
|
|
||||||
// In alignment with other tags implementations, this also dumps basic information
|
|
||||||
// about the tag, if one is found.
|
|
||||||
// Use helper function `get_em4x70_info()` if wanting to limit / avoid output.
|
|
||||||
bool detect_4x70_block(void) {
|
|
||||||
em4x70_tag_info_t info;
|
|
||||||
em4x70_cmd_input_info_t opts = { 0 };
|
|
||||||
|
|
||||||
int result = get_em4x70_info(&opts, &info);
|
static int CmdEM4x70Info(const char *Cmd) {
|
||||||
|
|
||||||
if (result == PM3_ETIMEOUT) { // consider removing this output?
|
|
||||||
PrintAndLogEx(WARNING, "Timeout while waiting for reply.");
|
|
||||||
}
|
|
||||||
return result == PM3_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CmdEM4x70Info(const char *Cmd) {
|
|
||||||
|
|
||||||
// invoke reading of a EM4x70 tag which has to be on the antenna because
|
// invoke reading of a EM4x70 tag which has to be on the antenna because
|
||||||
// decoding is done by the device (not on client side)
|
// decoding is done by the device (not on client side)
|
||||||
|
@ -487,7 +480,7 @@ int CmdEM4x70Info(const char *Cmd) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x70Write(const char *Cmd) {
|
static int CmdEM4x70Write(const char *Cmd) {
|
||||||
|
|
||||||
// write one block/word (16 bits) to the tag at given block address (0-15)
|
// write one block/word (16 bits) to the tag at given block address (0-15)
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
|
@ -539,7 +532,7 @@ int CmdEM4x70Write(const char *Cmd) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x70Brute(const char *Cmd) {
|
static int CmdEM4x70Brute(const char *Cmd) {
|
||||||
|
|
||||||
// From paper "Dismantling Megamos Crypto", Roel Verdult, Flavio D. Garcia and Barıs¸ Ege.
|
// From paper "Dismantling Megamos Crypto", Roel Verdult, Flavio D. Garcia and Barıs¸ Ege.
|
||||||
// Partial Key-Update Attack (optimized version)
|
// Partial Key-Update Attack (optimized version)
|
||||||
|
@ -549,7 +542,9 @@ int CmdEM4x70Brute(const char *Cmd) {
|
||||||
"This attack does NOT write anything to the tag.\n"
|
"This attack does NOT write anything to the tag.\n"
|
||||||
"Before starting this attack, 0000 must be written to the 16-bit key block: 'lf em 4x70 write -b 9 -d 0000'.\n"
|
"Before starting this attack, 0000 must be written to the 16-bit key block: 'lf em 4x70 write -b 9 -d 0000'.\n"
|
||||||
"After success, the 16-bit key block have to be restored with the key found: 'lf em 4x70 write -b 9 -d c0de'\n",
|
"After success, the 16-bit key block have to be restored with the key found: 'lf em 4x70 write -b 9 -d c0de'\n",
|
||||||
"lf em 4x70 brute -b 9 --rnd 45F54ADA252AAC --frn 4866BB70 --> bruteforcing key bits k95...k80\n"
|
"lf em 4x70 brute -b 9 --rnd 45F54ADA252AAC --frn 4866BB70 --> bruteforcing key bits k95...k80 (pm3 test key)\n"
|
||||||
|
"lf em 4x70 brute -b 8 --rnd 3FFE1FB6CC513F --frn F355F1A0 --> bruteforcing key bits k79...k64 (research paper key)\n"
|
||||||
|
"lf em 4x70 brute -b 7 --rnd 7D5167003571F8 --frn 982DBCC0 --> bruteforcing key bits k63...k48 (autorecovery test key)\n"
|
||||||
);
|
);
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
|
@ -623,7 +618,7 @@ int CmdEM4x70Brute(const char *Cmd) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x70Unlock(const char *Cmd) {
|
static int CmdEM4x70Unlock(const char *Cmd) {
|
||||||
|
|
||||||
// send pin code to device, unlocking it for writing
|
// send pin code to device, unlocking it for writing
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
|
@ -671,7 +666,7 @@ int CmdEM4x70Unlock(const char *Cmd) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x70Auth(const char *Cmd) {
|
static int CmdEM4x70Auth(const char *Cmd) {
|
||||||
|
|
||||||
// Authenticate transponder
|
// Authenticate transponder
|
||||||
// Send 56-bit random number + pre-computed f(rnd, k) to transponder.
|
// Send 56-bit random number + pre-computed f(rnd, k) to transponder.
|
||||||
|
@ -731,7 +726,7 @@ int CmdEM4x70Auth(const char *Cmd) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x70SetPIN(const char *Cmd) {
|
static int CmdEM4x70SetPIN(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "lf em 4x70 setpin",
|
CLIParserInit(&ctx, "lf em 4x70 setpin",
|
||||||
"Write new PIN\n",
|
"Write new PIN\n",
|
||||||
|
@ -776,7 +771,7 @@ int CmdEM4x70SetPIN(const char *Cmd) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x70SetKey(const char *Cmd) {
|
static int CmdEM4x70SetKey(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "lf em 4x70 setkey",
|
CLIParserInit(&ctx, "lf em 4x70 setkey",
|
||||||
"Write new 96-bit key to tag\n",
|
"Write new 96-bit key to tag\n",
|
||||||
|
@ -902,6 +897,7 @@ static int CmdEM4x70Recover_ParseArgs(const char *Cmd, em4x70_cmd_input_recover_
|
||||||
,
|
,
|
||||||
"lf em 4x70 recover --key F32AA98CF5BE --rnd 45F54ADA252AAC --frn 4866BB70 --grn 9BD180 (pm3 test key)\n"
|
"lf em 4x70 recover --key F32AA98CF5BE --rnd 45F54ADA252AAC --frn 4866BB70 --grn 9BD180 (pm3 test key)\n"
|
||||||
"lf em 4x70 recover --key A090A0A02080 --rnd 3FFE1FB6CC513F --frn F355F1A0 --grn 609D60 (research paper key)\n"
|
"lf em 4x70 recover --key A090A0A02080 --rnd 3FFE1FB6CC513F --frn F355F1A0 --grn 609D60 (research paper key)\n"
|
||||||
|
"lf em 4x70 recover --key 022A028C02BE --rnd 7D5167003571F8 --frn 982DBCC0 --grn 36C0E0 (autorecovery test key)\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
|
@ -973,7 +969,7 @@ static int CmdEM4x70Recover_ParseArgs(const char *Cmd, em4x70_cmd_input_recover_
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CmdEM4x70Recover(const char *Cmd) {
|
static int CmdEM4x70Recover(const char *Cmd) {
|
||||||
// From paper "Dismantling Megamos Crypto", Roel Verdult, Flavio D. Garcia and Barıs¸ Ege.
|
// From paper "Dismantling Megamos Crypto", Roel Verdult, Flavio D. Garcia and Barıs¸ Ege.
|
||||||
// Partial Key-Update Attack -- final 48 bits (after optimized version gets k95..k48)
|
// Partial Key-Update Attack -- final 48 bits (after optimized version gets k95..k48)
|
||||||
em4x70_recovery_data_t recover_ctx = {0};
|
em4x70_recovery_data_t recover_ctx = {0};
|
||||||
|
@ -1442,6 +1438,97 @@ static int CmdEM4x70AutoRecover(const char *Cmd) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int CmdEM4x70Calc_ParseArgs(const char *Cmd, em4x70_cmd_input_calculate_t *out_results) {
|
||||||
|
|
||||||
|
memset(out_results, 0, sizeof(em4x70_cmd_input_calculate_t));
|
||||||
|
|
||||||
|
int result = PM3_SUCCESS;
|
||||||
|
|
||||||
|
CLIParserContext *ctx;
|
||||||
|
CLIParserInit(
|
||||||
|
&ctx,
|
||||||
|
"lf em 4x70 calc",
|
||||||
|
"Calculates both the reader and tag challenge for a user-provided key and rnd.\n"
|
||||||
|
,
|
||||||
|
"lf em 4x70 calc --key F32AA98CF5BE4ADFA6D3480B --rnd 45F54ADA252AAC (pm3 test key)\n" // --frn 4866BB70 --grn 9BD180
|
||||||
|
"lf em 4x70 calc --key A090A0A02080000000000000 --rnd 3FFE1FB6CC513F (research paper key)\n" // --frn F355F1A0 --grn 609D60
|
||||||
|
"lf em 4x70 calc --key 022A028C02BE000102030405 --rnd 7D5167003571F8 (autorecovery test key)\n" // --frn 982DBCC0 --grn 36C0E0
|
||||||
|
);
|
||||||
|
void *argtable[] = {
|
||||||
|
arg_param_begin,
|
||||||
|
arg_str1(NULL, "key", "<hex>", "Key 96-bit as 12 hex bytes"),
|
||||||
|
arg_str1(NULL, "rnd", "<hex>", "56-bit random value sent to tag for authentication"),
|
||||||
|
arg_param_end
|
||||||
|
};
|
||||||
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
int key_len = 0; // must be 12 bytes hex data
|
||||||
|
int rnd_len = 0; // must be 7 bytes hex data
|
||||||
|
|
||||||
|
// These macros hide early function return on error ... including free'ing ctx.
|
||||||
|
CLIGetHexWithReturn(ctx, 1, out_results->key.k, &key_len);
|
||||||
|
CLIGetHexWithReturn(ctx, 2, out_results->rn.rn, &rnd_len);
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
if (key_len != 12) {
|
||||||
|
PrintAndLogEx(FAILED, "Key length must be 12 bytes, got %d", key_len);
|
||||||
|
result = PM3_EINVARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rnd_len != 7) {
|
||||||
|
PrintAndLogEx(FAILED, "Random number length must be 7 bytes, got %d", rnd_len);
|
||||||
|
result = PM3_EINVARG;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int CmdEM4x70Calc(const char *Cmd) {
|
||||||
|
em4x70_cmd_input_calculate_t opts = {0};
|
||||||
|
em4x70_cmd_output_calculate_t data = {0};
|
||||||
|
|
||||||
|
// 0. Parse the command line
|
||||||
|
int result = CmdEM4x70Calc_ParseArgs(Cmd, &opts);
|
||||||
|
if (PM3_SUCCESS != result) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// There are no failure paths. All inputs are valid, and ID48LIB doesn't add any failure paths.
|
||||||
|
id48lib_generator(&opts.key, &opts.rn, &data.frn, &data.grn);
|
||||||
|
|
||||||
|
char key_string[24 + 1] = {0};
|
||||||
|
char rnd_string[14 + 1] = {0};
|
||||||
|
char frn_string[ 8 + 1] = {0};
|
||||||
|
char grn_string[ 6 + 1] = {0};
|
||||||
|
if (true) {
|
||||||
|
snprintf(
|
||||||
|
key_string, 25,
|
||||||
|
"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||||
|
opts.key.k[ 0], opts.key.k[ 1], opts.key.k[ 2], opts.key.k[ 3],
|
||||||
|
opts.key.k[ 4], opts.key.k[ 5], opts.key.k[ 6], opts.key.k[ 7],
|
||||||
|
opts.key.k[ 8], opts.key.k[ 9], opts.key.k[10], opts.key.k[11]
|
||||||
|
);
|
||||||
|
snprintf(
|
||||||
|
rnd_string, 15,
|
||||||
|
"%02X%02X%02X%02X%02X%02X%02X",
|
||||||
|
opts.rn.rn[0], opts.rn.rn[1], opts.rn.rn[2], opts.rn.rn[3], opts.rn.rn[4], opts.rn.rn[5], opts.rn.rn[6]
|
||||||
|
);
|
||||||
|
snprintf(
|
||||||
|
frn_string, 9,
|
||||||
|
"%02X%02X%02X%02X",
|
||||||
|
data.frn.frn[0], data.frn.frn[1], data.frn.frn[2], data.frn.frn[3]
|
||||||
|
);
|
||||||
|
snprintf(
|
||||||
|
grn_string, 7,
|
||||||
|
"%02X%02X%02X",
|
||||||
|
data.grn.grn[0], data.grn.grn[1], data.grn.grn[2]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
PrintAndLogEx(SUCCESS, "KEY: %s RND: %s FRN: " _GREEN_("%s") " GRN: " _GREEN_("%s"), key_string, rnd_string, frn_string, grn_string);
|
||||||
|
return PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be declared to be used in the table,
|
||||||
|
// but cannot be defined yet because it uses the table.
|
||||||
|
static int CmdHelp(const char *Cmd);
|
||||||
|
|
||||||
static command_t CommandTable[] = {
|
static command_t CommandTable[] = {
|
||||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||||
|
@ -1452,6 +1539,7 @@ static command_t CommandTable[] = {
|
||||||
{"auth", CmdEM4x70Auth, IfPm3EM4x70, "Authenticate EM4x70"},
|
{"auth", CmdEM4x70Auth, IfPm3EM4x70, "Authenticate EM4x70"},
|
||||||
{"setpin", CmdEM4x70SetPIN, IfPm3EM4x70, "Write PIN"},
|
{"setpin", CmdEM4x70SetPIN, IfPm3EM4x70, "Write PIN"},
|
||||||
{"setkey", CmdEM4x70SetKey, IfPm3EM4x70, "Write key"},
|
{"setkey", CmdEM4x70SetKey, IfPm3EM4x70, "Write key"},
|
||||||
|
{"calc", CmdEM4x70Calc, AlwaysAvailable, "Calculate EM4x70 challenge and response"},
|
||||||
{"recover", CmdEM4x70Recover, AlwaysAvailable, "Recover remaining key from partial key"},
|
{"recover", CmdEM4x70Recover, AlwaysAvailable, "Recover remaining key from partial key"},
|
||||||
{"autorecover", CmdEM4x70AutoRecover, IfPm3EM4x70, "Recover entire key from writable tag"},
|
{"autorecover", CmdEM4x70AutoRecover, IfPm3EM4x70, "Recover entire key from writable tag"},
|
||||||
{NULL, NULL, NULL, NULL}
|
{NULL, NULL, NULL, NULL}
|
||||||
|
@ -1463,7 +1551,27 @@ static int CmdHelp(const char *Cmd) {
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Only two functions need to be non-static:
|
||||||
|
// * CmdLFEM4X70()
|
||||||
|
// * detect_4x70_block()
|
||||||
int CmdLFEM4X70(const char *Cmd) {
|
int CmdLFEM4X70(const char *Cmd) {
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
return CmdsParse(CommandTable, Cmd);
|
return CmdsParse(CommandTable, Cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// used by `lf search` and `search`, this is a quick test for EM4x70 tag
|
||||||
|
// In alignment with other tags implementations, this also dumps basic information
|
||||||
|
// about the tag, if one is found.
|
||||||
|
// Use helper function `get_em4x70_info()` if wanting to limit / avoid output.
|
||||||
|
bool detect_4x70_block(void) {
|
||||||
|
em4x70_tag_info_t info;
|
||||||
|
em4x70_cmd_input_info_t opts = { 0 };
|
||||||
|
|
||||||
|
int result = get_em4x70_info(&opts, &info);
|
||||||
|
|
||||||
|
if (result == PM3_ETIMEOUT) { // consider removing this output?
|
||||||
|
PrintAndLogEx(WARNING, "Timeout while waiting for reply.");
|
||||||
|
}
|
||||||
|
return result == PM3_SUCCESS;
|
||||||
|
}
|
||||||
|
|
|
@ -24,14 +24,6 @@
|
||||||
#define TIMEOUT 2000
|
#define TIMEOUT 2000
|
||||||
|
|
||||||
int CmdLFEM4X70(const char *Cmd);
|
int CmdLFEM4X70(const char *Cmd);
|
||||||
int CmdEM4x70Info(const char *Cmd);
|
|
||||||
int CmdEM4x70Write(const char *Cmd);
|
|
||||||
int CmdEM4x70Brute(const char *Cmd);
|
|
||||||
int CmdEM4x70Unlock(const char *Cmd);
|
|
||||||
int CmdEM4x70Auth(const char *Cmd);
|
|
||||||
int CmdEM4x70SetPIN(const char *Cmd);
|
|
||||||
int CmdEM4x70SetKey(const char *Cmd);
|
|
||||||
int CmdEM4x70Recover(const char *Cmd);
|
|
||||||
|
|
||||||
// for `lf search`:
|
// for `lf search`:
|
||||||
bool detect_4x70_block(void);
|
bool detect_4x70_block(void);
|
||||||
|
|
|
@ -530,7 +530,7 @@ static int CmdLFNedapSim(const char *Cmd) {
|
||||||
uint8_t data[16];
|
uint8_t data[16];
|
||||||
NedapGen(sub_type, customer_code, id, is_long, data);
|
NedapGen(sub_type, customer_code, id, is_long, data);
|
||||||
|
|
||||||
uint8_t bs[16 * 8];
|
uint8_t bs[16 * 8] = {0};
|
||||||
for (uint8_t i = 0; i < max; i++) {
|
for (uint8_t i = 0; i < max; i++) {
|
||||||
num_to_bytebits(data[i], 8, bs + i * 8);
|
num_to_bytebits(data[i], 8, bs + i * 8);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,12 +42,12 @@ static bool is_last_record(uint16_t tracepos, uint16_t traceLen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool next_record_is_response(uint16_t tracepos, uint8_t *trace) {
|
static bool next_record_is_response(uint16_t tracepos, uint8_t *trace) {
|
||||||
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos);
|
const tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
return (hdr->isResponse);
|
return (hdr->isResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen,
|
static bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, uint16_t *tracepos, uint16_t traceLen,
|
||||||
uint8_t *trace, uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) {
|
uint8_t *trace, const uint8_t *frame, uint8_t *topaz_reader_command, uint16_t *data_len) {
|
||||||
|
|
||||||
#define MAX_TOPAZ_READER_CMD_LEN 16
|
#define MAX_TOPAZ_READER_CMD_LEN 16
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ static bool merge_topaz_reader_frames(uint32_t timestamp, uint32_t *duration, ui
|
||||||
|
|
||||||
while (!is_last_record(*tracepos, traceLen) && !next_record_is_response(*tracepos, trace)) {
|
while (!is_last_record(*tracepos, traceLen) && !next_record_is_response(*tracepos, trace)) {
|
||||||
|
|
||||||
tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + *tracepos);
|
const tracelog_hdr_t *hdr = (tracelog_hdr_t *)(trace + *tracepos);
|
||||||
|
|
||||||
*tracepos += TRACELOG_HDR_LEN + hdr->data_len;
|
*tracepos += TRACELOG_HDR_LEN + hdr->data_len;
|
||||||
|
|
||||||
|
@ -93,7 +93,7 @@ static uint8_t calc_pos(const uint8_t *d) {
|
||||||
|
|
||||||
// Copy an existing buffer into client trace buffer
|
// Copy an existing buffer into client trace buffer
|
||||||
// I think this is cleaner than further globalizing gs_trace, and may lend itself to more modularity later?
|
// I think this is cleaner than further globalizing gs_trace, and may lend itself to more modularity later?
|
||||||
bool ImportTraceBuffer(uint8_t *trace_src, uint16_t trace_len) {
|
bool ImportTraceBuffer(const uint8_t *trace_src, uint16_t trace_len) {
|
||||||
if (trace_len == 0 || trace_src == NULL) return (false);
|
if (trace_len == 0 || trace_src == NULL) return (false);
|
||||||
if (gs_trace) {
|
if (gs_trace) {
|
||||||
free(gs_trace);
|
free(gs_trace);
|
||||||
|
@ -218,7 +218,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case ICLASS_CMD_SELECT: {
|
case ICLASS_CMD_SELECT: {
|
||||||
|
|
||||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
const tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
tracepos += SKIP_TO_NEXT(next_hdr);
|
tracepos += SKIP_TO_NEXT(next_hdr);
|
||||||
if (next_hdr->data_len != 10) {
|
if (next_hdr->data_len != 10) {
|
||||||
break;
|
break;
|
||||||
|
@ -231,7 +231,7 @@ static uint16_t extractChallenges(uint16_t tracepos, uint16_t traceLen, uint8_t
|
||||||
|
|
||||||
// get epurse
|
// get epurse
|
||||||
if (frame[1] == 2 && data_len == 2) {
|
if (frame[1] == 2 && data_len == 2) {
|
||||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
const tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
tracepos += SKIP_TO_NEXT(next_hdr);
|
tracepos += SKIP_TO_NEXT(next_hdr);
|
||||||
if (next_hdr->data_len < 8) {
|
if (next_hdr->data_len < 8) {
|
||||||
break;
|
break;
|
||||||
|
@ -641,25 +641,22 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
|
|
||||||
} else if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAG2) || (protocol == PROTO_HITAGS))) {
|
} else if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAG2) || (protocol == PROTO_HITAGS))) {
|
||||||
|
|
||||||
|
if (j == 0) {
|
||||||
|
|
||||||
// handle partial bytes. The parity array[0] is used to store number of left over bits from NBYTES
|
// handle partial bytes. The parity array[0] is used to store number of left over bits from NBYTES
|
||||||
// This part prints the number of bits in the trace entry for hitag.
|
// This part prints the number of bits in the trace entry for hitag.
|
||||||
uint8_t nbits = parityBytes[0];
|
uint8_t nbits = parityBytes[0];
|
||||||
if (j == 0) {
|
|
||||||
|
|
||||||
// only apply this to lesser than one byte
|
// only apply this to lesser than one byte
|
||||||
if (data_len == 1) {
|
if (data_len == 1) {
|
||||||
|
|
||||||
if (nbits == 5) {
|
|
||||||
snprintf(line[0], 120, "%2u: %02X ", nbits, frame[0] >> (8 - nbits));
|
snprintf(line[0], 120, "%2u: %02X ", nbits, frame[0] >> (8 - nbits));
|
||||||
} else {
|
|
||||||
snprintf(line[0], 120, "%2u: %02X ", nbits, frame[0] >> (8 - nbits));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (nbits == 0) {
|
if (nbits == 0) {
|
||||||
snprintf(line[0], 120, "%2u: %02X ", (data_len * 8), frame[0]);
|
snprintf(line[0], 120, "%2u: %02X ", (uint16_t)(data_len * 8), frame[0]);
|
||||||
} else {
|
} else {
|
||||||
snprintf(line[0], 120, "%2u: %02X ", ((data_len - 1) * 8) + nbits, frame[0]);
|
snprintf(line[0], 120, "%2u: %02X ", (uint16_t)(((data_len - 1) * 8) + nbits), frame[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset = 4;
|
offset = 4;
|
||||||
|
@ -676,7 +673,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
|
|
||||||
if (markCRCBytes && data_len > 2) {
|
if (markCRCBytes && data_len > 2) {
|
||||||
// CRC-command
|
// CRC-command
|
||||||
if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAGS)) && (data_len > 1)) {
|
if (((protocol == PROTO_HITAG1) || (protocol == PROTO_HITAGS))) {
|
||||||
// Note that UID REQUEST response has no CRC, but we don't know
|
// Note that UID REQUEST response has no CRC, but we don't know
|
||||||
// if the response we see is a UID
|
// if the response we see is a UID
|
||||||
char *pos1 = line[(data_len - 1) / 18] + (((data_len - 1) % 18) * 4) + offset - 1;
|
char *pos1 = line[(data_len - 1) / 18] + (((data_len - 1) % 18) * 4) + offset - 1;
|
||||||
|
@ -989,7 +986,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
// handle partial bytes. The parity array[0] is used to store number of left over bits from NBYTES
|
// handle partial bytes. The parity array[0] is used to store number of left over bits from NBYTES
|
||||||
// This part prints the number of bits in the trace entry for hitag.
|
// This part prints the number of bits in the trace entry for hitag.
|
||||||
uint8_t nbits = parityBytes[0];
|
uint8_t nbits = parityBytes[0];
|
||||||
|
|
||||||
annotateHitag2(explanation, sizeof(explanation), ht2plain, n, nbits, hdr->isResponse, NULL, 0, true);
|
annotateHitag2(explanation, sizeof(explanation), ht2plain, n, nbits, hdr->isResponse, NULL, 0, true);
|
||||||
|
|
||||||
// iceman: colorise crc bytes here will need a refactor of code from above.
|
// iceman: colorise crc bytes here will need a refactor of code from above.
|
||||||
|
@ -1000,19 +996,13 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
|
|
||||||
// only apply this to lesser than one byte
|
// only apply this to lesser than one byte
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
|
|
||||||
if (nbits == 5) {
|
|
||||||
snprintf(line[0], 120, "%2u: %02X ", nbits, ht2plain[0] >> (8 - nbits));
|
snprintf(line[0], 120, "%2u: %02X ", nbits, ht2plain[0] >> (8 - nbits));
|
||||||
} else {
|
|
||||||
snprintf(line[0], 120, "%2u: %02X ", nbits, ht2plain[0] >> (8 - nbits));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (nbits == 0) {
|
if (nbits == 0) {
|
||||||
snprintf(line[0], 120, "%2u: %02X ", (n * 8), ht2plain[0]);
|
snprintf(line[0], 120, "%2u: %02X ", (uint16_t)(n * 8), ht2plain[0]);
|
||||||
} else {
|
} else {
|
||||||
snprintf(line[0], 120, "%2u: %02X ", ((n - 1) * 8) + nbits, ht2plain[0]);
|
snprintf(line[0], 120, "%2u: %02X ", (uint16_t)(((n - 1) * 8) + nbits), ht2plain[0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset = 4;
|
offset = 4;
|
||||||
|
@ -1049,7 +1039,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
||||||
|
|
||||||
if (showWaitCycles && hdr->isResponse == false && next_record_is_response(tracepos, trace)) {
|
if (showWaitCycles && hdr->isResponse == false && next_record_is_response(tracepos, trace)) {
|
||||||
|
|
||||||
tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
const tracelog_hdr_t *next_hdr = (tracelog_hdr_t *)(trace + tracepos);
|
||||||
|
|
||||||
uint32_t time1 = end_of_transmission_timestamp - first_hdr->timestamp;
|
uint32_t time1 = end_of_transmission_timestamp - first_hdr->timestamp;
|
||||||
uint32_t time2 = next_hdr->timestamp - first_hdr->timestamp;
|
uint32_t time2 = next_hdr->timestamp - first_hdr->timestamp;
|
||||||
|
|
|
@ -24,6 +24,6 @@
|
||||||
int CmdTrace(const char *Cmd);
|
int CmdTrace(const char *Cmd);
|
||||||
int CmdTraceList(const char *Cmd);
|
int CmdTraceList(const char *Cmd);
|
||||||
int CmdTraceListAlias(const char *Cmd, const char *alias, const char *protocol);
|
int CmdTraceListAlias(const char *Cmd, const char *alias, const char *protocol);
|
||||||
bool ImportTraceBuffer(uint8_t *trace_src, uint16_t trace_len);
|
bool ImportTraceBuffer(const uint8_t *trace_src, uint16_t trace_len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -87,7 +87,7 @@ void SendCommandBL(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, vo
|
||||||
SendCommandOLD(cmd, arg0, arg1, arg2, data, len);
|
SendCommandOLD(cmd, arg0, arg1, arg2, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendCommandOLD(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len) {
|
void SendCommandOLD(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len) {
|
||||||
PacketCommandOLD c = {CMD_UNKNOWN, {0, 0, 0}, {{0}}};
|
PacketCommandOLD c = {CMD_UNKNOWN, {0, 0, 0}, {{0}}};
|
||||||
c.cmd = cmd;
|
c.cmd = cmd;
|
||||||
c.arg[0] = arg0;
|
c.arg[0] = arg0;
|
||||||
|
@ -198,7 +198,7 @@ void SendCommandNG(uint16_t cmd, uint8_t *data, size_t len) {
|
||||||
SendCommandNG_internal(cmd, data, len, true);
|
SendCommandNG_internal(cmd, data, len, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SendCommandMIX(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len) {
|
void SendCommandMIX(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len) {
|
||||||
uint64_t arg[3] = {arg0, arg1, arg2};
|
uint64_t arg[3] = {arg0, arg1, arg2};
|
||||||
if (len > PM3_CMD_DATA_SIZE_MIX) {
|
if (len > PM3_CMD_DATA_SIZE_MIX) {
|
||||||
PrintAndLogEx(WARNING, "Sending %zu bytes of payload is too much for MIX frames, abort", len);
|
PrintAndLogEx(WARNING, "Sending %zu bytes of payload is too much for MIX frames, abort", len);
|
||||||
|
@ -228,7 +228,7 @@ void clearCommandBuffer(void) {
|
||||||
* @brief storeCommand stores a USB command in a circular buffer
|
* @brief storeCommand stores a USB command in a circular buffer
|
||||||
* @param UC
|
* @param UC
|
||||||
*/
|
*/
|
||||||
static void storeReply(PacketResponseNG *packet) {
|
static void storeReply(const PacketResponseNG *packet) {
|
||||||
pthread_mutex_lock(&rxBufferMutex);
|
pthread_mutex_lock(&rxBufferMutex);
|
||||||
if ((cmd_head + 1) % CMD_BUFFER_SIZE == cmd_tail) {
|
if ((cmd_head + 1) % CMD_BUFFER_SIZE == cmd_tail) {
|
||||||
//If these two are equal, we're about to overwrite in the
|
//If these two are equal, we're about to overwrite in the
|
||||||
|
@ -296,7 +296,7 @@ static void PacketResponseReceived(PacketResponseNG *packet) {
|
||||||
uint16_t flag;
|
uint16_t flag;
|
||||||
uint8_t buf[PM3_CMD_DATA_SIZE - sizeof(uint16_t)];
|
uint8_t buf[PM3_CMD_DATA_SIZE - sizeof(uint16_t)];
|
||||||
} PACKED;
|
} PACKED;
|
||||||
struct d *data = (struct d *)&packet->data.asBytes;
|
const struct d *data = (struct d *)&packet->data.asBytes;
|
||||||
len = packet->length - sizeof(data->flag);
|
len = packet->length - sizeof(data->flag);
|
||||||
flag = data->flag;
|
flag = data->flag;
|
||||||
memcpy(s, data->buf, len);
|
memcpy(s, data->buf, len);
|
||||||
|
@ -350,7 +350,7 @@ static void PacketResponseReceived(PacketResponseNG *packet) {
|
||||||
// When communication thread is dead, start up and try to start it again
|
// When communication thread is dead, start up and try to start it again
|
||||||
void *uart_reconnect(void *targ) {
|
void *uart_reconnect(void *targ) {
|
||||||
|
|
||||||
communication_arg_t *connection = (communication_arg_t *)targ;
|
const communication_arg_t *connection = (communication_arg_t *)targ;
|
||||||
|
|
||||||
#if defined(__MACH__) && defined(__APPLE__)
|
#if defined(__MACH__) && defined(__APPLE__)
|
||||||
disableAppNap("Proxmark3 polling UART");
|
disableAppNap("Proxmark3 polling UART");
|
||||||
|
@ -405,7 +405,7 @@ __attribute__((force_align_arg_pointer))
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
*uart_communication(void *targ) {
|
*uart_communication(void *targ) {
|
||||||
communication_arg_t *connection = (communication_arg_t *)targ;
|
const communication_arg_t *connection = (communication_arg_t *)targ;
|
||||||
uint32_t rxlen;
|
uint32_t rxlen;
|
||||||
bool commfailed = false;
|
bool commfailed = false;
|
||||||
PacketResponseNG rx;
|
PacketResponseNG rx;
|
||||||
|
@ -686,7 +686,7 @@ bool IsCommunicationThreadDead(void) {
|
||||||
|
|
||||||
bool SetCommunicationReceiveMode(bool isRawMode) {
|
bool SetCommunicationReceiveMode(bool isRawMode) {
|
||||||
if (isRawMode) {
|
if (isRawMode) {
|
||||||
uint8_t *buffer = __atomic_load_n(&comm_raw_data, __ATOMIC_SEQ_CST);
|
const uint8_t *buffer = __atomic_load_n(&comm_raw_data, __ATOMIC_SEQ_CST);
|
||||||
if (buffer == NULL) {
|
if (buffer == NULL) {
|
||||||
PrintAndLogEx(ERR, "Buffer for raw data is not set");
|
PrintAndLogEx(ERR, "Buffer for raw data is not set");
|
||||||
return false;
|
return false;
|
||||||
|
@ -850,7 +850,7 @@ int TestProxmark(pm3_device_t *dev) {
|
||||||
return PM3_EDEVNOTSUPP;
|
return PM3_EDEVNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(&g_pm3_capabilities, resp.data.asBytes, MIN(sizeof(capabilities_t), resp.length));
|
memcpy(&g_pm3_capabilities, resp.data.asBytes, sizeof(capabilities_t));
|
||||||
g_conn.send_via_fpc_usart = g_pm3_capabilities.via_fpc;
|
g_conn.send_via_fpc_usart = g_pm3_capabilities.via_fpc;
|
||||||
g_conn.uart_speed = g_pm3_capabilities.baudrate;
|
g_conn.uart_speed = g_pm3_capabilities.baudrate;
|
||||||
|
|
||||||
|
|
|
@ -96,9 +96,9 @@ void *uart_reconnect(void *targ);
|
||||||
|
|
||||||
void *uart_receiver(void *targ);
|
void *uart_receiver(void *targ);
|
||||||
void SendCommandBL(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
|
void SendCommandBL(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
|
||||||
void SendCommandOLD(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
|
void SendCommandOLD(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len);
|
||||||
void SendCommandNG(uint16_t cmd, uint8_t *data, size_t len);
|
void SendCommandNG(uint16_t cmd, uint8_t *data, size_t len);
|
||||||
void SendCommandMIX(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, void *data, size_t len);
|
void SendCommandMIX(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2, const void *data, size_t len);
|
||||||
void clearCommandBuffer(void);
|
void clearCommandBuffer(void);
|
||||||
|
|
||||||
#define FLASHMODE_SPEED 460800
|
#define FLASHMODE_SPEED 460800
|
||||||
|
|
|
@ -292,7 +292,7 @@ static int emv_parse_track1(const uint8_t *d, size_t n, bool verbose) {
|
||||||
// decoder
|
// decoder
|
||||||
char *tmp = str_ndup((const char *)d, n);
|
char *tmp = str_ndup((const char *)d, n);
|
||||||
uint8_t i = 0;
|
uint8_t i = 0;
|
||||||
char delim[2] = "^";
|
const char delim[2] = "^";
|
||||||
char *token = strtok(tmp, delim);
|
char *token = strtok(tmp, delim);
|
||||||
while (token != NULL) {
|
while (token != NULL) {
|
||||||
|
|
||||||
|
|
|
@ -747,7 +747,7 @@ out:
|
||||||
int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose) {
|
int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose) {
|
||||||
return saveFileJSONrootEx(preferredName, root, flags, verbose, false);
|
return saveFileJSONrootEx(preferredName, root, flags, verbose, false);
|
||||||
}
|
}
|
||||||
int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool verbose, bool overwrite) {
|
int saveFileJSONrootEx(const char *preferredName, const void *root, size_t flags, bool verbose, bool overwrite) {
|
||||||
if (root == NULL)
|
if (root == NULL)
|
||||||
return PM3_EINVARG;
|
return PM3_EINVARG;
|
||||||
|
|
||||||
|
@ -863,7 +863,7 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
// key file dump
|
// key file dump
|
||||||
int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector) {
|
int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, const sector_t *e_sector) {
|
||||||
|
|
||||||
if (e_sector == NULL) return PM3_EINVARG;
|
if (e_sector == NULL) return PM3_EINVARG;
|
||||||
|
|
||||||
|
@ -1743,7 +1743,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
|
snprintf(blocks, sizeof(blocks), "$.blocks.%u", i);
|
||||||
JsonLoadBufAsHex(root, blocks, &tag->data[sptr], 4, &len);
|
JsonLoadBufAsHex(root, blocks, &tag->data[sptr], 4, &len);
|
||||||
if (load_file_sanity(ctype, tag->bytesPerPage, i, len) == false) {
|
if (load_file_sanity(ctype, tag->bytesPerPage, i, len) == false) {
|
||||||
break;
|
break;
|
||||||
|
@ -1790,7 +1790,7 @@ int loadFileJSONex(const char *preferredName, void *data, size_t maxdatalen, siz
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(blocks, sizeof(blocks), "$.blocks.%d", i);
|
snprintf(blocks, sizeof(blocks), "$.blocks.%u", i);
|
||||||
JsonLoadBufAsHex(root, blocks, &tag->data[sptr], 8, &len);
|
JsonLoadBufAsHex(root, blocks, &tag->data[sptr], 8, &len);
|
||||||
if (load_file_sanity(ctype, tag->bytesPerPage, i, len) == false) {
|
if (load_file_sanity(ctype, tag->bytesPerPage, i, len) == false) {
|
||||||
break;
|
break;
|
||||||
|
@ -2426,7 +2426,7 @@ mfu_df_e detect_mfu_dump_format(uint8_t **dump, bool verbose) {
|
||||||
|
|
||||||
// detect plain
|
// detect plain
|
||||||
if (retval == MFU_DF_UNKNOWN) {
|
if (retval == MFU_DF_UNKNOWN) {
|
||||||
uint8_t *plain = *dump;
|
const uint8_t *plain = *dump;
|
||||||
bcc0 = ct ^ plain[0] ^ plain[1] ^ plain[2];
|
bcc0 = ct ^ plain[0] ^ plain[1] ^ plain[2];
|
||||||
bcc1 = plain[4] ^ plain[5] ^ plain[6] ^ plain[7];
|
bcc1 = plain[4] ^ plain[5] ^ plain[6] ^ plain[7];
|
||||||
if ((bcc0 == plain[3]) && (bcc1 == plain[8])) {
|
if ((bcc0 == plain[3]) && (bcc1 == plain[8])) {
|
||||||
|
|
|
@ -107,8 +107,8 @@ int fileExists(const char *filename);
|
||||||
bool setDefaultPath(savePaths_t pathIndex, const char *path);
|
bool setDefaultPath(savePaths_t pathIndex, const char *path);
|
||||||
|
|
||||||
char *newfilenamemcopy(const char *preferredName, const char *suffix);
|
char *newfilenamemcopy(const char *preferredName, const char *suffix);
|
||||||
char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePaths_t save_path);
|
char *newfilenamemcopyEx(const char *preferredName, const char *suffix, savePaths_t e_save_path);
|
||||||
void truncate_filename(char *fn, uint16_t len);
|
void truncate_filename(char *fn, uint16_t maxlen);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -138,7 +138,7 @@ int saveFile(const char *preferredName, const char *suffix, const void *data, si
|
||||||
int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *));
|
int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, void (*callback)(json_t *));
|
||||||
int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *), savePaths_t e_save_path);
|
int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen, bool verbose, void (*callback)(json_t *), savePaths_t e_save_path);
|
||||||
int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose);
|
int saveFileJSONroot(const char *preferredName, void *root, size_t flags, bool verbose);
|
||||||
int saveFileJSONrootEx(const char *preferredName, void *root, size_t flags, bool verbose, bool overwrite);
|
int saveFileJSONrootEx(const char *preferredName, const void *root, size_t flags, bool verbose, bool overwrite);
|
||||||
/** STUB
|
/** STUB
|
||||||
* @brief Utility function to save WAVE data to a file. This method takes a preferred name, but if that
|
* @brief Utility function to save WAVE data to a file. This method takes a preferred name, but if that
|
||||||
* file already exists, it tries with another name until it finds something suitable.
|
* file already exists, it tries with another name until it finds something suitable.
|
||||||
|
@ -171,7 +171,7 @@ int saveFilePM3(const char *preferredName, int *data, size_t datalen);
|
||||||
* @param e_sector the keys in question
|
* @param e_sector the keys in question
|
||||||
* @return 0 for ok, 1 for failz
|
* @return 0 for ok, 1 for failz
|
||||||
*/
|
*/
|
||||||
int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, sector_t *e_sector);
|
int createMfcKeyDump(const char *preferredName, uint8_t sectorsCnt, const sector_t *e_sector);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Utility function to load data from a binary file. This method takes a preferred name.
|
* @brief Utility function to load data from a binary file. This method takes a preferred name.
|
||||||
|
|
|
@ -519,7 +519,8 @@ buffer_savestate_t save_buffer32(uint32_t *src, size_t length) {
|
||||||
buffer_savestate_t bst = {
|
buffer_savestate_t bst = {
|
||||||
.type = sizeof(uint32_t),
|
.type = sizeof(uint32_t),
|
||||||
.bufferSize = length,
|
.bufferSize = length,
|
||||||
.buffer = savedBuffer
|
.buffer = savedBuffer,
|
||||||
|
.padding = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
return bst;
|
return bst;
|
||||||
|
@ -535,7 +536,8 @@ buffer_savestate_t save_bufferS32(int32_t *src, size_t length) {
|
||||||
buffer_savestate_t bst = {
|
buffer_savestate_t bst = {
|
||||||
.type = (sizeof(int32_t) >> 8),
|
.type = (sizeof(int32_t) >> 8),
|
||||||
.bufferSize = length,
|
.bufferSize = length,
|
||||||
.buffer = savedBuffer
|
.buffer = savedBuffer,
|
||||||
|
.padding = 0
|
||||||
};
|
};
|
||||||
|
|
||||||
return bst;
|
return bst;
|
||||||
|
@ -547,8 +549,11 @@ buffer_savestate_t save_buffer8(uint8_t *src, size_t length) {
|
||||||
// 1/4 of the size needed
|
// 1/4 of the size needed
|
||||||
size_t buffSize = (length / 4);
|
size_t buffSize = (length / 4);
|
||||||
|
|
||||||
|
PrintAndLogEx(DEBUG, "(save_buffer8) buffSize = %llu, length = %llu", buffSize, length);
|
||||||
|
|
||||||
if (length % 4) {
|
if (length % 4) {
|
||||||
buffSize++;
|
buffSize++;
|
||||||
|
PrintAndLogEx(DEBUG, "(save_buffer8) new buffSize = %llu", buffSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
// calloc the memory needed
|
// calloc the memory needed
|
||||||
|
@ -564,7 +569,8 @@ buffer_savestate_t save_buffer8(uint8_t *src, size_t length) {
|
||||||
buffer_savestate_t bst = {
|
buffer_savestate_t bst = {
|
||||||
.type = sizeof(uint8_t),
|
.type = sizeof(uint8_t),
|
||||||
.bufferSize = buffSize,
|
.bufferSize = buffSize,
|
||||||
.buffer = savedBuffer
|
.buffer = savedBuffer,
|
||||||
|
.padding = ((buffSize * 4) - length)
|
||||||
};
|
};
|
||||||
|
|
||||||
return bst;
|
return bst;
|
||||||
|
@ -602,13 +608,18 @@ size_t restore_buffer8(buffer_savestate_t saveState, uint8_t *dest) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t index = 0;
|
size_t index = 0;
|
||||||
|
size_t length = ((saveState.bufferSize * 4) - saveState.padding);
|
||||||
|
|
||||||
// Unpack the array
|
// Unpack the array
|
||||||
for (size_t i = 0; i < saveState.bufferSize; i++) {
|
for (size_t i = 0; i < saveState.bufferSize; i++) {
|
||||||
dest[index++] = saveState.buffer[i];
|
dest[index++] = saveState.buffer[i];
|
||||||
|
if(index == length) break;
|
||||||
dest[index++] = (saveState.buffer[i] >> 8) & 0xFF;
|
dest[index++] = (saveState.buffer[i] >> 8) & 0xFF;
|
||||||
|
if(index == length) break;
|
||||||
dest[index++] = (saveState.buffer[i] >> 16) & 0xFF;
|
dest[index++] = (saveState.buffer[i] >> 16) & 0xFF;
|
||||||
|
if(index == length) break;
|
||||||
dest[index++] = (saveState.buffer[i] >> 24) & 0xFF;
|
dest[index++] = (saveState.buffer[i] >> 24) & 0xFF;
|
||||||
|
if(index == length) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
|
|
|
@ -27,10 +27,11 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const uint8_t type; // Used for sanity checks
|
const uint8_t type; // Used for sanity checks
|
||||||
const uint32_t *buffer;
|
const uint32_t *buffer; // The storage buffer for this save state
|
||||||
const size_t bufferSize;
|
const size_t bufferSize; // The size of the buffer
|
||||||
uint32_t offset;
|
const uint8_t padding; // The amount of padding at the end of the buffer, if needed
|
||||||
uint32_t clock; //Not used by all buffers
|
uint32_t offset; // (optional) Any offset the buffer needs after restoring
|
||||||
|
uint32_t clock; // (optional) Clock data for the buffer
|
||||||
} buffer_savestate_t;
|
} buffer_savestate_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
|
@ -158,7 +158,7 @@ Definition 14. Define the rotate key function rk : (F 82 ) 8 × N → (F 82 ) 8
|
||||||
rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
|
rk(x [0] . . . x [7] , 0) = x [0] . . . x [7]
|
||||||
rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
|
rk(x [0] . . . x [7] , n + 1) = rk(rl(x [0] ) . . . rl(x [7] ), n)
|
||||||
**/
|
**/
|
||||||
static void rk(uint8_t *key, uint8_t n, uint8_t *outp_key) {
|
static void rk(const uint8_t *key, uint8_t n, uint8_t *outp_key) {
|
||||||
memcpy(outp_key, key, 8);
|
memcpy(outp_key, key, 8);
|
||||||
while (n-- > 0) {
|
while (n-- > 0) {
|
||||||
outp_key[0] = rl(outp_key[0]);
|
outp_key[0] = rl(outp_key[0]);
|
||||||
|
|
|
@ -203,7 +203,7 @@ int CalculateMAC(mf4Session_t *mf4session, MACType_t mtype, uint8_t blockNum, ui
|
||||||
return aes_cmac8(NULL, mf4session->Kmac, macdata, mac, macdatalen);
|
return aes_cmac8(NULL, mf4session->Kmac, macdata, mac, macdatalen);
|
||||||
}
|
}
|
||||||
|
|
||||||
int MifareAuth4(mf4Session_t *mf4session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode) {
|
int MifareAuth4(mf4Session_t *mf4session, const uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode) {
|
||||||
uint8_t data[257] = {0};
|
uint8_t data[257] = {0};
|
||||||
int datalen = 0;
|
int datalen = 0;
|
||||||
|
|
||||||
|
@ -375,7 +375,7 @@ static int intExchangeRAW14aPlus(uint8_t *datain, int datainlen, bool activateFi
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
int MFPWritePerso(const uint8_t *keyNum, const uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen) {
|
||||||
uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00};
|
uint8_t rcmd[3 + 16] = {0xa8, keyNum[1], keyNum[0], 0x00};
|
||||||
memmove(&rcmd[3], key, 16);
|
memmove(&rcmd[3], key, 16);
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ int MFPReadBlock(mf4Session_t *mf4session, bool plain, bool nomaccmd, bool nomac
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MFPWriteBlock(mf4Session_t *mf4session, bool plain, bool nomacres, uint8_t blockNum, uint8_t blockHdr, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
int MFPWriteBlock(mf4Session_t *mf4session, bool plain, bool nomacres, uint8_t blockNum, uint8_t blockHdr, const uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac) {
|
||||||
int cmdb = 0xA1;
|
int cmdb = 0xA1;
|
||||||
if (nomacres) {
|
if (nomacres) {
|
||||||
cmdb = cmdb ^ 0x01; // If we do not want MAC in reply, remove 0x01
|
cmdb = cmdb ^ 0x01; // If we do not want MAC in reply, remove 0x01
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#define MIFARE4_H
|
#define MIFARE4_H
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bool Authenticated;
|
bool Authenticated;
|
||||||
|
@ -59,12 +60,12 @@ void mfpSetVerboseMode(bool verbose);
|
||||||
const char *mfpGetErrorDescription(uint8_t errorCode);
|
const char *mfpGetErrorDescription(uint8_t errorCode);
|
||||||
|
|
||||||
int CalculateMAC(mf4Session_t *mf4session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose);
|
int CalculateMAC(mf4Session_t *mf4session, MACType_t mtype, uint8_t blockNum, uint8_t blockCount, uint8_t *data, int datalen, uint8_t *mac, bool verbose);
|
||||||
int MifareAuth4(mf4Session_t *mf4session, uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode);
|
int MifareAuth4(mf4Session_t *mf4session, const uint8_t *keyn, uint8_t *key, bool activateField, bool leaveSignalON, bool dropFieldIfError, bool verbose, bool silentMode);
|
||||||
|
|
||||||
int MFPWritePerso(uint8_t *keyNum, uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
int MFPWritePerso(const uint8_t *keyNum, const uint8_t *key, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||||
int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
int MFPCommitPerso(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||||
int MFPReadBlock(mf4Session_t *mf4session, bool plain, bool maccmd, bool macres, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
int MFPReadBlock(mf4Session_t *mf4session, bool plain, bool nomaccmd, bool nomacres, uint8_t blockNum, uint8_t blockCount, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
||||||
int MFPWriteBlock(mf4Session_t *mf4session, bool plain, bool nomacres, uint8_t blockNum, uint8_t blockHdr, uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
int MFPWriteBlock(mf4Session_t *mf4session, bool plain, bool nomacres, uint8_t blockNum, uint8_t blockHdr, const uint8_t *data, bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen, uint8_t *mac);
|
||||||
int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose);
|
int mfpReadSector(uint8_t sectorNo, uint8_t keyType, uint8_t *key, uint8_t *dataout, bool verbose);
|
||||||
|
|
||||||
int MFPGetSignature(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
int MFPGetSignature(bool activateField, bool leaveSignalON, uint8_t *dataout, int maxdataoutlen, int *dataoutlen);
|
||||||
|
|
|
@ -118,6 +118,9 @@ const static vocabulary_t vocabulary[] = {
|
||||||
{ 1, "data diff" },
|
{ 1, "data diff" },
|
||||||
{ 0, "data hexsamples" },
|
{ 0, "data hexsamples" },
|
||||||
{ 0, "data samples" },
|
{ 0, "data samples" },
|
||||||
|
{ 0, "data test_ss8" },
|
||||||
|
{ 0, "data test_ss32" },
|
||||||
|
{ 0, "data test_ss32s" },
|
||||||
{ 1, "emv help" },
|
{ 1, "emv help" },
|
||||||
{ 1, "emv list" },
|
{ 1, "emv list" },
|
||||||
{ 1, "emv test" },
|
{ 1, "emv test" },
|
||||||
|
@ -170,6 +173,8 @@ const static vocabulary_t vocabulary[] = {
|
||||||
{ 0, "hf 14b wrbl" },
|
{ 0, "hf 14b wrbl" },
|
||||||
{ 1, "hf 14b view" },
|
{ 1, "hf 14b view" },
|
||||||
{ 1, "hf 14b valid" },
|
{ 1, "hf 14b valid" },
|
||||||
|
{ 0, "hf 14b calypso" },
|
||||||
|
{ 0, "hf 14b mobib" },
|
||||||
{ 1, "hf 15 help" },
|
{ 1, "hf 15 help" },
|
||||||
{ 1, "hf 15 list" },
|
{ 1, "hf 15 list" },
|
||||||
{ 1, "hf 15 demod" },
|
{ 1, "hf 15 demod" },
|
||||||
|
@ -645,7 +650,7 @@ const static vocabulary_t vocabulary[] = {
|
||||||
{ 1, "lf hitag help" },
|
{ 1, "lf hitag help" },
|
||||||
{ 1, "lf hitag list" },
|
{ 1, "lf hitag list" },
|
||||||
{ 0, "lf hitag info" },
|
{ 0, "lf hitag info" },
|
||||||
{ 1, "lf hitag selftest" },
|
{ 1, "lf hitag test" },
|
||||||
{ 0, "lf hitag dump" },
|
{ 0, "lf hitag dump" },
|
||||||
{ 0, "lf hitag read" },
|
{ 0, "lf hitag read" },
|
||||||
{ 0, "lf hitag sniff" },
|
{ 0, "lf hitag sniff" },
|
||||||
|
@ -655,6 +660,7 @@ const static vocabulary_t vocabulary[] = {
|
||||||
{ 0, "lf hitag eview" },
|
{ 0, "lf hitag eview" },
|
||||||
{ 0, "lf hitag sim" },
|
{ 0, "lf hitag sim" },
|
||||||
{ 0, "lf hitag cc" },
|
{ 0, "lf hitag cc" },
|
||||||
|
{ 0, "lf hitag crack2" },
|
||||||
{ 0, "lf hitag chk" },
|
{ 0, "lf hitag chk" },
|
||||||
{ 1, "lf hitag lookup" },
|
{ 1, "lf hitag lookup" },
|
||||||
{ 0, "lf hitag ta" },
|
{ 0, "lf hitag ta" },
|
||||||
|
|
|
@ -385,7 +385,7 @@ void
|
||||||
__attribute__((force_align_arg_pointer))
|
__attribute__((force_align_arg_pointer))
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) {
|
main_loop(const char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) {
|
||||||
|
|
||||||
char *cmd = NULL;
|
char *cmd = NULL;
|
||||||
bool execCommand = (script_cmd != NULL);
|
bool execCommand = (script_cmd != NULL);
|
||||||
|
@ -777,31 +777,29 @@ static void show_help(bool showFullHelp, char *exec_name) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dumpmem_to_file(const char *filename, uint32_t addr, uint32_t len, bool raw, bool in_bootloader) {
|
static int dumpmem_to_file(const char *filename, uint32_t addr, uint32_t len, bool raw, bool in_bootloader) {
|
||||||
int res = PM3_EUNDEF;
|
|
||||||
|
|
||||||
uint8_t *buffer = calloc(len, sizeof(uint8_t));
|
uint8_t *buffer = calloc(len, sizeof(uint8_t));
|
||||||
if (!buffer) {
|
if (buffer == NULL) {
|
||||||
PrintAndLogEx(ERR, "error, cannot allocate memory ");
|
PrintAndLogEx(ERR, "error, cannot allocate memory ");
|
||||||
res = PM3_EMALLOC;
|
return PM3_EMALLOC;
|
||||||
goto fail;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t read = 0;
|
int res = PM3_EUNDEF;
|
||||||
|
size_t readlen = 0;
|
||||||
DeviceMemType_t type = raw ? MCU_MEM : MCU_FLASH;
|
DeviceMemType_t type = raw ? MCU_MEM : MCU_FLASH;
|
||||||
if (GetFromDevice(type, buffer, len, addr, NULL, 0, NULL, 1000, true)) {
|
if (GetFromDevice(type, buffer, len, addr, NULL, 0, NULL, 1000, true)) {
|
||||||
res = PM3_SUCCESS;
|
res = PM3_SUCCESS;
|
||||||
read = len; // GetFromDevice does not report the actual number of bytes received.
|
readlen = len; // GetFromDevice does not report the actual number of bytes received.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res == PM3_SUCCESS) {
|
if (res == PM3_SUCCESS) {
|
||||||
if (saveFile(filename, ".bin", buffer, read) != 0) {
|
res = saveFile(filename, ".bin", buffer, readlen);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
PrintAndLogEx(ERR, "error writing to file "_YELLOW_("%s"), filename);
|
PrintAndLogEx(ERR, "error writing to file "_YELLOW_("%s"), filename);
|
||||||
res = PM3_EFILE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
fail:
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1441,7 +1439,7 @@ int main(int argc, char *argv[]) {
|
||||||
MainGraphics();
|
MainGraphics();
|
||||||
# else
|
# else
|
||||||
// for *nix distro's, check environment variable to verify a display
|
// for *nix distro's, check environment variable to verify a display
|
||||||
char *display = getenv("DISPLAY");
|
const char *display = getenv("DISPLAY");
|
||||||
if (display && strlen(display) > 1) {
|
if (display && strlen(display) > 1) {
|
||||||
InitGraphics(argc, argv, script_cmds_file, script_cmd, stayInCommandLoop);
|
InitGraphics(argc, argv, script_cmds_file, script_cmd, stayInCommandLoop);
|
||||||
MainGraphics();
|
MainGraphics();
|
||||||
|
|
|
@ -64,7 +64,7 @@ const char *get_my_executable_path(void);
|
||||||
const char *get_my_executable_directory(void);
|
const char *get_my_executable_directory(void);
|
||||||
const char *get_my_user_directory(void);
|
const char *get_my_user_directory(void);
|
||||||
void pm3_init(void);
|
void pm3_init(void);
|
||||||
void main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop);
|
void main_loop(const char *script_cmds_file, char *script_cmd, bool stayInCommandLoop);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,14 +63,16 @@ int bf_generator_set_charset(generator_context_t *ctx, uint8_t charsets) {
|
||||||
int bf_generate(generator_context_t *ctx) {
|
int bf_generate(generator_context_t *ctx) {
|
||||||
|
|
||||||
switch (ctx->mode) {
|
switch (ctx->mode) {
|
||||||
case BF_MODE_RANGE:
|
case BF_MODE_RANGE: {
|
||||||
return _bf_generate_mode_range(ctx);
|
return _bf_generate_mode_range(ctx);
|
||||||
case BF_MODE_CHARSET:
|
}
|
||||||
|
case BF_MODE_CHARSET: {
|
||||||
return _bf_generate_mode_charset(ctx);
|
return _bf_generate_mode_charset(ctx);
|
||||||
|
}
|
||||||
case BF_MODE_SMART:
|
case BF_MODE_SMART: {
|
||||||
return _bf_generate_mode_smart(ctx);
|
return _bf_generate_mode_smart(ctx);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return BF_GENERATOR_ERROR;
|
return BF_GENERATOR_ERROR;
|
||||||
}
|
}
|
||||||
|
@ -81,23 +83,27 @@ int bf_generate(generator_context_t *ctx) {
|
||||||
// returns -1 if incrementing reaches its end
|
// returns -1 if incrementing reaches its end
|
||||||
int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo) {
|
int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo) {
|
||||||
|
|
||||||
uint8_t prev_value;
|
|
||||||
|
|
||||||
// check if we reached max value already
|
// check if we reached max value already
|
||||||
uint8_t i;
|
uint8_t i;
|
||||||
for (i = 0; i < data_len; i++)
|
for (i = 0; i < data_len; i++) {
|
||||||
if (data[i] < modulo - 1)
|
if (data[i] < modulo - 1) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (i == data_len)
|
if (i == data_len) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
for (uint8_t pos = data_len - 1;; pos--) {
|
for (uint8_t pos = data_len - 1;; pos--) {
|
||||||
prev_value = ++data[pos];
|
|
||||||
|
uint8_t prev_value = ++data[pos];
|
||||||
|
|
||||||
data[pos] = data[pos] % modulo;
|
data[pos] = data[pos] % modulo;
|
||||||
if (prev_value == data[pos])
|
|
||||||
|
if (prev_value == data[pos]) {
|
||||||
return 0;
|
return 0;
|
||||||
else if (pos == 0) {
|
} else if (pos == 0) {
|
||||||
// we cannot carryover to next byte
|
// we cannot carryover to next byte
|
||||||
// with the max value check in place before, we should not reach this place
|
// with the max value check in place before, we should not reach this place
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -108,12 +114,12 @@ int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// get current key casted to 32 bit
|
// get current key casted to 32 bit
|
||||||
uint32_t bf_get_key32(generator_context_t *ctx) {
|
uint32_t bf_get_key32(const generator_context_t *ctx) {
|
||||||
return ctx->current_key & 0xFFFFFFFF;
|
return ctx->current_key & 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get current key casted to 48 bit
|
// get current key casted to 48 bit
|
||||||
uint64_t bf_get_key48(generator_context_t *ctx) {
|
uint64_t bf_get_key48(const generator_context_t *ctx) {
|
||||||
return ctx->current_key & 0xFFFFFFFFFFFF;
|
return ctx->current_key & 0xFFFFFFFFFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,8 +133,9 @@ void bf_generator_clear(generator_context_t *ctx) {
|
||||||
|
|
||||||
int _bf_generate_mode_range(generator_context_t *ctx) {
|
int _bf_generate_mode_range(generator_context_t *ctx) {
|
||||||
|
|
||||||
if (ctx->key_length != BF_KEY_SIZE_32 && ctx->key_length != BF_KEY_SIZE_48)
|
if (ctx->key_length != BF_KEY_SIZE_32 && ctx->key_length != BF_KEY_SIZE_48) {
|
||||||
return BF_GENERATOR_ERROR;
|
return BF_GENERATOR_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->current_key >= ctx->range_high) {
|
if (ctx->current_key >= ctx->range_high) {
|
||||||
return BF_GENERATOR_END;
|
return BF_GENERATOR_END;
|
||||||
|
@ -152,8 +159,9 @@ int _bf_generate_mode_charset(generator_context_t *ctx) {
|
||||||
return BF_GENERATOR_ERROR;
|
return BF_GENERATOR_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->flag1)
|
if (ctx->flag1) {
|
||||||
return BF_GENERATOR_END;
|
return BF_GENERATOR_END;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t key_byte = 0;
|
uint8_t key_byte = 0;
|
||||||
ctx->current_key = 0;
|
ctx->current_key = 0;
|
||||||
|
@ -162,43 +170,47 @@ int _bf_generate_mode_charset(generator_context_t *ctx) {
|
||||||
ctx->current_key |= (uint64_t) ctx->charset[ctx->pos[key_byte]] << ((ctx->key_length - key_byte - 1) * 8);
|
ctx->current_key |= (uint64_t) ctx->charset[ctx->pos[key_byte]] << ((ctx->key_length - key_byte - 1) * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bf_array_increment(ctx->pos, ctx->key_length, ctx->charset_length) == -1)
|
if (bf_array_increment(ctx->pos, ctx->key_length, ctx->charset_length) == -1) {
|
||||||
// set flag1 to emit value last time and end generation on next call
|
// set flag1 to emit value last time and end generation on next call
|
||||||
ctx->flag1 = true;
|
ctx->flag1 = true;
|
||||||
|
}
|
||||||
|
|
||||||
return BF_GENERATOR_NEXT;
|
return BF_GENERATOR_NEXT;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _bf_generate_mode_smart(generator_context_t *ctx) {
|
int _bf_generate_mode_smart(generator_context_t *ctx) {
|
||||||
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
if (smart_generators[ctx->smart_mode_stage] == NULL)
|
if (smart_generators[ctx->smart_mode_stage] == NULL) {
|
||||||
return BF_GENERATOR_END;
|
return BF_GENERATOR_END;
|
||||||
|
}
|
||||||
|
|
||||||
ret = smart_generators[ctx->smart_mode_stage](ctx);
|
int ret = smart_generators[ctx->smart_mode_stage](ctx);
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case BF_GENERATOR_NEXT:
|
case BF_GENERATOR_NEXT: {
|
||||||
return ret;
|
return ret;
|
||||||
case BF_GENERATOR_ERROR:
|
}
|
||||||
|
case BF_GENERATOR_ERROR: {
|
||||||
return ret;
|
return ret;
|
||||||
case BF_GENERATOR_END:
|
}
|
||||||
|
case BF_GENERATOR_END: {
|
||||||
ctx->smart_mode_stage++;
|
ctx->smart_mode_stage++;
|
||||||
bf_generator_clear(ctx);
|
bf_generator_clear(ctx);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int smart_generator_byte_repeat(generator_context_t *ctx) {
|
int smart_generator_byte_repeat(generator_context_t *ctx) {
|
||||||
// key consists of repeated single byte
|
// key consists of repeated single byte
|
||||||
uint32_t current_byte = ctx->counter1;
|
uint32_t current_byte = ctx->counter1;
|
||||||
|
|
||||||
if (current_byte > 0xFF)
|
if (current_byte > 0xFF) {
|
||||||
return BF_GENERATOR_END;
|
return BF_GENERATOR_END;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->current_key = 0;
|
ctx->current_key = 0;
|
||||||
|
|
||||||
|
@ -213,8 +225,9 @@ int smart_generator_msb_byte_only(generator_context_t *ctx) {
|
||||||
// key of one byte (most significant one) and all others being zero
|
// key of one byte (most significant one) and all others being zero
|
||||||
uint32_t current_byte = ctx->counter1;
|
uint32_t current_byte = ctx->counter1;
|
||||||
|
|
||||||
if (current_byte > 0xFF)
|
if (current_byte > 0xFF) {
|
||||||
return BF_GENERATOR_END;
|
return BF_GENERATOR_END;
|
||||||
|
}
|
||||||
|
|
||||||
ctx->current_key = (uint64_t)current_byte << ((ctx->key_length - 1) * 8);
|
ctx->current_key = (uint64_t)current_byte << ((ctx->key_length - 1) * 8);
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ typedef struct {
|
||||||
} generator_context_t;
|
} generator_context_t;
|
||||||
|
|
||||||
|
|
||||||
void bf_generator_init(generator_context_t *ctx, uint8_t mode, uint8_t key_size);
|
void bf_generator_init(generator_context_t *ctx, uint8_t mode, uint8_t key_length);
|
||||||
void bf_generator_clear(generator_context_t *ctx); // clear flags and counters used by generators
|
void bf_generator_clear(generator_context_t *ctx); // clear flags and counters used by generators
|
||||||
int bf_generator_set_charset(generator_context_t *ctx, uint8_t charsets);
|
int bf_generator_set_charset(generator_context_t *ctx, uint8_t charsets);
|
||||||
int bf_generate(generator_context_t *ctx);
|
int bf_generate(generator_context_t *ctx);
|
||||||
|
@ -87,8 +87,8 @@ int _bf_generate_mode_range(generator_context_t *ctx);
|
||||||
int _bf_generate_mode_charset(generator_context_t *ctx);
|
int _bf_generate_mode_charset(generator_context_t *ctx);
|
||||||
int _bf_generate_mode_smart(generator_context_t *ctx);
|
int _bf_generate_mode_smart(generator_context_t *ctx);
|
||||||
int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo);
|
int bf_array_increment(uint8_t *data, uint8_t data_len, uint8_t modulo);
|
||||||
uint32_t bf_get_key32(generator_context_t *ctx);
|
uint32_t bf_get_key32(const generator_context_t *ctx);
|
||||||
uint64_t bf_get_key48(generator_context_t *ctx);
|
uint64_t bf_get_key48(const generator_context_t *ctx);
|
||||||
|
|
||||||
// smart mode
|
// smart mode
|
||||||
typedef int (smart_generator_t)(generator_context_t *ctx);
|
typedef int (smart_generator_t)(generator_context_t *ctx);
|
||||||
|
|
|
@ -720,7 +720,7 @@
|
||||||
"-h, --help This help",
|
"-h, --help This help",
|
||||||
"--keep keep the current values of the markers",
|
"--keep keep the current values of the markers",
|
||||||
"-a <dec> yellow marker",
|
"-a <dec> yellow marker",
|
||||||
"-b <dec> pink marker",
|
"-b <dec> purple marker",
|
||||||
"-c <dec> orange marker",
|
"-c <dec> orange marker",
|
||||||
"-d <dec> blue marker"
|
"-d <dec> blue marker"
|
||||||
],
|
],
|
||||||
|
@ -740,6 +740,42 @@
|
||||||
],
|
],
|
||||||
"usage": "data shiftgraphzero [-h] -n <dec>"
|
"usage": "data shiftgraphzero [-h] -n <dec>"
|
||||||
},
|
},
|
||||||
|
"data test_ss32": {
|
||||||
|
"command": "data test_ss32",
|
||||||
|
"description": "Tests the implementation of Buffer Save States (32-bit buffer)",
|
||||||
|
"notes": [
|
||||||
|
"data test_ss32"
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help"
|
||||||
|
],
|
||||||
|
"usage": "data test_ss32 [-h]"
|
||||||
|
},
|
||||||
|
"data test_ss32s": {
|
||||||
|
"command": "data test_ss32s",
|
||||||
|
"description": "Tests the implementation of Buffer Save States (32-bit signed buffer)",
|
||||||
|
"notes": [
|
||||||
|
"data test_ss32s"
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help"
|
||||||
|
],
|
||||||
|
"usage": "data test_ss32s [-h]"
|
||||||
|
},
|
||||||
|
"data test_ss8": {
|
||||||
|
"command": "data test_ss8",
|
||||||
|
"description": "Tests the implementation of Buffer Save States (8-bit buffer)",
|
||||||
|
"notes": [
|
||||||
|
"data test_ss8"
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help"
|
||||||
|
],
|
||||||
|
"usage": "data test_ss8 [-h]"
|
||||||
|
},
|
||||||
"data timescale": {
|
"data timescale": {
|
||||||
"command": "data timescale",
|
"command": "data timescale",
|
||||||
"description": "Set cursor display timescale. Setting the timescale makes the differential `dt` reading between the yellow and purple markers meaningful. once the timescale is set, the differential reading between brackets can become a time duration.",
|
"description": "Set cursor display timescale. Setting the timescale makes the differential `dt` reading between the yellow and purple markers meaningful. once the timescale is set, the differential reading between brackets can become a time duration.",
|
||||||
|
@ -1386,6 +1422,18 @@
|
||||||
],
|
],
|
||||||
"usage": "hf 14b apdu [-hskte] [--decode] [-m <hex>] [-l <int>] -d <hex> [--timeout <dec>]"
|
"usage": "hf 14b apdu [-hskte] [--decode] [-m <hex>] [-l <int>] -d <hex> [--timeout <dec>]"
|
||||||
},
|
},
|
||||||
|
"hf 14b calypso": {
|
||||||
|
"command": "hf 14b calypso",
|
||||||
|
"description": "Reads out the contents of a ISO14443B Calypso card",
|
||||||
|
"notes": [
|
||||||
|
"hf 14b calypso"
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help"
|
||||||
|
],
|
||||||
|
"usage": "hf 14b calypso [-h]"
|
||||||
|
},
|
||||||
"hf 14b dump": {
|
"hf 14b dump": {
|
||||||
"command": "hf 14b dump",
|
"command": "hf 14b dump",
|
||||||
"description": "This command dumps the contents of a ISO-14443-B tag and save it to file Tries to autodetect cardtype, memory size defaults to SRI4K",
|
"description": "This command dumps the contents of a ISO-14443-B tag and save it to file Tries to autodetect cardtype, memory size defaults to SRI4K",
|
||||||
|
@ -1404,7 +1452,7 @@
|
||||||
},
|
},
|
||||||
"hf 14b help": {
|
"hf 14b help": {
|
||||||
"command": "hf 14b help",
|
"command": "hf 14b help",
|
||||||
"description": "--------- ----------------------- General ----------------------- help This help list List ISO-14443-B history --------- ----------------------- Operations ----------------------- view Display content from tag dump file valid SRIX4 checksum test --------------------------------------------------------------------------------------- hf 14b list available offline: yes Alias of `trace list -t 14b -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
|
"description": "--------- ----------------------- General ----------------------- help This help list List ISO-14443-B history --------- ----------------------- Operations ----------------------- view Display content from tag dump file valid SRIX4 checksum test --------- ------------------ Calypso / Mobib ------------------ --------------------------------------------------------------------------------------- hf 14b list available offline: yes Alias of `trace list -t 14b -c` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
|
||||||
"notes": [
|
"notes": [
|
||||||
"hf 14b list --frame -> show frame delay times",
|
"hf 14b list --frame -> show frame delay times",
|
||||||
"hf 14b list -1 -> use trace buffer"
|
"hf 14b list -1 -> use trace buffer"
|
||||||
|
@ -1437,6 +1485,18 @@
|
||||||
],
|
],
|
||||||
"usage": "hf 14b info [-hsv]"
|
"usage": "hf 14b info [-hsv]"
|
||||||
},
|
},
|
||||||
|
"hf 14b mobib": {
|
||||||
|
"command": "hf 14b mobib",
|
||||||
|
"description": "Reads out the contents of a ISO14443B Mobib card",
|
||||||
|
"notes": [
|
||||||
|
"hf 14b mobib"
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help"
|
||||||
|
],
|
||||||
|
"usage": "hf 14b mobib [-h]"
|
||||||
|
},
|
||||||
"hf 14b ndefread": {
|
"hf 14b ndefread": {
|
||||||
"command": "hf 14b ndefread",
|
"command": "hf 14b ndefread",
|
||||||
"description": "Print NFC Data Exchange Format (NDEF)",
|
"description": "Print NFC Data Exchange Format (NDEF)",
|
||||||
|
@ -1501,10 +1561,11 @@
|
||||||
"offline": false,
|
"offline": false,
|
||||||
"options": [
|
"options": [
|
||||||
"-h, --help This help",
|
"-h, --help This help",
|
||||||
|
"--plot show anticollision signal trace in plot window",
|
||||||
"-v, --verbose verbose output",
|
"-v, --verbose verbose output",
|
||||||
"-@ optional - continuous reader mode"
|
"-@ optional - continuous reader mode"
|
||||||
],
|
],
|
||||||
"usage": "hf 14b reader [-hv@]"
|
"usage": "hf 14b reader [-hv@] [--plot]"
|
||||||
},
|
},
|
||||||
"hf 14b restore": {
|
"hf 14b restore": {
|
||||||
"command": "hf 14b restore",
|
"command": "hf 14b restore",
|
||||||
|
@ -3102,7 +3163,7 @@
|
||||||
"description": "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag",
|
"description": "Checkkeys loads a dictionary text file with 8byte hex keys to test authenticating against a iClass tag",
|
||||||
"notes": [
|
"notes": [
|
||||||
"hf iclass chk -f iclass_default_keys.dic",
|
"hf iclass chk -f iclass_default_keys.dic",
|
||||||
"hf iclass chk -f iclass_default_keys.dic --elite"
|
"hf iclass chk -f iclass_elite_keys.dic --elite"
|
||||||
],
|
],
|
||||||
"offline": false,
|
"offline": false,
|
||||||
"options": [
|
"options": [
|
||||||
|
@ -8925,7 +8986,8 @@
|
||||||
"description": "Authenticate against an EM4x70 by sending random number (RN) and F(RN) If F(RN) is incorrect based on the tag key, the tag will not respond If F(RN) is correct based on the tag key, the tag will give a 20-bit response",
|
"description": "Authenticate against an EM4x70 by sending random number (RN) and F(RN) If F(RN) is incorrect based on the tag key, the tag will not respond If F(RN) is correct based on the tag key, the tag will give a 20-bit response",
|
||||||
"notes": [
|
"notes": [
|
||||||
"lf em 4x70 auth --rnd 45F54ADA252AAC --frn 4866BB70 -> (using pm3 test key)",
|
"lf em 4x70 auth --rnd 45F54ADA252AAC --frn 4866BB70 -> (using pm3 test key)",
|
||||||
"lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0 -> (using research paper key)"
|
"lf em 4x70 auth --rnd 3FFE1FB6CC513F --frn F355F1A0 -> (using research paper key)",
|
||||||
|
"lf em 4x70 auth --rnd 7D5167003571F8 --frn 982DBCC0 -> (autorecovery test key)"
|
||||||
],
|
],
|
||||||
"offline": false,
|
"offline": false,
|
||||||
"options": [
|
"options": [
|
||||||
|
@ -8941,7 +9003,8 @@
|
||||||
"description": "This command will perform automatic recovery of the key from a writable tag. All steps are possible to do manually. The corresponding sequence, if done manually, is as follows: 1. Verify passed parameters authenticate with the tag (safety check) lf em 4x70 auth --rnd <rnd_1> --frn <frn_1> 2. Brute force the key bits in block 9 lf em 4x70 write -b 9 -d 0000 lf em 4x70 recover -b 9 --rnd <rnd_1> --frn <frn_1> lf em 4x70 write -b 9 -d <key_block_9> 3. Brute force the key bits in block 8 lf em 4x70 write -b 8 -d 0000 lf em 4x70 recover -b 8 --rnd <rnd_1> --frn <frn_1> lf em 4x70 write -b 8 -d <key_block_8> 4. Brute force the key bits in block 7 lf em 4x70 write -b 7 -d 0000) lf em 4x70 recover -b 7 --rnd <rnd_1> --frn <frn_1> lf em 4x70 write -b 7 -d <key_block_7> 5. Recover potential values of the lower 48 bits of the key lf em 4x70 recover --key <key_block_9><key_block_8><key_block_7> --rnd <rnd_1> --frn <frn_1> 6. Verify which potential key is actually on the tag (using a different rnd/frn combination) lf em 4x70 auth --rnd <rnd_2> --frn <frn_N> 7. Print the validated key This command simply requires the rnd/frn/grn from a single known-good authentication.",
|
"description": "This command will perform automatic recovery of the key from a writable tag. All steps are possible to do manually. The corresponding sequence, if done manually, is as follows: 1. Verify passed parameters authenticate with the tag (safety check) lf em 4x70 auth --rnd <rnd_1> --frn <frn_1> 2. Brute force the key bits in block 9 lf em 4x70 write -b 9 -d 0000 lf em 4x70 recover -b 9 --rnd <rnd_1> --frn <frn_1> lf em 4x70 write -b 9 -d <key_block_9> 3. Brute force the key bits in block 8 lf em 4x70 write -b 8 -d 0000 lf em 4x70 recover -b 8 --rnd <rnd_1> --frn <frn_1> lf em 4x70 write -b 8 -d <key_block_8> 4. Brute force the key bits in block 7 lf em 4x70 write -b 7 -d 0000) lf em 4x70 recover -b 7 --rnd <rnd_1> --frn <frn_1> lf em 4x70 write -b 7 -d <key_block_7> 5. Recover potential values of the lower 48 bits of the key lf em 4x70 recover --key <key_block_9><key_block_8><key_block_7> --rnd <rnd_1> --frn <frn_1> 6. Verify which potential key is actually on the tag (using a different rnd/frn combination) lf em 4x70 auth --rnd <rnd_2> --frn <frn_N> 7. Print the validated key This command simply requires the rnd/frn/grn from a single known-good authentication.",
|
||||||
"notes": [
|
"notes": [
|
||||||
"lf em 4x70 autorecover --rnd 45F54ADA252AAC --frn 4866BB70 --grn 9BD180 (pm3 test key)",
|
"lf em 4x70 autorecover --rnd 45F54ADA252AAC --frn 4866BB70 --grn 9BD180 (pm3 test key)",
|
||||||
"lf em 4x70 autorecover --rnd 3FFE1FB6CC513F --frn F355F1A0 --grn 609D60 (research paper key)"
|
"lf em 4x70 autorecover --rnd 3FFE1FB6CC513F --frn F355F1A0 --grn 609D60 (research paper key)",
|
||||||
|
"lf em 4x70 autorecover --rnd 7D5167003571F8 --frn 982DBCC0 --grn 36C0E0 (autorecovery test key)"
|
||||||
],
|
],
|
||||||
"offline": false,
|
"offline": false,
|
||||||
"options": [
|
"options": [
|
||||||
|
@ -9007,7 +9070,8 @@
|
||||||
"description": "Write new 96-bit key to tag",
|
"description": "Write new 96-bit key to tag",
|
||||||
"notes": [
|
"notes": [
|
||||||
"lf em 4x70 setkey -k F32AA98CF5BE4ADFA6D3480B (pm3 test key)",
|
"lf em 4x70 setkey -k F32AA98CF5BE4ADFA6D3480B (pm3 test key)",
|
||||||
"lf em 4x70 setkey -k A090A0A02080000000000000 (research paper key)"
|
"lf em 4x70 setkey -k A090A0A02080000000000000 (research paper key)",
|
||||||
|
"lf em 4x70 setkey -k 022A028C02BE000102030405 (autorecovery test key)"
|
||||||
],
|
],
|
||||||
"offline": false,
|
"offline": false,
|
||||||
"options": [
|
"options": [
|
||||||
|
@ -9443,6 +9507,19 @@
|
||||||
],
|
],
|
||||||
"usage": "lf hitag chk [-h] [-f <fn>] [--pwd] [--crypto]"
|
"usage": "lf hitag chk [-h] [-f <fn>] [--pwd] [--crypto]"
|
||||||
},
|
},
|
||||||
|
"lf hitag crack2": {
|
||||||
|
"command": "lf hitag crack2",
|
||||||
|
"description": "This command tries to recover 2048 bits of Hitag2 crypto stream data.",
|
||||||
|
"notes": [
|
||||||
|
"lf hitag crack2 --nrar 73AA5A62EAB8529C"
|
||||||
|
],
|
||||||
|
"offline": false,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help",
|
||||||
|
"--nrar <hex> specify nonce / answer as 8 hex bytes"
|
||||||
|
],
|
||||||
|
"usage": "lf hitag lookup [-h] [--nrar <hex>]"
|
||||||
|
},
|
||||||
"lf hitag dump": {
|
"lf hitag dump": {
|
||||||
"command": "lf hitag dump",
|
"command": "lf hitag dump",
|
||||||
"description": "Read all Hitag 2 card memory and save to file Crypto mode key format: ISK high + ISK low, 4F4E4D494B52 (ONMIKR) Password mode, default key 4D494B52 (MIKR)",
|
"description": "Read all Hitag 2 card memory and save to file Crypto mode key format: ISK high + ISK low, 4F4E4D494B52 (ONMIKR) Password mode, default key 4D494B52 (MIKR)",
|
||||||
|
@ -9497,7 +9574,7 @@
|
||||||
},
|
},
|
||||||
"lf hitag help": {
|
"lf hitag help": {
|
||||||
"command": "lf hitag help",
|
"command": "lf hitag help",
|
||||||
"description": "help This help list List Hitag trace history selftest Perform self test view Display content from tag dump file lookup Uses authentication trace to check for key in dictionary file --------------------------------------------------------------------------------------- lf hitag list available offline: yes Alias of `trace list -t hitag2` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
|
"description": "help This help list List Hitag trace history test Perform self tests view Display content from tag dump file lookup Uses authentication trace to check for key in dictionary file --------------------------------------------------------------------------------------- lf hitag list available offline: yes Alias of `trace list -t hitag2` with selected protocol data to annotate trace buffer You can load a trace from file (see `trace load -h`) or it be downloaded from device by default It accepts all other arguments of `trace list`. Note that some might not be relevant for this specific protocol",
|
||||||
"notes": [
|
"notes": [
|
||||||
"lf hitag list --frame -> show frame delay times",
|
"lf hitag list --frame -> show frame delay times",
|
||||||
"lf hitag list -1 -> use trace buffer"
|
"lf hitag list -1 -> use trace buffer"
|
||||||
|
@ -9576,18 +9653,6 @@
|
||||||
],
|
],
|
||||||
"usage": "lf hitag read [-hs2] [--pwd] [--nrar <hex>] [--crypto] [-k <hex>]"
|
"usage": "lf hitag read [-hs2] [--pwd] [--nrar <hex>] [--crypto] [-k <hex>]"
|
||||||
},
|
},
|
||||||
"lf hitag selftest": {
|
|
||||||
"command": "lf hitag selftest",
|
|
||||||
"description": "Perform selftest of Hitag crypto engine",
|
|
||||||
"notes": [
|
|
||||||
"lf hitag selftest"
|
|
||||||
],
|
|
||||||
"offline": true,
|
|
||||||
"options": [
|
|
||||||
"-h, --help This help"
|
|
||||||
],
|
|
||||||
"usage": "lf hitag selftest [-h]"
|
|
||||||
},
|
|
||||||
"lf hitag sim": {
|
"lf hitag sim": {
|
||||||
"command": "lf hitag sim",
|
"command": "lf hitag sim",
|
||||||
"description": "Simulate Hitag transponder You need to `lf hitag eload` first",
|
"description": "Simulate Hitag transponder You need to `lf hitag eload` first",
|
||||||
|
@ -9615,6 +9680,18 @@
|
||||||
],
|
],
|
||||||
"usage": "lf hitag sniff [-h]"
|
"usage": "lf hitag sniff [-h]"
|
||||||
},
|
},
|
||||||
|
"lf hitag test": {
|
||||||
|
"command": "lf hitag test",
|
||||||
|
"description": "Perform self tests of Hitag crypto engine",
|
||||||
|
"notes": [
|
||||||
|
"lf hitag test"
|
||||||
|
],
|
||||||
|
"offline": true,
|
||||||
|
"options": [
|
||||||
|
"-h, --help This help"
|
||||||
|
],
|
||||||
|
"usage": "lf hitag test [-h]"
|
||||||
|
},
|
||||||
"lf hitag view": {
|
"lf hitag view": {
|
||||||
"command": "lf hitag view",
|
"command": "lf hitag view",
|
||||||
"description": "Print a HITAG dump file (bin/eml/json)",
|
"description": "Print a HITAG dump file (bin/eml/json)",
|
||||||
|
@ -12622,8 +12699,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"commands_extracted": 729,
|
"commands_extracted": 735,
|
||||||
"extracted_by": "PM3Help2JSON v1.00",
|
"extracted_by": "PM3Help2JSON v1.00",
|
||||||
"extracted_on": "2024-04-22T14:35:02"
|
"extracted_on": "2024-05-14T08:02:41"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,9 @@ Check column "offline" for their availability.
|
||||||
|`data diff `|Y |`Diff of input files`
|
|`data diff `|Y |`Diff of input files`
|
||||||
|`data hexsamples `|N |`Dump big buffer as hex bytes`
|
|`data hexsamples `|N |`Dump big buffer as hex bytes`
|
||||||
|`data samples `|N |`Get raw samples for graph window ( GraphBuffer )`
|
|`data samples `|N |`Get raw samples for graph window ( GraphBuffer )`
|
||||||
|
|`data test_ss8 `|N |`Test the implementation of Buffer Save States (8-bit buffer)`
|
||||||
|
|`data test_ss32 `|N |`Test the implementation of Buffer Save States (32-bit buffer)`
|
||||||
|
|`data test_ss32s `|N |`Test the implementation of Buffer Save States (32-bit signed buffer)`
|
||||||
|
|
||||||
|
|
||||||
### emv
|
### emv
|
||||||
|
@ -221,6 +224,8 @@ Check column "offline" for their availability.
|
||||||
|`hf 14b wrbl `|N |`Write data to a SRI512/SRIX4 tag`
|
|`hf 14b wrbl `|N |`Write data to a SRI512/SRIX4 tag`
|
||||||
|`hf 14b view `|Y |`Display content from tag dump file`
|
|`hf 14b view `|Y |`Display content from tag dump file`
|
||||||
|`hf 14b valid `|Y |`SRIX4 checksum test`
|
|`hf 14b valid `|Y |`SRIX4 checksum test`
|
||||||
|
|`hf 14b calypso `|N |`Read contents of a Calypso card`
|
||||||
|
|`hf 14b mobib `|N |`Read contents of a Mobib card`
|
||||||
|
|
||||||
|
|
||||||
### hf 15
|
### hf 15
|
||||||
|
@ -1041,7 +1046,7 @@ Check column "offline" for their availability.
|
||||||
|`lf hitag help `|Y |`This help`
|
|`lf hitag help `|Y |`This help`
|
||||||
|`lf hitag list `|Y |`List Hitag trace history`
|
|`lf hitag list `|Y |`List Hitag trace history`
|
||||||
|`lf hitag info `|N |`Hitag 2 tag information`
|
|`lf hitag info `|N |`Hitag 2 tag information`
|
||||||
|`lf hitag selftest `|Y |`Perform self test`
|
|`lf hitag test `|Y |`Perform self tests`
|
||||||
|`lf hitag dump `|N |`Dump Hitag 2 tag`
|
|`lf hitag dump `|N |`Dump Hitag 2 tag`
|
||||||
|`lf hitag read `|N |`Read Hitag memory`
|
|`lf hitag read `|N |`Read Hitag memory`
|
||||||
|`lf hitag sniff `|N |`Eavesdrop Hitag communication`
|
|`lf hitag sniff `|N |`Eavesdrop Hitag communication`
|
||||||
|
@ -1051,6 +1056,7 @@ Check column "offline" for their availability.
|
||||||
|`lf hitag eview `|N |`View emulator memory`
|
|`lf hitag eview `|N |`View emulator memory`
|
||||||
|`lf hitag sim `|N |`Simulate Hitag transponder`
|
|`lf hitag sim `|N |`Simulate Hitag transponder`
|
||||||
|`lf hitag cc `|N |`Hitag S: test all provided challenges`
|
|`lf hitag cc `|N |`Hitag S: test all provided challenges`
|
||||||
|
|`lf hitag crack2 `|N |`Recover 2048bits of crypto stream`
|
||||||
|`lf hitag chk `|N |`Check keys`
|
|`lf hitag chk `|N |`Check keys`
|
||||||
|`lf hitag lookup `|Y |`Uses authentication trace to check for key in dictionary file`
|
|`lf hitag lookup `|Y |`Uses authentication trace to check for key in dictionary file`
|
||||||
|`lf hitag ta `|N |`Hitag 2: test all recorded authentications`
|
|`lf hitag ta `|N |`Hitag 2: test all recorded authentications`
|
||||||
|
|
|
@ -51,6 +51,7 @@ Useful docs:
|
||||||
* [ULtra](#ultra)
|
* [ULtra](#ultra)
|
||||||
* [UL-5](#ul-5)
|
* [UL-5](#ul-5)
|
||||||
* [UL, other chips](#ul-other-chips)
|
* [UL, other chips](#ul-other-chips)
|
||||||
|
* [MIFARE Ultralight USCUID-UL](#mifare-ultralight-uscuid-ul)
|
||||||
* [NTAG](#ntag)
|
* [NTAG](#ntag)
|
||||||
* [NTAG213 DirectWrite](#ntag213-directwrite)
|
* [NTAG213 DirectWrite](#ntag213-directwrite)
|
||||||
* [NTAG21x](#ntag21x)
|
* [NTAG21x](#ntag21x)
|
||||||
|
@ -823,7 +824,7 @@ hf 14a raw -s -c 90FD111100
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
|
||||||
TLDR: These magic cards have a 16 byte long configuration page, which usually starts with 0x85.
|
TLDR: These magic cards have a 16 byte long configuration page, which usually starts with 0x85.
|
||||||
All of the known tags using this, except for Ultralight tags, are listed here.
|
All of the known tags are using this, except for Ultralight tags, are listed here.
|
||||||
|
|
||||||
You cannot turn a Classic tag into an Ultralight and vice-versa!
|
You cannot turn a Classic tag into an Ultralight and vice-versa!
|
||||||
|
|
||||||
|
@ -1142,8 +1143,6 @@ All commands are available before sealing. After the sealing acts as a Mifare Cl
|
||||||
* Magic wakeup: `40(7)`, `43`
|
* Magic wakeup: `40(7)`, `43`
|
||||||
* Backdoor read main block: `30xx+crc`
|
* Backdoor read main block: `30xx+crc`
|
||||||
* Backdoor write main block: `A0xx+crc`, `[16 bytes data]+crc`
|
* Backdoor write main block: `A0xx+crc`, `[16 bytes data]+crc`
|
||||||
* Read hidden block: `38xx+crc`
|
|
||||||
* Write hidden block: `A8xx+crc`, `[16 bytes data]+crc`
|
|
||||||
* Read configuration: `E000+crc`
|
* Read configuration: `E000+crc`
|
||||||
* Write configuration: `E100+crc`
|
* Write configuration: `E100+crc`
|
||||||
* Example of the sealing, performed by Chinese copiers in raw commands:
|
* Example of the sealing, performed by Chinese copiers in raw commands:
|
||||||
|
@ -1607,7 +1606,7 @@ hf 14a info
|
||||||
[+] Magic capabilities : Gen 2 / CUID
|
[+] Magic capabilities : Gen 2 / CUID
|
||||||
```
|
```
|
||||||
|
|
||||||
It seems so far that all MFUL DW have an ATS.
|
It seems so far that all MFUL DW have an ATS response in factory configuration.
|
||||||
|
|
||||||
### Magic commands
|
### Magic commands
|
||||||
|
|
||||||
|
@ -1638,14 +1637,6 @@ Issue three regular MFU write commands in a row to write first three blocks.
|
||||||
* ATS: 0A78008102DBA0C119402AB5
|
* ATS: 0A78008102DBA0C119402AB5
|
||||||
* Anticol shortcut (CL1/3000): fails
|
* Anticol shortcut (CL1/3000): fails
|
||||||
|
|
||||||
#### MIFARE Ultralight DirectWrite flavour 2
|
|
||||||
|
|
||||||
^[Top](#top)
|
|
||||||
|
|
||||||
* BCC: play blindly the block0 BCC0 and block2 BCC1 bytes, beware!
|
|
||||||
* ATS: 850000A00A000AB00000000000000000184D
|
|
||||||
* Anticol shortcut (CL1/3000): succeeds
|
|
||||||
|
|
||||||
### Proxmark3 commands
|
### Proxmark3 commands
|
||||||
|
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
@ -1977,6 +1968,186 @@ The manufacturer confirmed unpersonalized tags could be identified by first 3 by
|
||||||
|
|
||||||
UL-X, UL-Z - ?
|
UL-X, UL-Z - ?
|
||||||
|
|
||||||
|
## MIFARE Ultralight USCUID-UL
|
||||||
|
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
TLDR: These magic cards, like the MFC USCUIDs have a 16 byte long configuration page, comprised of 4 blocks of 4 bytes each. This usually starts with 0x85. All of the known tags use the same format config page.
|
||||||
|
|
||||||
|
The cards will respond to a RATS with the config page in the factory configuration.
|
||||||
|
|
||||||
|
As with the MFC USCUIDs, one cannot turn a Classic tag into an Ultralight and vice-versa!
|
||||||
|
|
||||||
|
### Characteristics
|
||||||
|
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
* UID: 7 bytes
|
||||||
|
* ATQA: always read from hidden block `F6`
|
||||||
|
* SAK: always read from hidden block `F6`
|
||||||
|
* BCC: read from blocks 0-1 per Ultralight specification
|
||||||
|
* ATS: These respond to an ATS request with the config page in factory mode.
|
||||||
|
|
||||||
|
### Identify
|
||||||
|
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
In factory config state:
|
||||||
|
|
||||||
|
```
|
||||||
|
hf 14a info
|
||||||
|
...
|
||||||
|
[=] -------------------------- ATS --------------------------
|
||||||
|
[!] ATS may be corrupted. Length of ATS (18 bytes incl. 2 Bytes CRC) doesn't match TL
|
||||||
|
[+] ATS: 85 00 85 A0 00 00 0A A5 00 04 04 02 01 00 0F 03 [ 07 00 ]
|
||||||
|
```
|
||||||
|
|
||||||
|
If config has been modified to not display config block as ATS response:
|
||||||
|
|
||||||
|
```
|
||||||
|
hf 14a raw -akb 7 40; hf 14a raw -k 43
|
||||||
|
|
||||||
|
OR (depending on the magic wakeup method set)
|
||||||
|
|
||||||
|
hf 14a raw -akb 7 20; hf 14a raw -k 23
|
||||||
|
|
||||||
|
THEN
|
||||||
|
|
||||||
|
hf 14a raw -c e100
|
||||||
|
[+] 85 00 85 A0 00 00 0A A5 00 04 04 02 01 00 0F 03 [ 07 00 ]
|
||||||
|
```
|
||||||
|
|
||||||
|
Possible tag wakeup mechanisms are:
|
||||||
|
|
||||||
|
* Gen1 Magic Wakeup
|
||||||
|
* Alt Magic Wakeup
|
||||||
|
|
||||||
|
### Magic commands
|
||||||
|
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
* Magic wakeup (A: 00): `40(7)`, `43`
|
||||||
|
* Magic wakeup (B: 85): `20(7)`, `23`
|
||||||
|
* Backdoor read main and hidden block: `30xx+crc`
|
||||||
|
* Backdoor write main and hidden block: `A2xx[4 bytes data]+crc`
|
||||||
|
* Read configuration: `E050+crc`
|
||||||
|
* Write configuration: `E2[offset*4, 1b][data, 4b]+crc`
|
||||||
|
|
||||||
|
* **DANGER**
|
||||||
|
* Set memory and config to 00 `F000+crc`
|
||||||
|
* Set memory and config to FF `F100+crc`
|
||||||
|
* Set memory and config to 55 (no 0A response) `F600+crc`
|
||||||
|
|
||||||
|
### USCUID-UL configuration guide
|
||||||
|
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
1. Configuration
|
||||||
|
|
||||||
|
```
|
||||||
|
0 1 2 3
|
||||||
|
850000A0 00000AC3 00040301 01000B03
|
||||||
|
^^ >> ??? Mystery ???
|
||||||
|
^^^^ >> Gen1a mode (works with bitflip)
|
||||||
|
^^ >> Magic wakeup command (00 for 40-43; 85 for 20-23)
|
||||||
|
^^ >> Config available using regular mode (ON: A0)
|
||||||
|
^^ >> Do not reply to 1B, making auth impossible
|
||||||
|
^^ >> Do not enforce OTP properties (ON: A0)
|
||||||
|
^^ >> Maximum memory configuration*
|
||||||
|
^^^^^^^^ ^^^^^^^^ >> Version info
|
||||||
|
|
||||||
|
* This isn't a customizable value - it's a preset. So far:
|
||||||
|
C3 = UL11
|
||||||
|
3C = UL21
|
||||||
|
00 = UL-C
|
||||||
|
A5 = NTAG 213
|
||||||
|
5A = NTAG 215
|
||||||
|
AA = NTAG 216
|
||||||
|
55 = Unknown IC w/ 238 pgs.
|
||||||
|
```
|
||||||
|
|
||||||
|
* Gen1a mode: Allow using custom wakeup commands, like real gen1a chip, to run backdoor commands, as well as some extras.
|
||||||
|
* Magic wakeup command: Use different wakeup commands for entering Gen1a mode. A) 00 - 40(7), 43; B) 85 - 20(7), 23.
|
||||||
|
* Config available using regular mode: If this option is turned on via A0, the tag will reply to RATS with the config block and the config block can be modified without doing a magic wakeup.
|
||||||
|
|
||||||
|
To write config:
|
||||||
|
|
||||||
|
You must send config info in E2 packets of 4 bytes each (format: `E2[offset*4, 1b][data, 4b]`), eg for a UL-11 tag:
|
||||||
|
|
||||||
|
```
|
||||||
|
hf 14a raw -sck E200850000A0; hf 14a raw -ck E20100000AC3; hf 14a raw -ck E20200040301; hf 14a raw -c E20301000B03
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Hidden blocks
|
||||||
|
|
||||||
|
```
|
||||||
|
F0: 00000000
|
||||||
|
^^^^^^^^ >> Unknown, usually always 00
|
||||||
|
|
||||||
|
F1: 00000000
|
||||||
|
^^^^^^^^ >> Unknown, usually always 00
|
||||||
|
|
||||||
|
F2: 000000BD
|
||||||
|
^^^^^^ >> Unknown, usually always 00
|
||||||
|
^^ >> Unknown, usually always BD, possible tearing counter value?
|
||||||
|
|
||||||
|
F3: 000000BD
|
||||||
|
^^^^^^ >> Unknown, usually always 00
|
||||||
|
^^ >> Unknown, usually always BD, possible tearing counter value?
|
||||||
|
|
||||||
|
F4: 000000BD
|
||||||
|
^^^^^^ >> Unknown, usually always 00
|
||||||
|
^^ >> Unknown, usually always BD, possible tearing counter value?
|
||||||
|
|
||||||
|
F5: 00000000
|
||||||
|
^^^^^^^^ >> Unknown, usually always 00
|
||||||
|
|
||||||
|
F6: 44000400
|
||||||
|
^^^^ >> ATQA in byte reverse order. 4400 = ATQA of 0044
|
||||||
|
^^ >> Unknown, usually always set to 04. Changing this value also has something to do with the SAK value in the next byte
|
||||||
|
^^ >> SAK, if previous byte set to 04
|
||||||
|
|
||||||
|
F7: 88AF0000
|
||||||
|
^^ >> First byte of UID BCC calculation, for Ultralight family is always 88 per the datasheet
|
||||||
|
^^ >> Unknown, usually always AF.
|
||||||
|
^^^^ >> Unknown, usually always 00
|
||||||
|
|
||||||
|
F8 - FF: xxxxxxxx >> signature
|
||||||
|
```
|
||||||
|
|
||||||
|
To read / write hidden blocks:
|
||||||
|
|
||||||
|
A config block beginning with `7AFF` must be set to enable a `40:43` / `20:23` magic wakeup. From limited testing, the `20:23` magic wakeup is not guaranteed to work, however the `40:43` wakeup works 100% of the time.
|
||||||
|
|
||||||
|
You must send config info in A2 packets of 4 bytes each (format: `A2[offset*4, 1b][data, 4b]`), eg for a UL-11 tag:
|
||||||
|
|
||||||
|
```
|
||||||
|
hf 14a raw -akb 7 40; hf 14a raw -k 43; hf 14a raw -ck A2F2000000BD; hf 14a raw -ck A2F3000000BD; hf 14a raw -ck A2F4000000BD; hf 14a raw -ck A2F644000400; hf 14a raw -c A2F888AF0000
|
||||||
|
```
|
||||||
|
|
||||||
|
### Proxmark3 commands
|
||||||
|
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
No implemented commands at time of writing
|
||||||
|
|
||||||
|
### libnfc commands
|
||||||
|
|
||||||
|
^[Top](#top)
|
||||||
|
|
||||||
|
No implemented commands at time of writing
|
||||||
|
|
||||||
|
### Variations
|
||||||
|
^[Top](#top)
|
||||||
|
| Factory configuration | Name |
|
||||||
|
| --- | --- |
|
||||||
|
| 850000A0 00000AC3 00040301 01000B03 | UL-11 |
|
||||||
|
| 850000A0 00000A3C 00040301 01000E03 | UL-21 |
|
||||||
|
| 850000A0 0A000A00 00000000 00000000 | UL-C |
|
||||||
|
| 850085A0 00000AA5 00040402 01000F03 | NTAG213 |
|
||||||
|
| 850000A0 00000A5A 00040402 01001103 | NTAG215 |
|
||||||
|
| 850000A0 00000AAA 00040402 01001303 | NTAG216 |
|
||||||
|
|
||||||
# DESFire
|
# DESFire
|
||||||
|
|
||||||
^[Top](#top)
|
^[Top](#top)
|
||||||
|
|
|
@ -222,6 +222,8 @@ static void *brute_thread(void *arguments) {
|
||||||
//make_key_borland_n(i, key, keylen);
|
//make_key_borland_n(i, key, keylen);
|
||||||
|
|
||||||
uint8_t iv[keylen << 1];
|
uint8_t iv[keylen << 1];
|
||||||
|
memset(iv, 0, sizeof(iv));
|
||||||
|
|
||||||
uint8_t dec_tag[16] = {0x00};
|
uint8_t dec_tag[16] = {0x00};
|
||||||
uint8_t dec_rdr[32] = {0x00};
|
uint8_t dec_rdr[32] = {0x00};
|
||||||
|
|
||||||
|
|
|
@ -166,7 +166,7 @@ static void pm3_staticnested(uint32_t uid, uint32_t nt1, uint32_t ks1, uint32_t
|
||||||
for (uint32_t k = 0; k < keycnt; k++) {
|
for (uint32_t k = 0; k < keycnt; k++) {
|
||||||
uint64_t key64 = 0;
|
uint64_t key64 = 0;
|
||||||
crypto1_get_lfsr(statelists[0].head.slhead + k, &key64);
|
crypto1_get_lfsr(statelists[0].head.slhead + k, &key64);
|
||||||
printf("[ %d ] " _GREEN_("%012" PRIx64) "\n", k + 1, key64);
|
printf("[ %u ] " _GREEN_("%012" PRIx64) "\n", k + 1, key64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -222,7 +222,7 @@ int main(int argc, char *const argv[]) {
|
||||||
if (key_count) {
|
if (key_count) {
|
||||||
printf("Ultra Static nested --> Found " _YELLOW_("%u") " key candidates\n", key_count);
|
printf("Ultra Static nested --> Found " _YELLOW_("%u") " key candidates\n", key_count);
|
||||||
for (uint32_t k = 0; k < key_count; k++) {
|
for (uint32_t k = 0; k < key_count; k++) {
|
||||||
printf("[ %d ] " _GREEN_("%012" PRIx64) "\n", k + 1, keys[k]);
|
printf("[ %u ] " _GREEN_("%012" PRIx64) "\n", k + 1, keys[k]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -420,6 +420,10 @@ while true; do
|
||||||
if ! CheckExecute "lf AWID test" "$CLIENTBIN -c 'data load -f traces/lf_AWID-15-259.pm3;lf search -1'" "AWID ID found"; then break; fi
|
if ! CheckExecute "lf AWID test" "$CLIENTBIN -c 'data load -f traces/lf_AWID-15-259.pm3;lf search -1'" "AWID ID found"; then break; fi
|
||||||
if ! CheckExecute "lf EM410x test" "$CLIENTBIN -c 'data load -f traces/lf_EM4102-1.pm3;lf search -1'" "EM410x ID found"; then break; fi
|
if ! CheckExecute "lf EM410x test" "$CLIENTBIN -c 'data load -f traces/lf_EM4102-1.pm3;lf search -1'" "EM410x ID found"; then break; fi
|
||||||
if ! CheckExecute "lf EM4x05 test" "$CLIENTBIN -c 'data load -f traces/lf_EM4x05.pm3;lf search -1'" "FDX-B ID found"; then break; fi
|
if ! CheckExecute "lf EM4x05 test" "$CLIENTBIN -c 'data load -f traces/lf_EM4x05.pm3;lf search -1'" "FDX-B ID found"; then break; fi
|
||||||
|
if ! CheckExecute "lf EM4x70 calc test" "$CLIENTBIN -c 'lf em 4x70 calc --key F32AA98CF5BE4ADFA6D3480B --rnd 45F54ADA252AAC'" "FRN: 4866BB70 GRN: 9BD180"; then break; fi
|
||||||
|
if ! CheckExecute "lf EM4x70 recover test 1/3" "$CLIENTBIN -c 'lf em 4x70 recover --key 022A028C02BE --rnd 7D5167003571F8 --frn 982DBCC0 --grn 36C0E0'" "022a028c02be000102030405"; then break; fi
|
||||||
|
if ! CheckExecute "lf EM4x70 recover test 2/3" "$CLIENTBIN -c 'lf em 4x70 recover --key 022A028C02BE --rnd 7D5167003571F8 --frn 982DBCC0 --grn 36C0E0'" "022a028c02be366866191b60"; then break; fi
|
||||||
|
if ! CheckExecute "lf EM4x70 recover test 3/3" "$CLIENTBIN -c 'lf em 4x70 recover --key 022A028C02BE --rnd 7D5167003571F8 --frn 982DBCC0 --grn 36C0E0'" "022a028c02bef1e352c2718d"; then break; fi
|
||||||
if ! CheckExecute "lf FDX-A FECAVA test" "$CLIENTBIN -c 'data load -f traces/lf_EM4305_fdxa_destron.pm3;lf search -1'" "FDX-A FECAVA Destron ID found"; then break; fi
|
if ! CheckExecute "lf FDX-A FECAVA test" "$CLIENTBIN -c 'data load -f traces/lf_EM4305_fdxa_destron.pm3;lf search -1'" "FDX-A FECAVA Destron ID found"; then break; fi
|
||||||
if ! CheckExecute "lf FDX-B test" "$CLIENTBIN -c 'data load -f traces/lf_HomeAgain1600.pm3;lf search -1'" "FDX-B ID found"; then break; fi
|
if ! CheckExecute "lf FDX-B test" "$CLIENTBIN -c 'data load -f traces/lf_HomeAgain1600.pm3;lf search -1'" "FDX-B ID found"; then break; fi
|
||||||
if ! CheckExecute "lf FDX/BioThermo test" "$CLIENTBIN -c 'data load -f traces/lf_FDXB_Bio-Thermo.pm3; lf fdxb demod'" "95.2 F / 35.1 C"; then break; fi
|
if ! CheckExecute "lf FDX/BioThermo test" "$CLIENTBIN -c 'data load -f traces/lf_FDXB_Bio-Thermo.pm3; lf fdxb demod'" "95.2 F / 35.1 C"; then break; fi
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue