|
Packit |
13e0ca |
/* High-level libcrypt interfaces.
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
Copyright 2007-2017 Thorsten Kukuk and Zack Weinberg
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
This library is free software; you can redistribute it and/or
|
|
Packit |
13e0ca |
modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
13e0ca |
as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
13e0ca |
the License, or (at your option) any later version.
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
This library is distributed in the hope that it will be useful,
|
|
Packit |
13e0ca |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
13e0ca |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
13e0ca |
GNU Lesser General Public License for more details.
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
You should have received a copy of the GNU Lesser General Public
|
|
Packit |
13e0ca |
License along with this library; if not, see
|
|
Packit |
13e0ca |
<https://www.gnu.org/licenses/>. */
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#include "crypt-port.h"
|
|
Packit |
13e0ca |
#include "crypt-private.h"
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#include <errno.h>
|
|
Packit |
13e0ca |
#include <stdlib.h>
|
|
Packit |
13e0ca |
#include <limits.h>
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* The internal storage area within struct crypt_data is used as
|
|
Packit |
13e0ca |
follows. We don't know what alignment the algorithm modules will
|
|
Packit |
13e0ca |
need for their scratch data, so give it the maximum natural
|
|
Packit |
13e0ca |
alignment. Note that the C11 alignas() specifier can't be applied
|
|
Packit |
13e0ca |
directly to a struct type, but it can be applied to the first field
|
|
Packit |
13e0ca |
of a struct, which effectively forces alignment of the entire
|
|
Packit |
13e0ca |
struct, since the first field must always have offset 0. */
|
|
Packit |
13e0ca |
struct crypt_internal
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
char alignas (max_align_t) alg_specific[ALG_SPECIFIC_SIZE];
|
|
Packit |
13e0ca |
};
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static_assert(sizeof (struct crypt_internal) + alignof (struct crypt_internal)
|
|
Packit |
13e0ca |
<= CRYPT_DATA_INTERNAL_SIZE,
|
|
Packit |
13e0ca |
"crypt_data.internal is too small for crypt_internal");
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* struct crypt_data is allocated by application code and contains
|
|
Packit |
13e0ca |
only char-typed fields, so its 'internal' field may not be
|
|
Packit |
13e0ca |
sufficiently aligned. */
|
|
Packit |
13e0ca |
static inline struct crypt_internal *
|
|
Packit |
13e0ca |
get_internal (struct crypt_data *data)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
uintptr_t internalp = (uintptr_t) data->internal;
|
|
Packit |
13e0ca |
const uintptr_t align = alignof (struct crypt_internal);
|
|
Packit |
13e0ca |
internalp = (internalp + align - 1) & ~(align - 1);
|
|
Packit |
13e0ca |
return (struct crypt_internal *)internalp;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
typedef void (*crypt_fn) (const char *phrase, size_t phr_size,
|
|
Packit |
13e0ca |
const char *setting, size_t set_size,
|
|
Packit |
13e0ca |
uint8_t *output, size_t out_size,
|
|
Packit |
13e0ca |
void *scratch, size_t scr_size);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
typedef void (*gensalt_fn) (unsigned long count,
|
|
Packit |
13e0ca |
const uint8_t *rbytes, size_t nrbytes,
|
|
Packit |
13e0ca |
uint8_t *output, size_t output_size);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
struct hashfn
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
const char *prefix;
|
|
Packit |
13e0ca |
size_t plen;
|
|
Packit |
13e0ca |
crypt_fn crypt;
|
|
Packit |
13e0ca |
gensalt_fn gensalt;
|
|
Packit |
13e0ca |
/* The type of this field is unsigned char to ensure that it cannot
|
|
Packit |
13e0ca |
be set larger than the size of an internal buffer in crypt_gensalt_rn. */
|
|
Packit |
13e0ca |
unsigned char nrbytes;
|
|
Packit |
13e0ca |
};
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static const struct hashfn hash_algorithms[] =
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
HASH_ALGORITHM_TABLE_ENTRIES
|
|
Packit |
13e0ca |
};
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#if INCLUDE_des || INCLUDE_des_big
|
|
Packit |
13e0ca |
static int
|
|
Packit |
13e0ca |
is_des_salt_char (char c)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
return ((c >= 'a' && c <= 'z') ||
|
|
Packit |
13e0ca |
(c >= 'A' && c <= 'Z') ||
|
|
Packit |
13e0ca |
(c >= '0' && c <= '9') ||
|
|
Packit |
13e0ca |
c == '.' || c == '/');
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static const struct hashfn *
|
|
Packit |
13e0ca |
get_hashfn (const char *setting)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
const struct hashfn *h;
|
|
Packit |
13e0ca |
for (h = hash_algorithms; h->prefix; h++)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (h->plen > 0)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (!strncmp (setting, h->prefix, h->plen))
|
|
Packit |
13e0ca |
return h;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
#if INCLUDE_des || INCLUDE_des_big
|
|
Packit |
13e0ca |
else
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (setting[0] == '\0' ||
|
|
Packit |
13e0ca |
(is_des_salt_char (setting[0]) && is_des_salt_char (setting[1])))
|
|
Packit |
13e0ca |
return h;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* For historical reasons, crypt and crypt_r are not expected ever to
|
|
Packit |
13e0ca |
return 0, and for internal implementation reasons (see
|
|
Packit |
13e0ca |
call_crypt_fn, below), it is simpler if the individual algorithms'
|
|
Packit |
13e0ca |
crypt and gensalt functions return nothing.
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
This function generates a "failure token" in the output buffer,
|
|
Packit |
13e0ca |
which is guaranteed not to be equal to any valid password hash or
|
|
Packit |
13e0ca |
setting string, nor to the setting(+hash) string that was passed
|
|
Packit |
13e0ca |
in; thus, a subsequent blind attempt to authenticate someone by
|
|
Packit |
13e0ca |
comparing the output to a previously recorded hash string will
|
|
Packit |
13e0ca |
fail, even if that string is itself one of these "failure tokens".
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
We always call this function on the output buffer as the first
|
|
Packit |
13e0ca |
step. If the individual algorithm's crypt or gensalt function
|
|
Packit |
13e0ca |
succeeds, it overwrites the failure token with real output;
|
|
Packit |
13e0ca |
otherwise the token is left intact, and the API functions that
|
|
Packit |
13e0ca |
_can_ return 0 on error notice it. */
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static void
|
|
Packit |
13e0ca |
make_failure_token (const char *setting, char *output, int size)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (size >= 3)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
output[0] = '*';
|
|
Packit |
13e0ca |
output[1] = '0';
|
|
Packit |
13e0ca |
output[2] = '\0';
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
if (setting && setting[0] == '*' && setting[1] == '0')
|
|
Packit |
13e0ca |
output[1] = '1';
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* If there's not enough space for the full failure token, do the
|
|
Packit |
13e0ca |
best we can. */
|
|
Packit |
13e0ca |
else if (size == 2)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
output[0] = '*';
|
|
Packit |
13e0ca |
output[1] = '\0';
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
else if (size == 1)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
output[0] = '\0';
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static void
|
|
Packit |
13e0ca |
do_crypt (const char *phrase, const char *setting, struct crypt_data *data)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (!phrase || !setting)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = EINVAL;
|
|
Packit |
13e0ca |
return;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
/* Do these strlen() calls before reading prefixes of either
|
|
Packit |
13e0ca |
'phrase' or 'setting', so we get a predictable crash if they are
|
|
Packit |
13e0ca |
not valid strings. */
|
|
Packit |
13e0ca |
size_t phr_size = strlen (phrase);
|
|
Packit |
13e0ca |
size_t set_size = strlen (setting);
|
|
Packit |
13e0ca |
const struct hashfn *h = get_hashfn (setting);
|
|
Packit |
13e0ca |
if (!h)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
/* Unrecognized hash algorithm */
|
|
Packit |
13e0ca |
errno = EINVAL;
|
|
Packit |
13e0ca |
return;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
struct crypt_internal *cint = get_internal (data);
|
|
Packit |
13e0ca |
h->crypt (phrase, phr_size, setting, set_size,
|
|
Packit |
13e0ca |
(unsigned char *)data->output, sizeof data->output,
|
|
Packit |
13e0ca |
cint->alg_specific, sizeof cint->alg_specific);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
XCRYPT_SECURE_MEMSET (data->internal, sizeof data->internal);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#if INCLUDE_crypt_rn
|
|
Packit |
13e0ca |
char *
|
|
Packit |
13e0ca |
crypt_rn (const char *phrase, const char *setting, void *data, int size)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
make_failure_token (setting, data, MIN (size, CRYPT_OUTPUT_SIZE));
|
|
Packit |
13e0ca |
if (size < 0 || (size_t)size < sizeof (struct crypt_data))
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = ERANGE;
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
struct crypt_data *p = data;
|
|
Packit |
13e0ca |
do_crypt (phrase, setting, p);
|
|
Packit |
13e0ca |
return p->output[0] == '*' ? 0 : p->output;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
SYMVER_crypt_rn;
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#if INCLUDE_crypt_ra
|
|
Packit |
13e0ca |
char *
|
|
Packit |
13e0ca |
crypt_ra (const char *phrase, const char *setting, void **data, int *size)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (!*data)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
*data = malloc (sizeof (struct crypt_data));
|
|
Packit |
13e0ca |
if (!*data)
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
*size = sizeof (struct crypt_data);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
if (*size < 0 || (size_t)*size < sizeof (struct crypt_data))
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
void *rdata = realloc (*data, sizeof (struct crypt_data));
|
|
Packit |
13e0ca |
if (!rdata)
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
*data = rdata;
|
|
Packit |
13e0ca |
*size = sizeof (struct crypt_data);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
struct crypt_data *p = *data;
|
|
Packit |
13e0ca |
make_failure_token (setting, p->output, sizeof p->output);
|
|
Packit |
13e0ca |
do_crypt (phrase, setting, p);
|
|
Packit |
13e0ca |
return p->output[0] == '*' ? 0 : p->output;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
SYMVER_crypt_ra;
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#if INCLUDE_crypt_r
|
|
Packit |
13e0ca |
char *
|
|
Packit |
13e0ca |
crypt_r (const char *phrase, const char *setting, struct crypt_data *data)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
make_failure_token (setting, data->output, sizeof data->output);
|
|
Packit |
13e0ca |
do_crypt (phrase, setting, data);
|
|
Packit Service |
0b5db0 |
#if ENABLE_FAILURE_TOKENS
|
|
Packit |
13e0ca |
return data->output;
|
|
Packit Service |
0b5db0 |
#else
|
|
Packit Service |
0b5db0 |
return data->output[0] == '*' ? 0 : data->output;
|
|
Packit Service |
0b5db0 |
#endif
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
SYMVER_crypt_r;
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#if INCLUDE_crypt_gensalt_rn
|
|
Packit |
13e0ca |
char *
|
|
Packit |
13e0ca |
crypt_gensalt_rn (const char *prefix, unsigned long count,
|
|
Packit |
13e0ca |
const char *rbytes, int nrbytes, char *output,
|
|
Packit |
13e0ca |
int output_size)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
make_failure_token ("", output, output_size);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* Individual gensalt functions will check for adequate space for
|
|
Packit |
13e0ca |
their own breed of setting, but the shortest possible one is
|
|
Packit |
13e0ca |
three bytes (DES two-character salt + NUL terminator) and we
|
|
Packit |
13e0ca |
also want to rule out negative numbers early. */
|
|
Packit |
13e0ca |
if (output_size < 3)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = ERANGE;
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* If the prefix is 0, that means to use the current best default.
|
|
Packit |
13e0ca |
Note that this is different from the behavior when the prefix is
|
|
Packit |
13e0ca |
"", which selects DES. HASH_ALGORITHM_DEFAULT is null when the
|
|
Packit |
13e0ca |
current default algorithm was disabled at configure time. */
|
|
Packit |
13e0ca |
if (!prefix)
|
|
Packit |
13e0ca |
prefix = HASH_ALGORITHM_DEFAULT;
|
|
Packit |
13e0ca |
if (!prefix)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = EINVAL;
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
const struct hashfn *h = get_hashfn (prefix);
|
|
Packit |
13e0ca |
if (!h)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = EINVAL;
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
char internal_rbytes[UCHAR_MAX];
|
|
Packit |
13e0ca |
/* typeof (internal_nrbytes) == typeof (h->nrbytes). */
|
|
Packit |
13e0ca |
unsigned char internal_nrbytes = 0;
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* If rbytes is 0, read random bytes from the operating system if
|
|
Packit |
13e0ca |
possible. */
|
|
Packit |
13e0ca |
if (!rbytes)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
if (!get_random_bytes (internal_rbytes, h->nrbytes))
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
rbytes = internal_rbytes;
|
|
Packit |
13e0ca |
nrbytes = internal_nrbytes = h->nrbytes;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* Individual gensalt functions will check for sufficient random bits
|
|
Packit |
13e0ca |
for their own breed of setting, but the shortest possible one has
|
|
Packit |
13e0ca |
64**2 = 4096 possibilities, which requires two bytes of input. */
|
|
Packit |
13e0ca |
if (nrbytes < 2)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = EINVAL;
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
h->gensalt (count,
|
|
Packit |
13e0ca |
(const unsigned char *)rbytes, (size_t)nrbytes,
|
|
Packit |
13e0ca |
(unsigned char *)output, (size_t)output_size);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
if (internal_nrbytes)
|
|
Packit |
13e0ca |
XCRYPT_SECURE_MEMSET (internal_rbytes, internal_nrbytes);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
return output[0] == '*' ? 0 : output;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
SYMVER_crypt_gensalt_rn;
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#if INCLUDE_crypt_gensalt_ra
|
|
Packit |
13e0ca |
char *
|
|
Packit |
13e0ca |
crypt_gensalt_ra (const char *prefix, unsigned long count,
|
|
Packit |
13e0ca |
const char *rbytes, int nrbytes)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
char *output = malloc (CRYPT_GENSALT_OUTPUT_SIZE);
|
|
Packit |
13e0ca |
if (!output)
|
|
Packit |
13e0ca |
return 0;
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
char *result = crypt_gensalt_rn (prefix, count, rbytes, nrbytes, output,
|
|
Packit |
13e0ca |
CRYPT_GENSALT_OUTPUT_SIZE);
|
|
Packit |
13e0ca |
if (result == 0)
|
|
Packit |
13e0ca |
free (output);
|
|
Packit |
13e0ca |
return result;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
SYMVER_crypt_gensalt_ra;
|
|
Packit |
13e0ca |
#endif
|