core/crypto/aes_xts_mbedtls.c (111 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_xts_mbedtls.h" #include "crypto_logging.h" #include "common/buffer_util.h" #include "mbedtls/aes.h" int aes_xts_mbedtls_set_key (const struct aes_xts_engine *engine, const uint8_t *key, size_t length) { const struct aes_xts_engine_mbedtls *mbedtls = (const struct aes_xts_engine_mbedtls*) engine; int status; if ((mbedtls == NULL) || (key == NULL)) { return AES_XTS_ENGINE_INVALID_ARGUMENT; } status = buffer_compare (key, &key[length / 2], length / 2); if (status == 0) { /* The two AES keys must be different. */ return AES_XTS_ENGINE_MATCHING_KEYS; } status = mbedtls_aes_xts_setkey_enc (&mbedtls->state->encrypt, key, length * 8); if (status == MBEDTLS_ERR_AES_INVALID_KEY_LENGTH) { return AES_XTS_ENGINE_INVALID_KEY_LENGTH; } else if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_AES_XTS_SET_KEY_EC, MBEDTLS_AES_ENCRYPT, status); return status; } status = mbedtls_aes_xts_setkey_dec (&mbedtls->state->decrypt, key, length * 8); if (status != 0) { /* Since the key length has already been validated, that condition doesn't need to be * checked here. */ debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_AES_XTS_SET_KEY_EC, MBEDTLS_AES_DECRYPT, status); return status; } mbedtls->state->has_key = true; return 0; } /** * Perform an AES-XTS encrypt or decrypt operation on one full unit of data. * * @param engine The AES engine to use for the operation. * @param mode The operation to perform. MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT. * @param input The input buffer for the operation. * @param length Length of the XTS data unit. * @param data_unit_id Encoded data unit identifier. * @param output Output buffer for the operation. * @param out_length Length of the output buffer. * * @return 0 if the operation completed successfully or an error code. */ static int aes_xts_mbedtls_crypt (const struct aes_xts_engine *engine, int mode, const uint8_t *input, size_t length, const uint8_t data_unit_id[16], uint8_t *output, size_t out_length) { const struct aes_xts_engine_mbedtls *mbedtls = (const struct aes_xts_engine_mbedtls*) engine; struct mbedtls_aes_xts_context *context; int status; if ((engine == NULL) || (input == NULL) || (data_unit_id == NULL) || (output == NULL)) { return AES_XTS_ENGINE_INVALID_ARGUMENT; } if (out_length < length) { return AES_XTS_ENGINE_OUT_BUFFER_TOO_SMALL; } if (!mbedtls->state->has_key) { return AES_XTS_ENGINE_NO_KEY; } if (mode == MBEDTLS_AES_ENCRYPT) { context = &mbedtls->state->encrypt; } else { context = &mbedtls->state->decrypt; } status = mbedtls_aes_crypt_xts (context, mode, length, data_unit_id, input, output); if (status == MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH) { return AES_XTS_ENGINE_INVALID_DATA_LENGTH; } else if (status != 0) { debug_log_create_entry (DEBUG_LOG_SEVERITY_INFO, DEBUG_LOG_COMPONENT_CRYPTO, CRYPTO_LOG_MSG_MBEDTLS_AES_XTS_CRYPT_EC, mode, status); return status; } return 0; } int aes_xts_mbedtls_encrypt_data (const struct aes_xts_engine *engine, const uint8_t *plaintext, size_t length, const uint8_t data_unit_id[16], uint8_t *ciphertext, size_t out_length) { return aes_xts_mbedtls_crypt (engine, MBEDTLS_AES_ENCRYPT, plaintext, length, data_unit_id, ciphertext, out_length); } int aes_xts_mbedtls_decrypt_data (const struct aes_xts_engine *engine, const uint8_t *ciphertext, size_t length, const uint8_t data_unit_id[16], uint8_t *plaintext, size_t out_length) { return aes_xts_mbedtls_crypt (engine, MBEDTLS_AES_DECRYPT, ciphertext, length, data_unit_id, plaintext, out_length); } /** * Initialize an instance for running AES-XTS operations using mbedTLS. * * @param engine The AES-XTS engine to initialize. * @param state Variable context for AES operations. This must be uninitialized. * * @return 0 if the AES-XTS engine was successfully initialized or an error code. */ int aes_xts_mbedtls_init (struct aes_xts_engine_mbedtls *engine, struct aes_xts_engine_mbedtls_state *state) { if (engine == NULL) { return AES_XTS_ENGINE_INVALID_ARGUMENT; } memset (engine, 0, sizeof (*engine)); engine->base.set_key = aes_xts_mbedtls_set_key; engine->base.encrypt_data = aes_xts_mbedtls_encrypt_data; engine->base.decrypt_data = aes_xts_mbedtls_decrypt_data; engine->state = state; return aes_xts_mbedtls_init_state (engine); } /** * Initialize only the variable state of an mbedTLS AES-XTS 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-XTS engine that contains the state to initialize. * * @return 0 if the state was successfully initialized or an error code. */ int aes_xts_mbedtls_init_state (const struct aes_xts_engine_mbedtls *engine) { if ((engine == NULL) || (engine->state == NULL)) { return AES_XTS_ENGINE_INVALID_ARGUMENT; } memset (engine->state, 0, sizeof (*engine->state)); mbedtls_aes_xts_init (&engine->state->encrypt); mbedtls_aes_xts_init (&engine->state->decrypt); return 0; } /** * Release the resources used by an mbedTLS AES-XTS engine. * * @param engine The AES-XTS engine to release. */ void aes_xts_mbedtls_release (const struct aes_xts_engine_mbedtls *engine) { if (engine) { mbedtls_aes_xts_free (&engine->state->encrypt); mbedtls_aes_xts_free (&engine->state->decrypt); } }