Revert "Merge branch 'pr/446' into 420"

This reverts commit 761dc48b3e, reversing
changes made to 91f037c63f.
This commit is contained in:
RogueMaster
2022-11-25 03:08:53 -05:00
parent d9e7780fb9
commit 28cc99ad2d
40 changed files with 184 additions and 3617 deletions

View File

@@ -36,7 +36,7 @@ uint32_t crypto1_filter(uint32_t in) {
return FURI_BIT(0xEC57E80A, out);
}
static inline uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) {
uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted) {
furi_assert(crypto1);
uint8_t out = crypto1_filter(crypto1->odd);
uint32_t feed = out & (!!is_encrypted);
@@ -58,15 +58,6 @@ uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted) {
return out;
}
static inline uint8_t crypto1_byte_inline(Crypto1* crypto1, uint8_t in, int is_encrypted) {
furi_assert(crypto1);
uint8_t out = 0;
for(uint8_t i = 0; i < 8; i++) {
out |= crypto1_bit(crypto1, FURI_BIT(in, i), is_encrypted) << i;
}
return out;
}
uint32_t crypto1_word(Crypto1* crypto1, uint32_t in, int is_encrypted) {
furi_assert(crypto1);
uint32_t out = 0;
@@ -101,7 +92,7 @@ void crypto1_decrypt(
decrypted_data[0] = decrypted_byte;
} else {
for(size_t i = 0; i < encrypted_data_bits / 8; i++) {
decrypted_data[i] = crypto1_byte_inline(crypto, 0, 0) ^ encrypted_data[i];
decrypted_data[i] = crypto1_byte(crypto, 0, 0) ^ encrypted_data[i];
}
}
}
@@ -126,7 +117,7 @@ void crypto1_encrypt(
} else {
memset(encrypted_parity, 0, plain_data_bits / 8 + 1);
for(uint8_t i = 0; i < plain_data_bits / 8; i++) {
encrypted_data[i] = crypto1_byte_inline(crypto, keystream ? keystream[i] : 0, 0) ^
encrypted_data[i] = crypto1_byte(crypto, keystream ? keystream[i] : 0, 0) ^
plain_data[i];
encrypted_parity[i / 8] |=
(((crypto1_filter(crypto->odd) ^ nfc_util_odd_parity8(plain_data[i])) & 0x01)

View File

@@ -12,7 +12,7 @@ void crypto1_reset(Crypto1* crypto1);
void crypto1_init(Crypto1* crypto1, uint64_t key);
//uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted);
uint8_t crypto1_bit(Crypto1* crypto1, uint8_t in, int is_encrypted);
uint8_t crypto1_byte(Crypto1* crypto1, uint8_t in, int is_encrypted);

View File

@@ -763,39 +763,26 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
uint8_t plain_data[MF_CLASSIC_MAX_DATA_SIZE];
MfClassicKey access_key = MfClassicKeyA;
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
FURI_LOG_D(TAG, "Starting mf_classic_emulator");
// Read command
while(!command_processed) {
if(!is_encrypted) {
crypto1_reset(&emulator->crypto);
memcpy(plain_data, tx_rx->rx_data, tx_rx->rx_bits / 8);
} else {
tx_rx->rx_bits = 0;
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) {
FURI_LOG_D(
TAG,
"Error in tx rx. Tx :%d bits, Rx: %d bits. Received:",
"Error in tx rx. Tx :%d bits, Rx: %d bits",
tx_rx->tx_bits,
tx_rx->rx_bits);
FURI_LOG_D(TAG,"Sent:");
for(int pos = 0; pos < tx_rx->tx_bits/8; pos++) {
FURI_LOG_D(TAG," %02X", tx_rx->tx_data[pos]);
}
FURI_LOG_D(TAG,"Received:");
for(int pos = 0; pos < tx_rx->rx_bits/8; pos++) {
FURI_LOG_D(TAG," %02X", tx_rx->rx_data[pos]);
}
break;
}
crypto1_decrypt(&emulator->crypto, tx_rx->rx_data, tx_rx->rx_bits, plain_data);
}
if(plain_data[0] == 0x50 && plain_data[1] == 0x00) {
//furi_hal_nfc_listen_sleep();
FURI_LOG_T(TAG, "Halt received");
furi_hal_nfc_listen_sleep();
command_processed = true;
break;
} else if(plain_data[0] == 0x60 || plain_data[0] == 0x61) {
@@ -812,7 +799,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
access_key = MfClassicKeyB;
}
uint32_t nonce = prng_successor(DWT->CYCCNT, 2) ^ 0xAA;
uint32_t nonce = prng_successor(DWT->CYCCNT, 32) ^ 0xAA;
uint8_t nt[4];
uint8_t nt_keystream[4];
nfc_util_num2bytes(nonce, 4, nt);
@@ -820,15 +807,13 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
crypto1_init(&emulator->crypto, key);
if(!is_encrypted) {
crypto1_word(&emulator->crypto, emulator->cuid ^ nonce, 0);
for(size_t pos = 0; pos < sizeof(nt); pos++) {
tx_rx->tx_data[pos] = nt[pos];
}
memcpy(tx_rx->tx_data, nt, sizeof(nt));
tx_rx->tx_parity[0] = 0;
for(size_t i = 0; i < sizeof(nt); i++) {
tx_rx->tx_parity[0] |= nfc_util_odd_parity8(nt[i]) << (7 - i);
}
tx_rx->tx_bits = sizeof(nt) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
} else {
crypto1_encrypt(
&emulator->crypto,
@@ -838,10 +823,10 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
tx_rx->tx_data,
tx_rx->tx_parity);
tx_rx->tx_bits = sizeof(nt) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
}
if(!furi_hal_nfc_tx_rx(tx_rx, 500)) {
FURI_LOG_E(TAG, "Error in NT exchange?");
FURI_LOG_E(TAG, "Error in NT exchange");
command_processed = true;
break;
}
@@ -854,7 +839,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
uint32_t nr = nfc_util_bytes2num(tx_rx->rx_data, 4);
uint32_t ar = nfc_util_bytes2num(&tx_rx->rx_data[4], 4);
/*
FURI_LOG_D(
TAG,
"%08lx key%c block %d nt/nr/ar: %08lx %08lx %08lx",
@@ -864,7 +849,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
nonce,
nr,
ar);
*/
crypto1_word(&emulator->crypto, nr, 1);
uint32_t cardRr = ar ^ crypto1_word(&emulator->crypto, 0, 0);
if(cardRr != prng_successor(nonce, 64)) {
@@ -885,7 +870,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
tx_rx->tx_data,
tx_rx->tx_parity);
tx_rx->tx_bits = sizeof(responce) * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
is_encrypted = true;
} else if(is_encrypted && plain_data[0] == 0x30) {
@@ -916,7 +901,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
} else {
tx_rx->tx_data[0] = nack;
}
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
tx_rx->tx_bits = 4;
furi_hal_nfc_tx_rx(tx_rx, 300);
break;
@@ -932,7 +917,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
tx_rx->tx_data,
tx_rx->tx_parity);
tx_rx->tx_bits = 18 * 8;
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
} else if(is_encrypted && plain_data[0] == 0xA0) {
uint8_t block = plain_data[1];
if(block > mf_classic_get_total_block_num(emulator->data.type)) {
@@ -941,7 +926,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
// Send ACK
uint8_t ack = 0x0A;
crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity);
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
tx_rx->tx_bits = 4;
if(!furi_hal_nfc_tx_rx(tx_rx, 300)) break;
@@ -976,10 +961,9 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
// Send ACK
ack = 0x0A;
crypto1_encrypt(&emulator->crypto, NULL, &ack, 4, tx_rx->tx_data, tx_rx->tx_parity);
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
tx_rx->tx_bits = 4;
} else {
FURI_LOG_T(TAG, "%02X unknown received", plain_data[0]);
// Unknown command
break;
}
@@ -993,7 +977,7 @@ bool mf_classic_emulator(MfClassicEmulator* emulator, FuriHalNfcTxRxContext* tx_
} else {
tx_rx->tx_data[0] = nack;
}
tx_rx->tx_rx_type = FuriHalNfcTxRxFullyTransparent;
tx_rx->tx_rx_type = FuriHalNfcTxRxTransparent;
tx_rx->tx_bits = 4;
furi_hal_nfc_tx_rx(tx_rx, 300);
}

View File

@@ -2,27 +2,19 @@
#include <string.h>
#include <stdio.h>
#include <furi.h>
#include <furi_hal_gpio.h>
#include <furi_hal_resources.h>
#define NFCA_CMD_RATS (0xE0U)
#define NFCA_CRC_INIT (0x6363)
#define NFCA_F_SIG (13560000.0) /* [Hz] NFC frequency */
#define NFCA_F_SUB (NFCA_F_SIG/16) /* [Hz] NFC subcarrier frequency fs/16 (847500 Hz) */
#define T_SUB (1000000000000.0f / NFCA_F_SUB) /* [ps] subcarrier period = 1/NFCA_F_SUB (1.18 µs) */
#define T_SUB_PHASE (T_SUB/2) /* [ps] a single subcarrier phase (590 µs) */
#define NFCA_F_SIG (13560000.0)
#define T_SIG 7374 //73.746ns*100
#define T_SIG_x8 58992 //T_SIG*8
#define T_SIG_x8_x8 471936 //T_SIG*8*8
#define T_SIG_x8_x9 530928 //T_SIG*8*9
#define NFCA_SIGNAL_MAX_EDGES (1350)
#define SEQ_SOF 0
#define SEQ_BIT0 1
#define SEQ_BIT1 2
#define SEQ_EOF 3
#define SEQ_IDLE 4
typedef struct {
uint8_t cmd;
uint8_t param;
@@ -71,69 +63,46 @@ bool nfca_emulation_handler(
return sleep;
}
static void nfca_add_bit(DigitalSignal* signal, bool bit) {
if(bit) {
signal->start_level = true;
for(size_t i = 0; i < 7; i++) {
signal->edge_timings[i] = T_SIG_x8;
}
signal->edge_timings[7] = T_SIG_x8_x9;
signal->edge_cnt = 8;
} else {
signal->start_level = false;
signal->edge_timings[0] = T_SIG_x8_x8;
for(size_t i = 1; i < 9; i++) {
signal->edge_timings[i] = T_SIG_x8;
}
signal->edge_cnt = 9;
}
}
static void nfca_add_byte(NfcaSignal* nfca_signal, uint8_t byte, bool parity) {
for(uint8_t i = 0; i < 8; i++) {
if(byte & (1 << i)) {
digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT1);
digital_signal_append(nfca_signal->tx_signal, nfca_signal->one);
} else {
digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT0);
digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero);
}
}
if(parity) {
digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT1);
digital_signal_append(nfca_signal->tx_signal, nfca_signal->one);
} else {
digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT0);
}
}
static void nfca_add_modulation(DigitalSignal* signal, size_t phases) {
for(size_t i = 0; i < phases; i++) {
signal->edge_timings[signal->edge_cnt++] = DIGITAL_SIGNAL_PS(T_SUB_PHASE);
}
}
static void nfca_add_silence(DigitalSignal* signal, size_t phases) {
bool end_level = signal->start_level ^ ((signal->edge_cnt % 2) == 0);
if((signal->edge_cnt == 0) || end_level) {
signal->edge_timings[signal->edge_cnt++] = DIGITAL_SIGNAL_PS(phases * T_SUB_PHASE);
} else {
signal->edge_timings[signal->edge_cnt - 1] += DIGITAL_SIGNAL_PS(phases * T_SUB_PHASE);
digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero);
}
}
NfcaSignal* nfca_signal_alloc() {
NfcaSignal* nfca_signal = malloc(sizeof(NfcaSignal));
/* ISO14443-2 defines 3 sequences for type A communication */
nfca_signal->seq_d = digital_signal_alloc(10);
nfca_signal->seq_e = digital_signal_alloc(10);
nfca_signal->seq_f = digital_signal_alloc(10);
/* SEQ D has the first half modulated, used as SOF */
nfca_signal->seq_d->start_level = true;
nfca_add_modulation(nfca_signal->seq_d, 8);
nfca_add_silence(nfca_signal->seq_d, 8);
/* SEQ E has the second half modulated */
nfca_signal->seq_e->start_level = false;
nfca_add_silence(nfca_signal->seq_e, 8);
nfca_add_modulation(nfca_signal->seq_e, 8);
/* SEQ F is just no modulation, used as EOF */
nfca_signal->seq_f->start_level = false;
nfca_add_silence(nfca_signal->seq_f, 16);
nfca_signal->tx_signal = digital_sequence_alloc(NFCA_SIGNAL_MAX_EDGES, &gpio_spi_r_mosi);
/* we are dealing with shorter sequences, enable bake-before-sending */
//nfca_signal->tx_signal->bake = true;
digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_SOF, nfca_signal->seq_d);
digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_BIT0, nfca_signal->seq_e);
digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_BIT1, nfca_signal->seq_d);
digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_EOF, nfca_signal->seq_f);
digital_sequence_set_signal(nfca_signal->tx_signal, SEQ_IDLE, nfca_signal->seq_f);
nfca_signal->one = digital_signal_alloc(10);
nfca_signal->zero = digital_signal_alloc(10);
nfca_add_bit(nfca_signal->one, true);
nfca_add_bit(nfca_signal->zero, false);
nfca_signal->tx_signal = digital_signal_alloc(NFCA_SIGNAL_MAX_EDGES);
return nfca_signal;
}
@@ -141,10 +110,9 @@ NfcaSignal* nfca_signal_alloc() {
void nfca_signal_free(NfcaSignal* nfca_signal) {
furi_assert(nfca_signal);
digital_signal_free(nfca_signal->seq_d);
digital_signal_free(nfca_signal->seq_e);
digital_signal_free(nfca_signal->seq_f);
digital_sequence_free(nfca_signal->tx_signal);
digital_signal_free(nfca_signal->one);
digital_signal_free(nfca_signal->zero);
digital_signal_free(nfca_signal->tx_signal);
free(nfca_signal);
}
@@ -153,18 +121,17 @@ void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, u
furi_assert(data);
furi_assert(parity);
digital_sequence_clear(nfca_signal->tx_signal);
/* add some idle bit times before SOF in case the GPIO was active */
digital_sequence_add(nfca_signal->tx_signal, SEQ_IDLE);
digital_sequence_add(nfca_signal->tx_signal, SEQ_SOF);
nfca_signal->tx_signal->edge_cnt = 0;
nfca_signal->tx_signal->start_level = true;
// Start of frame
digital_signal_append(nfca_signal->tx_signal, nfca_signal->one);
if(bits < 8) {
for(size_t i = 0; i < bits; i++) {
if(FURI_BIT(data[0], i)) {
digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT1);
digital_signal_append(nfca_signal->tx_signal, nfca_signal->one);
} else {
digital_sequence_add(nfca_signal->tx_signal, SEQ_BIT0);
digital_signal_append(nfca_signal->tx_signal, nfca_signal->zero);
}
}
} else {
@@ -172,6 +139,4 @@ void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, u
nfca_add_byte(nfca_signal, data[i], parity[i / 8] & (1 << (7 - (i & 0x07))));
}
}
digital_sequence_add(nfca_signal->tx_signal, SEQ_EOF);
}

View File

@@ -6,10 +6,9 @@
#include <lib/digital_signal/digital_signal.h>
typedef struct {
DigitalSignal* seq_d; /* sequence D, modulation with subcarrier during first half */
DigitalSignal* seq_e; /* sequence E, modulation with subcarrier during second half */
DigitalSignal* seq_f; /* sequence F, no modulation at all */
DigitalSequence* tx_signal;
DigitalSignal* one;
DigitalSignal* zero;
DigitalSignal* tx_signal;
} NfcaSignal;
uint16_t nfca_get_crc16(uint8_t* buff, uint16_t len);
@@ -27,4 +26,3 @@ NfcaSignal* nfca_signal_alloc();
void nfca_signal_free(NfcaSignal* nfca_signal);
void nfca_signal_encode(NfcaSignal* nfca_signal, uint8_t* data, uint16_t bits, uint8_t* parity);

View File

@@ -1,172 +0,0 @@
#include <limits.h>
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_nfc.h>
#include <furi_hal_spi.h>
#include <furi_hal_gpio.h>
#include <furi_hal_cortex.h>
#include <furi_hal_resources.h>
#include <st25r3916.h>
#include <st25r3916_irq.h>
#include "nfca_trans_rx.h"
#define TAG "NfcA-trans-rx"
void nfca_trans_rx_init(NfcaTransRxState *state) {
FURI_LOG_D(TAG, "Starting NfcA transparent rx");
st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0xC3);
st25r3916WriteRegister(ST25R3916_REG_MODE, 0x88);
st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE);
furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc);
/* allocate a 512 edge buffer, more than enough */
state->reader_signal = pulse_reader_alloc(&gpio_spi_r_miso, 512);
/* timebase shall be 1 ns */
pulse_reader_set_timebase(state->reader_signal, PulseReaderUnitNanosecond);
pulse_reader_start(state->reader_signal);
/* set start values */
state->bits_received = 0;
state->have_sof = false;
state->valid_frame = false;
}
void nfca_trans_rx_deinit(NfcaTransRxState *state) {
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
pulse_reader_free(state->reader_signal);
}
void nfca_trans_rx_pause(NfcaTransRxState *state) {
pulse_reader_stop(state->reader_signal);
}
void nfca_trans_rx_continue(NfcaTransRxState *state) {
pulse_reader_start(state->reader_signal);
}
static void nfca_bit_received(NfcaTransRxState *state, uint8_t bit) {
/* According to ISO14443-3 short frames have 7 bits and standard 9 bits per byte,
where the 9th bit is odd parity. Data is transmitted LSB first. */
uint32_t byte_num = (state->bits_received / 9);
uint32_t bit_num = (state->bits_received % 9);
if(byte_num >= NFCA_FRAME_LENGTH) {
return;
}
if(bit_num == 8) {
uint32_t parity_value = 1 << (state->bits_received / 9);
state->parity_bits &= ~parity_value;
state->parity_bits |= bit ? parity_value : 0;
} else {
uint32_t bit_value = 1 << bit_num;
state->frame_data[byte_num] &= ~bit_value;
state->frame_data[byte_num] |= bit ? bit_value : 0;
}
state->bits_received++;
}
bool nfca_trans_rx_loop(NfcaTransRxState *state, uint32_t timeout_ms) {
furi_assert(state);
state->valid_frame = false;
state->have_sof = false;
state->bits_received = 0;
bool done = false;
uint32_t timeout_us = timeout_ms * 1000;
while(!done) {
uint32_t nsec = pulse_reader_receive(state->reader_signal, timeout_us);
bool eof = state->have_sof && (nsec >= (2 * NFCA_TB));
bool lost_pulse = false;
if(state->have_sof && nsec == PULSE_READER_LOST_EDGE) {
nsec = NFCA_T1;
lost_pulse = true;
} else if(nsec == PULSE_READER_NO_EDGE) {
done = true;
}
if(IS_T1(nsec) || eof) {
timeout_us = (3 * NFCA_TB) / 1000;
if(!state->have_sof) {
state->frame_time = -(NFCA_TB - nsec);
state->have_sof = true;
state->valid_frame = false;
state->bits_received = 0;
state->debug_pos = 0;
if(lost_pulse) {
state->frame_time -= nsec;
}
continue;
}
if(state->frame_time > NFCA_TB_MIN) {
state->frame_time -= NFCA_TB;
nfca_bit_received(state, 0);
}
if(IS_ZERO(state->frame_time)) {
state->frame_time = -(NFCA_TB - nsec);
nfca_bit_received(state, 0);
} else if(IS_TX(state->frame_time)) {
state->frame_time = -(NFCA_TX - nsec);
nfca_bit_received(state, 1);
} else {
if(eof) {
state->have_sof = false;
state->valid_frame = true;
done = true;
} else {
}
}
} else {
if(!state->have_sof) {
if(IS_TB(nsec)) {
state->frame_time = 0;
state->have_sof = true;
state->valid_frame = false;
state->bits_received = 0;
state->debug_pos = 0;
if(lost_pulse) {
state->frame_time -= nsec;
}
continue;
} else {
state->frame_time = 0;
}
} else {
state->frame_time += nsec;
}
}
if(lost_pulse) {
state->frame_time -= nsec;
}
}
if(state->valid_frame) {
if(state->bits_received > 7) {
/* a last 0-bit will look like a missing bit */
if((state->bits_received % 9) == 8) {
nfca_bit_received(state, 0);
state->bits_received++;
}
}
}
return state->valid_frame;
}

View File

@@ -1,54 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <lib/digital_signal/digital_signal.h>
#include <lib/pulse_reader/pulse_reader.h>
#include <furi_hal_nfc.h>
#include "nfc_util.h"
/* assume fc/128 */
#define NFCA_FC (13560000.0f) /* MHz */
#define NFCA_FC_K ((uint32_t)(NFCA_FC/1000)) /* kHz */
#define NFCA_T1 (28.0f / NFCA_FC * 1000000000)
#define NFCA_T1_MIN (24.0f / NFCA_FC * 1000000000)
#define NFCA_T1_MAX (41.0f / NFCA_FC * 1000000000)
#define NFCA_TX (64.0f / NFCA_FC * 1000000000) /* 4.7198 µs */
#define NFCA_TX_MIN (0.90f * NFCA_TX)
#define NFCA_TX_MAX (1.10f * NFCA_TX)
#define NFCA_TB (128.0f / NFCA_FC * 1000000000) /* 9.4395 µs */
#define NFCA_TB_MIN (0.80f * NFCA_TB)
#define NFCA_TB_MAX (1.20f * NFCA_TB)
#define IS_T1(x) ((x)>=NFCA_T1_MIN && (x)<=NFCA_T1_MAX)
#define IS_TX(x) ((x)>=NFCA_TX_MIN && (x)<=NFCA_TX_MAX)
#define IS_TB(x) ((x)>=NFCA_TB_MIN && (x)<=NFCA_TB_MAX)
#define IS_ZERO(x) ((x)>=-NFCA_T1_MIN/2 && (x)<=NFCA_T1_MIN/2)
#define DIGITAL_SIGNAL_UNIT_S (100000000000.0f)
#define DIGITAL_SIGNAL_UNIT_US (100000.0f)
#define NFCA_FRAME_LENGTH 32
#define NFCA_DEBUG_LENGTH 128
typedef struct {
bool have_sof;
bool valid_frame;
int32_t frame_time;
size_t bits_received;
uint8_t frame_data[NFCA_FRAME_LENGTH];
uint32_t debug_buffer[NFCA_DEBUG_LENGTH];
size_t debug_pos;
uint32_t parity_bits;
PulseReader *reader_signal;
} NfcaTransRxState;
bool nfca_trans_rx_loop(NfcaTransRxState *state, uint32_t timeout_ms);
void nfca_trans_rx_deinit(NfcaTransRxState *state);
void nfca_trans_rx_init(NfcaTransRxState *state);
void nfca_trans_rx_pause(NfcaTransRxState *state);
void nfca_trans_rx_continue(NfcaTransRxState *state);

View File

@@ -1,747 +0,0 @@
#include <limits.h>
#include <furi.h>
#include <furi_hal.h>
#include <furi_hal_nfc.h>
#include <furi_hal_spi.h>
#include <furi_hal_gpio.h>
#include <furi_hal_cortex.h>
#include <furi_hal_resources.h>
#include <st25r3916.h>
#include <st25r3916_irq.h>
#include "nfcv.h"
#include "nfc_util.h"
#include "slix.h"
#define TAG "NfcV"
ReturnCode nfcv_inventory(uint8_t* uid) {
uint16_t received = 0;
rfalNfcvInventoryRes res;
ReturnCode ret = ERR_NONE;
for(int tries = 0; tries < 5; tries++) {
/* TODO: needs proper abstraction via fury_hal(_ll)_* */
ret = rfalNfcvPollerInventory(
RFAL_NFCV_NUM_SLOTS_1, 0, NULL, &res, &received);
if(ret == ERR_NONE) {
break;
}
}
if(ret == ERR_NONE) {
if(uid != NULL) {
memcpy(uid, res.UID, 8);
}
}
return ret;
}
ReturnCode nfcv_read_blocks(
NfcVReader* reader,
NfcVData* data) {
UNUSED(reader);
uint16_t received = 0;
for(size_t block = 0; block < data->block_num; block++) {
uint8_t rxBuf[32];
FURI_LOG_D(TAG, "Reading block %d/%d", block, (data->block_num - 1));
ReturnCode ret = ERR_NONE;
for(int tries = 0; tries < 5; tries++) {
ret = rfalNfcvPollerReadSingleBlock(
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, block,
rxBuf, sizeof(rxBuf), &received);
if(ret == ERR_NONE) {
break;
}
}
if(ret != ERR_NONE) {
FURI_LOG_D(TAG, "failed to read: %d", ret);
return ret;
}
memcpy(&(data->data[block * data->block_size]), &rxBuf[1], data->block_size);
FURI_LOG_D(TAG, " %02X %02X %02X %02X",
data->data[block * data->block_size + 0], data->data[block * data->block_size + 1],
data->data[block * data->block_size + 2], data->data[block * data->block_size + 3]);
}
return ERR_NONE;
}
ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data) {
uint8_t rxBuf[32];
uint16_t received = 0;
ReturnCode ret = ERR_NONE;
FURI_LOG_D(TAG, "Read SYSTEM INFORMATION...");
for(int tries = 0; tries < 5; tries++) {
/* TODO: needs proper abstraction via fury_hal(_ll)_* */
ret = rfalNfcvPollerGetSystemInformation(
RFAL_NFCV_REQ_FLAG_DEFAULT, NULL, rxBuf, sizeof(rxBuf), &received);
if(ret == ERR_NONE) {
break;
}
}
if(ret == ERR_NONE) {
nfc_data->type = FuriHalNfcTypeV;
nfc_data->uid_len = 8;
/* UID is stored reversed in this response */
for(int pos = 0; pos < nfc_data->uid_len; pos++) {
nfc_data->uid[pos] = rxBuf[2 + (7 - pos)];
}
data->dsfid = rxBuf[10];
data->afi = rxBuf[11];
data->block_num = rxBuf[12] + 1;
data->block_size = rxBuf[13] + 1;
data->ic_ref = rxBuf[14];
FURI_LOG_D(TAG, " UID: %02X %02X %02X %02X %02X %02X %02X %02X",
nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3],
nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]);
FURI_LOG_D(TAG, " DSFID %d, AFI %d, Blocks %d, Size %d, IC Ref %d", data->dsfid, data->afi, data->block_num, data->block_size, data->ic_ref);
return ret;
}
FURI_LOG_D(TAG, "Failed: %d", ret);
return ret;
}
bool nfcv_read_card(
NfcVReader* reader,
FuriHalNfcDevData* nfc_data,
NfcVData* nfcv_data) {
furi_assert(reader);
furi_assert(nfc_data);
furi_assert(nfcv_data);
if(nfcv_read_sysinfo(nfc_data, nfcv_data) != ERR_NONE) {
return false;
}
if(nfcv_read_blocks(reader, nfcv_data) != ERR_NONE) {
return false;
}
if(slix_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX detected");
nfcv_data->type = NfcVTypeSlix;
} else if(slix2_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX2 detected");
nfcv_data->type = NfcVTypeSlix2;
} else if(slix_s_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX-S detected");
nfcv_data->type = NfcVTypeSlixS;
} else if(slix_l_check_card_type(nfc_data)) {
FURI_LOG_I(TAG, "NXP SLIX-L detected");
nfcv_data->type = NfcVTypeSlixL;
} else {
nfcv_data->type = NfcVTypePlain;
}
return true;
}
/* emulation part */
PulseReader *reader_signal = NULL;
DigitalSignal* nfcv_resp_pulse_32 = NULL;
DigitalSignal* nfcv_resp_unmod = NULL;
DigitalSignal* nfcv_resp_one = NULL;
DigitalSignal* nfcv_resp_zero = NULL;
DigitalSignal* nfcv_resp_sof = NULL;
DigitalSignal* nfcv_resp_eof = NULL;
DigitalSignal* nfcv_resp_unmod_256 = NULL;
DigitalSignal* nfcv_resp_unmod_768 = NULL;
//const GpioPin* nfcv_out_io = &gpio_ext_pb2;
const GpioPin* nfcv_out_io = &gpio_spi_r_mosi;
DigitalSequence* nfcv_signal = NULL;
#define SIG_SOF 0
#define SIG_BIT0 1
#define SIG_BIT1 2
#define SIG_EOF 3
void nfcv_crc(uint8_t* data, uint32_t length, uint8_t* out) {
uint32_t reg = 0xFFFF;
uint32_t i = 0;
uint32_t j = 0;
for (i = 0; i < length; i++) {
reg = reg ^ ((uint32_t)data[i]);
for (j = 0; j < 8; j++) {
if (reg & 0x0001) {
reg = (reg >> 1) ^ 0x8408;
} else {
reg = (reg >> 1);
}
}
}
uint16_t crc = ~(uint16_t)(reg & 0xffff);
out[0] = crc & 0xFF;
out[1] = crc >> 8;
}
void nfcv_emu_free() {
digital_sequence_free(nfcv_signal);
digital_signal_free(nfcv_resp_unmod_256);
digital_signal_free(nfcv_resp_pulse_32);
digital_signal_free(nfcv_resp_one);
digital_signal_free(nfcv_resp_zero);
digital_signal_free(nfcv_resp_sof);
digital_signal_free(nfcv_resp_eof);
nfcv_signal = NULL;
nfcv_resp_unmod_256 = NULL;
nfcv_resp_pulse_32 = NULL;
nfcv_resp_one = NULL;
nfcv_resp_zero = NULL;
nfcv_resp_sof = NULL;
nfcv_resp_eof = NULL;
}
void nfcv_emu_alloc() {
if(!nfcv_signal) {
/* assuming max frame length is 255 bytes */
nfcv_signal = digital_sequence_alloc(8 * 255 + 2, nfcv_out_io);
}
if(!nfcv_resp_unmod_256) {
/* unmodulated 256/fc signal as building block */
nfcv_resp_unmod_256 = digital_signal_alloc(4);
nfcv_resp_unmod_256->start_level = false;
nfcv_resp_unmod_256->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_UNMOD_256 * DIGITAL_SIGNAL_UNIT_S);
nfcv_resp_unmod_256->edge_cnt = 1;
}
if(!nfcv_resp_pulse_32) {
/* modulated fc/32 pulse as building block */
nfcv_resp_pulse_32 = digital_signal_alloc(4);
nfcv_resp_pulse_32->start_level = true;
nfcv_resp_pulse_32->edge_timings[0] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
nfcv_resp_pulse_32->edge_timings[1] = (uint32_t)(NFCV_RESP_SUBC1_PULSE_32 * DIGITAL_SIGNAL_UNIT_S);
nfcv_resp_pulse_32->edge_cnt = 2;
}
if(!nfcv_resp_one) {
/* logical one: 256/fc unmodulated then 8 pulses fc/32 */
nfcv_resp_one = digital_signal_alloc(24);
digital_signal_append(nfcv_resp_one, nfcv_resp_unmod_256);
for(size_t i = 0; i < 8; i++) {
digital_signal_append(nfcv_resp_one, nfcv_resp_pulse_32);
}
}
if(!nfcv_resp_zero) {
/* logical zero: 8 pulses fc/32 then 256/fc unmodulated */
nfcv_resp_zero = digital_signal_alloc(24);
for(size_t i = 0; i < 8; i++) {
digital_signal_append(nfcv_resp_zero, nfcv_resp_pulse_32);
}
digital_signal_append(nfcv_resp_zero, nfcv_resp_unmod_256);
}
if(!nfcv_resp_sof) {
/* SOF: unmodulated 768/fc, 24 pulses fc/32, logic 1 */
nfcv_resp_sof = digital_signal_alloc(128);
digital_signal_append(nfcv_resp_sof, nfcv_resp_unmod_256);
digital_signal_append(nfcv_resp_sof, nfcv_resp_unmod_256);
digital_signal_append(nfcv_resp_sof, nfcv_resp_unmod_256);
for(size_t i = 0; i < 24; i++) {
digital_signal_append(nfcv_resp_sof, nfcv_resp_pulse_32);
}
digital_signal_append(nfcv_resp_sof, nfcv_resp_one);
}
if(!nfcv_resp_eof) {
/* EOF: logic 0, 24 pulses fc/32, unmodulated 768/fc */
nfcv_resp_eof = digital_signal_alloc(128);
digital_signal_append(nfcv_resp_eof, nfcv_resp_zero);
for(size_t i = 0; i < 24; i++) {
digital_signal_append(nfcv_resp_eof, nfcv_resp_pulse_32);
}
digital_signal_append(nfcv_resp_eof, nfcv_resp_unmod_256);
digital_signal_append(nfcv_resp_eof, nfcv_resp_unmod_256);
digital_signal_append(nfcv_resp_eof, nfcv_resp_unmod_256);
/* add extra silence */
digital_signal_append(nfcv_resp_eof, nfcv_resp_unmod_256);
}
digital_sequence_set_signal(nfcv_signal, SIG_SOF, nfcv_resp_sof);
digital_sequence_set_signal(nfcv_signal, SIG_BIT0, nfcv_resp_zero);
digital_sequence_set_signal(nfcv_signal, SIG_BIT1, nfcv_resp_one);
digital_sequence_set_signal(nfcv_signal, SIG_EOF, nfcv_resp_eof);
}
void nfcv_emu_send_raw(uint8_t* data, uint8_t length) {
digital_sequence_clear(nfcv_signal);
digital_sequence_add(nfcv_signal, SIG_SOF);
for(int bit_total = 0; bit_total < length * 8; bit_total++) {
uint32_t byte_pos = bit_total / 8;
uint32_t bit_pos = bit_total % 8;
uint8_t bit_val = 0x01 << bit_pos;
digital_sequence_add(nfcv_signal, (data[byte_pos] & bit_val) ? SIG_BIT1 : SIG_BIT0);
}
digital_sequence_add(nfcv_signal, SIG_EOF);
FURI_CRITICAL_ENTER();
digital_sequence_send(nfcv_signal);
FURI_CRITICAL_EXIT();
furi_hal_gpio_write(nfcv_out_io, false);
}
void nfcv_emu_send(uint8_t* data, uint8_t length) {
uint8_t buffer[64];
if(length + 2 > (uint8_t)sizeof(buffer)) {
return;
}
memcpy(buffer, data, length);
nfcv_crc(buffer, length, &buffer[length]);
nfcv_emu_send_raw(buffer, length + 2);
}
void nfcv_uidcpy(uint8_t *dst, uint8_t *src) {
for(int pos = 0; pos < 8; pos++) {
dst[pos] = src[7-pos];
}
}
int nfcv_uidcmp(uint8_t *dst, uint8_t *src) {
for(int pos = 0; pos < 8; pos++) {
if(dst[pos] != src[7-pos]) {
return 1;
}
}
return 0;
}
uint32_t nfcv_read_le(uint8_t *data, uint32_t length) {
uint32_t value = 0;
for(uint32_t pos = 0; pos < length; pos++) {
value |= data[pos] << ((int)pos * 8);
}
return value;
}
uint32_t nfcv_read_be(uint8_t *data, uint32_t length) {
uint32_t value = 0;
for(uint32_t pos = 0; pos < length; pos++) {
value <<= 8;
value |= data[pos];
}
return value;
}
void nfcv_emu_handle_packet(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint8_t* payload, uint32_t payload_length) {
if(!payload_length) {
return;
}
uint8_t flags = payload[0];
uint8_t command = payload[1];
bool addressed = !(flags & RFAL_NFCV_REQ_FLAG_INVENTORY) && (flags & RFAL_NFCV_REQ_FLAG_ADDRESS);
bool advanced = (command >= 0xA0);
uint8_t address_offset = 2 + (advanced ? 1 : 0);
uint8_t payload_offset = address_offset + (addressed ? 8 : 0);
uint8_t *address = &payload[address_offset];
if(addressed && nfcv_uidcmp(address, nfc_data->uid)) {
FURI_LOG_D(TAG, "addressed command 0x%02X, but not for us:", command);
FURI_LOG_D(TAG, " dest: %02X%02X%02X%02X%02X%02X%02X%02X", address[7], address[6], address[5], address[4], address[3], address[2], address[1], address[0]);
FURI_LOG_D(TAG, " our UID: %02X%02X%02X%02X%02X%02X%02X%02X", nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3], nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]);
return;
}
uint8_t response_buffer[32];
switch(nfcv_data->type) {
case NfcVTypeSlixL:
if(nfcv_data->sub_data.slix_l.privacy &&
command != ISO15693_CMD_NXP_GET_RANDOM_NUMBER &&
command != ISO15693_CMD_NXP_SET_PASSWORD) {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "command 0x%02X ignored, privacy mode", command);
FURI_LOG_D(TAG, "%s", nfcv_data->last_command);
return;
}
break;
default:
break;
}
/* unfortunately the response is quicker than the original NFC tag which causes frame misses */
furi_delay_us(270);
switch(command) {
case ISO15693_INVENTORY:
{
response_buffer[0] = ISO15693_NOERROR;
response_buffer[1] = nfcv_data->dsfid;
nfcv_uidcpy(&response_buffer[2], nfc_data->uid);
nfcv_emu_send(response_buffer, 10);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "INVENTORY");
break;
}
case ISO15693_STAYQUIET:
{
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "STAYQUIET");
break;
}
case ISO15693_LOCKBLOCK:
{
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "LOCKBLOCK");
break;
}
case ISO15693_READ_MULTI_BLOCK:
{
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ_MULTI_BLOCK");
break;
}
case ISO15693_WRITE_MULTI_BLOCK:
{
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "WRITE_MULTI_BLOCK");
break;
}
case ISO15693_SELECT:
{
response_buffer[0] = ISO15693_NOERROR;
nfcv_emu_send(response_buffer, 1);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SELECT");
break;
}
case ISO15693_READBLOCK:
{
uint8_t block = payload[payload_offset];
if(block >= nfcv_data->block_num) {
response_buffer[0] = ISO15693_ERROR_BLOCK_WRITE;
nfcv_emu_send(response_buffer, 1);
} else {
response_buffer[0] = ISO15693_NOERROR;
memcpy(&response_buffer[1], &nfcv_data->data[nfcv_data->block_size * block], nfcv_data->block_size);
nfcv_emu_send(response_buffer, 1 + nfcv_data->block_size);
}
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "READ BLOCK %d", block);
break;
}
case ISO15693_WRITEBLOCK:
{
uint8_t block = payload[payload_offset];
uint8_t *data = &payload[payload_offset + 1];
if(block >= nfcv_data->block_num) {
response_buffer[0] = ISO15693_ERROR_BLOCK_WRITE;
} else {
response_buffer[0] = ISO15693_NOERROR;
memcpy(&nfcv_data->data[nfcv_data->block_size * block], &response_buffer[1], nfcv_data->block_size);
}
nfcv_emu_send(response_buffer, 1);
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]);
break;
}
case ISO15693_GET_SYSTEM_INFO:
{
response_buffer[0] = ISO15693_NOERROR;
response_buffer[1] = 0x0F;
nfcv_uidcpy(&response_buffer[2], nfc_data->uid);
response_buffer[10] = nfcv_data->dsfid; /* DSFID */
response_buffer[11] = nfcv_data->afi; /* AFI */
response_buffer[12] = nfcv_data->block_num - 1; /* number of blocks */
response_buffer[13] = nfcv_data->block_size - 1; /* block size */
response_buffer[14] = nfcv_data->ic_ref; /* IC reference */
nfcv_emu_send(response_buffer, 15);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SYSTEMINFO");
break;
}
case ISO15693_CMD_NXP_GET_RANDOM_NUMBER:
{
nfcv_data->sub_data.slix_l.rand[0] = furi_hal_random_get();
nfcv_data->sub_data.slix_l.rand[1] = furi_hal_random_get();
response_buffer[0] = ISO15693_NOERROR;
response_buffer[1] = nfcv_data->sub_data.slix_l.rand[1];
response_buffer[2] = nfcv_data->sub_data.slix_l.rand[0];
nfcv_emu_send(response_buffer, 3);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command),
"GET_RANDOM_NUMBER -> 0x%02X%02X",
nfcv_data->sub_data.slix_l.rand[0],
nfcv_data->sub_data.slix_l.rand[1]);
break;
}
case ISO15693_CMD_NXP_SET_PASSWORD:
{
uint8_t password_id = payload[payload_offset];
uint8_t *password_xored = &payload[payload_offset + 1];
uint8_t *rand = nfcv_data->sub_data.slix_l.rand;
uint8_t *password = NULL;
uint8_t password_rcv[4];
switch(password_id) {
case 4:
password = nfcv_data->sub_data.slix_l.key_privacy;
break;
case 8:
password = nfcv_data->sub_data.slix_l.key_destroy;
break;
case 10:
password = nfcv_data->sub_data.slix_l.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_expect = nfcv_read_be(password, 4);
uint32_t pass_received = nfcv_read_be(password_rcv, 4);
if(pass_expect == pass_received) {
nfcv_data->sub_data.slix_l.privacy = false;
response_buffer[0] = ISO15693_NOERROR;
nfcv_emu_send(response_buffer, 1);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SET_PASSWORD #%02X 0x%08lX OK", password_id, pass_received);
} else {
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "SET_PASSWORD #%02X 0x%08lX/%08lX FAIL", password_id, pass_received, pass_expect);
}
break;
}
case ISO15693_CMD_NXP_ENABLE_PRIVACY:
{
response_buffer[0] = ISO15693_NOERROR;
nfcv_emu_send(response_buffer, 1);
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "ISO15693_CMD_NXP_ENABLE_PRIVACY");
nfcv_data->sub_data.slix_l.privacy = true;
break;
}
default:
snprintf(nfcv_data->last_command, sizeof(nfcv_data->last_command), "unsupported: %02X", command);
break;
}
if(strlen(nfcv_data->last_command) > 0) {
FURI_LOG_D(TAG, "Received command %s", nfcv_data->last_command);
}
}
void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data) {
nfcv_emu_alloc();
rfal_platform_spi_acquire();
st25r3916ExecuteCommand(ST25R3916_CMD_STOP);
st25r3916WriteRegister(ST25R3916_REG_OP_CONTROL, 0xC3);
st25r3916WriteRegister(ST25R3916_REG_MODE, 0x88);
st25r3916ExecuteCommand(ST25R3916_CMD_TRANSPARENT_MODE);
furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_nfc);
FURI_LOG_D(TAG, "Starting NfcV emulation");
FURI_LOG_D(TAG, " UID: %02X %02X %02X %02X %02X %02X %02X %02X",
nfc_data->uid[0], nfc_data->uid[1], nfc_data->uid[2], nfc_data->uid[3],
nfc_data->uid[4], nfc_data->uid[5], nfc_data->uid[6], nfc_data->uid[7]);
FURI_LOG_D(TAG, " Card type: %d", nfcv_data->type);
FURI_LOG_D(TAG, " Privacy pass: 0x%08lX", nfcv_read_be(nfcv_data->sub_data.slix_l.key_privacy, 4));
FURI_LOG_D(TAG, " Privacy mode: %s", nfcv_data->sub_data.slix_l.privacy ? "ON" : "OFF");
/* allocate a 512 edge buffer, more than enough */
reader_signal = pulse_reader_alloc(&gpio_spi_r_miso, 512);
/* timebase shall be 1 ns */
pulse_reader_set_timebase(reader_signal, PulseReaderUnitNanosecond);
/* and configure to already calculate the number of bits */
pulse_reader_set_bittime(reader_signal, PULSE_DURATION_NS);
pulse_reader_start(reader_signal);
}
void nfcv_emu_deinit() {
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_nfc);
rfal_platform_spi_release();
nfcv_emu_free();
pulse_reader_free(reader_signal);
}
bool nfcv_emu_loop(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms) {
bool ret = false;
uint32_t frame_state = NFCV_FRAME_STATE_SOF1;
uint32_t periods_previous = 0;
uint8_t frame_payload[128];
uint32_t frame_pos = 0;
uint32_t byte_value = 0;
uint32_t bits_received = 0;
char reset_reason[128];
bool wait_for_pulse = false;
while(true) {
uint32_t periods = pulse_reader_receive(reader_signal, timeout_ms * 1000);
if(periods == PULSE_READER_NO_EDGE) {
break;
}
if(wait_for_pulse) {
wait_for_pulse = false;
if(periods != 1) {
snprintf(reset_reason, sizeof(reset_reason), "SOF: Expected a single low pulse in state %lu, but got %lu", frame_state, periods);
frame_state = NFCV_FRAME_STATE_RESET;
}
continue;
}
switch(frame_state) {
case NFCV_FRAME_STATE_SOF1:
if(periods == 1) {
frame_state = NFCV_FRAME_STATE_SOF2;
} else {
frame_state = NFCV_FRAME_STATE_SOF1;
break;
}
break;
case NFCV_FRAME_STATE_SOF2:
/* waiting for the second low period, telling us about coding */
if(periods == 6) {
frame_state = NFCV_FRAME_STATE_CODING_256;
periods_previous = 0;
wait_for_pulse = true;
} else if(periods == 4) {
frame_state = NFCV_FRAME_STATE_CODING_4;
periods_previous = 2;
wait_for_pulse = true;
} else {
snprintf(reset_reason, sizeof(reset_reason), "SOF: Expected 4/6 periods, got %lu", periods);
frame_state = NFCV_FRAME_STATE_SOF1;
}
break;
case NFCV_FRAME_STATE_CODING_256:
if(periods_previous > periods) {
snprintf(reset_reason, sizeof(reset_reason), "1oo256: Missing %lu periods from previous symbol, got %lu", periods_previous, periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
/* previous symbol left us with some pulse periods */
periods -= periods_previous;
if(periods > 512) {
snprintf(reset_reason, sizeof(reset_reason), "1oo256: %lu periods is too much", periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
if(periods == 2) {
frame_state = NFCV_FRAME_STATE_EOF;
break;
}
periods_previous = 512 - (periods + 1);
byte_value = (periods - 1) / 2;
frame_payload[frame_pos++] = (uint8_t)byte_value;
wait_for_pulse = true;
break;
case NFCV_FRAME_STATE_CODING_4:
if(periods_previous > periods) {
snprintf(reset_reason, sizeof(reset_reason), "1oo4: Missing %lu periods from previous symbol, got %lu", periods_previous, periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
/* previous symbol left us with some pulse periods */
periods -= periods_previous;
periods_previous = 0;
byte_value >>= 2;
bits_received += 2;
if(periods == 1) {
byte_value |= 0x00 << 6;
periods_previous = 6;
} else if(periods == 3) {
byte_value |= 0x01 << 6;
periods_previous = 4;
} else if(periods == 5) {
byte_value |= 0x02 << 6;
periods_previous = 2;
} else if(periods == 7) {
byte_value |= 0x03 << 6;
periods_previous = 0;
} else if(periods == 2) {
frame_state = NFCV_FRAME_STATE_EOF;
break;
} else {
snprintf(reset_reason, sizeof(reset_reason), "1oo4: Expected 1/3/5/7 low pulses, but got %lu", periods);
frame_state = NFCV_FRAME_STATE_RESET;
break;
}
if(bits_received >= 8) {
frame_payload[frame_pos++] = (uint8_t)byte_value;
bits_received = 0;
}
wait_for_pulse = true;
break;
}
/* post-state-machine cleanup and reset */
if(frame_state == NFCV_FRAME_STATE_RESET) {
frame_state = NFCV_FRAME_STATE_SOF1;
FURI_LOG_D(TAG, "Resetting state machine, reason: '%s'", reset_reason);
} else if(frame_state == NFCV_FRAME_STATE_EOF) {
break;
}
}
if(frame_state == NFCV_FRAME_STATE_EOF) {
/* we know that this code uses TIM2, so stop pulse reader */
pulse_reader_stop(reader_signal);
nfcv_emu_handle_packet(nfc_data, nfcv_data, frame_payload, frame_pos);
pulse_reader_start(reader_signal);
ret = true;
}
return ret;
}

View File

@@ -1,168 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <lib/digital_signal/digital_signal.h>
#include <lib/pulse_reader/pulse_reader.h>
#include "nfc_util.h"
#include <furi_hal_nfc.h>
#define NFCV_FC (13560000.0f) /* MHz */
#define NFCV_RESP_SUBC1_PULSE_32 (1.0f / (NFCV_FC/32) / 2.0f) /* 1.1799 µs */
#define NFCV_RESP_SUBC1_UNMOD_256 (256.0f / NFCV_FC) /* 18.8791 µs */
#define PULSE_DURATION_NS (128.0f * 1000000000.0f / NFCV_FC) /* ns */
#define DIGITAL_SIGNAL_UNIT_S (100000000000.0f)
#define DIGITAL_SIGNAL_UNIT_US (100000.0f)
#define NFCV_TOTAL_BLOCKS_MAX 256
#define NFCV_BLOCK_SIZE 4
#define NFCV_MAX_DUMP_SIZE (NFCV_BLOCK_SIZE*NFCV_TOTAL_BLOCKS_MAX)
#define NFCV_FRAME_STATE_SOF1 0
#define NFCV_FRAME_STATE_SOF2 1
#define NFCV_FRAME_STATE_CODING_4 2
#define NFCV_FRAME_STATE_CODING_256 3
#define NFCV_FRAME_STATE_EOF 4
#define NFCV_FRAME_STATE_RESET 5
/* */
#define ISO15693_INVENTORY 0x01
#define ISO15693_STAYQUIET 0x02
#define ISO15693_READBLOCK 0x20
#define ISO15693_WRITEBLOCK 0x21
#define ISO15693_LOCKBLOCK 0x22
#define ISO15693_READ_MULTI_BLOCK 0x23
#define ISO15693_WRITE_MULTI_BLOCK 0x24
#define ISO15693_SELECT 0x25
#define ISO15693_RESET_TO_READY 0x26
#define ISO15693_WRITE_AFI 0x27
#define ISO15693_LOCK_AFI 0x28
#define ISO15693_WRITE_DSFID 0x29
#define ISO15693_LOCK_DSFID 0x2A
#define ISO15693_GET_SYSTEM_INFO 0x2B
#define ISO15693_READ_MULTI_SECSTATUS 0x2C
// ISO15693 MANUFACTURER CODES
#define ISO15693_MANUFACTURER_NXP 0x04
// ISO15693-3 CUSTOM NXP COMMANDS
#define ISO15693_CMD_NXP_SET_EAS 0xA2
#define ISO15693_CMD_NXP_RESET_EAS 0xA3
#define ISO15693_CMD_NXP_LOCK_EAS 0xA4
#define ISO15693_CMD_NXP_EAS_ALARM 0xA5
#define ISO15693_CMD_NXP_PASSWORD_PROTECT_EAS_AFI 0xA6
#define ISO15693_CMD_NXP_WRITE_EAS_ID 0xA7
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ 0xB0
#define ISO15693_CMD_NXP_INVENTORY_PAGE_READ_FAST 0xB1
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
#define ISO15693_CMD_NXP_WRITE_PASSWORD 0xB4
#define ISO15693_CMD_NXP_DESTROY 0xB9
#define ISO15693_CMD_NXP_ENABLE_PRIVACY 0xBA
// ISO15693 RESPONSE ERROR CODES
#define ISO15693_NOERROR 0x00
#define ISO15693_ERROR_CMD_NOT_SUP 0x01 // Command not supported
#define ISO15693_ERROR_CMD_NOT_REC 0x02 // Command not recognized (eg. parameter error)
#define ISO15693_ERROR_CMD_OPTION 0x03 // Command option not supported
#define ISO15693_ERROR_GENERIC 0x0F // No additional Info about this error
#define ISO15693_ERROR_BLOCK_UNAVAILABLE 0x10
#define ISO15693_ERROR_BLOCK_LOCKED_ALREADY 0x11 // cannot lock again
#define ISO15693_ERROR_BLOCK_LOCKED 0x12 // cannot be changed
#define ISO15693_ERROR_BLOCK_WRITE 0x13 // Writing was unsuccessful
#define ISO15693_ERROR_BLOCL_WRITELOCK 0x14 // Locking was unsuccessful
typedef enum {
NfcVAuthMethodManual,
NfcVAuthMethodTonieBox,
} NfcVAuthMethod;
typedef enum {
NfcVTypePlain = 0,
NfcVTypeSlix = 1,
NfcVTypeSlixS = 2,
NfcVTypeSlixL = 3,
NfcVTypeSlix2 = 4,
} NfcVType;
typedef struct {
uint8_t key_eas[4];
uint8_t rand[2];
} NfcVSlixData;
typedef struct {
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;
} NfcVSlix2Data;
typedef struct {
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;
} NfcVSlixSData;
typedef struct {
uint8_t key_privacy[4];
uint8_t key_destroy[4];
uint8_t key_eas[4];
uint8_t rand[2];
bool privacy;
} NfcVSlixLData;
typedef union {
NfcVSlixData slix;
NfcVSlix2Data slix2;
NfcVSlixSData slix_s;
NfcVSlixLData slix_l;
} NfcVSubtypeData;
typedef struct {
/* common ISO15693 fields */
uint8_t dsfid;
uint8_t afi;
uint8_t ic_ref;
uint16_t block_num;
uint8_t block_size;
uint8_t data[NFCV_MAX_DUMP_SIZE];
/* specfic variant infos */
NfcVType type;
NfcVSubtypeData sub_data;
/* runtime data */
char last_command[128];
char error[32];
NfcVAuthMethod auth_method;
bool auth_success;
} NfcVData;
typedef struct {
uint16_t blocks_to_read;
int16_t blocks_read;
} NfcVReader;
ReturnCode nfcv_read_blocks(NfcVReader* reader, NfcVData* data);
ReturnCode nfcv_read_sysinfo(FuriHalNfcDevData* nfc_data, NfcVData* data);
ReturnCode nfcv_inventory(uint8_t* uid);
bool nfcv_read_card(NfcVReader* reader, FuriHalNfcDevData* nfc_data, NfcVData* data);
void nfcv_emu_init(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data);
void nfcv_emu_deinit();
bool nfcv_emu_loop(FuriHalNfcDevData* nfc_data, NfcVData* nfcv_data, uint32_t timeout_ms);

View File

@@ -1,125 +0,0 @@
#include <limits.h>
#include "nfcv.h"
#include "slix.h"
#include "nfc_util.h"
#include <furi.h>
#include "furi_hal_nfc.h"
bool slix_check_card_type(FuriHalNfcDevData* nfc_data) {
if((nfc_data->uid[0] == 0xE0)
&& (nfc_data->uid[1] == 0x04)
&& (nfc_data->uid[2] == 0x01)
&& (((nfc_data->uid[3] >> 4) & 3) == 2)) {
return true;
}
return false;
}
bool slix2_check_card_type(FuriHalNfcDevData* nfc_data) {
if((nfc_data->uid[0] == 0xE0)
&& (nfc_data->uid[1] == 0x04)
&& (nfc_data->uid[2] == 0x01)
&& (((nfc_data->uid[3] >> 4) & 3) == 1)) {
return true;
}
return false;
}
bool slix_s_check_card_type(FuriHalNfcDevData* nfc_data) {
if((nfc_data->uid[0] == 0xE0)
&& (nfc_data->uid[1] == 0x04)
&& (nfc_data->uid[2] == 0x02)) {
return true;
}
return false;
}
bool slix_l_check_card_type(FuriHalNfcDevData* nfc_data) {
if((nfc_data->uid[0] == 0xE0)
&& (nfc_data->uid[1] == 0x04)
&& (nfc_data->uid[2] == 0x03)) {
return true;
}
return false;
}
ReturnCode slix_l_get_random(NfcVData* data) {
uint16_t received = 0;
uint8_t rxBuf[32];
ReturnCode ret = rfalNfcvPollerTransceiveReq(
ISO15693_CMD_NXP_GET_RANDOM_NUMBER,
RFAL_NFCV_REQ_FLAG_DEFAULT,
ISO15693_MANUFACTURER_NXP,
NULL,
NULL,
0,
rxBuf,
sizeof(rxBuf),
&received);
if(ret == ERR_NONE) {
if(received != 3) {
return ERR_PROTO;
}
if(data != NULL) {
data->sub_data.slix_l.rand[0] = rxBuf[2];
data->sub_data.slix_l.rand[1] = rxBuf[1];
}
}
return ret;
}
ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id) {
furi_assert(rand);
uint16_t received = 0;
uint8_t rxBuf[32];
uint8_t cmd_set_pass[] = {
password_id,
data->sub_data.slix_l.rand[1],
data->sub_data.slix_l.rand[0],
data->sub_data.slix_l.rand[1],
data->sub_data.slix_l.rand[0]
};
uint8_t *password = NULL;
switch(password_id) {
case 4:
password = data->sub_data.slix_l.key_privacy;
break;
case 8:
password = data->sub_data.slix_l.key_destroy;
break;
case 10:
password = data->sub_data.slix_l.key_eas;
break;
default:
break;
}
if(!password) {
return ERR_NOTSUPP;
}
for(int pos = 0; pos < 4; pos++) {
cmd_set_pass[1 + pos] ^= password[3 - pos];
}
ReturnCode ret = rfalNfcvPollerTransceiveReq(
ISO15693_CMD_NXP_SET_PASSWORD,
RFAL_NFCV_REQ_FLAG_DATA_RATE,
ISO15693_MANUFACTURER_NXP,
NULL,
cmd_set_pass,
sizeof(cmd_set_pass),
rxBuf,
sizeof(rxBuf),
&received);
return ret;
}

View File

@@ -1,19 +0,0 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "nfc_util.h"
#include <furi_hal_nfc.h>
#define ISO15693_CMD_NXP_GET_RANDOM_NUMBER 0xB2
#define ISO15693_CMD_NXP_SET_PASSWORD 0xB3
#define ISO15693_MANUFACTURER_NXP 0x04
bool slix_check_card_type(FuriHalNfcDevData* nfc_data);
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 slix_l_get_random(NfcVData* data);
ReturnCode slix_l_unlock(NfcVData* data, uint32_t password_id);