Home | History | Annotate | Line # | Download | only in scryptsalsa208sha256
      1 /*-
      2  * Copyright 2013 Alexander Peslyak
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted.
      7  *
      8  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
      9  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     10  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     11  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     12  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     13  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     14  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     15  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     16  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     17  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     18  * SUCH DAMAGE.
     19  */
     20 
     21 #include <stdint.h>
     22 #include <string.h>
     23 
     24 #include "crypto_pwhash_scryptsalsa208sha256.h"
     25 #include "crypto_scrypt.h"
     26 #include "private/common.h"
     27 #include "runtime.h"
     28 #include "utils.h"
     29 
     30 static const char *const itoa64 =
     31     "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
     32 
     33 static uint8_t *
     34 encode64_uint32(uint8_t *dst, size_t dstlen, uint32_t src, uint32_t srcbits)
     35 {
     36     uint32_t bit;
     37 
     38     for (bit = 0; bit < srcbits; bit += 6) {
     39         if (dstlen < 1) {
     40             return NULL; /* LCOV_EXCL_LINE */
     41         }
     42         *dst++ = itoa64[src & 0x3f];
     43         dstlen--;
     44         src >>= 6;
     45     }
     46     return dst;
     47 }
     48 
     49 static uint8_t *
     50 encode64(uint8_t *dst, size_t dstlen, const uint8_t *src, size_t srclen)
     51 {
     52     size_t i;
     53 
     54     for (i = 0; i < srclen;) {
     55         uint8_t *dnext;
     56         uint32_t value = 0, bits = 0;
     57 
     58         do {
     59             value |= (uint32_t) src[i++] << bits;
     60             bits += 8;
     61         } while (bits < 24 && i < srclen);
     62 
     63         dnext = encode64_uint32(dst, dstlen, value, bits);
     64         if (!dnext) {
     65             return NULL; /* LCOV_EXCL_LINE */
     66         }
     67         dstlen -= dnext - dst;
     68         dst = dnext;
     69     }
     70     return dst;
     71 }
     72 
     73 static int
     74 decode64_one(uint32_t *dst, uint8_t src)
     75 {
     76     const char *ptr = strchr(itoa64, src);
     77 
     78     if (ptr) {
     79         *dst = (uint32_t)(ptr - itoa64);
     80         return 0;
     81     }
     82     *dst = 0;
     83 
     84     return -1;
     85 }
     86 
     87 static const uint8_t *
     88 decode64_uint32(uint32_t *dst, uint32_t dstbits, const uint8_t *src)
     89 {
     90     uint32_t bit;
     91     uint32_t value;
     92 
     93     value = 0;
     94     for (bit = 0; bit < dstbits; bit += 6) {
     95         uint32_t one;
     96         if (decode64_one(&one, *src)) {
     97             *dst = 0;
     98             return NULL;
     99         }
    100         src++;
    101         value |= one << bit;
    102     }
    103     *dst = value;
    104 
    105     return src;
    106 }
    107 
    108 const uint8_t *
    109 escrypt_parse_setting(const uint8_t *setting,
    110                       uint32_t *N_log2_p, uint32_t *r_p, uint32_t *p_p)
    111 {
    112     const uint8_t *src;
    113 
    114     if (setting[0] != '$' || setting[1] != '7' || setting[2] != '$') {
    115         return NULL;
    116     }
    117     src = setting + 3;
    118 
    119     if (decode64_one(N_log2_p, *src)) {
    120         return NULL;
    121     }
    122     src++;
    123 
    124     src = decode64_uint32(r_p, 30, src);
    125     if (!src) {
    126         return NULL;
    127     }
    128 
    129     src = decode64_uint32(p_p, 30, src);
    130     if (!src) {
    131         return NULL;
    132     }
    133     return src;
    134 }
    135 
    136 uint8_t *
    137 escrypt_r(escrypt_local_t *local, const uint8_t *passwd, size_t passwdlen,
    138           const uint8_t *setting, uint8_t *buf, size_t buflen)
    139 {
    140     uint8_t        hash[crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES];
    141     escrypt_kdf_t  escrypt_kdf;
    142     const uint8_t *src;
    143     const uint8_t *salt;
    144     uint8_t       *dst;
    145     size_t         prefixlen;
    146     size_t         saltlen;
    147     size_t         need;
    148     uint64_t       N;
    149     uint32_t       N_log2;
    150     uint32_t       r;
    151     uint32_t       p;
    152 
    153     src = escrypt_parse_setting(setting, &N_log2, &r, &p);
    154     if (!src) {
    155         return NULL;
    156     }
    157     N = (uint64_t) 1 << N_log2;
    158     prefixlen = src - setting;
    159 
    160     salt = src;
    161     src  = (uint8_t *) strrchr((char *) salt, '$');
    162     if (src) {
    163         saltlen = src - salt;
    164     } else {
    165         saltlen = strlen((char *) salt);
    166     }
    167     need = prefixlen + saltlen + 1 +
    168            crypto_pwhash_scryptsalsa208sha256_STRHASHBYTES_ENCODED + 1;
    169     if (need > buflen || need < saltlen) {
    170         return NULL;
    171     }
    172 #ifdef HAVE_EMMINTRIN_H
    173     escrypt_kdf =
    174         sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse;
    175 #else
    176     escrypt_kdf = escrypt_kdf_nosse;
    177 #endif
    178     if (escrypt_kdf(local, passwd, passwdlen, salt, saltlen, N, r, p, hash,
    179                     sizeof(hash))) {
    180         return NULL;
    181     }
    182     dst = buf;
    183     memcpy(dst, setting, prefixlen + saltlen);
    184     dst += prefixlen + saltlen;
    185     *dst++ = '$';
    186 
    187     dst = encode64(dst, buflen - (dst - buf), hash, sizeof(hash));
    188     sodium_memzero(hash, sizeof hash);
    189     if (!dst || dst >= buf + buflen) {
    190         return NULL; /* Can't happen LCOV_EXCL_LINE */
    191     }
    192     *dst = 0; /* NUL termination */
    193 
    194     return buf;
    195 }
    196 
    197 uint8_t *
    198 escrypt_gensalt_r(uint32_t N_log2, uint32_t r, uint32_t p, const uint8_t *src,
    199                   size_t srclen, uint8_t *buf, size_t buflen)
    200 {
    201     uint8_t *dst;
    202     size_t   prefixlen =
    203         (sizeof "$7$" - 1U) + (1U /* N_log2 */) + (5U /* r */) + (5U /* p */);
    204     size_t saltlen = BYTES2CHARS(srclen);
    205     size_t need;
    206 
    207     need = prefixlen + saltlen + 1;
    208     if (need > buflen || need < saltlen || saltlen < srclen) {
    209         return NULL; /* LCOV_EXCL_LINE */
    210     }
    211     if (N_log2 > 63 || ((uint64_t) r * (uint64_t) p >= (1U << 30))) {
    212         return NULL; /* LCOV_EXCL_LINE */
    213     }
    214     dst    = buf;
    215     *dst++ = '$';
    216     *dst++ = '7';
    217     *dst++ = '$';
    218 
    219     *dst++ = itoa64[N_log2];
    220 
    221     dst = encode64_uint32(dst, buflen - (dst - buf), r, 30);
    222     if (!dst) {
    223         return NULL; /* Can't happen LCOV_EXCL_LINE */
    224     }
    225     dst = encode64_uint32(dst, buflen - (dst - buf), p, 30);
    226     if (!dst) {
    227         return NULL; /* Can't happen LCOV_EXCL_LINE */
    228     }
    229     dst = encode64(dst, buflen - (dst - buf), src, srclen);
    230     if (!dst || dst >= buf + buflen) {
    231         return NULL; /* Can't happen LCOV_EXCL_LINE */
    232     }
    233     *dst = 0; /* NUL termination */
    234 
    235     return buf;
    236 }
    237 
    238 int
    239 crypto_pwhash_scryptsalsa208sha256_ll(const uint8_t *passwd, size_t passwdlen,
    240                                       const uint8_t *salt, size_t saltlen,
    241                                       uint64_t N, uint32_t r, uint32_t p,
    242                                       uint8_t *buf, size_t buflen)
    243 {
    244     escrypt_kdf_t   escrypt_kdf;
    245     escrypt_local_t local;
    246     int             retval;
    247 
    248     if (escrypt_init_local(&local)) {
    249         return -1; /* LCOV_EXCL_LINE */
    250     }
    251 #if defined(HAVE_EMMINTRIN_H)
    252     escrypt_kdf =
    253         sodium_runtime_has_sse2() ? escrypt_kdf_sse : escrypt_kdf_nosse;
    254 #else
    255     escrypt_kdf = escrypt_kdf_nosse;
    256 #endif
    257     retval = escrypt_kdf(&local, passwd, passwdlen, salt, saltlen, N, r, p, buf,
    258                          buflen);
    259     if (escrypt_free_local(&local)) {
    260         return -1; /* LCOV_EXCL_LINE */
    261     }
    262     return retval;
    263 }
    264