crypto_wrapper.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  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->key, sizeof(ctx->key));
  57. #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  58. crypto_explicit_bzero(&(ctx->gcm_ctx), sizeof(ctx->gcm_ctx));
  59. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  60. ESubGhzChatReplayDict_reset(ctx->replay_dict);
  61. ctx->run_id = 0;
  62. ctx->counter = 1;
  63. }
  64. static uint64_t crypto_calc_run_id(FuriString *flipper_name, uint32_t tick)
  65. {
  66. const char *fn = furi_string_get_cstr(flipper_name);
  67. size_t fn_len = strlen(fn);
  68. uint8_t h_in[fn_len + sizeof(uint32_t)];
  69. memcpy(h_in, fn, fn_len);
  70. memcpy(h_in + fn_len, &tick, sizeof(uint32_t));
  71. uint8_t h_out[256];
  72. sha256(h_in, fn_len + sizeof(uint32_t), h_out);
  73. uint64_t run_id;
  74. memcpy(&run_id, h_out, sizeof(uint64_t));
  75. return run_id;
  76. }
  77. bool crypto_ctx_set_key(ESubGhzChatCryptoCtx *ctx, const uint8_t *key,
  78. FuriString *flipper_name, uint32_t tick)
  79. {
  80. ctx->run_id = crypto_calc_run_id(flipper_name, tick);
  81. ctx->counter = 1;
  82. memcpy(ctx->key, key, KEY_BITS / 8);
  83. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  84. return true;
  85. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  86. return (gcm_setkey(&(ctx->gcm_ctx), key, KEY_BITS / 8) == 0);
  87. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  88. }
  89. void crypto_ctx_get_key(ESubGhzChatCryptoCtx *ctx, uint8_t *key)
  90. {
  91. memcpy(key, ctx->key, KEY_BITS / 8);
  92. }
  93. bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len,
  94. uint8_t *out)
  95. {
  96. if (in_len < MSG_OVERHEAD + 1) {
  97. return false;
  98. }
  99. struct ESubGhzChatCryptoMsg *msg = (struct ESubGhzChatCryptoMsg *) in;
  100. // check if message is stale, if yes, discard
  101. uint32_t *counter = ESubGhzChatReplayDict_get(ctx->replay_dict,
  102. msg->run_id);
  103. if (counter != NULL) {
  104. if (*counter >= __ntohl(msg->counter)) {
  105. return false;
  106. }
  107. }
  108. // decrypt and auth message
  109. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  110. bool ret = (furi_hal_crypto_gcm_decrypt_and_verify(ctx->key,
  111. msg->iv,
  112. (uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
  113. msg->data, out,
  114. in_len - MSG_OVERHEAD,
  115. msg->tag) == FuriHalCryptoGCMStateOk);
  116. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  117. bool ret = (gcm_auth_decrypt(&(ctx->gcm_ctx),
  118. msg->iv, IV_BYTES,
  119. (uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
  120. msg->data, out,
  121. in_len - MSG_OVERHEAD,
  122. msg->tag, TAG_BYTES) == 0);
  123. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  124. // if auth was successful update replay dict
  125. if (ret) {
  126. ESubGhzChatReplayDict_set_at(ctx->replay_dict, msg->run_id,
  127. __ntohl(msg->counter));
  128. }
  129. return ret;
  130. }
  131. bool crypto_ctx_encrypt(ESubGhzChatCryptoCtx *ctx, uint8_t *in, size_t in_len,
  132. uint8_t *out)
  133. {
  134. struct ESubGhzChatCryptoMsg *msg = (struct ESubGhzChatCryptoMsg *) out;
  135. // fill message header
  136. msg->run_id = ctx->run_id;
  137. msg->counter = __htonl(ctx->counter);
  138. furi_hal_random_fill_buf(msg->iv, IV_BYTES);
  139. // encrypt message and store tag in header
  140. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  141. bool ret = (furi_hal_crypto_gcm_encrypt_and_tag(ctx->key,
  142. msg->iv,
  143. (uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
  144. in, msg->data,
  145. in_len,
  146. msg->tag) == FuriHalCryptoGCMStateOk);
  147. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  148. bool ret = (gcm_crypt_and_tag(&(ctx->gcm_ctx), ENCRYPT,
  149. msg->iv, IV_BYTES,
  150. (uint8_t *) msg, RUN_ID_BYTES + COUNTER_BYTES,
  151. in, msg->data,
  152. in_len,
  153. msg->tag, TAG_BYTES) == 0);
  154. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  155. // update replay dict and increase internal counter
  156. if (ret) {
  157. ESubGhzChatReplayDict_set_at(ctx->replay_dict, ctx->run_id,
  158. ctx->counter);
  159. ctx->counter++;
  160. }
  161. return ret;
  162. }
  163. size_t crypto_ctx_dump_replay_dict(ESubGhzChatCryptoCtx *ctx,
  164. CryptoCtxReplayDictWriter writer, void *writer_ctx)
  165. {
  166. size_t ret = 0;
  167. ESubGhzChatReplayDict_it_t i;
  168. for (ESubGhzChatReplayDict_it(i, ctx->replay_dict);
  169. !ESubGhzChatReplayDict_end_p(i);
  170. ESubGhzChatReplayDict_next(i), ret++) {
  171. ESubGhzChatReplayDict_itref_t *ref =
  172. ESubGhzChatReplayDict_ref(i);
  173. if (!writer(ref->key, ref->value, writer_ctx)) {
  174. break;
  175. }
  176. }
  177. return ret;
  178. }
  179. size_t crypto_ctx_read_replay_dict(ESubGhzChatCryptoCtx *ctx,
  180. CryptoCtxReplayDictReader reader, void *reader_ctx)
  181. {
  182. size_t ret = 0;
  183. uint64_t run_id;
  184. uint32_t counter;
  185. while (reader(&run_id, &counter, reader_ctx)) {
  186. ESubGhzChatReplayDict_set_at(ctx->replay_dict, run_id,
  187. counter);
  188. ret++;
  189. }
  190. return ret;
  191. }