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 <adrian.warecki@intel.com>
This commit is contained in:
Adrian Warecki 2023-02-27 09:41:47 +01:00 committed by pjdobrowolski
parent 93c5e8b51f
commit 2bd8be35d2
2 changed files with 266 additions and 8 deletions

View File

@ -1,9 +1,11 @@
// SPDX-License-Identifier: BSD-3-Clause
//
// Copyright(c) 2017 Intel Corporation. All rights reserved.
//
// Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
// Keyon Jie <yang.jie@linux.intel.com>
/*
* Copyright(c) 2017 Intel Corporation. All rights reserved.
*
* Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
* Keyon Jie <yang.jie@linux.intel.com>
* Adrian Warecki <adrian.warecki@intel.com>
*/
#include <assert.h>
#include <stdlib.h>
@ -11,8 +13,6 @@
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
@ -20,6 +20,9 @@
#include <rimage/rimage.h>
#include <rimage/manifest.h>
#include <rimage/hash.h>
#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)
{

111
src/include/rimage/hash.h Normal file
View File

@ -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 <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <stdint.h>
/* 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__ */