core/crypto/hash.h (124 lines of code) (raw):
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license.
#ifndef HASH_H_
#define HASH_H_
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "status/rot_status.h"
/* Hash lengths */
#define SHA1_HASH_LENGTH (160 / 8)
#define SHA256_HASH_LENGTH (256 / 8)
#define SHA384_HASH_LENGTH (384 / 8)
#define SHA512_HASH_LENGTH (512 / 8)
/* Maximum hash length */
#ifdef HASH_ENABLE_SHA512
#define HASH_MAX_HASH_LEN SHA512_HASH_LENGTH
#elif defined HASH_ENABLE_SHA384
#define HASH_MAX_HASH_LEN SHA384_HASH_LENGTH
#else
#define HASH_MAX_HASH_LEN SHA256_HASH_LENGTH
#endif
#define SHA1_BLOCK_SIZE (512 / 8)
#define SHA256_BLOCK_SIZE (512 / 8)
#define SHA384_BLOCK_SIZE (1024 / 8)
#define SHA512_BLOCK_SIZE (1024 / 8)
/**
* The types of hashes supported by the hashing API.
*/
enum hash_type {
HASH_TYPE_SHA1, /**< SHA-1 hash */
HASH_TYPE_SHA256, /**< SHA2-256 hash */
HASH_TYPE_SHA384, /**< SHA2-384 hash */
HASH_TYPE_SHA512, /**< SHA2-512 hash */
HASH_TYPE_INVALID, /**< Invalid hash type. */
};
/* Definitions of hash engine state for internal implementation use, as necessary. These map to
* enum hash_type, except there is the added value indicating there is no active context. */
enum {
HASH_ACTIVE_SHA1 = HASH_TYPE_SHA1, /**< SHA-1 context is active. */
HASH_ACTIVE_SHA256, /**< SHA2-256 context is active. */
HASH_ACTIVE_SHA384, /**< SHA2-384 context is active. */
HASH_ACTIVE_SHA512, /**< SHA2-512 context is active. */
HASH_ACTIVE_NONE = 0xff, /**< No hash context is active. */
};
/**
* A platform-independent API for calculating hashes. Hash engine instances are not guaranteed to
* be thread-safe.
*/
struct hash_engine {
#ifdef HASH_ENABLE_SHA1
/**
* Calculate the SHA-1 hash on a complete set of data.
*
* @param engine The hash engine to use to calculate the hash.
* @param data The data to hash.
* @param length The length of the data.
* @param hash The buffer that will contain the generated hash. It must be large enough to hold
* at least SHA1_HASH_LENGTH bytes.
* @param hash_length The size of the hash buffer.
*
* @return 0 if the hash calculated successfully or an error code.
*/
int (*calculate_sha1) (const struct hash_engine *engine, const uint8_t *data, size_t length,
uint8_t *hash, size_t hash_length);
/**
* Configure the hash engine to process independent blocks of data to calculate the SHA-1 hash
* of the aggregated data.
*
* Every call to start MUST be followed by either a call to finish or cancel.
*
* @param engine The hash engine to configure.
*
* @return 0 if the hash engine was configured successfully or an error code.
*/
int (*start_sha1) (const struct hash_engine *engine);
#endif
/**
* Calculate the SHA2-256 hash on a complete set of data.
*
* @param engine The hash engine to use to calculate the hash.
* @param data The data to hash.
* @param length The length of the data.
* @param hash The buffer that will contain the generated hash. It must be large enough to hold
* at least SHA256_HASH_LENGTH bytes.
* @param hash_length The size of the hash buffer.
*
* @return 0 if the hash calculated successfully or an error code.
*/
int (*calculate_sha256) (const struct hash_engine *engine, const uint8_t *data, size_t length,
uint8_t *hash, size_t hash_length);
/**
* Configure the hash engine to process independent blocks of data to calculate the SHA2-256
* hash of the aggregated data.
*
* Every call to start MUST be followed by either a call to finish or cancel.
*
* @param engine The hash engine to configure.
*
* @return 0 if the hash engine was configured successfully or an error code.
*/
int (*start_sha256) (const struct hash_engine *engine);
#ifdef HASH_ENABLE_SHA384
/**
* Calculate the SHA2-384 hash on a complete set of data.
*
* @param engine The hash engine to use to calculate the hash.
* @param data The data to hash.
* @param length The length of the data.
* @param hash The buffer that will contain the generated hash. It must be large enough to hold
* at least SHA384_HASH_LENGTH bytes.
* @param hash_length The size of the hash buffer.
*
* @return 0 if the hash calculated successfully or an error code.
*/
int (*calculate_sha384) (const struct hash_engine *engine, const uint8_t *data, size_t length,
uint8_t *hash, size_t hash_length);
/**
* Configure the hash engine to process independent blocks of data to calculate the SHA2-384
* hash of the aggregated data.
*
* Every call to start MUST be followed by either a call to finish or cancel.
*
* @param engine The hash engine to configure.
*
* @return 0 if the hash engine was configured successfully or an error code.
*/
int (*start_sha384) (const struct hash_engine *engine);
#endif
#ifdef HASH_ENABLE_SHA512
/**
* Calculate the SHA2-512 hash on a complete set of data.
*
* @param engine The hash engine to use to calculate the hash.
* @param data The data to hash.
* @param length The length of the data.
* @param hash The buffer that will contain the generated hash. It must be large enough to hold
* at least SHA512_HASH_LENGTH bytes.
* @param hash_length The size of the hash buffer.
*
* @return 0 if the hash calculated successfully or an error code.
*/
int (*calculate_sha512) (const struct hash_engine *engine, const uint8_t *data, size_t length,
uint8_t *hash, size_t hash_length);
/**
* Configure the hash engine to process independent blocks of data to calculate the SHA2-512
* hash of the aggregated data.
*
* Every call to start MUST be followed by either a call to finish or cancel.
*
* @param engine The hash engine to configure.
*
* @return 0 if the hash engine was configured successfully or an error code.
*/
int (*start_sha512) (const struct hash_engine *engine);
#endif
/**
* Determine the algorithm currently being used for hash calculation.
*
* @param engine The hash engine to query.
*
* @return The active hash algorithm or HASH_TYPE_INVALID if there no hash currently active.
*/
enum hash_type (*get_active_algorithm) (const struct hash_engine *engine);
/**
* Update the current hash operation with a block of data.
*
* @param engine The hash engine to update.
* @param data The data that should be added to generate the final hash.
* @param length The length of the data.
*
* @return 0 if the hash operation was updated successfully or an error code.
*/
int (*update) (const struct hash_engine *engine, const uint8_t *data, size_t length);
/**
* Get the current hash.
*
* The hash engine is still in-progress after the call and must be either finished or
* canceled later.
*
* @param engine The hash engine to get the current hash from.
* @param hash The buffer to hold the current hash.
* @param hash_length The length of the hash buffer.
*
* @return 0 if the hash was retrieved successfully or an error code.
*/
int (*get_hash) (const struct hash_engine *engine, uint8_t *hash, size_t hash_length);
/**
* Complete the current hash operation and get the calculated digest.
*
* If a call to finish fails, finish MUST be called until it succeeds or the operation can be
* terminated with a call to cancel.
*
* @param engine The hash engine to get the final hash from.
* @param hash The buffer to hold the completed hash.
* @param hash_length The length of the hash buffer.
*
* @return 0 if the hash was completed successfully or an error code.
*/
int (*finish) (const struct hash_engine *engine, uint8_t *hash, size_t hash_length);
/**
* Cancel an in-progress hash operation without getting the hash values. After canceling, any
* intermediate hash calculations will be lost and a new hash operation can be started.
*
* @param engine The hash engine to cancel.
*/
void (*cancel) (const struct hash_engine *engine);
};
int hash_start_new_hash (const struct hash_engine *engine, enum hash_type type);
int hash_calculate (const struct hash_engine *engine, enum hash_type type, const uint8_t *data,
size_t length, uint8_t *hash, size_t hash_length);
enum hash_type hash_get_type_from_length (size_t hash_length);
enum hash_type hash_get_type_from_active (uint8_t active);
int hash_get_hash_length (enum hash_type hash_type);
size_t hash_get_active_hash_length (const struct hash_engine *hash);
int hash_get_block_size (enum hash_type hash_type);
bool hash_is_alg_supported (enum hash_type type);
/* HMAC functions */
/**
* The types of hashes that can be used to generate an HMAC.
*/
enum hmac_hash {
HMAC_SHA1 = HASH_TYPE_SHA1, /**< HMAC with SHA-1 hash. */
HMAC_SHA256 = HASH_TYPE_SHA256, /**< HMAC with SHA-256 hash. */
HMAC_SHA384 = HASH_TYPE_SHA384, /**< HMAC with SHA-384 hash. */
HMAC_SHA512 = HASH_TYPE_SHA512, /**< HMAC with SHA-512 hash. */
HMAC_INVALID = HASH_TYPE_INVALID, /**< Invalid HMAC. */
};
/**
* A context for generating an HMAC using partial sets of data.
*/
struct hmac_engine {
const struct hash_engine *hash; /**< The hash engine to use when generating the HMAC. */
enum hmac_hash type; /**< The type of hash being used for the HMAC. */
uint8_t key[SHA512_BLOCK_SIZE]; /**< The key for the HMAC operation. */
size_t block_size; /**< The block size for the hash algorithm. */
size_t hash_length; /**< The digest length for the hash algorithm. */
};
int hash_generate_hmac (const struct hash_engine *engine, const uint8_t *key, size_t key_length,
const uint8_t *data, size_t length, enum hmac_hash hash, uint8_t *hmac, size_t hmac_length);
int hash_hmac_init (struct hmac_engine *engine, const struct hash_engine *hash,
enum hmac_hash hash_type, const uint8_t *key, size_t key_length);
int hash_hmac_update (struct hmac_engine *engine, const uint8_t *data, size_t length);
int hash_hmac_finish (struct hmac_engine *engine, uint8_t *hmac, size_t hmac_length);
void hash_hmac_cancel (struct hmac_engine *engine);
/**
* Determine the output length for an HMAC.
*
* @param type The type of hash used to generate the hmac. This should be an enum hmac_hash value.
*
* @return HMAC length if the hash algorithm is known or HASH_ENGINE_UNKNOWN_HASH.
*/
#define hash_hmac_get_hmac_length(type) hash_get_hash_length ((enum hash_type) (type))
#define HASH_ENGINE_ERROR(code) ROT_ERROR (ROT_MODULE_HASH_ENGINE, code)
/**
* Error codes that can be generated by a hash or HMAC engine.
*/
enum {
HASH_ENGINE_INVALID_ARGUMENT = HASH_ENGINE_ERROR (0x00), /**< Input parameter is null or not valid. */
HASH_ENGINE_NO_MEMORY = HASH_ENGINE_ERROR (0x01), /**< Memory allocation failed. */
HASH_ENGINE_SHA1_FAILED = HASH_ENGINE_ERROR (0x02), /**< The SHA-1 hash was not calculated. */
HASH_ENGINE_SHA256_FAILED = HASH_ENGINE_ERROR (0x03), /**< The SHA-256 hash was not calculated. */
HASH_ENGINE_START_SHA1_FAILED = HASH_ENGINE_ERROR (0x04), /**< The engine has not been initialized for SHA-1. */
HASH_ENGINE_START_SHA256_FAILED = HASH_ENGINE_ERROR (0x05), /**< The engine has not been initialized for SHA-256. */
HASH_ENGINE_UPDATE_FAILED = HASH_ENGINE_ERROR (0x06), /**< The hash has not been updated with new data. */
HASH_ENGINE_FINISH_FAILED = HASH_ENGINE_ERROR (0x07), /**< The hash was not calculated. */
HASH_ENGINE_HASH_BUFFER_TOO_SMALL = HASH_ENGINE_ERROR (0x08), /**< The output buffer is not large enough for the specified hash. */
HASH_ENGINE_NO_ACTIVE_HASH = HASH_ENGINE_ERROR (0x09), /**< No hash has been started for calculation. */
HASH_ENGINE_UNSUPPORTED_HASH = HASH_ENGINE_ERROR (0x0a), /**< The hash is not supported by the engine. */
HASH_ENGINE_HW_NOT_INIT = HASH_ENGINE_ERROR (0x0b), /**< The hash hardware has not been initialized. */
HASH_ENGINE_SHA384_FAILED = HASH_ENGINE_ERROR (0x0c), /**< The SHA-384 hash was not calculated. */
HASH_ENGINE_SHA512_FAILED = HASH_ENGINE_ERROR (0x0d), /**< The SHA-512 hash was not calculated. */
HASH_ENGINE_START_SHA384_FAILED = HASH_ENGINE_ERROR (0x0e), /**< The engine has not been initialized for SHA-384. */
HASH_ENGINE_START_SHA512_FAILED = HASH_ENGINE_ERROR (0x0f), /**< The engine has not been initialized for SHA-512. */
HASH_ENGINE_UNKNOWN_HASH = HASH_ENGINE_ERROR (0x10), /**< An unknown hash type was requested. */
HASH_ENGINE_HASH_IN_PROGRESS = HASH_ENGINE_ERROR (0x11), /**< Attempt to start a new hash before finishing the previous one. */
HASH_ENGINE_SELF_TEST_FAILED = HASH_ENGINE_ERROR (0x12), /**< An internal self-test of the hash engine failed. */
HASH_ENGINE_GET_HASH_FAILED = HASH_ENGINE_ERROR (0x13), /**< Getting the hash failed. */
HASH_ENGINE_UNSUPPORTED_OPERATION = HASH_ENGINE_ERROR (0x14), /**< The requested operation is not supported by the engine. */
HASH_ENGINE_SHA1_SELF_TEST_FAILED = HASH_ENGINE_ERROR (0x15), /**< A SHA-1 self-test of the hash engine failed. */
HASH_ENGINE_SHA256_SELF_TEST_FAILED = HASH_ENGINE_ERROR (0x16), /**< A SHA-256 self-test of the hash engine failed. */
HASH_ENGINE_SHA384_SELF_TEST_FAILED = HASH_ENGINE_ERROR (0x17), /**< A SHA-384 self-test of the hash engine failed. */
HASH_ENGINE_SHA512_SELF_TEST_FAILED = HASH_ENGINE_ERROR (0x18), /**< A SHA-512 self-test of the hash engine failed. */
HASH_ENGINE_HMAC_SHA1_SELF_TEST_FAILED = HASH_ENGINE_ERROR (0x19), /**< A SHA-1 HMAC self-test of the hash engine failed. */
HASH_ENGINE_HMAC_SHA256_SELF_TEST_FAILED = HASH_ENGINE_ERROR (0x1a), /**< A SHA-256 HMAC self-test of the hash engine failed. */
HASH_ENGINE_HMAC_SHA384_SELF_TEST_FAILED = HASH_ENGINE_ERROR (0x1b), /**< A SHA-384 HMAC self-test of the hash engine failed. */
HASH_ENGINE_HMAC_SHA512_SELF_TEST_FAILED = HASH_ENGINE_ERROR (0x1c), /**< A SHA-512 HMAC self-test of the hash engine failed. */
};
#endif /* HASH_H_ */