|
Packit |
13e0ca |
/*
|
|
Packit |
13e0ca |
* Copyright (c) 2004, Juniper Networks, Inc.
|
|
Packit |
13e0ca |
* All rights reserved.
|
|
Packit |
13e0ca |
*
|
|
Packit |
13e0ca |
* Redistribution and use in source and binary forms, with or without
|
|
Packit |
13e0ca |
* modification, are permitted provided that the following conditions
|
|
Packit |
13e0ca |
* are met:
|
|
Packit |
13e0ca |
* 1. Redistributions of source code must retain the above copyright
|
|
Packit |
13e0ca |
* notice, this list of conditions and the following disclaimer.
|
|
Packit |
13e0ca |
* 2. Redistributions in binary form must reproduce the above copyright
|
|
Packit |
13e0ca |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit |
13e0ca |
* documentation and/or other materials provided with the distribution.
|
|
Packit |
13e0ca |
* 3. Neither the name of the copyright holders nor the names of its
|
|
Packit |
13e0ca |
* contributors may be used to endorse or promote products derived
|
|
Packit |
13e0ca |
* from this software without specific prior written permission.
|
|
Packit |
13e0ca |
*
|
|
Packit |
13e0ca |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
Packit |
13e0ca |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
Packit |
13e0ca |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
Packit |
13e0ca |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
Packit |
13e0ca |
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
Packit |
13e0ca |
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
Packit |
13e0ca |
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
Packit |
13e0ca |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
Packit |
13e0ca |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
Packit |
13e0ca |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
Packit |
13e0ca |
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
Packit |
13e0ca |
*/
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#include "crypt-port.h"
|
|
Packit |
13e0ca |
#include "crypt-private.h"
|
|
Packit |
13e0ca |
#include "alg-hmac-sha1.h"
|
|
Packit |
13e0ca |
#include "byteorder.h"
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#include <errno.h>
|
|
Packit |
13e0ca |
#include <stdio.h>
|
|
Packit |
13e0ca |
#include <stdlib.h>
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#if INCLUDE_sha1
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/*
|
|
Packit |
13e0ca |
* The default iterations - should take >0s on a fast CPU
|
|
Packit |
13e0ca |
* but not be insane for a slow CPU.
|
|
Packit |
13e0ca |
*/
|
|
Packit |
13e0ca |
#ifndef CRYPT_SHA1_ITERATIONS
|
|
Packit |
13e0ca |
# define CRYPT_SHA1_ITERATIONS 262144
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
/*
|
|
Packit |
13e0ca |
* Support a reasonably? long salt.
|
|
Packit |
13e0ca |
*/
|
|
Packit |
13e0ca |
#ifndef CRYPT_SHA1_SALT_LENGTH
|
|
Packit |
13e0ca |
# define CRYPT_SHA1_SALT_LENGTH 64
|
|
Packit |
13e0ca |
#endif
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#define SHA1_SIZE 20 /* size of raw SHA1 digest, 160 bits */
|
|
Packit |
13e0ca |
#define SHA1_OUTPUT_SIZE 28 /* size of base64-ed output string */
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static const uint8_t itoa64[] =
|
|
Packit |
13e0ca |
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
static inline void
|
|
Packit |
13e0ca |
to64 (uint8_t *s, unsigned long v, int n)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
while (--n >= 0)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
*s++ = itoa64[v & 0x3f];
|
|
Packit |
13e0ca |
v >>= 6;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/*
|
|
Packit |
13e0ca |
* UNIX password using hmac_sha1
|
|
Packit |
13e0ca |
* This is PBKDF1 from RFC 2898, but using hmac_sha1.
|
|
Packit |
13e0ca |
*
|
|
Packit |
13e0ca |
* The format of the encrypted password is:
|
|
Packit |
13e0ca |
* $<tag>$<iterations>$<salt>$<digest>
|
|
Packit |
13e0ca |
*
|
|
Packit |
13e0ca |
* where:
|
|
Packit |
13e0ca |
* <tag> is "sha1"
|
|
Packit |
13e0ca |
* <iterations> is an unsigned int identifying how many rounds
|
|
Packit |
13e0ca |
* have been applied to <digest>. The number
|
|
Packit |
13e0ca |
* should vary slightly for each password to make
|
|
Packit |
13e0ca |
* it harder to generate a dictionary of
|
|
Packit |
13e0ca |
* pre-computed hashes. See gensalt_sha1_rn.
|
|
Packit |
13e0ca |
* <salt> up to 64 bytes of random data, 8 bytes is
|
|
Packit |
13e0ca |
* currently considered more than enough.
|
|
Packit |
13e0ca |
* <digest> the hashed password.
|
|
Packit |
13e0ca |
*
|
|
Packit |
13e0ca |
* NOTE:
|
|
Packit |
13e0ca |
* To be FIPS 140 compliant, the password which is used as a hmac key,
|
|
Packit |
13e0ca |
* should be between 10 and 20 characters to provide at least 80bits
|
|
Packit |
13e0ca |
* strength, and avoid the need to hash it before using as the
|
|
Packit |
13e0ca |
* hmac key.
|
|
Packit |
13e0ca |
*/
|
|
Packit |
13e0ca |
void
|
|
Packit |
13e0ca |
crypt_sha1_rn (const char *phrase, size_t phr_size,
|
|
Packit |
13e0ca |
const char *setting, size_t ARG_UNUSED (set_size),
|
|
Packit |
13e0ca |
uint8_t *output, size_t out_size,
|
|
Packit |
13e0ca |
void *scratch, size_t scr_size)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
static const char *magic = "$sha1$";
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
if ((out_size < (strlen (magic) + 2 + 10 + CRYPT_SHA1_SALT_LENGTH +
|
|
Packit |
13e0ca |
SHA1_OUTPUT_SIZE)) ||
|
|
Packit |
13e0ca |
scr_size < SHA1_SIZE)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = ERANGE;
|
|
Packit |
13e0ca |
return;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
const char *sp;
|
|
Packit |
13e0ca |
uint8_t *ep;
|
|
Packit |
13e0ca |
unsigned long ul;
|
|
Packit |
13e0ca |
size_t sl;
|
|
Packit |
13e0ca |
size_t pl = phr_size;
|
|
Packit |
13e0ca |
int dl;
|
|
Packit |
13e0ca |
unsigned long iterations;
|
|
Packit |
13e0ca |
unsigned long i;
|
|
Packit |
13e0ca |
/* XXX silence -Wpointer-sign (would be nice to fix this some other way) */
|
|
Packit |
13e0ca |
const uint8_t *pwu = (const uint8_t *)phrase;
|
|
Packit |
13e0ca |
uint8_t *hmac_buf = scratch;
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/*
|
|
Packit |
13e0ca |
* Salt format is
|
|
Packit |
13e0ca |
* $<tag>$<iterations>$salt[$]
|
|
Packit |
13e0ca |
*/
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* If the string doesn't starts with the magic prefix, we shouldn't have been called */
|
|
Packit |
13e0ca |
if (strncmp (setting, magic, strlen (magic)))
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = EINVAL;
|
|
Packit |
13e0ca |
return;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
setting += strlen (magic);
|
|
Packit |
13e0ca |
/* get the iteration count */
|
|
Packit |
13e0ca |
iterations = (unsigned long)strtoul (setting, (char **)&ep, 10);
|
|
Packit |
13e0ca |
if (*ep != '$')
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = EINVAL;
|
|
Packit |
13e0ca |
return; /* invalid input */
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
setting = (char *)ep + 1; /* skip over the '$' */
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* The next 1..CRYPT_SHA1_SALT_LENGTH bytes should be itoa64 characters,
|
|
Packit |
13e0ca |
followed by another '$' (or end of string). */
|
|
Packit |
13e0ca |
sp = setting + strspn (setting, (const char *)itoa64);
|
|
Packit |
13e0ca |
if (sp == setting || (*sp && *sp != '$'))
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = EINVAL;
|
|
Packit |
13e0ca |
return;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
sl = (size_t)(sp - setting);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/*
|
|
Packit |
13e0ca |
* Now get to work...
|
|
Packit |
13e0ca |
* Prime the pump with <salt><magic><iterations>
|
|
Packit |
13e0ca |
*/
|
|
Packit |
13e0ca |
dl = snprintf ((char *)output, out_size, "%.*s%s%lu",
|
|
Packit |
13e0ca |
(int)sl, setting, magic, iterations);
|
|
Packit |
13e0ca |
/*
|
|
Packit |
13e0ca |
* Then hmac using <phrase> as key, and repeat...
|
|
Packit |
13e0ca |
*/
|
|
Packit |
13e0ca |
hmac_sha1_process_data ((const unsigned char *)output, (size_t)dl,
|
|
Packit |
13e0ca |
pwu, pl, hmac_buf);
|
|
Packit |
13e0ca |
for (i = 1; i < iterations; ++i)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
hmac_sha1_process_data (hmac_buf, SHA1_SIZE, pwu, pl, hmac_buf);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
/* Now output... */
|
|
Packit |
13e0ca |
pl = (size_t)snprintf ((char *)output, out_size, "%s%lu$%.*s$",
|
|
Packit |
13e0ca |
magic, iterations, (int)sl, setting);
|
|
Packit |
13e0ca |
ep = output + pl;
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* Every 3 bytes of hash gives 24 bits which is 4 base64 chars */
|
|
Packit |
13e0ca |
for (i = 0; i < SHA1_SIZE - 3; i += 3)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
ul = (unsigned long)((hmac_buf[i+0] << 16) |
|
|
Packit |
13e0ca |
(hmac_buf[i+1] << 8) |
|
|
Packit |
13e0ca |
hmac_buf[i+2]);
|
|
Packit |
13e0ca |
to64 (ep, ul, 4);
|
|
Packit |
13e0ca |
ep += 4;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
/* Only 2 bytes left, so we pad with byte0 */
|
|
Packit |
13e0ca |
ul = (unsigned long)((hmac_buf[SHA1_SIZE - 2] << 16) |
|
|
Packit |
13e0ca |
(hmac_buf[SHA1_SIZE - 1] << 8) |
|
|
Packit |
13e0ca |
hmac_buf[0]);
|
|
Packit |
13e0ca |
to64 (ep, ul, 4);
|
|
Packit |
13e0ca |
ep += 4;
|
|
Packit |
13e0ca |
*ep = '\0';
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* Don't leave anything around in vm they could use. */
|
|
Packit |
13e0ca |
XCRYPT_SECURE_MEMSET (scratch, scr_size);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* Modified excerpt from:
|
|
Packit |
13e0ca |
http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/lib/libcrypt/pw_gensalt.c */
|
|
Packit |
13e0ca |
void
|
|
Packit |
13e0ca |
gensalt_sha1_rn (unsigned long count,
|
|
Packit |
13e0ca |
const uint8_t *rbytes, size_t nrbytes,
|
|
Packit |
13e0ca |
uint8_t *output, size_t o_size)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
static_assert (sizeof (uint32_t) == 4,
|
|
Packit |
13e0ca |
"space calculations below assume 8-bit bytes");
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* Make sure we have enough random bytes to use for the salt.
|
|
Packit |
13e0ca |
The format supports using up to 48 random bytes, but 12 is
|
|
Packit |
13e0ca |
enough. We require another 4 bytes of randomness to perturb
|
|
Packit |
13e0ca |
'count' with. */
|
|
Packit |
13e0ca |
if (nrbytes < 12 + 4)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = EINVAL;
|
|
Packit |
13e0ca |
return;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/* Make sure we have enough output space, given the amount of
|
|
Packit |
13e0ca |
randomness available. $sha1$<10digits>$<(nrbytes-4)*4/3>$ */
|
|
Packit |
13e0ca |
if (o_size < (nrbytes - 4) * 4 / 3 + sizeof "$sha1$$$" + 10)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
errno = ERANGE;
|
|
Packit |
13e0ca |
return;
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
/*
|
|
Packit |
13e0ca |
* We treat 'count' as a hint.
|
|
Packit |
13e0ca |
* Make it harder for someone to pre-compute hashes for a
|
|
Packit |
13e0ca |
* dictionary attack by not using the same iteration count for
|
|
Packit |
13e0ca |
* every entry.
|
|
Packit |
13e0ca |
*/
|
|
Packit |
13e0ca |
uint32_t rounds, random = le32_to_cpu (rbytes);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
if (count == 0)
|
|
Packit |
13e0ca |
count = CRYPT_SHA1_ITERATIONS;
|
|
Packit |
13e0ca |
if (count > UINT32_MAX)
|
|
Packit |
13e0ca |
count = UINT32_MAX;
|
|
Packit |
13e0ca |
rounds = (uint32_t) (count - (random % (count / 4)));
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
uint32_t encbuf;
|
|
Packit |
13e0ca |
int n = snprintf((char *)output, o_size, "$sha1$%u$", (unsigned int)rounds);
|
|
Packit |
13e0ca |
assert (n >= 1 && (size_t)n + 2 < o_size);
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
const uint8_t *r = rbytes + 4;
|
|
Packit |
13e0ca |
const uint8_t *rlim = rbytes + nrbytes;
|
|
Packit |
13e0ca |
uint8_t *o = output + n;
|
|
Packit |
13e0ca |
uint8_t *olim = output + n + CRYPT_SHA1_SALT_LENGTH;
|
|
Packit |
13e0ca |
if (olim + 2 > output + o_size)
|
|
Packit |
13e0ca |
olim = output + o_size - 2;
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
for (; r + 3 < rlim && o + 4 < olim; r += 3, o += 4)
|
|
Packit |
13e0ca |
{
|
|
Packit |
13e0ca |
encbuf = ((((uint32_t)r[0]) << 16) |
|
|
Packit |
13e0ca |
(((uint32_t)r[1]) << 8) |
|
|
Packit |
13e0ca |
(((uint32_t)r[2]) << 0));
|
|
Packit |
13e0ca |
to64 (o, encbuf, 4);
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
o[0] = '$';
|
|
Packit |
13e0ca |
o[1] = '\0';
|
|
Packit |
13e0ca |
}
|
|
Packit |
13e0ca |
|
|
Packit |
13e0ca |
#endif
|