diff mbox series

crypto: Introduce SM4 symmetric cipher algorithm

Message ID 386ee33ff8f1dc4e8416b037e548ae36c983d054.1701100272.git.yong.huang@smartx.com (mailing list archive)
State New, archived
Headers show
Series crypto: Introduce SM4 symmetric cipher algorithm | expand

Commit Message

Yong Huang Nov. 27, 2023, 3:55 p.m. UTC
Introduce the SM4 cipher algorithms (OSCCA GB/T 32907-2016).

SM4 (GBT.32907-2016) is a cryptographic standard issued by the
Organization of State Commercial Administration of China (OSCCA)
as an authorized cryptographic algorithms for the use within China.

Signed-off-by: Hyman Huang <yong.huang@smartx.com>
---
 crypto/block-luks.c             |  7 ++++++
 crypto/cipher-gcrypt.c.inc      |  4 ++++
 crypto/cipher-nettle.c.inc      | 42 +++++++++++++++++++++++++++++++++
 crypto/cipher.c                 |  2 ++
 qapi/crypto.json                |  5 +++-
 tests/unit/test-crypto-cipher.c | 11 +++++++++
 6 files changed, 70 insertions(+), 1 deletion(-)

Comments

Daniel P. Berrangé Nov. 27, 2023, 4:11 p.m. UTC | #1
On Mon, Nov 27, 2023 at 11:55:34PM +0800, Hyman Huang wrote:
> Introduce the SM4 cipher algorithms (OSCCA GB/T 32907-2016).
> 
> SM4 (GBT.32907-2016) is a cryptographic standard issued by the
> Organization of State Commercial Administration of China (OSCCA)
> as an authorized cryptographic algorithms for the use within China.

Just out of interest, what part of QEMU are you needing to use
SM4 with ? Is it for a LUKS block driver cipher ?

> 
> Signed-off-by: Hyman Huang <yong.huang@smartx.com>
> ---
>  crypto/block-luks.c             |  7 ++++++
>  crypto/cipher-gcrypt.c.inc      |  4 ++++

Looking at the gcrypt code, SM4 is only supported in >= 1.9.0 

QEMU min version is 1.8.0, so you'll need to modify meson.build
to check whether SM4 is supported and put conditionals in this
file

>  crypto/cipher-nettle.c.inc      | 42 +++++++++++++++++++++++++++++++++

Looking at the nettle code, SM4 is only supported in unreleased
versions thus far.

So again will need a meson.build check and conditionals.

>  crypto/cipher.c                 |  2 ++
>  qapi/crypto.json                |  5 +++-
>  tests/unit/test-crypto-cipher.c | 11 +++++++++
>  6 files changed, 70 insertions(+), 1 deletion(-)


> diff --git a/qapi/crypto.json b/qapi/crypto.json
> index fd3d46ebd1..95fa10bb6d 100644
> --- a/qapi/crypto.json
> +++ b/qapi/crypto.json
> @@ -94,6 +94,8 @@
>  #
>  # @twofish-256: Twofish with 256 bit / 32 byte keys
>  #
> +# @sm4: SM4 with 128 bit / 16 byte keys (since 8.2)

We're in feature freeze for 8.2, so mark this 9.0 as that'll be the
next available release this could be merged for.

> +#
>  # Since: 2.6
>  ##
>  { 'enum': 'QCryptoCipherAlgorithm',
> @@ -102,7 +104,8 @@
>             'des', '3des',
>             'cast5-128',
>             'serpent-128', 'serpent-192', 'serpent-256',
> -           'twofish-128', 'twofish-192', 'twofish-256']}
> +           'twofish-128', 'twofish-192', 'twofish-256',
> +           'sm4']}
>  
>  ##
>  # @QCryptoCipherMode:
> diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c
> index d9d9d078ff..80a4984e43 100644
> --- a/tests/unit/test-crypto-cipher.c
> +++ b/tests/unit/test-crypto-cipher.c
> @@ -382,6 +382,17 @@ static QCryptoCipherTestData test_data[] = {
>          .plaintext = "90afe91bb288544f2c32dc239b2635e6",
>          .ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa",
>      },
> +    {
> +        /* SM4, GB/T 32907-2016, Appendix A.1 */
> +        .path = "/crypto/cipher/sm4",
> +        .alg = QCRYPTO_CIPHER_ALG_SM4,
> +        .mode = QCRYPTO_CIPHER_MODE_ECB,
> +        .key = "0123456789abcdeffedcba9876543210",
> +        .plaintext  =
> +            "0123456789abcdeffedcba9876543210",
> +        .ciphertext =
> +            "681edf34d206965e86b3e94f536e4246",
> +    },
>      {
>          /* #1 32 byte key, 32 byte PTX */
>          .path = "/crypto/cipher/aes-xts-128-1",
> -- 
> 2.39.1
> 

With regards,
Daniel
Yong Huang Nov. 27, 2023, 4:38 p.m. UTC | #2
On Tue, Nov 28, 2023 at 12:11 AM Daniel P. Berrangé <berrange@redhat.com>
wrote:

> On Mon, Nov 27, 2023 at 11:55:34PM +0800, Hyman Huang wrote:
> > Introduce the SM4 cipher algorithms (OSCCA GB/T 32907-2016).
> >
> > SM4 (GBT.32907-2016) is a cryptographic standard issued by the
> > Organization of State Commercial Administration of China (OSCCA)
> > as an authorized cryptographic algorithms for the use within China.
>
> Just out of interest, what part of QEMU are you needing to use
> SM4 with ? Is it for a LUKS block driver cipher ?
>

Indeed, the LUKS block driver is the cause. Since SM4 can be accelerated by
encryption cards or hardware modules, we wish to evaluate the performance
overhead of the CPU and the proprietary hardware as in our production,
And the SM4 Algo CPU implementation could be introduced beforehand.

>
> >
> > Signed-off-by: Hyman Huang <yong.huang@smartx.com>
> > ---
> >  crypto/block-luks.c             |  7 ++++++
> >  crypto/cipher-gcrypt.c.inc      |  4 ++++
>
> Looking at the gcrypt code, SM4 is only supported in >= 1.9.0
>
> QEMU min version is 1.8.0, so you'll need to modify meson.build
> to check whether SM4 is supported and put conditionals in this
> file


> >  crypto/cipher-nettle.c.inc      | 42 +++++++++++++++++++++++++++++++++
>
> Looking at the nettle code, SM4 is only supported in unreleased
> versions thus far.


> So again will need a meson.build check and conditionals.
>
OK, I'll check the library versions in the next versoin.

>
> >  crypto/cipher.c                 |  2 ++
> >  qapi/crypto.json                |  5 +++-
> >  tests/unit/test-crypto-cipher.c | 11 +++++++++
> >  6 files changed, 70 insertions(+), 1 deletion(-)
>
>
> > diff --git a/qapi/crypto.json b/qapi/crypto.json
> > index fd3d46ebd1..95fa10bb6d 100644
> > --- a/qapi/crypto.json
> > +++ b/qapi/crypto.json
> > @@ -94,6 +94,8 @@
> >  #
> >  # @twofish-256: Twofish with 256 bit / 32 byte keys
> >  #
> > +# @sm4: SM4 with 128 bit / 16 byte keys (since 8.2)
>
> We're in feature freeze for 8.2, so mark this 9.0 as that'll be the
> next available release this could be merged for.
>
Get it.

>
> > +#
> >  # Since: 2.6
> >  ##
> >  { 'enum': 'QCryptoCipherAlgorithm',
> > @@ -102,7 +104,8 @@
> >             'des', '3des',
> >             'cast5-128',
> >             'serpent-128', 'serpent-192', 'serpent-256',
> > -           'twofish-128', 'twofish-192', 'twofish-256']}
> > +           'twofish-128', 'twofish-192', 'twofish-256',
> > +           'sm4']}
> >
> >  ##
> >  # @QCryptoCipherMode:
> > diff --git a/tests/unit/test-crypto-cipher.c
> b/tests/unit/test-crypto-cipher.c
> > index d9d9d078ff..80a4984e43 100644
> > --- a/tests/unit/test-crypto-cipher.c
> > +++ b/tests/unit/test-crypto-cipher.c
> > @@ -382,6 +382,17 @@ static QCryptoCipherTestData test_data[] = {
> >          .plaintext = "90afe91bb288544f2c32dc239b2635e6",
> >          .ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa",
> >      },
> > +    {
> > +        /* SM4, GB/T 32907-2016, Appendix A.1 */
> > +        .path = "/crypto/cipher/sm4",
> > +        .alg = QCRYPTO_CIPHER_ALG_SM4,
> > +        .mode = QCRYPTO_CIPHER_MODE_ECB,
> > +        .key = "0123456789abcdeffedcba9876543210",
> > +        .plaintext  =
> > +            "0123456789abcdeffedcba9876543210",
> > +        .ciphertext =
> > +            "681edf34d206965e86b3e94f536e4246",
> > +    },
> >      {
> >          /* #1 32 byte key, 32 byte PTX */
> >          .path = "/crypto/cipher/aes-xts-128-1",
> > --
> > 2.39.1
> >
>
> With regards,
> Daniel
> --
> |: https://berrange.com      -o-
> https://www.flickr.com/photos/dberrange :|
> |: https://libvirt.org         -o-
> https://fstop138.berrange.com :|
> |: https://entangle-photo.org    -o-
> https://www.instagram.com/dberrange :|
>
>
Thanks for the comment,
Yong
diff mbox series

Patch

diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index fb01ec38bb..1cb7f21a05 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -95,12 +95,19 @@  qcrypto_block_luks_cipher_size_map_twofish[] = {
     { 0, 0 },
 };
 
+static const QCryptoBlockLUKSCipherSizeMap
+qcrypto_block_luks_cipher_size_map_sm4[] = {
+    { 16, QCRYPTO_CIPHER_ALG_SM4},
+    { 0, 0 },
+};
+
 static const QCryptoBlockLUKSCipherNameMap
 qcrypto_block_luks_cipher_name_map[] = {
     { "aes", qcrypto_block_luks_cipher_size_map_aes },
     { "cast5", qcrypto_block_luks_cipher_size_map_cast5 },
     { "serpent", qcrypto_block_luks_cipher_size_map_serpent },
     { "twofish", qcrypto_block_luks_cipher_size_map_twofish },
+    { "sm4", qcrypto_block_luks_cipher_size_map_sm4},
 };
 
 QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSKeySlot) != 48);
diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc
index a6a0117717..03af50b0c3 100644
--- a/crypto/cipher-gcrypt.c.inc
+++ b/crypto/cipher-gcrypt.c.inc
@@ -35,6 +35,7 @@  bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
     case QCRYPTO_CIPHER_ALG_SERPENT_256:
     case QCRYPTO_CIPHER_ALG_TWOFISH_128:
     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+    case QCRYPTO_CIPHER_ALG_SM4:
         break;
     default:
         return false;
@@ -219,6 +220,9 @@  static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
         gcryalg = GCRY_CIPHER_TWOFISH;
         break;
+    case QCRYPTO_CIPHER_ALG_SM4:
+        gcryalg = GCRY_CIPHER_SM4;
+        break;
     default:
         error_setg(errp, "Unsupported cipher algorithm %s",
                    QCryptoCipherAlgorithm_str(alg));
diff --git a/crypto/cipher-nettle.c.inc b/crypto/cipher-nettle.c.inc
index 24cc61f87b..cd2ca0c7b5 100644
--- a/crypto/cipher-nettle.c.inc
+++ b/crypto/cipher-nettle.c.inc
@@ -30,6 +30,7 @@ 
 #include <nettle/serpent.h>
 #include <nettle/twofish.h>
 #include <nettle/ctr.h>
+#include <nettle/sm4.h>
 #ifndef CONFIG_QEMU_PRIVATE_XTS
 #include <nettle/xts.h>
 #endif
@@ -426,6 +427,28 @@  DEFINE_ECB_CBC_CTR_XTS(qcrypto_nettle_twofish,
                        QCryptoNettleTwofish, TWOFISH_BLOCK_SIZE,
                        twofish_encrypt_native, twofish_decrypt_native)
 
+typedef struct QCryptoNettleSm4 {
+    QCryptoCipher base;
+    struct sm4_ctx key[2];
+} QCryptoNettleSm4;
+
+static void sm4_encrypt_native(void *ctx, size_t length,
+                               uint8_t *dst, const uint8_t *src)
+{
+    struct sm4_ctx *keys = ctx;
+    sm4_crypt(&keys[0], length, dst, src);
+}
+
+static void sm4_decrypt_native(void *ctx, size_t length,
+                               uint8_t *dst, const uint8_t *src)
+{
+    struct sm4_ctx *keys = ctx;
+    sm4_crypt(&keys[1], length, dst, src);
+}
+
+DEFINE_ECB(qcrypto_nettle_sm4,
+           QCryptoNettleSm4, SM4_BLOCK_SIZE,
+           sm4_encrypt_native, sm4_decrypt_native)
 
 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
                              QCryptoCipherMode mode)
@@ -443,6 +466,7 @@  bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
     case QCRYPTO_CIPHER_ALG_TWOFISH_128:
     case QCRYPTO_CIPHER_ALG_TWOFISH_192:
     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+    case QCRYPTO_CIPHER_ALG_SM4:
         break;
     default:
         return false;
@@ -702,6 +726,24 @@  static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
             return &ctx->base;
         }
 
+    case QCRYPTO_CIPHER_ALG_SM4:
+        {
+            QCryptoNettleSm4 *ctx = g_new0(QCryptoNettleSm4, 1);
+
+            switch (mode) {
+            case QCRYPTO_CIPHER_MODE_ECB:
+                ctx->base.driver = &qcrypto_nettle_sm4_driver_ecb;
+                break;
+            default:
+                goto bad_cipher_mode;
+            }
+
+            sm4_set_encrypt_key(&ctx->key[0], key);
+            sm4_set_decrypt_key(&ctx->key[1], key);
+
+            return &ctx->base;
+        }
+
     default:
         error_setg(errp, "Unsupported cipher algorithm %s",
                    QCryptoCipherAlgorithm_str(alg));
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 74b09a5b26..048ceaa6a3 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -38,6 +38,7 @@  static const size_t alg_key_len[QCRYPTO_CIPHER_ALG__MAX] = {
     [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
     [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 24,
     [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 32,
+    [QCRYPTO_CIPHER_ALG_SM4] = 16,
 };
 
 static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
@@ -53,6 +54,7 @@  static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
     [QCRYPTO_CIPHER_ALG_TWOFISH_128] = 16,
     [QCRYPTO_CIPHER_ALG_TWOFISH_192] = 16,
     [QCRYPTO_CIPHER_ALG_TWOFISH_256] = 16,
+    [QCRYPTO_CIPHER_ALG_SM4] = 16,
 };
 
 static const bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
diff --git a/qapi/crypto.json b/qapi/crypto.json
index fd3d46ebd1..95fa10bb6d 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -94,6 +94,8 @@ 
 #
 # @twofish-256: Twofish with 256 bit / 32 byte keys
 #
+# @sm4: SM4 with 128 bit / 16 byte keys (since 8.2)
+#
 # Since: 2.6
 ##
 { 'enum': 'QCryptoCipherAlgorithm',
@@ -102,7 +104,8 @@ 
            'des', '3des',
            'cast5-128',
            'serpent-128', 'serpent-192', 'serpent-256',
-           'twofish-128', 'twofish-192', 'twofish-256']}
+           'twofish-128', 'twofish-192', 'twofish-256',
+           'sm4']}
 
 ##
 # @QCryptoCipherMode:
diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c
index d9d9d078ff..80a4984e43 100644
--- a/tests/unit/test-crypto-cipher.c
+++ b/tests/unit/test-crypto-cipher.c
@@ -382,6 +382,17 @@  static QCryptoCipherTestData test_data[] = {
         .plaintext = "90afe91bb288544f2c32dc239b2635e6",
         .ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa",
     },
+    {
+        /* SM4, GB/T 32907-2016, Appendix A.1 */
+        .path = "/crypto/cipher/sm4",
+        .alg = QCRYPTO_CIPHER_ALG_SM4,
+        .mode = QCRYPTO_CIPHER_MODE_ECB,
+        .key = "0123456789abcdeffedcba9876543210",
+        .plaintext  =
+            "0123456789abcdeffedcba9876543210",
+        .ciphertext =
+            "681edf34d206965e86b3e94f536e4246",
+    },
     {
         /* #1 32 byte key, 32 byte PTX */
         .path = "/crypto/cipher/aes-xts-128-1",