OFW PR 2783: SLIX2 emulation support

by g3gg0
This commit is contained in:
MX
2023-06-24 21:14:00 +03:00
parent 8e126112f0
commit 6f3f2fa1e7
8 changed files with 910 additions and 418 deletions

View File

@@ -149,12 +149,18 @@ bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* n
return false;
}
/* clear all know sub type data before reading them */
memset(&nfcv_data->sub_data, 0x00, sizeof(nfcv_data->sub_data));
if(slix_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX detected");
nfcv_data->sub_type = NfcVTypeSlix;
} else if(slix2_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX2 detected");
nfcv_data->sub_type = NfcVTypeSlix2;
if(slix2_read_custom(nfc_data, nfcv_data) != ERR_NONE) {
return false;
}
} else if(slix_s_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX-S detected");
nfcv_data->sub_type = NfcVTypeSlixS;
@@ -612,9 +618,34 @@ void nfcv_emu_handle_packet(
if(ctx->flags & NFCV_REQ_FLAG_AFI) {
uint8_t afi = nfcv_data->frame[ctx->payload_offset];
if(afi == nfcv_data->afi) {
respond = true;
uint8_t family = (afi & 0xF0);
uint8_t subfamily = (afi & 0x0F);
if(family) {
if(subfamily) {
/* selected family and subfamily only */
if(afi == nfcv_data->afi) {
respond = true;
}
} else {
/* selected family, any subfamily */
if(family == (nfcv_data->afi & 0xf0)) {
respond = true;
}
}
} else {
if(subfamily) {
/* proprietary subfamily only */
if(afi == nfcv_data->afi) {
respond = true;
}
} else {
/* all families and subfamilies */
respond = true;
}
}
} else {
respond = true;
}
@@ -740,13 +771,19 @@ void nfcv_emu_handle_packet(
case NFCV_CMD_READ_MULTI_BLOCK:
case NFCV_CMD_READ_BLOCK: {
uint8_t block = nfcv_data->frame[ctx->payload_offset];
uint8_t blocks = 1;
int blocks = 1;
if(ctx->command == NFCV_CMD_READ_MULTI_BLOCK) {
blocks = nfcv_data->frame[ctx->payload_offset + 1] + 1;
}
if(block + blocks <= nfcv_data->block_num) {
/* limit the maximum block count, underflow accepted */
if(block + blocks > nfcv_data->block_num) {
blocks = nfcv_data->block_num - block;
}
/* only respond with the valid blocks, if there are any */
if(blocks > 0) {
uint8_t buffer_pos = 0;
ctx->response_buffer[buffer_pos++] = NFCV_NOERROR;
@@ -773,10 +810,13 @@ void nfcv_emu_handle_packet(
ctx->response_flags,
ctx->send_time);
} else {
ctx->response_buffer[0] = NFCV_RES_FLAG_ERROR;
ctx->response_buffer[1] = NFCV_ERROR_GENERIC;
nfcv_emu_send(
tx_rx, nfcv_data, ctx->response_buffer, 2, ctx->response_flags, ctx->send_time);
/* reply with an error only in addressed or selected mode */
if(ctx->addressed || ctx->selected) {
ctx->response_buffer[0] = NFCV_RES_FLAG_ERROR;
ctx->response_buffer[1] = NFCV_ERROR_GENERIC;
nfcv_emu_send(
tx_rx, nfcv_data, ctx->response_buffer, 2, ctx->response_flags, ctx->send_time);
}
}
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block);

View File

@@ -139,8 +139,10 @@ typedef enum {
} NfcVErrorcodes;
typedef enum {
NfcVLockBitDsfid = 1,
NfcVLockBitAfi = 2,
NfcVLockBitDsfid = 1 << 0,
NfcVLockBitAfi = 1 << 1,
NfcVLockBitEas = 1 << 2,
NfcVLockBitPpl = 1 << 3,
} NfcVLockBits;
typedef enum {
@@ -168,14 +170,55 @@ typedef enum {
NfcVSendFlagsHighRate = 1 << 4
} NfcVSendFlags;
/* SLIX specific config flags */
typedef enum {
NfcVSlixDataFlagsNone = 0,
NfcVSlixDataFlagsHasKeyRead = 1 << 0,
NfcVSlixDataFlagsHasKeyWrite = 1 << 1,
NfcVSlixDataFlagsHasKeyPrivacy = 1 << 2,
NfcVSlixDataFlagsHasKeyDestroy = 1 << 3,
NfcVSlixDataFlagsHasKeyEas = 1 << 4,
NfcVSlixDataFlagsValidKeyRead = 1 << 8,
NfcVSlixDataFlagsValidKeyWrite = 1 << 9,
NfcVSlixDataFlagsValidKeyPrivacy = 1 << 10,
NfcVSlixDataFlagsValidKeyDestroy = 1 << 11,
NfcVSlixDataFlagsValidKeyEas = 1 << 12,
NfcVSlixDataFlagsPrivacy = 1 << 16,
NfcVSlixDataFlagsDestroyed = 1 << 17
} NfcVSlixDataFlags;
/* abstract the file read/write operations for all SLIX types to reduce duplicated code */
typedef enum {
SlixFeatureRead = 1 << 0,
SlixFeatureWrite = 1 << 1,
SlixFeaturePrivacy = 1 << 2,
SlixFeatureDestroy = 1 << 3,
SlixFeatureEas = 1 << 4,
SlixFeatureSignature = 1 << 5,
SlixFeatureProtection = 1 << 6,
SlixFeatureSlix = SlixFeatureEas,
SlixFeatureSlixS =
(SlixFeatureRead | SlixFeatureWrite | SlixFeaturePrivacy | SlixFeatureDestroy |
SlixFeatureEas),
SlixFeatureSlixL = (SlixFeaturePrivacy | SlixFeatureDestroy | SlixFeatureEas),
SlixFeatureSlix2 =
(SlixFeatureRead | SlixFeatureWrite | SlixFeaturePrivacy | SlixFeatureDestroy |
SlixFeatureEas | SlixFeatureSignature | SlixFeatureProtection),
} SlixTypeFeatures;
typedef struct {
uint32_t flags;
uint8_t key_read[4];
uint8_t key_write[4];
uint8_t key_privacy[4];
uint8_t key_destroy[4];
uint8_t key_eas[4];
uint8_t rand[2];
bool privacy;
uint8_t signature[32];
/* SLIX2 options */
uint8_t pp_pointer;
uint8_t pp_condition;
} NfcVSlixData;
typedef union {

View File

@@ -9,6 +9,120 @@
#define TAG "SLIX"
ReturnCode slix2_read_nxp_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
furi_assert(nfc_data);
furi_assert(nfcv_data);
uint8_t rxBuf[32];
uint16_t received = 0;
ReturnCode ret = ERR_NONE;
FURI_LOG_D(TAG, "Read NXP SYSTEM INFORMATION...");
for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) {
uint8_t cmd[] = {};
uint8_t uid[NFCV_UID_LENGTH];
/* UID is stored reversed in requests */
for(int pos = 0; pos < nfc_data->uid_len; pos++) {
uid[pos] = nfc_data->uid[nfc_data->uid_len - 1 - pos];
}
ReturnCode ret = rfalNfcvPollerTransceiveReq(
NFCV_CMD_NXP_GET_NXP_SYSTEM_INFORMATION,
RFAL_NFCV_REQ_FLAG_DEFAULT,
NFCV_MANUFACTURER_NXP,
uid,
cmd,
sizeof(cmd),
rxBuf,
sizeof(rxBuf),
&received);
if(ret == ERR_NONE) {
break;
}
}
if(ret != ERR_NONE || received != 8) {
FURI_LOG_D(TAG, "Failed: %d, %d", ret, received);
return ret;
}
FURI_LOG_D(TAG, "Success...");
NfcVSlixData* slix = &nfcv_data->sub_data.slix;
slix->pp_pointer = rxBuf[1];
slix->pp_condition = rxBuf[2];
/* convert NXP's to our internal lock bits format */
nfcv_data->security_status[0] = 0;
nfcv_data->security_status[0] |= (rxBuf[3] & SlixLockBitDsfid) ? NfcVLockBitDsfid : 0;
nfcv_data->security_status[0] |= (rxBuf[3] & SlixLockBitAfi) ? NfcVLockBitAfi : 0;
nfcv_data->security_status[0] |= (rxBuf[3] & SlixLockBitEas) ? NfcVLockBitEas : 0;
nfcv_data->security_status[0] |= (rxBuf[3] & SlixLockBitPpl) ? NfcVLockBitPpl : 0;
return ERR_NONE;
}
ReturnCode slix2_read_signature(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
furi_assert(nfc_data);
furi_assert(nfcv_data);
uint8_t rxBuf[64];
uint16_t received = 0;
ReturnCode ret = ERR_NONE;
FURI_LOG_D(TAG, "Read SIGNATURE...");
for(int tries = 0; tries < NFCV_COMMAND_RETRIES; tries++) {
uint8_t cmd[] = {};
uint8_t uid[NFCV_UID_LENGTH];
/* UID is stored reversed in requests */
for(int pos = 0; pos < nfc_data->uid_len; pos++) {
uid[pos] = nfc_data->uid[nfc_data->uid_len - 1 - pos];
}
ReturnCode ret = rfalNfcvPollerTransceiveReq(
NFCV_CMD_NXP_READ_SIGNATURE,
RFAL_NFCV_REQ_FLAG_DEFAULT,
NFCV_MANUFACTURER_NXP,
uid,
cmd,
sizeof(cmd),
rxBuf,
sizeof(rxBuf),
&received);
if(ret == ERR_NONE) {
break;
}
}
if(ret != ERR_NONE || received != 33) {
FURI_LOG_D(TAG, "Failed: %d, %d", ret, received);
return ret;
}
FURI_LOG_D(TAG, "Success...");
NfcVSlixData* slix = &nfcv_data->sub_data.slix;
memcpy(slix->signature, &rxBuf[1], 32);
return ERR_NONE;
}
ReturnCode slix2_read_custom(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
ReturnCode ret = ERR_NONE;
ret = slix2_read_nxp_sysinfo(nfc_data, nfcv_data);
if(ret != ERR_NONE) {
return ret;
}
ret = slix2_read_signature(nfc_data, nfcv_data);
return ret;
}
static uint32_t slix_read_be(uint8_t* data, uint32_t length) {
uint32_t value = 0;
@@ -137,6 +251,43 @@ ReturnCode slix_unlock(NfcVData* data, uint32_t password_id) {
return ret;
}
static void slix_generic_pass_infos(
uint8_t password_id,
NfcVSlixData* slix,
uint8_t** password,
uint32_t* flag_valid,
uint32_t* flag_set) {
switch(password_id) {
case SLIX_PASS_READ:
*password = slix->key_read;
*flag_valid = NfcVSlixDataFlagsValidKeyRead;
*flag_set = NfcVSlixDataFlagsHasKeyRead;
break;
case SLIX_PASS_WRITE:
*password = slix->key_write;
*flag_valid = NfcVSlixDataFlagsValidKeyWrite;
*flag_set = NfcVSlixDataFlagsHasKeyWrite;
break;
case SLIX_PASS_PRIVACY:
*password = slix->key_privacy;
*flag_valid = NfcVSlixDataFlagsValidKeyPrivacy;
*flag_set = NfcVSlixDataFlagsHasKeyPrivacy;
break;
case SLIX_PASS_DESTROY:
*password = slix->key_destroy;
*flag_valid = NfcVSlixDataFlagsValidKeyDestroy;
*flag_set = NfcVSlixDataFlagsHasKeyDestroy;
break;
case SLIX_PASS_EASAFI:
*password = slix->key_eas;
*flag_valid = NfcVSlixDataFlagsValidKeyEas;
*flag_set = NfcVSlixDataFlagsHasKeyEas;
break;
default:
break;
}
}
bool slix_generic_protocol_filter(
FuriHalNfcTxRxContext* tx_rx,
FuriHalNfcDevData* nfc_data,
@@ -150,7 +301,8 @@ bool slix_generic_protocol_filter(
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
NfcVSlixData* slix = &nfcv_data->sub_data.slix;
if(slix->privacy && ctx->command != NFCV_CMD_NXP_GET_RANDOM_NUMBER &&
if((slix->flags & NfcVSlixDataFlagsPrivacy) &&
ctx->command != NFCV_CMD_NXP_GET_RANDOM_NUMBER &&
ctx->command != NFCV_CMD_NXP_SET_PASSWORD) {
snprintf(
nfcv_data->last_command,
@@ -186,66 +338,73 @@ bool slix_generic_protocol_filter(
}
case NFCV_CMD_NXP_SET_PASSWORD: {
/* the password to be set is the first parameter */
uint8_t password_id = nfcv_data->frame[ctx->payload_offset];
/* right after that is the XORed password */
uint8_t* password_xored = &nfcv_data->frame[ctx->payload_offset + 1];
/* only handle if the password type is supported */
if(!(password_id & password_supported)) {
break;
}
uint8_t* password_xored = &nfcv_data->frame[ctx->payload_offset + 1];
/* fetch the last RAND value */
uint8_t* rand = slix->rand;
uint8_t* password = NULL;
/* first calc the password that has been sent */
uint8_t password_rcv[4];
switch(password_id) {
case SLIX_PASS_READ:
password = slix->key_read;
break;
case SLIX_PASS_WRITE:
password = slix->key_write;
break;
case SLIX_PASS_PRIVACY:
password = slix->key_privacy;
break;
case SLIX_PASS_DESTROY:
password = slix->key_destroy;
break;
case SLIX_PASS_EASAFI:
password = slix->key_eas;
break;
default:
break;
for(int pos = 0; pos < 4; pos++) {
password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2];
}
uint32_t pass_received = slix_read_be(password_rcv, 4);
/* then determine the password type (or even update if not set yet) */
uint8_t* password = NULL;
uint32_t flag_valid = 0;
uint32_t flag_set = 0;
slix_generic_pass_infos(password_id, slix, &password, &flag_valid, &flag_set);
/* when the password is not supported, return silently */
if(!password) {
break;
}
for(int pos = 0; pos < 4; pos++) {
password_rcv[pos] = password_xored[3 - pos] ^ rand[pos % 2];
}
uint32_t pass_expect = slix_read_be(password, 4);
uint32_t pass_received = slix_read_be(password_rcv, 4);
/* check if the password is known */
bool pass_valid = false;
uint32_t pass_expect = 0;
/* if the password is all-zeroes, just accept any password*/
if(!pass_expect || pass_expect == pass_received) {
if(slix->flags & flag_set) {
/* if so, fetch the stored password and compare */
pass_expect = slix_read_be(password, 4);
pass_valid = (pass_expect == pass_received);
} else {
/* if not known, just accept it and store that password */
memcpy(password, password_rcv, 4);
nfcv_data->modified = true;
slix->flags |= flag_set;
pass_valid = true;
}
/* if the pass was valid or accepted for other reasons, continue */
if(pass_valid) {
slix->flags |= flag_valid;
/* handle actions when a correct password was given, aside of setting the flag */
switch(password_id) {
case SLIX_PASS_READ:
break;
case SLIX_PASS_WRITE:
break;
case SLIX_PASS_PRIVACY:
slix->privacy = false;
slix->flags &= ~NfcVSlixDataFlagsPrivacy;
nfcv_data->modified = true;
break;
case SLIX_PASS_DESTROY:
slix->flags |= NfcVSlixDataFlagsDestroyed;
FURI_LOG_D(TAG, "Pooof! Got destroyed");
break;
case SLIX_PASS_EASAFI:
break;
default:
break;
}
ctx->response_buffer[0] = NFCV_NOERROR;
nfcv_emu_send(
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
@@ -268,6 +427,49 @@ bool slix_generic_protocol_filter(
break;
}
case NFCV_CMD_NXP_WRITE_PASSWORD: {
uint8_t password_id = nfcv_data->frame[ctx->payload_offset];
if(!(password_id & password_supported)) {
break;
}
uint8_t* new_password = &nfcv_data->frame[ctx->payload_offset + 1];
uint8_t* password = NULL;
uint32_t flag_valid = 0;
uint32_t flag_set = 0;
slix_generic_pass_infos(password_id, slix, &password, &flag_valid, &flag_set);
/* when the password is not supported, return silently */
if(!password) {
break;
}
bool pass_valid = (slix->flags & flag_valid);
if(!(slix->flags & flag_set)) {
pass_valid = true;
}
if(pass_valid) {
slix->flags |= flag_valid;
slix->flags |= flag_set;
memcpy(password, new_password, 4);
ctx->response_buffer[0] = NFCV_NOERROR;
nfcv_emu_send(
tx_rx, nfcv_data, ctx->response_buffer, 1, ctx->response_flags, ctx->send_time);
snprintf(
nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE_PASSWORD OK");
} else {
snprintf(
nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE_PASSWORD FAIL");
}
handled = true;
break;
}
case NFCV_CMD_NXP_ENABLE_PRIVACY: {
ctx->response_buffer[0] = NFCV_NOERROR;
@@ -278,7 +480,7 @@ bool slix_generic_protocol_filter(
sizeof(nfcv_data->last_command),
"NFCV_CMD_NXP_ENABLE_PRIVACY");
slix->privacy = true;
slix->flags |= NfcVSlixDataFlagsPrivacy;
handled = true;
break;
}
@@ -315,7 +517,10 @@ void slix_l_prepare(NfcVData* nfcv_data) {
FURI_LOG_D(
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
FURI_LOG_D(
TAG,
" Privacy mode: %s",
(nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsPrivacy) ? "ON" : "OFF");
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
ctx->emu_protocol_filter = &slix_l_protocol_filter;
@@ -345,7 +550,10 @@ void slix_s_prepare(NfcVData* nfcv_data) {
FURI_LOG_D(
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
FURI_LOG_D(
TAG,
" Privacy mode: %s",
(nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsPrivacy) ? "ON" : "OFF");
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
ctx->emu_protocol_filter = &slix_s_protocol_filter;
@@ -375,7 +583,10 @@ void slix_prepare(NfcVData* nfcv_data) {
FURI_LOG_D(
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
FURI_LOG_D(
TAG,
" Privacy mode: %s",
(nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsPrivacy) ? "ON" : "OFF");
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
ctx->emu_protocol_filter = &slix_protocol_filter;
@@ -389,6 +600,10 @@ bool slix2_protocol_filter( // -V524
furi_assert(nfc_data);
furi_assert(nfcv_data_in);
NfcVData* nfcv_data = (NfcVData*)nfcv_data_in;
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
NfcVSlixData* slix = &nfcv_data->sub_data.slix;
bool handled = false;
/* many SLIX share some of the functions, place that in a generic handler */
@@ -396,6 +611,157 @@ bool slix2_protocol_filter( // -V524
return true;
}
switch(ctx->command) {
/* override WRITE BLOCK for block 79 (16 bit counter) */
case NFCV_CMD_WRITE_BLOCK:
case NFCV_CMD_WRITE_MULTI_BLOCK: {
uint8_t resp_len = 1;
uint8_t blocks = 1;
uint8_t block = nfcv_data->frame[ctx->payload_offset];
uint8_t data_pos = ctx->payload_offset + 1;
if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) {
blocks = nfcv_data->frame[data_pos] + 1;
data_pos++;
}
uint8_t* data = &nfcv_data->frame[data_pos];
uint32_t data_len = nfcv_data->block_size * blocks;
if((block + blocks) <= nfcv_data->block_num &&
(data_pos + data_len + 2) == nfcv_data->frame_length) {
ctx->response_buffer[0] = NFCV_NOERROR;
for(int block_num = block; block_num < block + blocks; block_num++) {
/* special case, 16-bit counter */
if(block_num == 79) {
uint32_t dest;
uint32_t ctr_old;
memcpy(&dest, &nfcv_data->frame[data_pos], 4);
memcpy(&ctr_old, &nfcv_data->data[nfcv_data->block_size * block_num], 4);
uint32_t ctr_new = ctr_old;
bool allowed = true;
/* increment counter */
if(dest == 1) {
ctr_new = (ctr_old & 0xFFFF0000) | ((ctr_old + 1) & 0xFFFF);
/* protection flag set? */
if(ctr_old & 0x01000000) {
allowed = nfcv_data->sub_data.slix.flags &
NfcVSlixDataFlagsValidKeyRead;
}
} else {
ctr_new = dest;
allowed = nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsValidKeyWrite;
}
if(allowed) {
memcpy(&nfcv_data->data[nfcv_data->block_size * block_num], &ctr_new, 4);
} else {
/* incorrect read or write password */
ctx->response_buffer[0] = NFCV_RES_FLAG_ERROR;
ctx->response_buffer[1] = NFCV_ERROR_GENERIC;
resp_len = 2;
}
} else {
memcpy(
&nfcv_data->data[nfcv_data->block_size * block_num],
&nfcv_data->frame[data_pos],
nfcv_data->block_size);
}
data_pos += nfcv_data->block_size;
}
nfcv_data->modified = true;
} else {
ctx->response_buffer[0] = NFCV_RES_FLAG_ERROR;
ctx->response_buffer[1] = NFCV_ERROR_GENERIC;
resp_len = 2;
}
bool respond = (ctx->response_buffer[0] == NFCV_NOERROR) ||
(ctx->addressed || ctx->selected);
if(respond) {
nfcv_emu_send(
tx_rx,
nfcv_data,
ctx->response_buffer,
resp_len,
ctx->response_flags,
ctx->send_time);
}
if(ctx->command == NFCV_CMD_WRITE_MULTI_BLOCK) {
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"WRITE MULTI BLOCK %d, %d blocks",
block,
blocks);
} else {
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"WRITE BLOCK %d <- %02X %02X %02X %02X",
block,
data[0],
data[1],
data[2],
data[3]);
}
handled = true;
break;
}
case NFCV_CMD_NXP_READ_SIGNATURE: {
uint32_t len = 0;
ctx->response_buffer[len++] = NFCV_NOERROR;
memcpy(&ctx->response_buffer[len], slix->signature, sizeof(slix->signature));
len += sizeof(slix->signature);
nfcv_emu_send(
tx_rx, nfcv_data, ctx->response_buffer, len, ctx->response_flags, ctx->send_time);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ_SIGNATURE");
handled = true;
break;
}
case NFCV_CMD_NXP_GET_NXP_SYSTEM_INFORMATION: {
uint32_t len = 0;
uint8_t lock_bits = 0;
/* convert our internal lock bits format into NXP's */
lock_bits |= (nfcv_data->security_status[0] & NfcVLockBitDsfid) ? SlixLockBitDsfid : 0;
lock_bits |= (nfcv_data->security_status[0] & NfcVLockBitAfi) ? SlixLockBitAfi : 0;
lock_bits |= (nfcv_data->security_status[0] & NfcVLockBitEas) ? SlixLockBitEas : 0;
lock_bits |= (nfcv_data->security_status[0] & NfcVLockBitPpl) ? SlixLockBitPpl : 0;
ctx->response_buffer[len++] = NFCV_NOERROR;
ctx->response_buffer[len++] = nfcv_data->sub_data.slix.pp_pointer;
ctx->response_buffer[len++] = nfcv_data->sub_data.slix.pp_condition;
ctx->response_buffer[len++] = lock_bits;
ctx->response_buffer[len++] = 0x7F; /* features LSB */
ctx->response_buffer[len++] = 0x35; /* features */
ctx->response_buffer[len++] = 0; /* features */
ctx->response_buffer[len++] = 0; /* features MSB */
nfcv_emu_send(
tx_rx, nfcv_data, ctx->response_buffer, len, ctx->response_flags, ctx->send_time);
snprintf(
nfcv_data->last_command,
sizeof(nfcv_data->last_command),
"GET_NXP_SYSTEM_INFORMATION");
handled = true;
break;
}
}
return handled;
}
@@ -405,7 +771,10 @@ void slix2_prepare(NfcVData* nfcv_data) {
FURI_LOG_D(
TAG, " Destroy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_destroy, 4));
FURI_LOG_D(TAG, " EAS pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_eas, 4));
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix.privacy ? "ON" : "OFF");
FURI_LOG_D(
TAG,
" Privacy mode: %s",
(nfcv_data->sub_data.slix.flags & NfcVSlixDataFlagsPrivacy) ? "ON" : "OFF");
NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
ctx->emu_protocol_filter = &slix2_protocol_filter;

View File

@@ -8,19 +8,35 @@
#define NFCV_MANUFACTURER_NXP 0x04
/* ISO15693-3 CUSTOM NXP COMMANDS */
#define NFCV_CMD_NXP_SET_EAS 0xA2
#define NFCV_CMD_NXP_RESET_EAS 0xA3
#define NFCV_CMD_NXP_LOCK_EAS 0xA4
#define NFCV_CMD_NXP_EAS_ALARM 0xA5
#define NFCV_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6
#define NFCV_CMD_NXP_WRITE_EAS_ID 0xA7
#define NFCV_CMD_NXP_INVENTORY_PAGE_READ 0xB0
#define NFCV_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1
#define NFCV_CMD_NXP_GET_RANDOM_NUMBER 0xB2
#define NFCV_CMD_NXP_SET_PASSWORD 0xB3
#define NFCV_CMD_NXP_WRITE_PASSWORD 0xB4
#define NFCV_CMD_NXP_DESTROY 0xB9
#define NFCV_CMD_NXP_ENABLE_PRIVACY 0xBA
typedef enum {
NFCV_CMD_NXP_SET_EAS = 0xA2,
NFCV_CMD_NXP_RESET_EAS = 0xA3,
NFCV_CMD_NXP_LOCK_EAS = 0xA4,
NFCV_CMD_NXP_EAS_ALARM = 0xA5,
NFCV_CMD_NXP_PASSWORD_PROTECT_EAS_AFI = 0xA6,
NFCV_CMD_NXP_WRITE_EAS_ID = 0xA7,
NFCV_CMD_NXP_GET_NXP_SYSTEM_INFORMATION = 0xAB,
NFCV_CMD_NXP_INVENTORY_PAGE_READ = 0xB0,
NFCV_CMD_NXP_INVENTORY_PAGE_READ_FAST = 0xB1,
NFCV_CMD_NXP_GET_RANDOM_NUMBER = 0xB2,
NFCV_CMD_NXP_SET_PASSWORD = 0xB3,
NFCV_CMD_NXP_WRITE_PASSWORD = 0xB4,
NFCV_CMD_NXP_64_BIT_PASSWORD_PROTECTION = 0xB5,
NFCV_CMD_NXP_PROTECT_PAGE = 0xB6,
NFCV_CMD_NXP_LOCK_PAGE_PROTECTION_CONDITION = 0xB7,
NFCV_CMD_NXP_DESTROY = 0xB9,
NFCV_CMD_NXP_ENABLE_PRIVACY = 0xBA,
NFCV_CMD_NXP_STAY_QUIET_PERSISTENT = 0xBC,
NFCV_CMD_NXP_READ_SIGNATURE = 0xBD
} SlixCommands;
/* lock bit bits used in SLIX's NXP SYSTEM INFORMATION response */
typedef enum {
SlixLockBitAfi = 1 << 0,
SlixLockBitEas = 1 << 1,
SlixLockBitDsfid = 1 << 2,
SlixLockBitPpl = 1 << 3,
} SlixLockBits;
/* available passwords */
#define SLIX_PASS_READ 0x01
@@ -37,6 +53,10 @@ bool slix2_check_card_type(FuriHalNfcDevData* nfc_data);
bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data);
bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data);
ReturnCode slix2_read_custom(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data);
ReturnCode slix2_read_signature(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data);
ReturnCode slix2_read_nxp_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data);
ReturnCode slix_get_random(NfcVData* data);
ReturnCode slix_unlock(NfcVData* data, uint32_t password_id);