| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- #include <furi_hal.h>
- #include <lib/mlib/m-dict.h>
- #include <mbedtls/sha256.h>
- #include <machine/endian.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
- /* init the GCM and AES tables */
- gcm_initialize();
- #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
- }
- void crypto_explicit_bzero(void* s, size_t len) {
- memset(s, 0, len);
- asm volatile("" ::: "memory");
- }
- ESubGhzChatCryptoCtx* crypto_ctx_alloc(void) {
- ESubGhzChatCryptoCtx* ret = malloc(sizeof(ESubGhzChatCryptoCtx));
- if(ret != NULL) {
- memset(ret, 0, sizeof(ESubGhzChatCryptoCtx));
- ESubGhzChatReplayDict_init(ret->replay_dict);
- ret->run_id = 0;
- ret->counter = 1;
- }
- return ret;
- }
- 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->key, sizeof(ctx->key));
- #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
- crypto_explicit_bzero(&(ctx->gcm_ctx), sizeof(ctx->gcm_ctx));
- #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
- 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];
- mbedtls_sha256(h_in, fn_len + sizeof(uint32_t), h_out, 0);
- 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,
- 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;
- #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
- return (gcm_setkey(&(ctx->gcm_ctx), key, KEY_BITS / 8) == 0);
- #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
- }
- void crypto_ctx_get_key(ESubGhzChatCryptoCtx* ctx, uint8_t* key) {
- memcpy(key, ctx->key, KEY_BITS / 8);
- }
- bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx* ctx, uint8_t* in, size_t in_len, uint8_t* out) {
- if(in_len < MSG_OVERHEAD + 1) {
- 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
- 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,
- msg->tag) == FuriHalCryptoGCMStateOk);
- #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
- 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) {
- 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
- 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,
- msg->tag) == FuriHalCryptoGCMStateOk);
- #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
- 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 */
- // update replay dict and increase internal counter
- if(ret) {
- ESubGhzChatReplayDict_set_at(ctx->replay_dict, ctx->run_id, ctx->counter);
- ctx->counter++;
- }
- return ret;
- }
- size_t crypto_ctx_dump_replay_dict(
- ESubGhzChatCryptoCtx* ctx,
- CryptoCtxReplayDictWriter writer,
- void* writer_ctx) {
- size_t ret = 0;
- ESubGhzChatReplayDict_it_t i;
- for(ESubGhzChatReplayDict_it(i, ctx->replay_dict); !ESubGhzChatReplayDict_end_p(i);
- ESubGhzChatReplayDict_next(i), ret++) {
- ESubGhzChatReplayDict_itref_t* ref = ESubGhzChatReplayDict_ref(i);
- if(!writer(ref->key, ref->value, writer_ctx)) {
- break;
- }
- }
- return ret;
- }
- size_t crypto_ctx_read_replay_dict(
- ESubGhzChatCryptoCtx* ctx,
- CryptoCtxReplayDictReader reader,
- void* reader_ctx) {
- size_t ret = 0;
- uint64_t run_id;
- uint32_t counter;
- while(reader(&run_id, &counter, reader_ctx)) {
- ESubGhzChatReplayDict_set_at(ctx->replay_dict, run_id, counter);
- ret++;
- }
- return ret;
- }
|