@@ -320,6 +320,7 @@ vhdx=""
numa=""
tcmalloc="no"
jemalloc="no"
+cryptodev_linux="no"
# parse CC options first
for opt do
@@ -3616,6 +3617,16 @@ EOF
fi
##########################################
+# cryptodev-linux header probe
+cat > $TMPC << EOF
+#include <crypto/cryptodev.h>
+int main(void) { return 0; }
+EOF
+if compile_prog "" "" ; then
+ cryptodev_linux="yes"
+fi
+
+##########################################
# signalfd probe
signalfd="no"
cat > $TMPC << EOF
@@ -4920,6 +4931,7 @@ echo "NUMA host support $numa"
echo "tcmalloc support $tcmalloc"
echo "jemalloc support $jemalloc"
echo "avx2 optimization $avx2_opt"
+echo "cryptodev-linux support $cryptodev_linux"
if test "$sdl_too_old" = "yes"; then
echo "-> Your SDL version is too old - please upgrade to have SDL support"
@@ -5321,6 +5333,10 @@ if test "$avx2_opt" = "yes" ; then
echo "CONFIG_AVX2_OPT=y" >> $config_host_mak
fi
+if test "$cryptodev_linux" = "yes" ; then
+ echo "CONFIG_CRYPTODEV_LINUX=y" >> $config_host_mak
+fi
+
if test "$lzo" = "yes" ; then
echo "CONFIG_LZO=y" >> $config_host_mak
fi
@@ -28,6 +28,7 @@ crypto-obj-y += block-qcow.o
crypto-obj-y += block-luks.o
crypto-obj-y += crypto.o
crypto-obj-y += crypto-queue.o
+crypto-obj-$(CONFIG_CRYPTODEV_LINUX) += cryptodev-linux.o
# Let the userspace emulators avoid linking gnutls/etc
crypto-aes-obj-y = aes.o
@@ -34,6 +34,7 @@
#include "crypto/crypto.h"
#include "qemu/config-file.h"
#include "monitor/monitor.h"
+#include "crypto/crypto-clients.h"
static QTAILQ_HEAD(, CryptoClientState) crypto_clients;
@@ -81,7 +82,12 @@ int crypto_init_clients(void)
static int (* const crypto_client_init_fun[CRYPTO_CLIENT_OPTIONS_KIND__MAX])(
const CryptoClientOptions *opts,
const char *name,
- CryptoClientState *peer, Error **errp);
+ CryptoClientState *peer, Error **errp) = {
+#ifdef CONFIG_CRYPTODEV_LINUX
+ [CRYPTO_CLIENT_OPTIONS_KIND_CRYPTODEV_LINUX] =
+ crypto_init_cryptodev_linux,
+#endif
+};
static int crypto_client_init1(const void *object, Error **errp)
{
new file mode 100644
@@ -0,0 +1,419 @@
+/*
+ * cryptodev-linux backend support
+ *
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ * Gonglei <arei.gonglei@huawei.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or
+ * (at your option) any later version. See the COPYING file in the
+ * top-level directory.
+ */
+
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <crypto/cryptodev.h>
+
+#include "qemu/osdep.h"
+#include "sysemu/sysemu.h"
+#include "qapi/error.h"
+#include "qemu/iov.h"
+#include "qapi-visit.h"
+#include "qapi/opts-visitor.h"
+#include "qemu/error-report.h"
+
+#include "crypto/crypto.h"
+#include "crypto/crypto-clients.h"
+#include "standard-headers/linux/virtio_crypto.h"
+
+
+#define CRYPTO_CHARDEV_PATH "/dev/crypto"
+
+
+typedef struct CryptodevLinuxSession {
+ struct session_op *sess;
+ uint8_t direction; /* encryption or decryption */
+ uint8_t type; /* cipher? hash? aead? */
+ QTAILQ_ENTRY(CryptodevLinuxSession) next;
+} CryptodevLinuxSession;
+
+typedef struct CryptodevLinuxState {
+ CryptoClientState cc;
+ int fd;
+ bool read_poll;
+ bool write_poll;
+ bool enabled;
+ QTAILQ_HEAD(, CryptodevLinuxSession) sessions;
+} CryptodevLinuxState;
+
+static int
+cryptodev_linux_open(int *gfd, Error **errp)
+{
+ int fd = -1;
+
+ /* Open the crypto device */
+ fd = open(CRYPTO_CHARDEV_PATH, O_RDWR, 0);
+ if (fd < 0) {
+ error_setg_errno(errp, errno, "Cannot open %s",
+ CRYPTO_CHARDEV_PATH);
+ return -1;
+ }
+
+ /* Set close-on-exec (not really neede here) */
+ if (fcntl(fd, F_SETFD, 1) == -1) {
+ perror("fcntl(F_SETFD)");
+ error_setg_errno(errp, errno,
+ "Failed to fcntl(F_SETFD) %s",
+ CRYPTO_CHARDEV_PATH);
+ close(fd);
+ return -1;
+ }
+
+ *gfd = fd;
+
+ return 0;
+}
+
+static int
+cryptodev_linux_handle_cipher_sess(CryptodevLinuxState *s,
+ CryptoSymSessionInfo *session_info,
+ struct session_op *sess,
+ uint8_t *direction)
+{
+ switch (session_info->cipher_alg) {
+ case VIRTIO_CRYPTO_CIPHER_AES_CBC:
+ sess->cipher = CRYPTO_AES_CBC;
+ break;
+ default:
+ error_report("Unsupported cipher alg: %u",
+ session_info->cipher_alg);
+ return -1;
+ }
+ /* Get crypto session for assinged algorithm */
+ sess->keylen = session_info->key_len;
+ sess->key = session_info->cipher_key;
+ *direction = session_info->direction;
+ return 0;
+}
+
+static int
+cryptodev_linux_handle_hash_sess(CryptodevLinuxState *s,
+ CryptoSymSessionInfo *session_info,
+ struct session_op *sess)
+{
+ switch (session_info->hash_alg) {
+ case VIRTIO_CRYPTO_HASH_SHA1:
+ sess->mac = CRYPTO_SHA1_HMAC;
+ break;
+ default:
+ error_report("Unsupported hash alg: %u",
+ session_info->hash_alg);
+ return -1;
+ }
+
+ sess->mackeylen = session_info->auth_key_len;
+ sess->mackey = session_info->auth_key;
+ return 0;
+}
+
+static int
+cryptodev_linux_handle_chaining_sess(CryptodevLinuxState *s,
+ CryptoSymSessionInfo *session_info,
+ struct session_op *sess,
+ uint8_t *direction)
+{
+ int ret;
+
+ ret = cryptodev_linux_handle_cipher_sess(s, session_info,
+ sess, direction);
+ if (ret == 0) {
+ ret = cryptodev_linux_handle_hash_sess(s,
+ session_info, sess);
+ }
+ return ret;
+}
+
+static int
+cryptodev_linux_create_session(CryptoClientState *cc,
+ CryptoSymSessionInfo *session_info,
+ uint64_t *session_id)
+{
+ CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+ int fd = s->fd;
+ int ret = -1;
+ CryptodevLinuxSession *session = NULL;
+ uint8_t direction = 0;
+ struct session_op *sess;
+#ifdef CIOCGSESSINFO
+ struct session_info_op siop;
+#endif
+
+ sess = g_new0(struct session_op, 1);
+ /* Setup session Parameters */
+ switch (session_info->op_type) {
+ case VIRTIO_CRYPTO_SYM_OP_CIPHER:
+ ret = cryptodev_linux_handle_cipher_sess(s, session_info,
+ sess, &direction);
+ if (ret < 0) {
+ goto err;
+ }
+ break;
+ case VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING:
+ ret = cryptodev_linux_handle_chaining_sess(s, session_info,
+ sess, &direction);
+ if (ret < 0) {
+ goto err;
+ }
+ break;
+ default:
+ error_report("Unsupported type: %u", session_info->op_type);
+ goto err;
+ }
+
+ if (ioctl(fd, CIOCGSESSION, sess)) {
+ perror("ioctl(CIOCGSESSION)");
+ ret = -1;
+ goto err;
+ }
+
+#ifdef CIOCGSESSINFO
+ siop.ses = sess->ses;
+ if (ioctl(fd, CIOCGSESSINFO, &siop)) {
+ perror("ioctl(CIOCGSESSINFO)");
+ ret = -1;
+ goto err;
+ }
+ printf("got %s with driver %s\n",
+ siop.cipher_info.cra_name, siop.cipher_info.cra_driver_name);
+#endif
+
+ *session_id = sess->ses;
+
+ session = g_new0(CryptodevLinuxSession, 1);
+ session->sess = sess;
+ session->type = session_info->op_type;
+ switch (direction) {
+ case VIRTIO_CRYPTO_OP_ENCRYPT:
+ session->direction = COP_ENCRYPT;
+ break;
+ case VIRTIO_CRYPTO_OP_DECRYPT:
+ session->direction = COP_DECRYPT;
+ break;
+ default:
+ error_report("Unsupported direction: %u", direction);
+ goto err;
+ }
+
+ QTAILQ_INSERT_TAIL(&s->sessions, session, next);
+
+ return 0;
+err:
+ g_free(sess);
+ g_free(session);
+ return ret;
+}
+
+static CryptodevLinuxSession *
+cryptodev_linux_find_session(CryptodevLinuxState *s,
+ uint64_t session_id)
+{
+ CryptodevLinuxSession *session, *tmp;
+
+ QTAILQ_FOREACH_SAFE(session, &s->sessions, next, tmp) {
+ if (session->sess->ses == session_id) {
+ return session;
+ }
+ }
+
+ return NULL;
+}
+
+static int
+cryptodev_linux_close_session(CryptoClientState *cc,
+ uint64_t session_id)
+{
+ CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+ int fd = s->fd;
+ CryptodevLinuxSession *session;
+
+ session = cryptodev_linux_find_session(s, session_id);
+ if (session == NULL) {
+ error_report("Cannot find the session: %" PRIu64 "",
+ session_id);
+ return -1;
+ }
+
+ if (ioctl(fd, CIOCFSESSION, &session_id)) {
+ perror("ioctl(CIOCFSESSION)");
+ return -1;
+ }
+
+ QTAILQ_REMOVE(&s->sessions, session, next);
+ g_free(session->sess);
+ g_free(session);
+ return 0;
+}
+
+static int
+cryptodev_linux_handle_cipher_op(CryptoSymOpInfo *op_info,
+ CryptodevLinuxSession *session,
+ int fd)
+{
+ struct crypt_op cryp;
+
+ cryp.ses = op_info->session_id;
+ cryp.len = op_info->src_len;
+ cryp.src = op_info->src;
+ cryp.dst = op_info->dst;
+ cryp.iv = op_info->iv;
+ cryp.op = session->direction;
+
+ if (ioctl(fd, CIOCCRYPT, &cryp)) {
+ perror("ioctl(CIOCCRYPT)");
+ return -1;
+ }
+
+ return 1;
+}
+
+static int
+cryptodev_linux_handle_chaining_op(CryptoSymOpInfo *op_info,
+ CryptodevLinuxSession *session,
+ int fd)
+{
+ struct crypt_auth_op cao;
+
+ cao.ses = op_info->session_id;
+ cao.len = op_info->src_len;
+ cao.src = op_info->src;
+ cao.dst = op_info->dst;
+ cao.iv = op_info->iv;
+ cao.op = session->direction;
+
+ if (op_info->aad_len > 0) {
+ cao.auth_len = op_info->aad_len;
+ cao.auth_src = op_info->aad_data;
+ }
+
+ /* We only support TLS mode at present, the hash result is
+ stored at the end of cipher text, the frontend driver
+ should allocate enough memory. */
+ cao.flags = COP_FLAG_AEAD_TLS_TYPE;
+
+ if (ioctl(fd, CIOCAUTHCRYPT, &cao)) {
+ perror("ioctl(CIOCCRYPT)");
+ return -1;
+ }
+
+ return 1;
+}
+
+
+static int
+cryptodev_linux_do_sym_op(CryptoClientState *cc,
+ CryptoSymOpInfo *op_info)
+{
+ CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+ CryptodevLinuxSession *session;
+
+ session = cryptodev_linux_find_session(s, op_info->session_id);
+ if (session == NULL) {
+ error_report("Cannot find the session: %" PRIu64 "",
+ op_info->session_id);
+ return -VIRTIO_CRYPTO_OP_INVSESS;
+ }
+
+ switch (session->type) {
+ case VIRTIO_CRYPTO_SYM_OP_CIPHER:
+ return cryptodev_linux_handle_cipher_op(op_info, session, s->fd);
+ case VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING:
+ return cryptodev_linux_handle_chaining_op(op_info, session, s->fd);
+ default:
+ error_report("Unsupported type: %u", session->type);
+ return -1;
+ }
+}
+
+static void
+cryptodev_linux_cleanup(CryptoClientState *cc)
+{
+ CryptodevLinuxState *s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+ CryptodevLinuxSession *session;
+ uint64_t session_id;
+
+ QTAILQ_FOREACH(session, &s->sessions, next) {
+ session_id = session->sess->ses;
+ if (ioctl(s->fd, CIOCFSESSION, &session_id)) {
+ perror("ioctl(CIOCFSESSION)");
+ }
+ g_free(session->sess);
+ g_free(session);
+ }
+
+ close(s->fd);
+ s->fd = -1;
+ s->enabled = false;
+}
+
+static void
+cryptodev_linux_poll(CryptoClientState *cc, bool enable)
+{
+
+}
+
+static CryptoClientInfo crypto_cryptodev_info = {
+ .type = CRYPTO_CLIENT_OPTIONS_KIND_CRYPTODEV_LINUX,
+ .size = sizeof(CryptodevLinuxState),
+ .create_session = cryptodev_linux_create_session,
+ .close_session = cryptodev_linux_close_session,
+ .do_sym_op = cryptodev_linux_do_sym_op,
+ .cleanup = cryptodev_linux_cleanup,
+ .poll = cryptodev_linux_poll,
+};
+
+int crypto_init_cryptodev_linux(const CryptoClientOptions *opts,
+ const char *name,
+ CryptoClientState *peer, Error **errp)
+{
+ const CryptodevLinuxOptions *cryptodev;
+ int fd, ret;
+ CryptoClientState *cc;
+ CryptodevLinuxState *s;
+
+ assert(opts->type == CRYPTO_CLIENT_OPTIONS_KIND_CRYPTODEV_LINUX);
+
+ cryptodev = opts->u.cryptodev_linux.data;
+ if (cryptodev->has_fd) {
+ if (cryptodev->fd < 0) {
+ error_setg(errp, "Invaild fd: %" PRId64 "", cryptodev->fd);
+ return -1;
+ } else {
+ fd = cryptodev->fd;
+ }
+ } else {
+ ret = cryptodev_linux_open(&fd, errp);
+ if (ret < 0) {
+ return -1;
+ }
+ }
+
+ cc = new_crypto_client(&crypto_cryptodev_info, peer,
+ "cryptodev-linux", name);
+
+ cc->crypto_services = 1u << VIRTIO_CRYPTO_SERVICE_CIPHER |
+ 1u << VIRTIO_CRYPTO_SERVICE_HASH |
+ 1u << VIRTIO_CRYPTO_SERVICE_AEAD;
+ cc->cipher_algo_l = 1u << VIRTIO_CRYPTO_CIPHER_AES_CBC;
+ cc->hash_algo = 1u << VIRTIO_CRYPTO_HASH_SHA1;
+
+ /* the cryptodev backend is ready for work */
+ cc->ready = true;
+ s = DO_UPCAST(CryptodevLinuxState, cc, cc);
+
+ s->fd = fd;
+ s->enabled = true;
+ QTAILQ_INIT(&s->sessions);
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,39 @@
+/*
+ * Crypto clients header
+ *
+ * Copyright (c) 2016 HUAWEI TECHNOLOGIES CO., LTD.
+ *
+ * Authors:
+ * Gonglei <arei.gonglei@huawei.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#ifndef QEMU_CRYPTO_CLIENTS_H
+#define QEMU_CRYPTO_CLIENTS_H
+
+#include "crypto/crypto.h"
+#include "qapi-types.h"
+
+#ifdef CONFIG_CRYPTODEV_LINUX
+int crypto_init_cryptodev_linux(const CryptoClientOptions *opts,
+ const char *name,
+ CryptoClientState *peer, Error **errp);
+#endif
+
+#endif /* QEMU_CRYPTO_CLIENTS_H */
new file mode 100644
@@ -0,0 +1,448 @@
+#ifndef _VIRTIO_CRYPTO_H
+#define _VIRTIO_CRYPTO_H
+
+#include "standard-headers/linux/types.h"
+#include "standard-headers/linux/virtio_config.h"
+#include "standard-headers/linux/virtio_types.h"
+
+
+#define VIRTIO_CRYPTO_SERVICE_CIPHER (0)
+#define VIRTIO_CRYPTO_SERVICE_HASH (1)
+#define VIRTIO_CRYPTO_SERVICE_MAC (2)
+#define VIRTIO_CRYPTO_SERVICE_AEAD (3)
+
+#define VIRTIO_CRYPTO_OPCODE(service, op) ((service << 8) | (op))
+
+struct virtio_crypto_ctrl_header{
+#define VIRTIO_CRYPTO_CIPHER_CREATE_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x02)
+#define VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x03)
+#define VIRTIO_CRYPTO_HASH_CREATE_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x02)
+#define VIRTIO_CRYPTO_HASH_DESTROY_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x03)
+#define VIRTIO_CRYPTO_MAC_CREATE_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x02)
+#define VIRTIO_CRYPTO_MAC_DESTROY_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x03)
+#define VIRTIO_CRYPTO_AEAD_CREATE_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x02)
+#define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x03)
+ __virtio32 opcode;
+ __virtio32 algo;
+ __virtio32 flag;
+ /* data virtqueue id */
+ __virtio32 queue_id;
+};
+
+struct virtio_crypto_cipher_session_para {
+#define VIRTIO_CRYPTO_NO_CIPHER 0
+#define VIRTIO_CRYPTO_CIPHER_ARC4 1
+#define VIRTIO_CRYPTO_CIPHER_AES_ECB 2
+#define VIRTIO_CRYPTO_CIPHER_AES_CBC 3
+#define VIRTIO_CRYPTO_CIPHER_AES_CTR 4
+#define VIRTIO_CRYPTO_CIPHER_DES_ECB 5
+#define VIRTIO_CRYPTO_CIPHER_DES_CBC 6
+#define VIRTIO_CRYPTO_CIPHER_3DES_ECB 7
+#define VIRTIO_CRYPTO_CIPHER_3DES_CBC 8
+#define VIRTIO_CRYPTO_CIPHER_3DES_CTR 9
+#define VIRTIO_CRYPTO_CIPHER_KASUMI_F8 10
+#define VIRTIO_CRYPTO_CIPHER_SNOW3G_UEA2 11
+#define VIRTIO_CRYPTO_CIPHER_AES_F8 12
+#define VIRTIO_CRYPTO_CIPHER_AES_XTS 13
+#define VIRTIO_CRYPTO_CIPHER_ZUC_EEA3 14
+ __virtio32 algo;
+ /* length of key */
+ __virtio32 keylen;
+
+#define VIRTIO_CRYPTO_OP_ENCRYPT 1
+#define VIRTIO_CRYPTO_OP_DECRYPT 2
+ /* encrypt or decrypt */
+ __virtio32 op;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_session_input {
+ // Device-writable part
+ __virtio64 session_id;
+ __virtio32 status;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_cipher_session_output {
+ __virtio64 key_addr; /* guest key phycial address */
+};
+
+struct virtio_crypto_cipher_session_req {
+ struct virtio_crypto_cipher_session_para para;
+ struct virtio_crypto_cipher_session_output out;
+ struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_hash_session_para {
+#define VIRTIO_CRYPTO_NO_HASH 0
+#define VIRTIO_CRYPTO_HASH_MD5 1
+#define VIRTIO_CRYPTO_HASH_SHA1 2
+#define VIRTIO_CRYPTO_HASH_SHA_224 3
+#define VIRTIO_CRYPTO_HASH_SHA_256 4
+#define VIRTIO_CRYPTO_HASH_SHA_384 5
+#define VIRTIO_CRYPTO_HASH_SHA_512 6
+#define VIRTIO_CRYPTO_HASH_SHA3_224 7
+#define VIRTIO_CRYPTO_HASH_SHA3_256 8
+#define VIRTIO_CRYPTO_HASH_SHA3_384 9
+#define VIRTIO_CRYPTO_HASH_SHA3_512 10
+#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE128 11
+#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE256 12
+ __virtio32 algo;
+ /* hash result length */
+ __virtio32 hash_result_len;
+};
+
+struct virtio_crypto_hash_create_session_req {
+ struct virtio_crypto_hash_session_para para;
+ struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_mac_session_para {
+#define VIRTIO_CRYPTO_NO_MAC 0
+#define VIRTIO_CRYPTO_MAC_HMAC_MD5 1
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA1 2
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_224 3
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_256 4
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_384 5
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_512 6
+#define VIRTIO_CRYPTO_MAC_CMAC_3DES 25
+#define VIRTIO_CRYPTO_MAC_CMAC_AES 26
+#define VIRTIO_CRYPTO_MAC_KASUMI_F9 27
+#define VIRTIO_CRYPTO_MAC_SNOW3G_UIA2 28
+#define VIRTIO_CRYPTO_MAC_GMAC_AES 41
+#define VIRTIO_CRYPTO_MAC_GMAC_TWOFISH 42
+#define VIRTIO_CRYPTO_MAC_CBCMAC_AES 49
+#define VIRTIO_CRYPTO_MAC_CBCMAC_KASUMI_F9 50
+#define VIRTIO_CRYPTO_MAC_XCBC_AES 53
+ __virtio32 algo;
+ /* hash result length */
+ __virtio32 hash_result_len;
+ /* length of authenticated key */
+ __virtio32 auth_key_len;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_mac_session_output {
+ __virtio64 auth_key_addr; /* guest key phyical address */
+};
+
+struct virtio_crypto_mac_create_session_req {
+ struct virtio_crypto_mac_session_para para;
+ struct virtio_crypto_mac_session_output out;
+ struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_aead_session_para {
+#define VIRTIO_CRYPTO_NO_AEAD 0
+#define VIRTIO_CRYPTO_AEAD_GCM 1
+#define VIRTIO_CRYPTO_AEAD_CCM 2
+#define VIRTIO_CRYPTO_AEAD_CHACHA20_POLY1305 3
+ __virtio32 algo;
+ /* length of key */
+ __virtio32 key_len;
+ /* digest result length */
+ __virtio32 digest_result_len;
+ /* length of the additional authenticated data (AAD) in bytes */
+ __virtio32 aad_len;
+ /* encrypt or decrypt, See above VIRTIO_CRYPTO_OP_* */
+ __virtio32 op;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_aead_session_output {
+ __virtio64 key_addr; /* guest key phycial address */
+};
+
+struct virtio_crypto_aead_create_session_req {
+ struct virtio_crypto_aead_session_para para;
+ struct virtio_crypto_aead_session_output out;
+ struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_alg_chain_session_para {
+#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER 1
+#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH 2
+ __virtio32 alg_chain_order;
+/* Plain hash */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN 1
+/* Authenticated hash (mac) */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH 2
+/* Nested hash */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED 3
+ __virtio32 hash_mode;
+ struct virtio_crypto_cipher_session_para cipher_param;
+ union {
+ struct virtio_crypto_hash_session_para hash_param;
+ struct virtio_crypto_mac_session_para mac_param;
+ } u;
+ /* length of the additional authenticated data (AAD) in bytes */
+ __virtio32 aad_len;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_alg_chain_session_output {
+ struct virtio_crypto_cipher_session_output cipher;
+ struct virtio_crypto_mac_session_output mac;
+};
+
+struct virtio_crypto_alg_chain_session_req {
+ struct virtio_crypto_alg_chain_session_para para;
+ struct virtio_crypto_alg_chain_session_output out;
+ struct virtio_crypto_session_input input;
+};
+
+struct virtio_crypto_sym_create_session_req {
+ union {
+ struct virtio_crypto_cipher_session_req cipher;
+ struct virtio_crypto_alg_chain_session_req chain;
+ } u;
+
+ // Device-readable part
+
+/* No operation */
+#define VIRTIO_CRYPTO_SYM_OP_NONE 0
+/* Cipher only operation on the data */
+#define VIRTIO_CRYPTO_SYM_OP_CIPHER 1
+/* Chain any cipher with any hash or mac operation. The order
+ depends on the value of alg_chain_order param */
+#define VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING 2
+ __virtio32 op_type;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_destroy_session_req {
+ // Device-readable part
+ __virtio64 session_id;
+ // Device-writable part
+ __virtio32 status;
+ __virtio32 padding;
+};
+
+/* The request of the control viritqueue's packet */
+struct virtio_crypto_op_ctrl_req {
+ struct virtio_crypto_ctrl_header header;
+
+ union {
+ struct virtio_crypto_sym_create_session_req sym_create_session;
+ struct virtio_crypto_hash_create_session_req hash_create_session;
+ struct virtio_crypto_mac_create_session_req mac_create_session;
+ struct virtio_crypto_aead_create_session_req aead_create_session;
+ struct virtio_crypto_destroy_session_req destroy_session;
+ } u;
+};
+
+struct virtio_crypto_op_header {
+#define VIRTIO_CRYPTO_CIPHER_ENCRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x00)
+#define VIRTIO_CRYPTO_CIPHER_DECRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x01)
+#define VIRTIO_CRYPTO_HASH \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x00)
+#define VIRTIO_CRYPTO_MAC \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x00)
+#define VIRTIO_CRYPTO_AEAD_ENCRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x00)
+#define VIRTIO_CRYPTO_AEAD_DECRYPT \
+ VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x01)
+ __virtio32 opcode;
+ /* algo should be service-specific algorithms */
+ __virtio32 algo;
+ /* session_id should be service-specific algorithms */
+ __virtio64 session_id;
+ /* control flag to control the request */
+ __virtio32 flag;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_sym_input {
+ /* destination data guest address, it's useless for plain HASH and MAC */
+ __virtio64 dst_data_addr;
+ /* digest result guest address, it's useless for plain cipher algos */
+ __virtio64 digest_result_addr;
+
+ __virtio32 status;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_cipher_para {
+ __virtio32 iv_len;
+ /* length of source data */
+ __virtio32 src_data_len;
+ /* length of dst data */
+ __virtio32 dst_data_len;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_cipher_input {
+ struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_cipher_output {
+ __virtio64 iv_addr; /* iv guest address */
+ __virtio64 src_data_addr; /* source data guest address */
+};
+
+struct virtio_crypto_hash_input {
+ struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_hash_output {
+ /* source data guest address */
+ __virtio64 src_data_addr;
+ /* length of source data */
+ __virtio32 src_data_len;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_mac_input {
+ struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_mac_output {
+ struct virtio_crypto_hash_output hash_output;
+};
+
+struct virtio_crypto_aead_para {
+ __virtio32 iv_len;
+ /* length of additional auth data */
+ __virtio32 aad_len;
+ /* length of source data */
+ __virtio32 src_data_len;
+ /* length of dst data */
+ __virtio32 dst_data_len;
+};
+
+struct virtio_crypto_aead_input {
+ struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_aead_output {
+ __virtio64 iv_addr; /* iv guest address */
+ __virtio64 src_data_addr; /* source data guest address */
+ __virtio64 add_data_addr; /* additional auth data guest address */
+};
+
+struct virtio_crypto_cipher_data_req {
+ // Device-readable part
+ struct virtio_crypto_cipher_para para;
+ struct virtio_crypto_cipher_output odata;
+ // Device-writable part
+ struct virtio_crypto_cipher_input idata;
+};
+
+struct virtio_crypto_hash_data_req {
+ // Device-readable part
+ struct virtio_crypto_hash_output odata;
+ // Device-writable part
+ struct virtio_crypto_hash_input idata;
+};
+
+struct virtio_crypto_mac_data_req {
+ // Device-readable part
+ struct virtio_crypto_mac_output odata;
+ // Device-writable part
+ struct virtio_crypto_mac_input idata;
+};
+
+struct virtio_crypto_alg_chain_data_para {
+ struct virtio_crypto_cipher_para cipher;
+};
+
+struct virtio_crypto_alg_chain_data_output {
+ struct virtio_crypto_cipher_output cipher;
+
+ // Device-readable part
+ __virtio64 aad_data_addr; /* additional auth data guest address */
+ __virtio32 aad_len; /* length of additional auth data */
+ __virtio32 padding;
+};
+
+struct virtio_crypto_alg_chain_data_input {
+ struct virtio_crypto_sym_input input;
+};
+
+struct virtio_crypto_alg_chain_data_req {
+ // Device-readable part
+ struct virtio_crypto_alg_chain_data_para para;
+ struct virtio_crypto_alg_chain_data_output odata;
+ // Device-writable part
+ struct virtio_crypto_alg_chain_data_input idata;
+};
+
+struct virtio_crypto_sym_data_req {
+ union {
+ struct virtio_crypto_cipher_data_req cipher;
+ struct virtio_crypto_alg_chain_data_req chain;
+ } u;
+
+ // Device-readable part
+
+ /* See above VIRTIO_CRYPTO_SYM_OP_* */
+ __virtio32 op_type;
+ __virtio32 padding;
+};
+
+struct virtio_crypto_aead_data_req {
+ // Device-readable part
+ struct virtio_crypto_aead_para para;
+ struct virtio_crypto_aead_output odata;
+ // Device-writable part
+ struct virtio_crypto_aead_input idata;
+};
+
+/* The request of the data viritqueue's packet */
+struct virtio_crypto_op_data_req {
+ struct virtio_crypto_op_header header;
+
+ union {
+ struct virtio_crypto_sym_data_req sym_req;
+ struct virtio_crypto_hash_data_req hash_req;
+ struct virtio_crypto_mac_data_req mac_req;
+ struct virtio_crypto_aead_data_req aead_req;
+ } u;
+};
+
+#define VIRTIO_CRYPTO_OP_OK 0
+#define VIRTIO_CRYPTO_OP_ERR 1
+#define VIRTIO_CRYPTO_OP_BADMSG 2
+#define VIRTIO_CRYPTO_OP_NOTSUPP 3
+#define VIRTIO_CRYPTO_OP_INVSESS 4 /* Invaild session id */
+
+/* The accelerator hardware is ready */
+#define VIRTIO_CRYPTO_S_HW_READY (1 << 0)
+#define VIRTIO_CRYPTO_S_STARTED (1 << 1)
+
+struct virtio_crypto_config {
+ /* See VIRTIO_CRYPTO_OP_* above */
+ __virtio32 status;
+
+ /*
+ * Maximum number of data queue legal values are between 1 and 0x8000
+ */
+ __virtio32 max_dataqueues;
+
+ /* Specifies the services mask which the devcie support,
+ see VIRTIO_CRYPTO_SERVICE_* above */
+ __virtio32 crypto_services;
+
+ /* Detailed algorithms mask */
+ __virtio32 cipher_algo_l;
+ __virtio32 cipher_algo_h;
+ __virtio32 hash_algo;
+ __virtio32 mac_algo_l;
+ __virtio32 mac_algo_h;
+ __virtio32 asym_algo;
+ __virtio32 kdf_algo;
+ __virtio32 aead_algo;
+ __virtio32 primitive_algo;
+};
+
+#endif
@@ -4603,6 +4603,20 @@
'*vectors': 'uint32' } }
##
+# @CryptodevLinuxOptions
+#
+# Cryptodev-linux cryptodev backend. Cryptodev-linux is a device that
+# allows access to Linux kernel cryptographic drivers; thus allowing
+# of userspace applications to take advantage of hardware accelerators.
+#
+# @fd: #optional file descriptor of an already opened cryptodev chardev
+#
+# Since 2.7
+##
+{ 'struct': 'CryptodevLinuxOptions',
+ 'data': {
+ '*fd': 'int' } }
+##
# @CryptoClientOptions
#
# A discriminated record of crypto device traits.
@@ -4611,7 +4625,8 @@
#
##
{ 'union': 'CryptoClientOptions',
- 'data': {'legacy-hw': 'CryptoLegacyHWOptions'} }
+ 'data': {'legacy-hw': 'CryptoLegacyHWOptions',
+ 'cryptodev-linux': 'CryptodevLinuxOptions'} }
##
# @Cryptodev
@@ -3969,9 +3969,25 @@ contents of @code{iv.b64} to the second secret
ETEXI
DEF("cryptodev", HAS_ARG, QEMU_OPTION_cryptodev,
- "",
+ "-cryptodev cryptodev-linux,id=str[,fd=h]\n"
+ " configure a cryptodev-linux cryptodev backend with ID 'str'\n"
+ " use 'fd=h' to connect to an already opened '/dev/crypto' fd\n",
QEMU_ARCH_ALL)
+STEXI
+@item -cryptodev cryptodev-linux,id=@var{id}[,fd=@var{h}]
+configure a cryptodev backend with ID @var{id}.
+
+Example:
+@example
+#launch a QEMU instance with one virtio-crypto device,
+#which connected a cryptodev-linux backend device.
+qemu-system-x86_64 linux.img -cryptodev cryptodev-linux,id=cryptodev0 \
+ -device virtio-crypto-pci,cryptodev=cryptodev0
+
+@end example
+ETEXI
+
HXCOMM This is the last statement. Insert new options before this line!
STEXI
@end table
Cryptodev-linux is a device that allows access to Linux kernel cryptographic drivers; thus allowing of userspace applications to take advantage of hardware accelerators. Cryptodev-linux is implemented as a standalone module that requires no dependencies other than a stock linux kernel. The Cryptodev-linux project website is: http://cryptodev-linux.org/ Meanwile, I introdue the virtio_crypto.h which follows virtio-crypto specification bacause cryptodev-linux.c include it. Signed-off-by: Gonglei <arei.gonglei@huawei.com> --- configure | 16 + crypto/Makefile.objs | 1 + crypto/crypto.c | 8 +- crypto/cryptodev-linux.c | 419 +++++++++++++++++++++++ include/crypto/crypto-clients.h | 39 +++ include/standard-headers/linux/virtio_crypto.h | 448 +++++++++++++++++++++++++ qapi-schema.json | 17 +- qemu-options.hx | 18 +- 8 files changed, 963 insertions(+), 3 deletions(-) create mode 100644 crypto/cryptodev-linux.c create mode 100644 include/crypto/crypto-clients.h create mode 100644 include/standard-headers/linux/virtio_crypto.h