mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-04-24 03:29:57 -07:00
Merge remote-tracking branch 'xero/dev' into mntm-dev
This commit is contained in:
@@ -38,7 +38,6 @@ extern "C" {
|
||||
#define MF_ULTRALIGHT_TEARING_FLAG_NUM (3)
|
||||
#define MF_ULTRALIGHT_AUTH_PASSWORD_SIZE (4)
|
||||
#define MF_ULTRALIGHT_AUTH_PACK_SIZE (2)
|
||||
#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL)
|
||||
|
||||
#define MF_ULTRALIGHT_C_AUTH_RESPONSE_SIZE (9)
|
||||
#define MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE (16)
|
||||
@@ -48,11 +47,6 @@ extern "C" {
|
||||
#define MF_ULTRALIGHT_C_AUTH_RND_A_BLOCK_OFFSET (0)
|
||||
#define MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET (8)
|
||||
#define MF_ULTRALIGHT_C_ENCRYPTED_PACK_SIZE (MF_ULTRALIGHT_C_AUTH_DATA_SIZE + 1)
|
||||
#define MF_ULTRALIGHT_C_DEFAULT_KEY \
|
||||
(uint8_t[]) { \
|
||||
0x49, 0x45, 0x4D, 0x4B, 0x41, 0x45, 0x52, 0x42, 0x21, 0x4E, 0x41, 0x43, 0x55, 0x4F, 0x59, \
|
||||
0x46 \
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
MfUltralightErrorNone,
|
||||
|
||||
@@ -251,7 +251,7 @@ static NfcCommand mf_ultralight_poller_handler_read_version(MfUltralightPoller*
|
||||
instance->data->type = mf_ultralight_get_type_by_version(&instance->data->version);
|
||||
instance->state = MfUltralightPollerStateGetFeatureSet;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Didn't response. Check Ultralight C");
|
||||
FURI_LOG_D(TAG, "Didn't respond. Check Ultralight C");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->state = MfUltralightPollerStateDetectMfulC;
|
||||
}
|
||||
@@ -266,7 +266,7 @@ static NfcCommand mf_ultralight_poller_handler_check_ultralight_c(MfUltralightPo
|
||||
instance->data->type = MfUltralightTypeMfulC;
|
||||
instance->state = MfUltralightPollerStateGetFeatureSet;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Didn't response. Check NTAG 203");
|
||||
FURI_LOG_D(TAG, "Didn't respond. Check NTAG 203");
|
||||
instance->state = MfUltralightPollerStateDetectNtag203;
|
||||
}
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
@@ -445,36 +445,104 @@ static NfcCommand mf_ultralight_poller_handler_auth(MfUltralightPoller* instance
|
||||
static NfcCommand mf_ultralight_poller_handler_auth_ultralight_c(MfUltralightPoller* instance) {
|
||||
NfcCommand command = NfcCommandContinue;
|
||||
FURI_LOG_D(TAG, "MfulC auth");
|
||||
if(mf_ultralight_support_feature(
|
||||
instance->feature_set, MfUltralightFeatureSupportAuthenticate)) {
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeAuthRequest;
|
||||
|
||||
do {
|
||||
if(mf_ultralight_support_feature(
|
||||
instance->feature_set, MfUltralightFeatureSupportAuthenticate)) {
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeAuthRequest;
|
||||
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
if(!instance->mfu_event.data->auth_context.skip_auth) {
|
||||
FURI_LOG_D(TAG, "Trying to authenticate with 3des key");
|
||||
instance->auth_context.tdes_key = instance->mfu_event.data->auth_context.tdes_key;
|
||||
instance->error =
|
||||
mf_ultralight_poller_auth_tdes(instance, &instance->auth_context);
|
||||
|
||||
if(instance->error == MfUltralightErrorNone &&
|
||||
instance->auth_context.auth_success) {
|
||||
FURI_LOG_D(TAG, "Auth success");
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
if(!instance->mfu_event.data->auth_context.skip_auth) {
|
||||
FURI_LOG_D(TAG, "Trying to authenticate with 3des key");
|
||||
// Only use the key if it was actually provided
|
||||
if(instance->mfu_event.data->key_request_data.key_provided) {
|
||||
instance->auth_context.tdes_key = instance->mfu_event.data->key_request_data.key;
|
||||
} else if(instance->mode == MfUltralightPollerModeDictAttack) {
|
||||
// TODO: Can logic be rearranged to request this key before reaching mf_ultralight_poller_handler_auth_ultralight_c in poller?
|
||||
FURI_LOG_D(TAG, "No initial key provided, requesting key from dictionary");
|
||||
// Trigger dictionary key request
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeRequestKey;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
if(!instance->mfu_event.data->key_request_data.key_provided) {
|
||||
instance->state = MfUltralightPollerStateReadPages;
|
||||
return command;
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Auth failed");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
instance->auth_context.tdes_key = instance->mfu_event.data->key_request_data.key;
|
||||
}
|
||||
} else {
|
||||
// We assume here that it is card read without explicitly provided key
|
||||
// So we try to auth with default one
|
||||
instance->state = MfUltralightPollerStateTryDefaultMfulCKey;
|
||||
break;
|
||||
FURI_LOG_D(TAG, "No key provided, skipping auth");
|
||||
instance->state = MfUltralightPollerStateReadPages;
|
||||
return command;
|
||||
}
|
||||
instance->auth_context.auth_success = false;
|
||||
// For debugging
|
||||
FURI_LOG_D(
|
||||
"TAG",
|
||||
"Key data: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||
instance->auth_context.tdes_key.data[0],
|
||||
instance->auth_context.tdes_key.data[1],
|
||||
instance->auth_context.tdes_key.data[2],
|
||||
instance->auth_context.tdes_key.data[3],
|
||||
instance->auth_context.tdes_key.data[4],
|
||||
instance->auth_context.tdes_key.data[5],
|
||||
instance->auth_context.tdes_key.data[6],
|
||||
instance->auth_context.tdes_key.data[7],
|
||||
instance->auth_context.tdes_key.data[8],
|
||||
instance->auth_context.tdes_key.data[9],
|
||||
instance->auth_context.tdes_key.data[10],
|
||||
instance->auth_context.tdes_key.data[11],
|
||||
instance->auth_context.tdes_key.data[12],
|
||||
instance->auth_context.tdes_key.data[13],
|
||||
instance->auth_context.tdes_key.data[14],
|
||||
instance->auth_context.tdes_key.data[15]);
|
||||
do {
|
||||
uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE];
|
||||
uint8_t RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
|
||||
furi_hal_random_fill_buf(RndA, sizeof(RndA));
|
||||
instance->error = mf_ultralight_poller_authenticate_start(instance, RndA, output);
|
||||
if(instance->error != MfUltralightErrorNone) break;
|
||||
|
||||
uint8_t decoded_shifted_RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
|
||||
const uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET;
|
||||
instance->error = mf_ultralight_poller_authenticate_end(
|
||||
instance, RndB, output, decoded_shifted_RndA);
|
||||
if(instance->error != MfUltralightErrorNone) break;
|
||||
|
||||
mf_ultralight_3des_shift_data(RndA);
|
||||
instance->auth_context.auth_success =
|
||||
(memcmp(RndA, decoded_shifted_RndA, sizeof(decoded_shifted_RndA)) == 0);
|
||||
if(instance->auth_context.auth_success) {
|
||||
FURI_LOG_E(TAG, "Auth success");
|
||||
if(instance->mode == MfUltralightPollerModeDictAttack) {
|
||||
memcpy(
|
||||
&instance->data->page[44],
|
||||
instance->auth_context.tdes_key.data,
|
||||
MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE);
|
||||
// Continue to read pages after successful authentication
|
||||
instance->state = MfUltralightPollerStateReadPages;
|
||||
}
|
||||
}
|
||||
} while(false);
|
||||
if(instance->error != MfUltralightErrorNone || !instance->auth_context.auth_success) {
|
||||
FURI_LOG_E(TAG, "Auth failed");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
if(instance->mode == MfUltralightPollerModeDictAttack) {
|
||||
// Not needed? We already do a callback earlier?
|
||||
instance->mfu_event.type = MfUltralightPollerEventTypeRequestKey;
|
||||
command = instance->callback(instance->general_event, instance->context);
|
||||
if(!instance->mfu_event.data->key_request_data.key_provided) {
|
||||
instance->state = MfUltralightPollerStateReadPages;
|
||||
} else {
|
||||
instance->auth_context.tdes_key =
|
||||
instance->mfu_event.data->key_request_data.key;
|
||||
instance->state = MfUltralightPollerStateAuthMfulC;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Regression review
|
||||
if(instance->mode != MfUltralightPollerModeDictAttack) {
|
||||
instance->state = MfUltralightPollerStateReadPages;
|
||||
} while(false);
|
||||
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
@@ -497,12 +565,16 @@ static NfcCommand mf_ultralight_poller_handler_read_pages(MfUltralightPoller* in
|
||||
instance->error = mf_ultralight_poller_read_page(instance, start_page, &data);
|
||||
}
|
||||
|
||||
// Regression review
|
||||
const uint8_t read_cnt = instance->data->type == MfUltralightTypeMfulC ? 1 : 4;
|
||||
if(instance->error == MfUltralightErrorNone) {
|
||||
if(start_page < instance->pages_total) {
|
||||
FURI_LOG_D(TAG, "Read page %d success", start_page);
|
||||
instance->data->page[start_page] = data.page[0];
|
||||
instance->pages_read++;
|
||||
instance->data->pages_read = instance->pages_read;
|
||||
for(size_t i = 0; i < read_cnt; i++) {
|
||||
if(start_page + i < instance->pages_total) {
|
||||
FURI_LOG_D(TAG, "Read page %d success", start_page + i);
|
||||
instance->data->page[start_page + i] = data.page[i];
|
||||
instance->pages_read++;
|
||||
instance->data->pages_read = instance->pages_read;
|
||||
}
|
||||
}
|
||||
|
||||
if(instance->pages_read == instance->pages_total) {
|
||||
@@ -570,40 +642,6 @@ static NfcCommand mf_ultralight_poller_handler_try_default_pass(MfUltralightPoll
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand
|
||||
mf_ultralight_poller_handler_try_default_ultralight_c_key(MfUltralightPoller* instance) {
|
||||
do {
|
||||
if(!mf_ultralight_support_feature(
|
||||
instance->feature_set, MfUltralightFeatureSupportAuthenticate)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(instance->auth_context.auth_success) {
|
||||
break;
|
||||
}
|
||||
|
||||
FURI_LOG_D(TAG, "Trying authentication with default 3DES key");
|
||||
|
||||
memcpy(
|
||||
&instance->auth_context.tdes_key.data,
|
||||
MF_ULTRALIGHT_C_DEFAULT_KEY,
|
||||
MF_ULTRALIGHT_C_AUTH_DES_KEY_SIZE);
|
||||
|
||||
instance->error = mf_ultralight_poller_auth_tdes(instance, &instance->auth_context);
|
||||
|
||||
if(instance->error == MfUltralightErrorNone && instance->auth_context.auth_success) {
|
||||
FURI_LOG_D(TAG, "Default 3DES key detected");
|
||||
} else {
|
||||
FURI_LOG_D(TAG, "Authentication attempt with default 3DES key failed");
|
||||
iso14443_3a_poller_halt(instance->iso14443_3a_poller);
|
||||
}
|
||||
|
||||
} while(false);
|
||||
|
||||
instance->state = MfUltralightPollerStateReadPages;
|
||||
return NfcCommandContinue;
|
||||
}
|
||||
|
||||
static NfcCommand
|
||||
mf_ultralight_poller_handler_check_mfuc_auth_status(MfUltralightPoller* instance) {
|
||||
instance->state = MfUltralightPollerStateReadSuccess;
|
||||
@@ -768,8 +806,6 @@ static const MfUltralightPollerReadHandler
|
||||
mf_ultralight_poller_handler_read_tearing_flags,
|
||||
[MfUltralightPollerStateAuth] = mf_ultralight_poller_handler_auth,
|
||||
[MfUltralightPollerStateTryDefaultPass] = mf_ultralight_poller_handler_try_default_pass,
|
||||
[MfUltralightPollerStateTryDefaultMfulCKey] =
|
||||
mf_ultralight_poller_handler_try_default_ultralight_c_key,
|
||||
[MfUltralightPollerStateCheckMfulCAuthStatus] =
|
||||
mf_ultralight_poller_handler_check_mfuc_auth_status,
|
||||
[MfUltralightPollerStateAuthMfulC] = mf_ultralight_poller_handler_auth_ultralight_c,
|
||||
@@ -781,7 +817,6 @@ static const MfUltralightPollerReadHandler
|
||||
[MfUltralightPollerStateWritePages] = mf_ultralight_poller_handler_write_pages,
|
||||
[MfUltralightPollerStateWriteFail] = mf_ultralight_poller_handler_write_fail,
|
||||
[MfUltralightPollerStateWriteSuccess] = mf_ultralight_poller_handler_write_success,
|
||||
|
||||
};
|
||||
|
||||
static NfcCommand mf_ultralight_poller_run(NfcGenericEvent event, void* context) {
|
||||
|
||||
@@ -27,6 +27,7 @@ typedef enum {
|
||||
MfUltralightPollerEventTypeCardLocked, /**< Presented card is locked by password, AUTH0 or lock bytes. */
|
||||
MfUltralightPollerEventTypeWriteSuccess, /**< Poller wrote card successfully. */
|
||||
MfUltralightPollerEventTypeWriteFail, /**< Poller failed to write card. */
|
||||
MfUltralightPollerEventTypeRequestKey, /**< Poller requests key for dict attack. */
|
||||
} MfUltralightPollerEventType;
|
||||
|
||||
/**
|
||||
@@ -35,6 +36,7 @@ typedef enum {
|
||||
typedef enum {
|
||||
MfUltralightPollerModeRead, /**< Poller will only read card. It's a default mode. */
|
||||
MfUltralightPollerModeWrite, /**< Poller will write already saved card to another presented card. */
|
||||
MfUltralightPollerModeDictAttack, /**< Poller will perform dictionary attack against card. */
|
||||
} MfUltralightPollerMode;
|
||||
|
||||
/**
|
||||
@@ -42,20 +44,29 @@ typedef enum {
|
||||
*/
|
||||
typedef struct {
|
||||
MfUltralightAuthPassword password; /**< Password to be used for authentication. */
|
||||
MfUltralightC3DesAuthKey tdes_key;
|
||||
MfUltralightAuthPack pack; /**< Pack received on successfull authentication. */
|
||||
MfUltralightC3DesAuthKey tdes_key; /**< 3DES key to be used for authentication. */
|
||||
MfUltralightAuthPack pack; /**< Pack received on successful authentication. */
|
||||
bool auth_success; /**< Set to true if authentication succeeded, false otherwise. */
|
||||
bool skip_auth; /**< Set to true if authentication should be skipped, false otherwise. */
|
||||
} MfUltralightPollerAuthContext;
|
||||
|
||||
/**
|
||||
* @brief MfUltralight poller key request data.
|
||||
*/
|
||||
typedef struct {
|
||||
MfUltralightC3DesAuthKey key; /**< Key to try. */
|
||||
bool key_provided; /**< Set to true if key was provided, false to stop attack. */
|
||||
} MfUltralightPollerKeyRequestData;
|
||||
|
||||
/**
|
||||
* @brief MfUltralight poller event data.
|
||||
*/
|
||||
typedef union {
|
||||
MfUltralightPollerAuthContext auth_context; /**< Authentication context. */
|
||||
MfUltralightError error; /**< Error code indicating reading fail reason. */
|
||||
const MfUltralightData* write_data;
|
||||
MfUltralightPollerMode poller_mode;
|
||||
const MfUltralightData* write_data; /**< Data to be written to card. */
|
||||
MfUltralightPollerMode poller_mode; /**< Mode to operate in. */
|
||||
MfUltralightPollerKeyRequestData key_request_data; /**< Key request data. */
|
||||
} MfUltralightPollerEventData;
|
||||
|
||||
/**
|
||||
@@ -64,7 +75,7 @@ typedef union {
|
||||
* Upon emission of an event, an instance of this struct will be passed to the callback.
|
||||
*/
|
||||
typedef struct {
|
||||
MfUltralightPollerEventType type; /**< Type of emmitted event. */
|
||||
MfUltralightPollerEventType type; /**< Type of emitted event. */
|
||||
MfUltralightPollerEventData* data; /**< Pointer to event specific data. */
|
||||
} MfUltralightPollerEvent;
|
||||
|
||||
@@ -81,19 +92,6 @@ MfUltralightError mf_ultralight_poller_auth_pwd(
|
||||
MfUltralightPoller* instance,
|
||||
MfUltralightPollerAuthContext* data);
|
||||
|
||||
/**
|
||||
* @brief Perform 3DES authentication with key.
|
||||
*
|
||||
* Must ONLY be used inside the callback function.
|
||||
*
|
||||
* @param[in, out] instance pointer to the instance to be used in the transaction.
|
||||
* @param[in, out] data pointer to the authentication context.
|
||||
* @return MfUltralightErrorNone on success, an error code on failure.
|
||||
*/
|
||||
MfUltralightError mf_ultralight_poller_auth_tdes(
|
||||
MfUltralightPoller* instance,
|
||||
MfUltralightPollerAuthContext* data);
|
||||
|
||||
/**
|
||||
* @brief Start authentication procedure.
|
||||
*
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "mf_ultralight_poller_i.h"
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define TAG "MfUltralightPoller"
|
||||
|
||||
@@ -63,38 +62,6 @@ MfUltralightError mf_ultralight_poller_auth_pwd(
|
||||
return ret;
|
||||
}
|
||||
|
||||
MfUltralightError mf_ultralight_poller_auth_tdes(
|
||||
MfUltralightPoller* instance,
|
||||
MfUltralightPollerAuthContext* data) {
|
||||
furi_check(instance);
|
||||
furi_check(data);
|
||||
|
||||
MfUltralightError ret = MfUltralightErrorNone;
|
||||
|
||||
uint8_t output[MF_ULTRALIGHT_C_AUTH_DATA_SIZE];
|
||||
uint8_t RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
|
||||
furi_hal_random_fill_buf(RndA, sizeof(RndA));
|
||||
|
||||
ret = mf_ultralight_poller_authenticate_start(instance, RndA, output);
|
||||
|
||||
if(ret != MfUltralightErrorNone) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t decoded_shifted_RndA[MF_ULTRALIGHT_C_AUTH_RND_BLOCK_SIZE] = {0};
|
||||
const uint8_t* RndB = output + MF_ULTRALIGHT_C_AUTH_RND_B_BLOCK_OFFSET;
|
||||
ret = mf_ultralight_poller_authenticate_end(instance, RndB, output, decoded_shifted_RndA);
|
||||
|
||||
if(ret != MfUltralightErrorNone) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
mf_ultralight_3des_shift_data(RndA);
|
||||
data->auth_success = (memcmp(RndA, decoded_shifted_RndA, sizeof(decoded_shifted_RndA)) == 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static MfUltralightError mf_ultralight_poller_send_authenticate_cmd(
|
||||
MfUltralightPoller* instance,
|
||||
const uint8_t* cmd,
|
||||
|
||||
@@ -11,6 +11,8 @@ extern "C" {
|
||||
#define MF_ULTRALIGHT_POLLER_STANDARD_FWT_FC (60000)
|
||||
#define MF_ULTRALIGHT_MAX_BUFF_SIZE (64)
|
||||
|
||||
#define MF_ULTRALIGHT_DEFAULT_PASSWORD (0xffffffffUL)
|
||||
|
||||
#define MF_ULTRALIGHT_IS_NTAG_I2C(type) \
|
||||
(((type) == MfUltralightTypeNTAGI2C1K) || ((type) == MfUltralightTypeNTAGI2C2K) || \
|
||||
((type) == MfUltralightTypeNTAGI2CPlus1K) || ((type) == MfUltralightTypeNTAGI2CPlus2K))
|
||||
@@ -59,7 +61,6 @@ typedef enum {
|
||||
MfUltralightPollerStateAuthMfulC,
|
||||
MfUltralightPollerStateReadPages,
|
||||
MfUltralightPollerStateTryDefaultPass,
|
||||
MfUltralightPollerStateTryDefaultMfulCKey,
|
||||
MfUltralightPollerStateCheckMfulCAuthStatus,
|
||||
MfUltralightPollerStateReadFailed,
|
||||
MfUltralightPollerStateReadSuccess,
|
||||
|
||||
@@ -134,22 +134,21 @@ static void keys_dict_int_to_str(KeysDict* instance, const uint8_t* key_int, Fur
|
||||
furi_string_cat_printf(key_str, "%02X", key_int[i]);
|
||||
}
|
||||
|
||||
static void keys_dict_str_to_int(KeysDict* instance, FuriString* key_str, uint64_t* key_int) {
|
||||
static void keys_dict_str_to_int(KeysDict* instance, FuriString* key_str, uint8_t* key_out) {
|
||||
furi_assert(instance);
|
||||
furi_assert(key_str);
|
||||
furi_assert(key_int);
|
||||
furi_assert(key_out);
|
||||
|
||||
uint8_t key_byte_tmp;
|
||||
char h, l;
|
||||
|
||||
*key_int = 0ULL;
|
||||
|
||||
// Process two hex characters at a time to create each byte
|
||||
for(size_t i = 0; i < instance->key_size_symbols - 1; i += 2) {
|
||||
h = furi_string_get_char(key_str, i);
|
||||
l = furi_string_get_char(key_str, i + 1);
|
||||
|
||||
args_char_to_hex(h, l, &key_byte_tmp);
|
||||
*key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2));
|
||||
key_out[i / 2] = key_byte_tmp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,15 +192,7 @@ bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size) {
|
||||
bool key_read = keys_dict_get_next_key_str(instance, temp_key);
|
||||
|
||||
if(key_read) {
|
||||
size_t tmp_len = key_size;
|
||||
uint64_t key_int = 0;
|
||||
|
||||
keys_dict_str_to_int(instance, temp_key, &key_int);
|
||||
|
||||
while(tmp_len--) {
|
||||
key[tmp_len] = (uint8_t)key_int;
|
||||
key_int >>= 8;
|
||||
}
|
||||
keys_dict_str_to_int(instance, temp_key, key);
|
||||
}
|
||||
|
||||
furi_string_free(temp_key);
|
||||
|
||||
Reference in New Issue
Block a user