From: Hyman Huang <yong.huang@smartx.com>
To: qemu-devel@nongnu.org
Cc: "Daniel P . Berrangé" <berrange@redhat.com>,
"Paolo Bonzini" <pbonzini@redhat.com>,
"Marc-André Lureau" <marcandre.lureau@redhat.com>,
"Thomas Huth" <thuth@redhat.com>,
"Philippe Mathieu-Daudé" <philmd@linaro.org>,
yong.huang@smartx.com
Subject: [PATCH RFC 1/3] crypto: Introduce GM/T 0018-2012 cryptographic driver
Date: Sat, 24 Feb 2024 22:34:56 +0800 [thread overview]
Message-ID: <cf63cff38e5346a3b36e7dd8874a1775ed965683.1708527979.git.yong.huang@smartx.com> (raw)
In-Reply-To: <cover.1708527979.git.yong.huang@smartx.com>
GM/T 0018-2012 is a cryptographic standard issued by the State
Cryptography Administration of China. For more information about
the standard, visit https://hbba.sacinfo.org.cn.
The objective of the standard is to develop a uniform application
interface standard for the service-based cryptography device under
the public key cryptographic infrastructure application framework,
and to call the cryptography device through this interface to
provide basic cryptographic services for the uppler layer. For
more information about contents of the standard, download the
specificaiton from:
"https://github.com/guanzhi/GM-Standards/blob/master/GMT密码行标/
GMT%200018-2012%20密码设备应用接口规范.pdf"
This patch implement the basic functions of GM/T 0018-2012
standard. Currently, for block encryption, it support SM4 cipher
algorithm only.
Signed-off-by: Hyman Huang <yong.huang@smartx.com>
---
MAINTAINERS | 3 +-
crypto/cipher-gmt.c | 263 ++++++++++++++++++++++++++++++++++++++++++++
crypto/cipher.c | 2 +
crypto/cipherpriv.h | 6 +
4 files changed, 273 insertions(+), 1 deletion(-)
create mode 100644 crypto/cipher-gmt.c
diff --git a/MAINTAINERS b/MAINTAINERS
index a24c2b51b6..822726e9da 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -3418,10 +3418,11 @@ F: migration/dirtyrate.c
F: migration/dirtyrate.h
F: include/sysemu/dirtyrate.h
-Detached LUKS header
+Detached LUKS header and GM/T 0018-2012 cryptography
M: Hyman Huang <yong.huang@smartx.com>
S: Maintained
F: tests/qemu-iotests/tests/luks-detached-header
+F: crypto/cipher-gmt.c
D-Bus
M: Marc-André Lureau <marcandre.lureau@redhat.com>
diff --git a/crypto/cipher-gmt.c b/crypto/cipher-gmt.c
new file mode 100644
index 0000000000..40e32c114f
--- /dev/null
+++ b/crypto/cipher-gmt.c
@@ -0,0 +1,263 @@
+/*
+ * QEMU GM/T 0018-2012 cryptographic standard support
+ *
+ * Copyright (c) 2024 SmartX Inc
+ *
+ * Authors:
+ * Hyman Huang <yong.huang@smartx.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 <gmt-0018-2012.h>
+
+#include "qemu/osdep.h"
+#include "qemu/thread.h"
+#include "qapi/error.h"
+#include "crypto/cipher.h"
+#include "cipherpriv.h"
+
+#include "qemu/error-report.h"
+
+typedef struct QCryptoGMT QCryptoGMT;
+
+struct QCryptoGMT {
+ QCryptoCipher base;
+
+ SGD_HANDLE session;
+ SGD_HANDLE key;
+ SGD_UINT32 alg;
+ unsigned char iv[16]; /* not used for SM4 algo currently */
+};
+
+typedef struct QCryptoGMTDeviceInfo QCryptoGMTDeviceInfo;
+
+struct QCryptoGMTDeviceInfo {
+ SGD_HANDLE device;
+ struct DeviceInfo_st info;
+ bool opened;
+ gint ref_count;
+};
+/*
+ * It is advised to use numerous sessions with one open device
+ * as opposed to single sessions with several devices.
+ */
+static QCryptoGMTDeviceInfo gmt_device;
+/* Protect the gmt_device */
+static QemuMutex gmt_device_mutex;
+
+static const struct QCryptoCipherDriver qcrypto_cipher_gmt_driver;
+
+static void gmt_device_lock(void)
+{
+ qemu_mutex_lock(&gmt_device_mutex);
+}
+
+static void gmt_device_unlock(void)
+{
+ qemu_mutex_unlock(&gmt_device_mutex);
+}
+
+static void
+__attribute__((__constructor__)) gmt_device_mutex_init(void)
+{
+ qemu_mutex_init(&gmt_device_mutex);
+}
+
+static void
+gmt_device_ref(void)
+{
+ g_assert(gmt_device.device != NULL);
+ g_atomic_int_inc(&gmt_device.ref_count);
+}
+
+static void
+gmt_device_unref(void)
+{
+ g_assert(gmt_device.device != NULL);
+ if (g_atomic_int_dec_and_test(&gmt_device.ref_count)) {
+ SDF_CloseDevice(gmt_device.device);
+ gmt_device.opened = false;
+ gmt_device.device = NULL;
+ memset(&gmt_device.info, 0, sizeof(struct DeviceInfo_st));
+ }
+}
+
+static bool
+qcrypto_gmt_cipher_supports(QCryptoCipherAlgorithm alg,
+ QCryptoCipherMode mode)
+{
+ switch (alg) {
+ case QCRYPTO_CIPHER_ALG_SM4:
+ break;
+ default:
+ return false;
+ }
+
+ switch (mode) {
+ case QCRYPTO_CIPHER_MODE_ECB:
+ return true;
+ default:
+ return false;
+ }
+}
+
+QCryptoCipher *
+qcrypto_gmt_cipher_ctx_new(QCryptoCipherAlgorithm alg,
+ QCryptoCipherMode mode,
+ const uint8_t *key,
+ size_t nkey,
+ Error **errp)
+{
+ QCryptoGMT *gmt;
+ int rv;
+
+ if (!qcrypto_gmt_cipher_supports(alg, mode)) {
+ return NULL;
+ }
+
+ gmt = g_new0(QCryptoGMT, 1);
+ if (!gmt) {
+ return NULL;
+ }
+
+ switch (alg) {
+ case QCRYPTO_CIPHER_ALG_SM4:
+ gmt->alg = SGD_SM4_ECB;
+ break;
+ default:
+ return NULL;
+ }
+
+ gmt_device_lock();
+ if (!gmt_device.opened) {
+ rv = SDF_OpenDevice(&gmt_device.device);
+ if (rv != SDR_OK) {
+ info_report("Could not open encryption card device, disabling");
+ goto abort;
+ }
+ gmt_device.opened = true;
+ }
+
+ /*
+ * multi-sessions correspond to an opened device handle
+ */
+ rv = SDF_OpenSession(gmt_device.device, &gmt->session);
+ if (rv != SDR_OK) {
+ error_setg(errp, "Open session failed");
+ goto abort;
+ }
+
+ gmt_device_ref();
+
+ if (!(gmt_device.info.SymAlgAbility)) {
+ rv = SDF_GetDeviceInfo(gmt->session, &gmt_device.info);
+ if (rv != SDR_OK) {
+ error_setg(errp, "Get device info failed");
+ goto abort;
+ }
+ }
+ gmt_device_unlock();
+
+ if (!(gmt_device.info.SymAlgAbility & SGD_SM4_ECB & SGD_SYMM_ALG_MASK)) {
+ /* encryption card do not support SM4 cipher algorithm */
+ info_report("SM4 cipher algorithm is not supported, disabling");
+ return NULL;
+ }
+
+ rv = SDF_ImportKey(gmt->session, (SGD_UCHAR *)key,
+ (SGD_UINT32)nkey, &gmt->key);
+ if (rv != SDR_OK) {
+ error_setg(errp, "Import key failed");
+ return NULL;
+ }
+
+ gmt->base.alg = alg;
+ gmt->base.mode = mode;
+ gmt->base.driver = &qcrypto_cipher_gmt_driver;
+ return &gmt->base;
+
+abort:
+ gmt_device_unlock();
+ return NULL;
+}
+
+static int
+qcrypto_gmt_cipher_setiv(QCryptoCipher *cipher,
+ const uint8_t *iv,
+ size_t niv, Error **errp)
+{
+ error_setg(errp, "Setting IV is not supported");
+ return -1;
+}
+
+static int
+qcrypto_gmt_cipher_op(QCryptoGMT *gmt,
+ const void *in, void *out,
+ size_t len, bool do_encrypt,
+ Error **errp)
+{
+ unsigned int rlen;
+ int rv;
+
+ if (do_encrypt) {
+ rv = SDF_Encrypt(gmt->session, gmt->key, gmt->alg, gmt->iv,
+ (SGD_UCHAR *)in, len, out, &rlen);
+ } else {
+ rv = SDF_Decrypt(gmt->session, gmt->key, gmt->alg, gmt->iv,
+ (SGD_UCHAR *)in, len, out, &rlen);
+ }
+
+ if (rv != SDR_OK) {
+ error_setg(errp, "Crypto operation failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+qcrypto_gmt_free(QCryptoGMT *gmt)
+{
+ g_assert(gmt != NULL);
+
+ SDF_DestroyKey(gmt->session, gmt->key);
+ SDF_CloseSession(gmt->session);
+
+ gmt_device_lock();
+ gmt_device_unref();
+ gmt_device_unlock();
+}
+
+static int
+qcrypto_gmt_cipher_encrypt(QCryptoCipher *cipher,
+ const void *in, void *out,
+ size_t len, Error **errp)
+{
+ QCryptoGMT *gmt = container_of(cipher, QCryptoGMT, base);
+ return qcrypto_gmt_cipher_op(gmt, in, out, len, true, errp);
+}
+
+static int
+qcrypto_gmt_cipher_decrypt(QCryptoCipher *cipher,
+ const void *in, void *out,
+ size_t len, Error **errp)
+{
+ QCryptoGMT *gmt = container_of(cipher, QCryptoGMT, base);
+ return qcrypto_gmt_cipher_op(gmt, in, out, len, false, errp);
+}
+
+static void qcrypto_gmt_comm_ctx_free(QCryptoCipher *cipher)
+{
+ QCryptoGMT *gmt = container_of(cipher, QCryptoGMT, base);
+ qcrypto_gmt_free(gmt);
+ g_free(gmt);
+}
+
+static const struct QCryptoCipherDriver qcrypto_cipher_gmt_driver = {
+ .cipher_encrypt = qcrypto_gmt_cipher_encrypt,
+ .cipher_decrypt = qcrypto_gmt_cipher_decrypt,
+ .cipher_setiv = qcrypto_gmt_cipher_setiv,
+ .cipher_free = qcrypto_gmt_comm_ctx_free,
+};
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 5f512768ea..785f231948 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -157,6 +157,8 @@ QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
#ifdef CONFIG_AF_ALG
cipher = qcrypto_afalg_cipher_ctx_new(alg, mode, key, nkey, NULL);
+#elif defined CONFIG_GMT_0018_2012
+ cipher = qcrypto_gmt_cipher_ctx_new(alg, mode, key, nkey, NULL);
#endif
if (!cipher) {
diff --git a/crypto/cipherpriv.h b/crypto/cipherpriv.h
index 396527857d..b8e542134c 100644
--- a/crypto/cipherpriv.h
+++ b/crypto/cipherpriv.h
@@ -46,7 +46,13 @@ qcrypto_afalg_cipher_ctx_new(QCryptoCipherAlgorithm alg,
QCryptoCipherMode mode,
const uint8_t *key,
size_t nkey, Error **errp);
+#elif defined CONFIG_GMT_0018_2012
+extern QCryptoCipher *
+qcrypto_gmt_cipher_ctx_new(QCryptoCipherAlgorithm alg,
+ QCryptoCipherMode mode,
+ const uint8_t *key,
+ size_t nkey, Error **errp);
#endif
#endif
--
2.39.3
next prev parent reply other threads:[~2024-02-24 14:38 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-02-24 14:34 [PATCH RFC 0/3] Support GM/T 0018-2012 cryptographic standard Hyman Huang
2024-02-24 14:34 ` Hyman Huang [this message]
2024-02-24 14:34 ` [PATCH RFC 2/3] meson.build: " Hyman Huang
2024-02-24 14:34 ` [PATCH RFC 3/3] crypto: Allow GM/T 0018-2012 to support SM4 cipher algorithm Hyman Huang
2024-02-29 9:03 ` [PATCH RFC 0/3] Support GM/T 0018-2012 cryptographic standard Daniel P. Berrangé
2024-02-29 10:13 ` Yong Huang
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=cf63cff38e5346a3b36e7dd8874a1775ed965683.1708527979.git.yong.huang@smartx.com \
--to=yong.huang@smartx.com \
--cc=berrange@redhat.com \
--cc=marcandre.lureau@redhat.com \
--cc=pbonzini@redhat.com \
--cc=philmd@linaro.org \
--cc=qemu-devel@nongnu.org \
--cc=thuth@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).