Skip to content

Commit

Permalink
Add simple replay protection
Browse files Browse the repository at this point in the history
WARNING: This commit will break interoperability with previous versions
of the app!
  • Loading branch information
twisted_pear committed Aug 4, 2023
1 parent 188f2fa commit 72d2a6e
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 26 deletions.
121 changes: 101 additions & 20 deletions crypto_wrapper.c
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
#include <furi_hal.h>
#include <lib/mlib/m-dict.h>
#include <toolbox/sha256.h>

#ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
#include "crypto/gcm.h"
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */

#include "crypto_wrapper.h"

DICT_DEF2(ESubGhzChatReplayDict, uint64_t, uint32_t)

struct ESugGhzChatCryptoCtx {
uint8_t key[KEY_BITS / 8];
#ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
gcm_context gcm_ctx;
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
ESubGhzChatReplayDict_t replay_dict;
uint64_t run_id;
uint32_t counter;
};

struct ESubGhzChatCryptoMsg {
uint64_t run_id;
uint32_t counter;
uint8_t iv[IV_BYTES];
uint8_t tag[TAG_BYTES];
uint8_t data[0];
} __attribute__ ((packed));

void crypto_init(void)
{
#ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
Expand All @@ -33,6 +48,9 @@ ESubGhzChatCryptoCtx *crypto_ctx_alloc(void)

if (ret != NULL) {
memset(ret, 0, sizeof(ESubGhzChatCryptoCtx));
ESubGhzChatReplayDict_init(ret->replay_dict);
ret->run_id = 0;
ret->counter = 1;
}

return ret;
Expand All @@ -41,16 +59,42 @@ ESubGhzChatCryptoCtx *crypto_ctx_alloc(void)
void crypto_ctx_free(ESubGhzChatCryptoCtx *ctx)
{
crypto_ctx_clear(ctx);
ESubGhzChatReplayDict_clear(ctx->replay_dict);
free(ctx);
}

void crypto_ctx_clear(ESubGhzChatCryptoCtx *ctx)
{
crypto_explicit_bzero(ctx, sizeof(ESubGhzChatCryptoCtx));
ESubGhzChatReplayDict_reset(ctx->replay_dict);
ctx->run_id = 0;
ctx->counter = 1;
}

static uint64_t crypto_calc_run_id(FuriString *flipper_name, uint32_t tick)
{
const char *fn = furi_string_get_cstr(flipper_name);
size_t fn_len = strlen(fn);

uint8_t h_in[fn_len + sizeof(uint32_t)];
memcpy(h_in, fn, fn_len);
memcpy(h_in + fn_len, &tick, sizeof(uint32_t));

uint8_t h_out[256];
sha256(h_in, fn_len + sizeof(uint32_t), h_out);

uint64_t run_id;
memcpy(&run_id, h_out, sizeof(uint64_t));

return run_id;
}

bool crypto_ctx_set_key(ESubGhzChatCryptoCtx *ctx, const uint8_t *key)
bool crypto_ctx_set_key(ESubGhzChatCryptoCtx *ctx, const uint8_t *key,
FuriString *flipper_name, uint32_t tick)
{
ctx->run_id = crypto_calc_run_id(flipper_name, tick);
ctx->counter = 1;

memcpy(ctx->key, key, KEY_BITS / 8);
#ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
return true;
Expand All @@ -71,37 +115,74 @@ bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len,
return false;
}

struct ESubGhzChatCryptoMsg *msg = (struct ESubGhzChatCryptoMsg *) in;

// check if message is stale, if yes, discard
uint32_t *counter = ESubGhzChatReplayDict_get(ctx->replay_dict,
msg->run_id);
if (counter != NULL) {
if (*counter >= __ntohl(msg->counter)) {
return false;
}
}

// decrypt and auth message
#ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
return (furi_hal_crypto_gcm_decrypt_and_verify(ctx->key,
in, NULL, 0,
in + IV_BYTES, out,
bool ret = (furi_hal_crypto_gcm_decrypt_and_verify(ctx->key,
msg->iv,
(uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
msg->data, out,
in_len - MSG_OVERHEAD,
in + in_len - TAG_BYTES) == FuriHalCryptoGCMStateOk);
msg->tag) == FuriHalCryptoGCMStateOk);
#else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
return (gcm_auth_decrypt(&(ctx->gcm_ctx),
in, IV_BYTES,
NULL, 0,
in + IV_BYTES, out, in_len - MSG_OVERHEAD,
in + in_len - TAG_BYTES, TAG_BYTES) == 0);
bool ret = (gcm_auth_decrypt(&(ctx->gcm_ctx),
msg->iv, IV_BYTES,
(uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
msg->data, out,
in_len - MSG_OVERHEAD,
msg->tag, TAG_BYTES) == 0);
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */

// if auth was successful update replay dict
if (ret) {
ESubGhzChatReplayDict_set_at(ctx->replay_dict, msg->run_id,
__ntohl(msg->counter));
}

return ret;
}

bool crypto_ctx_encrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len,
uint8_t *out)
{
furi_hal_random_fill_buf(out, IV_BYTES);
struct ESubGhzChatCryptoMsg *msg = (struct ESubGhzChatCryptoMsg *) out;

// fill message header
msg->run_id = ctx->run_id;
msg->counter = __htonl(ctx->counter);
furi_hal_random_fill_buf(msg->iv, IV_BYTES);

// encrypt message and store tag in header
#ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
return (furi_hal_crypto_gcm_encrypt_and_tag(ctx->key,
out, NULL, 0,
in, out + IV_BYTES,
bool ret = (furi_hal_crypto_gcm_encrypt_and_tag(ctx->key,
msg->iv,
(uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
in, msg->data,
in_len,
out + IV_BYTES + in_len) == FuriHalCryptoGCMStateOk);
msg->tag) == FuriHalCryptoGCMStateOk);
#else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
return (gcm_crypt_and_tag(&(ctx->gcm_ctx), ENCRYPT,
out, IV_BYTES,
NULL, 0,
in, out + IV_BYTES, in_len,
out + IV_BYTES + in_len, TAG_BYTES) == 0);
bool ret = (gcm_crypt_and_tag(&(ctx->gcm_ctx), ENCRYPT,
msg->iv, IV_BYTES,
(uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
in, msg->data,
in_len,
msg->tag, TAG_BYTES) == 0);
#endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */

// increase internal counter
if (ret) {
ctx->counter++;
}

return ret;
}
7 changes: 5 additions & 2 deletions crypto_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@
extern "C" {
#endif

#define RUN_ID_BYTES (sizeof(uint64_t))
#define COUNTER_BYTES (sizeof(uint32_t))
#define KEY_BITS 256
#define IV_BYTES 12
#define TAG_BYTES 16

#define MSG_OVERHEAD (IV_BYTES + TAG_BYTES)
#define MSG_OVERHEAD (RUN_ID_BYTES + COUNTER_BYTES + IV_BYTES + TAG_BYTES)

typedef struct ESugGhzChatCryptoCtx ESubGhzChatCryptoCtx;

Expand All @@ -22,7 +24,8 @@ void crypto_ctx_free(ESubGhzChatCryptoCtx *ctx);

void crypto_ctx_clear(ESubGhzChatCryptoCtx *ctx);

bool crypto_ctx_set_key(ESubGhzChatCryptoCtx *ctx, const uint8_t *key);
bool crypto_ctx_set_key(ESubGhzChatCryptoCtx *ctx, const uint8_t *key,
FuriString *flipper_name, uint32_t tick);
void crypto_ctx_get_key(ESubGhzChatCryptoCtx *ctx, uint8_t *key);

bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len,
Expand Down
3 changes: 2 additions & 1 deletion scenes/esubghz_chat_hex_key_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ static void hex_key_input_cb(void* context)

/* initiate the crypto context */
bool ret = crypto_ctx_set_key(state->crypto_ctx,
state->hex_key_input_store);
state->hex_key_input_store, state->name_prefix,
furi_get_tick());

/* cleanup */
crypto_explicit_bzero(state->hex_key_input_store,
Expand Down
3 changes: 2 additions & 1 deletion scenes/esubghz_chat_key_menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ static void key_menu_cb(void* context, uint32_t index)
furi_hal_random_fill_buf(key, KEY_BITS / 8);

/* initiate the crypto context */
bool ret = crypto_ctx_set_key(state->crypto_ctx, key);
bool ret = crypto_ctx_set_key(state->crypto_ctx, key,
state->name_prefix, furi_get_tick());

/* cleanup */
crypto_explicit_bzero(key, sizeof(key));
Expand Down
3 changes: 2 additions & 1 deletion scenes/esubghz_chat_key_read_popup.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ static bool key_read_popup_handle_key_read(ESubGhzChatState *state)

/* initiate the crypto context */
bool ret = crypto_ctx_set_key(state->crypto_ctx,
dev_data->mf_ul_data.data);
dev_data->mf_ul_data.data, state->name_prefix,
furi_get_tick());

/* cleanup */
crypto_explicit_bzero(dev_data->mf_ul_data.data, KEY_BITS / 8);
Expand Down
3 changes: 2 additions & 1 deletion scenes/esubghz_chat_pass_input.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ static bool pass_input_validator(const char *text, FuriString *error,
sha256((unsigned char *) text, strlen(text), key);

/* initiate the crypto context */
bool ret = crypto_ctx_set_key(state->crypto_ctx, key);
bool ret = crypto_ctx_set_key(state->crypto_ctx, key,
state->name_prefix, furi_get_tick());

/* cleanup */
crypto_explicit_bzero(key, sizeof(key));
Expand Down

0 comments on commit 72d2a6e

Please sign in to comment.