esp_hmac.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. /*
  2. * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. */
  6. #include <string.h>
  7. #include "rom/efuse.h"
  8. #include "rom/hmac.h"
  9. #include "rom/ets_sys.h"
  10. #include "esp_efuse.h"
  11. #include "esp_efuse_table.h"
  12. #include "esp_hmac.h"
  13. #include "esp_log.h"
  14. #include "esp_crypto_lock.h"
  15. #include "soc/hwcrypto_reg.h"
  16. #include "soc/system_reg.h"
  17. #if !CONFIG_IDF_TARGET_ESP32S2
  18. #include "hal/hmac_hal.h"
  19. #include "esp_private/periph_ctrl.h"
  20. #endif
  21. #define SHA256_BLOCK_SZ 64
  22. #define SHA256_PAD_SZ 8
  23. #if defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32S2)
  24. #define JTAG_STATUS_BIT ESP_EFUSE_HARD_DIS_JTAG
  25. #else
  26. /* For ESP32C3, ESP32C6, ESP32H2 */
  27. #define JTAG_STATUS_BIT ESP_EFUSE_DIS_PAD_JTAG
  28. #endif
  29. static const char *TAG = "esp_hmac";
  30. #if !CONFIG_IDF_TARGET_ESP32S2
  31. /**
  32. * @brief Apply the HMAC padding without the embedded length.
  33. *
  34. * @note This function does not check the data length, it is the responsibility of the other functions in this
  35. * module to make sure that \c data_len is at most SHA256_BLOCK_SZ - 1 so the padding fits in.
  36. * Otherwise, this function has undefined behavior.
  37. * Note however, that for the actual HMAC implementation, the length also needs to be applied at the end
  38. * of the block. This function alone deosn't do that.
  39. */
  40. static void write_and_padd(uint8_t *block, const uint8_t *data, uint16_t data_len)
  41. {
  42. memcpy(block, data, data_len);
  43. // Apply a one bit, followed by zero bits (refer to the TRM of respective target).
  44. block[data_len] = 0x80;
  45. bzero(block + data_len + 1, SHA256_BLOCK_SZ - data_len - 1);
  46. }
  47. esp_err_t esp_hmac_calculate(hmac_key_id_t key_id,
  48. const void *message,
  49. size_t message_len,
  50. uint8_t *hmac)
  51. {
  52. const uint8_t *message_bytes = (const uint8_t *)message;
  53. if (!message || !hmac) {
  54. return ESP_ERR_INVALID_ARG;
  55. }
  56. if (key_id >= HMAC_KEY_MAX) {
  57. return ESP_ERR_INVALID_ARG;
  58. }
  59. esp_crypto_hmac_lock_acquire();
  60. // We also enable SHA and DS here. SHA is used by HMAC, DS will otherwise hold SHA in reset state.
  61. periph_module_enable(PERIPH_HMAC_MODULE);
  62. periph_module_enable(PERIPH_SHA_MODULE);
  63. periph_module_enable(PERIPH_DS_MODULE);
  64. hmac_hal_start();
  65. uint32_t conf_error = hmac_hal_configure(HMAC_OUTPUT_USER, key_id);
  66. if (conf_error) {
  67. esp_crypto_hmac_lock_release();
  68. return ESP_FAIL;
  69. }
  70. if (message_len + 1 + SHA256_PAD_SZ <= SHA256_BLOCK_SZ) {
  71. // If message including padding is only one block...
  72. // Last message block, so apply SHA-256 padding rules in software
  73. uint8_t block[SHA256_BLOCK_SZ];
  74. uint64_t bit_len = __builtin_bswap64(message_len * 8 + 512);
  75. write_and_padd(block, message_bytes, message_len);
  76. // Final block: append the bit length in this block and signal padding to peripheral
  77. memcpy(block + SHA256_BLOCK_SZ - sizeof(bit_len),
  78. &bit_len, sizeof(bit_len));
  79. hmac_hal_write_one_block_512(block);
  80. } else {
  81. // If message including padding is needs more than one block
  82. // write all blocks without padding except the last one
  83. size_t remaining_blocks = message_len / SHA256_BLOCK_SZ;
  84. for (int i = 1; i < remaining_blocks; i++) {
  85. hmac_hal_write_block_512(message_bytes);
  86. message_bytes += SHA256_BLOCK_SZ;
  87. hmac_hal_next_block_normal();
  88. }
  89. // If message fits into one block but without padding, we must not write another block.
  90. if (remaining_blocks) {
  91. hmac_hal_write_block_512(message_bytes);
  92. message_bytes += SHA256_BLOCK_SZ;
  93. }
  94. size_t remaining = message_len % SHA256_BLOCK_SZ;
  95. // Last message block, so apply SHA-256 padding rules in software
  96. uint8_t block[SHA256_BLOCK_SZ];
  97. uint64_t bit_len = __builtin_bswap64(message_len * 8 + 512);
  98. // If the remaining message and appended padding doesn't fit into a single block, we have to write an
  99. // extra block with the rest of the message and potential padding first.
  100. if (remaining >= SHA256_BLOCK_SZ - SHA256_PAD_SZ) {
  101. write_and_padd(block, message_bytes, remaining);
  102. hmac_hal_next_block_normal();
  103. hmac_hal_write_block_512(block);
  104. bzero(block, SHA256_BLOCK_SZ);
  105. } else {
  106. write_and_padd(block, message_bytes, remaining);
  107. }
  108. memcpy(block + SHA256_BLOCK_SZ - sizeof(bit_len),
  109. &bit_len, sizeof(bit_len));
  110. hmac_hal_next_block_padding();
  111. hmac_hal_write_block_512(block);
  112. }
  113. // Read back result (bit swapped)
  114. hmac_hal_read_result_256(hmac);
  115. periph_module_disable(PERIPH_DS_MODULE);
  116. periph_module_disable(PERIPH_SHA_MODULE);
  117. periph_module_disable(PERIPH_HMAC_MODULE);
  118. esp_crypto_hmac_lock_release();
  119. return ESP_OK;
  120. }
  121. static ets_efuse_block_t convert_key_type(hmac_key_id_t key_id) {
  122. return ETS_EFUSE_BLOCK_KEY0 + (ets_efuse_block_t) key_id;
  123. }
  124. esp_err_t esp_hmac_jtag_enable(hmac_key_id_t key_id, const uint8_t *token)
  125. {
  126. int ets_status;
  127. esp_err_t err = ESP_OK;
  128. if ((!token) || (key_id >= HMAC_KEY_MAX))
  129. return ESP_ERR_INVALID_ARG;
  130. /* Check if JTAG is permanently disabled by HW Disable eFuse */
  131. if (esp_efuse_read_field_bit(JTAG_STATUS_BIT)) {
  132. ESP_LOGE(TAG, "JTAG disabled permanently.");
  133. return ESP_FAIL;
  134. }
  135. esp_crypto_hmac_lock_acquire();
  136. ets_status = ets_jtag_enable_temporarily(token, convert_key_type(key_id));
  137. if (ets_status != ETS_OK) {
  138. // ets_jtag_enable_temporarily returns either ETS_OK or ETS_FAIL
  139. err = ESP_FAIL;
  140. ESP_LOGE(TAG, "JTAG re-enabling failed (%d)", err);
  141. }
  142. ESP_LOGD(TAG, "HMAC computation in downstream mode is completed.");
  143. ets_hmac_disable();
  144. esp_crypto_hmac_lock_release();
  145. return err;
  146. }
  147. esp_err_t esp_hmac_jtag_disable()
  148. {
  149. esp_crypto_hmac_lock_acquire();
  150. REG_WRITE(HMAC_SET_INVALIDATE_JTAG_REG, 1);
  151. esp_crypto_hmac_lock_release();
  152. ESP_LOGD(TAG, "Invalidate JTAG result register. JTAG disabled.");
  153. return ESP_OK;
  154. }
  155. #else /* !CONFIG_IDF_TARGET_ESP32S2 */
  156. static ets_efuse_block_t convert_key_type(hmac_key_id_t key_id) {
  157. return ETS_EFUSE_BLOCK_KEY0 + (ets_efuse_block_t) key_id;
  158. }
  159. esp_err_t esp_hmac_calculate(hmac_key_id_t key_id,
  160. const void *message,
  161. size_t message_len,
  162. uint8_t *hmac)
  163. {
  164. int hmac_ret;
  165. if (!message || !hmac) return ESP_ERR_INVALID_ARG;
  166. if (key_id >= HMAC_KEY_MAX) return ESP_ERR_INVALID_ARG;
  167. esp_crypto_dma_lock_acquire();
  168. ets_hmac_enable();
  169. hmac_ret = ets_hmac_calculate_message(convert_key_type(key_id), message, message_len, hmac);
  170. ets_hmac_disable();
  171. esp_crypto_dma_lock_release();
  172. if (hmac_ret != 0) {
  173. return ESP_FAIL;
  174. } else {
  175. return ESP_OK;
  176. }
  177. }
  178. esp_err_t esp_hmac_jtag_enable(hmac_key_id_t key_id, const uint8_t *token)
  179. {
  180. int ets_status;
  181. esp_err_t err = ESP_OK;
  182. if ((!token) || (key_id >= HMAC_KEY_MAX))
  183. return ESP_ERR_INVALID_ARG;
  184. /* Check if JTAG is permanently disabled by HW Disable eFuse */
  185. if (esp_efuse_read_field_bit(ESP_EFUSE_HARD_DIS_JTAG)) {
  186. ESP_LOGE(TAG, "JTAG disabled permanently.");
  187. return ESP_FAIL;
  188. }
  189. esp_crypto_dma_lock_acquire();
  190. ets_hmac_enable();
  191. /* Token updating into HMAC module. */
  192. for (int i = 0; i < 32; i += 4) {
  193. uint32_t key_word;
  194. memcpy(&key_word, &token[i], 4);
  195. REG_WRITE(DPORT_JTAG_CTRL_0_REG + i, __builtin_bswap32(key_word));
  196. }
  197. ets_status = ets_hmac_calculate_downstream(convert_key_type(key_id), ETS_EFUSE_KEY_PURPOSE_HMAC_DOWN_JTAG);
  198. if (ets_status != ETS_OK) {
  199. err = ESP_FAIL;
  200. ESP_LOGE(TAG, "HMAC downstream JTAG enable mode setting failed. (%d)", err);
  201. }
  202. ESP_LOGD(TAG, "HMAC computation in downstream mode is completed.");
  203. ets_hmac_disable();
  204. esp_crypto_dma_lock_release();
  205. return err;
  206. }
  207. esp_err_t esp_hmac_jtag_disable()
  208. {
  209. esp_crypto_dma_lock_acquire();
  210. REG_WRITE(HMAC_SET_INVALIDATE_JTAG_REG, 1);
  211. esp_crypto_dma_lock_release();
  212. ESP_LOGD(TAG, "Invalidate JTAG result register. JTAG disabled.");
  213. return ESP_OK;
  214. }
  215. #endif /* CONFIG_IDF_TARGET_ESP32S2*/