crypto_wrapper.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. #include <furi_hal.h>
  2. #include <lib/mlib/m-dict.h>
  3. #include <mbedtls/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. #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  27. /* init the GCM and AES tables */
  28. gcm_initialize();
  29. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  30. }
  31. void crypto_explicit_bzero(void* s, size_t len) {
  32. memset(s, 0, len);
  33. asm volatile("" ::: "memory");
  34. }
  35. ESubGhzChatCryptoCtx* crypto_ctx_alloc(void) {
  36. ESubGhzChatCryptoCtx* ret = malloc(sizeof(ESubGhzChatCryptoCtx));
  37. if(ret != NULL) {
  38. memset(ret, 0, sizeof(ESubGhzChatCryptoCtx));
  39. ESubGhzChatReplayDict_init(ret->replay_dict);
  40. ret->run_id = 0;
  41. ret->counter = 1;
  42. }
  43. return ret;
  44. }
  45. void crypto_ctx_free(ESubGhzChatCryptoCtx* ctx) {
  46. crypto_ctx_clear(ctx);
  47. ESubGhzChatReplayDict_clear(ctx->replay_dict);
  48. free(ctx);
  49. }
  50. void crypto_ctx_clear(ESubGhzChatCryptoCtx* ctx) {
  51. crypto_explicit_bzero(ctx->key, sizeof(ctx->key));
  52. #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  53. crypto_explicit_bzero(&(ctx->gcm_ctx), sizeof(ctx->gcm_ctx));
  54. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  55. ESubGhzChatReplayDict_reset(ctx->replay_dict);
  56. ctx->run_id = 0;
  57. ctx->counter = 1;
  58. }
  59. static uint64_t crypto_calc_run_id(FuriString* flipper_name, uint32_t tick) {
  60. const char* fn = furi_string_get_cstr(flipper_name);
  61. size_t fn_len = strlen(fn);
  62. uint8_t h_in[fn_len + sizeof(uint32_t)];
  63. memcpy(h_in, fn, fn_len);
  64. memcpy(h_in + fn_len, &tick, sizeof(uint32_t));
  65. uint8_t h_out[256];
  66. mbedtls_sha256(h_in, fn_len + sizeof(uint32_t), h_out, 0);
  67. uint64_t run_id;
  68. memcpy(&run_id, h_out, sizeof(uint64_t));
  69. return run_id;
  70. }
  71. bool crypto_ctx_set_key(
  72. ESubGhzChatCryptoCtx* ctx,
  73. const uint8_t* key,
  74. FuriString* flipper_name,
  75. uint32_t tick) {
  76. ctx->run_id = crypto_calc_run_id(flipper_name, tick);
  77. ctx->counter = 1;
  78. memcpy(ctx->key, key, KEY_BITS / 8);
  79. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  80. return true;
  81. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  82. return (gcm_setkey(&(ctx->gcm_ctx), key, KEY_BITS / 8) == 0);
  83. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  84. }
  85. void crypto_ctx_get_key(ESubGhzChatCryptoCtx* ctx, uint8_t* key) {
  86. memcpy(key, ctx->key, KEY_BITS / 8);
  87. }
  88. bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx* ctx, uint8_t* in, size_t in_len, uint8_t* out) {
  89. if(in_len < MSG_OVERHEAD + 1) {
  90. return false;
  91. }
  92. struct ESubGhzChatCryptoMsg* msg = (struct ESubGhzChatCryptoMsg*)in;
  93. // check if message is stale, if yes, discard
  94. uint32_t* counter = ESubGhzChatReplayDict_get(ctx->replay_dict, msg->run_id);
  95. if(counter != NULL) {
  96. if(*counter >= __ntohl(msg->counter)) {
  97. return false;
  98. }
  99. }
  100. // decrypt and auth message
  101. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  102. bool ret =
  103. (furi_hal_crypto_gcm_decrypt_and_verify(
  104. ctx->key,
  105. msg->iv,
  106. (uint8_t*)msg,
  107. RUN_ID_BYTES + COUNTER_BYTES,
  108. msg->data,
  109. out,
  110. in_len - MSG_OVERHEAD,
  111. msg->tag) == FuriHalCryptoGCMStateOk);
  112. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  113. bool ret =
  114. (gcm_auth_decrypt(
  115. &(ctx->gcm_ctx),
  116. msg->iv,
  117. IV_BYTES,
  118. (uint8_t*)msg,
  119. RUN_ID_BYTES + COUNTER_BYTES,
  120. msg->data,
  121. out,
  122. in_len - MSG_OVERHEAD,
  123. msg->tag,
  124. TAG_BYTES) == 0);
  125. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  126. // if auth was successful update replay dict
  127. if(ret) {
  128. ESubGhzChatReplayDict_set_at(ctx->replay_dict, msg->run_id, __ntohl(msg->counter));
  129. }
  130. return ret;
  131. }
  132. bool crypto_ctx_encrypt(ESubGhzChatCryptoCtx* ctx, uint8_t* in, size_t in_len, uint8_t* out) {
  133. struct ESubGhzChatCryptoMsg* msg = (struct ESubGhzChatCryptoMsg*)out;
  134. // fill message header
  135. msg->run_id = ctx->run_id;
  136. msg->counter = __htonl(ctx->counter);
  137. furi_hal_random_fill_buf(msg->iv, IV_BYTES);
  138. // encrypt message and store tag in header
  139. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  140. bool ret =
  141. (furi_hal_crypto_gcm_encrypt_and_tag(
  142. ctx->key,
  143. msg->iv,
  144. (uint8_t*)msg,
  145. RUN_ID_BYTES + COUNTER_BYTES,
  146. in,
  147. msg->data,
  148. in_len,
  149. msg->tag) == FuriHalCryptoGCMStateOk);
  150. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  151. bool ret =
  152. (gcm_crypt_and_tag(
  153. &(ctx->gcm_ctx),
  154. ENCRYPT,
  155. msg->iv,
  156. IV_BYTES,
  157. (uint8_t*)msg,
  158. RUN_ID_BYTES + COUNTER_BYTES,
  159. in,
  160. msg->data,
  161. in_len,
  162. msg->tag,
  163. TAG_BYTES) == 0);
  164. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  165. // update replay dict and increase internal counter
  166. if(ret) {
  167. ESubGhzChatReplayDict_set_at(ctx->replay_dict, ctx->run_id, ctx->counter);
  168. ctx->counter++;
  169. }
  170. return ret;
  171. }
  172. size_t crypto_ctx_dump_replay_dict(
  173. ESubGhzChatCryptoCtx* ctx,
  174. CryptoCtxReplayDictWriter writer,
  175. void* writer_ctx) {
  176. size_t ret = 0;
  177. ESubGhzChatReplayDict_it_t i;
  178. for(ESubGhzChatReplayDict_it(i, ctx->replay_dict); !ESubGhzChatReplayDict_end_p(i);
  179. ESubGhzChatReplayDict_next(i), ret++) {
  180. ESubGhzChatReplayDict_itref_t* ref = ESubGhzChatReplayDict_ref(i);
  181. if(!writer(ref->key, ref->value, writer_ctx)) {
  182. break;
  183. }
  184. }
  185. return ret;
  186. }
  187. size_t crypto_ctx_read_replay_dict(
  188. ESubGhzChatCryptoCtx* ctx,
  189. CryptoCtxReplayDictReader reader,
  190. void* reader_ctx) {
  191. size_t ret = 0;
  192. uint64_t run_id;
  193. uint32_t counter;
  194. while(reader(&run_id, &counter, reader_ctx)) {
  195. ESubGhzChatReplayDict_set_at(ctx->replay_dict, run_id, counter);
  196. ret++;
  197. }
  198. return ret;
  199. }