core/crypto/aes_gcm_mbedtls.c (130 lines of code) (raw):

// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. #include <stddef.h> #include <stdlib.h> #include <string.h> #include "aes_gcm_mbedtls.h" #include "crypto_logging.h" #include "logging/debug_log.h" int aes_gcm_mbedtls_set_key (const struct aes_gcm_engine *engine, const uint8_t *key, size_t length) { const struct aes_gcm_engine_mbedtls *mbedtls = (const struct aes_gcm_engine_mbedtls*) engine; int status; if ((mbedtls == NULL) || (key == NULL)) { return AES_GCM_ENGINE_INVALID_ARGUMENT; } switch (length) { case (128 / 8): case (192 / 8): return AES_GCM_ENGINE_UNSUPPORTED_KEY_LENGTH; case (256 / 8): break; default: return AES_GCM_ENGINE_INVALID_KEY_LENGTH; } status = mbedtls_gcm_setkey (&mbedtls->state->context, MBEDTLS_CIPHER_ID_AES, key, 256); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_AES_GCM_INIT_EC, status, 0); return status; } mbedtls->state->has_key = true; return 0; } int aes_gcm_mbedtls_encrypt_with_add_data (const struct aes_gcm_engine *engine, const uint8_t *plaintext, size_t length, const uint8_t *iv, size_t iv_length, const uint8_t *additional_data, size_t additional_data_length, uint8_t *ciphertext, size_t out_length, uint8_t *tag, size_t tag_length) { const struct aes_gcm_engine_mbedtls *mbedtls = (const struct aes_gcm_engine_mbedtls*) engine; int status; if ((mbedtls == NULL) || (plaintext == NULL) || (length == 0) || (iv == NULL) || (iv_length == 0) || (ciphertext == NULL) || (tag == NULL) || ((additional_data_length > 0) && (additional_data == NULL))) { return AES_GCM_ENGINE_INVALID_ARGUMENT; } if ((out_length < length) || (tag_length < 16)) { return AES_GCM_ENGINE_OUT_BUFFER_TOO_SMALL; } if (!mbedtls->state->has_key) { return AES_GCM_ENGINE_NO_KEY; } status = mbedtls_gcm_crypt_and_tag (&mbedtls->state->context, MBEDTLS_GCM_ENCRYPT, length, iv, iv_length, additional_data, additional_data_length, plaintext, ciphertext, 16, tag); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_AES_GCM_CRYPT_EC, status, 0); return status; } return 0; } int aes_gcm_mbedtls_encrypt_data (const struct aes_gcm_engine *engine, const uint8_t *plaintext, size_t length, const uint8_t *iv, size_t iv_length, uint8_t *ciphertext, size_t out_length, uint8_t *tag, size_t tag_length) { return aes_gcm_mbedtls_encrypt_with_add_data (engine, plaintext, length, iv, iv_length, NULL, 0, ciphertext, out_length, tag, tag_length); } int aes_gcm_mbedtls_decrypt_with_add_data (const struct aes_gcm_engine *engine, const uint8_t *ciphertext, size_t length, const uint8_t *tag, const uint8_t *iv, size_t iv_length, const uint8_t *additional_data, size_t additional_data_length, uint8_t *plaintext, size_t out_length) { const struct aes_gcm_engine_mbedtls *mbedtls = (const struct aes_gcm_engine_mbedtls*) engine; int status; if ((mbedtls == NULL) || (ciphertext == NULL) || (length == 0) || (tag == NULL) || (iv == NULL) || (iv_length == 0) || (plaintext == NULL)) { return AES_GCM_ENGINE_INVALID_ARGUMENT; } if (out_length < length) { return AES_GCM_ENGINE_OUT_BUFFER_TOO_SMALL; } if (!mbedtls->state->has_key) { return AES_GCM_ENGINE_NO_KEY; } status = mbedtls_gcm_auth_decrypt (&mbedtls->state->context, length, iv, iv_length, additional_data, additional_data_length, tag, 16, ciphertext, plaintext); if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_AES_GCM_AUTH_DECRYPT_EC, status, 0); if (status == MBEDTLS_ERR_GCM_AUTH_FAILED) { status = AES_GCM_ENGINE_GCM_AUTH_FAILED; } } return status; } int aes_gcm_mbedtls_decrypt_data (const struct aes_gcm_engine *engine, const uint8_t *ciphertext, size_t length, const uint8_t *tag, const uint8_t *iv, size_t iv_length, uint8_t *plaintext, size_t out_length) { return aes_gcm_mbedtls_decrypt_with_add_data (engine, ciphertext, length, tag, iv, iv_length, NULL, 0, plaintext, out_length); } /** * Initialize an instance for running AES-GCM operations using mbedTLS. * * @param engine The AES engine to initialize. * @param state The state information for the engine. * * @return 0 if the AES engine was successfully initialized or an error code. */ int aes_gcm_mbedtls_init (struct aes_gcm_engine_mbedtls *engine, struct aes_gcm_engine_mbedtls_state *state) { if ((engine == NULL) || (state == NULL)) { return AES_GCM_ENGINE_INVALID_ARGUMENT; } memset (engine, 0, sizeof (struct aes_gcm_engine_mbedtls)); engine->state = state; engine->base.set_key = aes_gcm_mbedtls_set_key; engine->base.encrypt_data = aes_gcm_mbedtls_encrypt_data; engine->base.encrypt_with_add_data = aes_gcm_mbedtls_encrypt_with_add_data; engine->base.decrypt_data = aes_gcm_mbedtls_decrypt_data; engine->base.decrypt_with_add_data = aes_gcm_mbedtls_decrypt_with_add_data; return aes_gcm_mbedtls_init_state (engine); } /** * Initialize only the variable state of an mbedTLS AES-GCM 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 AES-GCM engine that contains the state to initialize. * * @return 0 if the state was successfully initialized or an error code. */ int aes_gcm_mbedtls_init_state (const struct aes_gcm_engine_mbedtls *engine) { if ((engine == NULL) || (engine->state == NULL)) { return AES_GCM_ENGINE_INVALID_ARGUMENT; } memset (engine->state, 0, sizeof (*engine->state)); mbedtls_gcm_init (&engine->state->context); return 0; } /** * Release a mbedTLS AES-GCM engine. * * @param engine The AES engine to release. */ void aes_gcm_mbedtls_release (const struct aes_gcm_engine_mbedtls *engine) { if (engine) { mbedtls_gcm_free (&engine->state->context); } }