]> granicus.if.org Git - shadow/commitdiff
* libmisc/salt.c: The salt has a random size (between 8 and 16
authornekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Tue, 20 Nov 2007 00:05:54 +0000 (00:05 +0000)
committernekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Tue, 20 Nov 2007 00:05:54 +0000 (00:05 +0000)
  bytes).
* lib/getdef.c, etc/login.defs: Add definitions for
  SHA_CRYPT_MIN_ROUNDS and SHA_CRYPT_MAX_ROUNDS.
* libmisc/salt.c: Use SHA_CRYPT_MIN_ROUNDS and SHA_CRYPT_MAX_ROUNDS
  to add a random number of rounds if needed.

ChangeLog
etc/login.defs
lib/getdef.c
libmisc/salt.c

index 6195cfc8e70c02e7de1c3b94cd4e307125420fd7..82e1a769b37e4ed8d0b373690133b628c85170c0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2007-11-19  Nicolas François  <nicolas.francois@centraliens.net>
+
+       * libmisc/salt.c: The salt has a random size (between 8 and 16
+       bytes).
+       * lib/getdef.c, etc/login.defs: Add definitions for
+       SHA_CRYPT_MIN_ROUNDS and SHA_CRYPT_MAX_ROUNDS.
+       * libmisc/salt.c: Use SHA_CRYPT_MIN_ROUNDS and SHA_CRYPT_MAX_ROUNDS
+       to add a random number of rounds if needed.
+
 2007-11-19  Nicolas François  <nicolas.francois@centraliens.net>
 
        * libmisc/salt.c (MAGNUM): Terminate the array with nul (the array
index 04d20aa30ec1c401dec3bc015c628a422e38d431..dae98f25a30feb5a43cb2f0ad70286222c008ecb 100644 (file)
@@ -288,6 +288,22 @@ CHFN_RESTRICT              rwh
 #
 #ENCRYPT_METHOD DES
 
+#
+# Only works if ENCRYPT_METHOD is set to SHA256 or SHA512.
+#
+# Define the number of SHA rounds.
+# With a lot of rounds, it is more difficult to brute forcing the password.
+# But note also that it more CPU resources will be needed to authenticate
+# users.
+#
+# If not specified, the libc will choose the default number of rounds (5000).
+# The values must be inside 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.
+#
+# SHA_CRYPT_MIN_ROUNDS 5000
+# SHA_CRYPT_MAX_ROUNDS 5000
+
 #
 # List of groups to add to the user's supplementary group set
 # when logging in on the console (as determined by the CONSOLE
index 93546b9d7363e05391711a7db784d9c5ab179aed..7b8a798a048e5978402b65c3785e7371a0957d39 100644 (file)
@@ -104,6 +104,8 @@ static struct itemdef def_table[] = {
        {"PASS_MIN_LEN", NULL},
        {"PORTTIME_CHECKS_ENAB", NULL},
        {"QUOTAS_ENAB", NULL},
+       {"SHA_CRYPT_MAX_ROUNDS", NULL},
+       {"SHA_CRYPT_MIN_ROUNDS", NULL},
        {"SU_WHEEL_ONLY", NULL},
        {"ULIMIT", NULL},
 #endif
index 9f36ec7a8a798ff15d5a7f17dd341032bc82e40e..9fb639d187da206c2f97f461086fda27626634d8 100644 (file)
@@ -53,19 +53,91 @@ char *l64a(long value)
 #endif /* !HAVE_L64A */
 
 /*
- * Generate 8 base64 ASCII characters of random salt.  If MD5_CRYPT_ENAB
- * in /etc/login.defs is "yes", the salt string will be prefixed by "$1$"
- * (magic) and pw_encrypt() will execute the MD5-based FreeBSD-compatible
- * version of crypt() instead of the standard one.
+ * Add the salt prefix.
  */
-
 #define MAGNUM(array,ch)       (array)[0]= (array)[2] = '$',\
                                (array)[1]=(ch),\
                                (array)[2]='\0'
 
+/*
+ * Return the salt size.
+ * The size of the salt string is between 8 and 16 bytes for the SHA crypt
+ * methods.
+ */
+static unsigned int SHA_salt_size (void)
+{
+       return 8 + 8*rand ()/(RAND_MAX+1);
+}
+
+/* ! Arguments evaluated twice ! */
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+
+/* 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
+
+/*
+ * Return a salt prefix specifying the rounds number for the SHA crypt methods.
+ */
+static char *SHA_salt_rounds (void)
+{
+       static char *rounds_prefix[18];
+       long min_rounds = getdef_long ("SHA_CRYPT_MIN_ROUNDS", -1);
+       long max_rounds = getdef_long ("SHA_CRYPT_MAX_ROUNDS", -1);
+       long rounds;
+
+       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 = min_rounds + (max_rounds - min_rounds)*rand ()/(RAND_MAX+1);
+
+       /* 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;
+
+       snprintf (rounds_prefix, 18, "rounds=%ld$", rounds);
+
+       /* Sanity checks. That should not be necessary. */
+       rounds_prefix[17] = '\0';
+       if ('$' != rounds_prefix[16])
+               rounds_prefix[17] = '$';
+
+       return rounds_prefix;
+}
+
+/*
+ * Generate 8 base64 ASCII characters of random salt.  If MD5_CRYPT_ENAB
+ * in /etc/login.defs is "yes", the salt string will be prefixed by "$1$"
+ * (magic) and pw_encrypt() will execute the MD5-based FreeBSD-compatible
+ * version of crypt() instead of the standard one.
+ * Other methods can be set with ENCRYPT_METHOD
+ */
 char *crypt_make_salt (void)
 {
        struct timeval tv;
+       /* Max result size for the SHA methods:
+        *  +3          $5$
+        *  +17         rounds=999999999$
+        *  +16         salt
+        *  +1          \0
+        */
        static char result[40];
        int max_salt_len = 8;
        char *method;
@@ -87,10 +159,12 @@ char *crypt_make_salt (void)
                        max_salt_len = 11;
                } else if (!strncmp (method, "SHA256", 6)) {
                        MAGNUM(result, '5');
-                       max_salt_len = 11; /* XXX: should not be fixed */
+                       strcat(result, SHA_salt_rounds());
+                       max_salt_len = strlen(result) + SHA_salt_size();
                } else if (!strncmp (method, "SHA512", 6)) {
                        MAGNUM(result, '6');
-                       max_salt_len = 11; /* XXX: should not be fixed */
+                       strcat(result, SHA_salt_rounds());
+                       max_salt_len = strlen(result) + SHA_salt_size();
                } else if (0 != strncmp (method, "DES", 3)) {
                        fprintf (stderr,
                                 _("Invalid ENCRYPT_METHOD value: '%s'.\n"
@@ -101,12 +175,14 @@ char *crypt_make_salt (void)
        }
 #endif                         /* ENCRYPTMETHOD_SELECT */
 #endif                         /* USE_PAM */
+
        /*
-        * Generate 8 chars of salt, the old crypt() will use only first 2.
+        * Concatenate a pseudo random salt.
         */
        gettimeofday (&tv, (struct timezone *) 0);
-       strcat (result, l64a (tv.tv_usec));
-       strcat (result, l64a (tv.tv_sec + getpid () + clock ()));
+       strncat (result, sizeof(result), l64a (tv.tv_usec));
+       strncat (result, sizeof(result),
+                l64a (tv.tv_sec + getpid () + clock ()));
 
        if (strlen (result) > max_salt_len)     /* magic+salt */
                result[max_salt_len] = '\0';