mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-19 21:03:48 -07:00
Merge pull request #2731 from jkramarz/feature/sam_picopass
support for HID SAM communication with Picopass cards
This commit is contained in:
commit
50b66a6fe5
13 changed files with 548 additions and 494 deletions
|
@ -2258,7 +2258,7 @@ static void PacketReceived(PacketCommandNG *packet) {
|
||||||
}
|
}
|
||||||
|
|
||||||
case CMD_HF_SAM_PICOPASS: {
|
case CMD_HF_SAM_PICOPASS: {
|
||||||
sam_picopass_get_pacs();
|
sam_picopass_get_pacs(packet);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CMD_HF_SAM_SEOS: {
|
case CMD_HF_SAM_SEOS: {
|
||||||
|
|
|
@ -371,3 +371,76 @@ void sam_send_ack(void) {
|
||||||
|
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copies the payload from an NFC buffer to a SAM buffer.
|
||||||
|
*
|
||||||
|
* Wraps received data from NFC into an ASN1 tree, so it can be transmitted to the SAM .
|
||||||
|
*
|
||||||
|
* @param sam_tx Pointer to the SAM transmit buffer.
|
||||||
|
* @param nfc_rx Pointer to the NFC receive buffer.
|
||||||
|
* @param nfc_len Length of the data to be copied from the NFC buffer.
|
||||||
|
*
|
||||||
|
* @return Length of SAM APDU to be sent.
|
||||||
|
*/
|
||||||
|
uint16_t sam_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t *nfc_rx, uint8_t nfc_len) {
|
||||||
|
// NFC resp:
|
||||||
|
// 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3
|
||||||
|
|
||||||
|
// SAM req:
|
||||||
|
// bd 1c
|
||||||
|
// a0 1a
|
||||||
|
// a0 18
|
||||||
|
// 80 12
|
||||||
|
// 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3
|
||||||
|
// 81 02
|
||||||
|
// 00 00
|
||||||
|
|
||||||
|
const uint8_t payload[] = {
|
||||||
|
0xbd, 4,
|
||||||
|
0xa0, 2,
|
||||||
|
0xa0, 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t tag81[] = {
|
||||||
|
0x00, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
memcpy(sam_tx, payload, sizeof(payload));
|
||||||
|
|
||||||
|
sam_append_asn1_node(sam_tx, sam_tx + 4, 0x80, nfc_rx, nfc_len);
|
||||||
|
sam_append_asn1_node(sam_tx, sam_tx + 4, 0x81, tag81, sizeof(tag81));
|
||||||
|
|
||||||
|
return sam_tx[1] + 2; // length of the ASN1 tree
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Copies the payload from the SAM receive buffer to the NFC transmit buffer.
|
||||||
|
*
|
||||||
|
* Unpacks data to be transmitted from ASN1 tree in APDU received from SAM.
|
||||||
|
*
|
||||||
|
* @param nfc_tx_buf Pointer to the buffer where the NFC transmit data will be stored.
|
||||||
|
* @param sam_rx_buf Pointer to the buffer containing the data received from the SAM.
|
||||||
|
* @return Length of NFC APDU to be sent.
|
||||||
|
*/
|
||||||
|
uint16_t sam_copy_payload_sam2nfc(uint8_t *nfc_tx_buf, uint8_t *sam_rx_buf) {
|
||||||
|
// SAM resp:
|
||||||
|
// c1 61 c1 00 00
|
||||||
|
// a1 10 <- nfc command
|
||||||
|
// a1 0e <- nfc send
|
||||||
|
// 80 10 <- data
|
||||||
|
// 00 a4 04 00 0a a0 00 00 04 40 00 01 01 00 01 00
|
||||||
|
// 81 02 <- protocol
|
||||||
|
// 00 04
|
||||||
|
// 82 02 <- timeout
|
||||||
|
// 01 F4
|
||||||
|
// 90 00
|
||||||
|
|
||||||
|
// NFC req:
|
||||||
|
// 0C 05 DE 64
|
||||||
|
|
||||||
|
// copy data out of c1->a1>->a1->80 node
|
||||||
|
uint16_t nfc_tx_len = (uint8_t) * (sam_rx_buf + 10);
|
||||||
|
memcpy(nfc_tx_buf, sam_rx_buf + 11, nfc_tx_len);
|
||||||
|
return nfc_tx_len;
|
||||||
|
}
|
|
@ -46,4 +46,7 @@ void sam_append_asn1_node(const uint8_t *root, const uint8_t *node, uint8_t type
|
||||||
|
|
||||||
void sam_send_ack(void);
|
void sam_send_ack(void);
|
||||||
|
|
||||||
|
uint16_t sam_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t *nfc_rx, uint8_t nfc_len);
|
||||||
|
uint16_t sam_copy_payload_sam2nfc(uint8_t *nfc_tx_buf, uint8_t *sam_rx_buf);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -30,6 +30,218 @@
|
||||||
#include "protocols.h"
|
#include "protocols.h"
|
||||||
#include "optimized_cipher.h"
|
#include "optimized_cipher.h"
|
||||||
#include "fpgaloader.h"
|
#include "fpgaloader.h"
|
||||||
|
#include "pm3_cmd.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sends a request to the SAM and retrieves the response.
|
||||||
|
*
|
||||||
|
* Unpacks request to the SAM and relays ISO15 traffic to the card.
|
||||||
|
* If no request data provided, sends a request to get PACS data.
|
||||||
|
*
|
||||||
|
* @param request Pointer to the buffer containing the request to be sent to the SAM.
|
||||||
|
* @param request_len Length of the request to be sent to the SAM.
|
||||||
|
* @param response Pointer to the buffer where the retreived data will be stored.
|
||||||
|
* @param response_len Pointer to the variable where the length of the retreived data will be stored.
|
||||||
|
* @return Status code indicating success or failure of the operation.
|
||||||
|
*/
|
||||||
|
static int sam_send_request_iso15(const uint8_t *const request, const uint8_t request_len, uint8_t *response, uint8_t *response_len, const bool shallow_mod, const bool break_on_nr_mac, const bool prevent_epurse_update) {
|
||||||
|
int res = PM3_SUCCESS;
|
||||||
|
if (g_dbglevel >= DBG_DEBUG)
|
||||||
|
DbpString("start sam_send_request_iso14a");
|
||||||
|
|
||||||
|
uint8_t * buf1 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||||
|
uint8_t * buf2 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||||
|
if(buf1 == NULL || buf2 == NULL){
|
||||||
|
res = PM3_EMALLOC;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *sam_tx_buf = buf1;
|
||||||
|
uint16_t sam_tx_len;
|
||||||
|
|
||||||
|
uint8_t *sam_rx_buf = buf2;
|
||||||
|
uint16_t sam_rx_len;
|
||||||
|
|
||||||
|
uint8_t *nfc_tx_buf = buf1;
|
||||||
|
uint16_t nfc_tx_len;
|
||||||
|
|
||||||
|
uint8_t *nfc_rx_buf = buf2;
|
||||||
|
uint16_t nfc_rx_len;
|
||||||
|
|
||||||
|
if (request_len > 0) {
|
||||||
|
sam_tx_len = request_len;
|
||||||
|
memcpy(sam_tx_buf, request, sam_tx_len);
|
||||||
|
} else {
|
||||||
|
// send get pacs
|
||||||
|
static const uint8_t payload[] = {
|
||||||
|
0xa0, 19, // <- SAM command
|
||||||
|
0xBE, 17, // <- samCommandGetContentElement2
|
||||||
|
0x80, 1,
|
||||||
|
0x04, // <- implicitFormatPhysicalAccessBits
|
||||||
|
0x84, 12,
|
||||||
|
0x2B, 0x06, 0x01, 0x04, 0x01, 0x81, 0xE4, 0x38, 0x01, 0x01, 0x02, 0x04 // <- SoRootOID
|
||||||
|
};
|
||||||
|
|
||||||
|
sam_tx_len = sizeof(payload);
|
||||||
|
memcpy(sam_tx_buf, payload, sam_tx_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
sam_send_payload(
|
||||||
|
0x44, 0x0a, 0x44,
|
||||||
|
sam_tx_buf, &sam_tx_len,
|
||||||
|
sam_rx_buf, &sam_rx_len
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sam_rx_buf[1] == 0x61) { // commands to be relayed to card starts with 0x61
|
||||||
|
switch_clock_to_countsspclk();
|
||||||
|
// tag <-> SAM exchange starts here
|
||||||
|
|
||||||
|
while (sam_rx_buf[1] == 0x61) {
|
||||||
|
uint32_t start_time = GetCountSspClk();
|
||||||
|
uint32_t eof_time = start_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
||||||
|
|
||||||
|
nfc_tx_len = sam_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf);
|
||||||
|
|
||||||
|
bool is_cmd_check = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_CHECK;
|
||||||
|
if(is_cmd_check && break_on_nr_mac){
|
||||||
|
memcpy(response, nfc_tx_buf, nfc_tx_len);
|
||||||
|
*response_len = nfc_tx_len;
|
||||||
|
if (g_dbglevel >= DBG_INFO) {
|
||||||
|
DbpString("NR-MAC: ");
|
||||||
|
Dbhexdump((*response_len)-1, response+1, false);
|
||||||
|
}
|
||||||
|
res = PM3_SUCCESS;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_cmd_update = (nfc_tx_buf[0] & 0x0F) == ICLASS_CMD_UPDATE;
|
||||||
|
if(is_cmd_update && prevent_epurse_update && nfc_tx_buf[0] == 0x87 && nfc_tx_buf[1] == 0x02){
|
||||||
|
// block update(2) command and fake the response to prevent update of epurse
|
||||||
|
|
||||||
|
// NFC TX BUFFERS PREPARED BY SAM LOOKS LIKE:
|
||||||
|
// 87 02 #1(C9 FD FF FF) #2(FF FF FF FF) F4 BF 98 E2
|
||||||
|
|
||||||
|
// NFC RX BUFFERS EXPECTED BY SAM WOULD LOOK LIKE:
|
||||||
|
// #2(FF FF FF FF) #1(C9 FD FF FF) 3A 47
|
||||||
|
|
||||||
|
memcpy(nfc_rx_buf+0, nfc_tx_buf+6, 4);
|
||||||
|
memcpy(nfc_rx_buf+4, nfc_tx_buf+0, 4);
|
||||||
|
AddCrc(nfc_rx_buf, 8);
|
||||||
|
nfc_rx_len = 10;
|
||||||
|
|
||||||
|
if (g_dbglevel >= DBG_INFO) {
|
||||||
|
DbpString("FAKE EPURSE UPDATE RESPONSE: ");
|
||||||
|
Dbhexdump(nfc_rx_len, nfc_rx_buf, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (g_dbglevel >= DBG_INFO) {
|
||||||
|
DbpString("ISO15 TAG REQUEST: ");
|
||||||
|
Dbhexdump(nfc_tx_len, nfc_tx_buf, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tries = 3;
|
||||||
|
nfc_rx_len = 0;
|
||||||
|
while (tries-- > 0) {
|
||||||
|
iclass_send_as_reader(nfc_tx_buf, nfc_tx_len, &start_time, &eof_time, shallow_mod);
|
||||||
|
uint16_t timeout = is_cmd_update ? ICLASS_READER_TIMEOUT_UPDATE : ICLASS_READER_TIMEOUT_ACTALL;
|
||||||
|
|
||||||
|
res = GetIso15693AnswerFromTag(nfc_rx_buf, ISO7816_MAX_FRAME, timeout, &eof_time, false, true, &nfc_rx_len);
|
||||||
|
if (res == PM3_SUCCESS && nfc_rx_len > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
start_time = eof_time + ((DELAY_ICLASS_VICC_TO_VCD_READER + DELAY_ISO15693_VCD_TO_VICC_READER + (8 * 8 * 8 * 16)) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (res != PM3_SUCCESS ) {
|
||||||
|
res = PM3_ECARDEXCHANGE;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_dbglevel >= DBG_INFO) {
|
||||||
|
DbpString("ISO15 TAG RESPONSE: ");
|
||||||
|
Dbhexdump(nfc_rx_len, nfc_rx_buf, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
switch_clock_to_ticks();
|
||||||
|
sam_tx_len = sam_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len);
|
||||||
|
|
||||||
|
sam_send_payload(
|
||||||
|
0x14, 0x0a, 0x14,
|
||||||
|
sam_tx_buf, &sam_tx_len,
|
||||||
|
sam_rx_buf, &sam_rx_len
|
||||||
|
);
|
||||||
|
|
||||||
|
// last SAM->TAG
|
||||||
|
// c1 61 c1 00 00 a1 02 >>82<< 00 90 00
|
||||||
|
if (sam_rx_buf[7] == 0x82) {
|
||||||
|
// tag <-> SAM exchange ends here
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_clock_to_countsspclk();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t hfack[] = {
|
||||||
|
0xbd, 0x04, 0xa0, 0x02, 0x82, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
sam_tx_len = sizeof(hfack);
|
||||||
|
memcpy(sam_tx_buf, hfack, sam_tx_len);
|
||||||
|
|
||||||
|
sam_send_payload(
|
||||||
|
0x14, 0x0a, 0x00,
|
||||||
|
sam_tx_buf, &sam_tx_len,
|
||||||
|
sam_rx_buf, &sam_rx_len
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// resp for SamCommandGetContentElement:
|
||||||
|
// c1 64 00 00 00
|
||||||
|
// bd 09
|
||||||
|
// 8a 07
|
||||||
|
// 03 05 <- include tag for pm3 client
|
||||||
|
// 06 85 80 6d c0 <- decoded PACS data
|
||||||
|
// 90 00
|
||||||
|
|
||||||
|
// resp for samCommandGetContentElement2:
|
||||||
|
// c1 64 00 00 00
|
||||||
|
// bd 1e
|
||||||
|
// b3 1c
|
||||||
|
// a0 1a
|
||||||
|
// 80 05
|
||||||
|
// 06 85 80 6d c0
|
||||||
|
// 81 0e
|
||||||
|
// 2b 06 01 04 01 81 e4 38 01 01 02 04 3c ff
|
||||||
|
// 82 01
|
||||||
|
// 07
|
||||||
|
// 90 00
|
||||||
|
if (request_len == 0) {
|
||||||
|
if (
|
||||||
|
!(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0x8a && sam_rx_buf[5 + 4] == 0x03)
|
||||||
|
&&
|
||||||
|
!(sam_rx_buf[5] == 0xbd && sam_rx_buf[5 + 2] == 0xb3 && sam_rx_buf[5 + 4] == 0xa0)
|
||||||
|
) {
|
||||||
|
if (g_dbglevel >= DBG_ERROR)
|
||||||
|
Dbprintf("No PACS data in SAM response");
|
||||||
|
res = PM3_ESOFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*response_len = sam_rx_buf[5 + 1] + 2;
|
||||||
|
memcpy(response, sam_rx_buf + 5, *response_len);
|
||||||
|
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
out:
|
||||||
|
BigBuf_free();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -41,7 +253,7 @@
|
||||||
* @param card_select Pointer to the descriptor of the detected card.
|
* @param card_select Pointer to the descriptor of the detected card.
|
||||||
* @return Status code indicating success or failure of the operation.
|
* @return Status code indicating success or failure of the operation.
|
||||||
*/
|
*/
|
||||||
static int sam_set_card_detected(picopass_hdr_t *card_select) {
|
static int sam_set_card_detected_picopass(picopass_hdr_t *card_select) {
|
||||||
int res = PM3_SUCCESS;
|
int res = PM3_SUCCESS;
|
||||||
if (g_dbglevel >= DBG_DEBUG)
|
if (g_dbglevel >= DBG_DEBUG)
|
||||||
DbpString("start sam_set_card_detected");
|
DbpString("start sam_set_card_detected");
|
||||||
|
@ -107,366 +319,81 @@ out:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// using HID SAM to authenticate w PICOPASS
|
|
||||||
int sam_picopass_get_pacs(void) {
|
|
||||||
|
|
||||||
static uint8_t act_all[] = { ICLASS_CMD_ACTALL };
|
/**
|
||||||
static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 };
|
* @brief Retrieves PACS data from PICOPASS card using SAM.
|
||||||
static uint8_t read_conf[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x01, 0xfa, 0x22 };
|
*
|
||||||
uint8_t select[] = { 0x80 | ICLASS_CMD_SELECT, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
* This function is called by appmain.c
|
||||||
uint8_t read_aia[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x05, 0xde, 0x64};
|
* It sends a request to the SAM to get the PACS data from the PICOPASS card.
|
||||||
uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 };
|
* The PACS data is then returned to the PM3 client.
|
||||||
|
*
|
||||||
|
* @return Status code indicating success or failure of the operation.
|
||||||
|
*/
|
||||||
|
int sam_picopass_get_pacs(PacketCommandNG *c) {
|
||||||
|
const uint8_t flags = c->data.asBytes[0];
|
||||||
|
const bool disconnectAfter = !!(flags & BITMASK(0));
|
||||||
|
const bool skipDetect = !!(flags & BITMASK(1));
|
||||||
|
const bool breakOnNrMac = !!(flags & BITMASK(2));
|
||||||
|
const bool preventEpurseUpdate = !!(flags & BITMASK(3));
|
||||||
|
const bool shallow_mod = !!(flags & BITMASK(4));
|
||||||
|
|
||||||
picopass_hdr_t hdr = {0};
|
uint8_t *cmd = c->data.asBytes + 1;
|
||||||
// Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used
|
uint16_t cmd_len = c->length - 1;
|
||||||
// bit 7: parity.
|
|
||||||
// if (use_credit_key)
|
|
||||||
// read_check_cc[0] = 0x10 | ICLASS_CMD_READCHECK;
|
|
||||||
|
|
||||||
BigBuf_free_keep_EM();
|
int res = PM3_EFAILED;
|
||||||
|
|
||||||
clear_trace();
|
clear_trace();
|
||||||
|
|
||||||
I2C_Reset_EnterMainProgram();
|
I2C_Reset_EnterMainProgram();
|
||||||
StopTicks();
|
|
||||||
|
|
||||||
uint8_t *resp = BigBuf_calloc(ISO7816_MAX_FRAME);
|
set_tracing(true);
|
||||||
|
StartTicks();
|
||||||
|
|
||||||
bool shallow_mod = false;
|
// step 1: ping SAM
|
||||||
uint16_t resp_len = 0;
|
sam_get_version();
|
||||||
int res;
|
|
||||||
uint32_t eof_time = 0;
|
|
||||||
|
|
||||||
// wakeup
|
if (!skipDetect) {
|
||||||
Iso15693InitReader();
|
// step 2: get card information
|
||||||
|
picopass_hdr_t card_a_info;
|
||||||
|
uint32_t eof_time = 0;
|
||||||
|
|
||||||
uint32_t start_time = GetCountSspClk();
|
// implicit StartSspClk() happens here
|
||||||
iclass_send_as_reader(act_all, 1, &start_time, &eof_time, shallow_mod);
|
Iso15693InitReader();
|
||||||
|
if(!select_iclass_tag(&card_a_info, false, &eof_time, shallow_mod)){
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_ACTALL, &eof_time, false, true, &resp_len);
|
switch_clock_to_ticks();
|
||||||
|
|
||||||
|
// step 3: SamCommand CardDetected
|
||||||
|
sam_set_card_detected_picopass(&card_a_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// step 3: SamCommand RequestPACS, relay NFC communication
|
||||||
|
uint8_t sam_response[ISO7816_MAX_FRAME] = { 0x00 };
|
||||||
|
uint8_t sam_response_len = 0;
|
||||||
|
res = sam_send_request_iso15(cmd, cmd_len, sam_response, &sam_response_len, shallow_mod, breakOnNrMac, preventEpurseUpdate);
|
||||||
if (res != PM3_SUCCESS) {
|
if (res != PM3_SUCCESS) {
|
||||||
res = PM3_ECARDEXCHANGE;
|
goto err;
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
if (g_dbglevel >= DBG_INFO)
|
||||||
|
print_result("Response data", sam_response, sam_response_len);
|
||||||
|
|
||||||
// send Identify
|
goto out;
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
|
||||||
iclass_send_as_reader(identify, 1, &start_time, &eof_time, shallow_mod);
|
|
||||||
|
|
||||||
// expect a 10-byte response here, 8 byte anticollision-CSN and 2 byte CRC
|
|
||||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy the Anti-collision CSN to our select-packet
|
|
||||||
memcpy(&select[1], resp, 8);
|
|
||||||
|
|
||||||
// select the card
|
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
|
||||||
iclass_send_as_reader(select, sizeof(select), &start_time, &eof_time, shallow_mod);
|
|
||||||
|
|
||||||
// expect a 10-byte response here, 8 byte CSN and 2 byte CRC
|
|
||||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store CSN
|
|
||||||
memcpy(hdr.csn, resp, sizeof(hdr.csn));
|
|
||||||
|
|
||||||
// card selected, now read config (block1) (only 8 bytes no CRC)
|
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
|
||||||
iclass_send_as_reader(read_conf, sizeof(read_conf), &start_time, &eof_time, shallow_mod);
|
|
||||||
|
|
||||||
// expect a 8-byte response here
|
|
||||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store CONFIG
|
|
||||||
memcpy((uint8_t *)&hdr.conf, resp, sizeof(hdr.conf));
|
|
||||||
|
|
||||||
uint8_t pagemap = get_pagemap(&hdr);
|
|
||||||
if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) {
|
|
||||||
res = PM3_EWRONGANSWER;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read App Issuer Area block 5
|
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
|
||||||
iclass_send_as_reader(read_aia, sizeof(read_aia), &start_time, &eof_time, shallow_mod);
|
|
||||||
|
|
||||||
// expect a 10-byte response here
|
|
||||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store AIA
|
|
||||||
memcpy(hdr.app_issuer_area, resp, sizeof(hdr.app_issuer_area));
|
|
||||||
|
|
||||||
// card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC)
|
|
||||||
start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER;
|
|
||||||
iclass_send_as_reader(read_check_cc, sizeof(read_check_cc), &start_time, &eof_time, shallow_mod);
|
|
||||||
|
|
||||||
// expect a 8-byte response here
|
|
||||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
if (res != PM3_SUCCESS || resp_len != 8) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// store EPURSE
|
|
||||||
memcpy(hdr.epurse, resp, sizeof(hdr.epurse));
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// SAM comms
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
size_t sam_len = 0;
|
|
||||||
uint8_t *sam_apdu = BigBuf_calloc(ISO7816_MAX_FRAME);
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// first - set detected card (0xAD)
|
|
||||||
switch_clock_to_ticks();
|
|
||||||
sam_set_card_detected(&hdr);
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// second - get PACS (0xA1)
|
|
||||||
|
|
||||||
// a0 05
|
|
||||||
// a1 03
|
|
||||||
// 80 01
|
|
||||||
// 04
|
|
||||||
hexstr_to_byte_array("a005a103800104", sam_apdu, &sam_len);
|
|
||||||
if (sam_send_payload(0x44, 0x0a, 0x44, sam_apdu, (uint16_t *) &sam_len, resp, &resp_len) != PM3_SUCCESS) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
print_dbg("-- 2", resp, resp_len);
|
|
||||||
|
|
||||||
// TAG response
|
|
||||||
// -- 0c 05 de64 // read block 5
|
|
||||||
// Tag|c00a140a000000a110a10e8004 0c05de64 8102 0004 820201f4
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// third AIA block 5 (emulated tag <-> SAM exchange starts here)
|
|
||||||
// a0da02631c140a00000000bd14a012a010800a ffffff0006fffffff88e 81020000
|
|
||||||
// picopass legacy is fixed. wants AIA and crc. ff ff ff ff ff ff ff ff ea f5
|
|
||||||
// picpoasss SE ff ff ff 00 06 ff ff ff f8 8e
|
|
||||||
hexstr_to_byte_array("a0da02631c140a00000000bd14a012a010800affffff0006fffffff88e81020000", sam_apdu, &sam_len);
|
|
||||||
memcpy(sam_apdu + 19, hdr.app_issuer_area, sizeof(hdr.app_issuer_area));
|
|
||||||
AddCrc(sam_apdu + 19, 8);
|
|
||||||
|
|
||||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
print_dbg("-- 3", resp, resp_len);
|
|
||||||
|
|
||||||
// 88 02 -- readcheck (block2 epurse, start of auth)
|
|
||||||
// Tag|c00a140a000000a10ea10c8002 8802 8102 0004 820201f4 9000
|
|
||||||
// 61 16 f5 0a140a000000a10ea10c 8002 8802 8102 0004 820201f4 9000
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// forth EPURSE
|
|
||||||
// a0da02631a140a00000000bd12a010a00e8008 ffffffffedffffff 81020000
|
|
||||||
hexstr_to_byte_array("a0da02631a140a00000000bd12a010a00e8008ffffffffedffffff81020000", sam_apdu, &sam_len);
|
|
||||||
memcpy(sam_apdu + 19, hdr.epurse, sizeof(hdr.epurse));
|
|
||||||
|
|
||||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
print_dbg("-- 4", resp, resp_len);
|
|
||||||
|
|
||||||
uint8_t nr_mac[9] = {0};
|
|
||||||
memcpy(nr_mac, resp + 11, sizeof(nr_mac));
|
|
||||||
// resp here hold the whole NR/MAC
|
|
||||||
// 05 9bcd475e965ee20e // CHECK (w key)
|
|
||||||
print_dbg("NR/MAC", nr_mac, sizeof(nr_mac));
|
|
||||||
|
|
||||||
// c00a140a000000a115a1138009 059bcd475e965ee20e 8102 0004 820201f4 9000
|
|
||||||
|
|
||||||
// pre calc ourself?
|
|
||||||
// uint8_t cc_nr[] = {0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0, 0, 0, 0};
|
|
||||||
uint8_t div_key[8] = {0};
|
|
||||||
static uint8_t legacy_aa1_key[] = {0xAE, 0xA6, 0x84, 0xA6, 0xDA, 0xB2, 0x32, 0x78};
|
|
||||||
iclass_calc_div_key(hdr.csn, legacy_aa1_key, div_key, false);
|
|
||||||
|
|
||||||
uint8_t mac[4] = {0};
|
|
||||||
if (g_dbglevel == DBG_DEBUG) {
|
|
||||||
uint8_t wb[16] = {0};
|
|
||||||
memcpy(wb, hdr.epurse, sizeof(hdr.epurse));
|
|
||||||
memcpy(wb + sizeof(hdr.epurse), nr_mac + 1, 4);
|
|
||||||
print_dbg("cc_nr...", wb, sizeof(wb));
|
|
||||||
doMAC_N(wb, sizeof(wb), div_key, mac);
|
|
||||||
print_dbg("Calc MAC...", mac, sizeof(mac));
|
|
||||||
}
|
|
||||||
|
|
||||||
// start ssp clock again...
|
|
||||||
switch_clock_to_countsspclk();
|
|
||||||
|
|
||||||
// NOW we auth against tag
|
|
||||||
uint8_t cmd_check[9] = { ICLASS_CMD_CHECK };
|
|
||||||
memcpy(cmd_check + 1, nr_mac + 1, 8);
|
|
||||||
|
|
||||||
start_time = GetCountSspClk();
|
|
||||||
iclass_send_as_reader(cmd_check, sizeof(cmd_check), &start_time, &eof_time, shallow_mod);
|
|
||||||
|
|
||||||
// expect a 10-byte response here
|
|
||||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
if (res != PM3_SUCCESS || resp_len != 4) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
// store MAC
|
|
||||||
memcpy(mac, resp, sizeof(mac));
|
|
||||||
print_dbg("Got MAC", mac, sizeof(mac));
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// fifth send received MAC
|
|
||||||
// A0DA026316140A00000000BD0EA00CA00A8004 311E32E9 81020000
|
|
||||||
hexstr_to_byte_array("A0DA026316140A00000000BD0EA00CA00A8004311E32E981020000", sam_apdu, &sam_len);
|
|
||||||
memcpy(sam_apdu + 19, mac, sizeof(mac));
|
|
||||||
|
|
||||||
switch_clock_to_ticks();
|
|
||||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
print_dbg("-- 5", resp, resp_len);
|
|
||||||
|
|
||||||
uint8_t tmp_p1[4] = {0};
|
|
||||||
uint8_t tmp_p2[4] = {0};
|
|
||||||
|
|
||||||
// c161c10000a11aa118800e8702 ffffffff88ffffff 0a914eb981020004820236b09000
|
|
||||||
|
|
||||||
memcpy(tmp_p1, resp + 13, sizeof(tmp_p1));
|
|
||||||
memcpy(tmp_p2, resp + 13 + 4, sizeof(tmp_p2));
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// sixth send fake epurse update
|
|
||||||
// A0DA02631C140A00000000BD14A012A010800A 88FFFFFFFFFFFFFF9DE1 81020000
|
|
||||||
hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A88FFFFFFFFFFFFFF9DE181020000", sam_apdu, &sam_len);
|
|
||||||
|
|
||||||
memcpy(sam_apdu + 19, tmp_p2, sizeof(tmp_p1));
|
|
||||||
memcpy(sam_apdu + 19 + 4, tmp_p1, sizeof(tmp_p1));
|
|
||||||
AddCrc(sam_apdu + 19, 8);
|
|
||||||
|
|
||||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
print_dbg("-- 6", resp, resp_len);
|
|
||||||
// c1 61 c1 00 00 a1 10 a1 0e 80 04 0c 06 45 56 81 02 00 04 82 02 01 f4 90 00
|
|
||||||
|
|
||||||
// read block 6
|
|
||||||
switch_clock_to_countsspclk();
|
|
||||||
start_time = GetCountSspClk();
|
|
||||||
iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod);
|
|
||||||
|
|
||||||
// expect a 10-byte response here
|
|
||||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
if (res != PM3_SUCCESS || resp_len != 10) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
print_dbg("Block 6 from Picopass", resp, resp_len);
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// eight send block 6 config to SAM
|
|
||||||
// A0DA02631C140A00000000BD14A012A010800A 030303030003E0174323 81020000
|
|
||||||
hexstr_to_byte_array("A0DA02631C140A00000000BD14A012A010800A030303030003E017432381020000", sam_apdu, &sam_len);
|
|
||||||
memcpy(sam_apdu + 19, resp, resp_len);
|
|
||||||
|
|
||||||
switch_clock_to_ticks();
|
|
||||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
print_dbg("-- 7", resp, resp_len);
|
|
||||||
|
|
||||||
// c161c10000a110a10e8004 0606455681020004820201f49000
|
|
||||||
|
|
||||||
// read the credential blocks
|
|
||||||
switch_clock_to_countsspclk();
|
|
||||||
start_time = GetCountSspClk();
|
|
||||||
iclass_send_as_reader(resp + 11, 4, &start_time, &eof_time, shallow_mod);
|
|
||||||
|
|
||||||
// expect a 10-byte response here
|
|
||||||
res = GetIso15693AnswerFromTag(resp, ISO7816_MAX_FRAME, ICLASS_READER_TIMEOUT_OTHERS, &eof_time, false, true, &resp_len);
|
|
||||||
if (res != PM3_SUCCESS) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
print_dbg("Block 6-9 from Picopass", resp, resp_len);
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// nine send credential blocks to SAM
|
|
||||||
// A0DA026334140A00000000BD2CA02AA0288022 030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C 81020000
|
|
||||||
hexstr_to_byte_array("A0DA026334140A00000000BD2CA02AA0288022030303030003E017769CB4A198E0DEC82AD4C8211F9968712BE7393CF8E71D7E804C81020000", sam_apdu, &sam_len);
|
|
||||||
memcpy(sam_apdu + 19, resp, resp_len);
|
|
||||||
|
|
||||||
switch_clock_to_ticks();
|
|
||||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
print_dbg("-- 8", resp, resp_len);
|
|
||||||
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
// TEN ask for PACS data
|
|
||||||
// A0 DA 02 63 0C
|
|
||||||
// 44 0A 00 00 00 00
|
|
||||||
// BD 04
|
|
||||||
// A0 02
|
|
||||||
// 82 00
|
|
||||||
|
|
||||||
// (emulated tag <-> SAM exchange ends here)
|
|
||||||
hexstr_to_byte_array("A0DA02630C440A00000000BD04A0028200", sam_apdu, &sam_len);
|
|
||||||
memcpy(sam_apdu + 19, resp, resp_len);
|
|
||||||
|
|
||||||
if (sam_rxtx(sam_apdu, sam_len, resp, &resp_len) == false) {
|
|
||||||
res = PM3_ECARDEXCHANGE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_dbg("-- 9 response", resp, resp_len);
|
|
||||||
if (memcmp(resp, "\xc1\x64\x00\x00\x00\xbd\x17\x8a\x15", 9) == 0) {
|
|
||||||
res = PM3_ENOPACS;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// resp:
|
|
||||||
// c1 64 00 00 00
|
|
||||||
// bd 09
|
|
||||||
// 8a 07
|
|
||||||
// 03 05 06 95 1f 9a 00 <- decoded PACS data
|
|
||||||
// 90 00
|
|
||||||
uint8_t *pacs = BigBuf_calloc(resp[8]);
|
|
||||||
memcpy(pacs, resp + 9, resp[8]);
|
|
||||||
|
|
||||||
print_dbg("-- 10 PACS data", pacs, resp[8]);
|
|
||||||
|
|
||||||
reply_ng(CMD_HF_SAM_PICOPASS, PM3_SUCCESS, pacs, resp[8]);
|
|
||||||
res = PM3_SUCCESS;
|
|
||||||
goto off;
|
goto off;
|
||||||
|
|
||||||
out:
|
err:
|
||||||
|
res = PM3_ENOPACS;
|
||||||
reply_ng(CMD_HF_SAM_PICOPASS, res, NULL, 0);
|
reply_ng(CMD_HF_SAM_PICOPASS, res, NULL, 0);
|
||||||
|
goto off;
|
||||||
|
out:
|
||||||
|
reply_ng(CMD_HF_SAM_PICOPASS, PM3_SUCCESS, sam_response, sam_response_len);
|
||||||
|
goto off;
|
||||||
off:
|
off:
|
||||||
switch_off();
|
if (disconnectAfter) {
|
||||||
|
switch_off();
|
||||||
|
}
|
||||||
|
set_tracing(false);
|
||||||
StopTicks();
|
StopTicks();
|
||||||
BigBuf_free();
|
BigBuf_free();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// HID SAM <-> MFC
|
|
||||||
// HID SAM <-> SEOS
|
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "sam_common.h"
|
#include "sam_common.h"
|
||||||
|
#include "pm3_cmd.h"
|
||||||
|
|
||||||
int sam_picopass_get_pacs(void);
|
int sam_picopass_get_pacs(PacketCommandNG *c);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
* @param card_select Pointer to the descriptor of the detected card.
|
* @param card_select Pointer to the descriptor of the detected card.
|
||||||
* @return Status code indicating success or failure of the operation.
|
* @return Status code indicating success or failure of the operation.
|
||||||
*/
|
*/
|
||||||
static int sam_set_card_detected(iso14a_card_select_t *card_select) {
|
static int sam_set_card_detected_seos(iso14a_card_select_t *card_select) {
|
||||||
int res = PM3_SUCCESS;
|
int res = PM3_SUCCESS;
|
||||||
if (g_dbglevel >= DBG_DEBUG)
|
if (g_dbglevel >= DBG_DEBUG)
|
||||||
DbpString("start sam_set_card_detected");
|
DbpString("start sam_set_card_detected");
|
||||||
|
@ -112,81 +112,6 @@ out:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Copies the payload from an NFC buffer to a SAM buffer.
|
|
||||||
*
|
|
||||||
* Wraps received data from NFC into an ASN1 tree, so it can be transmitted to the SAM .
|
|
||||||
*
|
|
||||||
* @param sam_tx Pointer to the SAM transmit buffer.
|
|
||||||
* @param nfc_rx Pointer to the NFC receive buffer.
|
|
||||||
* @param nfc_len Length of the data to be copied from the NFC buffer.
|
|
||||||
*
|
|
||||||
* @return Length of SAM APDU to be sent.
|
|
||||||
*/
|
|
||||||
inline static uint16_t sam_seos_copy_payload_nfc2sam(uint8_t *sam_tx, uint8_t *nfc_rx, uint8_t nfc_len) {
|
|
||||||
// NFC resp:
|
|
||||||
// 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3
|
|
||||||
|
|
||||||
// SAM req:
|
|
||||||
// bd 1c
|
|
||||||
// a0 1a
|
|
||||||
// a0 18
|
|
||||||
// 80 12
|
|
||||||
// 6f 0c 84 0a a0 00 00 04 40 00 01 01 00 01 90 00 fb e3
|
|
||||||
// 81 02
|
|
||||||
// 00 00
|
|
||||||
|
|
||||||
const uint8_t payload[] = {
|
|
||||||
0xbd, 4,
|
|
||||||
0xa0, 2,
|
|
||||||
0xa0, 0
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t tag81[] = {
|
|
||||||
0x00, 0x00
|
|
||||||
};
|
|
||||||
|
|
||||||
memcpy(sam_tx, payload, sizeof(payload));
|
|
||||||
|
|
||||||
sam_append_asn1_node(sam_tx, sam_tx + 4, 0x80, nfc_rx, nfc_len);
|
|
||||||
sam_append_asn1_node(sam_tx, sam_tx + 4, 0x81, tag81, sizeof(tag81));
|
|
||||||
|
|
||||||
return sam_tx[1] + 2; // length of the ASN1 tree
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Copies the payload from the SAM receive buffer to the NFC transmit buffer.
|
|
||||||
*
|
|
||||||
* Unpacks data to be transmitted from ASN1 tree in APDU received from SAM.
|
|
||||||
*
|
|
||||||
* @param nfc_tx_buf Pointer to the buffer where the NFC transmit data will be stored.
|
|
||||||
* @param sam_rx_buf Pointer to the buffer containing the data received from the SAM.
|
|
||||||
* @return Length of NFC APDU to be sent.
|
|
||||||
*/
|
|
||||||
inline static uint16_t sam_seos_copy_payload_sam2nfc(uint8_t *nfc_tx_buf, uint8_t *sam_rx_buf) {
|
|
||||||
// SAM resp:
|
|
||||||
// c1 61 c1 00 00
|
|
||||||
// a1 21 <- nfc command
|
|
||||||
// a1 1f <- nfc send
|
|
||||||
// 80 10 <- data
|
|
||||||
// 00 a4 04 00 0a a0 00 00 04 40 00 01 01 00 01 00
|
|
||||||
// 81 02 <- protocol
|
|
||||||
// 02 02
|
|
||||||
// 82 02 <- timeout
|
|
||||||
// 01 2e
|
|
||||||
// 85 03 <- format
|
|
||||||
// 06 c0 00
|
|
||||||
// 90 00
|
|
||||||
|
|
||||||
// NFC req:
|
|
||||||
// 00 a4 04 00 0a a0 00 00 04 40 00 01 01 00 01 00
|
|
||||||
|
|
||||||
// copy data out of c1->a1>->a1->80 node
|
|
||||||
uint16_t nfc_tx_len = (uint8_t) * (sam_rx_buf + 10);
|
|
||||||
memcpy(nfc_tx_buf, sam_rx_buf + 11, nfc_tx_len);
|
|
||||||
return nfc_tx_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends a request to the SAM and retrieves the response.
|
* @brief Sends a request to the SAM and retrieves the response.
|
||||||
*
|
*
|
||||||
|
@ -204,8 +129,12 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r
|
||||||
if (g_dbglevel >= DBG_DEBUG)
|
if (g_dbglevel >= DBG_DEBUG)
|
||||||
DbpString("start sam_send_request_iso14a");
|
DbpString("start sam_send_request_iso14a");
|
||||||
|
|
||||||
uint8_t buf1[ISO7816_MAX_FRAME] = {0};
|
uint8_t * buf1 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||||
uint8_t buf2[ISO7816_MAX_FRAME] = {0};
|
uint8_t * buf2 = BigBuf_malloc(ISO7816_MAX_FRAME);
|
||||||
|
if(buf1 == NULL || buf2 == NULL){
|
||||||
|
res = PM3_EMALLOC;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t *sam_tx_buf = buf1;
|
uint8_t *sam_tx_buf = buf1;
|
||||||
uint16_t sam_tx_len;
|
uint16_t sam_tx_len;
|
||||||
|
@ -247,7 +176,7 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r
|
||||||
// tag <-> SAM exchange starts here
|
// tag <-> SAM exchange starts here
|
||||||
while (sam_rx_buf[1] == 0x61) {
|
while (sam_rx_buf[1] == 0x61) {
|
||||||
switch_clock_to_countsspclk();
|
switch_clock_to_countsspclk();
|
||||||
nfc_tx_len = sam_seos_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf);
|
nfc_tx_len = sam_copy_payload_sam2nfc(nfc_tx_buf, sam_rx_buf);
|
||||||
|
|
||||||
nfc_rx_len = iso14_apdu(
|
nfc_rx_len = iso14_apdu(
|
||||||
nfc_tx_buf,
|
nfc_tx_buf,
|
||||||
|
@ -259,7 +188,7 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r
|
||||||
);
|
);
|
||||||
|
|
||||||
switch_clock_to_ticks();
|
switch_clock_to_ticks();
|
||||||
sam_tx_len = sam_seos_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len - 2);
|
sam_tx_len = sam_copy_payload_nfc2sam(sam_tx_buf, nfc_rx_buf, nfc_rx_len - 2);
|
||||||
|
|
||||||
sam_send_payload(
|
sam_send_payload(
|
||||||
0x14, 0x0a, 0x14,
|
0x14, 0x0a, 0x14,
|
||||||
|
@ -328,6 +257,7 @@ static int sam_send_request_iso14a(const uint8_t *const request, const uint8_t r
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
BigBuf_free();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,11 +271,13 @@ out:
|
||||||
* @return Status code indicating success or failure of the operation.
|
* @return Status code indicating success or failure of the operation.
|
||||||
*/
|
*/
|
||||||
int sam_seos_get_pacs(PacketCommandNG *c) {
|
int sam_seos_get_pacs(PacketCommandNG *c) {
|
||||||
bool disconnectAfter = c->oldarg[0] & 0x01;
|
const uint8_t flags = c->data.asBytes[0];
|
||||||
bool skipDetect = c->oldarg[1] & 0x01;
|
const bool disconnectAfter = !!(flags & BITMASK(0));
|
||||||
|
const bool skipDetect = !!(flags & BITMASK(1));
|
||||||
|
|
||||||
|
uint8_t *cmd = c->data.asBytes + 1;
|
||||||
|
uint16_t cmd_len = c->length - 1;
|
||||||
|
|
||||||
uint8_t *cmd = c->data.asBytes;
|
|
||||||
uint16_t cmd_len = (uint16_t) c->oldarg[2];
|
|
||||||
|
|
||||||
int res = PM3_EFAILED;
|
int res = PM3_EFAILED;
|
||||||
|
|
||||||
|
@ -371,7 +303,7 @@ int sam_seos_get_pacs(PacketCommandNG *c) {
|
||||||
switch_clock_to_ticks();
|
switch_clock_to_ticks();
|
||||||
|
|
||||||
// step 3: SamCommand CardDetected
|
// step 3: SamCommand CardDetected
|
||||||
sam_set_card_detected(&card_a_info);
|
sam_set_card_detected_seos(&card_a_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
// step 3: SamCommand RequestPACS, relay NFC communication
|
// step 3: SamCommand RequestPACS, relay NFC communication
|
||||||
|
|
|
@ -413,6 +413,7 @@ set (TARGET_SOURCES
|
||||||
${PM3_ROOT}/client/src/fileutils.c
|
${PM3_ROOT}/client/src/fileutils.c
|
||||||
${PM3_ROOT}/client/src/flash.c
|
${PM3_ROOT}/client/src/flash.c
|
||||||
${PM3_ROOT}/client/src/graph.c
|
${PM3_ROOT}/client/src/graph.c
|
||||||
|
${PM3_ROOT}/client/src/hidsio.c
|
||||||
${PM3_ROOT}/client/src/iso4217.c
|
${PM3_ROOT}/client/src/iso4217.c
|
||||||
${PM3_ROOT}/client/src/jansson_path.c
|
${PM3_ROOT}/client/src/jansson_path.c
|
||||||
${PM3_ROOT}/client/src/lua_bitlib.c
|
${PM3_ROOT}/client/src/lua_bitlib.c
|
||||||
|
|
|
@ -723,6 +723,7 @@ SRCS = mifare/aiddesfire.c \
|
||||||
flash.c \
|
flash.c \
|
||||||
generator.c \
|
generator.c \
|
||||||
graph.c \
|
graph.c \
|
||||||
|
hidsio.c \
|
||||||
jansson_path.c \
|
jansson_path.c \
|
||||||
iso4217.c \
|
iso4217.c \
|
||||||
iso7816/apduinfo.c \
|
iso7816/apduinfo.c \
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "generator.h"
|
#include "generator.h"
|
||||||
#include "cmdhf14b.h"
|
#include "cmdhf14b.h"
|
||||||
#include "cmdhw.h"
|
#include "cmdhw.h"
|
||||||
|
#include "hidsio.h"
|
||||||
|
|
||||||
|
|
||||||
#define NUM_CSNS 9
|
#define NUM_CSNS 9
|
||||||
|
@ -5398,15 +5399,48 @@ static int CmdHFiClassSAM(const char *Cmd) {
|
||||||
CLIParserInit(&ctx, "hf iclass sam",
|
CLIParserInit(&ctx, "hf iclass sam",
|
||||||
"Extract PACS via a HID SAM\n",
|
"Extract PACS via a HID SAM\n",
|
||||||
"hf iclass sam\n"
|
"hf iclass sam\n"
|
||||||
|
"hf iclass sam -p -d a005a103800104 -> get PACS data, but ensure that epurse will stay unchanged\n"
|
||||||
|
"hf iclass sam --break-on-nr-mac -> get Nr-MAC for extracting encrypted SIO\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("v", "verbose", "verbose output"),
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
arg_lit0("k", "keep", "keep the field active after command executed"),
|
||||||
|
arg_lit0("n", "nodetect", "skip selecting the card and sending card details to SAM"),
|
||||||
|
arg_lit0("t", "tlv", "decode TLV"),
|
||||||
|
arg_lit0(NULL, "break-on-nr-mac", "stop tag interaction on nr-mac"),
|
||||||
|
arg_lit0("p", "prevent-epurse-update", "fake epurse update"),
|
||||||
|
arg_lit0(NULL, "shallow", "shallow mod"),
|
||||||
|
arg_strx0("d", "data", "<hex>", "DER encoded command to send to SAM"),
|
||||||
arg_param_end
|
arg_param_end
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool verbose = arg_get_lit(ctx, 1);
|
bool verbose = arg_get_lit(ctx, 1);
|
||||||
|
bool disconnectAfter = !arg_get_lit(ctx, 2);
|
||||||
|
bool skipDetect = arg_get_lit(ctx, 3);
|
||||||
|
bool decodeTLV = arg_get_lit(ctx, 4);
|
||||||
|
bool breakOnNrMac = arg_get_lit(ctx, 5);
|
||||||
|
bool preventEpurseUpdate = arg_get_lit(ctx, 6);
|
||||||
|
bool shallow_mod = arg_get_lit(ctx, 7);
|
||||||
|
|
||||||
|
uint8_t flags = 0;
|
||||||
|
if (disconnectAfter) flags |= BITMASK(0);
|
||||||
|
if (skipDetect) flags |= BITMASK(1);
|
||||||
|
if (breakOnNrMac) flags |= BITMASK(2);
|
||||||
|
if (preventEpurseUpdate) flags |= BITMASK(3);
|
||||||
|
if (shallow_mod) flags |= BITMASK(4);
|
||||||
|
|
||||||
|
uint8_t data[PM3_CMD_DATA_SIZE] = {0};
|
||||||
|
data[0] = flags;
|
||||||
|
|
||||||
|
int cmdlen = 0;
|
||||||
|
if (CLIParamHexToBuf(arg_get_str(ctx, 8), data+1, PM3_CMD_DATA_SIZE-1, &cmdlen) != PM3_SUCCESS){
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
if (IsHIDSamPresent(verbose) == false) {
|
if (IsHIDSamPresent(verbose) == false) {
|
||||||
|
@ -5414,7 +5448,7 @@ static int CmdHFiClassSAM(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandNG(CMD_HF_SAM_PICOPASS, NULL, 0);
|
SendCommandNG(CMD_HF_SAM_PICOPASS, data, cmdlen+1);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_HF_SAM_PICOPASS, &resp, 4000) == false) {
|
if (WaitForResponseTimeout(CMD_HF_SAM_PICOPASS, &resp, 4000) == false) {
|
||||||
PrintAndLogEx(WARNING, "SAM timeout");
|
PrintAndLogEx(WARNING, "SAM timeout");
|
||||||
|
@ -5432,16 +5466,58 @@ static int CmdHFiClassSAM(const char *Cmd) {
|
||||||
return resp.status;
|
return resp.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CSN, config, epurse, NR/MAC, AIA
|
|
||||||
// PACS
|
|
||||||
// 03 05
|
|
||||||
// 06 85 80 6d c0
|
|
||||||
// first byte skip
|
|
||||||
// second byte length
|
|
||||||
// third padded
|
|
||||||
// fourth ..
|
|
||||||
uint8_t *d = resp.data.asBytes;
|
uint8_t *d = resp.data.asBytes;
|
||||||
HIDDumpPACSBits(d + 2, d[1], verbose);
|
// check for standard SamCommandGetContentElement response
|
||||||
|
// bd 09
|
||||||
|
// 8a 07
|
||||||
|
// 03 05 <- tag + length
|
||||||
|
// 06 85 80 6d c0 <- decoded PACS data
|
||||||
|
if (d[0] == 0xbd && d[2] == 0x8a && d[4] == 0x03) {
|
||||||
|
uint8_t pacs_length = d[5];
|
||||||
|
uint8_t *pacs_data = d + 6;
|
||||||
|
int res = HIDDumpPACSBits(pacs_data, pacs_length, verbose);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
// check for standard samCommandGetContentElement2:
|
||||||
|
// bd 1e
|
||||||
|
// b3 1c
|
||||||
|
// a0 1a
|
||||||
|
// 80 05
|
||||||
|
// 06 85 80 6d c0
|
||||||
|
// 81 0e
|
||||||
|
// 2b 06 01 04 01 81 e4 38 01 01 02 04 3c ff
|
||||||
|
// 82 01
|
||||||
|
// 07
|
||||||
|
} else if (d[0] == 0xbd && d[2] == 0xb3 && d[4] == 0xa0) {
|
||||||
|
const uint8_t *pacs = d + 6;
|
||||||
|
const uint8_t pacs_length = pacs[1];
|
||||||
|
const uint8_t *pacs_data = pacs + 2;
|
||||||
|
int res = HIDDumpPACSBits(pacs_data, pacs_length, verbose);
|
||||||
|
if (res != PM3_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *oid = pacs + 2 + pacs_length;
|
||||||
|
const uint8_t oid_length = oid[1];
|
||||||
|
const uint8_t *oid_data = oid + 2;
|
||||||
|
PrintAndLogEx(SUCCESS, "SIO OID.......: " _GREEN_("%s"), sprint_hex_inrow(oid_data, oid_length));
|
||||||
|
|
||||||
|
const uint8_t *mediaType = oid + 2 + oid_length;
|
||||||
|
const uint8_t mediaType_data = mediaType[2];
|
||||||
|
PrintAndLogEx(SUCCESS, "SIO Media Type: " _GREEN_("%s"), getSioMediaTypeInfo(mediaType_data));
|
||||||
|
} else if(breakOnNrMac && d[0] == 0x05) {
|
||||||
|
PrintAndLogEx(SUCCESS, "Nr-MAC: " _GREEN_("%s"), sprint_hex_inrow(d+1, 8));
|
||||||
|
if(verbose){
|
||||||
|
PrintAndLogEx(INFO, "Replay Nr-MAC to dump SIO:");
|
||||||
|
PrintAndLogEx(SUCCESS, " hf iclass dump -k \"%s\" --nr", sprint_hex_inrow(d+1, 8));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print_hex(d, resp.length);
|
||||||
|
}
|
||||||
|
if (decodeTLV) {
|
||||||
|
asn1_print(d, d[1] + 2, " ");
|
||||||
|
}
|
||||||
|
|
||||||
return PM3_SUCCESS;
|
return PM3_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "crypto/libpcrypto.h" // AES decrypt
|
#include "crypto/libpcrypto.h" // AES decrypt
|
||||||
#include "commonutil.h" // get_sw
|
#include "commonutil.h" // get_sw
|
||||||
#include "protocols.h" // ISO7816 APDU return codes
|
#include "protocols.h" // ISO7816 APDU return codes
|
||||||
|
#include "hidsio.h"
|
||||||
|
|
||||||
static uint8_t zeros[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
static uint8_t zeros[16] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
|
|
||||||
|
@ -100,17 +101,6 @@ static const known_algo_t known_algorithm_map[] = {
|
||||||
{9, "AES-128_CBC_MODE"},
|
{9, "AES-128_CBC_MODE"},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const sioMediaTypeName_t sioMediaTypeMapping[] = {
|
|
||||||
{ 0x00, "Unknown"},
|
|
||||||
{ 0x01, "DESFire"},
|
|
||||||
{ 0x02, "MIFARE"},
|
|
||||||
{ 0x03, "iCLASS (PicoPass)"},
|
|
||||||
{ 0x04, "ISO14443AL4"},
|
|
||||||
{ 0x06, "MIFARE Plus"},
|
|
||||||
{ 0x07, "Seos"},
|
|
||||||
{ 0xFF, "INVALID VALUE"}
|
|
||||||
};
|
|
||||||
|
|
||||||
static int create_cmac(uint8_t *key, uint8_t *input, uint8_t *out, int input_len, int encryption_algorithm) {
|
static int create_cmac(uint8_t *key, uint8_t *input, uint8_t *out, int input_len, int encryption_algorithm) {
|
||||||
uint8_t iv[16] = {0x00};
|
uint8_t iv[16] = {0x00};
|
||||||
|
|
||||||
|
@ -1638,32 +1628,14 @@ static int CmdHfSeosList(const char *Cmd) {
|
||||||
return CmdTraceListAlias(Cmd, "hf seos", "seos -c");
|
return CmdTraceListAlias(Cmd, "hf seos", "seos -c");
|
||||||
}
|
}
|
||||||
|
|
||||||
// get a SIO media type based on the UID
|
|
||||||
// uid[8] tag uid
|
|
||||||
// returns description of the best match
|
|
||||||
static const char *getSioMediaTypeInfo(uint8_t uid) {
|
|
||||||
|
|
||||||
for (int i = 0; i < ARRAYLEN(sioMediaTypeMapping); ++i) {
|
|
||||||
if (uid == sioMediaTypeMapping[i].uid) {
|
|
||||||
return sioMediaTypeMapping[i].desc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//No match, return default
|
|
||||||
return sioMediaTypeMapping[ARRAYLEN(sioMediaTypeMapping) - 1].desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int CmdHfSeosSAM(const char *Cmd) {
|
static int CmdHfSeosSAM(const char *Cmd) {
|
||||||
CLIParserContext *ctx;
|
CLIParserContext *ctx;
|
||||||
CLIParserInit(&ctx, "hf seos sam",
|
CLIParserInit(&ctx, "hf seos sam",
|
||||||
"Extract PACS via a HID SAM\n",
|
"Extract PACS via a HID SAM\n",
|
||||||
"hf seos sam\n"
|
"hf seos sam\n"
|
||||||
"hd seos sam -d a005a103800104 -> get PACS data\n"
|
"hf seos sam -d a005a103800104 -> get PACS data\n"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void *argtable[] = {
|
void *argtable[] = {
|
||||||
arg_param_begin,
|
arg_param_begin,
|
||||||
arg_lit0("v", "verbose", "verbose output"),
|
arg_lit0("v", "verbose", "verbose output"),
|
||||||
|
@ -1675,26 +1647,23 @@ static int CmdHfSeosSAM(const char *Cmd) {
|
||||||
};
|
};
|
||||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||||
|
|
||||||
bool verbose = false;
|
bool verbose = arg_get_lit(ctx, 1);
|
||||||
if (arg_get_lit(ctx, 1)) {
|
bool disconnectAfter = !arg_get_lit(ctx, 2);
|
||||||
verbose = true;
|
bool skipDetect = arg_get_lit(ctx, 3);
|
||||||
}
|
bool decodeTLV = arg_get_lit(ctx, 4);
|
||||||
bool disconnectAfter = true;
|
|
||||||
if (arg_get_lit(ctx, 2)) {
|
uint8_t flags = 0;
|
||||||
disconnectAfter = false;
|
if (disconnectAfter) flags |= BITMASK(0);
|
||||||
}
|
if (skipDetect) flags |= BITMASK(1);
|
||||||
bool skipDetect = false;
|
|
||||||
if (arg_get_lit(ctx, 3)) {
|
|
||||||
skipDetect = true;
|
|
||||||
}
|
|
||||||
bool decodeTLV = false;
|
|
||||||
if (arg_get_lit(ctx, 4)) {
|
|
||||||
decodeTLV = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t data[PM3_CMD_DATA_SIZE] = {0};
|
uint8_t data[PM3_CMD_DATA_SIZE] = {0};
|
||||||
int datalen = 0;
|
data[0] = flags;
|
||||||
CLIGetHexBLessWithReturn(ctx, 5, data, &datalen, 0);
|
|
||||||
|
int cmdlen = 0;
|
||||||
|
if (CLIParamHexToBuf(arg_get_str(ctx, 5), data+1, PM3_CMD_DATA_SIZE-1, &cmdlen) != PM3_SUCCESS){
|
||||||
|
CLIParserFree(ctx);
|
||||||
|
return PM3_ESOFT;
|
||||||
|
}
|
||||||
|
|
||||||
CLIParserFree(ctx);
|
CLIParserFree(ctx);
|
||||||
|
|
||||||
|
@ -1703,7 +1672,7 @@ static int CmdHfSeosSAM(const char *Cmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
clearCommandBuffer();
|
clearCommandBuffer();
|
||||||
SendCommandMIX(CMD_HF_SAM_SEOS, disconnectAfter, skipDetect, datalen, data, datalen);
|
SendCommandNG(CMD_HF_SAM_SEOS, data, cmdlen+1);
|
||||||
PacketResponseNG resp;
|
PacketResponseNG resp;
|
||||||
if (WaitForResponseTimeout(CMD_HF_SAM_SEOS, &resp, 4000) == false) {
|
if (WaitForResponseTimeout(CMD_HF_SAM_SEOS, &resp, 4000) == false) {
|
||||||
PrintAndLogEx(WARNING, "SAM timeout");
|
PrintAndLogEx(WARNING, "SAM timeout");
|
||||||
|
|
|
@ -21,12 +21,6 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
// structure and database for uid -> tagtype lookups
|
|
||||||
typedef struct {
|
|
||||||
uint8_t uid;
|
|
||||||
const char *desc;
|
|
||||||
} sioMediaTypeName_t;
|
|
||||||
|
|
||||||
int infoSeos(bool verbose);
|
int infoSeos(bool verbose);
|
||||||
int CmdHFSeos(const char *Cmd);
|
int CmdHFSeos(const char *Cmd);
|
||||||
int seos_kdf(bool encryption, uint8_t *masterKey, uint8_t keyslot,
|
int seos_kdf(bool encryption, uint8_t *masterKey, uint8_t keyslot,
|
||||||
|
|
51
client/src/hidsio.c
Normal file
51
client/src/hidsio.c
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for the text of the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// HID Global SIO utilities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#include "commonutil.h"
|
||||||
|
#include "hidsio.h"
|
||||||
|
|
||||||
|
// structure and database for uid -> tagtype lookups
|
||||||
|
typedef struct {
|
||||||
|
uint8_t uid;
|
||||||
|
const char *desc;
|
||||||
|
} sioMediaTypeName_t;
|
||||||
|
|
||||||
|
static const sioMediaTypeName_t sioMediaTypeMapping[] = {
|
||||||
|
{ 0x00, "Unknown"},
|
||||||
|
{ 0x01, "DESFire"},
|
||||||
|
{ 0x02, "MIFARE"},
|
||||||
|
{ 0x03, "iCLASS (PicoPass)"},
|
||||||
|
{ 0x04, "ISO14443AL4"},
|
||||||
|
{ 0x06, "MIFARE Plus"},
|
||||||
|
{ 0x07, "Seos"},
|
||||||
|
{ 0xFF, "INVALID VALUE"}
|
||||||
|
};
|
||||||
|
|
||||||
|
// get a SIO media type based on the UID
|
||||||
|
// uid[8] tag uid
|
||||||
|
// returns description of the best match
|
||||||
|
const char *getSioMediaTypeInfo(uint8_t uid) {
|
||||||
|
|
||||||
|
for (int i = 0; i < ARRAYLEN(sioMediaTypeMapping); ++i) {
|
||||||
|
if (uid == sioMediaTypeMapping[i].uid) {
|
||||||
|
return sioMediaTypeMapping[i].desc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//No match, return default
|
||||||
|
return sioMediaTypeMapping[ARRAYLEN(sioMediaTypeMapping) - 1].desc;
|
||||||
|
}
|
26
client/src/hidsio.h
Normal file
26
client/src/hidsio.h
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// See LICENSE.txt for the text of the license.
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// HID Global SIO utilities
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
#ifndef __HIDSIO_H_
|
||||||
|
#define __HIDSIO_H_
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
const char *getSioMediaTypeInfo(uint8_t uid);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Add table
Add a link
Reference in a new issue