From 2bd8be35d21504bcf69dc99e10e36caecc58343e Mon Sep 17 00:00:00 2001 From: Adrian Warecki Date: Mon, 27 Feb 2023 09:41:47 +0100 Subject: [PATCH] hash: New hash functions Prepared a new set of functions for computing digest with error handling. The hash context has been placed into a separate structure. This allows to conveniently pass the calculated digest along with its length and used algorithm. Signed-off-by: Adrian Warecki --- src/hash.c | 163 ++++++++++++++++++++++++++++++++++++-- src/include/rimage/hash.h | 111 ++++++++++++++++++++++++++ 2 files changed, 266 insertions(+), 8 deletions(-) create mode 100644 src/include/rimage/hash.h diff --git a/src/hash.c b/src/hash.c index ff68f82f5..f6409e3cd 100644 --- a/src/hash.c +++ b/src/hash.c @@ -1,9 +1,11 @@ // SPDX-License-Identifier: BSD-3-Clause -// -// Copyright(c) 2017 Intel Corporation. All rights reserved. -// -// Author: Liam Girdwood -// Keyon Jie +/* + * Copyright(c) 2017 Intel Corporation. All rights reserved. + * + * Author: Liam Girdwood + * Keyon Jie + * Adrian Warecki + */ #include #include @@ -11,8 +13,6 @@ #include #include #include -#include -#include #include #include @@ -20,6 +20,9 @@ #include #include +#include + +#define DEBUG_HASH 0 #if OPENSSL_VERSION_NUMBER < 0x10100000L void EVP_MD_CTX_free(EVP_MD_CTX *ctx); @@ -46,7 +49,151 @@ void EVP_MD_CTX_free(EVP_MD_CTX *ctx) } #endif -#define DEBUG_HASH 0 +static int hash_error(struct hash_context *context, int errcode, const char *msg) +{ + EVP_MD_CTX_free(context->context); + context->context = NULL; + context->state = HS_ERROR; + context->error = -errcode; + fprintf(stderr, "hash: %s\n", msg); + return context->error; +} + +int hash_init(struct hash_context *context, const EVP_MD *algo) +{ + assert(context); + assert(algo); + + context->error = 0; + context->digest_length = 0; + context->algo = algo; + + context->context = EVP_MD_CTX_new(); + if (!context->context) + return hash_error(context, ENOMEM, "Unable to allocate hash context."); + + if (!EVP_DigestInit_ex(context->context, context->algo, NULL)) { + EVP_MD_CTX_free(context->context); + return hash_error(context, ENOTRECOVERABLE, "Unable to initialize hash context."); + } + + context->state = HS_UPDATE; + return 0; +} + +int hash_sha256_init(struct hash_context *context) +{ + return hash_init(context, EVP_sha256()); +} + +int hash_sha384_init(struct hash_context *context) +{ + return hash_init(context, EVP_sha384()); +} + +int hash_update(struct hash_context *context, const void *data, size_t size) +{ + assert(context); + assert(data); + + if (context->error) + return context->error; + + assert(context->state == HS_UPDATE); + + if (!EVP_DigestUpdate(context->context, data, size)) + return hash_error(context, EINVAL, "Unable to update hash context."); + + return 0; +} + +int hash_finalize(struct hash_context *context) +{ + assert(context); + + if (context->error) + return context->error; + + assert(context->state == HS_UPDATE); + + if (!EVP_DigestFinal_ex(context->context, context->digest, &context->digest_length)) + return hash_error(context, EINVAL, "Unable to finalize hash context."); + + context->state = HS_DONE; + +#if DEBUG_HASH + fprintf(stdout, "Hash result is: "); + hash_print(context); +#endif + + EVP_MD_CTX_free(context->context); + context->context = NULL; + return 0; +} + +int hash_get_digest(struct hash_context *context, void *output, size_t output_len) +{ + assert(context); + assert(output); + + if (context->error) + return context->error; + + assert(context->state == HS_DONE); + + if (context->digest_length > output_len) + return -ENOBUFS; + + memcpy(output, context->digest, context->digest_length); + return context->digest_length; +} + +void hash_print(struct hash_context *context) +{ + unsigned int i; + + assert(context); + assert(context->state == HS_DONE); + assert(context->digest_length); + + for (i = 0; i < context->digest_length; i++) + fprintf(stdout, "%02x", context->digest[i]); + fprintf(stdout, "\n"); +} + +int hash_single(const void *data, size_t size, const EVP_MD *algo, void *output, size_t output_len) +{ + int algo_out_size; + + assert(algo); + assert(data); + assert(output); + + //algo_out_size = EVP_MD_get_size(algo); + algo_out_size = EVP_MD_size(algo); + if (algo_out_size <= 0) + return -EINVAL; + + if (output_len > algo_out_size) + return -ENOBUFS; + + if (!EVP_Digest(data, size, output, NULL, algo, NULL)) { + fprintf(stderr, "Unable to compute hash."); + return -ENOTRECOVERABLE; + } + + return 0; +} + +int hash_sha256(const void *data, size_t size, void *output, size_t output_len) +{ + return hash_single(data, size, EVP_sha256(), output, output_len); +} + +int hash_sha384(const void *data, size_t size, void *output, size_t output_len) +{ + return hash_single(data, size, EVP_sha384(), output, output_len); +} void module_sha256_create(struct image *image) { diff --git a/src/include/rimage/hash.h b/src/include/rimage/hash.h new file mode 100644 index 000000000..47a00101a --- /dev/null +++ b/src/include/rimage/hash.h @@ -0,0 +1,111 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Copyright(c) 2023 Intel Corporation. All rights reserved. + */ + +#ifndef __HASH_H__ +#define __HASH_H__ + +#include +#include +#include + +#include + +/* Hash context state used to detect invalid use of hash functions */ +enum hash_state { HS_INIT, HS_UPDATE, HS_DONE, HS_ERROR }; + +struct hash_context { + enum hash_state state; + EVP_MD_CTX *context; + const EVP_MD *algo; + uint8_t digest[EVP_MAX_MD_SIZE]; + unsigned int digest_length; + int error; +}; + +/** + * Initialize hash context with given algorithm + * @param [out]context structure storing the hash context + * @param [in]algo hash algorithm + * @return error code, 0 when success + */ +int hash_init(struct hash_context *context, const EVP_MD *algo); + +/** + * Initialize sha256 hash context + * @param [out]context structure storing the hash context + * @return error code, 0 when success + */ +int hash_sha256_init(struct hash_context *context); + +/** + * Initialize sha384 hash context + * @param [out]context structure storing the hash context + * @return error code, 0 when success + */ +int hash_sha384_init(struct hash_context *context); + +/** + * Add data to hash + * @param [in]context structure storing the hash context + * @param [in]data data to be added + * @param [in]size length of data in bytes + * @return error code, 0 when success + */ +int hash_update(struct hash_context *context, const void *data, size_t size); + +/** + * Completes the hash calculation. No more data can be added! + * @param [in]context structure storing the hash context + * @return error code, 0 when success + */ +int hash_finalize(struct hash_context *context); + +/** + * Read out computed digest. Must finalize first. + * @param [in]context structure storing the hash context + * @param [out]output pointer to array where place hash value + * @param [in]output_len size of the output buffer + * @return copied digest length, < 0 if error + */ +int hash_get_digest(struct hash_context *context, void *output, size_t output_len); + +/** + * Print digest value + * @param [in]context structure storing the hash context + */ +void hash_print(struct hash_context *context); + +/** + * Calculates hash of a single memory buffer + * @param [in]data pointer to the data to be processed + * @param [in]size length of the data to be processed + * @param [in]algo hash algorithm + * @param [out]output pointer to array where place hash value + * @param [in]output_len size of the output buffer + * @return error code, 0 when success + */ +int hash_single(const void* data, size_t size, const EVP_MD *algo, void *output, size_t output_len); + +/** + * Calculates sha256 hash of a memory buffer + * @param [in]data pointer to the data to be processed + * @param [in]size length of the data to be processed + * @param [out]output pointer to array where place hash value + * @param [in]output_len size of the output buffer + * @return error code, 0 when success + */ +int hash_sha256(const void* data, size_t size, void *output, size_t output_len); + +/** + * Calculates sha384 hash of a memory buffer + * @param [in]data pointer to the data to be processed + * @param [in]size length of the data to be processed + * @param [out]output pointer to array where place hash value + * @param [in]output_len size of the output buffer + * @return error code, 0 when success + */ +int hash_sha384(const void* data, size_t size, void *output, size_t output_len); + +#endif /* __HASH_H__ */