accel: Add crypto operation support
Add functions to submit encrypt/decrypt operations Add RPCS to register and dump crypto keys Software accel module uses isa-l_crypto AEX_XTS functionality Signed-off-by: Alexey Marchuk <alexeymar@nvidia.com> Change-Id: Iecf0e9913edf11ab85171d0fa467a2a62dfff984 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/14858 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Paul Luse <paul.e.luse@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: <qun.wan@intel.com> Reviewed-by: Shuhei Matsumoto <smatsumoto@nvidia.com>
This commit is contained in:
parent
d68159b618
commit
2608d129d0
@ -6,6 +6,8 @@
|
||||
|
||||
New library isa-l-crypto has been added, it is used by accel library in crypto operations.
|
||||
|
||||
New functions `spdk_accel_submit_encrypt` and `spdk_accel_submit_decrypt` were added.
|
||||
|
||||
### bdev
|
||||
|
||||
Both of interleaved and separated metadata are now supported by the malloc bdev module.
|
||||
|
@ -442,6 +442,8 @@ Example response:
|
||||
"framework_monitor_context_switch",
|
||||
"spdk_kill_instance",
|
||||
"accel_get_opc_assignments",
|
||||
"accel_crypto_key_create",
|
||||
"accel_crypto_keys_get",
|
||||
"ioat_scan_accel_module",
|
||||
"dsa_scan_accel_module",
|
||||
"bdev_virtio_attach_controller",
|
||||
@ -1776,6 +1778,92 @@ Example response:
|
||||
}
|
||||
~~~
|
||||
|
||||
### accel_crypto_key_create {#rpc_accel_crypto_key_create}
|
||||
|
||||
Create a crypt key which will be used in accel framework
|
||||
|
||||
#### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
-----------|----------| ----------- | -----------------
|
||||
cipher | Required | string | crypto cipher to use
|
||||
key | Required | string | Key in **hex** form
|
||||
key2 | Optional | string | Optional 2nd part of the key or a tweak in **hex** form
|
||||
name | Required | string | The key name
|
||||
|
||||
#### Example
|
||||
|
||||
Example request:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "accel_crypto_key_create",
|
||||
"id": 1,
|
||||
"params": {
|
||||
"cipher": "AES_XTS",
|
||||
"key": "00112233445566778899001122334455",
|
||||
"key2": "00112233445566778899001122334455",
|
||||
"name": "super_key"
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": true
|
||||
}
|
||||
~~~
|
||||
|
||||
### accel_crypto_keys_get {#rpc_accel_crypto_keys_get}
|
||||
|
||||
Get information about existing crypto keys
|
||||
|
||||
#### Parameters
|
||||
|
||||
Name | Optional | Type | Description
|
||||
----------------------- |----------| ----------- | -----------------
|
||||
key_name | Optional | string | If specified, return info about a specific key
|
||||
|
||||
#### Example
|
||||
|
||||
Example request:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "accel_crypto_keys_get",
|
||||
"id": 1
|
||||
}
|
||||
~~~
|
||||
|
||||
Example response:
|
||||
|
||||
~~~json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": [
|
||||
{
|
||||
"name": "test_dek",
|
||||
"cipher": "AES_XTS",
|
||||
"key": "00112233445566778899001122334455",
|
||||
"key2": "11223344556677889900112233445500"
|
||||
},
|
||||
{
|
||||
"name": "test_dek2",
|
||||
"cipher": "AES_XTS",
|
||||
"key": "11223344556677889900112233445500",
|
||||
"key2": "22334455667788990011223344550011"
|
||||
}
|
||||
]
|
||||
}
|
||||
~~~
|
||||
|
||||
### dsa_scan_accel_module {#rpc_dsa_scan_accel_module}
|
||||
|
||||
Set config and enable dsa accel module offload.
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
@ -17,9 +18,19 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** Data Encryption Key identifier */
|
||||
struct spdk_accel_crypto_key;
|
||||
|
||||
/* Flags for accel operations */
|
||||
#define ACCEL_FLAG_PERSISTENT (1 << 0)
|
||||
|
||||
struct spdk_accel_crypto_key_create_param {
|
||||
char *cipher; /**< Cipher to be used for crypto operations */
|
||||
char *hex_key; /**< Hexlified key */
|
||||
char *hex_key2; /**< Hexlified key2 */
|
||||
char *key_name; /**< Key name */
|
||||
};
|
||||
|
||||
enum accel_opcode {
|
||||
ACCEL_OPC_COPY = 0,
|
||||
ACCEL_OPC_FILL = 1,
|
||||
@ -29,7 +40,9 @@ enum accel_opcode {
|
||||
ACCEL_OPC_COPY_CRC32C = 5,
|
||||
ACCEL_OPC_COMPRESS = 6,
|
||||
ACCEL_OPC_DECOMPRESS = 7,
|
||||
ACCEL_OPC_LAST = 8,
|
||||
ACCEL_OPC_ENCRYPT = 8,
|
||||
ACCEL_OPC_DECRYPT = 9,
|
||||
ACCEL_OPC_LAST = 10,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -71,6 +84,29 @@ void spdk_accel_finish(spdk_accel_fini_cb cb_fn, void *cb_arg);
|
||||
*/
|
||||
struct spdk_io_channel *spdk_accel_get_io_channel(void);
|
||||
|
||||
/**
|
||||
* Create a crypto key with given parameters. Accel module copies content of \b param structure
|
||||
*
|
||||
* \param param Key parameters
|
||||
* \return 0 on success, negated errno on error
|
||||
*/
|
||||
int spdk_accel_crypto_key_create(const struct spdk_accel_crypto_key_create_param *param);
|
||||
|
||||
/**
|
||||
* Destroy a crypto key
|
||||
*
|
||||
* \param key Key to destroy
|
||||
* \return 0 on success, negated errno on error
|
||||
*/
|
||||
int spdk_accel_crypto_key_destroy(struct spdk_accel_crypto_key *key);
|
||||
|
||||
/**
|
||||
* Find a crypto key structure by name
|
||||
* \param name Key name
|
||||
* \return Crypto key structure or NULL
|
||||
*/
|
||||
struct spdk_accel_crypto_key *spdk_accel_crypto_key_get(const char *name);
|
||||
|
||||
/**
|
||||
* Submit a copy request.
|
||||
*
|
||||
@ -404,6 +440,67 @@ int spdk_accel_get_buf(struct spdk_io_channel *ch, uint64_t len, void **buf,
|
||||
void spdk_accel_put_buf(struct spdk_io_channel *ch, void *buf,
|
||||
struct spdk_memory_domain *domain, void *domain_ctx);
|
||||
|
||||
/**
|
||||
* Build and submit a data encryption request.
|
||||
*
|
||||
* This function will build the encryption request and submit it. \b nbytes must be multiple of \b block_size.
|
||||
* \b iv is used to encrypt the first logical block of size \b block_size. If \b src_iovs describes more than
|
||||
* one logical block then \b iv will be incremented for each next logical block.
|
||||
* Data Encryption Key identifier should be created before calling this function using methods specific to the accel
|
||||
* module being used.
|
||||
*
|
||||
* \param ch I/O channel associated with this call
|
||||
* \param key Data Encryption Key identifier
|
||||
* \param dst_iovs The io vector array which stores the dst data and len.
|
||||
* \param dst_iovcnt The size of the destination io vectors.
|
||||
* \param src_iovs The io vector array which stores the src data and len.
|
||||
* \param src_iovcnt The size of the source io vectors.
|
||||
* \param iv Initialization vector (tweak) used for encryption
|
||||
* \param block_size Logical block size, if src contains more than 1 logical block, subsequent logical blocks will be
|
||||
* encrypted with incremented \b iv
|
||||
* \param flags Accel framework flags for operations.
|
||||
* \param cb_fn Callback function which will be called when the request is complete.
|
||||
* \param cb_arg Opaque value which will be passed back as the arg parameter in the completion callback.
|
||||
*
|
||||
* \return 0 on success, negative errno on failure.
|
||||
*/
|
||||
int spdk_accel_submit_encrypt(struct spdk_io_channel *ch, struct spdk_accel_crypto_key *key,
|
||||
struct iovec *dst_iovs, uint32_t dst_iovcnt,
|
||||
struct iovec *src_iovs, uint32_t src_iovcnt,
|
||||
uint64_t iv, uint32_t block_size, int flags,
|
||||
spdk_accel_completion_cb cb_fn, void *cb_arg);
|
||||
|
||||
/**
|
||||
* Build and submit a data decryption request.
|
||||
*
|
||||
* This function will build the decryption request and submit it. \b nbytes must be multiple of \b block_size.
|
||||
* \b iv is used to decrypt the first logical block of size \b block_size. If \b src_iovs describes more than
|
||||
* one logical block then \b iv will be incremented for each next logical block.
|
||||
* Data Encryption Key identifier should be created before calling this function using methods specific to the accel
|
||||
* module being used.
|
||||
*
|
||||
* \param ch I/O channel associated with this call
|
||||
* \param key Data Encryption Key identifier
|
||||
* \param dst_iovs The io vector array which stores the dst data and len.
|
||||
* \param dst_iovcnt The size of the destination io vectors.
|
||||
* \param src_iovs The io vector array which stores the src data and len.
|
||||
* \param src_iovcnt The size of the source io vectors.
|
||||
* \param iv Initialization vector (tweak) used for decryption. Should be the same as \b iv used for encryption of a
|
||||
* data block
|
||||
* \param block_size Logical block size, if src contains more than 1 logical block, subsequent logical blocks will be
|
||||
* decrypted with incremented \b iv
|
||||
* \param flags Accel framework flags for operations.
|
||||
* \param cb_fn Callback function which will be called when the request is complete.
|
||||
* \param cb_arg Opaque value which will be passed back as the arg parameter in the completion callback.
|
||||
*
|
||||
* \return 0 on success, negative errno on failure.
|
||||
*/
|
||||
int spdk_accel_submit_decrypt(struct spdk_io_channel *ch, struct spdk_accel_crypto_key *key,
|
||||
struct iovec *dst_iovs, uint32_t dst_iovcnt,
|
||||
struct iovec *src_iovs, uint32_t src_iovcnt,
|
||||
uint64_t iv, uint32_t block_size, int flags,
|
||||
spdk_accel_completion_cb cb_fn, void *cb_arg);
|
||||
|
||||
/**
|
||||
* Return the name of the module assigned to a specific opcode.
|
||||
*
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (C) 2020 Intel Corporation.
|
||||
* Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
@ -12,10 +13,25 @@
|
||||
#include "spdk/queue.h"
|
||||
#include "spdk/config.h"
|
||||
|
||||
struct spdk_accel_module_if;
|
||||
struct spdk_accel_task;
|
||||
|
||||
void spdk_accel_task_complete(struct spdk_accel_task *task, int status);
|
||||
|
||||
/** Some reasonable key length used with strnlen() */
|
||||
#define SPDK_ACCEL_CRYPTO_KEY_MAX_HEX_LENGTH (256 + 1)
|
||||
|
||||
struct spdk_accel_crypto_key {
|
||||
void *priv; /**< Module private data */
|
||||
char *key; /**< Key in binary form */
|
||||
size_t key_size; /**< Key size in bytes */
|
||||
char *key2; /**< Key2 in binary form */
|
||||
size_t key2_size; /**< Key2 size in bytes */
|
||||
struct spdk_accel_module_if *module_if; /**< Accel module the key belongs to */
|
||||
struct spdk_accel_crypto_key_create_param param; /**< User input parameters */
|
||||
TAILQ_ENTRY(spdk_accel_crypto_key) link;
|
||||
};
|
||||
|
||||
struct spdk_accel_task {
|
||||
struct accel_io_channel *accel_ch;
|
||||
spdk_accel_completion_cb cb_fn;
|
||||
@ -45,14 +61,19 @@ struct spdk_accel_task {
|
||||
void *dst2;
|
||||
uint32_t seed;
|
||||
uint64_t fill_pattern;
|
||||
struct spdk_accel_crypto_key *crypto_key;
|
||||
};
|
||||
union {
|
||||
uint32_t *crc_dst;
|
||||
uint32_t *output_size;
|
||||
uint32_t block_size; /* for crypto op */
|
||||
};
|
||||
enum accel_opcode op_code;
|
||||
uint64_t nbytes;
|
||||
uint64_t nbytes_dst;
|
||||
union {
|
||||
uint64_t nbytes_dst; /* for compress op */
|
||||
uint64_t iv; /* Initialization vector (tweak) for crypto op */
|
||||
};
|
||||
int flags;
|
||||
int status;
|
||||
TAILQ_ENTRY(spdk_accel_task) link;
|
||||
@ -89,6 +110,13 @@ struct spdk_accel_module_if {
|
||||
struct spdk_io_channel *(*get_io_channel)(void);
|
||||
int (*submit_tasks)(struct spdk_io_channel *ch, struct spdk_accel_task *accel_task);
|
||||
|
||||
/**
|
||||
* Create crypto key function. Module is responsible to fill all necessary parameters in
|
||||
* \b spdk_accel_crypto_key structure
|
||||
*/
|
||||
int (*crypto_key_init)(struct spdk_accel_crypto_key *key);
|
||||
void (*crypto_key_deinit)(struct spdk_accel_crypto_key *key);
|
||||
|
||||
TAILQ_ENTRY(spdk_accel_module_if) tailq;
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Copyright (C) 2015 Intel Corporation.
|
||||
# Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
@ -17,6 +18,10 @@ ifeq ($(CONFIG_ISAL), y)
|
||||
LOCAL_SYS_LIBS = -L$(ISAL_DIR)/.libs -lisal
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ISAL_CRYPTO), y)
|
||||
LOCAL_SYS_LIBS = -L$(ISAL_CRYPTO_DIR)/.libs -lisal_crypto
|
||||
endif
|
||||
|
||||
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_accel.map)
|
||||
|
||||
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "spdk/json.h"
|
||||
#include "spdk/crc32.h"
|
||||
#include "spdk/util.h"
|
||||
#include "spdk/hexlify.h"
|
||||
|
||||
/* Accelerator Framework: The following provides a top level
|
||||
* generic API for the accelerator functions defined here. Modules,
|
||||
@ -46,13 +47,17 @@ static struct spdk_memory_domain *g_accel_domain;
|
||||
static TAILQ_HEAD(, spdk_accel_module_if) spdk_accel_module_list =
|
||||
TAILQ_HEAD_INITIALIZER(spdk_accel_module_list);
|
||||
|
||||
/* Crypto keyring */
|
||||
static TAILQ_HEAD(, spdk_accel_crypto_key) g_keyring = TAILQ_HEAD_INITIALIZER(g_keyring);
|
||||
static struct spdk_spinlock g_keyring_spin;
|
||||
|
||||
/* Global array mapping capabilities to modules */
|
||||
static struct spdk_accel_module_if *g_modules_opc[ACCEL_OPC_LAST] = {};
|
||||
static char *g_modules_opc_override[ACCEL_OPC_LAST] = {};
|
||||
|
||||
static const char *g_opcode_strings[ACCEL_OPC_LAST] = {
|
||||
"copy", "fill", "dualcast", "compare", "crc32c", "copy_crc32c",
|
||||
"compress", "decompress"
|
||||
"compress", "decompress", "encrypt", "decrypt"
|
||||
};
|
||||
|
||||
struct accel_buffer {
|
||||
@ -191,8 +196,6 @@ _get_task(struct accel_io_channel *accel_ch, spdk_accel_completion_cb cb_fn, voi
|
||||
return accel_task;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Accel framework public API for copy function */
|
||||
int
|
||||
spdk_accel_submit_copy(struct spdk_io_channel *ch, void *dst, void *src,
|
||||
@ -526,6 +529,106 @@ spdk_accel_submit_decompress(struct spdk_io_channel *ch, struct iovec *dst_iovs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_accel_submit_encrypt(struct spdk_io_channel *ch, struct spdk_accel_crypto_key *key,
|
||||
struct iovec *dst_iovs, uint32_t dst_iovcnt,
|
||||
struct iovec *src_iovs, uint32_t src_iovcnt,
|
||||
uint64_t iv, uint32_t block_size, int flags,
|
||||
spdk_accel_completion_cb cb_fn, void *cb_arg)
|
||||
{
|
||||
struct accel_io_channel *accel_ch = spdk_io_channel_get_ctx(ch);
|
||||
struct spdk_accel_task *accel_task;
|
||||
struct spdk_accel_module_if *module = g_modules_opc[ACCEL_OPC_ENCRYPT];
|
||||
struct spdk_io_channel *module_ch = accel_ch->module_ch[ACCEL_OPC_ENCRYPT];
|
||||
size_t src_nbytes = 0, dst_nbytes = 0;
|
||||
uint32_t i;
|
||||
|
||||
if (spdk_unlikely(!dst_iovs || !dst_iovcnt || !src_iovs || !src_iovcnt || !key || !block_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < src_iovcnt; i++) {
|
||||
src_nbytes += src_iovs[i].iov_len;
|
||||
}
|
||||
for (i = 0; i < dst_iovcnt; i++) {
|
||||
dst_nbytes += dst_iovs[i].iov_len;
|
||||
}
|
||||
if (spdk_unlikely(src_nbytes != dst_nbytes || !src_nbytes)) {
|
||||
return -ERANGE;
|
||||
}
|
||||
if (spdk_unlikely(src_nbytes % block_size != 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
accel_task = _get_task(accel_ch, cb_fn, cb_arg);
|
||||
if (accel_task == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
accel_task->crypto_key = key;
|
||||
accel_task->s.iovs = src_iovs;
|
||||
accel_task->s.iovcnt = src_iovcnt;
|
||||
accel_task->d.iovs = dst_iovs;
|
||||
accel_task->d.iovcnt = dst_iovcnt;
|
||||
accel_task->nbytes = src_nbytes;
|
||||
accel_task->iv = iv;
|
||||
accel_task->block_size = block_size;
|
||||
accel_task->flags = flags;
|
||||
accel_task->op_code = ACCEL_OPC_ENCRYPT;
|
||||
|
||||
return module->submit_tasks(module_ch, accel_task);
|
||||
}
|
||||
|
||||
int
|
||||
spdk_accel_submit_decrypt(struct spdk_io_channel *ch, struct spdk_accel_crypto_key *key,
|
||||
struct iovec *dst_iovs, uint32_t dst_iovcnt,
|
||||
struct iovec *src_iovs, uint32_t src_iovcnt,
|
||||
uint64_t iv, uint32_t block_size, int flags,
|
||||
spdk_accel_completion_cb cb_fn, void *cb_arg)
|
||||
{
|
||||
struct accel_io_channel *accel_ch = spdk_io_channel_get_ctx(ch);
|
||||
struct spdk_accel_task *accel_task;
|
||||
struct spdk_accel_module_if *module = g_modules_opc[ACCEL_OPC_DECRYPT];
|
||||
struct spdk_io_channel *module_ch = accel_ch->module_ch[ACCEL_OPC_DECRYPT];
|
||||
size_t src_nbytes = 0, dst_nbytes = 0;
|
||||
uint32_t i;
|
||||
|
||||
if (spdk_unlikely(!dst_iovs || !dst_iovcnt || !src_iovs || !src_iovcnt || !key || !block_size)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < src_iovcnt; i++) {
|
||||
src_nbytes += src_iovs[i].iov_len;
|
||||
}
|
||||
for (i = 0; i < dst_iovcnt; i++) {
|
||||
dst_nbytes += dst_iovs[i].iov_len;
|
||||
}
|
||||
if (spdk_unlikely(src_nbytes != dst_nbytes || !src_nbytes)) {
|
||||
return -ERANGE;
|
||||
}
|
||||
if (spdk_unlikely(src_nbytes % block_size != 0)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
accel_task = _get_task(accel_ch, cb_fn, cb_arg);
|
||||
if (accel_task == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
accel_task->crypto_key = key;
|
||||
accel_task->s.iovs = src_iovs;
|
||||
accel_task->s.iovcnt = src_iovcnt;
|
||||
accel_task->d.iovs = dst_iovs;
|
||||
accel_task->d.iovcnt = dst_iovcnt;
|
||||
accel_task->nbytes = src_nbytes;
|
||||
accel_task->iv = iv;
|
||||
accel_task->block_size = block_size;
|
||||
accel_task->flags = flags;
|
||||
accel_task->op_code = ACCEL_OPC_DECRYPT;
|
||||
|
||||
return module->submit_tasks(module_ch, accel_task);
|
||||
}
|
||||
|
||||
static inline struct accel_buffer *
|
||||
accel_get_buf(struct accel_io_channel *ch, uint64_t len)
|
||||
{
|
||||
@ -1036,7 +1139,224 @@ _module_find_by_name(const char *name)
|
||||
return accel_module;
|
||||
}
|
||||
|
||||
/* Helper function when when accel modules register with the framework. */
|
||||
static inline struct spdk_accel_crypto_key *
|
||||
_accel_crypto_key_get(const char *name)
|
||||
{
|
||||
struct spdk_accel_crypto_key *key;
|
||||
|
||||
assert(spdk_spin_held(&g_keyring_spin));
|
||||
|
||||
TAILQ_FOREACH(key, &g_keyring, link) {
|
||||
if (strcmp(name, key->param.key_name) == 0) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
accel_crypto_key_free_mem(struct spdk_accel_crypto_key *key)
|
||||
{
|
||||
if (key->param.hex_key) {
|
||||
spdk_memset_s(key->param.hex_key, key->key_size * 2, 0, key->key_size * 2);
|
||||
free(key->param.hex_key);
|
||||
}
|
||||
if (key->param.hex_key2) {
|
||||
spdk_memset_s(key->param.hex_key2, key->key2_size * 2, 0, key->key2_size * 2);
|
||||
free(key->param.hex_key2);
|
||||
}
|
||||
free(key->param.key_name);
|
||||
free(key->param.cipher);
|
||||
if (key->key) {
|
||||
spdk_memset_s(key->key, key->key_size, 0, key->key_size);
|
||||
free(key->key);
|
||||
}
|
||||
if (key->key2) {
|
||||
spdk_memset_s(key->key2, key->key2_size, 0, key->key2_size);
|
||||
free(key->key2);
|
||||
}
|
||||
free(key);
|
||||
}
|
||||
|
||||
static void
|
||||
accel_crypto_key_destroy_unsafe(struct spdk_accel_crypto_key *key)
|
||||
{
|
||||
assert(key->module_if);
|
||||
assert(key->module_if->crypto_key_deinit);
|
||||
|
||||
key->module_if->crypto_key_deinit(key);
|
||||
accel_crypto_key_free_mem(key);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function mitigates a timing side channel which could be caused by using strcmp()
|
||||
* Please refer to chapter "Mitigating Information Leakage Based on Variable Timing" in
|
||||
* the article [1] for more details
|
||||
* [1] https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/secure-coding/mitigate-timing-side-channel-crypto-implementation.html
|
||||
*/
|
||||
static bool
|
||||
accel_aes_xts_keys_equal(const char *k1, size_t k1_len, const char *k2, size_t k2_len)
|
||||
{
|
||||
size_t i;
|
||||
volatile size_t x = k1_len ^ k2_len;
|
||||
|
||||
for (i = 0; ((i < k1_len) & (i < k2_len)); i++) {
|
||||
x |= k1[i] ^ k2[i];
|
||||
}
|
||||
|
||||
return x == 0;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_accel_crypto_key_create(const struct spdk_accel_crypto_key_create_param *param)
|
||||
{
|
||||
struct spdk_accel_module_if *module;
|
||||
struct spdk_accel_crypto_key *key;
|
||||
size_t hex_key_size, hex_key2_size;
|
||||
int rc;
|
||||
|
||||
if (!param || !param->hex_key || !param->cipher || !param->key_name) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (g_modules_opc[ACCEL_OPC_ENCRYPT] != g_modules_opc[ACCEL_OPC_DECRYPT]) {
|
||||
/* hardly ever possible, but let's check and warn the user */
|
||||
SPDK_ERRLOG("Different accel modules are used for encryption and decryption\n");
|
||||
}
|
||||
module = g_modules_opc[ACCEL_OPC_ENCRYPT];
|
||||
|
||||
if (!module) {
|
||||
SPDK_ERRLOG("No accel module found assigned for crypto operation\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
if (!module->crypto_key_init) {
|
||||
SPDK_ERRLOG("Accel module \"%s\" doesn't support crypto operations\n", module->name);
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
key = calloc(1, sizeof(*key));
|
||||
if (!key) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
key->param.key_name = strdup(param->key_name);
|
||||
if (!key->param.key_name) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->param.cipher = strdup(param->cipher);
|
||||
if (!key->param.cipher) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
hex_key_size = strnlen(param->hex_key, SPDK_ACCEL_CRYPTO_KEY_MAX_HEX_LENGTH);
|
||||
if (hex_key_size == SPDK_ACCEL_CRYPTO_KEY_MAX_HEX_LENGTH) {
|
||||
SPDK_ERRLOG("key1 size exceeds max %d\n", SPDK_ACCEL_CRYPTO_KEY_MAX_HEX_LENGTH);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
key->param.hex_key = strdup(param->hex_key);
|
||||
if (!key->param.hex_key) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->key_size = hex_key_size / 2;
|
||||
key->key = spdk_unhexlify(key->param.hex_key);
|
||||
if (!key->key) {
|
||||
SPDK_ERRLOG("Failed to unhexlify key1\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (param->hex_key2) {
|
||||
hex_key2_size = strnlen(param->hex_key2, SPDK_ACCEL_CRYPTO_KEY_MAX_HEX_LENGTH);
|
||||
if (hex_key2_size == SPDK_ACCEL_CRYPTO_KEY_MAX_HEX_LENGTH) {
|
||||
SPDK_ERRLOG("key2 size exceeds max %d\n", SPDK_ACCEL_CRYPTO_KEY_MAX_HEX_LENGTH);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
key->param.hex_key2 = strdup(param->hex_key2);
|
||||
if (!key->param.hex_key2) {
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
key->key2_size = hex_key2_size / 2;
|
||||
key->key2 = spdk_unhexlify(key->param.hex_key2);
|
||||
if (!key->key2) {
|
||||
SPDK_ERRLOG("Failed to unhexlify key2\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (accel_aes_xts_keys_equal(key->key, key->key_size, key->key2, key->key2_size)) {
|
||||
SPDK_ERRLOG("Identical keys are not secure\n");
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
key->module_if = module;
|
||||
|
||||
spdk_spin_lock(&g_keyring_spin);
|
||||
if (_accel_crypto_key_get(param->key_name)) {
|
||||
rc = -EEXIST;
|
||||
} else {
|
||||
rc = module->crypto_key_init(key);
|
||||
if (!rc) {
|
||||
TAILQ_INSERT_TAIL(&g_keyring, key, link);
|
||||
}
|
||||
}
|
||||
spdk_spin_unlock(&g_keyring_spin);
|
||||
|
||||
if (rc) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
accel_crypto_key_free_mem(key);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
spdk_accel_crypto_key_destroy(struct spdk_accel_crypto_key *key)
|
||||
{
|
||||
if (!key || !key->module_if) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spdk_spin_lock(&g_keyring_spin);
|
||||
if (!_accel_crypto_key_get(key->param.key_name)) {
|
||||
spdk_spin_unlock(&g_keyring_spin);
|
||||
return -ENOENT;
|
||||
}
|
||||
TAILQ_REMOVE(&g_keyring, key, link);
|
||||
spdk_spin_unlock(&g_keyring_spin);
|
||||
|
||||
accel_crypto_key_destroy_unsafe(key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct spdk_accel_crypto_key *
|
||||
spdk_accel_crypto_key_get(const char *name)
|
||||
{
|
||||
struct spdk_accel_crypto_key *key;
|
||||
|
||||
spdk_spin_lock(&g_keyring_spin);
|
||||
key = _accel_crypto_key_get(name);
|
||||
spdk_spin_unlock(&g_keyring_spin);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/* Helper function when accel modules register with the framework. */
|
||||
void
|
||||
spdk_accel_module_list_add(struct spdk_accel_module_if *accel_module)
|
||||
{
|
||||
@ -1048,7 +1368,7 @@ spdk_accel_module_list_add(struct spdk_accel_module_if *accel_module)
|
||||
|
||||
/* Make sure that the software module is at the head of the list, this
|
||||
* will assure that all opcodes are later assigned to software first and
|
||||
* then udpated to HW modules as they are registered.
|
||||
* then updated to HW modules as they are registered.
|
||||
*/
|
||||
if (strcmp(accel_module->name, "software") == 0) {
|
||||
TAILQ_INSERT_HEAD(&spdk_accel_module_list, accel_module, tailq);
|
||||
@ -1178,14 +1498,16 @@ spdk_accel_initialize(void)
|
||||
return rc;
|
||||
}
|
||||
|
||||
spdk_spin_init(&g_keyring_spin);
|
||||
|
||||
g_modules_started = true;
|
||||
accel_module_initialize();
|
||||
|
||||
/* Create our priority global map of opcodes to modules, we populate starting
|
||||
* with the software module (guaranteed to be first on the list) and then
|
||||
* updating opcodes with HW modules that have been initilaized.
|
||||
* updating opcodes with HW modules that have been initialized.
|
||||
* NOTE: all opcodes must be supported by software in the event that no HW
|
||||
* modules are initilaized to support the operation.
|
||||
* modules are initialized to support the operation.
|
||||
*/
|
||||
TAILQ_FOREACH(accel_module, &spdk_accel_module_list, tailq) {
|
||||
for (op = 0; op < ACCEL_OPC_LAST; op++) {
|
||||
@ -1214,6 +1536,11 @@ spdk_accel_initialize(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (g_modules_opc[ACCEL_OPC_ENCRYPT] != g_modules_opc[ACCEL_OPC_DECRYPT]) {
|
||||
SPDK_ERRLOG("Different accel modules are assigned to encrypt and decrypt operations");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (op = 0; op < ACCEL_OPC_LAST; op++) {
|
||||
assert(g_modules_opc[op] != NULL);
|
||||
@ -1264,6 +1591,59 @@ accel_write_overridden_opc(struct spdk_json_write_ctx *w, const char *opc_str,
|
||||
spdk_json_write_object_end(w);
|
||||
}
|
||||
|
||||
static void
|
||||
__accel_crypto_key_dump_param(struct spdk_json_write_ctx *w, struct spdk_accel_crypto_key *key)
|
||||
{
|
||||
spdk_json_write_named_string(w, "name", key->param.key_name);
|
||||
spdk_json_write_named_string(w, "cipher", key->param.cipher);
|
||||
spdk_json_write_named_string(w, "key", key->param.hex_key);
|
||||
if (key->param.hex_key2) {
|
||||
spdk_json_write_named_string(w, "key2", key->param.hex_key2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_accel_crypto_key_dump_param(struct spdk_json_write_ctx *w, struct spdk_accel_crypto_key *key)
|
||||
{
|
||||
spdk_json_write_object_begin(w);
|
||||
__accel_crypto_key_dump_param(w, key);
|
||||
spdk_json_write_object_end(w);
|
||||
}
|
||||
|
||||
static void
|
||||
_accel_crypto_key_write_config_json(struct spdk_json_write_ctx *w,
|
||||
struct spdk_accel_crypto_key *key)
|
||||
{
|
||||
spdk_json_write_object_begin(w);
|
||||
spdk_json_write_named_string(w, "method", "accel_crypto_key_create");
|
||||
spdk_json_write_named_object_begin(w, "params");
|
||||
__accel_crypto_key_dump_param(w, key);
|
||||
spdk_json_write_object_end(w);
|
||||
spdk_json_write_object_end(w);
|
||||
}
|
||||
|
||||
static void
|
||||
_accel_crypto_keys_write_config_json(struct spdk_json_write_ctx *w, bool full_dump)
|
||||
{
|
||||
struct spdk_accel_crypto_key *key;
|
||||
|
||||
spdk_spin_lock(&g_keyring_spin);
|
||||
TAILQ_FOREACH(key, &g_keyring, link) {
|
||||
if (full_dump) {
|
||||
_accel_crypto_key_write_config_json(w, key);
|
||||
} else {
|
||||
_accel_crypto_key_dump_param(w, key);
|
||||
}
|
||||
}
|
||||
spdk_spin_unlock(&g_keyring_spin);
|
||||
}
|
||||
|
||||
void
|
||||
_accel_crypto_keys_dump_param(struct spdk_json_write_ctx *w)
|
||||
{
|
||||
_accel_crypto_keys_write_config_json(w, false);
|
||||
}
|
||||
|
||||
void
|
||||
spdk_accel_write_config_json(struct spdk_json_write_ctx *w)
|
||||
{
|
||||
@ -1285,6 +1665,9 @@ spdk_accel_write_config_json(struct spdk_json_write_ctx *w)
|
||||
accel_write_overridden_opc(w, g_opcode_strings[i], g_modules_opc_override[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_accel_crypto_keys_write_config_json(w, true);
|
||||
|
||||
spdk_json_write_array_end(w);
|
||||
}
|
||||
|
||||
@ -1298,6 +1681,7 @@ spdk_accel_module_finish(void)
|
||||
}
|
||||
|
||||
if (!g_accel_module) {
|
||||
spdk_spin_destroy(&g_keyring_spin);
|
||||
accel_module_finish_cb();
|
||||
return;
|
||||
}
|
||||
@ -1312,6 +1696,7 @@ spdk_accel_module_finish(void)
|
||||
void
|
||||
spdk_accel_finish(spdk_accel_fini_cb cb_fn, void *cb_arg)
|
||||
{
|
||||
struct spdk_accel_crypto_key *key, *key_tmp;
|
||||
enum accel_opcode op;
|
||||
|
||||
assert(cb_fn != NULL);
|
||||
@ -1319,6 +1704,12 @@ spdk_accel_finish(spdk_accel_fini_cb cb_fn, void *cb_arg)
|
||||
g_fini_cb_fn = cb_fn;
|
||||
g_fini_cb_arg = cb_arg;
|
||||
|
||||
spdk_spin_lock(&g_keyring_spin);
|
||||
TAILQ_FOREACH_SAFE(key, &g_keyring, link, key_tmp) {
|
||||
accel_crypto_key_destroy_unsafe(key);
|
||||
}
|
||||
spdk_spin_unlock(&g_keyring_spin);
|
||||
|
||||
for (op = 0; op < ACCEL_OPC_LAST; op++) {
|
||||
if (g_modules_opc_override[op] != NULL) {
|
||||
free(g_modules_opc_override[op]);
|
||||
|
@ -23,5 +23,8 @@ struct module_info {
|
||||
typedef void (*_accel_for_each_module_fn)(struct module_info *info);
|
||||
void _accel_for_each_module(struct module_info *info, _accel_for_each_module_fn fn);
|
||||
int _accel_get_opc_name(enum accel_opcode opcode, const char **opcode_name);
|
||||
void _accel_crypto_key_dump_param(struct spdk_json_write_ctx *w, struct spdk_accel_crypto_key *key);
|
||||
void _accel_crypto_keys_dump_param(struct spdk_json_write_ctx *w);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -5,12 +5,14 @@
|
||||
*/
|
||||
|
||||
#include "accel_internal.h"
|
||||
#include "spdk_internal/accel_module.h"
|
||||
|
||||
#include "spdk/rpc.h"
|
||||
#include "spdk/util.h"
|
||||
#include "spdk/event.h"
|
||||
#include "spdk/stdinc.h"
|
||||
#include "spdk/env.h"
|
||||
#include "spdk/util.h"
|
||||
|
||||
static void
|
||||
rpc_accel_get_opc_assignments(struct spdk_jsonrpc_request *request,
|
||||
@ -171,3 +173,102 @@ cleanup:
|
||||
|
||||
}
|
||||
SPDK_RPC_REGISTER("accel_assign_opc", rpc_accel_assign_opc, SPDK_RPC_STARTUP)
|
||||
|
||||
struct rpc_accel_crypto_key_create {
|
||||
struct spdk_accel_crypto_key_create_param param;
|
||||
};
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_accel_dek_create_decoders[] = {
|
||||
{"cipher", offsetof(struct rpc_accel_crypto_key_create, param.cipher), spdk_json_decode_string},
|
||||
{"key", offsetof(struct rpc_accel_crypto_key_create, param.hex_key), spdk_json_decode_string},
|
||||
{"key2", offsetof(struct rpc_accel_crypto_key_create, param.hex_key2), spdk_json_decode_string, true},
|
||||
{"name", offsetof(struct rpc_accel_crypto_key_create, param.key_name), spdk_json_decode_string},
|
||||
};
|
||||
|
||||
static void
|
||||
rpc_accel_crypto_key_create(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_accel_crypto_key_create req = {};
|
||||
size_t key_size;
|
||||
int rc;
|
||||
|
||||
if (spdk_json_decode_object(params, rpc_accel_dek_create_decoders,
|
||||
SPDK_COUNTOF(rpc_accel_dek_create_decoders),
|
||||
&req)) {
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_PARSE_ERROR,
|
||||
"spdk_json_decode_object failed");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = spdk_accel_crypto_key_create(&req.param);
|
||||
if (rc) {
|
||||
spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
|
||||
"failed to create DEK, rc %d", rc);
|
||||
} else {
|
||||
spdk_jsonrpc_send_bool_response(request, true);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
free(req.param.cipher);
|
||||
if (req.param.hex_key) {
|
||||
key_size = strnlen(req.param.hex_key, SPDK_ACCEL_CRYPTO_KEY_MAX_HEX_LENGTH);
|
||||
spdk_memset_s(req.param.hex_key, key_size, 0, key_size);
|
||||
free(req.param.hex_key);
|
||||
}
|
||||
if (req.param.hex_key2) {
|
||||
key_size = strnlen(req.param.hex_key2, SPDK_ACCEL_CRYPTO_KEY_MAX_HEX_LENGTH);
|
||||
spdk_memset_s(req.param.hex_key2, key_size, 0, key_size);
|
||||
free(req.param.hex_key2);
|
||||
}
|
||||
free(req.param.key_name);
|
||||
}
|
||||
SPDK_RPC_REGISTER("accel_crypto_key_create", rpc_accel_crypto_key_create, SPDK_RPC_RUNTIME)
|
||||
|
||||
struct rpc_accel_crypto_keys_get_ctx {
|
||||
char *key_name;
|
||||
};
|
||||
|
||||
static const struct spdk_json_object_decoder rpc_accel_crypto_keys_get_decoders[] = {
|
||||
{"key_name", offsetof(struct rpc_accel_crypto_keys_get_ctx, key_name), spdk_json_decode_string, true},
|
||||
};
|
||||
|
||||
static void
|
||||
rpc_accel_crypto_keys_get(struct spdk_jsonrpc_request *request,
|
||||
const struct spdk_json_val *params)
|
||||
{
|
||||
struct rpc_accel_crypto_keys_get_ctx req = {};
|
||||
struct spdk_accel_crypto_key *key = NULL;
|
||||
struct spdk_json_write_ctx *w;
|
||||
|
||||
if (params && spdk_json_decode_object(params, rpc_accel_crypto_keys_get_decoders,
|
||||
SPDK_COUNTOF(rpc_accel_crypto_keys_get_decoders),
|
||||
&req)) {
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_PARSE_ERROR,
|
||||
"spdk_json_decode_object failed");
|
||||
free(req.key_name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req.key_name) {
|
||||
key = spdk_accel_crypto_key_get(req.key_name);
|
||||
free(req.key_name);
|
||||
if (!key) {
|
||||
spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "key was not found\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
w = spdk_jsonrpc_begin_result(request);
|
||||
spdk_json_write_array_begin(w);
|
||||
|
||||
if (key) {
|
||||
_accel_crypto_key_dump_param(w, key);
|
||||
} else {
|
||||
_accel_crypto_keys_dump_param(w);
|
||||
}
|
||||
|
||||
spdk_json_write_array_end(w);
|
||||
spdk_jsonrpc_end_result(request, w);
|
||||
}
|
||||
SPDK_RPC_REGISTER("accel_crypto_keys_get", rpc_accel_crypto_keys_get, SPDK_RPC_RUNTIME)
|
||||
|
@ -1,11 +1,13 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause
|
||||
* Copyright (C) 2022 Intel Corporation.
|
||||
* Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
#include "spdk/stdinc.h"
|
||||
|
||||
#include "spdk_internal/accel_module.h"
|
||||
#include "accel_internal.h"
|
||||
|
||||
#include "spdk/env.h"
|
||||
#include "spdk/likely.h"
|
||||
@ -21,7 +23,16 @@
|
||||
|
||||
#ifdef SPDK_CONFIG_ISAL
|
||||
#include "../isa-l/include/igzip_lib.h"
|
||||
#ifdef SPDK_CONFIG_ISAL_CRYPTO
|
||||
#include "../isa-l-crypto/include/aes_xts.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define ACCEL_AES_XTS_128_KEY_SIZE 16
|
||||
#define ACCEL_AES_XTS_256_KEY_SIZE 32
|
||||
#define ACCEL_AES_XTS "AES_XTS"
|
||||
/* Per the AES-XTS spec, the size of data unit cannot be bigger than 2^20 blocks, 128b each block */
|
||||
#define ACCEL_AES_XTS_MAX_BLOCK_SIZE (1 << 24)
|
||||
|
||||
struct sw_accel_io_channel {
|
||||
/* for ISAL */
|
||||
@ -33,6 +44,19 @@ struct sw_accel_io_channel {
|
||||
TAILQ_HEAD(, spdk_accel_task) tasks_to_complete;
|
||||
};
|
||||
|
||||
typedef void (*sw_accel_crypto_op)(uint8_t *k2, uint8_t *k1, uint8_t *tweak, uint64_t lba_size,
|
||||
const uint8_t *src, uint8_t *dst);
|
||||
|
||||
struct sw_accel_crypto_key_data {
|
||||
sw_accel_crypto_op encrypt;
|
||||
sw_accel_crypto_op decrypt;
|
||||
};
|
||||
|
||||
static struct spdk_accel_module_if g_sw_module;
|
||||
|
||||
static void sw_accel_crypto_key_deinit(struct spdk_accel_crypto_key *_key);
|
||||
static int sw_accel_crypto_key_init(struct spdk_accel_crypto_key *key);
|
||||
|
||||
/* Post SW completions to a list and complete in a poller as we don't want to
|
||||
* complete them on the caller's stack as they'll likely submit another. */
|
||||
inline static void
|
||||
@ -68,6 +92,8 @@ sw_accel_supports_opcode(enum accel_opcode opc)
|
||||
case ACCEL_OPC_COPY_CRC32C:
|
||||
case ACCEL_OPC_COMPRESS:
|
||||
case ACCEL_OPC_DECOMPRESS:
|
||||
case ACCEL_OPC_ENCRYPT:
|
||||
case ACCEL_OPC_DECRYPT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@ -230,7 +256,7 @@ _sw_accel_compress(struct sw_accel_io_channel *sw_ch, struct spdk_accel_task *ac
|
||||
|
||||
rc = isal_deflate(&sw_ch->stream);
|
||||
if (rc) {
|
||||
SPDK_ERRLOG("isal_deflate retunred error %d.\n", rc);
|
||||
SPDK_ERRLOG("isal_deflate returned error %d.\n", rc);
|
||||
}
|
||||
|
||||
if (remaining > 0) {
|
||||
@ -290,7 +316,7 @@ _sw_accel_decompress(struct sw_accel_io_channel *sw_ch, struct spdk_accel_task *
|
||||
|
||||
rc = isal_inflate(&sw_ch->state);
|
||||
if (rc) {
|
||||
SPDK_ERRLOG("isal_inflate retunred error %d.\n", rc);
|
||||
SPDK_ERRLOG("isal_inflate returned error %d.\n", rc);
|
||||
}
|
||||
|
||||
} while (sw_ch->state.block_state < ISAL_BLOCK_FINISH);
|
||||
@ -303,6 +329,127 @@ _sw_accel_decompress(struct sw_accel_io_channel *sw_ch, struct spdk_accel_task *
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
_sw_accel_crypto_operation(struct spdk_accel_task *accel_task, struct spdk_accel_crypto_key *key,
|
||||
sw_accel_crypto_op op)
|
||||
{
|
||||
#ifdef SPDK_CONFIG_ISAL_CRYPTO
|
||||
uint64_t iv[2];
|
||||
size_t remaining_len;
|
||||
uint64_t src_offset = 0, dst_offset = 0;
|
||||
uint32_t src_iovpos = 0, dst_iovpos = 0, src_iovcnt, dst_iovcnt;
|
||||
uint32_t block_size, crypto_len, crypto_accum_len = 0;
|
||||
struct iovec *src_iov, *dst_iov;
|
||||
uint8_t *src, *dst;
|
||||
|
||||
/* iv is 128 bits, since we are using logical block address (64 bits) as iv, fill first 8 bytes with zeroes */
|
||||
iv[0] = 0;
|
||||
iv[1] = accel_task->iv;
|
||||
src_iov = accel_task->s.iovs;
|
||||
src_iovcnt = accel_task->s.iovcnt;
|
||||
if (accel_task->d.iovcnt) {
|
||||
dst_iov = accel_task->d.iovs;
|
||||
dst_iovcnt = accel_task->d.iovcnt;
|
||||
} else {
|
||||
/* inplace operation */
|
||||
dst_iov = accel_task->s.iovs;
|
||||
dst_iovcnt = accel_task->s.iovcnt;
|
||||
}
|
||||
block_size = accel_task->block_size;
|
||||
|
||||
if (!src_iovcnt || !dst_iovcnt || !block_size || !op) {
|
||||
SPDK_ERRLOG("src_iovcnt %d, dst_iovcnt %d, block_size %d, op %p\n", src_iovcnt, dst_iovcnt,
|
||||
block_size, op);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
remaining_len = accel_task->nbytes;
|
||||
|
||||
while (remaining_len) {
|
||||
crypto_len = spdk_min(block_size - crypto_accum_len, src_iov->iov_len - src_offset);
|
||||
crypto_len = spdk_min(crypto_len, dst_iov->iov_len - dst_offset);
|
||||
src = (uint8_t *)src_iov->iov_base + src_offset;
|
||||
dst = (uint8_t *)dst_iov->iov_base + dst_offset;
|
||||
|
||||
op((uint8_t *)key->key2, (uint8_t *)key->key, (uint8_t *)iv, crypto_len, src, dst);
|
||||
|
||||
src_offset += crypto_len;
|
||||
dst_offset += crypto_len;
|
||||
crypto_accum_len += crypto_len;
|
||||
remaining_len -= crypto_len;
|
||||
|
||||
if (crypto_accum_len == block_size) {
|
||||
/* we can process part of logical block. Once the whole block is processed, increment iv */
|
||||
crypto_accum_len = 0;
|
||||
iv[1]++;
|
||||
}
|
||||
if (src_offset == src_iov->iov_len) {
|
||||
src_iov++;
|
||||
src_iovpos++;
|
||||
src_offset = 0;
|
||||
}
|
||||
if (src_iovpos == src_iovcnt) {
|
||||
break;
|
||||
}
|
||||
if (dst_offset == dst_iov->iov_len) {
|
||||
dst_iov++;
|
||||
dst_iovpos++;
|
||||
dst_offset = 0;
|
||||
}
|
||||
if (dst_iovpos == dst_iovcnt) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (remaining_len) {
|
||||
SPDK_ERRLOG("remaining len %zu\n", remaining_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
_sw_accel_encrypt(struct sw_accel_io_channel *sw_ch, struct spdk_accel_task *accel_task)
|
||||
{
|
||||
struct spdk_accel_crypto_key *key;
|
||||
struct sw_accel_crypto_key_data *key_data;
|
||||
|
||||
key = accel_task->crypto_key;
|
||||
if (spdk_unlikely(key->module_if != &g_sw_module || !key->priv)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (spdk_unlikely(accel_task->block_size > ACCEL_AES_XTS_MAX_BLOCK_SIZE)) {
|
||||
SPDK_WARNLOG("Max block size for AES_XTS is limited to %u, current size %u\n",
|
||||
ACCEL_AES_XTS_MAX_BLOCK_SIZE, accel_task->block_size);
|
||||
return -ERANGE;
|
||||
}
|
||||
key_data = key->priv;
|
||||
return _sw_accel_crypto_operation(accel_task, key, key_data->encrypt);
|
||||
}
|
||||
|
||||
static int
|
||||
_sw_accel_decrypt(struct sw_accel_io_channel *sw_ch, struct spdk_accel_task *accel_task)
|
||||
{
|
||||
struct spdk_accel_crypto_key *key;
|
||||
struct sw_accel_crypto_key_data *key_data;
|
||||
|
||||
key = accel_task->crypto_key;
|
||||
if (spdk_unlikely(key->module_if != &g_sw_module || !key->priv)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (spdk_unlikely(accel_task->block_size > ACCEL_AES_XTS_MAX_BLOCK_SIZE)) {
|
||||
SPDK_WARNLOG("Max block size for AES_XTS is limited to %u, current size %u\n",
|
||||
ACCEL_AES_XTS_MAX_BLOCK_SIZE, accel_task->block_size);
|
||||
return -ERANGE;
|
||||
}
|
||||
key_data = key->priv;
|
||||
return _sw_accel_crypto_operation(accel_task, key, key_data->decrypt);
|
||||
}
|
||||
|
||||
static int
|
||||
sw_accel_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *accel_task)
|
||||
{
|
||||
@ -359,6 +506,12 @@ sw_accel_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *accel_
|
||||
case ACCEL_OPC_DECOMPRESS:
|
||||
rc = _sw_accel_decompress(sw_ch, accel_task);
|
||||
break;
|
||||
case ACCEL_OPC_ENCRYPT:
|
||||
rc = _sw_accel_encrypt(sw_ch, accel_task);
|
||||
break;
|
||||
case ACCEL_OPC_DECRYPT:
|
||||
rc = _sw_accel_decrypt(sw_ch, accel_task);
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
break;
|
||||
@ -380,14 +533,16 @@ static void sw_accel_module_fini(void *ctxt);
|
||||
static size_t sw_accel_module_get_ctx_size(void);
|
||||
|
||||
static struct spdk_accel_module_if g_sw_module = {
|
||||
.module_init = sw_accel_module_init,
|
||||
.module_fini = sw_accel_module_fini,
|
||||
.write_config_json = NULL,
|
||||
.get_ctx_size = sw_accel_module_get_ctx_size,
|
||||
.module_init = sw_accel_module_init,
|
||||
.module_fini = sw_accel_module_fini,
|
||||
.write_config_json = NULL,
|
||||
.get_ctx_size = sw_accel_module_get_ctx_size,
|
||||
.name = "software",
|
||||
.supports_opcode = sw_accel_supports_opcode,
|
||||
.get_io_channel = sw_accel_get_io_channel,
|
||||
.submit_tasks = sw_accel_submit_tasks
|
||||
.submit_tasks = sw_accel_submit_tasks,
|
||||
.crypto_key_init = sw_accel_crypto_key_init,
|
||||
.crypto_key_deinit = sw_accel_crypto_key_deinit,
|
||||
};
|
||||
|
||||
static int
|
||||
@ -477,4 +632,74 @@ sw_accel_module_fini(void *ctxt)
|
||||
spdk_accel_module_finish();
|
||||
}
|
||||
|
||||
static int
|
||||
sw_accel_create_aes_xts(struct spdk_accel_crypto_key *key)
|
||||
{
|
||||
#ifdef SPDK_CONFIG_ISAL_CRYPTO
|
||||
struct sw_accel_crypto_key_data *key_data;
|
||||
|
||||
if (!key->key || !key->key2) {
|
||||
SPDK_ERRLOG("key or key2 are missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!key->key_size || key->key_size != key->key2_size) {
|
||||
SPDK_ERRLOG("key size %zu is not equal to key2 size %zu or is 0\n", key->key_size,
|
||||
key->key2_size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key_data = calloc(1, sizeof(*key_data));
|
||||
if (!key_data) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
switch (key->key_size) {
|
||||
case ACCEL_AES_XTS_128_KEY_SIZE:
|
||||
key_data->encrypt = XTS_AES_128_enc;
|
||||
key_data->decrypt = XTS_AES_128_dec;
|
||||
break;
|
||||
case ACCEL_AES_XTS_256_KEY_SIZE:
|
||||
key_data->encrypt = XTS_AES_256_enc;
|
||||
key_data->decrypt = XTS_AES_256_dec;
|
||||
break;
|
||||
default:
|
||||
SPDK_ERRLOG("Incorrect key size %zu, should be %d for AEX_XTS_128 or %d for AES_XTS_256\n",
|
||||
key->key_size, ACCEL_AES_XTS_128_KEY_SIZE, ACCEL_AES_XTS_256_KEY_SIZE);
|
||||
free(key_data);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
key->priv = key_data;
|
||||
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTSUP;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
sw_accel_crypto_key_init(struct spdk_accel_crypto_key *key)
|
||||
{
|
||||
if (!key || !key->param.cipher) {
|
||||
return -EINVAL;
|
||||
}
|
||||
if (strcmp(key->param.cipher, ACCEL_AES_XTS) == 0) {
|
||||
return sw_accel_create_aes_xts(key);
|
||||
} else {
|
||||
SPDK_ERRLOG("Only %s cipher is supported\n", ACCEL_AES_XTS);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
sw_accel_crypto_key_deinit(struct spdk_accel_crypto_key *key)
|
||||
{
|
||||
if (!key || key->module_if != &g_sw_module || !key->priv) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(key->priv);
|
||||
}
|
||||
|
||||
SPDK_ACCEL_MODULE_REGISTER(sw, &g_sw_module)
|
||||
|
@ -15,6 +15,8 @@
|
||||
spdk_accel_submit_copy_crc32cv;
|
||||
spdk_accel_submit_compress;
|
||||
spdk_accel_submit_decompress;
|
||||
spdk_accel_submit_encrypt;
|
||||
spdk_accel_submit_decrypt;
|
||||
spdk_accel_get_opc_module_name;
|
||||
spdk_accel_assign_opc;
|
||||
spdk_accel_write_config_json;
|
||||
@ -26,6 +28,9 @@
|
||||
spdk_accel_sequence_reverse;
|
||||
spdk_accel_get_buf;
|
||||
spdk_accel_put_buf;
|
||||
spdk_accel_crypto_key_create;
|
||||
spdk_accel_crypto_key_destroy;
|
||||
spdk_accel_crypto_key_get;
|
||||
|
||||
# functions needed by modules
|
||||
spdk_accel_module_list_add;
|
||||
|
@ -31,3 +31,37 @@ def accel_assign_opc(client, opname, module):
|
||||
}
|
||||
|
||||
return client.call('accel_assign_opc', params)
|
||||
|
||||
|
||||
def accel_crypto_key_create(client, cipher, key, key2, name):
|
||||
"""Create Data Encryption Key Identifier.
|
||||
|
||||
Args:
|
||||
cipher: cipher
|
||||
key: key
|
||||
key2: key2
|
||||
name: key name
|
||||
"""
|
||||
params = {
|
||||
'cipher': cipher,
|
||||
'key': key,
|
||||
'name': name,
|
||||
}
|
||||
if key2 is not None:
|
||||
params['key2'] = key2
|
||||
|
||||
return client.call('accel_crypto_key_create', params)
|
||||
|
||||
|
||||
def accel_crypto_keys_get(client, key_name):
|
||||
"""Get a list of the crypto keys.
|
||||
|
||||
Args:
|
||||
key_name: Get information about a specific key
|
||||
"""
|
||||
params = {}
|
||||
|
||||
if key_name is not None:
|
||||
params['key_name'] = key_name
|
||||
|
||||
return client.call('accel_crypto_keys_get', params)
|
||||
|
@ -2792,6 +2792,28 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse
|
||||
p.add_argument('-m', '--module', help='name of module')
|
||||
p.set_defaults(func=accel_assign_opc)
|
||||
|
||||
def accel_crypto_key_create(args):
|
||||
print_dict(rpc.accel.accel_crypto_key_create(args.client,
|
||||
cipher=args.cipher,
|
||||
key=args.key,
|
||||
key2=args.key2,
|
||||
name=args.name))
|
||||
|
||||
p = subparsers.add_parser('accel_crypto_key_create', help='Create encryption key')
|
||||
p.add_argument('-c', '--cipher', help='cipher', required=True, type=str)
|
||||
p.add_argument('-k', '--key', help='key', required=True, type=str)
|
||||
p.add_argument('-e', '--key2', help='key2', required=False, type=str)
|
||||
p.add_argument('-n', '--name', help='key name', required=True, type=str)
|
||||
p.set_defaults(func=accel_crypto_key_create)
|
||||
|
||||
def accel_crypto_keys_get(args):
|
||||
print_dict(rpc.accel.accel_crypto_keys_get(args.client,
|
||||
key_name=args.key_name))
|
||||
|
||||
p = subparsers.add_parser('accel_crypto_keys_get', help='Get a list of the crypto keys')
|
||||
p.add_argument('-k', '--key-name', help='Get information about a specific key', type=str)
|
||||
p.set_defaults(func=accel_crypto_keys_get)
|
||||
|
||||
# ioat
|
||||
def ioat_scan_accel_module(args):
|
||||
rpc.ioat.ioat_scan_accel_module(args.client)
|
||||
|
@ -1,5 +1,6 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Copyright (C) 2020 Intel Corporation.
|
||||
# Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
|
||||
# All rights reserved.
|
||||
#
|
||||
|
||||
@ -13,22 +14,22 @@ SYS_LIB := $(shell PKG_CONFIG_PATH="$(PKG_CONFIG_PATH)" pkg-config --libs --stat
|
||||
# Shows how to compile both an external bdev and an external application against the SPDK combined shared object and dpdk shared objects.
|
||||
bdev_shared_combo:
|
||||
$(CC) $(COMMON_CFLAGS) -L../passthru -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c -lpassthru_external \
|
||||
-lspdk $(DPDK_LIB) -Wl,--no-whole-archive
|
||||
-lspdk $(DPDK_LIB) -Wl,--no-whole-archive $(SYS_LIB)
|
||||
|
||||
# Shows how to compile both an external bdev and an external application against the SPDK individual shared objects and dpdk shared objects.
|
||||
bdev_shared_iso:
|
||||
$(CC) $(COMMON_CFLAGS) -L../passthru -Wl,--no-as-needed -o hello_bdev ./hello_bdev.c \
|
||||
-lpassthru_external $(SPDK_EVENT_LIB) \
|
||||
$(DPDK_LIB)
|
||||
$(DPDK_LIB) $(SYS_LIB)
|
||||
|
||||
# Shows how to compile an external application against the SPDK combined shared object and dpdk shared objects.
|
||||
alone_shared_combo:
|
||||
$(CC) $(COMMON_CFLAGS) -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c -lspdk $(DPDK_LIB)
|
||||
$(CC) $(COMMON_CFLAGS) -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c -lspdk $(DPDK_LIB) $(SYS_LIB)
|
||||
|
||||
# Shows how to compile an external application against the SPDK individual shared objects and dpdk shared objects.
|
||||
alone_shared_iso:
|
||||
$(CC) $(COMMON_CFLAGS) -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c \
|
||||
$(SPDK_EVENT_LIB) $(DPDK_LIB)
|
||||
$(SPDK_EVENT_LIB) $(DPDK_LIB) $(SYS_LIB)
|
||||
|
||||
# Shows how to compile an external application against the SPDK archives.
|
||||
alone_static:
|
||||
|
@ -24,6 +24,17 @@ DEFINE_STUB(spdk_memory_domain_create, int,
|
||||
struct spdk_memory_domain_ctx *ctx, const char *id), 0);
|
||||
DEFINE_STUB_V(spdk_memory_domain_destroy, (struct spdk_memory_domain *domain));
|
||||
|
||||
#ifdef SPDK_CONFIG_ISAL
|
||||
DEFINE_STUB_V(XTS_AES_128_enc, (uint8_t *k2, uint8_t *k1, uint8_t *tweak, uint64_t lba_size,
|
||||
const uint8_t *src, uint8_t *dst));
|
||||
DEFINE_STUB_V(XTS_AES_128_dec, (uint8_t *k2, uint8_t *k1, uint8_t *tweak, uint64_t lba_size,
|
||||
const uint8_t *src, uint8_t *dst));
|
||||
DEFINE_STUB_V(XTS_AES_256_enc, (uint8_t *k2, uint8_t *k1, uint8_t *tweak, uint64_t lba_size,
|
||||
const uint8_t *src, uint8_t *dst));
|
||||
DEFINE_STUB_V(XTS_AES_256_dec, (uint8_t *k2, uint8_t *k1, uint8_t *tweak, uint64_t lba_size,
|
||||
const uint8_t *src, uint8_t *dst));
|
||||
#endif
|
||||
|
||||
/* global vars and setup/cleanup functions used for all test functions */
|
||||
struct spdk_accel_module_if g_module = {};
|
||||
struct spdk_io_channel *g_ch = NULL;
|
||||
|
Loading…
Reference in New Issue
Block a user