crypto_wrapper.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #include <furi_hal.h>
  2. #include <lib/mlib/m-dict.h>
  3. #include <toolbox/sha256.h>
  4. #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  5. #include "crypto/gcm.h"
  6. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  7. #include "crypto_wrapper.h"
  8. DICT_DEF2(ESubGhzChatReplayDict, uint64_t, uint32_t)
  9. struct ESugGhzChatCryptoCtx {
  10. uint8_t key[KEY_BITS / 8];
  11. #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  12. gcm_context gcm_ctx;
  13. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  14. ESubGhzChatReplayDict_t replay_dict;
  15. uint64_t run_id;
  16. uint32_t counter;
  17. };
  18. struct ESubGhzChatCryptoMsg {
  19. uint64_t run_id;
  20. uint32_t counter;
  21. uint8_t iv[IV_BYTES];
  22. uint8_t tag[TAG_BYTES];
  23. uint8_t data[0];
  24. } __attribute__ ((packed));
  25. void crypto_init(void)
  26. {
  27. #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  28. /* init the GCM and AES tables */
  29. gcm_initialize();
  30. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  31. }
  32. void crypto_explicit_bzero(void *s, size_t len)
  33. {
  34. memset(s, 0, len);
  35. asm volatile("" ::: "memory");
  36. }
  37. ESubGhzChatCryptoCtx *crypto_ctx_alloc(void)
  38. {
  39. ESubGhzChatCryptoCtx *ret = malloc(sizeof(ESubGhzChatCryptoCtx));
  40. if (ret != NULL) {
  41. memset(ret, 0, sizeof(ESubGhzChatCryptoCtx));
  42. ESubGhzChatReplayDict_init(ret->replay_dict);
  43. ret->run_id = 0;
  44. ret->counter = 1;
  45. }
  46. return ret;
  47. }
  48. void crypto_ctx_free(ESubGhzChatCryptoCtx *ctx)
  49. {
  50. crypto_ctx_clear(ctx);
  51. ESubGhzChatReplayDict_clear(ctx->replay_dict);
  52. free(ctx);
  53. }
  54. void crypto_ctx_clear(ESubGhzChatCryptoCtx *ctx)
  55. {
  56. crypto_explicit_bzero(ctx, sizeof(ESubGhzChatCryptoCtx));
  57. ESubGhzChatReplayDict_reset(ctx->replay_dict);
  58. ctx->run_id = 0;
  59. ctx->counter = 1;
  60. }
  61. static uint64_t crypto_calc_run_id(FuriString *flipper_name, uint32_t tick)
  62. {
  63. const char *fn = furi_string_get_cstr(flipper_name);
  64. size_t fn_len = strlen(fn);
  65. uint8_t h_in[fn_len + sizeof(uint32_t)];
  66. memcpy(h_in, fn, fn_len);
  67. memcpy(h_in + fn_len, &tick, sizeof(uint32_t));
  68. uint8_t h_out[256];
  69. sha256(h_in, fn_len + sizeof(uint32_t), h_out);
  70. uint64_t run_id;
  71. memcpy(&run_id, h_out, sizeof(uint64_t));
  72. return run_id;
  73. }
  74. bool crypto_ctx_set_key(ESubGhzChatCryptoCtx *ctx, const uint8_t *key,
  75. FuriString *flipper_name, uint32_t tick)
  76. {
  77. ctx->run_id = crypto_calc_run_id(flipper_name, tick);
  78. ctx->counter = 1;
  79. memcpy(ctx->key, key, KEY_BITS / 8);
  80. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  81. return true;
  82. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  83. return (gcm_setkey(&(ctx->gcm_ctx), key, KEY_BITS / 8) == 0);
  84. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  85. }
  86. void crypto_ctx_get_key(ESubGhzChatCryptoCtx *ctx, uint8_t *key)
  87. {
  88. memcpy(key, ctx->key, KEY_BITS / 8);
  89. }
  90. bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len,
  91. uint8_t *out)
  92. {
  93. if (in_len < MSG_OVERHEAD + 1) {
  94. return false;
  95. }
  96. struct ESubGhzChatCryptoMsg *msg = (struct ESubGhzChatCryptoMsg *) in;
  97. // check if message is stale, if yes, discard
  98. uint32_t *counter = ESubGhzChatReplayDict_get(ctx->replay_dict,
  99. msg->run_id);
  100. if (counter != NULL) {
  101. if (*counter >= __ntohl(msg->counter)) {
  102. return false;
  103. }
  104. }
  105. // decrypt and auth message
  106. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  107. bool ret = (furi_hal_crypto_gcm_decrypt_and_verify(ctx->key,
  108. msg->iv,
  109. (uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
  110. msg->data, out,
  111. in_len - MSG_OVERHEAD,
  112. msg->tag) == FuriHalCryptoGCMStateOk);
  113. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  114. bool ret = (gcm_auth_decrypt(&(ctx->gcm_ctx),
  115. msg->iv, IV_BYTES,
  116. (uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
  117. msg->data, out,
  118. in_len - MSG_OVERHEAD,
  119. msg->tag, TAG_BYTES) == 0);
  120. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  121. // if auth was successful update replay dict
  122. if (ret) {
  123. ESubGhzChatReplayDict_set_at(ctx->replay_dict, msg->run_id,
  124. __ntohl(msg->counter));
  125. }
  126. return ret;
  127. }
  128. bool crypto_ctx_encrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len,
  129. uint8_t *out)
  130. {
  131. struct ESubGhzChatCryptoMsg *msg = (struct ESubGhzChatCryptoMsg *) out;
  132. // fill message header
  133. msg->run_id = ctx->run_id;
  134. msg->counter = __htonl(ctx->counter);
  135. furi_hal_random_fill_buf(msg->iv, IV_BYTES);
  136. // encrypt message and store tag in header
  137. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  138. bool ret = (furi_hal_crypto_gcm_encrypt_and_tag(ctx->key,
  139. msg->iv,
  140. (uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
  141. in, msg->data,
  142. in_len,
  143. msg->tag) == FuriHalCryptoGCMStateOk);
  144. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  145. bool ret = (gcm_crypt_and_tag(&(ctx->gcm_ctx), ENCRYPT,
  146. msg->iv, IV_BYTES,
  147. (uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
  148. in, msg->data,
  149. in_len,
  150. msg->tag, TAG_BYTES) == 0);
  151. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  152. // increase internal counter
  153. if (ret) {
  154. ctx->counter++;
  155. }
  156. return ret;
  157. }