projects/linux/crypto/hash_openssl.c (313 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <openssl/sha.h> #include <stdlib.h> #include <string.h> #include "hash_openssl.h" #ifdef HASH_ENABLE_SHA1 int hash_openssl_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_openssl *openssl = (const struct hash_engine_openssl*) engine; if ((openssl == NULL) || ((data == NULL) && (length != 0)) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (hash_length < SHA1_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } SHA1 (data, length, hash); return 0; } int hash_openssl_start_sha1 (const struct hash_engine *engine) { const struct hash_engine_openssl *openssl = (const struct hash_engine_openssl*) engine; if (openssl == NULL) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (EVP_DigestInit (openssl->state->sha, EVP_sha1 ()) == 1) { openssl->state->active = HASH_ACTIVE_SHA1; return 0; } else { return HASH_ENGINE_START_SHA1_FAILED; } } #endif int hash_openssl_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_openssl *openssl = (const struct hash_engine_openssl*) engine; if ((openssl == NULL) || ((data == NULL) && (length != 0)) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (hash_length < SHA256_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } SHA256 (data, length, hash); return 0; } int hash_openssl_start_sha256 (const struct hash_engine *engine) { const struct hash_engine_openssl *openssl = (const struct hash_engine_openssl*) engine; if (openssl == NULL) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (EVP_DigestInit (openssl->state->sha, EVP_sha256 ()) == 1) { openssl->state->active = HASH_ACTIVE_SHA256; return 0; } else { return HASH_ENGINE_START_SHA256_FAILED; } } #ifdef HASH_ENABLE_SHA384 int hash_openssl_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_openssl *openssl = (const struct hash_engine_openssl*) engine; if ((openssl == NULL) || ((data == NULL) && (length != 0)) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (hash_length < SHA384_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } SHA384 (data, length, hash); return 0; } int hash_openssl_start_sha384 (const struct hash_engine *engine) { const struct hash_engine_openssl *openssl = (const struct hash_engine_openssl*) engine; if (openssl == NULL) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (EVP_DigestInit (openssl->state->sha, EVP_sha384 ()) == 1) { openssl->state->active = HASH_ACTIVE_SHA384; return 0; } else { return HASH_ENGINE_START_SHA384_FAILED; } } #endif #ifdef HASH_ENABLE_SHA512 int hash_openssl_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_openssl *openssl = (const struct hash_engine_openssl*) engine; if ((openssl == NULL) || ((data == NULL) && (length != 0)) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (hash_length < SHA512_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } SHA512 (data, length, hash); return 0; } int hash_openssl_start_sha512 (const struct hash_engine *engine) { const struct hash_engine_openssl *openssl = (const struct hash_engine_openssl*) engine; if (openssl == NULL) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active != HASH_ACTIVE_NONE) { return HASH_ENGINE_HASH_IN_PROGRESS; } if (EVP_DigestInit (openssl->state->sha, EVP_sha512 ()) == 1) { openssl->state->active = HASH_ACTIVE_SHA512; return 0; } else { return HASH_ENGINE_START_SHA512_FAILED; } } #endif enum hash_type hash_openssl_get_active_algorithm (const struct hash_engine *engine) { const struct hash_engine_openssl *openssl = (const struct hash_engine_openssl*) engine; if (openssl == NULL) { return HASH_TYPE_INVALID; } return hash_get_type_from_active (openssl->state->active); } int hash_openssl_update (const struct hash_engine *engine, const uint8_t *data, size_t length) { const struct hash_engine_openssl *openssl = (const struct hash_engine_openssl*) engine; int status; if ((openssl == NULL) || ((data == NULL) && (length != 0))) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active == HASH_ACTIVE_NONE) { return HASH_ENGINE_NO_ACTIVE_HASH; } status = EVP_DigestUpdate (openssl->state->sha, data, length); if (status == 1) { return 0; } else { return HASH_ENGINE_UPDATE_FAILED; } } /** * Check the length of an output buffer to ensure it is large enough for the generated hash. * * @param openssl The hash instance that will be generating the output hash. * @param hash_length Length of the output buffer to check. * * @return 0 if the buffer is large enough for the hash or an error code. */ static int hash_openssl_check_output_buffer_length (const struct hash_engine_openssl *openssl, size_t hash_length) { switch (openssl->state->active) { #ifdef HASH_ENABLE_SHA1 case HASH_ACTIVE_SHA1: if (hash_length < SHA1_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } break; #endif case HASH_ACTIVE_SHA256: if (hash_length < SHA256_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } break; #ifdef HASH_ENABLE_SHA384 case HASH_ACTIVE_SHA384: if (hash_length < SHA384_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } break; #endif #ifdef HASH_ENABLE_SHA512 case HASH_ACTIVE_SHA512: if (hash_length < SHA512_HASH_LENGTH) { return HASH_ENGINE_HASH_BUFFER_TOO_SMALL; } break; #endif default: return HASH_ENGINE_NO_ACTIVE_HASH; } return 0; } int hash_openssl_get_hash (const struct hash_engine *engine, uint8_t *hash, size_t hash_length) { const struct hash_engine_openssl *openssl = (const struct hash_engine_openssl*) engine; EVP_MD_CTX *clone; int status; if ((openssl == NULL) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } if (openssl->state->active == HASH_ACTIVE_NONE) { return HASH_ENGINE_NO_ACTIVE_HASH; } status = hash_openssl_check_output_buffer_length (openssl, hash_length); if (status != 0) { return status; } clone = EVP_MD_CTX_new (); if (clone == NULL) { return HASH_ENGINE_NO_MEMORY; } status = EVP_MD_CTX_copy (clone, openssl->state->sha); if (status == 0) { status = HASH_ENGINE_GET_HASH_FAILED; goto exit; } status = EVP_DigestFinal (clone, hash, NULL); if (status == 1) { status = 0; } else { status = HASH_ENGINE_GET_HASH_FAILED; } exit: EVP_MD_CTX_free (clone); return status; } int hash_openssl_finish (const struct hash_engine *engine, uint8_t *hash, size_t hash_length) { const struct hash_engine_openssl *openssl = (const struct hash_engine_openssl*) engine; int status = 0; if ((openssl == NULL) || (hash == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } status = hash_openssl_check_output_buffer_length (openssl, hash_length); if (status != 0) { return status; } status = EVP_DigestFinal (openssl->state->sha, hash, NULL); if (status == 1) { openssl->state->active = HASH_ACTIVE_NONE; status = 0; } else if (status == 0) { status = HASH_ENGINE_FINISH_FAILED; } return status; } void hash_openssl_cancel (const struct hash_engine *engine) { const struct hash_engine_openssl *openssl = (const struct hash_engine_openssl*) engine; if (openssl) { openssl->state->active = HASH_ACTIVE_NONE; } } /** * Initialize an OpenSSL engine for calculating hashes. * * @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 initialize successfully or an error code. */ int hash_openssl_init (struct hash_engine_openssl *engine, struct hash_engine_openssl_state *state) { if (engine == NULL) { return HASH_ENGINE_INVALID_ARGUMENT; } memset (engine, 0, sizeof (struct hash_engine_openssl)); #ifdef HASH_ENABLE_SHA1 engine->base.calculate_sha1 = hash_openssl_calculate_sha1; engine->base.start_sha1 = hash_openssl_start_sha1; #endif engine->base.calculate_sha256 = hash_openssl_calculate_sha256; engine->base.start_sha256 = hash_openssl_start_sha256; #ifdef HASH_ENABLE_SHA384 engine->base.calculate_sha384 = hash_openssl_calculate_sha384; engine->base.start_sha384 = hash_openssl_start_sha384; #endif #ifdef HASH_ENABLE_SHA512 engine->base.calculate_sha512 = hash_openssl_calculate_sha512; engine->base.start_sha512 = hash_openssl_start_sha512; #endif engine->base.get_active_algorithm = hash_openssl_get_active_algorithm; engine->base.update = hash_openssl_update; engine->base.get_hash = hash_openssl_get_hash; engine->base.finish = hash_openssl_finish; engine->base.cancel = hash_openssl_cancel; engine->state = state; return hash_openssl_init_state (engine); } /** * Initialize only the variable state of an OpenSSL 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_openssl_init_state (const struct hash_engine_openssl *engine) { if ((engine == NULL) || (engine->state == NULL)) { return HASH_ENGINE_INVALID_ARGUMENT; } memset (engine->state, 0, sizeof (*engine->state)); engine->state->sha = EVP_MD_CTX_new (); if (engine->state->sha == NULL) { return HASH_ENGINE_NO_MEMORY; } engine->state->active = HASH_ACTIVE_NONE; return 0; } /** * Release the resources used by an OpenSSL hash engine. * * @param engine The hash engine to release. */ void hash_openssl_release (const struct hash_engine_openssl *engine) { if (engine != NULL) { EVP_MD_CTX_free (engine->state->sha); } }