core/crypto/hash_mbedtls.c (340 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stdlib.h> #include <string.h> #include "hash_mbedtls.h" /** * Free the active hash context. * * @param state The hash engine context that should be freed. */ static void hash_mbedtls_free_context (struct hash_engine_mbedtls_state *state) { switch (state->active) { #ifdef HASH_ENABLE_SHA1 case HASH_ACTIVE_SHA1: mbedtls_sha1_free (&state->context.sha1); break; #endif case HASH_ACTIVE_SHA256: mbedtls_sha256_free (&state->context.sha256); break; #if defined HASH_ENABLE_SHA384 || defined HASH_ENABLE_SHA512 case HASH_ACTIVE_SHA384: case HASH_ACTIVE_SHA512: mbedtls_sha512_free (&state->context.sha512); break; #endif } state->active = HASH_ACTIVE_NONE; } #ifdef HASH_ENABLE_SHA1 int hash_mbedtls_calculate_sha1 (const struct hash_engine *engine, const uint8_t *data, size_t length, uint8_t *hash, size_t hash_length) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; if ((mbedtls == NULL) || ((data == NULL) && (length != 0)) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } if (mbedtls->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (hash_length < SHA1_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } return mbedtls_sha1_ret (data, length, hash); } int hash_mbedtls_start_sha1 (const struct hash_engine *engine) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; int status; if (mbedtls == NULL) { return HASH_ENGINE_INVALID_ARGUMENT; } if (mbedtls->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } mbedtls_sha1_init (&mbedtls->state->context.sha1); status = mbedtls_sha1_starts_ret (&mbedtls->state->context.sha1); if (status != 0) { return status; } mbedtls->state->active = HASH_ACTIVE_SHA1; return 0; } #endif int hash_mbedtls_calculate_sha256 (const struct hash_engine *engine, const uint8_t *data, size_t length, uint8_t *hash, size_t hash_length) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; if ((mbedtls == NULL) || ((data == NULL) && (length != 0)) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } if (mbedtls->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (hash_length < SHA256_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } return mbedtls_sha256_ret (data, length, hash, 0); } int hash_mbedtls_start_sha256 (const struct hash_engine *engine) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; int status; if (mbedtls == NULL) { return HASH_ENGINE_INVALID_ARGUMENT; } if (mbedtls->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } mbedtls_sha256_init (&mbedtls->state->context.sha256); status = mbedtls_sha256_starts_ret (&mbedtls->state->context.sha256, 0); if (status != 0) { return status; } mbedtls->state->active = HASH_ACTIVE_SHA256; return 0; } #ifdef HASH_ENABLE_SHA384 int hash_mbedtls_calculate_sha384 (const struct hash_engine *engine, const uint8_t *data, size_t length, uint8_t *hash, size_t hash_length) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; if ((mbedtls == NULL) || ((data == NULL) && (length != 0)) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } if (mbedtls->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (hash_length < SHA384_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } return mbedtls_sha512_ret (data, length, hash, 1); } int hash_mbedtls_start_sha384 (const struct hash_engine *engine) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; int status; if (mbedtls == NULL) { return HASH_ENGINE_INVALID_ARGUMENT; } if (mbedtls->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } mbedtls_sha512_init (&mbedtls->state->context.sha512); status = mbedtls_sha512_starts_ret (&mbedtls->state->context.sha512, 1); if (status != 0) { return status; } mbedtls->state->active = HASH_ACTIVE_SHA384; return 0; } #endif #ifdef HASH_ENABLE_SHA512 int hash_mbedtls_calculate_sha512 (const struct hash_engine *engine, const uint8_t *data, size_t length, uint8_t *hash, size_t hash_length) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; if ((mbedtls == NULL) || ((data == NULL) && (length != 0)) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } if (mbedtls->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (hash_length < SHA512_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } return mbedtls_sha512_ret (data, length, hash, 0); } int hash_mbedtls_start_sha512 (const struct hash_engine *engine) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; int status; if (mbedtls == NULL) { return HASH_ENGINE_INVALID_ARGUMENT; } if (mbedtls->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } mbedtls_sha512_init (&mbedtls->state->context.sha512); status = mbedtls_sha512_starts_ret (&mbedtls->state->context.sha512, 0); if (status != 0) { return status; } mbedtls->state->active = HASH_ACTIVE_SHA512; return 0; } #endif enum hash_type hash_mbedtls_get_active_algorithm (const struct hash_engine *engine) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; if (mbedtls == NULL) { return HASH_TYPE_INVALID; } return hash_get_type_from_active (mbedtls->state->active); } int hash_mbedtls_update (const struct hash_engine *engine, const uint8_t *data, size_t length) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; int status; if ((mbedtls == NULL) || ((data == NULL) && (length != 0))) { return HASH_ENGINE_INVALID_ARGUMENT; } switch (mbedtls->state->active) { #ifdef HASH_ENABLE_SHA1 case HASH_ACTIVE_SHA1: status = mbedtls_sha1_update_ret (&mbedtls->state->context.sha1, data, length); break; #endif case HASH_ACTIVE_SHA256: status = mbedtls_sha256_update_ret (&mbedtls->state->context.sha256, data, length); break; #if defined HASH_ENABLE_SHA384 || defined HASH_ENABLE_SHA512 case HASH_ACTIVE_SHA384: case HASH_ACTIVE_SHA512: status = mbedtls_sha512_update_ret (&mbedtls->state->context.sha512, data, length); break; #endif default: return HASH_ENGINE_NO_ACTIVE_HASH; } return status; } int hash_mbedtls_get_hash (const struct hash_engine *engine, uint8_t *hash, size_t hash_length) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; struct hash_engine_mbedtls_state mbedtls_clone; int status; if ((mbedtls == NULL) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } mbedtls_clone.active = mbedtls->state->active; switch (mbedtls_clone.active) { #ifdef HASH_ENABLE_SHA1 case HASH_ACTIVE_SHA1: if (hash_length < SHA1_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } mbedtls_sha1_init (&mbedtls_clone.context.sha1); mbedtls_sha1_clone (&mbedtls_clone.context.sha1, &mbedtls->state->context.sha1); status = mbedtls_sha1_finish_ret (&mbedtls_clone.context.sha1, hash); break; #endif case HASH_ACTIVE_SHA256: if (hash_length < SHA256_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } mbedtls_sha256_init (&mbedtls_clone.context.sha256); mbedtls_sha256_clone (&mbedtls_clone.context.sha256, &mbedtls->state->context.sha256); status = mbedtls_sha256_finish_ret (&mbedtls_clone.context.sha256, hash); break; #if defined HASH_ENABLE_SHA384 || defined HASH_ENABLE_SHA512 case HASH_ACTIVE_SHA384: case HASH_ACTIVE_SHA512: if (((mbedtls_clone.active == HASH_ACTIVE_SHA512) && (hash_length < SHA512_HASH_LENGTH)) || ((mbedtls_clone.active == HASH_ACTIVE_SHA384) && (hash_length < SHA384_HASH_LENGTH))) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } mbedtls_sha512_init (&mbedtls_clone.context.sha512); mbedtls_sha512_clone (&mbedtls_clone.context.sha512, &mbedtls->state->context.sha512); status = mbedtls_sha512_finish_ret (&mbedtls_clone.context.sha512, hash); break; #endif default: return HASH_ENGINE_NO_ACTIVE_HASH; } hash_mbedtls_free_context (&mbedtls_clone); return status; } int hash_mbedtls_finish (const struct hash_engine *engine, uint8_t *hash, size_t hash_length) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; int status; if ((mbedtls == NULL) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } switch (mbedtls->state->active) { #ifdef HASH_ENABLE_SHA1 case HASH_ACTIVE_SHA1: if (hash_length < SHA1_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } status = mbedtls_sha1_finish_ret (&mbedtls->state->context.sha1, hash); break; #endif case HASH_ACTIVE_SHA256: if (hash_length < SHA256_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } status = mbedtls_sha256_finish_ret (&mbedtls->state->context.sha256, hash); break; #ifdef HASH_ENABLE_SHA384 case HASH_ACTIVE_SHA384: if (hash_length < SHA384_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } status = mbedtls_sha512_finish_ret (&mbedtls->state->context.sha512, hash); break; #endif #ifdef HASH_ENABLE_SHA512 case HASH_ACTIVE_SHA512: if (hash_length < SHA512_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } status = mbedtls_sha512_finish_ret (&mbedtls->state->context.sha512, hash); break; #endif default: return HASH_ENGINE_NO_ACTIVE_HASH; } if (status == 0) { hash_mbedtls_free_context (mbedtls->state); } return status; } void hash_mbedtls_cancel (const struct hash_engine *engine) { const struct hash_engine_mbedtls *mbedtls = (const struct hash_engine_mbedtls*) engine; if (mbedtls) { hash_mbedtls_free_context (mbedtls->state); } } /** * Initialize an mbedTLS hash engine. * * @param engine The hash engine to initialize. * @param state Variable context for the hash engine. This must be uninitialized. * * @return 0 if the hash engine was successfully initialized or an error code. */ int hash_mbedtls_init (struct hash_engine_mbedtls *engine, struct hash_engine_mbedtls_state *state) { if ((engine == NULL) || (state == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } memset (engine, 0, sizeof (struct hash_engine_mbedtls)); #ifdef HASH_ENABLE_SHA1 engine->base.calculate_sha1 = hash_mbedtls_calculate_sha1; engine->base.start_sha1 = hash_mbedtls_start_sha1; #endif engine->base.calculate_sha256 = hash_mbedtls_calculate_sha256; engine->base.start_sha256 = hash_mbedtls_start_sha256; #ifdef HASH_ENABLE_SHA384 engine->base.calculate_sha384 = hash_mbedtls_calculate_sha384; engine->base.start_sha384 = hash_mbedtls_start_sha384; #endif #ifdef HASH_ENABLE_SHA512 engine->base.calculate_sha512 = hash_mbedtls_calculate_sha512; engine->base.start_sha512 = hash_mbedtls_start_sha512; #endif engine->base.get_active_algorithm = hash_mbedtls_get_active_algorithm; engine->base.update = hash_mbedtls_update; engine->base.get_hash = hash_mbedtls_get_hash; engine->base.finish = hash_mbedtls_finish; engine->base.cancel = hash_mbedtls_cancel; engine->state = state; return hash_mbedtls_init_state (engine); } /** * Initialize only the variable state of an mbedTLS hash engine. The rest of the instance is * assumed to already have been initialized. * * This would generally be used with a statically initialized instance. * * @param engine The hash engine that contains the state to initialize. * * @return 0 if the state was successfully initialized or an error code. */ int hash_mbedtls_init_state (const struct hash_engine_mbedtls *engine) { if ((engine == NULL) || (engine->state == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } memset (engine->state, 0, sizeof (*engine->state)); engine->state->active = HASH_ACTIVE_NONE; return 0; } /** * Release the resources used by an mbedTLS hash engine. * * @param engine The hash engine to release. */ void hash_mbedtls_release (const struct hash_engine_mbedtls *engine) { if (engine != NULL) { hash_mbedtls_free_context (engine->state); } }