* github: re-enabled f18 build * scripts: storage: better transfer logging * Fix PVS warnings Co-authored-by: あく <alleteam@gmail.com>
		
			
				
	
	
		
			413 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			413 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
 | 
						|
#include <limits.h>
 | 
						|
#include "nfcv.h"
 | 
						|
#include "slix.h"
 | 
						|
#include "nfc_util.h"
 | 
						|
#include <furi.h>
 | 
						|
#include "furi_hal_nfc.h"
 | 
						|
#include <furi_hal_random.h>
 | 
						|
 | 
						|
#define TAG "SLIX"
 | 
						|
 | 
						|
static uint32_t slix_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;
 | 
						|
}
 | 
						|
 | 
						|
uint8_t slix_get_ti(FuriHalNfcDevData* nfc_data) {
 | 
						|
    return (nfc_data->uid[3] >> 3) & 3;
 | 
						|
}
 | 
						|
 | 
						|
bool slix_check_card_type(FuriHalNfcDevData* nfc_data) {
 | 
						|
    if((nfc_data->uid[0] == 0xE0) && (nfc_data->uid[1] == 0x04) && (nfc_data->uid[2] == 0x01) &&
 | 
						|
       slix_get_ti(nfc_data) == 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) &&
 | 
						|
       slix_get_ti(nfc_data) == 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_get_random(NfcVData* data) {
 | 
						|
    uint16_t received = 0;
 | 
						|
    uint8_t rxBuf[32];
 | 
						|
 | 
						|
    ReturnCode ret = rfalNfcvPollerTransceiveReq(
 | 
						|
        NFCV_CMD_NXP_GET_RANDOM_NUMBER,
 | 
						|
        RFAL_NFCV_REQ_FLAG_DEFAULT,
 | 
						|
        NFCV_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.rand[0] = rxBuf[2];
 | 
						|
            data->sub_data.slix.rand[1] = rxBuf[1];
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
ReturnCode slix_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.rand[1],
 | 
						|
        data->sub_data.slix.rand[0],
 | 
						|
        data->sub_data.slix.rand[1],
 | 
						|
        data->sub_data.slix.rand[0]};
 | 
						|
    uint8_t* password = NULL;
 | 
						|
 | 
						|
    switch(password_id) {
 | 
						|
    case SLIX_PASS_READ:
 | 
						|
        password = data->sub_data.slix.key_read;
 | 
						|
        break;
 | 
						|
    case SLIX_PASS_WRITE:
 | 
						|
        password = data->sub_data.slix.key_write;
 | 
						|
        break;
 | 
						|
    case SLIX_PASS_PRIVACY:
 | 
						|
        password = data->sub_data.slix.key_privacy;
 | 
						|
        break;
 | 
						|
    case SLIX_PASS_DESTROY:
 | 
						|
        password = data->sub_data.slix.key_destroy;
 | 
						|
        break;
 | 
						|
    case SLIX_PASS_EASAFI:
 | 
						|
        password = data->sub_data.slix.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(
 | 
						|
        NFCV_CMD_NXP_SET_PASSWORD,
 | 
						|
        RFAL_NFCV_REQ_FLAG_DATA_RATE,
 | 
						|
        NFCV_MANUFACTURER_NXP,
 | 
						|
        NULL,
 | 
						|
        cmd_set_pass,
 | 
						|
        sizeof(cmd_set_pass),
 | 
						|
        rxBuf,
 | 
						|
        sizeof(rxBuf),
 | 
						|
        &received);
 | 
						|
 | 
						|
    return ret;
 | 
						|
}
 | 
						|
 | 
						|
bool slix_generic_protocol_filter(
 | 
						|
    FuriHalNfcTxRxContext* tx_rx,
 | 
						|
    FuriHalNfcDevData* nfc_data,
 | 
						|
    void* nfcv_data_in,
 | 
						|
    uint32_t password_supported) {
 | 
						|
    furi_assert(tx_rx);
 | 
						|
    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;
 | 
						|
 | 
						|
    if(slix->privacy && ctx->command != NFCV_CMD_NXP_GET_RANDOM_NUMBER &&
 | 
						|
       ctx->command != NFCV_CMD_NXP_SET_PASSWORD) {
 | 
						|
        snprintf(
 | 
						|
            nfcv_data->last_command,
 | 
						|
            sizeof(nfcv_data->last_command),
 | 
						|
            "command 0x%02X ignored, privacy mode",
 | 
						|
            ctx->command);
 | 
						|
        FURI_LOG_D(TAG, "%s", nfcv_data->last_command);
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    bool handled = false;
 | 
						|
 | 
						|
    switch(ctx->command) {
 | 
						|
    case NFCV_CMD_NXP_GET_RANDOM_NUMBER: {
 | 
						|
        slix->rand[0] = furi_hal_random_get();
 | 
						|
        slix->rand[1] = furi_hal_random_get();
 | 
						|
 | 
						|
        ctx->response_buffer[0] = NFCV_NOERROR;
 | 
						|
        ctx->response_buffer[1] = slix->rand[1];
 | 
						|
        ctx->response_buffer[2] = slix->rand[0];
 | 
						|
 | 
						|
        nfcv_emu_send(
 | 
						|
            tx_rx, nfcv_data, ctx->response_buffer, 3, ctx->response_flags, ctx->send_time);
 | 
						|
        snprintf(
 | 
						|
            nfcv_data->last_command,
 | 
						|
            sizeof(nfcv_data->last_command),
 | 
						|
            "GET_RANDOM_NUMBER -> 0x%02X%02X",
 | 
						|
            slix->rand[0],
 | 
						|
            slix->rand[1]);
 | 
						|
 | 
						|
        handled = true;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    case NFCV_CMD_NXP_SET_PASSWORD: {
 | 
						|
        uint8_t password_id = nfcv_data->frame[ctx->payload_offset];
 | 
						|
 | 
						|
        if(!(password_id & password_supported)) {
 | 
						|
            break;
 | 
						|
        }
 | 
						|
 | 
						|
        uint8_t* password_xored = &nfcv_data->frame[ctx->payload_offset + 1];
 | 
						|
        uint8_t* rand = slix->rand;
 | 
						|
        uint8_t* password = NULL;
 | 
						|
        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;
 | 
						|
        }
 | 
						|
 | 
						|
        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);
 | 
						|
 | 
						|
        /* if the password is all-zeroes, just accept any password*/
 | 
						|
        if(!pass_expect || pass_expect == pass_received) {
 | 
						|
            switch(password_id) {
 | 
						|
            case SLIX_PASS_READ:
 | 
						|
                break;
 | 
						|
            case SLIX_PASS_WRITE:
 | 
						|
                break;
 | 
						|
            case SLIX_PASS_PRIVACY:
 | 
						|
                slix->privacy = false;
 | 
						|
                nfcv_data->modified = true;
 | 
						|
                break;
 | 
						|
            case SLIX_PASS_DESTROY:
 | 
						|
                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);
 | 
						|
            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);
 | 
						|
        }
 | 
						|
        handled = true;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
 | 
						|
    case NFCV_CMD_NXP_ENABLE_PRIVACY: {
 | 
						|
        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),
 | 
						|
            "NFCV_CMD_NXP_ENABLE_PRIVACY");
 | 
						|
 | 
						|
        slix->privacy = true;
 | 
						|
        handled = true;
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    }
 | 
						|
 | 
						|
    return handled;
 | 
						|
}
 | 
						|
 | 
						|
bool slix_l_protocol_filter(
 | 
						|
    FuriHalNfcTxRxContext* tx_rx,
 | 
						|
    FuriHalNfcDevData* nfc_data,
 | 
						|
    void* nfcv_data_in) {
 | 
						|
    furi_assert(tx_rx);
 | 
						|
    furi_assert(nfc_data);
 | 
						|
    furi_assert(nfcv_data_in);
 | 
						|
 | 
						|
    bool handled = false;
 | 
						|
 | 
						|
    /* many SLIX share some of the functions, place that in a generic handler */
 | 
						|
    if(slix_generic_protocol_filter(
 | 
						|
           tx_rx,
 | 
						|
           nfc_data,
 | 
						|
           nfcv_data_in,
 | 
						|
           SLIX_PASS_PRIVACY | SLIX_PASS_DESTROY | SLIX_PASS_EASAFI)) {
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    return handled;
 | 
						|
}
 | 
						|
 | 
						|
void slix_l_prepare(NfcVData* nfcv_data) {
 | 
						|
    FURI_LOG_D(
 | 
						|
        TAG, "  Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
 | 
						|
    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");
 | 
						|
 | 
						|
    NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
 | 
						|
    ctx->emu_protocol_filter = &slix_l_protocol_filter;
 | 
						|
}
 | 
						|
 | 
						|
bool slix_s_protocol_filter(
 | 
						|
    FuriHalNfcTxRxContext* tx_rx,
 | 
						|
    FuriHalNfcDevData* nfc_data,
 | 
						|
    void* nfcv_data_in) {
 | 
						|
    furi_assert(tx_rx);
 | 
						|
    furi_assert(nfc_data);
 | 
						|
    furi_assert(nfcv_data_in);
 | 
						|
 | 
						|
    bool handled = false;
 | 
						|
 | 
						|
    /* many SLIX share some of the functions, place that in a generic handler */
 | 
						|
    if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) {
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    return handled;
 | 
						|
}
 | 
						|
 | 
						|
void slix_s_prepare(NfcVData* nfcv_data) {
 | 
						|
    FURI_LOG_D(
 | 
						|
        TAG, "  Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
 | 
						|
    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");
 | 
						|
 | 
						|
    NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
 | 
						|
    ctx->emu_protocol_filter = &slix_s_protocol_filter;
 | 
						|
}
 | 
						|
 | 
						|
bool slix_protocol_filter(
 | 
						|
    FuriHalNfcTxRxContext* tx_rx,
 | 
						|
    FuriHalNfcDevData* nfc_data,
 | 
						|
    void* nfcv_data_in) {
 | 
						|
    furi_assert(tx_rx);
 | 
						|
    furi_assert(nfc_data);
 | 
						|
    furi_assert(nfcv_data_in);
 | 
						|
 | 
						|
    bool handled = false;
 | 
						|
 | 
						|
    /* many SLIX share some of the functions, place that in a generic handler */
 | 
						|
    if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_EASAFI)) {
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    return handled;
 | 
						|
}
 | 
						|
 | 
						|
void slix_prepare(NfcVData* nfcv_data) {
 | 
						|
    FURI_LOG_D(
 | 
						|
        TAG, "  Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
 | 
						|
    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");
 | 
						|
 | 
						|
    NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
 | 
						|
    ctx->emu_protocol_filter = &slix_protocol_filter;
 | 
						|
}
 | 
						|
 | 
						|
bool slix2_protocol_filter( // -V524
 | 
						|
    FuriHalNfcTxRxContext* tx_rx,
 | 
						|
    FuriHalNfcDevData* nfc_data,
 | 
						|
    void* nfcv_data_in) {
 | 
						|
    furi_assert(tx_rx);
 | 
						|
    furi_assert(nfc_data);
 | 
						|
    furi_assert(nfcv_data_in);
 | 
						|
 | 
						|
    bool handled = false;
 | 
						|
 | 
						|
    /* many SLIX share some of the functions, place that in a generic handler */
 | 
						|
    if(slix_generic_protocol_filter(tx_rx, nfc_data, nfcv_data_in, SLIX_PASS_ALL)) {
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    return handled;
 | 
						|
}
 | 
						|
 | 
						|
void slix2_prepare(NfcVData* nfcv_data) {
 | 
						|
    FURI_LOG_D(
 | 
						|
        TAG, "  Privacy pass: 0x%08lX", slix_read_be(nfcv_data->sub_data.slix.key_privacy, 4));
 | 
						|
    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");
 | 
						|
 | 
						|
    NfcVEmuProtocolCtx* ctx = nfcv_data->emu_protocol_ctx;
 | 
						|
    ctx->emu_protocol_filter = &slix2_protocol_filter;
 | 
						|
}
 |