summaryrefslogtreecommitdiff
path: root/drivers/crypto/caam/caamkeyblob.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/crypto/caam/caamkeyblob.c')
-rw-r--r--drivers/crypto/caam/caamkeyblob.c670
1 files changed, 670 insertions, 0 deletions
diff --git a/drivers/crypto/caam/caamkeyblob.c b/drivers/crypto/caam/caamkeyblob.c
new file mode 100644
index 000000000000..5551f6725d79
--- /dev/null
+++ b/drivers/crypto/caam/caamkeyblob.c
@@ -0,0 +1,670 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
+/*
+ * Black key generation and blob encapsulation/decapsulation for CAAM
+ *
+ * Copyright 2018-2020 NXP
+ */
+#include "caamkeyblob.h"
+#include "error.h"
+
+/* Black key generation and blob encap/decap job completion handler */
+static void caam_key_blob_done(struct device *dev, u32 *desc, u32 err,
+ void *context)
+{
+ struct jr_job_result *res = context;
+ int ecode = 0;
+
+ dev_dbg(dev, "%s %d: err 0x%x\n", __func__, __LINE__, err);
+
+ if (err)
+ ecode = caam_jr_strstatus(dev, err);
+
+ /* Save the error for post-processing */
+ res->error = ecode;
+ /* Mark job as complete */
+ complete(&res->completion);
+}
+
+/**
+ * map_write_data - Prepare data to be written to CAAM
+ *
+ * @dev : struct device of the job ring to be used
+ * @data : The data to be prepared
+ * @size : The size of data to be prepared
+ * @dma_addr : The retrieve DMA address of the input data
+ * @allocated_data : Pointer to a DMA-able address where the input
+ * data is copied and synchronized
+ *
+ * Return : '0' on success, error code otherwise
+ */
+static int map_write_data(struct device *dev, const u8 *data, size_t size,
+ dma_addr_t *dma_addr, u8 **allocated_data)
+{
+ int ret = 0;
+
+ /* Allocate memory for data and copy it to DMA zone */
+ *allocated_data = kmemdup(data, size, GFP_KERNEL | GFP_DMA);
+ if (!*allocated_data) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ *dma_addr = dma_map_single(dev, *allocated_data, size, DMA_TO_DEVICE);
+ if (dma_mapping_error(dev, *dma_addr)) {
+ dev_err(dev, "Unable to map write data\n");
+ ret = -ENOMEM;
+ goto free_alloc;
+ }
+
+ goto exit;
+
+free_alloc:
+ kfree(*allocated_data);
+
+exit:
+ return ret;
+}
+
+/**
+ * map_read_data - Prepare data to be read from CAAM
+ *
+ * @dev : struct device of the job ring to be used
+ * @size : The size of data to be prepared
+ * @dma_addr : The retrieve DMA address of the data to be read
+ * @allocated_data : Pointer to a DMA-able address where the data
+ * to be read will be copied and synchronized
+ *
+ * Return : '0' on success, error code otherwise
+ */
+static int map_read_data(struct device *dev, size_t size, dma_addr_t *dma_addr,
+ u8 **allocated_data)
+{
+ int ret = 0;
+
+ /* Allocate memory for data compatible with DMA */
+ *allocated_data = kmalloc(size, GFP_KERNEL | GFP_DMA);
+ if (!*allocated_data) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ *dma_addr = dma_map_single(dev, *allocated_data, size, DMA_FROM_DEVICE);
+ if (dma_mapping_error(dev, *dma_addr)) {
+ dev_err(dev, "Unable to map read data\n");
+ ret = -ENOMEM;
+ goto free_alloc;
+ }
+
+ goto exit;
+
+free_alloc:
+ kfree(*allocated_data);
+
+exit:
+ return ret;
+}
+
+/**
+ * read_map_data - Read the data from CAAM
+ *
+ * @dev : struct device of the job ring to be used
+ * @data : The read data from CAAM will be copied here
+ * @dma_addr : The DMA address of the data to be read
+ * @allocated_data : Pointer to a DMA-able address where the data
+ * to be read is
+ * @size : The size of data to be read
+ */
+static void read_map_data(struct device *dev, u8 *data, dma_addr_t dma_addr,
+ u8 *allocated_data, size_t size)
+{
+ /* Synchronize the DMA and copy the data */
+ dma_sync_single_for_cpu(dev, dma_addr, size, DMA_FROM_DEVICE);
+ memcpy(data, allocated_data, size);
+}
+
+/**
+ * unmap_read_write_data - Unmap the data needed for or from CAAM
+ *
+ * @dev : struct device of the job ring to be used
+ * @dma_addr : The DMA address of the data used for DMA transfer
+ * @allocated_data : The data used for DMA transfer
+ * @size : The size of data
+ * @dir : The DMA_API direction
+ */
+static void unmap_read_write_data(struct device *dev, dma_addr_t dma_addr,
+ u8 *allocated_data, size_t size,
+ enum dma_data_direction dir)
+{
+ /* Free the resources and clear the data*/
+ dma_unmap_single(dev, dma_addr, size, dir);
+ kzfree(allocated_data);
+}
+
+/**
+ * get_caam_dma_addr - Get the CAAM DMA address of a physical address.
+ *
+ * @phy_address : The physical address
+ *
+ * Return : The CAAM DMA address
+ */
+static dma_addr_t get_caam_dma_addr(const void *phy_address)
+{
+ uintptr_t ptr_conv;
+ dma_addr_t caam_dma_address = 0;
+
+ /* Check if conversion is possible */
+ if (sizeof(caam_dma_address) < sizeof(phy_address)) {
+ /*
+ * Check that all bits sets in the phy_address
+ * can be stored in caam_dma_address
+ */
+
+ /* Generate a mask of the representable bits */
+ u64 mask = GENMASK_ULL(sizeof(caam_dma_address) * 8 - 1, 0);
+
+ /*
+ * Check that the bits not representable of
+ * the physical address are not set
+ */
+ if ((uintptr_t)phy_address & ~mask)
+ goto exit;
+ }
+
+ /* Convert address to caam_dma_address */
+ ptr_conv = (uintptr_t)phy_address;
+ caam_dma_address = (dma_addr_t)ptr_conv;
+
+exit:
+ return caam_dma_address;
+}
+
+/**
+ * generate_black_key - Generate a black key from a plaintext or random,
+ * based on the given input: a size for a random black
+ * key, or a plaintext (input key).
+ *
+ * If the memory type is Secure Memory, the key to cover is read
+ * directly by CAAM from Secure Memory without intermediate copy.
+ * The value of the input key (plaintext) must be a physical address
+ * in Secure Memory.
+ *
+ * Notes:
+ * Limited to Class 1 keys, at the present time.
+ * The input and output data are copied to temporary arrays
+ * except for the input key if the memory type is Secure Memory.
+ * For now, we have support for Black keys, stored in General Memory.
+ *
+ * @dev : struct device of the job ring to be used
+ * @info : keyblob_info structure, will be updated with
+ * the black key data from CAAM.
+ * This contains, also, all the data necessary to generate
+ * a black key from plaintext/random like: key encryption
+ * key, memory type, input key, etc.
+ *
+ * Return : '0' on success, error code otherwise
+ */
+int generate_black_key(struct device *dev, struct keyblob_info *info)
+{
+ int ret = 0;
+ bool not_random = false;
+ u8 trusted_key, key_enc;
+ u32 *desc = NULL;
+ size_t black_key_length_req = 0;
+ dma_addr_t black_key_dma;
+ u8 *tmp_black_key = NULL;
+
+ /* Validate device */
+ if (!dev)
+ return -EINVAL;
+
+ /*
+ * If an input key (plaintext) is given,
+ * generate a black key from it, not from random
+ */
+ if (info->key)
+ not_random = true;
+
+ /* Get trusted key and key encryption type from type */
+ trusted_key = (info->type >> TAG_OBJ_TK_OFFSET) & 0x1;
+ key_enc = (info->type >> TAG_OBJ_EKT_OFFSET) & 0x1;
+
+ dev_dbg(dev, "%s input: [key: (%zu) black_key: %p(%zu), key_enc: %x]\n",
+ __func__, info->key_len, info->black_key, info->black_key_len,
+ key_enc);
+ if (not_random)
+ print_hex_dump_debug("input key @" __stringify(__LINE__) ": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, info->key,
+ info->key_len, 1);
+
+ /* Validate key type - only JDKEK keys are supported */
+ if (!is_key_type(info->type) || is_trusted_type(info->type))
+ return -EINVAL;
+
+ /*
+ * Validate key size, expected values are
+ * between 16 and 64 bytes.
+ * See TODO from cnstr_desc_black_key().
+ */
+ if (info->key_len < MIN_KEY_SIZE || info->key_len > MAX_KEY_SIZE)
+ return -EINVAL;
+
+ /*
+ * Based on key encryption type (ecb or ccm),
+ * compute the black key size
+ */
+ if (key_enc == KEY_COVER_ECB)
+ /*
+ * ECB-Black Key will be padded with zeros to make it a
+ * multiple of 16 bytes long before it is encrypted,
+ * and the resulting Black Key will be this length.
+ */
+ black_key_length_req = ECB_BLACK_KEY_SIZE(info->key_len);
+ else if (key_enc == KEY_COVER_CCM)
+ /*
+ * CCM-Black Key will always be at least 12 bytes longer,
+ * since the encapsulation uses a 6-byte nonce and adds
+ * a 6-byte ICV. But first, the key is padded as necessary so
+ * that CCM-Black Key is a multiple of 8 bytes long.
+ */
+ black_key_length_req = CCM_BLACK_KEY_SIZE(info->key_len);
+
+ /* Check if there is enough space for black key */
+ if (info->black_key_len < black_key_length_req) {
+ info->black_key_len = black_key_length_req;
+ return -EINVAL;
+ }
+
+ /* Black key will have at least the same length as the input key */
+ info->black_key_len = info->key_len;
+
+ dev_dbg(dev, "%s processing: [key: (%zu) black_key: %p(%zu)",
+ __func__, info->key_len, info->black_key, info->black_key_len);
+ dev_dbg(dev, "req:%zu, key_enc: 0x%x]\n", black_key_length_req, key_enc);
+
+ /* Map black key, this will be read from CAAM */
+ if (map_read_data(dev, black_key_length_req,
+ &black_key_dma, &tmp_black_key)) {
+ dev_err(dev, "Unable to map black key\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ /* Construct descriptor for black key */
+ if (not_random)
+ ret = cnstr_desc_black_key(&desc, info->key, info->key_len,
+ black_key_dma, info->black_key_len,
+ key_enc, trusted_key);
+ else
+ ret = cnstr_desc_random_black_key(&desc, info->key_len,
+ black_key_dma,
+ info->black_key_len,
+ key_enc, trusted_key);
+
+ if (ret) {
+ dev_err(dev,
+ "Failed to construct the descriptor for black key\n");
+ goto unmap_black_key;
+ }
+
+ /* Execute descriptor and wait for its completion */
+ ret = caam_jr_run_and_wait_for_completion(dev, desc,
+ caam_key_blob_done);
+ if (ret) {
+ dev_err(dev, "Failed to execute black key descriptor\n");
+ goto free_desc;
+ }
+
+ /* Read black key from CAAM */
+ read_map_data(dev, info->black_key, black_key_dma,
+ tmp_black_key, black_key_length_req);
+
+ /* Update black key length with the correct size */
+ info->black_key_len = black_key_length_req;
+
+free_desc:
+ kfree(desc);
+
+unmap_black_key:
+ unmap_read_write_data(dev, black_key_dma, tmp_black_key,
+ black_key_length_req, DMA_FROM_DEVICE);
+
+exit:
+ return ret;
+}
+EXPORT_SYMBOL(generate_black_key);
+
+/**
+ * caam_blob_encap - Encapsulate a black key into a blob
+ *
+ * If the memory type is Secure Memory, the key to encapsulate is read
+ * directly by CAAM from Secure Memory without intermediate copy.
+ * The value of the key (black key) must be a physical address
+ * in Secure Memory.
+ *
+ * Notes:
+ * For now, we have support for Black keys, stored in General Memory and
+ * encapsulated into black blobs.
+ *
+ * @dev : struct device of the job ring to be used
+ * @info : keyblob_info structure, will be updated with
+ * the blob data from CAAM.
+ * This contains, also, all the data necessary to
+ * encapsulate a black key into a blob: key encryption
+ * key, memory type, color, etc.
+ *
+ * Return : '0' on success, error code otherwise
+ */
+int caam_blob_encap(struct device *dev, struct keyblob_info *info)
+{
+ int ret = 0;
+ u32 *desc = NULL;
+ size_t black_key_real_len = 0;
+ size_t blob_req_len = 0;
+ u8 mem_type, color, key_enc, trusted_key;
+ dma_addr_t black_key_dma, blob_dma;
+ unsigned char *blob = info->blob;
+ u8 *tmp_black_key = NULL, *tmp_blob = NULL;
+
+ /* Validate device */
+ if (!dev)
+ return -EINVAL;
+
+ /*
+ * Get memory type, trusted key, key encryption
+ * type and color from type
+ */
+ mem_type = (info->type >> TAG_OBJ_MEM_OFFSET) & 0x1;
+ color = (info->type >> TAG_OBJ_COLOR_OFFSET) & 0x1;
+ key_enc = (info->type >> TAG_OBJ_EKT_OFFSET) & 0x1;
+ trusted_key = (info->type >> TAG_OBJ_TK_OFFSET) & 0x1;
+
+ /* Validate input data*/
+ if (!info->key_mod || !blob)
+ return -EINVAL;
+
+ /* Validate object type - only JDKEK keys are supported */
+ if (is_trusted_type(info->type))
+ return -EINVAL;
+
+ dev_dbg(dev, "%s input:[black_key: %p (%zu) color: %x, key_enc: %x",
+ __func__, info->black_key, info->black_key_len, color, key_enc);
+ dev_dbg(dev, ", key_mod: %p (%zu)", info->key_mod, info->key_mod_len);
+ dev_dbg(dev, "blob: %p (%zu)]\n", blob, info->blob_len);
+
+ /*
+ * Based on memory type, the key modifier length
+ * can be 8-byte or 16-byte.
+ */
+ if (mem_type == DATA_SECMEM)
+ info->key_mod_len = KEYMOD_SIZE_SM;
+ else
+ info->key_mod_len = KEYMOD_SIZE_GM;
+
+ /* Adapt the size of the black key */
+ black_key_real_len = info->black_key_len;
+
+ blob_req_len = CCM_BLACK_KEY_SIZE(info->key_len);
+
+ /* Check if the blob can be stored */
+ if (info->blob_len < (blob_req_len + BLOB_OVERHEAD))
+ return -EINVAL;
+
+ /* Update the blob length */
+ info->blob_len = blob_req_len + BLOB_OVERHEAD;
+
+ dev_dbg(dev, "%s processing: [black_key: %p (%zu) cnstr: %zu",
+ __func__, info->black_key, info->black_key_len,
+ black_key_real_len);
+ dev_dbg(dev, " color: %x key_enc: %x, mem_type: %x,",
+ color, key_enc, mem_type);
+ dev_dbg(dev, ", key_mod: %p (%zu) ", info->key_mod, info->key_mod_len);
+ dev_dbg(dev, "blob: %p (%zu)]\n", blob, info->blob_len);
+
+ /* Map black key, this will be transferred to CAAM */
+ if (mem_type == DATA_GENMEM) {
+ if (map_write_data(dev, info->black_key, info->black_key_len,
+ &black_key_dma, &tmp_black_key)) {
+ dev_err(dev, "Unable to map black key for blob\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ } else {
+ black_key_dma = get_caam_dma_addr(info->black_key);
+ if (!black_key_dma)
+ return -ENOMEM;
+ }
+
+ /* Map blob, this will be read to CAAM */
+ if (mem_type == DATA_GENMEM) {
+ if (map_read_data(dev, info->blob_len, &blob_dma, &tmp_blob)) {
+ dev_err(dev, "Unable to map blob\n");
+ ret = -ENOMEM;
+ goto unmap_black_key;
+ }
+ } else {
+ blob_dma = get_caam_dma_addr(info->blob);
+ if (!blob_dma)
+ return -ENOMEM;
+ }
+
+ /* Construct descriptor for blob encapsulation */
+ ret = cnstr_desc_blob_encap(&desc, black_key_dma, info->key_len,
+ color, key_enc, trusted_key, mem_type,
+ info->key_mod, info->key_mod_len,
+ blob_dma, info->blob_len);
+ if (ret) {
+ dev_err(dev,
+ "Failed to construct the descriptor for blob encap\n");
+ goto unmap_blob;
+ }
+
+ /* Execute descriptor and wait for its completion */
+ ret = caam_jr_run_and_wait_for_completion(dev, desc,
+ caam_key_blob_done);
+ if (ret) {
+ dev_err(dev, "Failed to execute blob encap descriptor\n");
+ goto free_desc;
+ }
+
+ /* Read blob from CAAM */
+ if (mem_type == DATA_GENMEM)
+ read_map_data(dev, blob, blob_dma, tmp_blob, info->blob_len);
+
+ print_hex_dump_debug("blob @" __stringify(__LINE__) ": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, blob,
+ info->blob_len, 1);
+free_desc:
+ kfree(desc);
+
+unmap_blob:
+ if (mem_type == DATA_GENMEM)
+ unmap_read_write_data(dev, blob_dma, tmp_blob,
+ info->blob_len, DMA_FROM_DEVICE);
+
+unmap_black_key:
+ if (mem_type == DATA_GENMEM)
+ unmap_read_write_data(dev, black_key_dma, tmp_black_key,
+ info->black_key_len, DMA_TO_DEVICE);
+
+exit:
+ return ret;
+}
+EXPORT_SYMBOL(caam_blob_encap);
+
+/**
+ * caam_blob_decap - Decapsulate a black key from a blob
+ *
+ * Notes:
+ * For now, we have support for Black blob, stored in General Memory and
+ * can be decapsulated into a black key.
+ *
+ * @dev : struct device of the job ring to be used
+ * @info : keyblob_info structure, will be updated with
+ * the black key decapsulated from the blob.
+ * This contains, also, all the data necessary to
+ * encapsulate a black key into a blob: key encryption
+ * key, memory type, color, etc.
+ *
+ * Return : '0' on success, error code otherwise
+ */
+int caam_blob_decap(struct device *dev, struct keyblob_info *info)
+{
+ int ret = 0;
+ u32 *desc = NULL;
+ u8 mem_type, color, key_enc, trusted_key;
+ size_t black_key_real_len;
+ dma_addr_t black_key_dma, blob_dma;
+ unsigned char *blob = info->blob + TAG_OVERHEAD_SIZE;
+ u8 *tmp_black_key = NULL, *tmp_blob = NULL;
+
+ /* Validate device */
+ if (!dev)
+ return -EINVAL;
+
+ /*
+ * Get memory type, trusted key, key encryption
+ * type and color from type
+ */
+ mem_type = (info->type >> TAG_OBJ_MEM_OFFSET) & 0x1;
+ color = (info->type >> TAG_OBJ_COLOR_OFFSET) & 0x1;
+ key_enc = (info->type >> TAG_OBJ_EKT_OFFSET) & 0x1;
+ trusted_key = (info->type >> TAG_OBJ_TK_OFFSET) & 0x1;
+
+ /* Validate input data*/
+ if (!info->key_mod || !blob)
+ return -EINVAL;
+
+ dev_dbg(dev, "%s input: [blob: %p (%zu), mem_type: %x, color: %x",
+ __func__, blob, info->blob_len, mem_type, color);
+ dev_dbg(dev, " keymod: %p (%zu)", info->key_mod, info->key_mod_len);
+ dev_dbg(dev, " secret: %p (%zu) key_enc: %x]\n",
+ info->black_key, info->black_key_len, key_enc);
+
+ /* Validate object type - only JDKEK keys are supported */
+ if (is_trusted_type(info->type))
+ return -EINVAL;
+
+ print_hex_dump_debug("blob @" __stringify(__LINE__) ": ",
+ DUMP_PREFIX_ADDRESS, 16, 4, blob,
+ info->blob_len, 1);
+
+ /*
+ * Based on memory type, the key modifier length
+ * can be 8-byte or 16-byte.
+ */
+ if (mem_type == DATA_SECMEM)
+ info->key_mod_len = KEYMOD_SIZE_SM;
+ else
+ info->key_mod_len = KEYMOD_SIZE_GM;
+
+ /* Check if the blob is valid */
+ if (info->blob_len <= BLOB_OVERHEAD)
+ return -EINVAL;
+
+ /* Initialize black key length */
+ black_key_real_len = info->blob_len - BLOB_OVERHEAD;
+
+ /* Check if the black key has enough space to be stored */
+ if (info->black_key_len < black_key_real_len)
+ return -EINVAL;
+
+ /*
+ * Based on key encryption type (ecb or ccm),
+ * compute the black key size
+ */
+ if (key_enc == KEY_COVER_ECB)
+ /*
+ * ECB-Black Key will be padded with zeros to make it a
+ * multiple of 16 bytes long before it is encrypted,
+ * and the resulting Black Key will be this length.
+ */
+ black_key_real_len = ECB_BLACK_KEY_SIZE(info->key_len);
+ else if (key_enc == KEY_COVER_CCM)
+ /*
+ * CCM-Black Key will always be at least 12 bytes longer,
+ * since the encapsulation uses a 6-byte nonce and adds
+ * a 6-byte ICV. But first, the key is padded as necessary so
+ * that CCM-Black Key is a multiple of 8 bytes long.
+ */
+ black_key_real_len = CCM_BLACK_KEY_SIZE(info->key_len);
+
+ /* Check if there is enough space for black key */
+ if (info->black_key_len < black_key_real_len)
+ return -EINVAL;
+
+ /* Update black key length with the one computed based on key_enc */
+ info->black_key_len = black_key_real_len;
+
+ dev_dbg(dev, "%s processing: [blob: %p (%zu), mem_type: %x, color: %x,",
+ __func__, blob, info->blob_len, mem_type, color);
+ dev_dbg(dev, " key_mod: %p (%zu), black_key: %p (%zu) real_len: %zu]\n",
+ info->key_mod, info->key_mod_len, info->black_key,
+ info->black_key_len, black_key_real_len);
+
+ /* Map blob, this will be transferred to CAAM */
+ if (mem_type == DATA_GENMEM) {
+ if (map_write_data(dev, blob, info->blob_len,
+ &blob_dma, &tmp_blob)) {
+ dev_err(dev, "Unable to map blob for decap\n");
+ ret = -ENOMEM;
+ goto exit;
+ }
+ } else {
+ blob_dma = get_caam_dma_addr(blob);
+ if (!blob_dma)
+ return -ENOMEM;
+ }
+
+ /* Map black key, this will be read from CAAM */
+ if (mem_type == DATA_GENMEM) {
+ if (map_read_data(dev, info->black_key_len,
+ &black_key_dma, &tmp_black_key)) {
+ dev_err(dev, "Unable to map black key for blob decap\n");
+ ret = -ENOMEM;
+ goto unmap_blob;
+ }
+ } else {
+ black_key_dma = get_caam_dma_addr(info->black_key);
+ if (!black_key_dma)
+ return -ENOMEM;
+ }
+
+ ret = cnstr_desc_blob_decap(&desc, blob_dma, info->blob_len,
+ info->key_mod, info->key_mod_len,
+ black_key_dma, info->key_len,
+ color, key_enc, trusted_key, mem_type);
+ if (ret) {
+ dev_err(dev,
+ "Failed to construct the descriptor for blob decap\n");
+ goto unmap_black_key;
+ }
+
+ ret = caam_jr_run_and_wait_for_completion(dev, desc,
+ caam_key_blob_done);
+ if (ret) {
+ dev_err(dev, "Failed to execute blob decap descriptor\n");
+ goto free_desc;
+ }
+
+ /* Read black key from CAAM */
+ if (mem_type == DATA_GENMEM)
+ read_map_data(dev, info->black_key, black_key_dma,
+ tmp_black_key, info->black_key_len);
+
+free_desc:
+ kfree(desc);
+
+unmap_black_key:
+ if (mem_type == DATA_GENMEM)
+ unmap_read_write_data(dev, black_key_dma, tmp_black_key,
+ info->black_key_len, DMA_FROM_DEVICE);
+
+unmap_blob:
+ if (mem_type == DATA_GENMEM)
+ unmap_read_write_data(dev, blob_dma, tmp_blob,
+ info->blob_len, DMA_TO_DEVICE);
+
+exit:
+ return ret;
+}
+EXPORT_SYMBOL(caam_blob_decap);