mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-07-16 10:03:04 -07:00
this commit fixes #2244 #2246 #1596 #2101. Its kind of a big refactoring and I most likely broke something. With that said. Now: HF 15 commands now uses NG packets, hf 15 raw support -k keepfield on and -s select, hf 15 dump/rdbl/rdmulti should handle blocksizes of 4 or 8, the error messages are unified and error handling the same. Some understanding how add_option impacts response message from card. A more clear separation between PM3 flags and ISO15693 protocol flags.
This commit is contained in:
parent
224da75e7a
commit
8d0b41a911
11 changed files with 824 additions and 544 deletions
|
@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file.
|
|||
This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log...
|
||||
|
||||
## [unreleased][unreleased]
|
||||
- Changed `hf 15 findafi` - improved the params (@iceman1001)
|
||||
- Changed `hf 15 rdbl/rdmulti/dump` - should handle 4 vs 8 bytes block sizes in cards (@iceman1001)
|
||||
- Changed `hf 15 *` - all 15 commands now uses NG packets (@iceman1001)
|
||||
- Changed `hf 15 raw` - now supports "-k" keep field on and "-s" select (@iceman1001)
|
||||
- Changed `prefs set client.debug` - now also toggles the client side APDU logging (@iceman1001)
|
||||
- Changed `hf 14b sriwrbl` - now supports --force to override block checks. Thanks @gentilkiwi for the idea! (@iceman1001)
|
||||
- Changed `hf 14b sriwrbl` - now tries to verify the write (@iceman1001)
|
||||
|
|
|
@ -815,14 +815,21 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
bool off;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
if (payload->on && payload->off)
|
||||
if (payload->on && payload->off) {
|
||||
reply_ng(CMD_SET_TEAROFF, PM3_EINVARG, NULL, 0);
|
||||
if (payload->on)
|
||||
}
|
||||
|
||||
if (payload->on) {
|
||||
g_tearoff_enabled = true;
|
||||
if (payload->off)
|
||||
}
|
||||
|
||||
if (payload->off) {
|
||||
g_tearoff_enabled = false;
|
||||
if (payload->delay_us > 0)
|
||||
}
|
||||
|
||||
if (payload->delay_us > 0) {
|
||||
g_tearoff_delay_us = payload->delay_us;
|
||||
}
|
||||
reply_ng(CMD_SET_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
|
@ -1269,11 +1276,16 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_COMMAND: {
|
||||
DirectTag15693Command(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
|
||||
iso15_raw_cmd_t *payload = (iso15_raw_cmd_t *)packet->data.asBytes;
|
||||
SendRawCommand15693(payload);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_FINDAFI: {
|
||||
BruteforceIso15693Afi(packet->oldarg[0]);
|
||||
struct p {
|
||||
uint32_t flags;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
BruteforceIso15693Afi(payload->flags);
|
||||
break;
|
||||
}
|
||||
case CMD_HF_ISO15693_READER: {
|
||||
|
|
|
@ -1937,8 +1937,8 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
|
|||
*eof_time = start_time + 32 * ((8 * ts->max) - 4); // subtract the 4 padding bits after EOF
|
||||
LogTrace_ISO15693(send, sendlen, (start_time * 4), (*eof_time * 4), NULL, true);
|
||||
if (recv != NULL) {
|
||||
bool fsk = send[0] & ISO15_REQ_SUBCARRIER_TWO;
|
||||
bool recv_speed = send[0] & ISO15_REQ_DATARATE_HIGH;
|
||||
bool fsk = ((send[0] & ISO15_REQ_SUBCARRIER_TWO) == ISO15_REQ_SUBCARRIER_TWO);
|
||||
bool recv_speed = ((send[0] & ISO15_REQ_DATARATE_HIGH) == ISO15_REQ_DATARATE_HIGH);
|
||||
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time, fsk, recv_speed, resp_len);
|
||||
}
|
||||
return res;
|
||||
|
@ -2087,7 +2087,7 @@ void ReaderIso15693(iso15_card_select_t *p_card) {
|
|||
reply_ng(CMD_HF_ISO15693_READER, PM3_SUCCESS, uid, sizeof(uid));
|
||||
|
||||
if (g_dbglevel >= DBG_EXTENDED) {
|
||||
Dbprintf("[+] %d octets read from IDENTIFY request:", recvlen);
|
||||
Dbprintf("[+] %d bytes read from IDENTIFY request:", recvlen);
|
||||
DbdecodeIso15693Answer(recvlen, answer);
|
||||
Dbhexdump(recvlen, answer, true);
|
||||
}
|
||||
|
@ -2360,16 +2360,20 @@ void SimTagIso15693(uint8_t *uid, uint8_t block_size) {
|
|||
|
||||
// Since there is no standardized way of reading the AFI out of a tag, we will brute force it
|
||||
// (some manufactures offer a way to read the AFI, though)
|
||||
void BruteforceIso15693Afi(uint32_t speed) {
|
||||
void BruteforceIso15693Afi(uint32_t flags) {
|
||||
|
||||
clear_trace();
|
||||
|
||||
uint8_t data[7] = {0};
|
||||
uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH];
|
||||
Iso15693InitReader();
|
||||
|
||||
bool speed = ((flags & ISO15_HIGH_SPEED) == ISO15_HIGH_SPEED);
|
||||
|
||||
// first without AFI
|
||||
// Tags should respond without AFI and with AFI=0 even when AFI is active
|
||||
uint8_t data[7] = {0};
|
||||
uint8_t recv[ISO15693_MAX_RESPONSE_LENGTH] = {0};
|
||||
|
||||
data[0] = ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1;
|
||||
data[0] = (ISO15_REQ_SUBCARRIER_SINGLE | ISO15_REQ_DATARATE_HIGH | ISO15_REQ_INVENTORY | ISO15_REQINV_SLOT1);
|
||||
data[1] = ISO15693_INVENTORY;
|
||||
data[2] = 0; // AFI
|
||||
AddCrc15(data, 3);
|
||||
|
@ -2434,16 +2438,26 @@ void BruteforceIso15693Afi(uint32_t speed) {
|
|||
|
||||
// Allows to directly send commands to the tag via the client
|
||||
// OBS: doesn't turn off rf field afterwards.
|
||||
void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data) {
|
||||
void SendRawCommand15693(iso15_raw_cmd_t *packet) {
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
||||
uint16_t timeout;
|
||||
uint32_t eof_time = 0;
|
||||
bool request_answer = false;
|
||||
uint16_t timeout = ISO15693_READER_TIMEOUT;
|
||||
if ((packet->flags & ISO15_LONG_WAIT) == ISO15_LONG_WAIT) {
|
||||
timeout = ISO15693_READER_TIMEOUT_WRITE;
|
||||
}
|
||||
|
||||
switch (data[1]) {
|
||||
bool speed = ((packet->flags & ISO15_HIGH_SPEED) == ISO15_HIGH_SPEED);
|
||||
bool keep_field_on = ((packet->flags & ISO15_NO_DISCONNECT) == ISO15_NO_DISCONNECT);
|
||||
bool read_respone = ((packet->flags & ISO15_READ_RESPONSE) == ISO15_READ_RESPONSE);
|
||||
bool init = ((packet->flags & ISO15_CONNECT) == ISO15_CONNECT);
|
||||
|
||||
// This isn't part of the RAW FLAGS from the client.
|
||||
// This is part of ISO15693 protocol definitions where the following commands needs to request option.
|
||||
bool request_answer = false;
|
||||
switch (packet->raw[1]) {
|
||||
case ISO15693_SET_PASSWORD:
|
||||
case ISO15693_ENABLE_PRIVACY:
|
||||
case ISO15693_WRITEBLOCK:
|
||||
case ISO15693_LOCKBLOCK:
|
||||
case ISO15693_WRITE_MULTI_BLOCK:
|
||||
|
@ -2453,42 +2467,50 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
|
|||
case ISO15693_WRITE_PASSWORD:
|
||||
case ISO15693_PASSWORD_PROTECT_EAS:
|
||||
case ISO15693_LOCK_DSFID:
|
||||
timeout = ISO15693_READER_TIMEOUT_WRITE;
|
||||
request_answer = data[0] & ISO15_REQ_OPTION;
|
||||
request_answer = ((packet->raw[0] & ISO15_REQ_OPTION) == ISO15_REQ_OPTION);
|
||||
break;
|
||||
default:
|
||||
timeout = ISO15693_READER_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t eof_time = 0;
|
||||
uint32_t start_time = 0;
|
||||
uint16_t recvlen = 0;
|
||||
int res = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time, &recvlen);
|
||||
|
||||
uint8_t buf[ISO15693_MAX_RESPONSE_LENGTH] = {0x00};
|
||||
|
||||
int res = SendDataTag(packet->raw, packet->rawlen, init, speed, (read_respone ? buf : NULL), sizeof(buf), start_time, timeout, &eof_time, &recvlen);
|
||||
|
||||
if (res == PM3_ETEAROFF) { // tearoff occurred
|
||||
reply_ng(CMD_HF_ISO15693_COMMAND, res, NULL, 0);
|
||||
} else {
|
||||
|
||||
bool fsk = data[0] & ISO15_REQ_SUBCARRIER_TWO;
|
||||
bool recv_speed = data[0] & ISO15_REQ_DATARATE_HIGH;
|
||||
// looking at the first byte of the RAW bytes to determine Subcarrier, datarate, request option
|
||||
bool fsk = packet->raw[0] & ISO15_REQ_SUBCARRIER_TWO;
|
||||
bool recv_speed = packet->raw[0] & ISO15_REQ_DATARATE_HIGH;
|
||||
|
||||
// send a single EOF to get the tag response
|
||||
if (request_answer) {
|
||||
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
|
||||
res = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time, fsk, recv_speed, &recvlen);
|
||||
res = SendDataTagEOF((read_respone ? buf : NULL), sizeof(buf), start_time, ISO15693_READER_TIMEOUT, &eof_time, fsk, recv_speed, &recvlen);
|
||||
}
|
||||
|
||||
if (recv) {
|
||||
if (read_respone) {
|
||||
recvlen = MIN(recvlen, ISO15693_MAX_RESPONSE_LENGTH);
|
||||
reply_ng(CMD_HF_ISO15693_COMMAND, res, recvbuf, recvlen);
|
||||
reply_ng(CMD_HF_ISO15693_COMMAND, res, buf, recvlen);
|
||||
} else {
|
||||
reply_ng(CMD_HF_ISO15693_COMMAND, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway
|
||||
// also prevents hf 15 raw -k keep_field on ...
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
|
||||
if (keep_field_on == false) {
|
||||
switch_off(); // disconnect raw
|
||||
SpinDelay(20);
|
||||
}
|
||||
|
||||
LED_A_OFF();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -48,8 +48,8 @@ void AcquireRawAdcSamplesIso15693(void);
|
|||
void ReaderIso15693(iso15_card_select_t *p_card); // ISO15693 reader
|
||||
void EmlClearIso15693(void);
|
||||
void SimTagIso15693(uint8_t *uid, uint8_t block_size); // simulate an ISO15693 tag
|
||||
void BruteforceIso15693Afi(uint32_t speed); // find an AFI of a tag
|
||||
void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint8_t *data); // send arbitrary commands from CLI
|
||||
void BruteforceIso15693Afi(uint32_t flags); // find an AFI of a tag
|
||||
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);
|
||||
|
||||
|
|
1120
client/src/cmdhf15.c
1120
client/src/cmdhf15.c
File diff suppressed because it is too large
Load diff
|
@ -263,28 +263,32 @@ static const char *felica_model_name(uint8_t rom_type, uint8_t ic_type) {
|
|||
* @param verbose prints out the response received.
|
||||
*/
|
||||
static bool waitCmdFelica(uint8_t iSelect, PacketResponseNG *resp, bool verbose) {
|
||||
if (WaitForResponseTimeout(CMD_ACK, resp, 2000)) {
|
||||
if (WaitForResponseTimeout(CMD_ACK, resp, 2000) == false) {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t len = iSelect ? (resp->oldarg[1] & 0xffff) : (resp->oldarg[0] & 0xffff);
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "client received %i octets", len);
|
||||
|
||||
if (len == 0 || len == 1) {
|
||||
PrintAndLogEx(ERR, "Could not receive data correctly!");
|
||||
return false;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex(resp->data.asBytes, len));
|
||||
if (!check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2)) {
|
||||
PrintAndLogEx(WARNING, "wrong or no CRC bytes");
|
||||
|
||||
PrintAndLogEx(SUCCESS, "(%u) %s", len, sprint_hex(resp->data.asBytes, len));
|
||||
|
||||
if (check_crc(CRC_FELICA, resp->data.asBytes + 2, len - 2) == false) {
|
||||
PrintAndLogEx(WARNING, "CRC ( " _RED_("fail") " )");
|
||||
}
|
||||
|
||||
if (resp->data.asBytes[0] != 0xB2 && resp->data.asBytes[1] != 0x4D) {
|
||||
PrintAndLogEx(ERR, "received incorrect frame format!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1690,7 +1690,7 @@ static int acquire_nonces(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_
|
|||
}
|
||||
|
||||
if (acquisition_completed) {
|
||||
field_off = true; // switch off field with next SendCommandOLD and then finish
|
||||
field_off = true; // switch off field with next SendCommandMIX and then finish
|
||||
}
|
||||
|
||||
if (initialize == false) {
|
||||
|
|
|
@ -44,10 +44,11 @@ static isodep_state_t isodep_state = ISODEP_INACTIVE;
|
|||
void SetISODEPState(isodep_state_t state) {
|
||||
isodep_state = state;
|
||||
if (APDULogging) {
|
||||
PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s"
|
||||
PrintAndLogEx(SUCCESS, "Setting ISODEP -> %s%s%s%s"
|
||||
, isodep_state == ISODEP_INACTIVE ? "inactive" : ""
|
||||
, isodep_state == ISODEP_NFCA ? _GREEN_("NFC-A") : ""
|
||||
, isodep_state == ISODEP_NFCB ? _GREEN_("NFC-B") : ""
|
||||
, isodep_state == ISODEP_NFCV ? _GREEN_("NFC-V") : ""
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -64,7 +65,6 @@ int Iso7816Connect(Iso7816CommandChannel channel) {
|
|||
// select with no disconnect and set frameLength
|
||||
int res = SelectCard14443A_4(false, false, NULL);
|
||||
if (res == PM3_SUCCESS) {
|
||||
SetISODEPState(ISODEP_NFCA);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,6 @@ int Iso7816Connect(Iso7816CommandChannel channel) {
|
|||
// If not 14a, try to 14b
|
||||
res = select_card_14443b_4(false, NULL);
|
||||
if (res == PM3_SUCCESS) {
|
||||
SetISODEPState(ISODEP_NFCB);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -110,8 +109,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
return 201;
|
||||
}
|
||||
|
||||
if (APDULogging)
|
||||
if (APDULogging) {
|
||||
PrintAndLogEx(SUCCESS, ">>>> %s", sprint_hex(data, datalen));
|
||||
}
|
||||
|
||||
int res = 0;
|
||||
|
||||
|
@ -125,6 +125,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
case ISODEP_NFCB:
|
||||
res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000);
|
||||
break;
|
||||
case ISODEP_NFCV:
|
||||
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
|
||||
break;
|
||||
case ISODEP_INACTIVE:
|
||||
if (activate_field == false) {
|
||||
PrintAndLogEx(FAILED, "Field currently inactive, cannot send an APDU");
|
||||
|
@ -133,11 +136,7 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
res = ExchangeAPDU14a(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len);
|
||||
if (res != PM3_SUCCESS) {
|
||||
res = exchange_14b_apdu(data, datalen, activate_field, leave_field_on, result, (int)max_result_len, (int *)result_len, 4000);
|
||||
if (res == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Testing ISO14443-B... ( " _GREEN_("ok") " )");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Testing ISO14443-B... ( " _RED_("fail") " )");
|
||||
}
|
||||
PrintAndLogEx(INFO, "Testing ISO14443-B... ( %s )", (res == PM3_SUCCESS) ? _GREEN_("ok") : _RED_("fail"));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -160,8 +159,9 @@ int Iso7816ExchangeEx(Iso7816CommandChannel channel, bool activate_field, bool l
|
|||
}
|
||||
}
|
||||
|
||||
if (APDULogging)
|
||||
if (APDULogging) {
|
||||
PrintAndLogEx(SUCCESS, "<<<< %s", sprint_hex(result, *result_len));
|
||||
}
|
||||
|
||||
if (*result_len < 2) {
|
||||
return 200;
|
||||
|
|
|
@ -30,6 +30,7 @@ typedef enum {
|
|||
ISODEP_INACTIVE = 0,
|
||||
ISODEP_NFCA,
|
||||
ISODEP_NFCB,
|
||||
ISODEP_NFCV,
|
||||
} isodep_state_t;
|
||||
|
||||
typedef enum {
|
||||
|
|
|
@ -202,17 +202,22 @@ void ResetSspClk(void) {
|
|||
AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;
|
||||
while (AT91C_BASE_TC2->TC_CV > 0);
|
||||
}
|
||||
|
||||
uint32_t RAMFUNC GetCountSspClk(void) {
|
||||
uint32_t tmp_count = (AT91C_BASE_TC2->TC_CV << 16) | AT91C_BASE_TC0->TC_CV;
|
||||
if ((tmp_count & 0x0000ffff) == 0) //small chance that we may have missed an increment in TC2
|
||||
|
||||
// small chance that we may have missed an increment in TC2
|
||||
if ((tmp_count & 0x0000ffff) == 0) {
|
||||
return (AT91C_BASE_TC2->TC_CV << 16);
|
||||
}
|
||||
return tmp_count;
|
||||
}
|
||||
|
||||
uint32_t RAMFUNC GetCountSspClkDelta(uint32_t start) {
|
||||
uint32_t stop = GetCountSspClk();
|
||||
if (stop >= start)
|
||||
if (stop >= start) {
|
||||
return stop - start;
|
||||
}
|
||||
return (UINT32_MAX - start) + stop;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,14 @@ typedef enum ISO15_COMMAND {
|
|||
ISO15_RAW = (1 << 2),
|
||||
ISO15_APPEND_CRC = (1 << 3),
|
||||
ISO15_HIGH_SPEED = (1 << 4),
|
||||
ISO15_READ_RESPONSE = (1 << 5)
|
||||
ISO15_READ_RESPONSE = (1 << 5),
|
||||
ISO15_LONG_WAIT = (1 << 6),
|
||||
} iso15_command_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t flags; // ISO15_COMMAND
|
||||
uint16_t rawlen;
|
||||
uint8_t raw[];
|
||||
} PACKED iso15_raw_cmd_t;
|
||||
|
||||
#endif // _ISO15_H_
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue