diff mbox series

[v2] crypto: Introduce SM4 symmetric cipher algorithm

Message ID 4413f00465bda93eda7a7560afb990ca01191062.1701185032.git.yong.huang@smartx.com
State New
Headers show
Series [v2] crypto: Introduce SM4 symmetric cipher algorithm | expand

Commit Message

Yong Huang Nov. 28, 2023, 3:24 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.

Use the crypto-sm4 meson build option for enabling this feature.

Signed-off-by: Hyman Huang <yong.huang@smartx.com>
---
 crypto/block-luks.c             | 11 ++++++++
 crypto/cipher-gcrypt.c.inc      |  8 ++++++
 crypto/cipher-nettle.c.inc      | 49 +++++++++++++++++++++++++++++++++
 crypto/cipher.c                 |  6 ++++
 meson.build                     | 23 ++++++++++++++++
 meson_options.txt               |  2 ++
 qapi/crypto.json                |  5 +++-
 scripts/meson-buildoptions.sh   |  3 ++
 tests/unit/test-crypto-cipher.c | 13 +++++++++
 9 files changed, 119 insertions(+), 1 deletion(-)

Comments

Philippe Mathieu-Daudé Nov. 28, 2023, 3:57 p.m. UTC | #1
Hi Hyman,

On 28/11/23 16:24, 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.
> 
> Use the crypto-sm4 meson build option for enabling this feature.
> 
> Signed-off-by: Hyman Huang <yong.huang@smartx.com>
> ---
>   crypto/block-luks.c             | 11 ++++++++
>   crypto/cipher-gcrypt.c.inc      |  8 ++++++
>   crypto/cipher-nettle.c.inc      | 49 +++++++++++++++++++++++++++++++++
>   crypto/cipher.c                 |  6 ++++
>   meson.build                     | 23 ++++++++++++++++
>   meson_options.txt               |  2 ++
>   qapi/crypto.json                |  5 +++-
>   scripts/meson-buildoptions.sh   |  3 ++
>   tests/unit/test-crypto-cipher.c | 13 +++++++++
>   9 files changed, 119 insertions(+), 1 deletion(-)


> diff --git a/meson.build b/meson.build
> index ec01f8b138..256d3257bb 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -1480,6 +1480,7 @@ endif
>   gcrypt = not_found
>   nettle = not_found
>   hogweed = not_found
> +crypto_sm4 = not_found
>   xts = 'none'
>   
>   if get_option('nettle').enabled() and get_option('gcrypt').enabled()
> @@ -1514,6 +1515,26 @@ if not gnutls_crypto.found()
>         xts = 'private'
>       endif
>     endif
> +  if get_option('crypto_sm4').enabled()

We want to detect it by default (not only when explicitly enabled) ...

> +    if get_option('gcrypt').enabled()
> +      # SM4 ALG is available in libgcrypt >= 1.9
> +      crypto_sm4 = dependency('libgcrypt', version: '>=1.9',
> +                              method: 'config-tool',
> +                              required: get_option('gcrypt'))
> +      # SM4 ALG static compilation
> +      if crypto_sm4.found() and get_option('prefer_static')
> +        crypto_sm4 = declare_dependency(dependencies: [
> +          crypto_sm4,
> +          cc.find_library('gpg-error', required: true)],
> +          version: crypto_sm4.version())
> +      endif
> +    else
> +      # SM4 ALG is available in nettle >= 3.9
> +      crypto_sm4 = dependency('nettle', version: '>=3.9',
> +                              method: 'pkg-config',
> +                              required: get_option('nettle'))
> +    endif

... and if it was forced with --enable-crypto_sm4 AND not found,
display an error.

IIUC your config you try to find the best effort implementation then
if not found, keep going silently.

> +  endif
>   endif


> diff --git a/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
> index 680fa3f581..f189f34829 100644
> --- a/scripts/meson-buildoptions.sh
> +++ b/scripts/meson-buildoptions.sh
> @@ -106,6 +106,7 @@ meson_options_help() {
>     printf "%s\n" '  colo-proxy      colo-proxy support'
>     printf "%s\n" '  coreaudio       CoreAudio sound support'
>     printf "%s\n" '  crypto-afalg    Linux AF_ALG crypto backend driver'
> +  printf "%s\n" '  crypto-sm4      SM4 symmetric cipher algorithm support'
>     printf "%s\n" '  curl            CURL block device driver'
>     printf "%s\n" '  curses          curses UI'
>     printf "%s\n" '  dbus-display    -display dbus support'
> @@ -282,6 +283,8 @@ _meson_option_parse() {
>       --disable-coroutine-pool) printf "%s" -Dcoroutine_pool=false ;;
>       --enable-crypto-afalg) printf "%s" -Dcrypto_afalg=enabled ;;
>       --disable-crypto-afalg) printf "%s" -Dcrypto_afalg=disabled ;;
> +    --enable-crypto-sm4) printf "%s" -Dcrypto_sm4=enabled ;;
> +    --disable-crypto-sm4) printf "%s" -Dcrypto_sm4=disabled ;;
>       --enable-curl) printf "%s" -Dcurl=enabled ;;
>       --disable-curl) printf "%s" -Dcurl=disabled ;;
>       --enable-curses) printf "%s" -Dcurses=enabled ;;
Daniel P. Berrangé Nov. 28, 2023, 4:20 p.m. UTC | #2
On Tue, Nov 28, 2023 at 04:57:20PM +0100, Philippe Mathieu-Daudé wrote:
> Hi Hyman,
> 
> On 28/11/23 16:24, 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.
> > 
> > Use the crypto-sm4 meson build option for enabling this feature.
> > 
> > Signed-off-by: Hyman Huang <yong.huang@smartx.com>
> > ---
> >   crypto/block-luks.c             | 11 ++++++++
> >   crypto/cipher-gcrypt.c.inc      |  8 ++++++
> >   crypto/cipher-nettle.c.inc      | 49 +++++++++++++++++++++++++++++++++
> >   crypto/cipher.c                 |  6 ++++
> >   meson.build                     | 23 ++++++++++++++++
> >   meson_options.txt               |  2 ++
> >   qapi/crypto.json                |  5 +++-
> >   scripts/meson-buildoptions.sh   |  3 ++
> >   tests/unit/test-crypto-cipher.c | 13 +++++++++
> >   9 files changed, 119 insertions(+), 1 deletion(-)
> 
> 
> > diff --git a/meson.build b/meson.build
> > index ec01f8b138..256d3257bb 100644
> > --- a/meson.build
> > +++ b/meson.build
> > @@ -1480,6 +1480,7 @@ endif
> >   gcrypt = not_found
> >   nettle = not_found
> >   hogweed = not_found
> > +crypto_sm4 = not_found
> >   xts = 'none'
> >   if get_option('nettle').enabled() and get_option('gcrypt').enabled()
> > @@ -1514,6 +1515,26 @@ if not gnutls_crypto.found()
> >         xts = 'private'
> >       endif
> >     endif
> > +  if get_option('crypto_sm4').enabled()
> 
> We want to detect it by default (not only when explicitly enabled) ...
> 
> > +    if get_option('gcrypt').enabled()
> > +      # SM4 ALG is available in libgcrypt >= 1.9
> > +      crypto_sm4 = dependency('libgcrypt', version: '>=1.9',
> > +                              method: 'config-tool',
> > +                              required: get_option('gcrypt'))
> > +      # SM4 ALG static compilation
> > +      if crypto_sm4.found() and get_option('prefer_static')
> > +        crypto_sm4 = declare_dependency(dependencies: [
> > +          crypto_sm4,
> > +          cc.find_library('gpg-error', required: true)],
> > +          version: crypto_sm4.version())
> > +      endif
> > +    else
> > +      # SM4 ALG is available in nettle >= 3.9
> > +      crypto_sm4 = dependency('nettle', version: '>=3.9',
> > +                              method: 'pkg-config',
> > +                              required: get_option('nettle'))
> > +    endif
> 
> ... and if it was forced with --enable-crypto_sm4 AND not found,
> display an error.
> 
> IIUC your config you try to find the best effort implementation then
> if not found, keep going silently.

Yes, ignore the get_option() calls, and instead look at .found()
in the library we just detected

ie

  if nettle.found()
      ....check sm4 in nettle
  endif

  if gcrypt.found()
      ....check sm4 in crypt
  endif


With regards,
Daniel
Yong Huang Nov. 29, 2023, 1:40 a.m. UTC | #3
I'll try to understand the comment, if i misunderstood, please point out.

On Wed, Nov 29, 2023 at 12:20 AM Daniel P. Berrangé <berrange@redhat.com>
wrote:

> On Tue, Nov 28, 2023 at 04:57:20PM +0100, Philippe Mathieu-Daudé wrote:
> > Hi Hyman,
> >
> > On 28/11/23 16:24, 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.
> > >
> > > Use the crypto-sm4 meson build option for enabling this feature.
> > >
> > > Signed-off-by: Hyman Huang <yong.huang@smartx.com>
> > > ---
> > >   crypto/block-luks.c             | 11 ++++++++
> > >   crypto/cipher-gcrypt.c.inc      |  8 ++++++
> > >   crypto/cipher-nettle.c.inc      | 49
> +++++++++++++++++++++++++++++++++
> > >   crypto/cipher.c                 |  6 ++++
> > >   meson.build                     | 23 ++++++++++++++++
> > >   meson_options.txt               |  2 ++
> > >   qapi/crypto.json                |  5 +++-
> > >   scripts/meson-buildoptions.sh   |  3 ++
> > >   tests/unit/test-crypto-cipher.c | 13 +++++++++
> > >   9 files changed, 119 insertions(+), 1 deletion(-)
> >
> >
> > > diff --git a/meson.build b/meson.build
> > > index ec01f8b138..256d3257bb 100644
> > > --- a/meson.build
> > > +++ b/meson.build
> > > @@ -1480,6 +1480,7 @@ endif
> > >   gcrypt = not_found
> > >   nettle = not_found
> > >   hogweed = not_found
> > > +crypto_sm4 = not_found
> > >   xts = 'none'
> > >   if get_option('nettle').enabled() and get_option('gcrypt').enabled()
> > > @@ -1514,6 +1515,26 @@ if not gnutls_crypto.found()
> > >         xts = 'private'
> > >       endif
> > >     endif
> > > +  if get_option('crypto_sm4').enabled()
> >
> > We want to detect it by default (not only when explicitly enabled) ...
> >
> > > +    if get_option('gcrypt').enabled()
> > > +      # SM4 ALG is available in libgcrypt >= 1.9
> > > +      crypto_sm4 = dependency('libgcrypt', version: '>=1.9',
> > > +                              method: 'config-tool',
> > > +                              required: get_option('gcrypt'))
> > > +      # SM4 ALG static compilation
> > > +      if crypto_sm4.found() and get_option('prefer_static')
> > > +        crypto_sm4 = declare_dependency(dependencies: [
> > > +          crypto_sm4,
> > > +          cc.find_library('gpg-error', required: true)],
> > > +          version: crypto_sm4.version())
> > > +      endif
> > > +    else
> > > +      # SM4 ALG is available in nettle >= 3.9
> > > +      crypto_sm4 = dependency('nettle', version: '>=3.9',
> > > +                              method: 'pkg-config',
> > > +                              required: get_option('nettle'))
> > > +    endif
> >
> > ... and if it was forced with --enable-crypto_sm4 AND not found,
> > display an error.
> >
> > IIUC your config you try to find the best effort implementation then
> > if not found, keep going silently.
>
> Yes, ignore the get_option() calls, and instead look at .found()
> in the library we just detected
>
ie
>
>   if nettle.found()
>       ....check sm4 in nettle
>   endif
>
>   if gcrypt.found()
>       ....check sm4 in crypt
>   endif
>
> To detect if sm4 is supported, there may be two methods:
One is to specify the version explicitly(ligcrypt >=1.9,nettle >= 3.9)
as in patch

Another is to use the cc.link for a test. eg:

+      crypto_sm4 = gcrypt
+      if gcrypt.found() and not cc.links('''
+        #include <gcrypt.h>
+        void main(void) {
+          gcry_cipher_hd_t handler;
+          gcry_cipher_open(&handler, GCRY_CIPHER_SM4,
GCRY_CIPHER_MODE_ECB, 0);
+        }''', dependencies: gcrypt)
+        crypto_sm4 = not_found
+      endif

Is the latter a better choice?


>
> 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 :|
>
>
Yong Huang Nov. 29, 2023, 1:43 a.m. UTC | #4
On Tue, Nov 28, 2023 at 11:57 PM Philippe Mathieu-Daudé <philmd@linaro.org>
wrote:

> Hi Hyman,
>
> On 28/11/23 16:24, 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.
> >
> > Use the crypto-sm4 meson build option for enabling this feature.
> >
> > Signed-off-by: Hyman Huang <yong.huang@smartx.com>
> > ---
> >   crypto/block-luks.c             | 11 ++++++++
> >   crypto/cipher-gcrypt.c.inc      |  8 ++++++
> >   crypto/cipher-nettle.c.inc      | 49 +++++++++++++++++++++++++++++++++
> >   crypto/cipher.c                 |  6 ++++
> >   meson.build                     | 23 ++++++++++++++++
> >   meson_options.txt               |  2 ++
> >   qapi/crypto.json                |  5 +++-
> >   scripts/meson-buildoptions.sh   |  3 ++
> >   tests/unit/test-crypto-cipher.c | 13 +++++++++
> >   9 files changed, 119 insertions(+), 1 deletion(-)
>
>
> > diff --git a/meson.build b/meson.build
> > index ec01f8b138..256d3257bb 100644
> > --- a/meson.build
> > +++ b/meson.build
> > @@ -1480,6 +1480,7 @@ endif
> >   gcrypt = not_found
> >   nettle = not_found
> >   hogweed = not_found
> > +crypto_sm4 = not_found
> >   xts = 'none'
> >
> >   if get_option('nettle').enabled() and get_option('gcrypt').enabled()
> > @@ -1514,6 +1515,26 @@ if not gnutls_crypto.found()
> >         xts = 'private'
> >       endif
> >     endif
> > +  if get_option('crypto_sm4').enabled()
>
> We want to detect it by default (not only when explicitly enabled) ...
>
Ok, get it.

>
> > +    if get_option('gcrypt').enabled()
> > +      # SM4 ALG is available in libgcrypt >= 1.9
> > +      crypto_sm4 = dependency('libgcrypt', version: '>=1.9',
> > +                              method: 'config-tool',
> > +                              required: get_option('gcrypt'))
> > +      # SM4 ALG static compilation
> > +      if crypto_sm4.found() and get_option('prefer_static')
> > +        crypto_sm4 = declare_dependency(dependencies: [
> > +          crypto_sm4,
> > +          cc.find_library('gpg-error', required: true)],
> > +          version: crypto_sm4.version())
> > +      endif
> > +    else
> > +      # SM4 ALG is available in nettle >= 3.9
> > +      crypto_sm4 = dependency('nettle', version: '>=3.9',
> > +                              method: 'pkg-config',
> > +                              required: get_option('nettle'))
> > +    endif
>
> ... and if it was forced with --enable-crypto_sm4 AND not found,
> display an error.
>
Ok.

>
> IIUC your config you try to find the best effort implementation then
> if not found, keep going silently.
>
> > +  endif
> >   endif
>
>
> > diff --git a/scripts/meson-buildoptions.sh
> b/scripts/meson-buildoptions.sh
> > index 680fa3f581..f189f34829 100644
> > --- a/scripts/meson-buildoptions.sh
> > +++ b/scripts/meson-buildoptions.sh
> > @@ -106,6 +106,7 @@ meson_options_help() {
> >     printf "%s\n" '  colo-proxy      colo-proxy support'
> >     printf "%s\n" '  coreaudio       CoreAudio sound support'
> >     printf "%s\n" '  crypto-afalg    Linux AF_ALG crypto backend driver'
> > +  printf "%s\n" '  crypto-sm4      SM4 symmetric cipher algorithm
> support'
> >     printf "%s\n" '  curl            CURL block device driver'
> >     printf "%s\n" '  curses          curses UI'
> >     printf "%s\n" '  dbus-display    -display dbus support'
> > @@ -282,6 +283,8 @@ _meson_option_parse() {
> >       --disable-coroutine-pool) printf "%s" -Dcoroutine_pool=false ;;
> >       --enable-crypto-afalg) printf "%s" -Dcrypto_afalg=enabled ;;
> >       --disable-crypto-afalg) printf "%s" -Dcrypto_afalg=disabled ;;
> > +    --enable-crypto-sm4) printf "%s" -Dcrypto_sm4=enabled ;;
> > +    --disable-crypto-sm4) printf "%s" -Dcrypto_sm4=disabled ;;
> >       --enable-curl) printf "%s" -Dcurl=enabled ;;
> >       --disable-curl) printf "%s" -Dcurl=disabled ;;
> >       --enable-curses) printf "%s" -Dcurses=enabled ;;
>
>
Daniel P. Berrangé Nov. 29, 2023, 4:50 p.m. UTC | #5
On Wed, Nov 29, 2023 at 09:40:29AM +0800, Yong Huang wrote:
> I'll try to understand the comment, if i misunderstood, please point out.
> 
> On Wed, Nov 29, 2023 at 12:20 AM Daniel P. Berrangé <berrange@redhat.com>
> wrote:
> 
> > On Tue, Nov 28, 2023 at 04:57:20PM +0100, Philippe Mathieu-Daudé wrote:
> > > Hi Hyman,
> > >
> > > On 28/11/23 16:24, 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.
> > > >
> > > > Use the crypto-sm4 meson build option for enabling this feature.
> > > >
> > > > Signed-off-by: Hyman Huang <yong.huang@smartx.com>
> > > > ---
> > > >   crypto/block-luks.c             | 11 ++++++++
> > > >   crypto/cipher-gcrypt.c.inc      |  8 ++++++
> > > >   crypto/cipher-nettle.c.inc      | 49
> > +++++++++++++++++++++++++++++++++
> > > >   crypto/cipher.c                 |  6 ++++
> > > >   meson.build                     | 23 ++++++++++++++++
> > > >   meson_options.txt               |  2 ++
> > > >   qapi/crypto.json                |  5 +++-
> > > >   scripts/meson-buildoptions.sh   |  3 ++
> > > >   tests/unit/test-crypto-cipher.c | 13 +++++++++
> > > >   9 files changed, 119 insertions(+), 1 deletion(-)
> > >
> > >
> > > > diff --git a/meson.build b/meson.build
> > > > index ec01f8b138..256d3257bb 100644
> > > > --- a/meson.build
> > > > +++ b/meson.build
> > > > @@ -1480,6 +1480,7 @@ endif
> > > >   gcrypt = not_found
> > > >   nettle = not_found
> > > >   hogweed = not_found
> > > > +crypto_sm4 = not_found
> > > >   xts = 'none'
> > > >   if get_option('nettle').enabled() and get_option('gcrypt').enabled()
> > > > @@ -1514,6 +1515,26 @@ if not gnutls_crypto.found()
> > > >         xts = 'private'
> > > >       endif
> > > >     endif
> > > > +  if get_option('crypto_sm4').enabled()
> > >
> > > We want to detect it by default (not only when explicitly enabled) ...
> > >
> > > > +    if get_option('gcrypt').enabled()
> > > > +      # SM4 ALG is available in libgcrypt >= 1.9
> > > > +      crypto_sm4 = dependency('libgcrypt', version: '>=1.9',
> > > > +                              method: 'config-tool',
> > > > +                              required: get_option('gcrypt'))
> > > > +      # SM4 ALG static compilation
> > > > +      if crypto_sm4.found() and get_option('prefer_static')
> > > > +        crypto_sm4 = declare_dependency(dependencies: [
> > > > +          crypto_sm4,
> > > > +          cc.find_library('gpg-error', required: true)],
> > > > +          version: crypto_sm4.version())
> > > > +      endif
> > > > +    else
> > > > +      # SM4 ALG is available in nettle >= 3.9
> > > > +      crypto_sm4 = dependency('nettle', version: '>=3.9',
> > > > +                              method: 'pkg-config',
> > > > +                              required: get_option('nettle'))
> > > > +    endif
> > >
> > > ... and if it was forced with --enable-crypto_sm4 AND not found,
> > > display an error.
> > >
> > > IIUC your config you try to find the best effort implementation then
> > > if not found, keep going silently.
> >
> > Yes, ignore the get_option() calls, and instead look at .found()
> > in the library we just detected
> >
> ie
> >
> >   if nettle.found()
> >       ....check sm4 in nettle
> >   endif
> >
> >   if gcrypt.found()
> >       ....check sm4 in crypt
> >   endif
> >
> > To detect if sm4 is supported, there may be two methods:
> One is to specify the version explicitly(ligcrypt >=1.9,nettle >= 3.9)
> as in patch
> 
> Another is to use the cc.link for a test. eg:
> 
> +      crypto_sm4 = gcrypt
> +      if gcrypt.found() and not cc.links('''
> +        #include <gcrypt.h>
> +        void main(void) {
> +          gcry_cipher_hd_t handler;
> +          gcry_cipher_open(&handler, GCRY_CIPHER_SM4,
> GCRY_CIPHER_MODE_ECB, 0);
> +        }''', dependencies: gcrypt)
> +        crypto_sm4 = not_found
> +      endif
> 
> Is the latter a better choice?

I'm fine with either a version check, or a link check. A
link check is robust against anyone backporting new features,
so a little better.


With regards,
Daniel
diff mbox series

Patch

diff --git a/crypto/block-luks.c b/crypto/block-luks.c
index fb01ec38bb..f0813d69b4 100644
--- a/crypto/block-luks.c
+++ b/crypto/block-luks.c
@@ -95,12 +95,23 @@  qcrypto_block_luks_cipher_size_map_twofish[] = {
     { 0, 0 },
 };
 
+#ifdef CONFIG_CRYPTO_SM4
+static const QCryptoBlockLUKSCipherSizeMap
+qcrypto_block_luks_cipher_size_map_sm4[] = {
+    { 16, QCRYPTO_CIPHER_ALG_SM4},
+    { 0, 0 },
+};
+#endif
+
 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 },
+#ifdef CONFIG_CRYPTO_SM4
+    { "sm4", qcrypto_block_luks_cipher_size_map_sm4},
+#endif
 };
 
 QEMU_BUILD_BUG_ON(sizeof(struct QCryptoBlockLUKSKeySlot) != 48);
diff --git a/crypto/cipher-gcrypt.c.inc b/crypto/cipher-gcrypt.c.inc
index a6a0117717..1377cbaf14 100644
--- a/crypto/cipher-gcrypt.c.inc
+++ b/crypto/cipher-gcrypt.c.inc
@@ -35,6 +35,9 @@  bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
     case QCRYPTO_CIPHER_ALG_SERPENT_256:
     case QCRYPTO_CIPHER_ALG_TWOFISH_128:
     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+#ifdef CONFIG_CRYPTO_SM4
+    case QCRYPTO_CIPHER_ALG_SM4:
+#endif
         break;
     default:
         return false;
@@ -219,6 +222,11 @@  static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
         gcryalg = GCRY_CIPHER_TWOFISH;
         break;
+#ifdef CONFIG_CRYPTO_SM4
+    case QCRYPTO_CIPHER_ALG_SM4:
+        gcryalg = GCRY_CIPHER_SM4;
+        break;
+#endif
     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..42b39e18a2 100644
--- a/crypto/cipher-nettle.c.inc
+++ b/crypto/cipher-nettle.c.inc
@@ -33,6 +33,9 @@ 
 #ifndef CONFIG_QEMU_PRIVATE_XTS
 #include <nettle/xts.h>
 #endif
+#ifdef CONFIG_CRYPTO_SM4
+#include <nettle/sm4.h>
+#endif
 
 static inline bool qcrypto_length_check(size_t len, size_t blocksize,
                                         Error **errp)
@@ -426,6 +429,30 @@  DEFINE_ECB_CBC_CTR_XTS(qcrypto_nettle_twofish,
                        QCryptoNettleTwofish, TWOFISH_BLOCK_SIZE,
                        twofish_encrypt_native, twofish_decrypt_native)
 
+#ifdef CONFIG_CRYPTO_SM4
+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)
+#endif
 
 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
                              QCryptoCipherMode mode)
@@ -443,6 +470,9 @@  bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
     case QCRYPTO_CIPHER_ALG_TWOFISH_128:
     case QCRYPTO_CIPHER_ALG_TWOFISH_192:
     case QCRYPTO_CIPHER_ALG_TWOFISH_256:
+#ifdef CONFIG_CRYPTO_SM4
+    case QCRYPTO_CIPHER_ALG_SM4:
+#endif
         break;
     default:
         return false;
@@ -701,6 +731,25 @@  static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
 
             return &ctx->base;
         }
+#ifdef CONFIG_CRYPTO_SM4
+    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;
+        }
+#endif
 
     default:
         error_setg(errp, "Unsupported cipher algorithm %s",
diff --git a/crypto/cipher.c b/crypto/cipher.c
index 74b09a5b26..5f512768ea 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -38,6 +38,9 @@  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,
+#ifdef CONFIG_CRYPTO_SM4
+    [QCRYPTO_CIPHER_ALG_SM4] = 16,
+#endif
 };
 
 static const size_t alg_block_len[QCRYPTO_CIPHER_ALG__MAX] = {
@@ -53,6 +56,9 @@  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,
+#ifdef CONFIG_CRYPTO_SM4
+    [QCRYPTO_CIPHER_ALG_SM4] = 16,
+#endif
 };
 
 static const bool mode_need_iv[QCRYPTO_CIPHER_MODE__MAX] = {
diff --git a/meson.build b/meson.build
index ec01f8b138..256d3257bb 100644
--- a/meson.build
+++ b/meson.build
@@ -1480,6 +1480,7 @@  endif
 gcrypt = not_found
 nettle = not_found
 hogweed = not_found
+crypto_sm4 = not_found
 xts = 'none'
 
 if get_option('nettle').enabled() and get_option('gcrypt').enabled()
@@ -1514,6 +1515,26 @@  if not gnutls_crypto.found()
       xts = 'private'
     endif
   endif
+  if get_option('crypto_sm4').enabled()
+    if get_option('gcrypt').enabled()
+      # SM4 ALG is available in libgcrypt >= 1.9
+      crypto_sm4 = dependency('libgcrypt', version: '>=1.9',
+                              method: 'config-tool',
+                              required: get_option('gcrypt'))
+      # SM4 ALG static compilation
+      if crypto_sm4.found() and get_option('prefer_static')
+        crypto_sm4 = declare_dependency(dependencies: [
+          crypto_sm4,
+          cc.find_library('gpg-error', required: true)],
+          version: crypto_sm4.version())
+      endif
+    else
+      # SM4 ALG is available in nettle >= 3.9
+      crypto_sm4 = dependency('nettle', version: '>=3.9',
+                              method: 'pkg-config',
+                              required: get_option('nettle'))
+    endif
+  endif
 endif
 
 gmp = dependency('gmp', required: false, method: 'pkg-config')
@@ -2199,6 +2220,7 @@  config_host_data.set('CONFIG_GNUTLS_CRYPTO', gnutls_crypto.found())
 config_host_data.set('CONFIG_TASN1', tasn1.found())
 config_host_data.set('CONFIG_GCRYPT', gcrypt.found())
 config_host_data.set('CONFIG_NETTLE', nettle.found())
+config_host_data.set('CONFIG_CRYPTO_SM4', crypto_sm4.found())
 config_host_data.set('CONFIG_HOGWEED', hogweed.found())
 config_host_data.set('CONFIG_QEMU_PRIVATE_XTS', xts == 'private')
 config_host_data.set('CONFIG_MALLOC_TRIM', has_malloc_trim)
@@ -4273,6 +4295,7 @@  summary_info += {'nettle':            nettle}
 if nettle.found()
    summary_info += {'  XTS':             xts != 'private'}
 endif
+summary_info += {'SM4 ALG support':   crypto_sm4}
 summary_info += {'AF_ALG support':    have_afalg}
 summary_info += {'rng-none':          get_option('rng_none')}
 summary_info += {'Linux keyring':     have_keyring}
diff --git a/meson_options.txt b/meson_options.txt
index c9baeda639..db8de4ec5b 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -172,6 +172,8 @@  option('nettle', type : 'feature', value : 'auto',
        description: 'nettle cryptography support')
 option('gcrypt', type : 'feature', value : 'auto',
        description: 'libgcrypt cryptography support')
+option('crypto_sm4', type : 'feature', value : 'auto',
+       description: 'SM4 symmetric cipher algorithm support')
 option('crypto_afalg', type : 'feature', value : 'disabled',
        description: 'Linux AF_ALG crypto backend driver')
 option('libdaxctl', type : 'feature', value : 'auto',
diff --git a/qapi/crypto.json b/qapi/crypto.json
index fd3d46ebd1..2f2aeff5fd 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 9.0)
+#
 # 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/scripts/meson-buildoptions.sh b/scripts/meson-buildoptions.sh
index 680fa3f581..f189f34829 100644
--- a/scripts/meson-buildoptions.sh
+++ b/scripts/meson-buildoptions.sh
@@ -106,6 +106,7 @@  meson_options_help() {
   printf "%s\n" '  colo-proxy      colo-proxy support'
   printf "%s\n" '  coreaudio       CoreAudio sound support'
   printf "%s\n" '  crypto-afalg    Linux AF_ALG crypto backend driver'
+  printf "%s\n" '  crypto-sm4      SM4 symmetric cipher algorithm support'
   printf "%s\n" '  curl            CURL block device driver'
   printf "%s\n" '  curses          curses UI'
   printf "%s\n" '  dbus-display    -display dbus support'
@@ -282,6 +283,8 @@  _meson_option_parse() {
     --disable-coroutine-pool) printf "%s" -Dcoroutine_pool=false ;;
     --enable-crypto-afalg) printf "%s" -Dcrypto_afalg=enabled ;;
     --disable-crypto-afalg) printf "%s" -Dcrypto_afalg=disabled ;;
+    --enable-crypto-sm4) printf "%s" -Dcrypto_sm4=enabled ;;
+    --disable-crypto-sm4) printf "%s" -Dcrypto_sm4=disabled ;;
     --enable-curl) printf "%s" -Dcurl=enabled ;;
     --disable-curl) printf "%s" -Dcurl=disabled ;;
     --enable-curses) printf "%s" -Dcurses=enabled ;;
diff --git a/tests/unit/test-crypto-cipher.c b/tests/unit/test-crypto-cipher.c
index d9d9d078ff..11ab1a54fc 100644
--- a/tests/unit/test-crypto-cipher.c
+++ b/tests/unit/test-crypto-cipher.c
@@ -382,6 +382,19 @@  static QCryptoCipherTestData test_data[] = {
         .plaintext = "90afe91bb288544f2c32dc239b2635e6",
         .ciphertext = "6cb4561c40bf0a9705931cb6d408e7fa",
     },
+#ifdef CONFIG_CRYPTO_SM4
+    {
+        /* 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",
+    },
+#endif
     {
         /* #1 32 byte key, 32 byte PTX */
         .path = "/crypto/cipher/aes-xts-128-1",