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:
Alexey Marchuk 2022-10-04 21:16:21 +02:00 committed by Tomasz Zawadzki
parent d68159b618
commit 2608d129d0
14 changed files with 1033 additions and 20 deletions

View File

@ -6,6 +6,8 @@
New library isa-l-crypto has been added, it is used by accel library in crypto operations. 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 ### bdev
Both of interleaved and separated metadata are now supported by the malloc bdev module. Both of interleaved and separated metadata are now supported by the malloc bdev module.

View File

@ -442,6 +442,8 @@ Example response:
"framework_monitor_context_switch", "framework_monitor_context_switch",
"spdk_kill_instance", "spdk_kill_instance",
"accel_get_opc_assignments", "accel_get_opc_assignments",
"accel_crypto_key_create",
"accel_crypto_keys_get",
"ioat_scan_accel_module", "ioat_scan_accel_module",
"dsa_scan_accel_module", "dsa_scan_accel_module",
"bdev_virtio_attach_controller", "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} ### dsa_scan_accel_module {#rpc_dsa_scan_accel_module}
Set config and enable dsa accel module offload. Set config and enable dsa accel module offload.

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause /* SPDX-License-Identifier: BSD-3-Clause
* Copyright (C) 2020 Intel Corporation. * Copyright (C) 2020 Intel Corporation.
* Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
* All rights reserved. * All rights reserved.
*/ */
@ -17,9 +18,19 @@
extern "C" { extern "C" {
#endif #endif
/** Data Encryption Key identifier */
struct spdk_accel_crypto_key;
/* Flags for accel operations */ /* Flags for accel operations */
#define ACCEL_FLAG_PERSISTENT (1 << 0) #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 { enum accel_opcode {
ACCEL_OPC_COPY = 0, ACCEL_OPC_COPY = 0,
ACCEL_OPC_FILL = 1, ACCEL_OPC_FILL = 1,
@ -29,7 +40,9 @@ enum accel_opcode {
ACCEL_OPC_COPY_CRC32C = 5, ACCEL_OPC_COPY_CRC32C = 5,
ACCEL_OPC_COMPRESS = 6, ACCEL_OPC_COMPRESS = 6,
ACCEL_OPC_DECOMPRESS = 7, 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); 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. * 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, void spdk_accel_put_buf(struct spdk_io_channel *ch, void *buf,
struct spdk_memory_domain *domain, void *domain_ctx); 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. * Return the name of the module assigned to a specific opcode.
* *

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: BSD-3-Clause /* SPDX-License-Identifier: BSD-3-Clause
* Copyright (C) 2020 Intel Corporation. * Copyright (C) 2020 Intel Corporation.
* Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
* All rights reserved. * All rights reserved.
*/ */
@ -12,10 +13,25 @@
#include "spdk/queue.h" #include "spdk/queue.h"
#include "spdk/config.h" #include "spdk/config.h"
struct spdk_accel_module_if;
struct spdk_accel_task; struct spdk_accel_task;
void spdk_accel_task_complete(struct spdk_accel_task *task, int status); 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 spdk_accel_task {
struct accel_io_channel *accel_ch; struct accel_io_channel *accel_ch;
spdk_accel_completion_cb cb_fn; spdk_accel_completion_cb cb_fn;
@ -45,14 +61,19 @@ struct spdk_accel_task {
void *dst2; void *dst2;
uint32_t seed; uint32_t seed;
uint64_t fill_pattern; uint64_t fill_pattern;
struct spdk_accel_crypto_key *crypto_key;
}; };
union { union {
uint32_t *crc_dst; uint32_t *crc_dst;
uint32_t *output_size; uint32_t *output_size;
uint32_t block_size; /* for crypto op */
}; };
enum accel_opcode op_code; enum accel_opcode op_code;
uint64_t nbytes; 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 flags;
int status; int status;
TAILQ_ENTRY(spdk_accel_task) link; TAILQ_ENTRY(spdk_accel_task) link;
@ -89,6 +110,13 @@ struct spdk_accel_module_if {
struct spdk_io_channel *(*get_io_channel)(void); struct spdk_io_channel *(*get_io_channel)(void);
int (*submit_tasks)(struct spdk_io_channel *ch, struct spdk_accel_task *accel_task); 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; TAILQ_ENTRY(spdk_accel_module_if) tailq;
}; };

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
# Copyright (C) 2015 Intel Corporation. # Copyright (C) 2015 Intel Corporation.
# Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
# All rights reserved. # All rights reserved.
# #
@ -17,6 +18,10 @@ ifeq ($(CONFIG_ISAL), y)
LOCAL_SYS_LIBS = -L$(ISAL_DIR)/.libs -lisal LOCAL_SYS_LIBS = -L$(ISAL_DIR)/.libs -lisal
endif 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) SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_accel.map)
include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk include $(SPDK_ROOT_DIR)/mk/spdk.lib.mk

View File

@ -18,6 +18,7 @@
#include "spdk/json.h" #include "spdk/json.h"
#include "spdk/crc32.h" #include "spdk/crc32.h"
#include "spdk/util.h" #include "spdk/util.h"
#include "spdk/hexlify.h"
/* Accelerator Framework: The following provides a top level /* Accelerator Framework: The following provides a top level
* generic API for the accelerator functions defined here. Modules, * 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 = static TAILQ_HEAD(, spdk_accel_module_if) spdk_accel_module_list =
TAILQ_HEAD_INITIALIZER(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 */ /* Global array mapping capabilities to modules */
static struct spdk_accel_module_if *g_modules_opc[ACCEL_OPC_LAST] = {}; static struct spdk_accel_module_if *g_modules_opc[ACCEL_OPC_LAST] = {};
static char *g_modules_opc_override[ACCEL_OPC_LAST] = {}; static char *g_modules_opc_override[ACCEL_OPC_LAST] = {};
static const char *g_opcode_strings[ACCEL_OPC_LAST] = { static const char *g_opcode_strings[ACCEL_OPC_LAST] = {
"copy", "fill", "dualcast", "compare", "crc32c", "copy_crc32c", "copy", "fill", "dualcast", "compare", "crc32c", "copy_crc32c",
"compress", "decompress" "compress", "decompress", "encrypt", "decrypt"
}; };
struct accel_buffer { 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; return accel_task;
} }
/* Accel framework public API for copy function */ /* Accel framework public API for copy function */
int int
spdk_accel_submit_copy(struct spdk_io_channel *ch, void *dst, void *src, 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; 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 * static inline struct accel_buffer *
accel_get_buf(struct accel_io_channel *ch, uint64_t len) 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; 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 void
spdk_accel_module_list_add(struct spdk_accel_module_if *accel_module) 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 /* 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 * 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) { if (strcmp(accel_module->name, "software") == 0) {
TAILQ_INSERT_HEAD(&spdk_accel_module_list, accel_module, tailq); TAILQ_INSERT_HEAD(&spdk_accel_module_list, accel_module, tailq);
@ -1178,14 +1498,16 @@ spdk_accel_initialize(void)
return rc; return rc;
} }
spdk_spin_init(&g_keyring_spin);
g_modules_started = true; g_modules_started = true;
accel_module_initialize(); accel_module_initialize();
/* Create our priority global map of opcodes to modules, we populate starting /* 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 * 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 * 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) { TAILQ_FOREACH(accel_module, &spdk_accel_module_list, tailq) {
for (op = 0; op < ACCEL_OPC_LAST; op++) { 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 #ifdef DEBUG
for (op = 0; op < ACCEL_OPC_LAST; op++) { for (op = 0; op < ACCEL_OPC_LAST; op++) {
assert(g_modules_opc[op] != NULL); 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); 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 void
spdk_accel_write_config_json(struct spdk_json_write_ctx *w) 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_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); spdk_json_write_array_end(w);
} }
@ -1298,6 +1681,7 @@ spdk_accel_module_finish(void)
} }
if (!g_accel_module) { if (!g_accel_module) {
spdk_spin_destroy(&g_keyring_spin);
accel_module_finish_cb(); accel_module_finish_cb();
return; return;
} }
@ -1312,6 +1696,7 @@ spdk_accel_module_finish(void)
void void
spdk_accel_finish(spdk_accel_fini_cb cb_fn, void *cb_arg) spdk_accel_finish(spdk_accel_fini_cb cb_fn, void *cb_arg)
{ {
struct spdk_accel_crypto_key *key, *key_tmp;
enum accel_opcode op; enum accel_opcode op;
assert(cb_fn != NULL); 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_fn = cb_fn;
g_fini_cb_arg = cb_arg; 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++) { for (op = 0; op < ACCEL_OPC_LAST; op++) {
if (g_modules_opc_override[op] != NULL) { if (g_modules_opc_override[op] != NULL) {
free(g_modules_opc_override[op]); free(g_modules_opc_override[op]);

View File

@ -23,5 +23,8 @@ struct module_info {
typedef void (*_accel_for_each_module_fn)(struct module_info *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); 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); 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 #endif

View File

@ -5,12 +5,14 @@
*/ */
#include "accel_internal.h" #include "accel_internal.h"
#include "spdk_internal/accel_module.h"
#include "spdk/rpc.h" #include "spdk/rpc.h"
#include "spdk/util.h" #include "spdk/util.h"
#include "spdk/event.h" #include "spdk/event.h"
#include "spdk/stdinc.h" #include "spdk/stdinc.h"
#include "spdk/env.h" #include "spdk/env.h"
#include "spdk/util.h"
static void static void
rpc_accel_get_opc_assignments(struct spdk_jsonrpc_request *request, 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) 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)

View File

@ -1,11 +1,13 @@
/* SPDX-License-Identifier: BSD-3-Clause /* SPDX-License-Identifier: BSD-3-Clause
* Copyright (C) 2022 Intel Corporation. * Copyright (C) 2022 Intel Corporation.
* Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
* All rights reserved. * All rights reserved.
*/ */
#include "spdk/stdinc.h" #include "spdk/stdinc.h"
#include "spdk_internal/accel_module.h" #include "spdk_internal/accel_module.h"
#include "accel_internal.h"
#include "spdk/env.h" #include "spdk/env.h"
#include "spdk/likely.h" #include "spdk/likely.h"
@ -21,7 +23,16 @@
#ifdef SPDK_CONFIG_ISAL #ifdef SPDK_CONFIG_ISAL
#include "../isa-l/include/igzip_lib.h" #include "../isa-l/include/igzip_lib.h"
#ifdef SPDK_CONFIG_ISAL_CRYPTO
#include "../isa-l-crypto/include/aes_xts.h"
#endif #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 { struct sw_accel_io_channel {
/* for ISAL */ /* for ISAL */
@ -33,6 +44,19 @@ struct sw_accel_io_channel {
TAILQ_HEAD(, spdk_accel_task) tasks_to_complete; 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 /* 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. */ * complete them on the caller's stack as they'll likely submit another. */
inline static void inline static void
@ -68,6 +92,8 @@ sw_accel_supports_opcode(enum accel_opcode opc)
case ACCEL_OPC_COPY_CRC32C: case ACCEL_OPC_COPY_CRC32C:
case ACCEL_OPC_COMPRESS: case ACCEL_OPC_COMPRESS:
case ACCEL_OPC_DECOMPRESS: case ACCEL_OPC_DECOMPRESS:
case ACCEL_OPC_ENCRYPT:
case ACCEL_OPC_DECRYPT:
return true; return true;
default: default:
return false; 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); rc = isal_deflate(&sw_ch->stream);
if (rc) { if (rc) {
SPDK_ERRLOG("isal_deflate retunred error %d.\n", rc); SPDK_ERRLOG("isal_deflate returned error %d.\n", rc);
} }
if (remaining > 0) { 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); rc = isal_inflate(&sw_ch->state);
if (rc) { 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); } 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 #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 static int
sw_accel_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *accel_task) 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: case ACCEL_OPC_DECOMPRESS:
rc = _sw_accel_decompress(sw_ch, accel_task); rc = _sw_accel_decompress(sw_ch, accel_task);
break; 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: default:
assert(false); assert(false);
break; break;
@ -380,14 +533,16 @@ static void sw_accel_module_fini(void *ctxt);
static size_t sw_accel_module_get_ctx_size(void); static size_t sw_accel_module_get_ctx_size(void);
static struct spdk_accel_module_if g_sw_module = { static struct spdk_accel_module_if g_sw_module = {
.module_init = sw_accel_module_init, .module_init = sw_accel_module_init,
.module_fini = sw_accel_module_fini, .module_fini = sw_accel_module_fini,
.write_config_json = NULL, .write_config_json = NULL,
.get_ctx_size = sw_accel_module_get_ctx_size, .get_ctx_size = sw_accel_module_get_ctx_size,
.name = "software", .name = "software",
.supports_opcode = sw_accel_supports_opcode, .supports_opcode = sw_accel_supports_opcode,
.get_io_channel = sw_accel_get_io_channel, .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 static int
@ -477,4 +632,74 @@ sw_accel_module_fini(void *ctxt)
spdk_accel_module_finish(); 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) SPDK_ACCEL_MODULE_REGISTER(sw, &g_sw_module)

View File

@ -15,6 +15,8 @@
spdk_accel_submit_copy_crc32cv; spdk_accel_submit_copy_crc32cv;
spdk_accel_submit_compress; spdk_accel_submit_compress;
spdk_accel_submit_decompress; spdk_accel_submit_decompress;
spdk_accel_submit_encrypt;
spdk_accel_submit_decrypt;
spdk_accel_get_opc_module_name; spdk_accel_get_opc_module_name;
spdk_accel_assign_opc; spdk_accel_assign_opc;
spdk_accel_write_config_json; spdk_accel_write_config_json;
@ -26,6 +28,9 @@
spdk_accel_sequence_reverse; spdk_accel_sequence_reverse;
spdk_accel_get_buf; spdk_accel_get_buf;
spdk_accel_put_buf; spdk_accel_put_buf;
spdk_accel_crypto_key_create;
spdk_accel_crypto_key_destroy;
spdk_accel_crypto_key_get;
# functions needed by modules # functions needed by modules
spdk_accel_module_list_add; spdk_accel_module_list_add;

View File

@ -31,3 +31,37 @@ def accel_assign_opc(client, opname, module):
} }
return client.call('accel_assign_opc', params) 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)

View File

@ -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.add_argument('-m', '--module', help='name of module')
p.set_defaults(func=accel_assign_opc) 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 # ioat
def ioat_scan_accel_module(args): def ioat_scan_accel_module(args):
rpc.ioat.ioat_scan_accel_module(args.client) rpc.ioat.ioat_scan_accel_module(args.client)

View File

@ -1,5 +1,6 @@
# SPDX-License-Identifier: BSD-3-Clause # SPDX-License-Identifier: BSD-3-Clause
# Copyright (C) 2020 Intel Corporation. # Copyright (C) 2020 Intel Corporation.
# Copyright (c) 2022 NVIDIA CORPORATION & AFFILIATES
# All rights reserved. # 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. # 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: bdev_shared_combo:
$(CC) $(COMMON_CFLAGS) -L../passthru -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c -lpassthru_external \ $(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. # 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: bdev_shared_iso:
$(CC) $(COMMON_CFLAGS) -L../passthru -Wl,--no-as-needed -o hello_bdev ./hello_bdev.c \ $(CC) $(COMMON_CFLAGS) -L../passthru -Wl,--no-as-needed -o hello_bdev ./hello_bdev.c \
-lpassthru_external $(SPDK_EVENT_LIB) \ -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. # Shows how to compile an external application against the SPDK combined shared object and dpdk shared objects.
alone_shared_combo: 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. # Shows how to compile an external application against the SPDK individual shared objects and dpdk shared objects.
alone_shared_iso: alone_shared_iso:
$(CC) $(COMMON_CFLAGS) -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c \ $(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. # Shows how to compile an external application against the SPDK archives.
alone_static: alone_static:

View File

@ -24,6 +24,17 @@ DEFINE_STUB(spdk_memory_domain_create, int,
struct spdk_memory_domain_ctx *ctx, const char *id), 0); struct spdk_memory_domain_ctx *ctx, const char *id), 0);
DEFINE_STUB_V(spdk_memory_domain_destroy, (struct spdk_memory_domain *domain)); 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 */ /* global vars and setup/cleanup functions used for all test functions */
struct spdk_accel_module_if g_module = {}; struct spdk_accel_module_if g_module = {};
struct spdk_io_channel *g_ch = NULL; struct spdk_io_channel *g_ch = NULL;