2007-10-07 17:14:02 +05:30
|
|
|
/*
|
|
|
|
* salt.c - generate a random salt string for crypt()
|
|
|
|
*
|
|
|
|
* Written by Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>,
|
2008-04-27 06:10:09 +05:30
|
|
|
* it is in the public domain.
|
2007-11-16 18:06:21 +05:30
|
|
|
*
|
|
|
|
* l64a was Written by J.T. Conklin <jtc@netbsd.org>. Public domain.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2007-11-11 05:16:11 +05:30
|
|
|
#ident "$Id$"
|
2007-10-07 17:17:01 +05:30
|
|
|
|
2007-10-07 17:16:07 +05:30
|
|
|
#include <sys/time.h>
|
|
|
|
#include <stdlib.h>
|
2008-01-26 23:11:20 +05:30
|
|
|
#include <stdio.h>
|
2007-11-24 02:21:43 +05:30
|
|
|
#include <assert.h>
|
2007-10-07 17:14:02 +05:30
|
|
|
#include "prototypes.h"
|
|
|
|
#include "defines.h"
|
|
|
|
#include "getdef.h"
|
2007-11-16 18:06:21 +05:30
|
|
|
|
2008-01-06 20:20:26 +05:30
|
|
|
/* local function prototypes */
|
2008-02-03 22:53:58 +05:30
|
|
|
static void seedRNG (void);
|
* libmisc/xgetXXbyYY.c, libmisc/myname.c, libmisc/getgr_nam_gid.c,
libmisc/salt.c, libmisc/list.c, libmisc/cleanup.c, src/login.c,
lib/getdef.h, lib/groupio.c, lib/getlong.c, lib/gshadow_.h,
lib/sgroupio.c, lib/shadowio.c, lib/pwio.c, lib/commonio.h,
lib/fputsx.c, lib/prototypes.h: Added splint annotations.
* lib/groupio.c: Avoid implicit conversion of pointers to
booleans.
* lib/groupio.c: Free allocated buffers in case of failure.
2009-04-23 15:27:03 +05:30
|
|
|
static /*@observer@*/const char *gensalt (size_t salt_size);
|
2008-01-06 20:20:26 +05:30
|
|
|
#ifdef USE_SHA_CRYPT
|
2008-06-14 01:07:15 +05:30
|
|
|
static size_t SHA_salt_size (void);
|
* libmisc/xgetXXbyYY.c, libmisc/myname.c, libmisc/getgr_nam_gid.c,
libmisc/salt.c, libmisc/list.c, libmisc/cleanup.c, src/login.c,
lib/getdef.h, lib/groupio.c, lib/getlong.c, lib/gshadow_.h,
lib/sgroupio.c, lib/shadowio.c, lib/pwio.c, lib/commonio.h,
lib/fputsx.c, lib/prototypes.h: Added splint annotations.
* lib/groupio.c: Avoid implicit conversion of pointers to
booleans.
* lib/groupio.c: Free allocated buffers in case of failure.
2009-04-23 15:27:03 +05:30
|
|
|
static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds);
|
2008-05-20 02:26:48 +05:30
|
|
|
#endif /* USE_SHA_CRYPT */
|
2008-01-06 20:20:26 +05:30
|
|
|
|
|
|
|
#ifndef HAVE_L64A
|
* libmisc/xgetXXbyYY.c, libmisc/myname.c, libmisc/getgr_nam_gid.c,
libmisc/salt.c, libmisc/list.c, libmisc/cleanup.c, src/login.c,
lib/getdef.h, lib/groupio.c, lib/getlong.c, lib/gshadow_.h,
lib/sgroupio.c, lib/shadowio.c, lib/pwio.c, lib/commonio.h,
lib/fputsx.c, lib/prototypes.h: Added splint annotations.
* lib/groupio.c: Avoid implicit conversion of pointers to
booleans.
* lib/groupio.c: Free allocated buffers in case of failure.
2009-04-23 15:27:03 +05:30
|
|
|
static /*@observer@*/char *l64a(long value)
|
2007-11-16 18:06:21 +05:30
|
|
|
{
|
|
|
|
static char buf[8];
|
|
|
|
char *s = buf;
|
|
|
|
int digit;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (value < 0) {
|
|
|
|
errno = EINVAL;
|
|
|
|
return(NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; value != 0 && i < 6; i++) {
|
|
|
|
digit = value & 0x3f;
|
|
|
|
|
2008-06-14 01:07:15 +05:30
|
|
|
if (digit < 2) {
|
2007-11-16 18:06:21 +05:30
|
|
|
*s = digit + '.';
|
2008-06-14 01:07:15 +05:30
|
|
|
} else if (digit < 12) {
|
2007-11-16 18:06:21 +05:30
|
|
|
*s = digit + '0' - 2;
|
2008-06-14 01:07:15 +05:30
|
|
|
} else if (digit < 38) {
|
2007-11-16 18:06:21 +05:30
|
|
|
*s = digit + 'A' - 12;
|
2008-06-14 01:07:15 +05:30
|
|
|
} else {
|
2007-11-16 18:06:21 +05:30
|
|
|
*s = digit + 'a' - 38;
|
2008-06-14 01:07:15 +05:30
|
|
|
}
|
2007-11-16 18:06:21 +05:30
|
|
|
|
|
|
|
value >>= 6;
|
|
|
|
s++;
|
|
|
|
}
|
|
|
|
|
|
|
|
*s = '\0';
|
|
|
|
|
|
|
|
return(buf);
|
|
|
|
}
|
|
|
|
#endif /* !HAVE_L64A */
|
|
|
|
|
2008-02-03 22:53:58 +05:30
|
|
|
static void seedRNG (void)
|
|
|
|
{
|
|
|
|
struct timeval tv;
|
|
|
|
static int seeded = 0;
|
|
|
|
|
|
|
|
if (0 == seeded) {
|
2009-04-25 04:19:20 +05:30
|
|
|
(void) gettimeofday (&tv, NULL);
|
|
|
|
srandom (tv.tv_sec ^ tv.tv_usec ^ getpid ());
|
2008-02-03 22:53:58 +05:30
|
|
|
seeded = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
2007-11-20 05:35:54 +05:30
|
|
|
* Add the salt prefix.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-11-24 02:21:43 +05:30
|
|
|
#define MAGNUM(array,ch) (array)[0]=(array)[2]='$',(array)[1]=(ch),(array)[3]='\0'
|
2007-11-20 03:44:19 +05:30
|
|
|
|
* configure.in: New configure option: --with-sha-crypt enabled by
default. Keeping the feature enabled is safe. Disabling it permits
to disable the references to the SHA256 and SHA512 password
encryption algorithms from the usage help and manuals (in addition
to the support for these algorithms in the code).
* libmisc/obscure.c, libmisc/salt.c, src/newusers.c,
src/chpasswd.c, src/chgpasswd.c, src/passwd.c: ENCRYPT_METHOD is
always supported in login.defs. Remove the ENCRYPTMETHOD_SELECT
preprocessor condition.
* libmisc/obscure.c, libmisc/salt.c, src/newusers.c,
src/chpasswd.c, src/chgpasswd.c, src/passwd.c: Disable SHA256 and
SHA512 if USE_SHA_CRYPT is not defined (this corresponds to a
subset of the ENCRYPTMETHOD_SELECT sections).
2007-11-24 18:38:08 +05:30
|
|
|
#ifdef USE_SHA_CRYPT
|
2007-11-20 05:35:54 +05:30
|
|
|
/*
|
|
|
|
* Return the salt size.
|
|
|
|
* The size of the salt string is between 8 and 16 bytes for the SHA crypt
|
|
|
|
* methods.
|
|
|
|
*/
|
2008-06-14 01:07:15 +05:30
|
|
|
static size_t SHA_salt_size (void)
|
2007-11-20 05:35:54 +05:30
|
|
|
{
|
*** security:
- generation of SHA encrypted passwords (chpasswd, gpasswd, newusers,
chgpasswd; and also passwd if configured without PAM support).
The number of rounds and number of salt bytes was fixed to their lower
allowed values (resp. configurable and 8), hence voiding some of the
advantages of this encryption method. Dictionary attacks with
precomputed tables were easier than expected, but still harder than with
the MD5 (or DES) methods.
* NEWS, libmisc/salt.c (SHA_salt_size): Seed the RNG, and fix a
overflow. These caused the SHA salt size to always be 8 bytes,
instead of being in the 8-16 range. Thanks to Peter Vrabec
pvrabec@redhat.com for noticing.
* NEWS, libmisc/salt.c (SHA_salt_rounds): Seed the RNG with
seedRNG instead of srand, and fix the same overflow. This caused
the number of rounds to always be the smallest one.
2008-05-20 19:04:06 +05:30
|
|
|
double rand_size;
|
|
|
|
seedRNG ();
|
|
|
|
rand_size = (double) 9.0 * random () / RAND_MAX;
|
2008-06-14 01:07:15 +05:30
|
|
|
return (size_t) (8 + rand_size);
|
2007-11-20 05:35:54 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
*/
|
* libmisc/xgetXXbyYY.c, libmisc/myname.c, libmisc/getgr_nam_gid.c,
libmisc/salt.c, libmisc/list.c, libmisc/cleanup.c, src/login.c,
lib/getdef.h, lib/groupio.c, lib/getlong.c, lib/gshadow_.h,
lib/sgroupio.c, lib/shadowio.c, lib/pwio.c, lib/commonio.h,
lib/fputsx.c, lib/prototypes.h: Added splint annotations.
* lib/groupio.c: Avoid implicit conversion of pointers to
booleans.
* lib/groupio.c: Free allocated buffers in case of failure.
2009-04-23 15:27:03 +05:30
|
|
|
static /*@observer@*/const char *SHA_salt_rounds (/*@null@*/int *prefered_rounds)
|
2007-11-20 05:35:54 +05:30
|
|
|
{
|
2007-11-20 15:03:52 +05:30
|
|
|
static char rounds_prefix[18];
|
2007-11-20 05:35:54 +05:30
|
|
|
long rounds;
|
|
|
|
|
2007-11-20 15:03:52 +05:30
|
|
|
if (NULL == prefered_rounds) {
|
|
|
|
long min_rounds = getdef_long ("SHA_CRYPT_MIN_ROUNDS", -1);
|
|
|
|
long max_rounds = getdef_long ("SHA_CRYPT_MAX_ROUNDS", -1);
|
2008-01-06 20:20:26 +05:30
|
|
|
double rand_rounds;
|
2007-11-20 05:35:54 +05:30
|
|
|
|
2008-06-14 01:07:15 +05:30
|
|
|
if ((-1 == min_rounds) && (-1 == max_rounds)) {
|
2007-11-20 15:03:52 +05:30
|
|
|
return "";
|
2008-06-14 01:07:15 +05:30
|
|
|
}
|
2007-11-20 05:35:54 +05:30
|
|
|
|
2008-06-14 01:07:15 +05:30
|
|
|
if (-1 == min_rounds) {
|
2007-11-20 15:03:52 +05:30
|
|
|
min_rounds = max_rounds;
|
2008-06-14 01:07:15 +05:30
|
|
|
}
|
2007-11-20 05:35:54 +05:30
|
|
|
|
2008-06-14 01:07:15 +05:30
|
|
|
if (-1 == max_rounds) {
|
2007-11-20 15:03:52 +05:30
|
|
|
max_rounds = min_rounds;
|
2008-06-14 01:07:15 +05:30
|
|
|
}
|
2007-11-20 05:35:54 +05:30
|
|
|
|
2008-06-14 01:07:15 +05:30
|
|
|
if (min_rounds > max_rounds) {
|
2007-11-20 15:03:52 +05:30
|
|
|
max_rounds = min_rounds;
|
2008-06-14 01:07:15 +05:30
|
|
|
}
|
2007-11-20 15:03:52 +05:30
|
|
|
|
*** security:
- generation of SHA encrypted passwords (chpasswd, gpasswd, newusers,
chgpasswd; and also passwd if configured without PAM support).
The number of rounds and number of salt bytes was fixed to their lower
allowed values (resp. configurable and 8), hence voiding some of the
advantages of this encryption method. Dictionary attacks with
precomputed tables were easier than expected, but still harder than with
the MD5 (or DES) methods.
* NEWS, libmisc/salt.c (SHA_salt_size): Seed the RNG, and fix a
overflow. These caused the SHA salt size to always be 8 bytes,
instead of being in the 8-16 range. Thanks to Peter Vrabec
pvrabec@redhat.com for noticing.
* NEWS, libmisc/salt.c (SHA_salt_rounds): Seed the RNG with
seedRNG instead of srand, and fix the same overflow. This caused
the number of rounds to always be the smallest one.
2008-05-20 19:04:06 +05:30
|
|
|
seedRNG ();
|
|
|
|
rand_rounds = (double) (max_rounds-min_rounds+1.0) * random ();
|
2008-01-06 20:20:26 +05:30
|
|
|
rand_rounds /= RAND_MAX;
|
|
|
|
rounds = min_rounds + rand_rounds;
|
2008-06-14 01:07:15 +05:30
|
|
|
} else if (0 == *prefered_rounds) {
|
2007-11-20 15:03:52 +05:30
|
|
|
return "";
|
2008-06-14 01:07:15 +05:30
|
|
|
} else {
|
2007-11-21 01:30:16 +05:30
|
|
|
rounds = *prefered_rounds;
|
2008-06-14 01:07:15 +05:30
|
|
|
}
|
2007-11-20 05:35:54 +05:30
|
|
|
|
|
|
|
/* Sanity checks. The libc should also check this, but this
|
|
|
|
* protects against a rounds_prefix overflow. */
|
2008-06-14 01:07:15 +05:30
|
|
|
if (rounds < ROUNDS_MIN) {
|
2007-11-20 05:35:54 +05:30
|
|
|
rounds = ROUNDS_MIN;
|
2008-06-14 01:07:15 +05:30
|
|
|
}
|
2007-11-20 05:35:54 +05:30
|
|
|
|
2008-06-14 01:07:15 +05:30
|
|
|
if (rounds > ROUNDS_MAX) {
|
2007-11-20 05:35:54 +05:30
|
|
|
rounds = ROUNDS_MAX;
|
2008-06-14 01:07:15 +05:30
|
|
|
}
|
2007-11-20 05:35:54 +05:30
|
|
|
|
|
|
|
snprintf (rounds_prefix, 18, "rounds=%ld$", rounds);
|
|
|
|
|
|
|
|
/* Sanity checks. That should not be necessary. */
|
|
|
|
rounds_prefix[17] = '\0';
|
2008-06-14 01:07:15 +05:30
|
|
|
if ('$' != rounds_prefix[16]) {
|
2007-11-20 05:35:54 +05:30
|
|
|
rounds_prefix[17] = '$';
|
2008-06-14 01:07:15 +05:30
|
|
|
}
|
2007-11-20 05:35:54 +05:30
|
|
|
|
|
|
|
return rounds_prefix;
|
|
|
|
}
|
2008-05-20 02:26:48 +05:30
|
|
|
#endif /* USE_SHA_CRYPT */
|
2007-11-20 05:35:54 +05:30
|
|
|
|
2007-11-24 02:21:43 +05:30
|
|
|
/*
|
|
|
|
* Generate salt of size salt_size.
|
|
|
|
*/
|
|
|
|
#define MAX_SALT_SIZE 16
|
|
|
|
#define MIN_SALT_SIZE 8
|
|
|
|
|
* libmisc/xgetXXbyYY.c, libmisc/myname.c, libmisc/getgr_nam_gid.c,
libmisc/salt.c, libmisc/list.c, libmisc/cleanup.c, src/login.c,
lib/getdef.h, lib/groupio.c, lib/getlong.c, lib/gshadow_.h,
lib/sgroupio.c, lib/shadowio.c, lib/pwio.c, lib/commonio.h,
lib/fputsx.c, lib/prototypes.h: Added splint annotations.
* lib/groupio.c: Avoid implicit conversion of pointers to
booleans.
* lib/groupio.c: Free allocated buffers in case of failure.
2009-04-23 15:27:03 +05:30
|
|
|
static /*@observer@*/const char *gensalt (size_t salt_size)
|
2008-01-06 20:20:26 +05:30
|
|
|
{
|
2007-11-24 05:30:12 +05:30
|
|
|
static char salt[32];
|
|
|
|
|
|
|
|
salt[0] = '\0';
|
|
|
|
|
2007-11-24 02:34:43 +05:30
|
|
|
assert (salt_size >= MIN_SALT_SIZE &&
|
|
|
|
salt_size <= MAX_SALT_SIZE);
|
2008-02-03 22:53:58 +05:30
|
|
|
seedRNG ();
|
2007-11-24 05:30:12 +05:30
|
|
|
strcat (salt, l64a (random()));
|
|
|
|
do {
|
|
|
|
strcat (salt, l64a (random()));
|
|
|
|
} while (strlen (salt) < salt_size);
|
2008-06-14 01:07:15 +05:30
|
|
|
|
2007-11-24 05:30:12 +05:30
|
|
|
salt[salt_size] = '\0';
|
|
|
|
|
|
|
|
return salt;
|
2007-11-24 02:21:43 +05:30
|
|
|
}
|
|
|
|
|
2007-11-20 05:35:54 +05:30
|
|
|
/*
|
|
|
|
* 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
|
2007-11-20 15:03:52 +05:30
|
|
|
*
|
|
|
|
* The method can be forced with the meth parameter.
|
|
|
|
* If NULL, the method will be defined according to the MD5_CRYPT_ENAB and
|
|
|
|
* 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
|
|
|
|
* (if not NULL).
|
2007-11-20 05:35:54 +05:30
|
|
|
*/
|
* libmisc/xgetXXbyYY.c, libmisc/myname.c, libmisc/getgr_nam_gid.c,
libmisc/salt.c, libmisc/list.c, libmisc/cleanup.c, src/login.c,
lib/getdef.h, lib/groupio.c, lib/getlong.c, lib/gshadow_.h,
lib/sgroupio.c, lib/shadowio.c, lib/pwio.c, lib/commonio.h,
lib/fputsx.c, lib/prototypes.h: Added splint annotations.
* lib/groupio.c: Avoid implicit conversion of pointers to
booleans.
* lib/groupio.c: Free allocated buffers in case of failure.
2009-04-23 15:27:03 +05:30
|
|
|
/*@observer@*/const char *crypt_make_salt (/*@null@*/const char *meth, /*@null@*/void *arg)
|
2007-10-07 17:14:02 +05:30
|
|
|
{
|
2007-11-20 05:35:54 +05:30
|
|
|
/* Max result size for the SHA methods:
|
|
|
|
* +3 $5$
|
|
|
|
* +17 rounds=999999999$
|
|
|
|
* +16 salt
|
|
|
|
* +1 \0
|
|
|
|
*/
|
2007-10-07 17:14:02 +05:30
|
|
|
static char result[40];
|
2007-11-24 02:21:43 +05:30
|
|
|
size_t salt_len = 8;
|
2008-01-06 20:20:26 +05:30
|
|
|
const char *method;
|
2007-10-07 17:14:02 +05:30
|
|
|
|
2007-11-20 04:04:48 +05:30
|
|
|
result[0] = '\0';
|
|
|
|
|
2007-11-20 15:03:52 +05:30
|
|
|
if (NULL != meth)
|
|
|
|
method = meth;
|
2007-11-24 05:27:47 +05:30
|
|
|
else {
|
2008-06-14 01:07:15 +05:30
|
|
|
method = getdef_str ("ENCRYPT_METHOD");
|
|
|
|
if (NULL == method) {
|
|
|
|
method = getdef_bool ("MD5_CRYPT_ENAB") ? "MD5" : "DES";
|
|
|
|
}
|
2007-11-24 05:27:47 +05:30
|
|
|
}
|
2007-11-20 15:03:52 +05:30
|
|
|
|
2008-05-24 18:38:58 +05:30
|
|
|
if (0 == strcmp (method, "MD5")) {
|
2007-11-20 15:03:52 +05:30
|
|
|
MAGNUM(result, '1');
|
* configure.in: New configure option: --with-sha-crypt enabled by
default. Keeping the feature enabled is safe. Disabling it permits
to disable the references to the SHA256 and SHA512 password
encryption algorithms from the usage help and manuals (in addition
to the support for these algorithms in the code).
* libmisc/obscure.c, libmisc/salt.c, src/newusers.c,
src/chpasswd.c, src/chgpasswd.c, src/passwd.c: ENCRYPT_METHOD is
always supported in login.defs. Remove the ENCRYPTMETHOD_SELECT
preprocessor condition.
* libmisc/obscure.c, libmisc/salt.c, src/newusers.c,
src/chpasswd.c, src/chgpasswd.c, src/passwd.c: Disable SHA256 and
SHA512 if USE_SHA_CRYPT is not defined (this corresponds to a
subset of the ENCRYPTMETHOD_SELECT sections).
2007-11-24 18:38:08 +05:30
|
|
|
#ifdef USE_SHA_CRYPT
|
2008-05-24 18:38:58 +05:30
|
|
|
} else if (0 == strcmp (method, "SHA256")) {
|
2007-11-20 15:03:52 +05:30
|
|
|
MAGNUM(result, '5');
|
|
|
|
strcat(result, SHA_salt_rounds((int *)arg));
|
2007-11-24 02:21:43 +05:30
|
|
|
salt_len = SHA_salt_size();
|
2008-05-24 18:38:58 +05:30
|
|
|
} else if (0 == strcmp (method, "SHA512")) {
|
2007-11-20 15:03:52 +05:30
|
|
|
MAGNUM(result, '6');
|
|
|
|
strcat(result, SHA_salt_rounds((int *)arg));
|
2007-11-24 02:21:43 +05:30
|
|
|
salt_len = SHA_salt_size();
|
2008-05-20 02:26:48 +05:30
|
|
|
#endif /* USE_SHA_CRYPT */
|
2007-11-21 01:30:16 +05:30
|
|
|
} else if (0 != strcmp (method, "DES")) {
|
2007-11-20 15:03:52 +05:30
|
|
|
fprintf (stderr,
|
|
|
|
_("Invalid ENCRYPT_METHOD value: '%s'.\n"
|
|
|
|
"Defaulting to DES.\n"),
|
|
|
|
method);
|
|
|
|
result[0] = '\0';
|
2007-11-20 03:44:19 +05:30
|
|
|
}
|
2007-11-20 05:35:54 +05:30
|
|
|
|
2007-10-07 17:14:02 +05:30
|
|
|
/*
|
2007-11-20 05:35:54 +05:30
|
|
|
* Concatenate a pseudo random salt.
|
2007-10-07 17:14:02 +05:30
|
|
|
*/
|
2007-11-24 02:21:43 +05:30
|
|
|
assert (sizeof (result) > strlen (result) + salt_len);
|
|
|
|
strncat (result, gensalt (salt_len),
|
|
|
|
sizeof (result) - strlen (result) - 1);
|
2007-10-07 17:14:02 +05:30
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
2008-01-06 20:20:26 +05:30
|
|
|
|