/*- * Copyright 2013 Alexander Peslyak * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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 #include #include "crypto_pwhash_scryptsalsa208sha256.h" #include "crypto_scrypt.h" #include "runtime.h" #include "utils.h" static const char * const itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; static uint8_t * encode64_uint32(uint8_t * dst, size_t dstlen, uint32_t src, uint32_t srcbits) { uint32_t bit; for (bit = 0; bit < srcbits; bit += 6) { if (dstlen < 1) { return NULL; } *dst++ = itoa64[src & 0x3f]; dstlen--; src >>= 6; } return dst; } static uint8_t * encode64(uint8_t * dst, size_t dstlen, const uint8_t * src, size_t srclen) { size_t i; for (i = 0; i < srclen; ) { uint8_t * dnext; uint32_t value = 0, bits = 0; do { value |= (uint32_t)src[i++] << bits; bits += 8; } while (bits < 24 && i < srclen); dnext = encode64_uint32(dst, dstlen, value, bits); if (!dnext) { return NULL; } dstlen -= dnext - dst; dst = dnext; } return dst; } static int decode64_one(uint32_t * dst, uint8_t src) { const char *ptr = strchr(itoa64, src); if (ptr) { *dst = ptr - itoa64; return 0; } *dst = 0; return -1; } static const uint8_t * decode64_uint32(uint32_t * dst, uint32_t dstbits, const uint8_t * src) { uint32_t bit; uint32_t value; value = 0; for (bit = 0; bit < dstbits; bit += 6) { uint32_t one; if (decode64_one(&one, *src)) { *dst = 0; return NULL; } src++; value |= one << bit; } *dst = value; return src; } uint8_t * escrypt_r(escrypt_local_t * local, const uint8_t * passwd, size_t passwdlen, const uint8_t * setting, uint8_t * buf, size_t buflen) { uint8_t hash[crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES]; escrypt_kdf_t escrypt_kdf; const uint8_t *src; const uint8_t *salt; uint8_t *dst; size_t prefixlen; size_t saltlen; size_t need; uint64_t N; uint32_t N_log2; uint32_t r; uint32_t p; if (setting[0] != '$' || setting[1] != '7' || setting[2] != '$') { return NULL; } src = setting + 3; if (decode64_one(&N_log2, *src)) { return NULL; } src++; N = (uint64_t)1 << N_log2; src = decode64_uint32(&r, 30, src); if (!src) { return NULL; } src = decode64_uint32(&p, 30, src); if (!src) { return NULL; } prefixlen = src - setting; salt = src; src = (uint8_t *) strrchr((char *)salt, '$'); if (src) { saltlen = src - salt; } else { saltlen = strlen((char *)salt); } need = prefixlen + saltlen + 1 + crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1; if (need > buflen || need < saltlen) { return NULL; } #if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) escrypt_kdf = sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; #else escrypt_kdf = escrypt_kdf_nosse; #endif if (escrypt_kdf(local, passwd, passwdlen, salt, saltlen, N, r, p, hash, sizeof(hash))) { return NULL; } dst = buf; memcpy(dst, setting, prefixlen + saltlen); dst += prefixlen + saltlen; *dst++ = '$'; dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash)); sodium_memzero(hash, sizeof hash); if (!dst || dst >= buf + buflen) { /* Can't happen */ return NULL; } *dst = 0; /* NUL termination */ return buf; } uint8_t * escrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, const uint8_t * src, size_t srclen, uint8_t * buf, size_t buflen) { uint8_t *dst; size_t prefixlen = (sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */); size_t saltlen = BYTES2CHARS(srclen); size_t need; need = prefixlen + saltlen + 1; if (need > buflen || need < saltlen || saltlen < srclen) { return NULL; } if (N_log2 > 63 || ((uint64_t)r * (uint64_t)p >= (1U << 30))) { return NULL; } dst = buf; *dst++ = '$'; *dst++ = '7'; *dst++ = '$'; *dst++ = itoa64[N_log2]; dst = encode64_uint32(dst, buflen - (dst - buf), r, 30); if (!dst) { /* Can't happen */ return NULL; } dst = encode64_uint32(dst, buflen - (dst - buf), p, 30); if (!dst) { /* Can't happen */ return NULL; } dst = encode64(dst, buflen - (dst - buf), src, srclen); if (!dst || dst >= buf + buflen) { /* Can't happen */ return NULL; } *dst = 0; /* NUL termination */ return buf; } int crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t * passwd, size_t passwdlen, const uint8_t * salt, size_t saltlen, uint64_t N, uint32_t r, uint32_t p, uint8_t * buf, size_t buflen) { escrypt_kdf_t escrypt_kdf; escrypt_local_t local; int retval; if (escrypt_init_local(&local)) { return -1; } #if defined(HAVE_EMMINTRIN_H) || defined(_MSC_VER) escrypt_kdf = sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse; #else escrypt_kdf = escrypt_kdf_nosse; #endif retval = escrypt_kdf(&local, passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen); if (escrypt_free_local(&local)) { return -1; } return retval; }