 3226254876
			
		
	
	
		3226254876
		
			
		
	
	
	
	
		
			
			* 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;
 | |
| }
 |