From 3f0688642317b6385329aa593af933d0bdc2974c Mon Sep 17 00:00:00 2001
From: river <314264452@qq.com>
Date: Fri, 29 Oct 2021 12:05:57 +0800
Subject: [PATCH] sm3

---
 configure.ac      |   9 +++
 etc/login.defs    |  17 +++++
 lib/encrypt.c     |   3 +
 lib/getdef.c      |   4 ++
 libmisc/obscure.c |   3 +
 libmisc/salt.c    |  77 ++++++++++++++++++++--
 src/chgpasswd.c   | 155 +++++++++++++++++++++++++++++++++++++------
 src/chpasswd.c    | 147 +++++++++++++++++++++++++++++++++++------
 src/newusers.c    | 193 +++++++++++++++++++++++++++++++++++++++++++++++-------
 src/passwd.c      |   3 +
 10 files changed, 543 insertions(+), 68 deletions(-)

diff --git a/configure.ac b/configure.ac
index e4c6aae..e51417e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -277,6 +277,9 @@ AC_ARG_WITH(libcrack,
 AC_ARG_WITH(sha-crypt,
 	[AC_HELP_STRING([--with-sha-crypt], [allow the SHA256 and SHA512 password encryption algorithms @<:@default=yes@:>@])],
 	[with_sha_crypt=$withval], [with_sha_crypt=yes])
+AC_ARG_WITH(sm3-crypt,
+	[AC_HELP_STRING([--with-sm3-crypt], [allow the SM3 password encryption algorithms @<:@default=yes@:>@])],
+	[with_sm3_crypt=$withval], [with_sm3_crypt=yes])
 AC_ARG_WITH(bcrypt,
 	[AC_HELP_STRING([--with-bcrypt], [allow the bcrypt password encryption algorithm @<:@default=no@:>@])],
 	[with_bcrypt=$withval], [with_bcrypt=no])
@@ -307,6 +310,11 @@ if test "$with_sha_crypt" = "yes"; then
 	AC_DEFINE(USE_SHA_CRYPT, 1, [Define to allow the SHA256 and SHA512 password encryption algorithms])
 fi
 
+AM_CONDITIONAL(USE_SM3_CRYPT, test "x$with_sm3_crypt" = "xyes")
+if test "$with_sm3_crypt" = "yes"; then
+	AC_DEFINE(USE_SM3_CRYPT, 1, [Define to allow the SM3 password encryption algorithms])
+fi
+
 AM_CONDITIONAL(USE_BCRYPT, test "x$with_bcrypt" = "xyes")
 if test "$with_bcrypt" = "yes"; then
 	AC_DEFINE(USE_BCRYPT, 1, [Define to allow the bcrypt password encryption algorithm])
@@ -740,6 +748,7 @@ echo "	tcb support (incomplete):	$with_tcb"
 echo "	shadow group support:		$enable_shadowgrp"
 echo "	S/Key support:			$with_skey"
 echo "	SHA passwords encryption:	$with_sha_crypt"
+echo "	SM3 passwords encryption:	$with_sm3_crypt"
 echo "	bcrypt passwords encryption:	$with_bcrypt"
 echo "	nscd support:			$with_nscd"
 echo "	sssd support:			$with_sssd"
diff --git a/etc/login.defs b/etc/login.defs
index a2f8cd5..9f66ebf 100644
--- a/etc/login.defs
+++ b/etc/login.defs
@@ -351,6 +351,23 @@ CHFN_RESTRICT		rwh
 #SHA_CRYPT_MAX_ROUNDS 5000
 
 #
+# Only works if ENCRYPT_METHOD is set to SM3.
+#
+# Define the number of SM3 rounds.
+# With a lot of rounds, it is more difficult to brute-force the password.
+# However, more CPU resources will be needed to authenticate users if
+# this value is increased.
+#
+# If not specified, the libc will choose the default number of rounds (5000),
+# which is orders of magnitude too low for modern hardware.
+# The values must be within the 1000-999999999 range.
+# If only one of the MIN or MAX values is set, then this value will be used.
+# If MIN > MAX, the highest value will be used.
+#
+#SM3_CRYPT_MAX_ROUNDS 5000
+#SM3_CRYPT_MIN_ROUNDS 5000
+
+#
 # Only works if ENCRYPT_METHOD is set to BCRYPT.
 #
 # Define the number of BCRYPT rounds.
diff --git a/lib/encrypt.c b/lib/encrypt.c
index 4247f24..5a14c99 100644
--- a/lib/encrypt.c
+++ b/lib/encrypt.c
@@ -74,6 +74,9 @@
 			case '6':
 				method = "SHA512";
 				break;
+			case 's':   // salt = $sm3$...
+				method = "SM3";
+				break;
 			default:
 			{
 				static char nummethod[4] = "$x$";
diff --git a/lib/getdef.c b/lib/getdef.c
index 00f6abf..f3171f3 100644
--- a/lib/getdef.c
+++ b/lib/getdef.c
@@ -112,6 +112,10 @@ static struct itemdef def_table[] = {
 	{"SHA_CRYPT_MAX_ROUNDS", NULL},
 	{"SHA_CRYPT_MIN_ROUNDS", NULL},
 #endif
+#ifdef USE_SM3_CRYPT
+	{"SM3_CRYPT_MAX_ROUNDS", NULL},
+	{"SM3_CRYPT_MIN_ROUNDS", NULL},
+#endif
 #ifdef USE_BCRYPT
 	{"BCRYPT_MAX_ROUNDS", NULL},
 	{"BCRYPT_MIN_ROUNDS", NULL},
diff --git a/libmisc/obscure.c b/libmisc/obscure.c
index 15da760..2067602 100644
--- a/libmisc/obscure.c
+++ b/libmisc/obscure.c
@@ -269,6 +269,9 @@ static /*@observer@*//*@null@*/const char *obscure_msg (
 		    || (strcmp (result, "SHA256") == 0)
 		    || (strcmp (result, "SHA512") == 0)
 #endif
+#ifdef USE_SM3_CRYPT
+		    || (strcmp (result, "SM3") == 0)
+#endif
 #ifdef USE_BCRYPT
 		    || (strcmp (result, "BCRYPT") == 0)
 #endif
diff --git a/libmisc/salt.c b/libmisc/salt.c
index e1a7ac8..da4fb11 100644
--- a/libmisc/salt.c
+++ b/libmisc/salt.c
@@ -22,12 +22,15 @@
 /* local function prototypes */
 static void seedRNG (void);
 static /*@observer@*/const char *gensalt (size_t salt_size);
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 static long shadow_random (long min, long max);
-#endif /* USE_SHA_CRYPT || USE_BCRYPT */
+#endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_SM3_CRYPT*/
 #ifdef USE_SHA_CRYPT
 static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds);
 #endif /* USE_SHA_CRYPT */
+#ifdef USE_SM3_CRYPT
+static /*@observer@*/const char *SM3_salt_rounds (/*@null@*/int *prefered_rounds);
+#endif
 #ifdef USE_BCRYPT
 static /*@observer@*/const char *gensalt_bcrypt (void);
 static /*@observer@*/const char *BCRYPT_salt_rounds (/*@null@*/int *prefered_rounds);
@@ -94,7 +97,7 @@ static void seedRNG (void)
 #define BCRYPTMAGNUM(array)	(array)[0]=(array)[3]='$',(array)[1]='2',(array)[2]='a',(array)[4]='\0'
 #endif /* USE_BCRYPT */
 
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 /* It is not clear what is the maximum value of random().
  * We assume 2^31-1.*/
 #define RANDOM_MAX 0x7FFFFFFF
@@ -119,15 +122,18 @@ static long shadow_random (long min, long max)
 	}
 	return ret;
 }
-#endif /* USE_SHA_CRYPT || USE_BCRYPT */
+#endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_SM3_CRYPT*/
 
-#ifdef USE_SHA_CRYPT
+#if defined(USE_SHA_CRYPT) || defined(USE_SM3_CRYPT)
 /* Default number of rounds if not explicitly specified.  */
 #define ROUNDS_DEFAULT 5000
 /* Minimum number of rounds.  */
 #define ROUNDS_MIN 1000
 /* Maximum number of rounds.  */
 #define ROUNDS_MAX 999999999
+#endif
+
+#ifdef USE_SHA_CRYPT
 /*
  * Return a salt prefix specifying the rounds number for the SHA crypt methods.
  */
@@ -180,6 +186,57 @@ static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds
 }
 #endif /* USE_SHA_CRYPT */
 
+#ifdef USE_SM3_CRYPT
+static /*@observer@*/const char *SM3_salt_rounds (/*@null@*/int *prefered_rounds)
+{
+	static char rounds_prefix[18]; /* Max size: rounds=999999999$ */
+	long rounds;
+
+	if (NULL == prefered_rounds) {
+		long min_rounds = getdef_long ("SM3_CRYPT_MIN_ROUNDS", -1);
+		long max_rounds = getdef_long ("SM3_CRYPT_MAX_ROUNDS", -1);
+
+		if ((-1 == min_rounds) && (-1 == max_rounds)) {
+			return "";
+		}
+
+		if (-1 == min_rounds) {
+			min_rounds = max_rounds;
+		}
+
+		if (-1 == max_rounds) {
+			max_rounds = min_rounds;
+		}
+
+		if (min_rounds > max_rounds) {
+			max_rounds = min_rounds;
+		}
+
+		rounds = shadow_random (min_rounds, max_rounds);
+	} else if (0 == *prefered_rounds) {
+		return "";
+	} else {
+		rounds = *prefered_rounds;
+	}
+
+	/* Sanity checks. The libc should also check this, but this
+	 * protects against a rounds_prefix overflow. */
+	if (rounds < ROUNDS_MIN) {
+		rounds = ROUNDS_MIN;
+	}
+
+	if (rounds > ROUNDS_MAX) {
+		rounds = ROUNDS_MAX;
+	}
+
+	(void) snprintf (rounds_prefix, sizeof rounds_prefix,
+	                 "rounds=%ld$", rounds);
+
+	return rounds_prefix;
+}
+#endif /* USE_SM3_CRYPT */
+
+
 #ifdef USE_BCRYPT
 /* Default number of rounds if not explicitly specified.  */
 #define B_ROUNDS_DEFAULT 13
@@ -300,12 +357,12 @@ static /*@observer@*/const char *gensalt (size_t salt_size)
  * ENCRYPT_METHOD login.defs variables.
  *
  * If meth is specified, an additional parameter can be provided.
- *  * For the SHA256 and SHA512 method, this specifies the number of rounds
+ *  * For the SHA256 and SHA512 and SM3 method, this specifies the number of rounds
  *    (if not NULL).
  */
 /*@observer@*/const char *crypt_make_salt (/*@null@*//*@observer@*/const char *meth, /*@null@*/void *arg)
 {
-	/* Max result size for the SHA methods:
+	/* Max result size for the SHA and SM3 methods:
 	 *  +3		$5$
 	 *  +17		rounds=999999999$
 	 *  +16		salt
@@ -343,6 +400,12 @@ static /*@observer@*/const char *gensalt (size_t salt_size)
 		strcat(result, SHA_salt_rounds((int *)arg));
 		salt_len = (size_t) shadow_random (8, 16);
 #endif /* USE_SHA_CRYPT */
+#ifdef USE_SM3_CRYPT
+	} else if (0 == strcmp (method, "SM3")) {
+		strcpy(result, "$sm3$");
+		strcat(result, SM3_salt_rounds((int *)arg));
+		salt_len = (size_t) shadow_random (8, 16);
+#endif /* USE_SM3_CRYPT */
 	} else if (0 != strcmp (method, "DES")) {
 		fprintf (stderr,
 			 _("Invalid ENCRYPT_METHOD value: '%s'.\n"
diff --git a/src/chgpasswd.c b/src/chgpasswd.c
index 4013abb..05dd6de 100644
--- a/src/chgpasswd.c
+++ b/src/chgpasswd.c
@@ -61,15 +61,20 @@
 const char *Prog;
 static bool eflg   = false;
 static bool md5flg = false;
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 static bool sflg   = false;
-#endif /* USE_SHA_CRYPT || USE_BCRYPT */
+#endif /* USE_SHA_CRYPT || USE_BCRYPT || USE_SM3_CRYPT */
 
 static /*@null@*//*@observer@*/const char *crypt_method = NULL;
 #define cflg (NULL != crypt_method)
 #ifdef USE_SHA_CRYPT
 static long sha_rounds = 5000;
 #endif
+
+#ifdef USE_SM3_CRYPT
+static long sm3_rounds = 5000;
+#endif
+
 #ifdef USE_BCRYPT
 static long bcrypt_rounds = 13;
 #endif
@@ -128,12 +133,20 @@ static /*@noreturn@*/void usage (int status)
 	                Prog);
 	(void) fprintf (usageout,
 	                _("  -c, --crypt-method METHOD     the crypt method (one of %s)\n"),
-#if !defined(USE_SHA_CRYPT) && !defined(USE_BCRYPT)
+#if !defined(USE_SHA_CRYPT) && !defined(USE_BCRYPT) && !defined(USE_SM3_CRYPT)
 	                "NONE DES MD5"
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 SHA256 SHA512 BCRYPT SM3"
 #elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
 	                "NONE DES MD5 SHA256 SHA512 BCRYPT"
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 SHA256 SHA512 SM3"
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 BCRYPT SM3"
 #elif defined(USE_SHA_CRYPT)
 	                "NONE DES MD5 SHA256 SHA512"
+#elif defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 SM3"
 #else
 	                "NONE DES MD5 BCRYPT"
 #endif
@@ -144,11 +157,11 @@ static /*@noreturn@*/void usage (int status)
 	                "                                the MD5 algorithm\n"),
 	              usageout);
 	(void) fputs (_("  -R, --root CHROOT_DIR         directory to chroot into\n"), usageout);
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
-	(void) fputs (_("  -s, --sha-rounds              number of rounds for the SHA or BCRYPT\n"
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
+	(void) fputs (_("  -s, --sha-rounds              number of rounds for the SHA, BCRYPT or SM3\n"
 	                "                                crypt algorithms\n"),
 	              usageout);
-#endif				/* USE_SHA_CRYPT || USE_BCRYPT */
+#endif				/* USE_SHA_CRYPT || USE_BCRYPT  || USE_SM3_CRYPT*/
 	(void) fputs ("\n", usageout);
 
 	exit (status);
@@ -168,13 +181,13 @@ static void process_flags (int argc, char **argv)
 		{"help",         no_argument,       NULL, 'h'},
 		{"md5",          no_argument,       NULL, 'm'},
 		{"root",         required_argument, NULL, 'R'},
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 		{"sha-rounds",   required_argument, NULL, 's'},
-#endif				/* USE_SHA_CRYPT || USE_BCRYPT */
+#endif				/* USE_SHA_CRYPT || USE_BCRYPT || USE_SM3_CRYPT */
 		{NULL, 0, NULL, '\0'}
 	};
 	while ((c = getopt_long (argc, argv,
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 	                         "c:ehmR:s:",
 #else
 	                         "c:ehmR:",
@@ -195,17 +208,70 @@ static void process_flags (int argc, char **argv)
 			break;
 		case 'R': /* no-op, handled in process_root_flag () */
 			break;
-#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
 		case 's':
 			sflg = true;
-			if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
-			       && (0 == getlong(optarg, &sha_rounds))) 
-			   || (   (0 == strcmp (crypt_method, "BCRYPT"))
-			       && (0 == getlong(optarg, &bcrypt_rounds)))) {
-				fprintf (stderr,
-				         _("%s: invalid numeric argument '%s'\n"),
-				         Prog, optarg);
-				usage (E_USAGE);
+			if (crypt_method != NULL) {
+				if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
+					&& (0 == getlong(optarg, &sha_rounds))) 
+				|| (   (0 == strcmp (crypt_method, "BCRYPT"))
+					&& (0 == getlong(optarg, &bcrypt_rounds)))
+				|| (   (0 == strcmp (crypt_method, "SM3"))
+					&& (0 == getlong(optarg, &sm3_rounds)))
+					) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (E_USAGE);
+				}	
+			}
+			break;
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+		case 's':
+			sflg = true;
+			if (crypt_method != NULL) {
+				if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
+					&& (0 == getlong(optarg, &sha_rounds))) 
+				|| (   (0 == strcmp (crypt_method, "BCRYPT"))
+					&& (0 == getlong(optarg, &bcrypt_rounds)))
+					) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (E_USAGE);
+				}
+			}
+			break;
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+		case 's':
+			sflg = true;
+			if (crypt_method != NULL) {
+				if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
+					&& (0 == getlong(optarg, &sha_rounds))) 
+				|| (   (0 == strcmp (crypt_method, "SM3"))
+					&& (0 == getlong(optarg, &sm3_rounds)))
+					) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (E_USAGE);
+				}	
+			}
+			break;
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+		case 's':
+			sflg = true;
+			if (crypt_method != NULL) {
+				if (   (   (0 == strcmp (crypt_method, "BCRYPT"))
+					&& (0 == getlong(optarg, &bcrypt_rounds)))
+				|| (   (0 == strcmp (crypt_method, "SM3"))
+					&& (0 == getlong(optarg, &sm3_rounds)))
+					) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (E_USAGE);
+				}	
 			}
 			break;
 #elif defined(USE_SHA_CRYPT)
@@ -228,6 +294,16 @@ static void process_flags (int argc, char **argv)
 				usage (E_USAGE);
 			}
 			break;
+#elif defined(USE_SM3_CRYPT)
+		case 's':
+			sflg = true;
+			if (0 == getlong(optarg, &sm3_rounds)) { 
+				fprintf (stderr,
+				         _("%s: invalid numeric argument '%s'\n"),
+				         Prog, optarg);
+				usage (E_USAGE);
+			}
+			break;
 #endif
 
 		default:
@@ -247,7 +323,7 @@ static void process_flags (int argc, char **argv)
  */
 static void check_flags (void)
 {
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 	if (sflg && !cflg) {
 		fprintf (stderr,
 		         _("%s: %s flag is only allowed with the %s flag\n"),
@@ -272,6 +348,9 @@ static void check_flags (void)
 		    && (0 != strcmp (crypt_method, "SHA256"))
 		    && (0 != strcmp (crypt_method, "SHA512"))
 #endif
+#ifdef USE_SM3_CRYPT
+			&& (0 != strcmp (crypt_method, "SM3"))
+#endif
 #ifdef USE_BCRYPT
 		    && (0 != strcmp (crypt_method, "BCRYPT"))
 #endif
@@ -497,7 +576,20 @@ int main (int argc, char **argv)
 			if (md5flg) {
 				crypt_method = "MD5";
 			}
-#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+			if (sflg) {
+				if (   (0 == strcmp (crypt_method, "SHA256"))
+					|| (0 == strcmp (crypt_method, "SHA512"))) {
+					arg = &sha_rounds;
+				}
+				else if (0 == strcmp (crypt_method, "BCRYPT")) {
+					arg = &bcrypt_rounds;
+				}
+				else if (0 == strcmp (crypt_method, "SM3")) {
+					arg = &sm3_rounds;
+				}
+			}
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
 			if (sflg) {
 				if (   (0 == strcmp (crypt_method, "SHA256"))
 					|| (0 == strcmp (crypt_method, "SHA512"))) {
@@ -507,6 +599,25 @@ int main (int argc, char **argv)
 					arg = &bcrypt_rounds;
 				}
 			}
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+			if (sflg) {
+				if (   (0 == strcmp (crypt_method, "SHA256"))
+					|| (0 == strcmp (crypt_method, "SHA512"))) {
+					arg = &sha_rounds;
+				}
+				else if (0 == strcmp (crypt_method, "SM3")) {
+					arg = &sm3_rounds;
+				}
+			}
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+			if (sflg) {
+				if (0 == strcmp (crypt_method, "BCRYPT")) {
+					arg = &bcrypt_rounds;
+				}
+				else if (0 == strcmp (crypt_method, "SM3")) {
+					arg = &sm3_rounds;
+				}
+			}
 #elif defined(USE_SHA_CRYPT)
 			if (sflg) {
 				arg = &sha_rounds;
@@ -515,6 +626,10 @@ int main (int argc, char **argv)
 			if (sflg) {
 				arg = &bcrypt_rounds;
 			}
+#elif defined(USE_SM3_CRYPT)
+			if (sflg) {
+				arg = &sm3_rounds;
+			}
 #endif
 			salt = crypt_make_salt (crypt_method, arg);
 			cp = pw_encrypt (newpwd, salt);
diff --git a/src/chpasswd.c b/src/chpasswd.c
index be61e03..76fb562 100644
--- a/src/chpasswd.c
+++ b/src/chpasswd.c
@@ -58,7 +58,7 @@
 const char *Prog;
 static bool eflg   = false;
 static bool md5flg = false;
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 static bool sflg   = false;
 #endif
 
@@ -67,6 +67,9 @@ static /*@null@*//*@observer@*/const char *crypt_method = NULL;
 #ifdef USE_SHA_CRYPT
 static long sha_rounds = 5000;
 #endif
+#ifdef USE_SM3_CRYPT
+static long sm3_rounds = 5000;
+#endif
 #ifdef USE_BCRYPT
 static long bcrypt_rounds = 13;
 #endif
@@ -121,12 +124,20 @@ static /*@noreturn@*/void usage (int status)
 	                Prog);
 	(void) fprintf (usageout,
 	                _("  -c, --crypt-method METHOD     the crypt method (one of %s)\n"),
-#if !defined(USE_SHA_CRYPT) && !defined(USE_BCRYPT)
+#if !defined(USE_SHA_CRYPT) && !defined(USE_BCRYPT) && !defined(USE_SM3_CRYPT)
 	                "NONE DES MD5"
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 SHA256 SHA512 BCRYPT SM3"
 #elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
 	                "NONE DES MD5 SHA256 SHA512 BCRYPT"
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 SHA256 SHA512 SM3"
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 BCRYPT SM3"
 #elif defined(USE_SHA_CRYPT)
 	                "NONE DES MD5 SHA256 SHA512"
+#elif defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 SM3"
 #else
 	                "NONE DES MD5 BCRYPT"
 #endif
@@ -137,11 +148,11 @@ static /*@noreturn@*/void usage (int status)
 	                "                                the MD5 algorithm\n"),
 	              usageout);
 	(void) fputs (_("  -R, --root CHROOT_DIR         directory to chroot into\n"), usageout);
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
-	(void) fputs (_("  -s, --sha-rounds              number of rounds for the SHA or BCRYPT\n"
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
+	(void) fputs (_("  -s, --sha-rounds              number of rounds for the SHA , BCRYPT or SM3\n"
 	                "                                crypt algorithms\n"),
 	              usageout);
-#endif				/* USE_SHA_CRYPT || USE_BCRYPT */
+#endif				/* USE_SHA_CRYPT || USE_BCRYPT || USE_SM3_CRYPT*/
 	(void) fputs ("\n", usageout);
 
 	exit (status);
@@ -161,14 +172,14 @@ static void process_flags (int argc, char **argv)
 		{"help",         no_argument,       NULL, 'h'},
 		{"md5",          no_argument,       NULL, 'm'},
 		{"root",         required_argument, NULL, 'R'},
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 		{"sha-rounds",   required_argument, NULL, 's'},
-#endif				/* USE_SHA_CRYPT || USE_BCRYPT */
+#endif				/* USE_SHA_CRYPT || USE_BCRYPT || USE_SM3_CRYPT*/
 		{NULL, 0, NULL, '\0'}
 	};
 
 	while ((c = getopt_long (argc, argv,
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 	                         "c:ehmR:s:",
 #else
 	                         "c:ehmR:",
@@ -189,17 +200,66 @@ static void process_flags (int argc, char **argv)
 			break;
 		case 'R': /* no-op, handled in process_root_flag () */
 			break;
-#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
 		case 's':
 			sflg = true;
-			if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
-			       && (0 == getlong(optarg, &sha_rounds))) 
-			   || (   (0 == strcmp (crypt_method, "BCRYPT"))
-			       && (0 == getlong(optarg, &bcrypt_rounds)))) {
-				fprintf (stderr,
-				         _("%s: invalid numeric argument '%s'\n"),
-				         Prog, optarg);
-				usage (E_USAGE);
+			if (crypt_method != NULL) {
+				if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
+					&& (0 == getlong(optarg, &sha_rounds))) 
+				|| (   (0 == strcmp (crypt_method, "BCRYPT"))
+					&& (0 == getlong(optarg, &bcrypt_rounds)))
+				|| (   (0 == strcmp (crypt_method, "SM3"))
+					&& (0 == getlong(optarg, &sm3_rounds)))) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (E_USAGE);
+				}	
+			}
+			break;
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+		case 's':
+			sflg = true;
+			if (crypt_method != NULL) {
+				if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
+					&& (0 == getlong(optarg, &sha_rounds))) 
+				|| (   (0 == strcmp (crypt_method, "BCRYPT"))
+					&& (0 == getlong(optarg, &bcrypt_rounds)))) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (E_USAGE);
+				}	
+			}
+			break;
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+		case 's':
+			sflg = true;
+			if (crypt_method != NULL) {
+				if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
+					&& (0 == getlong(optarg, &sha_rounds))) 
+				|| (   (0 == strcmp (crypt_method, "SM3"))
+					&& (0 == getlong(optarg, &sm3_rounds)))) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (E_USAGE);
+				}	
+			}
+			break;
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+		case 's':
+			sflg = true;
+			if (crypt_method != NULL) {
+				if (  (   (0 == strcmp (crypt_method, "BCRYPT"))
+					&& (0 == getlong(optarg, &bcrypt_rounds)))
+				|| (   (0 == strcmp (crypt_method, "SM3"))
+					&& (0 == getlong(optarg, &sm3_rounds)))) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (E_USAGE);
+				}	
 			}
 			break;
 #elif defined(USE_SHA_CRYPT)
@@ -222,6 +282,16 @@ static void process_flags (int argc, char **argv)
 				usage (E_USAGE);
 			}
 			break;
+#elif defined(USE_SM3_CRYPT)
+		case 's':
+			sflg = true;
+			if (  0 == getlong(optarg, &sm3_rounds)) {
+				fprintf (stderr,
+				         _("%s: invalid numeric argument '%s'\n"),
+				         Prog, optarg);
+				usage (E_USAGE);
+			}
+			break;
 #endif
 
 		default:
@@ -241,7 +311,7 @@ static void process_flags (int argc, char **argv)
  */
 static void check_flags (void)
 {
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 	if (sflg && !cflg) {
 		fprintf (stderr,
 		         _("%s: %s flag is only allowed with the %s flag\n"),
@@ -266,6 +336,9 @@ static void check_flags (void)
 		    && (0 != strcmp (crypt_method, "SHA256"))
 		    && (0 != strcmp (crypt_method, "SHA512"))
 #endif				/* USE_SHA_CRYPT */
+#ifdef USE_SM3_CRYPT
+		    && (0 != strcmp (crypt_method, "SM3"))
+#endif				/* USE_SM3_CRYPT */
 #ifdef USE_BCRYPT
 		    && (0 != strcmp (crypt_method, "BCRYPT"))
 #endif				/* USE_BCRYPT */
@@ -530,7 +603,7 @@ int main (int argc, char **argv)
 			if (md5flg) {
 				crypt_method = "MD5";
 			}
-#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
 			if (sflg) {
 				if (   (0 == strcmp (crypt_method, "SHA256"))
 					|| (0 == strcmp (crypt_method, "SHA512"))) {
@@ -539,6 +612,38 @@ int main (int argc, char **argv)
 				else if (0 == strcmp (crypt_method, "BCRYPT")) {
 					arg = &bcrypt_rounds;
 				}
+				else if ( 0 == strcmp (crypt_method, "SM3")) {
+					arg = &sm3_rounds;
+				}
+			}
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) 
+			if (sflg) {
+				if (   (0 == strcmp (crypt_method, "SHA256"))
+					|| (0 == strcmp (crypt_method, "SHA512"))) {
+					arg = &sha_rounds;
+				}
+				else if (0 == strcmp (crypt_method, "BCRYPT")) {
+					arg = &bcrypt_rounds;
+				}
+			}
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+			if (sflg) {
+				if (   (0 == strcmp (crypt_method, "SHA256"))
+					|| (0 == strcmp (crypt_method, "SHA512"))) {
+					arg = &sha_rounds;
+				}
+				else if ( 0 == strcmp (crypt_method, "SM3")) {
+					arg = &sm3_rounds;
+				}
+			}
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+			if (sflg) {
+				if (0 == strcmp (crypt_method, "BCRYPT")) {
+					arg = &bcrypt_rounds;
+				}
+				else if ( 0 == strcmp (crypt_method, "SM3")) {
+					arg = &sm3_rounds;
+				}
 			}
 #elif defined(USE_SHA_CRYPT)
 			if (sflg) {
@@ -548,6 +653,10 @@ int main (int argc, char **argv)
 			if (sflg) {
 				arg = &bcrypt_rounds;
 			}
+#elif defined(USE_SM3_CRYPT) 
+			if (sflg) {
+				arg = &sm3_rounds;
+			}
 #endif
 			salt = crypt_make_salt (crypt_method, arg);
 			cp = pw_encrypt (newpwd, salt);
diff --git a/src/newusers.c b/src/newusers.c
index e9fe0e2..37b739f 100644
--- a/src/newusers.c
+++ b/src/newusers.c
@@ -80,12 +80,15 @@ static bool rflg = false;	/* create a system account */
 #ifndef USE_PAM
 static /*@null@*//*@observer@*/char *crypt_method = NULL;
 #define cflg (NULL != crypt_method)
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 static bool sflg = false;
 #endif
 #ifdef USE_SHA_CRYPT
 static long sha_rounds = 5000;
 #endif				/* USE_SHA_CRYPT */
+#ifdef USE_SM3_CRYPT
+static long sm3_rounds = 5000;
+#endif				/* USE_SM3_CRYPT */
 #ifdef USE_BCRYPT
 static long bcrypt_rounds = 13;
 #endif				/* USE_BCRYPT */
@@ -139,12 +142,20 @@ static void usage (int status)
 #ifndef USE_PAM
 	(void) fprintf (usageout,
 	                _("  -c, --crypt-method METHOD     the crypt method (one of %s)\n"),
-#if !defined(USE_SHA_CRYPT) && !defined(USE_BCRYPT)
+#if !defined(USE_SHA_CRYPT) && !defined(USE_BCRYPT) && !defined(USE_SM3_CRYPT)
 	                "NONE DES MD5"
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 SHA256 SHA512 BCRYPT SM3"
 #elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
 	                "NONE DES MD5 SHA256 SHA512 BCRYPT"
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 SHA256 SHA512 SM3"
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 BCRYPT SM3"
 #elif defined(USE_SHA_CRYPT)
 	                "NONE DES MD5 SHA256 SHA512"
+#elif defined(USE_SM3_CRYPT)
+	                "NONE DES MD5 SM3"
 #else
 	                "NONE DES MD5 BCRYPT"
 #endif
@@ -154,11 +165,11 @@ static void usage (int status)
 	(void) fputs (_("  -r, --system                  create system accounts\n"), usageout);
 	(void) fputs (_("  -R, --root CHROOT_DIR         directory to chroot into\n"), usageout);
 #ifndef USE_PAM
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
-	(void) fputs (_("  -s, --sha-rounds              number of rounds for the SHA or BCRYPT\n"
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
+	(void) fputs (_("  -s, --sha-rounds              number of rounds for the SHA , BCRYPT or SM3\n"
 	                "                                crypt algorithms\n"),
 	              usageout);
-#endif				/* USE_SHA_CRYPT || USE_BCRYPT */
+#endif				/* USE_SHA_CRYPT || USE_BCRYPT || USE_SM3_CRYPT*/
 #endif				/* !USE_PAM */
 	(void) fputs ("\n", usageout);
 
@@ -433,7 +444,7 @@ static int update_passwd (struct passwd *pwd, const char *password)
 	void *crypt_arg = NULL;
 	char *cp;
 	if (NULL != crypt_method) {
-#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
 		if (sflg) {
 			if (   (0 == strcmp (crypt_method, "SHA256"))
 				|| (0 == strcmp (crypt_method, "SHA512"))) {
@@ -442,6 +453,38 @@ static int update_passwd (struct passwd *pwd, const char *password)
 			else if (0 == strcmp (crypt_method, "BCRYPT")) {
 				crypt_arg = &bcrypt_rounds;
 			}
+			else if (0 == strcmp (crypt_method, "SM3")) {
+				crypt_arg = &sm3_rounds;
+			}
+		}
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+		if (sflg) {
+			if (   (0 == strcmp (crypt_method, "SHA256"))
+				|| (0 == strcmp (crypt_method, "SHA512"))) {
+				crypt_arg = &sha_rounds;
+			}
+			else if (0 == strcmp (crypt_method, "BCRYPT")) {
+				crypt_arg = &bcrypt_rounds;
+			}
+		}
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+		if (sflg) {
+			if (   (0 == strcmp (crypt_method, "SHA256"))
+				|| (0 == strcmp (crypt_method, "SHA512"))) {
+				crypt_arg = &sha_rounds;
+			}
+			else if (0 == strcmp (crypt_method, "SM3")) {
+				crypt_arg = &sm3_rounds;
+			}
+		}
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+		if (sflg) {
+			if (0 == strcmp (crypt_method, "BCRYPT")) {
+				crypt_arg = &bcrypt_rounds;
+			}
+			else if (0 == strcmp (crypt_method, "SM3")) {
+				crypt_arg = &sm3_rounds;
+			}
 		}
 #elif defined(USE_SHA_CRYPT)
 		if (sflg) {
@@ -451,6 +494,10 @@ static int update_passwd (struct passwd *pwd, const char *password)
 		if (sflg) {
 			crypt_arg = &bcrypt_rounds;
 		}
+#elif defined(USE_SM3_CRYPT)
+		if (sflg) {
+			crypt_arg = &sm3_rounds;
+		}
 #endif
 	}
 
@@ -484,7 +531,20 @@ static int add_passwd (struct passwd *pwd, const char *password)
 #ifndef USE_PAM
 	void *crypt_arg = NULL;
 	if (NULL != crypt_method) {
-#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+		if (sflg) {
+			if (   (0 == strcmp (crypt_method, "SHA256"))
+				|| (0 == strcmp (crypt_method, "SHA512"))) {
+				crypt_arg = &sha_rounds;
+			}
+			else if (0 == strcmp (crypt_method, "BCRYPT")) {
+				crypt_arg = &bcrypt_rounds;
+			}
+			else if (0 == strcmp (crypt_method, "SM3")) {
+				crypt_arg = &sm3_rounds;
+			}
+		}
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
 		if (sflg) {
 			if (   (0 == strcmp (crypt_method, "SHA256"))
 				|| (0 == strcmp (crypt_method, "SHA512"))) {
@@ -494,6 +554,25 @@ static int add_passwd (struct passwd *pwd, const char *password)
 				crypt_arg = &bcrypt_rounds;
 			}
 		}
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+		if (sflg) {
+			if (   (0 == strcmp (crypt_method, "SHA256"))
+				|| (0 == strcmp (crypt_method, "SHA512"))) {
+				crypt_arg = &sha_rounds;
+			}
+			else if (0 == strcmp (crypt_method, "SM3")) {
+				crypt_arg = &sm3_rounds;
+			}
+		}
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+		if (sflg) {
+			if (0 == strcmp (crypt_method, "BCRYPT")) {
+				crypt_arg = &bcrypt_rounds;
+			}
+			else if (0 == strcmp (crypt_method, "SM3")) {
+				crypt_arg = &sm3_rounds;
+			}
+		}
 #elif defined(USE_SHA_CRYPT)
 		if (sflg) {
 			crypt_arg = &sha_rounds;
@@ -502,6 +581,10 @@ static int add_passwd (struct passwd *pwd, const char *password)
 		if (sflg) {
 			crypt_arg = &bcrypt_rounds;
 		}
+#elif defined(USE_SM3_CRYPT)
+		if (sflg) {
+			crypt_arg = &sm3_rounds;
+		}
 #endif
 	}
 
@@ -628,20 +711,20 @@ static void process_flags (int argc, char **argv)
 		{"system",       no_argument,       NULL, 'r'},
 		{"root",         required_argument, NULL, 'R'},
 #ifndef USE_PAM
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 		{"sha-rounds",   required_argument, NULL, 's'},
-#endif				/* USE_SHA_CRYPT || USE_BCRYPT */
+#endif				/* USE_SHA_CRYPT || USE_BCRYPT || USE_SM3_CRYPT*/
 #endif				/* !USE_PAM */
 		{NULL, 0, NULL, '\0'}
 	};
 
 	while ((c = getopt_long (argc, argv,
 #ifndef USE_PAM
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 	                         "c:bhrs:",
-#else				/* !USE_SHA_CRYPT && !USE_BCRYPT */
+#else				/* !USE_SHA_CRYPT && !USE_BCRYPT && !USE_SHA_CRYPT*/
 	                         "c:bhr",
-#endif				/* USE_SHA_CRYPT || USE_BCRYPT */
+#endif				/* USE_SHA_CRYPT || USE_BCRYPT || USE_SHA_CRYPT*/
 #else				/* USE_PAM */
 	                         "bhr",
 #endif
@@ -664,17 +747,70 @@ static void process_flags (int argc, char **argv)
 		case 'R': /* no-op, handled in process_root_flag () */
 			break;
 #ifndef USE_PAM
-#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) && defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
 		case 's':
 			sflg = true;
-			if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
-			       && (0 == getlong(optarg, &sha_rounds))) 
-			   || (   (0 == strcmp (crypt_method, "BCRYPT"))
-			       && (0 == getlong(optarg, &bcrypt_rounds)))) {
-				fprintf (stderr,
-				         _("%s: invalid numeric argument '%s'\n"),
-				         Prog, optarg);
-				usage (EXIT_FAILURE);
+			if (crypt_method != NULL) {
+				if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
+					&& (0 == getlong(optarg, &sha_rounds))) 
+				|| (   (0 == strcmp (crypt_method, "BCRYPT"))
+					&& (0 == getlong(optarg, &bcrypt_rounds)))
+				|| (   (0 == strcmp (crypt_method, "SM3"))
+					&& (0 == getlong(optarg, &sm3_rounds)))
+					) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (EXIT_FAILURE);
+				}				
+			}
+			break;
+#elif defined(USE_SHA_CRYPT) && defined(USE_BCRYPT)
+		case 's':
+			sflg = true;
+			if (crypt_method != NULL) {
+				if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
+					&& (0 == getlong(optarg, &sha_rounds))) 
+				|| (   (0 == strcmp (crypt_method, "BCRYPT"))
+					&& (0 == getlong(optarg, &bcrypt_rounds)))
+					) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (EXIT_FAILURE);
+				}	
+			}
+			break;
+#elif defined(USE_SHA_CRYPT) && defined(USE_SM3_CRYPT)
+		case 's':
+			sflg = true;
+			if (crypt_method != NULL) {
+				if (  (   ((0 == strcmp (crypt_method, "SHA256")) || (0 == strcmp (crypt_method, "SHA512")))
+					&& (0 == getlong(optarg, &sha_rounds))) 
+				|| (   (0 == strcmp (crypt_method, "SM3"))
+					&& (0 == getlong(optarg, &sm3_rounds)))
+					) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (EXIT_FAILURE);
+				}	
+			}
+			break;
+#elif defined(USE_BCRYPT) && defined(USE_SM3_CRYPT)
+		case 's':
+			sflg = true;
+			if (crypt_method != NULL) {
+				if (  (   (0 == strcmp (crypt_method, "BCRYPT"))
+					&& (0 == getlong(optarg, &bcrypt_rounds)))
+				|| (   (0 == strcmp (crypt_method, "SM3"))
+					&& (0 == getlong(optarg, &sm3_rounds)))
+					) {
+					fprintf (stderr,
+							_("%s: invalid numeric argument '%s'\n"),
+							Prog, optarg);
+					usage (EXIT_FAILURE);
+				}	
 			}
 			break;
 #elif defined(USE_SHA_CRYPT)
@@ -697,6 +833,16 @@ static void process_flags (int argc, char **argv)
 				usage (EXIT_FAILURE);
 			}
 			break;
+#elif defined(USE_SM3_CRYPT)
+		case 's':
+			sflg = true;
+			if (0 == getlong(optarg, &sm3_rounds)) { 
+				fprintf (stderr,
+				         _("%s: invalid numeric argument '%s'\n"),
+				         Prog, optarg);
+				usage (EXIT_FAILURE);
+			}
+			break;
 #endif
 #endif				/* !USE_PAM */
 		default:
@@ -731,7 +877,7 @@ static void process_flags (int argc, char **argv)
 static void check_flags (void)
 {
 #ifndef USE_PAM
-#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT)
+#if defined(USE_SHA_CRYPT) || defined(USE_BCRYPT) || defined(USE_SM3_CRYPT)
 	if (sflg && !cflg) {
 		fprintf (stderr,
 		         _("%s: %s flag is only allowed with the %s flag\n"),
@@ -748,6 +894,9 @@ static void check_flags (void)
 		    && (0 != strcmp (crypt_method, "SHA256"))
 		    && (0 != strcmp (crypt_method, "SHA512"))
 #endif				/* USE_SHA_CRYPT */
+#ifdef USE_SM3_CRYPT
+		    && (0 != strcmp (crypt_method, "SM3"))
+#endif				/* USE_SM3_CRYPT */
 #ifdef USE_BCRYPT
 		    && (0 != strcmp (crypt_method, "BCRYPT"))
 #endif				/* USE_BCRYPT */
diff --git a/src/passwd.c b/src/passwd.c
index 2c83c10..bdf10cd 100644
--- a/src/passwd.c
+++ b/src/passwd.c
@@ -280,6 +280,9 @@ static int new_password (const struct passwd *pw)
 		    || (strcmp (method, "SHA256") == 0)
 		    || (strcmp (method, "SHA512") == 0)
 #endif /* USE_SHA_CRYPT */
+#ifdef USE_SM3_CRYPT
+		    || (strcmp (method, "SM3") == 0)
+#endif /* USE_SM3_CRYPT */
 #ifdef USE_BCRYPT
 		    || (strcmp (method, "BCRYPT") == 0)
 #endif /* USE_SHA_CRYPT */
-- 
1.8.3.1

