2 * salt.c - generate a random salt string for crypt()
4 * Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
5 * it is in the public domain.
7 * l64a was Written by J.T. Conklin <jtc@netbsd.org>. Public domain.
18 #include "prototypes.h"
22 /* local function prototypes */
24 char *l64a(long value);
25 #endif /* !HAVE_L64A */
26 static void seedRNG (void);
27 static char *gensalt (unsigned int salt_size);
29 static unsigned int SHA_salt_size (void);
30 static const char *SHA_salt_rounds (int *prefered_rounds);
31 #endif /* USE_SHA_CRYPT */
34 static char *l64a(long value)
46 for (i = 0; value != 0 && i < 6; i++) {
54 *s = digit + 'A' - 12;
56 *s = digit + 'a' - 38;
66 #endif /* !HAVE_L64A */
68 static void seedRNG (void)
71 static int seeded = 0;
74 gettimeofday(&tv, NULL);
75 srandom (tv.tv_sec + tv.tv_usec);
81 * Add the salt prefix.
83 #define MAGNUM(array,ch) (array)[0]=(array)[2]='$',(array)[1]=(ch),(array)[3]='\0'
87 * Return the salt size.
88 * The size of the salt string is between 8 and 16 bytes for the SHA crypt
91 static unsigned int SHA_salt_size (void)
95 rand_size = (double) 9.0 * random () / RAND_MAX;
99 /* ! Arguments evaluated twice ! */
100 #define MAX(x,y) ((x) > (y) ? (x) : (y))
101 #define MIN(x,y) ((x) < (y) ? (x) : (y))
103 /* Default number of rounds if not explicitly specified. */
104 #define ROUNDS_DEFAULT 5000
105 /* Minimum number of rounds. */
106 #define ROUNDS_MIN 1000
107 /* Maximum number of rounds. */
108 #define ROUNDS_MAX 999999999
111 * Return a salt prefix specifying the rounds number for the SHA crypt methods.
113 static const char *SHA_salt_rounds (int *prefered_rounds)
115 static char rounds_prefix[18];
118 if (NULL == prefered_rounds) {
119 long min_rounds = getdef_long ("SHA_CRYPT_MIN_ROUNDS", -1);
120 long max_rounds = getdef_long ("SHA_CRYPT_MAX_ROUNDS", -1);
123 if (-1 == min_rounds && -1 == max_rounds)
126 if (-1 == min_rounds)
127 min_rounds = max_rounds;
129 if (-1 == max_rounds)
130 max_rounds = min_rounds;
132 if (min_rounds > max_rounds)
133 max_rounds = min_rounds;
136 rand_rounds = (double) (max_rounds-min_rounds+1.0) * random ();
137 rand_rounds /= RAND_MAX;
138 rounds = min_rounds + rand_rounds;
139 } else if (0 == *prefered_rounds)
142 rounds = *prefered_rounds;
144 /* Sanity checks. The libc should also check this, but this
145 * protects against a rounds_prefix overflow. */
146 if (rounds < ROUNDS_MIN)
149 if (rounds > ROUNDS_MAX)
152 snprintf (rounds_prefix, 18, "rounds=%ld$", rounds);
154 /* Sanity checks. That should not be necessary. */
155 rounds_prefix[17] = '\0';
156 if ('$' != rounds_prefix[16])
157 rounds_prefix[17] = '$';
159 return rounds_prefix;
161 #endif /* USE_SHA_CRYPT */
164 * Generate salt of size salt_size.
166 #define MAX_SALT_SIZE 16
167 #define MIN_SALT_SIZE 8
169 static char *gensalt (unsigned int salt_size)
171 static char salt[32];
175 assert (salt_size >= MIN_SALT_SIZE &&
176 salt_size <= MAX_SALT_SIZE);
178 strcat (salt, l64a (random()));
180 strcat (salt, l64a (random()));
181 } while (strlen (salt) < salt_size);
182 salt[salt_size] = '\0';
188 * Generate 8 base64 ASCII characters of random salt. If MD5_CRYPT_ENAB
189 * in /etc/login.defs is "yes", the salt string will be prefixed by "$1$"
190 * (magic) and pw_encrypt() will execute the MD5-based FreeBSD-compatible
191 * version of crypt() instead of the standard one.
192 * Other methods can be set with ENCRYPT_METHOD
194 * The method can be forced with the meth parameter.
195 * If NULL, the method will be defined according to the MD5_CRYPT_ENAB and
196 * ENCRYPT_METHOD login.defs variables.
198 * If meth is specified, an additional parameter can be provided.
199 * * For the SHA256 and SHA512 method, this specifies the number of rounds
202 char *crypt_make_salt (const char *meth, void *arg)
204 /* Max result size for the SHA methods:
206 * +17 rounds=999999999$
210 static char result[40];
219 if ((method = getdef_str ("ENCRYPT_METHOD")) == NULL)
220 method = getdef_bool ("MD5_CRYPT_ENAB") ? "MD5" : "DES";
223 if (0 == strcmp (method, "MD5")) {
226 } else if (0 == strcmp (method, "SHA256")) {
228 strcat(result, SHA_salt_rounds((int *)arg));
229 salt_len = SHA_salt_size();
230 } else if (0 == strcmp (method, "SHA512")) {
232 strcat(result, SHA_salt_rounds((int *)arg));
233 salt_len = SHA_salt_size();
234 #endif /* USE_SHA_CRYPT */
235 } else if (0 != strcmp (method, "DES")) {
237 _("Invalid ENCRYPT_METHOD value: '%s'.\n"
238 "Defaulting to DES.\n"),
244 * Concatenate a pseudo random salt.
246 assert (sizeof (result) > strlen (result) + salt_len);
247 strncat (result, gensalt (salt_len),
248 sizeof (result) - strlen (result) - 1);