crypto_wrapper.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #include <furi_hal.h>
  2. #include <lib/mlib/m-dict.h>
  3. #include <mbedtls/sha256.h>
  4. #include <machine/endian.h>
  5. #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  6. #include "crypto/gcm.h"
  7. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  8. #include "crypto_wrapper.h"
  9. DICT_DEF2(ESubGhzChatReplayDict, uint64_t, uint32_t)
  10. struct ESugGhzChatCryptoCtx {
  11. uint8_t key[KEY_BITS / 8];
  12. #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  13. gcm_context gcm_ctx;
  14. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  15. ESubGhzChatReplayDict_t replay_dict;
  16. uint64_t run_id;
  17. uint32_t counter;
  18. };
  19. struct ESubGhzChatCryptoMsg {
  20. uint64_t run_id;
  21. uint32_t counter;
  22. uint8_t iv[IV_BYTES];
  23. uint8_t tag[TAG_BYTES];
  24. uint8_t data[0];
  25. } __attribute__((packed));
  26. void crypto_init(void) {
  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. memset(s, 0, len);
  34. asm volatile("" ::: "memory");
  35. }
  36. ESubGhzChatCryptoCtx* crypto_ctx_alloc(void) {
  37. ESubGhzChatCryptoCtx* ret = malloc(sizeof(ESubGhzChatCryptoCtx));
  38. if(ret != NULL) {
  39. memset(ret, 0, sizeof(ESubGhzChatCryptoCtx));
  40. ESubGhzChatReplayDict_init(ret->replay_dict);
  41. ret->run_id = 0;
  42. ret->counter = 1;
  43. }
  44. return ret;
  45. }
  46. void crypto_ctx_free(ESubGhzChatCryptoCtx* ctx) {
  47. crypto_ctx_clear(ctx);
  48. ESubGhzChatReplayDict_clear(ctx->replay_dict);
  49. free(ctx);
  50. }
  51. void crypto_ctx_clear(ESubGhzChatCryptoCtx* ctx) {
  52. crypto_explicit_bzero(ctx->key, sizeof(ctx->key));
  53. #ifndef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  54. crypto_explicit_bzero(&(ctx->gcm_ctx), sizeof(ctx->gcm_ctx));
  55. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  56. ESubGhzChatReplayDict_reset(ctx->replay_dict);
  57. ctx->run_id = 0;
  58. ctx->counter = 1;
  59. }
  60. static uint64_t crypto_calc_run_id(FuriString* flipper_name, uint32_t tick) {
  61. const char* fn = furi_string_get_cstr(flipper_name);
  62. size_t fn_len = strlen(fn);
  63. uint8_t h_in[fn_len + sizeof(uint32_t)];
  64. memcpy(h_in, fn, fn_len);
  65. memcpy(h_in + fn_len, &tick, sizeof(uint32_t));
  66. uint8_t h_out[256];
  67. mbedtls_sha256(h_in, fn_len + sizeof(uint32_t), h_out, 0);
  68. uint64_t run_id;
  69. memcpy(&run_id, h_out, sizeof(uint64_t));
  70. return run_id;
  71. }
  72. bool crypto_ctx_set_key(
  73. ESubGhzChatCryptoCtx* ctx,
  74. const uint8_t* key,
  75. FuriString* flipper_name,
  76. uint32_t tick) {
  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. memcpy(key, ctx->key, KEY_BITS / 8);
  88. }
  89. bool crypto_ctx_decrypt(ESubGhzChatCryptoCtx* ctx, uint8_t* in, size_t in_len, uint8_t* out) {
  90. if(in_len < MSG_OVERHEAD + 1) {
  91. return false;
  92. }
  93. struct ESubGhzChatCryptoMsg* msg = (struct ESubGhzChatCryptoMsg*)in;
  94. // check if message is stale, if yes, discard
  95. uint32_t* counter = ESubGhzChatReplayDict_get(ctx->replay_dict, msg->run_id);
  96. if(counter != NULL) {
  97. if(*counter >= __ntohl(msg->counter)) {
  98. return false;
  99. }
  100. }
  101. // decrypt and auth message
  102. #ifdef FURI_HAL_CRYPTO_ADVANCED_AVAIL
  103. bool ret =
  104. (furi_hal_crypto_gcm_decrypt_and_verify(
  105. ctx->key,
  106. msg->iv,
  107. (uint8_t*)msg,
  108. RUN_ID_BYTES + COUNTER_BYTES,
  109. msg->data,
  110. out,
  111. in_len - MSG_OVERHEAD,
  112. msg->tag) == FuriHalCryptoGCMStateOk);
  113. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  114. bool ret =
  115. (gcm_auth_decrypt(
  116. &(ctx->gcm_ctx),
  117. msg->iv,
  118. IV_BYTES,
  119. (uint8_t*)msg,
  120. RUN_ID_BYTES + COUNTER_BYTES,
  121. msg->data,
  122. out,
  123. in_len - MSG_OVERHEAD,
  124. msg->tag,
  125. TAG_BYTES) == 0);
  126. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  127. // if auth was successful update replay dict
  128. if(ret) {
  129. ESubGhzChatReplayDict_set_at(ctx->replay_dict, msg->run_id, __ntohl(msg->counter));
  130. }
  131. return ret;
  132. }
  133. bool crypto_ctx_encrypt(ESubGhzChatCryptoCtx* ctx, uint8_t* in, size_t in_len, uint8_t* out) {
  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 =
  142. (furi_hal_crypto_gcm_encrypt_and_tag(
  143. ctx->key,
  144. msg->iv,
  145. (uint8_t*)msg,
  146. RUN_ID_BYTES + COUNTER_BYTES,
  147. in,
  148. msg->data,
  149. in_len,
  150. msg->tag) == FuriHalCryptoGCMStateOk);
  151. #else /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  152. bool ret =
  153. (gcm_crypt_and_tag(
  154. &(ctx->gcm_ctx),
  155. ENCRYPT,
  156. msg->iv,
  157. IV_BYTES,
  158. (uint8_t*)msg,
  159. RUN_ID_BYTES + COUNTER_BYTES,
  160. in,
  161. msg->data,
  162. in_len,
  163. msg->tag,
  164. TAG_BYTES) == 0);
  165. #endif /* FURI_HAL_CRYPTO_ADVANCED_AVAIL */
  166. // update replay dict and increase internal counter
  167. if(ret) {
  168. ESubGhzChatReplayDict_set_at(ctx->replay_dict, ctx->run_id, ctx->counter);
  169. ctx->counter++;
  170. }
  171. return ret;
  172. }
  173. size_t crypto_ctx_dump_replay_dict(
  174. ESubGhzChatCryptoCtx* ctx,
  175. CryptoCtxReplayDictWriter writer,
  176. void* writer_ctx) {
  177. size_t ret = 0;
  178. ESubGhzChatReplayDict_it_t i;
  179. for(ESubGhzChatReplayDict_it(i, ctx->replay_dict); !ESubGhzChatReplayDict_end_p(i);
  180. ESubGhzChatReplayDict_next(i), ret++) {
  181. ESubGhzChatReplayDict_itref_t* ref = ESubGhzChatReplayDict_ref(i);
  182. if(!writer(ref->key, ref->value, writer_ctx)) {
  183. break;
  184. }
  185. }
  186. return ret;
  187. }
  188. size_t crypto_ctx_read_replay_dict(
  189. ESubGhzChatCryptoCtx* ctx,
  190. CryptoCtxReplayDictReader reader,
  191. void* reader_ctx) {
  192. size_t ret = 0;
  193. uint64_t run_id;
  194. uint32_t counter;
  195. while(reader(&run_id, &counter, reader_ctx)) {
  196. ESubGhzChatReplayDict_set_at(ctx->replay_dict, run_id, counter);
  197. ret++;
  198. }
  199. return ret;
  200. }