File
Blob: firmware/platform/crypto_hash.c
| 1 | #include <string.h> |
| 2 | #include "radio_bridge.h" |
| 3 | #include "esp_err.h" |
| 4 | #include "sdkconfig.h" |
| 5 | #include "mbedtls/md.h" |
| 6 | #include "mbedtls/sha256.h" |
| 7 | #include "mbedtls/sha512.h" |
| 8 | #include "mbedtls/platform_util.h" |
| 9 | |
| 10 | #if !CONFIG_IDF_TARGET_ESP32S3 |
| 11 | #error "Review the SHA context lifetime and hardware locking before porting this adapter" |
| 12 | #endif |
| 13 | |
| 14 | /* The pinned S3 SHA contexts contain only counters, digest words, a partial |
| 15 | * block, and scalar mode flags. Hardware locks are released after each update. |
| 16 | * No native pointer, allocation, or retained peripheral ownership crosses calls. |
| 17 | * Review sha256_alt.h/sha512_alt.h and the port implementations on SDK upgrades. */ |
| 18 | typedef struct { |
| 19 | int32_t bits; |
| 20 | union { |
| 21 | mbedtls_sha256_context sha256; |
| 22 | mbedtls_sha512_context sha512; |
| 23 | } context; |
| 24 | } hash_state; |
| 25 | _Static_assert(sizeof(hash_state) <= RADIO_CRYPTO_HASH_STATE_BYTES, "SHA state ABI capacity"); |
| 26 | |
| 27 | int32_t radio_crypto_sha256(const uint8_t *input, size_t length, uint8_t output[32]) |
| 28 | { |
| 29 | return mbedtls_sha256(input, length, output, 0); |
| 30 | } |
| 31 | |
| 32 | int32_t radio_crypto_hmac(int32_t bits, const uint8_t *key, size_t key_length, |
| 33 | const radio_crypto_part *parts, size_t count, uint8_t *output, |
| 34 | size_t capacity) |
| 35 | { |
| 36 | mbedtls_md_type_t type; |
| 37 | switch (bits) { |
| 38 | case 160: |
| 39 | type = MBEDTLS_MD_SHA1; |
| 40 | break; |
| 41 | case 256: |
| 42 | type = MBEDTLS_MD_SHA256; |
| 43 | break; |
| 44 | case 384: |
| 45 | type = MBEDTLS_MD_SHA384; |
| 46 | break; |
| 47 | default: |
| 48 | return ESP_ERR_INVALID_ARG; |
| 49 | } |
| 50 | if (count > 8 || capacity < (size_t)bits / 8) |
| 51 | return ESP_ERR_INVALID_SIZE; |
| 52 | mbedtls_md_context_t context; |
| 53 | mbedtls_md_init(&context); |
| 54 | int result = mbedtls_md_setup(&context, mbedtls_md_info_from_type(type), 1); |
| 55 | if (!result) |
| 56 | result = mbedtls_md_hmac_starts(&context, key, key_length); |
| 57 | for (size_t i = 0; !result && i < count; i++) |
| 58 | result = mbedtls_md_hmac_update(&context, parts[i].bytes, parts[i].length); |
| 59 | if (!result) |
| 60 | result = mbedtls_md_hmac_finish(&context, output); |
| 61 | mbedtls_md_free(&context); |
| 62 | return result; |
| 63 | } |
| 64 | |
| 65 | int32_t radio_crypto_hash_init(uint8_t out[RADIO_CRYPTO_HASH_STATE_BYTES], int32_t bits) |
| 66 | { |
| 67 | if (bits != 256 && bits != 384) |
| 68 | return ESP_ERR_INVALID_ARG; |
| 69 | hash_state state; |
| 70 | memset(&state, 0, sizeof(state)); |
| 71 | state.bits = bits; |
| 72 | int result; |
| 73 | if (bits == 256) { |
| 74 | mbedtls_sha256_init(&state.context.sha256); |
| 75 | result = mbedtls_sha256_starts(&state.context.sha256, 0); |
| 76 | } else { |
| 77 | mbedtls_sha512_init(&state.context.sha512); |
| 78 | result = mbedtls_sha512_starts(&state.context.sha512, 1); |
| 79 | } |
| 80 | memset(out, 0, RADIO_CRYPTO_HASH_STATE_BYTES); |
| 81 | if (!result) |
| 82 | memcpy(out, &state, sizeof(state)); |
| 83 | mbedtls_platform_zeroize(&state, sizeof(state)); |
| 84 | return result; |
| 85 | } |
| 86 | |
| 87 | int32_t radio_crypto_hash_update(uint8_t bytes[RADIO_CRYPTO_HASH_STATE_BYTES], const uint8_t *input, |
| 88 | size_t length) |
| 89 | { |
| 90 | hash_state state; |
| 91 | memcpy(&state, bytes, sizeof(state)); |
| 92 | int result = ESP_ERR_INVALID_ARG; |
| 93 | if (state.bits == 256) |
| 94 | result = mbedtls_sha256_update(&state.context.sha256, input, length); |
| 95 | else if (state.bits == 384) |
| 96 | result = mbedtls_sha512_update(&state.context.sha512, input, length); |
| 97 | if (!result) |
| 98 | memcpy(bytes, &state, sizeof(state)); |
| 99 | mbedtls_platform_zeroize(&state, sizeof(state)); |
| 100 | return result; |
| 101 | } |
| 102 | |
| 103 | int32_t radio_crypto_hash_finish(const uint8_t bytes[RADIO_CRYPTO_HASH_STATE_BYTES], |
| 104 | uint8_t *output, size_t capacity) |
| 105 | { |
| 106 | hash_state state; |
| 107 | memcpy(&state, bytes, sizeof(state)); |
| 108 | uint8_t digest[64] = {0}; |
| 109 | int result = ESP_ERR_INVALID_ARG; |
| 110 | if (state.bits == 256 && capacity >= 32) |
| 111 | result = mbedtls_sha256_finish(&state.context.sha256, digest); |
| 112 | else if (state.bits == 384 && capacity >= 48) |
| 113 | result = mbedtls_sha512_finish(&state.context.sha512, digest); |
| 114 | if (!result) |
| 115 | memcpy(output, digest, state.bits / 8); |
| 116 | mbedtls_platform_zeroize(digest, sizeof(digest)); |
| 117 | mbedtls_platform_zeroize(&state, sizeof(state)); |
| 118 | return result; |
| 119 | } |