wolfSSL SSL/TLS library, support up to TLS1.3

Dependents:   CyaSSL-Twitter-OAuth4Tw Example-client-tls-cert TwitterReader TweetTest ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pwdbased.c Source File

pwdbased.c

00001 /* pwdbased.c
00002  *
00003  * Copyright (C) 2006-2020 wolfSSL Inc.
00004  *
00005  * This file is part of wolfSSL.
00006  *
00007  * wolfSSL is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 2 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * wolfSSL is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
00020  */
00021 
00022 
00023 #ifdef HAVE_CONFIG_H
00024     #include <config.h>
00025 #endif
00026 
00027 #include <wolfssl/wolfcrypt/settings.h>
00028 
00029 #ifndef NO_PWDBASED
00030 
00031 #include <wolfssl/wolfcrypt/pwdbased.h >
00032 #include <wolfssl/wolfcrypt/hmac.h >
00033 #include <wolfssl/wolfcrypt/hash.h >
00034 #include <wolfssl/wolfcrypt/integer.h>
00035 #include <wolfssl/wolfcrypt/error-crypt.h >
00036 
00037 #ifdef NO_INLINE
00038     #include <wolfssl/wolfcrypt/misc.h>
00039 #else
00040     #define WOLFSSL_MISC_INCLUDED
00041     #include <wolfcrypt/src/misc.c>
00042 #endif
00043 
00044 
00045 #ifdef HAVE_PBKDF1
00046 
00047 /* PKCS#5 v1.5 with non standard extension to optionally derive the extra data (IV) */
00048 int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen,
00049     const byte* passwd, int passwdLen, const byte* salt, int saltLen,
00050     int iterations, int hashType, void* heap)
00051 {
00052     int  err;
00053     int  keyLeft, ivLeft, i;
00054     int  digestLeft, store;
00055     int  keyOutput = 0;
00056     int  diestLen;
00057     byte digest[WC_MAX_DIGEST_SIZE];
00058 #ifdef WOLFSSL_SMALL_STACK
00059     wc_HashAlg* hash = NULL;
00060 #else
00061     wc_HashAlg  hash[1];
00062 #endif
00063     enum wc_HashType hashT;
00064 
00065     (void)heap;
00066 
00067     if (key == NULL || keyLen < 0 || passwdLen < 0 || saltLen < 0 || ivLen < 0){
00068         return BAD_FUNC_ARG;
00069     }
00070 
00071     if (iterations <= 0)
00072         iterations = 1;
00073 
00074     hashT = wc_HashTypeConvert(hashType);
00075     err = wc_HashGetDigestSize(hashT);
00076     if (err < 0)
00077         return err;
00078     diestLen = err;
00079 
00080     /* initialize hash */
00081 #ifdef WOLFSSL_SMALL_STACK
00082     hash = (wc_HashAlg*)XMALLOC(sizeof(wc_HashAlg), heap,
00083                                 DYNAMIC_TYPE_HASHCTX);
00084     if (hash == NULL)
00085         return MEMORY_E;
00086 #endif
00087 
00088     err = wc_HashInit_ex(hash, hashT, heap, INVALID_DEVID);
00089     if (err != 0) {
00090     #ifdef WOLFSSL_SMALL_STACK
00091         XFREE(hash, heap, DYNAMIC_TYPE_HASHCTX);
00092     #endif
00093         return err;
00094     }
00095 
00096     keyLeft = keyLen;
00097     ivLeft  = ivLen;
00098     while (keyOutput < (keyLen + ivLen)) {
00099         digestLeft = diestLen;
00100         /* D_(i - 1) */
00101         if (keyOutput) { /* first time D_0 is empty */
00102             err = wc_HashUpdate(hash, hashT, digest, diestLen);
00103             if (err != 0) break;
00104         }
00105 
00106         /* data */
00107         err = wc_HashUpdate(hash, hashT, passwd, passwdLen);
00108         if (err != 0) break;
00109 
00110         /* salt */
00111         if (salt) {
00112             err = wc_HashUpdate(hash, hashT, salt, saltLen);
00113             if (err != 0) break;
00114         }
00115 
00116         err = wc_HashFinal(hash, hashT, digest);
00117         if (err != 0) break;
00118 
00119         /* count */
00120         for (i = 1; i < iterations; i++) {
00121             err = wc_HashUpdate(hash, hashT, digest, diestLen);
00122             if (err != 0) break;
00123 
00124             err = wc_HashFinal(hash, hashT, digest);
00125             if (err != 0) break;
00126         }
00127 
00128         if (keyLeft) {
00129             store = min(keyLeft, diestLen);
00130             XMEMCPY(&key[keyLen - keyLeft], digest, store);
00131 
00132             keyOutput  += store;
00133             keyLeft    -= store;
00134             digestLeft -= store;
00135         }
00136 
00137         if (ivLeft && digestLeft) {
00138             store = min(ivLeft, digestLeft);
00139             if (iv != NULL)
00140                 XMEMCPY(&iv[ivLen - ivLeft],
00141                         &digest[diestLen - digestLeft], store);
00142             keyOutput += store;
00143             ivLeft    -= store;
00144         }
00145     }
00146 
00147     wc_HashFree(hash, hashT);
00148 
00149 #ifdef WOLFSSL_SMALL_STACK
00150     XFREE(hash, heap, DYNAMIC_TYPE_HASHCTX);
00151 #endif
00152 
00153     if (err != 0)
00154         return err;
00155 
00156     if (keyOutput != (keyLen + ivLen))
00157         return BUFFER_E;
00158 
00159     return err;
00160 }
00161 
00162 /* PKCS#5 v1.5 */
00163 int wc_PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt,
00164            int sLen, int iterations, int kLen, int hashType)
00165 {
00166     return wc_PBKDF1_ex(output, kLen, NULL, 0,
00167         passwd, pLen, salt, sLen, iterations, hashType, NULL);
00168 }
00169 
00170 #endif /* HAVE_PKCS5 */
00171 
00172 #ifdef HAVE_PBKDF2
00173 
00174 int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen, const byte* salt,
00175            int sLen, int iterations, int kLen, int hashType, void* heap, int devId)
00176 {
00177     word32 i = 1;
00178     int    hLen;
00179     int    j, ret;
00180 #ifdef WOLFSSL_SMALL_STACK
00181     byte*  buffer;
00182     Hmac*  hmac;
00183 #else
00184     byte   buffer[WC_MAX_DIGEST_SIZE];
00185     Hmac   hmac[1];
00186 #endif
00187     enum wc_HashType hashT;
00188 
00189     if (output == NULL || pLen < 0 || sLen < 0 || kLen < 0) {
00190         return BAD_FUNC_ARG;
00191     }
00192 
00193     if (iterations <= 0)
00194         iterations = 1;
00195 
00196     hashT = wc_HashTypeConvert(hashType);
00197     hLen = wc_HashGetDigestSize(hashT);
00198     if (hLen < 0)
00199         return BAD_FUNC_ARG;
00200 
00201 #ifdef WOLFSSL_SMALL_STACK
00202     buffer = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
00203     if (buffer == NULL)
00204         return MEMORY_E;
00205     hmac = (Hmac*)XMALLOC(sizeof(Hmac), heap, DYNAMIC_TYPE_HMAC);
00206     if (hmac == NULL) {
00207         XFREE(buffer, heap, DYNAMIC_TYPE_TMP_BUFFER);
00208         return MEMORY_E;
00209     }
00210 #endif
00211 
00212     ret = wc_HmacInit(hmac, heap, devId);
00213     if (ret == 0) {
00214         /* use int hashType here, since HMAC FIPS uses the old unique value */
00215         ret = wc_HmacSetKey(hmac, hashType, passwd, pLen);
00216 
00217         while (ret == 0 && kLen) {
00218             int currentLen;
00219 
00220             ret = wc_HmacUpdate(hmac, salt, sLen);
00221             if (ret != 0)
00222                 break;
00223 
00224             /* encode i */
00225             for (j = 0; j < 4; j++) {
00226                 byte b = (byte)(i >> ((3-j) * 8));
00227 
00228                 ret = wc_HmacUpdate(hmac, &b, 1);
00229                 if (ret != 0)
00230                     break;
00231             }
00232 
00233             /* check ret from inside for loop */
00234             if (ret != 0)
00235                 break;
00236 
00237             ret = wc_HmacFinal(hmac, buffer);
00238             if (ret != 0)
00239                 break;
00240 
00241             currentLen = min(kLen, hLen);
00242             XMEMCPY(output, buffer, currentLen);
00243 
00244             for (j = 1; j < iterations; j++) {
00245                 ret = wc_HmacUpdate(hmac, buffer, hLen);
00246                 if (ret != 0)
00247                     break;
00248                 ret = wc_HmacFinal(hmac, buffer);
00249                 if (ret != 0)
00250                     break;
00251                 xorbuf(output, buffer, currentLen);
00252             }
00253 
00254             /* check ret from inside for loop */
00255             if (ret != 0)
00256                 break;
00257 
00258             output += currentLen;
00259             kLen   -= currentLen;
00260             i++;
00261         }
00262         wc_HmacFree(hmac);
00263     }
00264 
00265 #ifdef WOLFSSL_SMALL_STACK
00266     XFREE(buffer, heap, DYNAMIC_TYPE_TMP_BUFFER);
00267     XFREE(hmac, heap, DYNAMIC_TYPE_HMAC);
00268 #endif
00269 
00270     return ret;
00271 }
00272 
00273 int wc_PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt,
00274            int sLen, int iterations, int kLen, int hashType)
00275 {
00276     return wc_PBKDF2_ex(output, passwd, pLen, salt, sLen, iterations, kLen,
00277         hashType, NULL, INVALID_DEVID);
00278 }
00279 
00280 #endif /* HAVE_PBKDF2 */
00281 
00282 #ifdef HAVE_PKCS12
00283 
00284 /* helper for PKCS12_PBKDF(), does hash operation */
00285 static int DoPKCS12Hash(int hashType, byte* buffer, word32 totalLen,
00286                  byte* Ai, word32 u, int iterations)
00287 {
00288     int i;
00289     int ret = 0;
00290 #ifdef WOLFSSL_SMALL_STACK
00291     wc_HashAlg* hash = NULL;
00292 #else
00293     wc_HashAlg  hash[1];
00294 #endif
00295     enum wc_HashType hashT;
00296 
00297     if (buffer == NULL || Ai == NULL) {
00298         return BAD_FUNC_ARG;
00299     }
00300 
00301     hashT = wc_HashTypeConvert(hashType);
00302 
00303     /* initialize hash */
00304 #ifdef WOLFSSL_SMALL_STACK
00305     hash = (wc_HashAlg*)XMALLOC(sizeof(wc_HashAlg), NULL,
00306                                 DYNAMIC_TYPE_HASHCTX);
00307     if (hash == NULL)
00308         return MEMORY_E;
00309 #endif
00310 
00311     ret = wc_HashInit(hash, hashT);
00312     if (ret != 0) {
00313     #ifdef WOLFSSL_SMALL_STACK
00314         XFREE(hash, NULL, DYNAMIC_TYPE_HASHCTX);
00315     #endif
00316         return ret;
00317     }
00318 
00319     ret = wc_HashUpdate(hash, hashT, buffer, totalLen);
00320 
00321     if (ret == 0)
00322         ret = wc_HashFinal(hash, hashT, Ai);
00323 
00324     for (i = 1; i < iterations; i++) {
00325         if (ret == 0)
00326             ret = wc_HashUpdate(hash, hashT, Ai, u);
00327         if (ret == 0)
00328             ret = wc_HashFinal(hash, hashT, Ai);
00329     }
00330 
00331     wc_HashFree(hash, hashT);
00332 
00333 #ifdef WOLFSSL_SMALL_STACK
00334     XFREE(hash, NULL, DYNAMIC_TYPE_HASHCTX);
00335 #endif
00336 
00337     return ret;
00338 }
00339 
00340 
00341 int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,
00342     const byte* salt, int saltLen, int iterations, int kLen, int hashType,
00343     int id)
00344 {
00345     return wc_PKCS12_PBKDF_ex(output, passwd, passLen, salt, saltLen,
00346                               iterations, kLen, hashType, id, NULL);
00347 }
00348 
00349 
00350 /* extended API that allows a heap hint to be used */
00351 int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen,
00352                        const byte* salt, int saltLen, int iterations, int kLen,
00353                        int hashType, int id, void* heap)
00354 {
00355     /* all in bytes instead of bits */
00356     word32 u, v, dLen, pLen, iLen, sLen, totalLen;
00357     int    dynamic = 0;
00358     int    ret = 0;
00359     int    i;
00360     byte   *D, *S, *P, *I;
00361 #ifdef WOLFSSL_SMALL_STACK
00362     byte   staticBuffer[1]; /* force dynamic usage */
00363 #else
00364     byte   staticBuffer[1024];
00365 #endif
00366     byte*  buffer = staticBuffer;
00367 
00368 #ifdef WOLFSSL_SMALL_STACK
00369     byte*  Ai;
00370     byte*  B;
00371 #else
00372     byte   Ai[WC_MAX_DIGEST_SIZE];
00373     byte   B[WC_MAX_BLOCK_SIZE];
00374 #endif
00375     enum wc_HashType hashT;
00376 
00377     (void)heap;
00378 
00379     if (output == NULL || passLen < 0 || saltLen < 0 || kLen < 0) {
00380         return BAD_FUNC_ARG;
00381     }
00382 
00383     if (iterations <= 0)
00384         iterations = 1;
00385 
00386     hashT = wc_HashTypeConvert(hashType);
00387     ret = wc_HashGetDigestSize(hashT);
00388     if (ret < 0)
00389         return ret;
00390     u = ret;
00391 
00392     ret = wc_HashGetBlockSize(hashT);
00393     if (ret < 0)
00394         return ret;
00395     v = ret;
00396 
00397 #ifdef WOLFSSL_SMALL_STACK
00398     Ai = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
00399     if (Ai == NULL)
00400         return MEMORY_E;
00401 
00402     B = (byte*)XMALLOC(WC_MAX_BLOCK_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER);
00403     if (B == NULL) {
00404         XFREE(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER);
00405         return MEMORY_E;
00406     }
00407 #endif
00408 
00409     XMEMSET(Ai, 0, WC_MAX_DIGEST_SIZE);
00410     XMEMSET(B,  0, WC_MAX_BLOCK_SIZE);
00411 
00412     dLen = v;
00413     sLen = v * ((saltLen + v - 1) / v);
00414     if (passLen)
00415         pLen = v * ((passLen + v - 1) / v);
00416     else
00417         pLen = 0;
00418     iLen = sLen + pLen;
00419 
00420     totalLen = dLen + sLen + pLen;
00421 
00422     if (totalLen > sizeof(staticBuffer)) {
00423         buffer = (byte*)XMALLOC(totalLen, heap, DYNAMIC_TYPE_KEY);
00424         if (buffer == NULL) {
00425 #ifdef WOLFSSL_SMALL_STACK
00426             XFREE(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER);
00427             XFREE(B,  heap, DYNAMIC_TYPE_TMP_BUFFER);
00428 #endif
00429             return MEMORY_E;
00430         }
00431         dynamic = 1;
00432     }
00433 
00434     D = buffer;
00435     S = D + dLen;
00436     P = S + sLen;
00437     I = S;
00438 
00439     XMEMSET(D, id, dLen);
00440 
00441     for (i = 0; i < (int)sLen; i++)
00442         S[i] = salt[i % saltLen];
00443     for (i = 0; i < (int)pLen; i++)
00444         P[i] = passwd[i % passLen];
00445 
00446     while (kLen > 0) {
00447         word32 currentLen;
00448         mp_int B1;
00449 
00450         ret = DoPKCS12Hash(hashType, buffer, totalLen, Ai, u, iterations);
00451         if (ret < 0)
00452             break;
00453 
00454         for (i = 0; i < (int)v; i++)
00455             B[i] = Ai[i % u];
00456 
00457         if (mp_init(&B1) != MP_OKAY)
00458             ret = MP_INIT_E;
00459         else if (mp_read_unsigned_bin(&B1, B, v) != MP_OKAY)
00460             ret = MP_READ_E;
00461         else if (mp_add_d(&B1, (mp_digit)1, &B1) != MP_OKAY)
00462             ret = MP_ADD_E;
00463 
00464         if (ret != 0) {
00465             mp_clear(&B1);
00466             break;
00467         }
00468 
00469         for (i = 0; i < (int)iLen; i += v) {
00470             int    outSz;
00471             mp_int i1;
00472             mp_int res;
00473 
00474             if (mp_init_multi(&i1, &res, NULL, NULL, NULL, NULL) != MP_OKAY) {
00475                 ret = MP_INIT_E;
00476                 break;
00477             }
00478             if (mp_read_unsigned_bin(&i1, I + i, v) != MP_OKAY)
00479                 ret = MP_READ_E;
00480             else if (mp_add(&i1, &B1, &res) != MP_OKAY)
00481                 ret = MP_ADD_E;
00482             else if ( (outSz = mp_unsigned_bin_size(&res)) < 0)
00483                 ret = MP_TO_E;
00484             else {
00485                 if (outSz > (int)v) {
00486                     /* take off MSB */
00487                     byte  tmp[WC_MAX_BLOCK_SIZE + 1];
00488                     ret = mp_to_unsigned_bin(&res, tmp);
00489                     XMEMCPY(I + i, tmp + 1, v);
00490                 }
00491                 else if (outSz < (int)v) {
00492                     XMEMSET(I + i, 0, v - outSz);
00493                     ret = mp_to_unsigned_bin(&res, I + i + v - outSz);
00494                 }
00495                 else
00496                     ret = mp_to_unsigned_bin(&res, I + i);
00497             }
00498 
00499             mp_clear(&i1);
00500             mp_clear(&res);
00501             if (ret < 0) break;
00502         }
00503 
00504         currentLen = min(kLen, (int)u);
00505         XMEMCPY(output, Ai, currentLen);
00506         output += currentLen;
00507         kLen   -= currentLen;
00508         mp_clear(&B1);
00509     }
00510 
00511     if (dynamic) XFREE(buffer, heap, DYNAMIC_TYPE_KEY);
00512 
00513 #ifdef WOLFSSL_SMALL_STACK
00514     XFREE(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER);
00515     XFREE(B,  heap, DYNAMIC_TYPE_TMP_BUFFER);
00516 #endif
00517 
00518     return ret;
00519 }
00520 
00521 #endif /* HAVE_PKCS12 */
00522 
00523 #ifdef HAVE_SCRYPT
00524 /* Rotate the 32-bit value a by b bits to the left.
00525  *
00526  * a  32-bit value.
00527  * b  Number of bits to rotate.
00528  * returns rotated value.
00529  */
00530 #define R(a, b) rotlFixed(a, b)
00531 
00532 /* One round of Salsa20/8.
00533  * Code taken from RFC 7914: scrypt PBKDF.
00534  *
00535  * out  Output buffer.
00536  * in   Input data to hash.
00537  */
00538 static void scryptSalsa(word32* out, word32* in)
00539 {
00540     int    i;
00541     word32 x[16];
00542 
00543 #ifdef LITTLE_ENDIAN_ORDER
00544     for (i = 0; i < 16; ++i)
00545         x[i] = in[i];
00546 #else
00547     for (i = 0; i < 16; i++)
00548         x[i] = ByteReverseWord32(in[i]);
00549 #endif
00550     for (i = 8; i > 0; i -= 2) {
00551         x[ 4] ^= R(x[ 0] + x[12],  7);  x[ 8] ^= R(x[ 4] + x[ 0],  9);
00552         x[12] ^= R(x[ 8] + x[ 4], 13);  x[ 0] ^= R(x[12] + x[ 8], 18);
00553         x[ 9] ^= R(x[ 5] + x[ 1],  7);  x[13] ^= R(x[ 9] + x[ 5],  9);
00554         x[ 1] ^= R(x[13] + x[ 9], 13);  x[ 5] ^= R(x[ 1] + x[13], 18);
00555         x[14] ^= R(x[10] + x[ 6],  7);  x[ 2] ^= R(x[14] + x[10],  9);
00556         x[ 6] ^= R(x[ 2] + x[14], 13);  x[10] ^= R(x[ 6] + x[ 2], 18);
00557         x[ 3] ^= R(x[15] + x[11],  7);  x[ 7] ^= R(x[ 3] + x[15],  9);
00558         x[11] ^= R(x[ 7] + x[ 3], 13);  x[15] ^= R(x[11] + x[ 7], 18);
00559         x[ 1] ^= R(x[ 0] + x[ 3],  7);  x[ 2] ^= R(x[ 1] + x[ 0],  9);
00560         x[ 3] ^= R(x[ 2] + x[ 1], 13);  x[ 0] ^= R(x[ 3] + x[ 2], 18);
00561         x[ 6] ^= R(x[ 5] + x[ 4],  7);  x[ 7] ^= R(x[ 6] + x[ 5],  9);
00562         x[ 4] ^= R(x[ 7] + x[ 6], 13);  x[ 5] ^= R(x[ 4] + x[ 7], 18);
00563         x[11] ^= R(x[10] + x[ 9],  7);  x[ 8] ^= R(x[11] + x[10],  9);
00564         x[ 9] ^= R(x[ 8] + x[11], 13);  x[10] ^= R(x[ 9] + x[ 8], 18);
00565         x[12] ^= R(x[15] + x[14],  7);  x[13] ^= R(x[12] + x[15],  9);
00566         x[14] ^= R(x[13] + x[12], 13);  x[15] ^= R(x[14] + x[13], 18);
00567     }
00568 #ifdef LITTLE_ENDIAN_ORDER
00569     for (i = 0; i < 16; ++i)
00570         out[i] = in[i] + x[i];
00571 #else
00572     for (i = 0; i < 16; i++)
00573         out[i] = ByteReverseWord32(ByteReverseWord32(in[i]) + x[i]);
00574 #endif
00575 }
00576 
00577 /* Mix a block using Salsa20/8.
00578  * Based on RFC 7914: scrypt PBKDF.
00579  *
00580  * b  Blocks to mix.
00581  * y  Temporary storage.
00582  * r  Size of the block.
00583  */
00584 static void scryptBlockMix(byte* b, byte* y, int r)
00585 {
00586     byte x[64];
00587 #ifdef WORD64_AVAILABLE
00588     word64* b64 = (word64*)b;
00589     word64* y64 = (word64*)y;
00590     word64* x64 = (word64*)x;
00591 #else
00592     word32* b32 = (word32*)b;
00593     word32* y32 = (word32*)y;
00594     word32* x32 = (word32*)x;
00595 #endif
00596     int  i;
00597     int  j;
00598 
00599     /* Step 1. */
00600     XMEMCPY(x, b + (2 * r - 1) * 64, sizeof(x));
00601     /* Step 2. */
00602     for (i = 0; i < 2 * r; i++)
00603     {
00604 #ifdef WORD64_AVAILABLE
00605         for (j = 0; j < 8; j++)
00606             x64[j] ^= b64[i * 8 + j];
00607 #else
00608         for (j = 0; j < 16; j++)
00609             x32[j] ^= b32[i * 16 + j];
00610 #endif
00611         scryptSalsa((word32*)x, (word32*)x);
00612         XMEMCPY(y + i * 64, x, sizeof(x));
00613     }
00614     /* Step 3. */
00615     for (i = 0; i < r; i++) {
00616 #ifdef WORD64_AVAILABLE
00617         for (j = 0; j < 8; j++) {
00618             b64[i * 8 + j] = y64[2 * i * 8 + j];
00619             b64[(r + i) * 8 + j] = y64[(2 * i + 1) * 8 + j];
00620         }
00621 #else
00622         for (j = 0; j < 16; j++) {
00623             b32[i * 16 + j] = y32[2 * i * 16 + j];
00624             b32[(r + i) * 16 + j] = y32[(2 * i + 1) * 16 + j];
00625         }
00626 #endif
00627     }
00628 }
00629 
00630 /* Random oracles mix.
00631  * Based on RFC 7914: scrypt PBKDF.
00632  *
00633  * x  Data to mix.
00634  * v  Temporary buffer.
00635  * y  Temporary buffer for the block mix.
00636  * r  Block size parameter.
00637  * n  CPU/Memory cost parameter.
00638  */
00639 static void scryptROMix(byte* x, byte* v, byte* y, int r, word32 n)
00640 {
00641     word32 i;
00642     word32 j;
00643     word32 k;
00644     word32 bSz = 128 * r;
00645 #ifdef WORD64_AVAILABLE
00646     word64* x64 = (word64*)x;
00647     word64* v64 = (word64*)v;
00648 #else
00649     word32* x32 = (word32*)x;
00650     word32* v32 = (word32*)v;
00651 #endif
00652 
00653     /* Step 1. X = B (B not needed therefore not implemented) */
00654     /* Step 2. */
00655     for (i = 0; i < n; i++)
00656     {
00657         XMEMCPY(v + i * bSz, x, bSz);
00658         scryptBlockMix(x, y, r);
00659     }
00660 
00661     /* Step 3. */
00662     for (i = 0; i < n; i++)
00663     {
00664 #ifdef LITTLE_ENDIAN_ORDER
00665 #ifdef WORD64_AVAILABLE
00666         j = *(word64*)(x + (2*r - 1) * 64) & (n-1);
00667 #else
00668         j = *(word32*)(x + (2*r - 1) * 64) & (n-1);
00669 #endif
00670 #else
00671         byte* t = x + (2*r - 1) * 64;
00672         j = (t[0] | (t[1] << 8) | (t[2] << 16) | ((word32)t[3] << 24)) & (n-1);
00673 #endif
00674 #ifdef WORD64_AVAILABLE
00675         for (k = 0; k < bSz / 8; k++)
00676             x64[k] ^= v64[j * bSz / 8 + k];
00677 #else
00678         for (k = 0; k < bSz / 4; k++)
00679             x32[k] ^= v32[j * bSz / 4 + k];
00680 #endif
00681         scryptBlockMix(x, y, r);
00682     }
00683     /* Step 4. B' = X (B = X = B' so not needed, therefore not implemented) */
00684 }
00685 
00686 /* Generates an key derived from a password and salt using a memory hard
00687  * algorithm.
00688  * Implements RFC 7914: scrypt PBKDF.
00689  *
00690  * output     The derived key.
00691  * passwd     The password to derive key from.
00692  * passLen    The length of the password.
00693  * salt       The key specific data.
00694  * saltLen    The length of the salt data.
00695  * cost       The CPU/memory cost parameter. Range: 1..(128*r/8-1)
00696  *            (Iterations = 2^cost)
00697  * blockSize  The number of 128 byte octets in a working block.
00698  * parallel   The number of parallel mix operations to perform.
00699  *            (Note: this implementation does not use threads.)
00700  * dkLen      The length of the derived key in bytes.
00701  * returns BAD_FUNC_ARG when: blockSize is too large for cost.
00702  */
00703 int wc_scrypt(byte* output, const byte* passwd, int passLen,
00704               const byte* salt, int saltLen, int cost, int blockSize,
00705               int parallel, int dkLen)
00706 {
00707     int    ret = 0;
00708     int    i;
00709     byte*  v = NULL;
00710     byte*  y = NULL;
00711     byte*  blocks = NULL;
00712     word32 blocksSz;
00713     word32 bSz;
00714 
00715     if (blockSize > 8)
00716         return BAD_FUNC_ARG;
00717 
00718     if (cost < 1 || cost >= 128 * blockSize / 8 || parallel < 1 || dkLen < 1)
00719         return BAD_FUNC_ARG;
00720 
00721     bSz = 128 * blockSize;
00722     blocksSz = bSz * parallel;
00723     blocks = (byte*)XMALLOC(blocksSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00724     if (blocks == NULL)
00725         goto end;
00726     /* Temporary for scryptROMix. */
00727     v = (byte*)XMALLOC((1 << cost) * bSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00728     if (v == NULL)
00729         goto end;
00730     /* Temporary for scryptBlockMix. */
00731     y = (byte*)XMALLOC(blockSize * 128, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00732     if (y == NULL)
00733         goto end;
00734 
00735     /* Step 1. */
00736     ret = wc_PBKDF2(blocks, passwd, passLen, salt, saltLen, 1, blocksSz,
00737                     WC_SHA256);
00738     if (ret != 0)
00739         goto end;
00740 
00741     /* Step 2. */
00742     for (i = 0; i < parallel; i++)
00743         scryptROMix(blocks + i * bSz, v, y, blockSize, 1 << cost);
00744 
00745     /* Step 3. */
00746     ret = wc_PBKDF2(output, passwd, passLen, blocks, blocksSz, 1, dkLen,
00747                     WC_SHA256);
00748 end:
00749     if (blocks != NULL)
00750         XFREE(blocks, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00751     if (v != NULL)
00752         XFREE(v, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00753     if (y != NULL)
00754         XFREE(y, NULL, DYNAMIC_TYPE_TMP_BUFFER);
00755 
00756     return ret;
00757 }
00758 
00759 /* Generates an key derived from a password and salt using a memory hard
00760  * algorithm.
00761  * Implements RFC 7914: scrypt PBKDF.
00762  *
00763  * output      Derived key.
00764  * passwd      Password to derive key from.
00765  * passLen     Length of the password.
00766  * salt        Key specific data.
00767  * saltLen     Length of the salt data.
00768  * iterations  Number of iterations to perform. Range: 1 << (1..(128*r/8-1))
00769  * blockSize   Number of 128 byte octets in a working block.
00770  * parallel    Number of parallel mix operations to perform.
00771  *             (Note: this implementation does not use threads.)
00772  * dkLen       Length of the derived key in bytes.
00773  * returns BAD_FUNC_ARG when: iterations is not a power of 2 or blockSize is too
00774  *                            large for iterations.
00775  */
00776 int wc_scrypt_ex(byte* output, const byte* passwd, int passLen,
00777                  const byte* salt, int saltLen, word32 iterations,
00778                  int blockSize, int parallel, int dkLen)
00779 {
00780     int cost;
00781 
00782     /* Iterations must be a power of 2. */
00783     if ((iterations & (iterations - 1)) != 0)
00784         return BAD_FUNC_ARG;
00785 
00786     for (cost = -1; iterations != 0; cost++) {
00787         iterations >>= 1;
00788     }
00789 
00790     return wc_scrypt(output, passwd, passLen, salt, saltLen, cost, blockSize,
00791                      parallel, dkLen);
00792 }
00793 #endif /* HAVE_SCRYPT */
00794 
00795 #endif /* NO_PWDBASED */
00796