// SPDX-License-Identifier: BSD-2-Clause /* * Copyright 2018-2020 NXP * * Crypto Cipher interface implementation to enable HW driver. */ #include #include #include #include #include #include #include #include #include static const struct crypto_cipher_ops cipher_ops; /* * Returns the reference to the driver context * * @ctx Reference the API context pointer */ static struct crypto_cipher *to_cipher_ctx(struct crypto_cipher_ctx *ctx) { assert(ctx && ctx->ops == &cipher_ops); return container_of(ctx, struct crypto_cipher, cipher_ctx); } /* * Free cipher context * * @ctx Reference the API context pointer */ static void cipher_free_ctx(struct crypto_cipher_ctx *ctx) { struct crypto_cipher *cipher = to_cipher_ctx(ctx); if (cipher->op && cipher->op->free_ctx) cipher->op->free_ctx(cipher->ctx); free(cipher); } /* * Copy cipher context * * @dst_ctx [out] Reference the API context pointer destination * @src_ctx Reference the API context pointer source */ static void cipher_copy_state(struct crypto_cipher_ctx *dst_ctx, struct crypto_cipher_ctx *src_ctx) { struct crypto_cipher *cipher_src = to_cipher_ctx(src_ctx); struct crypto_cipher *cipher_dst = to_cipher_ctx(dst_ctx); if (cipher_src->op && cipher_src->op->copy_state) cipher_src->op->copy_state(cipher_dst->ctx, cipher_src->ctx); } /* * Initialization of the cipher operation * * @ctx Reference the API context pointer * @mode Operation mode * @key1 First Key * @key1_len Length of the first key * @key2 Second Key * @key2_len Length of the second key * @iv Initial Vector * @iv_len Length of the IV */ static TEE_Result cipher_init(struct crypto_cipher_ctx *ctx, TEE_OperationMode mode, const uint8_t *key1, size_t key1_len, const uint8_t *key2, size_t key2_len, const uint8_t *iv, size_t iv_len) { TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED; struct crypto_cipher *cipher = to_cipher_ctx(ctx); if ((!key1 && key1_len) || (!key2 && key2_len) || (!iv && iv_len)) { CRYPTO_TRACE("One of the key is not correct"); CRYPTO_TRACE("key1 @%p-%zu bytes", key1, key1_len); CRYPTO_TRACE("key2 @%p-%zu bytes", key1, key1_len); CRYPTO_TRACE("iv @%p-%zu bytes", iv, iv_len); return TEE_ERROR_BAD_PARAMETERS; } if (cipher->op && cipher->op->init) { struct drvcrypt_cipher_init dinit = { .ctx = cipher->ctx, .encrypt = (mode == TEE_MODE_ENCRYPT), .key1.data = (uint8_t *)key1, .key1.length = key1_len, .key2.data = (uint8_t *)key2, .key2.length = key2_len, .iv.data = (uint8_t *)iv, .iv.length = iv_len, }; ret = cipher->op->init(&dinit); } CRYPTO_TRACE("cipher ret 0x%" PRIX32, ret); return ret; } /* * Update of the cipher operation * * @ctx Reference the API context pointer * @last_block True if last block to handle * @data Data to encrypt/decrypt * @len Length of the input data and output result * @dst [out] Output data of the operation */ static TEE_Result cipher_update(struct crypto_cipher_ctx *ctx, bool last_block, const uint8_t *data, size_t len, uint8_t *dst) { TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED; struct crypto_cipher *cipher = to_cipher_ctx(ctx); if (!dst) { CRYPTO_TRACE("Destination buffer error"); return TEE_ERROR_BAD_PARAMETERS; } if (!data && len) { CRYPTO_TRACE("Bad data data @%p-%zu bytes", data, len); return TEE_ERROR_BAD_PARAMETERS; } if (cipher->op && cipher->op->update) { struct drvcrypt_cipher_update dupdate = { .ctx = cipher->ctx, .last = last_block, .src.data = (uint8_t *)data, .src.length = len, .dst.data = dst, .dst.length = len, }; ret = cipher->op->update(&dupdate); } CRYPTO_TRACE("cipher ret 0x%" PRIX32, ret); return ret; } /* * Finalize the cipher operation * * @ctx Reference the API context pointer */ static void cipher_final(struct crypto_cipher_ctx *ctx) { struct crypto_cipher *cipher = to_cipher_ctx(ctx); if (cipher->op && cipher->op->final) cipher->op->final(cipher->ctx); } static const struct crypto_cipher_ops cipher_ops = { .init = cipher_init, .update = cipher_update, .final = cipher_final, .free_ctx = cipher_free_ctx, .copy_state = cipher_copy_state, }; TEE_Result drvcrypt_cipher_alloc_ctx(struct crypto_cipher_ctx **ctx, uint32_t algo) { TEE_Result ret = TEE_ERROR_NOT_IMPLEMENTED; struct crypto_cipher *cipher = NULL; CRYPTO_TRACE("Cipher alloc_ctx algo 0x%" PRIX32, algo); assert(ctx); cipher = calloc(1, sizeof(*cipher)); if (!cipher) return TEE_ERROR_OUT_OF_MEMORY; cipher->op = drvcrypt_get_ops(CRYPTO_CIPHER); if (cipher->op && cipher->op->alloc_ctx) ret = cipher->op->alloc_ctx(&cipher->ctx, algo); if (ret != TEE_SUCCESS) { free(cipher); } else { cipher->cipher_ctx.ops = &cipher_ops; *ctx = &cipher->cipher_ctx; } CRYPTO_TRACE("Cipher alloc_ctx ret 0x%" PRIX32, ret); return ret; }