diff mbox series

crypto: Introduce SM3 hash hmac pbkdf algorithm

Message ID CAAsfc_opwD26bx=9GiQbcuNT3mviySe-9t-rz3U9nA+PkCUS3w@mail.gmail.com (mailing list archive)
State New
Headers show
Series crypto: Introduce SM3 hash hmac pbkdf algorithm | expand

Commit Message

liequan che Oct. 29, 2024, 7:50 a.m. UTC
Introduce the SM3 cryptographic hash algorithm (GB/T 32905-2016).

SM3 (GB/T 32905-2016) is a cryptographic standard issued by the
Organization of State Commercial Cryptography Administration (OSCCA)
as an authorized cryptographic algorithm for use within China.

Detect the SM3 cryptographic hash algorithm and enable the feature silently
if it is available.

Signed-off-by: cheliequan <cheliequan@inspur.com>
---
 crypto/hash-gcrypt.c           |  3 +++
 crypto/hash-nettle.c           | 14 ++++++++++++
 crypto/hash.c                  |  3 +++
 crypto/hmac-gcrypt.c           |  3 +++
 crypto/hmac-nettle.c           | 11 ++++++++++
 crypto/pbkdf-gcrypt.c          |  6 ++++++
 crypto/pbkdf-nettle.c          | 13 ++++++++++++
 meson.build                    | 39 ++++++++++++++++++++++++++++++++++
 qapi/crypto.json               |  4 +++-
 tests/unit/test-crypto-hash.c  | 16 ++++++++++++++
 tests/unit/test-crypto-hmac.c  |  8 +++++++
 tests/unit/test-crypto-pbkdf.c | 16 ++++++++++++++
 12 files changed, 135 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/crypto/hash-gcrypt.c b/crypto/hash-gcrypt.c
index 829e48258d..d3bdfe5633 100644
--- a/crypto/hash-gcrypt.c
+++ b/crypto/hash-gcrypt.c
@@ -33,6 +33,9 @@  static int qcrypto_hash_alg_map[QCRYPTO_HASH_ALG__MAX] = {
     [QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384,
     [QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512,
     [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160,
+#ifdef CONFIG_CRYPTO_SM3
+    [QCRYPTO_HASH_ALG_SM3] = GCRY_MD_SM3,
+#endif
 };

 gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
diff --git a/crypto/hash-nettle.c b/crypto/hash-nettle.c
index 1ca1a41062..0c2f8ce86c 100644
--- a/crypto/hash-nettle.c
+++ b/crypto/hash-nettle.c
@@ -25,6 +25,9 @@ 
 #include <nettle/md5.h>
 #include <nettle/sha.h>
 #include <nettle/ripemd160.h>
+#ifdef CONFIG_CRYPTO_SM3
+#include <nettle/sm3.h>
+#endif

 typedef void (*qcrypto_nettle_init)(void *ctx);
 typedef void (*qcrypto_nettle_write)(void *ctx,
@@ -42,6 +45,9 @@  union qcrypto_hash_ctx {
     struct sha384_ctx sha384;
     struct sha512_ctx sha512;
     struct ripemd160_ctx ripemd160;
+#ifdef CONFIG_CRYPTO_SM3
+    struct sm3_ctx sm3;
+#endif
 };

 struct qcrypto_hash_alg {
@@ -92,6 +98,14 @@  struct qcrypto_hash_alg {
         .result = (qcrypto_nettle_result)ripemd160_digest,
         .len = RIPEMD160_DIGEST_SIZE,
     },
+#ifdef CONFIG_CRYPTO_SM3
+    [QCRYPTO_HASH_ALG_SM3] = {
+        .init = (qcrypto_nettle_init)sm3_init,
+        .write = (qcrypto_nettle_write)sm3_update,
+        .result = (qcrypto_nettle_result)sm3_digest,
+        .len = SM3_DIGEST_SIZE,
+    },
+#endif
 };

 gboolean qcrypto_hash_supports(QCryptoHashAlgorithm alg)
diff --git a/crypto/hash.c b/crypto/hash.c
index b0f8228bdc..8f1502ce68 100644
--- a/crypto/hash.c
+++ b/crypto/hash.c
@@ -30,6 +30,9 @@  static size_t
qcrypto_hash_alg_size[QCRYPTO_HASH_ALG__MAX] = {
     [QCRYPTO_HASH_ALG_SHA384] = 48,
     [QCRYPTO_HASH_ALG_SHA512] = 64,
     [QCRYPTO_HASH_ALG_RIPEMD160] = 20,
+#ifdef CONFIG_CRYPTO_SM3
+    [QCRYPTO_HASH_ALG_SM3] = 32,
+#endif
 };

 size_t qcrypto_hash_digest_len(QCryptoHashAlgorithm alg)
diff --git a/crypto/hmac-gcrypt.c b/crypto/hmac-gcrypt.c
index 0c6f979711..888afb86ed 100644
--- a/crypto/hmac-gcrypt.c
+++ b/crypto/hmac-gcrypt.c
@@ -26,6 +26,9 @@  static int qcrypto_hmac_alg_map[QCRYPTO_HASH_ALG__MAX] = {
     [QCRYPTO_HASH_ALG_SHA384] = GCRY_MAC_HMAC_SHA384,
     [QCRYPTO_HASH_ALG_SHA512] = GCRY_MAC_HMAC_SHA512,
     [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MAC_HMAC_RMD160,
+#ifdef CONFIG_CRYPTO_SM3
+    [QCRYPTO_HASH_ALG_SM3] = GCRY_MAC_HMAC_SM3,
+#endif
 };

 typedef struct QCryptoHmacGcrypt QCryptoHmacGcrypt;
diff --git a/crypto/hmac-nettle.c b/crypto/hmac-nettle.c
index 1ad6c4f253..e51e3319ab 100644
--- a/crypto/hmac-nettle.c
+++ b/crypto/hmac-nettle.c
@@ -38,6 +38,9 @@  struct QCryptoHmacNettle {
         struct hmac_sha256_ctx sha256_ctx; /* equals hmac_sha224_ctx */
         struct hmac_sha512_ctx sha512_ctx; /* equals hmac_sha384_ctx */
         struct hmac_ripemd160_ctx ripemd160_ctx;
+#ifdef CONFIG_CRYPTO_SM3
+ struct hmac_sm3_ctx ctx;
+#endif
     } u;
 };

@@ -89,6 +92,14 @@  struct qcrypto_nettle_hmac_alg {
         .digest = (qcrypto_nettle_hmac_digest)hmac_ripemd160_digest,
         .len = RIPEMD160_DIGEST_SIZE,
     },
+#ifdef CONFIG_CRYPTO_SM3
+    [QCRYPTO_HASH_ALG_SM3] = {
+        .setkey = (qcrypto_nettle_hmac_setkey)hmac_sm3_set_key,
+        .update = (qcrypto_nettle_hmac_update)hmac_sm3_update,
+        .digest = (qcrypto_nettle_hmac_digest)hmac_sm3_digest,
+        .len = SM3_DIGEST_SIZE,
+    },
+#endif
 };

 bool qcrypto_hmac_supports(QCryptoHashAlgorithm alg)
diff --git a/crypto/pbkdf-gcrypt.c b/crypto/pbkdf-gcrypt.c
index a8d8e64f4d..09b38d0d6e 100644
--- a/crypto/pbkdf-gcrypt.c
+++ b/crypto/pbkdf-gcrypt.c
@@ -33,6 +33,9 @@  bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
     case QCRYPTO_HASH_ALG_SHA384:
     case QCRYPTO_HASH_ALG_SHA512:
     case QCRYPTO_HASH_ALG_RIPEMD160:
+#ifdef CONFIG_CRYPTO_SM3
+    case QCRYPTO_HASH_ALG_SM3:
+#endif
         return true;
     default:
         return false;
@@ -54,6 +57,9 @@  int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
         [QCRYPTO_HASH_ALG_SHA384] = GCRY_MD_SHA384,
         [QCRYPTO_HASH_ALG_SHA512] = GCRY_MD_SHA512,
         [QCRYPTO_HASH_ALG_RIPEMD160] = GCRY_MD_RMD160,
+#ifdef CONFIG_CRYPTO_SM3
+        [QCRYPTO_HASH_ALG_SM3] = GCRY_MD_SM3,
+#endif
     };
     int ret;

diff --git a/crypto/pbkdf-nettle.c b/crypto/pbkdf-nettle.c
index d6293c25a1..5fea570bd3 100644
--- a/crypto/pbkdf-nettle.c
+++ b/crypto/pbkdf-nettle.c
@@ -34,6 +34,9 @@  bool qcrypto_pbkdf2_supports(QCryptoHashAlgorithm hash)
     case QCRYPTO_HASH_ALG_SHA384:
     case QCRYPTO_HASH_ALG_SHA512:
     case QCRYPTO_HASH_ALG_RIPEMD160:
+#ifdef CONFIG_CRYPTO_SM3
+    case QCRYPTO_HASH_ALG_SM3:
+#endif
         return true;
     default:
         return false;
@@ -55,6 +58,9 @@  int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
         struct hmac_sha384_ctx sha384;
         struct hmac_sha512_ctx sha512;
         struct hmac_ripemd160_ctx ripemd160;
+#ifdef CONFIG_CRYPTO_SM3
+        struct hmac_sm3_ctx sm3;
+#endif
     } ctx;

     if (iterations > UINT_MAX) {
@@ -106,6 +112,13 @@  int qcrypto_pbkdf2(QCryptoHashAlgorithm hash,
         PBKDF2(&ctx.ripemd160, hmac_ripemd160_update,
hmac_ripemd160_digest,
                RIPEMD160_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
         break;
+#ifdef CONFIG_CRYPTO_SM3
+    case QCRYPTO_HASH_ALG_SM3:
+        hmac_sm3_set_key(&ctx.sm3, nkey, key);
+        PBKDF2(&ctx.sm3, hmac_sm3_update, hmac_sm3_digest,
+               SM3_DIGEST_SIZE, iterations, nsalt, salt, nout, out);
+        break;
+#endif

     default:
         error_setg_errno(errp, ENOSYS,
diff --git a/meson.build b/meson.build
index 089f45d386..4024f9a4bb 100644
--- a/meson.build
+++ b/meson.build
@@ -1486,6 +1486,7 @@  gcrypt = not_found
 nettle = not_found
 hogweed = not_found
 crypto_sm4 = not_found
+crypto_sm3 = not_found
 xts = 'none'

 if get_option('nettle').enabled() and get_option('gcrypt').enabled()
@@ -1522,6 +1523,17 @@  if not gnutls_crypto.found()
       }''', dependencies: gcrypt)
       crypto_sm4 = not_found
     endif
+    crypto_sm3 = gcrypt
+    # SM3 ALG is available in libgcrypt >= 1.8
+    if gcrypt.found() and not cc.links('''
+      #include <gcrypt.h>
+      int main(void) {
+        gcry_md_hd_t handler;
+        gcry_md_open(&handler, GCRY_MD_SM3, 0);
+        return 0;
+      }''', dependencies: gcrypt)
+      crypto_sm3 = not_found
+    endif
   endif
   if (not get_option('nettle').auto() or have_system) and not
gcrypt.found()
     nettle = dependency('nettle', version: '>=3.4',
@@ -1542,6 +1554,31 @@  if not gnutls_crypto.found()
       }''', dependencies: nettle)
       crypto_sm4 = not_found
     endif
+    crypto_sm3 = nettle
+    # SM3 ALG is available in nettle >= 3.4
+    if nettle.found() and not cc.links('''
+      #include <nettle/sm3.h>
+      #include <nettle/hmac.h>
+      int main(void) {
+      struct sm3_ctx ctx;
+      struct hmac_sm3_ctx hmac_ctx;
+      unsigned char data[64] = {0};
+      unsigned char output[32];
+
+      // SM3 hash function test
+      sm3_init(&ctx);
+      sm3_update(&ctx, 64, data);
+      sm3_digest(&ctx, 32, data);
+
+      // HMAC-SM3 test
+      hmac_sm3_set_key(&hmac_ctx, 32, data);
+      hmac_sm3_update(&hmac_ctx, 64, data);
+      hmac_sm3_digest(&hmac_ctx, 32, output);
+
+      return 0;
+      }''', dependencies: nettle)
+      crypto_sm3 = not_found
+    endif
   endif
 endif

@@ -2229,6 +2266,7 @@  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_CRYPTO_SM3', crypto_sm3.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)
@@ -4306,6 +4344,7 @@  if nettle.found()
    summary_info += {'  XTS':             xts != 'private'}
 endif
 summary_info += {'SM4 ALG support':   crypto_sm4}
+summary_info += {'SM3 ALG support':   crypto_sm3}
 summary_info += {'AF_ALG support':    have_afalg}
 summary_info += {'rng-none':          get_option('rng_none')}
 summary_info += {'Linux keyring':     have_keyring}
diff --git a/qapi/crypto.json b/qapi/crypto.json
index 2f2aeff5fd..af38f0a4bd 100644
--- a/qapi/crypto.json
+++ b/qapi/crypto.json
@@ -58,11 +58,13 @@ 
 #
 # @ripemd160: RIPEMD-160. (since 2.7)
 #
+# @sm3: SM3. (since 8.2.0)
+#
 # Since: 2.6
 ##
 { 'enum': 'QCryptoHashAlgorithm',
   'prefix': 'QCRYPTO_HASH_ALG',
-  'data': ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
'ripemd160']}
+  'data': ['md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512',
'ripemd160', 'sm3']}

 ##
 # @QCryptoCipherAlgorithm:
diff --git a/tests/unit/test-crypto-hash.c b/tests/unit/test-crypto-hash.c
index 1f4abb822b..61908e1769 100644
--- a/tests/unit/test-crypto-hash.c
+++ b/tests/unit/test-crypto-hash.c
@@ -42,6 +42,9 @@ 
                       "63b54e4cb2d2032b393994aa263c0dbb" \
                       "e00a9f2fe9ef6037352232a1eec55ee7"
 #define OUTPUT_RIPEMD160 "f3d658fad3fdfb2b52c9369cf0d441249ddfa8a0"
+#ifdef CONFIG_CRYPTO_SM3
+#define OUTPUT_SM3
"d4a97db105b477b84c4f20ec9c31a6c814e2705a0b83a5a89748d75f0ef456a1"
+#endif

 #define OUTPUT_MD5_B64 "Yo0gY3FWMDWrjvYvSSveyQ=="
 #define OUTPUT_SHA1_B64 "sudPJnWKOkIeUJzuBFJEt4dTzAI="
@@ -54,6 +57,10 @@ 
                           "7sVe5w=="
 #define OUTPUT_RIPEMD160_B64 "89ZY+tP9+ytSyTac8NRBJJ3fqKA="

+#ifdef CONFIG_CRYPTO_SM3
+#define OUTPUT_SM3_B64 "1Kl9sQW0d7hMTyDsnDGmyBTicFoLg6Wol0jXXw70VqE="
+#endif
+
 static const char *expected_outputs[] = {
     [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5,
     [QCRYPTO_HASH_ALG_SHA1] = OUTPUT_SHA1,
@@ -62,6 +69,9 @@  static const char *expected_outputs[] = {
     [QCRYPTO_HASH_ALG_SHA384] = OUTPUT_SHA384,
     [QCRYPTO_HASH_ALG_SHA512] = OUTPUT_SHA512,
     [QCRYPTO_HASH_ALG_RIPEMD160] = OUTPUT_RIPEMD160,
+#ifdef CONFIG_CRYPTO_SM3
+    [QCRYPTO_HASH_ALG_SM3] = OUTPUT_SM3,
+#endif
 };
 static const char *expected_outputs_b64[] = {
     [QCRYPTO_HASH_ALG_MD5] = OUTPUT_MD5_B64,
@@ -71,6 +81,9 @@  static const char *expected_outputs_b64[] = {
     [QCRYPTO_HASH_ALG_SHA384] = OUTPUT_SHA384_B64,
     [QCRYPTO_HASH_ALG_SHA512] = OUTPUT_SHA512_B64,
     [QCRYPTO_HASH_ALG_RIPEMD160] = OUTPUT_RIPEMD160_B64,
+#ifdef CONFIG_CRYPTO_SM3
+    [QCRYPTO_HASH_ALG_SM3] = OUTPUT_SM3_B64,
+#endif
 };
 static const int expected_lens[] = {
     [QCRYPTO_HASH_ALG_MD5] = 16,
@@ -80,6 +93,9 @@  static const int expected_lens[] = {
     [QCRYPTO_HASH_ALG_SHA384] = 48,
     [QCRYPTO_HASH_ALG_SHA512] = 64,
     [QCRYPTO_HASH_ALG_RIPEMD160] = 20,
+#ifdef CONFIG_CRYPTO_SM3
+    [QCRYPTO_HASH_ALG_SM3] = 32,
+#endif
 };

 static const char hex[] = "0123456789abcdef";
diff --git a/tests/unit/test-crypto-hmac.c b/tests/unit/test-crypto-hmac.c
index 23eb724d94..b1d04e9fcc 100644
--- a/tests/unit/test-crypto-hmac.c
+++ b/tests/unit/test-crypto-hmac.c
@@ -76,6 +76,14 @@  static QCryptoHmacTestData test_data[] = {
             "94964ed4c1155b62b668c241d67279e5"
             "8a711676",
     },
+#ifdef CONFIG_CRYPTO_SM3
+    {
+        .alg = QCRYPTO_HASH_ALG_SM3,
+        .hex_digest =
+            "760e3799332bc913819b930085360ddb"
+    "c05529261313d5b15b75bab4fd7ae91e",
+    },
+#endif
 };

 static const char hex[] = "0123456789abcdef";
diff --git a/tests/unit/test-crypto-pbkdf.c b/tests/unit/test-crypto-pbkdf.c
index 43c417f6b4..3d76593c86 100644
--- a/tests/unit/test-crypto-pbkdf.c
+++ b/tests/unit/test-crypto-pbkdf.c
@@ -326,6 +326,22 @@  static QCryptoPbkdfTestData test_data[] = {
                "\xce\xbf\x91\x14\x8b\x5c\x48\x41",
         .nout = 32
     },
+#ifdef CONFIG_CRYPTO_SM3
+    {
+        .path = "/crypto/pbkdf/nonrfc/sm3/iter2",
+        .hash = QCRYPTO_HASH_ALG_SM3,
+        .iterations = 2,
+        .key = "password",
+        .nkey = 8,
+        .salt = "ATHENA.MIT.EDUraeburn",
+        .nsalt = 21,
+        .out = "\x48\x71\x1b\x58\xa3\xcb\xce\x06"
+ "\xba\xad\x77\xa8\xb5\xb9\xd8\x07"
+ "\x6a\xe2\xb3\x5b\x95\xce\xc8\xce"
+ "\xe7\xb1\xcb\xee\x61\xdf\x04\xea",
+        .nout = 32
+    },
+#endif
 #if 0
     {
         .path = "/crypto/pbkdf/nonrfc/whirlpool/iter1200",