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