diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pwdbased.c')
-rw-r--r-- | FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pwdbased.c | 785 |
1 files changed, 509 insertions, 276 deletions
diff --git a/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pwdbased.c b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pwdbased.c index b9764d8d0..c672c2285 100644 --- a/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pwdbased.c +++ b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pwdbased.c @@ -1,8 +1,8 @@ /* pwdbased.c * - * Copyright (C) 2006-2015 wolfSSL Inc. + * Copyright (C) 2006-2020 wolfSSL Inc. * - * This file is part of wolfSSL. (formerly known as CyaSSL) + * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,9 +16,10 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -27,176 +28,196 @@ #ifndef NO_PWDBASED -#ifdef WOLFSSL_PIC32MZ_HASH - #ifndef NO_MD5 - #define wc_InitMd5 wc_InitMd5_sw - #define wc_Md5Update wc_Md5Update_sw - #define wc_Md5Final wc_Md5Final_sw - #endif /* NO_MD5 */ - - #define wc_InitSha wc_InitSha_sw - #define wc_ShaUpdate wc_ShaUpdate_sw - #define wc_ShaFinal wc_ShaFinal_sw - - #define wc_InitSha256 wc_InitSha256_sw - #define wc_Sha256Update wc_Sha256Update_sw - #define wc_Sha256Final wc_Sha256Final_sw -#endif - #include <wolfssl/wolfcrypt/pwdbased.h> #include <wolfssl/wolfcrypt/hmac.h> +#include <wolfssl/wolfcrypt/hash.h> #include <wolfssl/wolfcrypt/integer.h> #include <wolfssl/wolfcrypt/error-crypt.h> -#if defined(WOLFSSL_SHA512) || defined(WOLFSSL_SHA384) - #include <wolfssl/wolfcrypt/sha512.h> -#endif #ifdef NO_INLINE #include <wolfssl/wolfcrypt/misc.h> #else + #define WOLFSSL_MISC_INCLUDED #include <wolfcrypt/src/misc.c> #endif -#ifndef WOLFSSL_HAVE_MIN -#define WOLFSSL_HAVE_MIN - - static INLINE word32 min(word32 a, word32 b) - { - return a > b ? b : a; - } -#endif /* WOLFSSL_HAVE_MIN */ +#ifdef HAVE_PBKDF1 - -#ifndef NO_SHA -/* PBKDF1 needs at least SHA available */ -int wc_PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt, - int sLen, int iterations, int kLen, int hashType) +/* PKCS#5 v1.5 with non standard extension to optionally derive the extra data (IV) */ +int wc_PBKDF1_ex(byte* key, int keyLen, byte* iv, int ivLen, + const byte* passwd, int passwdLen, const byte* salt, int saltLen, + int iterations, int hashType, void* heap) { - Sha sha; -#ifndef NO_MD5 - Md5 md5; + int err; + int keyLeft, ivLeft, i; + int digestLeft, store; + int keyOutput = 0; + int diestLen; + byte digest[WC_MAX_DIGEST_SIZE]; +#ifdef WOLFSSL_SMALL_STACK + wc_HashAlg* hash = NULL; +#else + wc_HashAlg hash[1]; #endif - int hLen = (int)SHA_DIGEST_SIZE; - int i, ret = 0; - byte buffer[SHA_DIGEST_SIZE]; /* max size */ + enum wc_HashType hashT; - if (hashType != MD5 && hashType != SHA) + (void)heap; + + if (key == NULL || keyLen < 0 || passwdLen < 0 || saltLen < 0 || ivLen < 0){ return BAD_FUNC_ARG; + } -#ifndef NO_MD5 - if (hashType == MD5) - hLen = (int)MD5_DIGEST_SIZE; -#endif + if (iterations <= 0) + iterations = 1; - if (kLen > hLen) - return BAD_FUNC_ARG; + hashT = wc_HashTypeConvert(hashType); + err = wc_HashGetDigestSize(hashT); + if (err < 0) + return err; + diestLen = err; - if (iterations < 1) - return BAD_FUNC_ARG; + /* initialize hash */ +#ifdef WOLFSSL_SMALL_STACK + hash = (wc_HashAlg*)XMALLOC(sizeof(wc_HashAlg), heap, + DYNAMIC_TYPE_HASHCTX); + if (hash == NULL) + return MEMORY_E; +#endif - switch (hashType) { -#ifndef NO_MD5 - case MD5: - wc_InitMd5(&md5); - wc_Md5Update(&md5, passwd, pLen); - wc_Md5Update(&md5, salt, sLen); - wc_Md5Final(&md5, buffer); - break; -#endif /* NO_MD5 */ - case SHA: - default: - ret = wc_InitSha(&sha); - if (ret != 0) - return ret; - wc_ShaUpdate(&sha, passwd, pLen); - wc_ShaUpdate(&sha, salt, sLen); - wc_ShaFinal(&sha, buffer); - break; + err = wc_HashInit_ex(hash, hashT, heap, INVALID_DEVID); + if (err != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(hash, heap, DYNAMIC_TYPE_HASHCTX); + #endif + return err; } - for (i = 1; i < iterations; i++) { - if (hashType == SHA) { - wc_ShaUpdate(&sha, buffer, hLen); - wc_ShaFinal(&sha, buffer); + keyLeft = keyLen; + ivLeft = ivLen; + while (keyOutput < (keyLen + ivLen)) { + digestLeft = diestLen; + /* D_(i - 1) */ + if (keyOutput) { /* first time D_0 is empty */ + err = wc_HashUpdate(hash, hashT, digest, diestLen); + if (err != 0) break; } -#ifndef NO_MD5 - else { - wc_Md5Update(&md5, buffer, hLen); - wc_Md5Final(&md5, buffer); + + /* data */ + err = wc_HashUpdate(hash, hashT, passwd, passwdLen); + if (err != 0) break; + + /* salt */ + if (salt) { + err = wc_HashUpdate(hash, hashT, salt, saltLen); + if (err != 0) break; } -#endif - } - XMEMCPY(output, buffer, kLen); - return 0; -} -#endif /* NO_SHA */ + err = wc_HashFinal(hash, hashT, digest); + if (err != 0) break; + /* count */ + for (i = 1; i < iterations; i++) { + err = wc_HashUpdate(hash, hashT, digest, diestLen); + if (err != 0) break; -int GetDigestSize(int hashType) -{ - int hLen; + err = wc_HashFinal(hash, hashT, digest); + if (err != 0) break; + } - switch (hashType) { -#ifndef NO_MD5 - case MD5: - hLen = MD5_DIGEST_SIZE; - break; -#endif -#ifndef NO_SHA - case SHA: - hLen = SHA_DIGEST_SIZE; - break; -#endif -#ifndef NO_SHA256 - case SHA256: - hLen = SHA256_DIGEST_SIZE; - break; -#endif -#ifdef WOLFSSL_SHA512 - case SHA512: - hLen = SHA512_DIGEST_SIZE; - break; -#endif - default: - return BAD_FUNC_ARG; + if (keyLeft) { + store = min(keyLeft, diestLen); + XMEMCPY(&key[keyLen - keyLeft], digest, store); + + keyOutput += store; + keyLeft -= store; + digestLeft -= store; + } + + if (ivLeft && digestLeft) { + store = min(ivLeft, digestLeft); + if (iv != NULL) + XMEMCPY(&iv[ivLen - ivLeft], + &digest[diestLen - digestLeft], store); + keyOutput += store; + ivLeft -= store; + } } - return hLen; -} + wc_HashFree(hash, hashT); +#ifdef WOLFSSL_SMALL_STACK + XFREE(hash, heap, DYNAMIC_TYPE_HASHCTX); +#endif -int wc_PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt, + if (err != 0) + return err; + + if (keyOutput != (keyLen + ivLen)) + return BUFFER_E; + + return err; +} + +/* PKCS#5 v1.5 */ +int wc_PBKDF1(byte* output, const byte* passwd, int pLen, const byte* salt, int sLen, int iterations, int kLen, int hashType) { + return wc_PBKDF1_ex(output, kLen, NULL, 0, + passwd, pLen, salt, sLen, iterations, hashType, NULL); +} + +#endif /* HAVE_PKCS5 */ + +#ifdef HAVE_PBKDF2 + +int wc_PBKDF2_ex(byte* output, const byte* passwd, int pLen, const byte* salt, + int sLen, int iterations, int kLen, int hashType, void* heap, int devId) +{ word32 i = 1; int hLen; int j, ret; - Hmac hmac; #ifdef WOLFSSL_SMALL_STACK byte* buffer; + Hmac* hmac; #else - byte buffer[MAX_DIGEST_SIZE]; + byte buffer[WC_MAX_DIGEST_SIZE]; + Hmac hmac[1]; #endif + enum wc_HashType hashT; + + if (output == NULL || pLen < 0 || sLen < 0 || kLen < 0) { + return BAD_FUNC_ARG; + } + + if (iterations <= 0) + iterations = 1; - hLen = GetDigestSize(hashType); + hashT = wc_HashTypeConvert(hashType); + hLen = wc_HashGetDigestSize(hashT); if (hLen < 0) return BAD_FUNC_ARG; #ifdef WOLFSSL_SMALL_STACK - buffer = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + buffer = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER); if (buffer == NULL) return MEMORY_E; + hmac = (Hmac*)XMALLOC(sizeof(Hmac), heap, DYNAMIC_TYPE_HMAC); + if (hmac == NULL) { + XFREE(buffer, heap, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } #endif - ret = wc_HmacSetKey(&hmac, hashType, passwd, pLen); - + ret = wc_HmacInit(hmac, heap, devId); if (ret == 0) { - while (kLen) { + /* use int hashType here, since HMAC FIPS uses the old unique value */ + ret = wc_HmacSetKey(hmac, hashType, passwd, pLen); + + while (ret == 0 && kLen) { int currentLen; - ret = wc_HmacUpdate(&hmac, salt, sLen); + ret = wc_HmacUpdate(hmac, salt, sLen); if (ret != 0) break; @@ -204,7 +225,7 @@ int wc_PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt, for (j = 0; j < 4; j++) { byte b = (byte)(i >> ((3-j) * 8)); - ret = wc_HmacUpdate(&hmac, &b, 1); + ret = wc_HmacUpdate(hmac, &b, 1); if (ret != 0) break; } @@ -213,7 +234,7 @@ int wc_PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt, if (ret != 0) break; - ret = wc_HmacFinal(&hmac, buffer); + ret = wc_HmacFinal(hmac, buffer); if (ret != 0) break; @@ -221,10 +242,10 @@ int wc_PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt, XMEMCPY(output, buffer, currentLen); for (j = 1; j < iterations; j++) { - ret = wc_HmacUpdate(&hmac, buffer, hLen); + ret = wc_HmacUpdate(hmac, buffer, hLen); if (ret != 0) break; - ret = wc_HmacFinal(&hmac, buffer); + ret = wc_HmacFinal(hmac, buffer); if (ret != 0) break; xorbuf(output, buffer, currentLen); @@ -238,171 +259,98 @@ int wc_PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt, kLen -= currentLen; i++; } + wc_HmacFree(hmac); } #ifdef WOLFSSL_SMALL_STACK - XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(buffer, heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(hmac, heap, DYNAMIC_TYPE_HMAC); #endif return ret; } -#ifdef WOLFSSL_SHA512 - #define PBKDF_DIGEST_SIZE SHA512_BLOCK_SIZE -#elif !defined(NO_SHA256) - #define PBKDF_DIGEST_SIZE SHA256_BLOCK_SIZE -#else - #define PBKDF_DIGEST_SIZE SHA_DIGEST_SIZE -#endif - -/* helper for wc_PKCS12_PBKDF(), sets block and digest sizes */ -int GetPKCS12HashSizes(int hashType, word32* v, word32* u) +int wc_PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt, + int sLen, int iterations, int kLen, int hashType) { - if (!v || !u) - return BAD_FUNC_ARG; + return wc_PBKDF2_ex(output, passwd, pLen, salt, sLen, iterations, kLen, + hashType, NULL, INVALID_DEVID); +} - switch (hashType) { -#ifndef NO_MD5 - case MD5: - *v = MD5_BLOCK_SIZE; - *u = MD5_DIGEST_SIZE; - break; -#endif -#ifndef NO_SHA - case SHA: - *v = SHA_BLOCK_SIZE; - *u = SHA_DIGEST_SIZE; - break; -#endif -#ifndef NO_SHA256 - case SHA256: - *v = SHA256_BLOCK_SIZE; - *u = SHA256_DIGEST_SIZE; - break; -#endif -#ifdef WOLFSSL_SHA512 - case SHA512: - *v = SHA512_BLOCK_SIZE; - *u = SHA512_DIGEST_SIZE; - break; -#endif - default: - return BAD_FUNC_ARG; - } +#endif /* HAVE_PBKDF2 */ - return 0; -} +#ifdef HAVE_PKCS12 /* helper for PKCS12_PBKDF(), does hash operation */ -int DoPKCS12Hash(int hashType, byte* buffer, word32 totalLen, +static int DoPKCS12Hash(int hashType, byte* buffer, word32 totalLen, byte* Ai, word32 u, int iterations) { int i; int ret = 0; +#ifdef WOLFSSL_SMALL_STACK + wc_HashAlg* hash = NULL; +#else + wc_HashAlg hash[1]; +#endif + enum wc_HashType hashT; - if (buffer == NULL || Ai == NULL) + if (buffer == NULL || Ai == NULL) { return BAD_FUNC_ARG; + } - switch (hashType) { -#ifndef NO_MD5 - case MD5: - { - Md5 md5; - wc_InitMd5(&md5); - wc_Md5Update(&md5, buffer, totalLen); - wc_Md5Final(&md5, Ai); - - for (i = 1; i < iterations; i++) { - wc_Md5Update(&md5, Ai, u); - wc_Md5Final(&md5, Ai); - } - } - break; -#endif /* NO_MD5 */ -#ifndef NO_SHA - case SHA: - { - Sha sha; - ret = wc_InitSha(&sha); - if (ret != 0) - break; - wc_ShaUpdate(&sha, buffer, totalLen); - wc_ShaFinal(&sha, Ai); - - for (i = 1; i < iterations; i++) { - wc_ShaUpdate(&sha, Ai, u); - wc_ShaFinal(&sha, Ai); - } - } - break; -#endif /* NO_SHA */ -#ifndef NO_SHA256 - case SHA256: - { - Sha256 sha256; - ret = wc_InitSha256(&sha256); - if (ret != 0) - break; + hashT = wc_HashTypeConvert(hashType); - ret = wc_Sha256Update(&sha256, buffer, totalLen); - if (ret != 0) - break; + /* initialize hash */ +#ifdef WOLFSSL_SMALL_STACK + hash = (wc_HashAlg*)XMALLOC(sizeof(wc_HashAlg), NULL, + DYNAMIC_TYPE_HASHCTX); + if (hash == NULL) + return MEMORY_E; +#endif - ret = wc_Sha256Final(&sha256, Ai); - if (ret != 0) - break; + ret = wc_HashInit(hash, hashT); + if (ret != 0) { + #ifdef WOLFSSL_SMALL_STACK + XFREE(hash, NULL, DYNAMIC_TYPE_HASHCTX); + #endif + return ret; + } - for (i = 1; i < iterations; i++) { - ret = wc_Sha256Update(&sha256, Ai, u); - if (ret != 0) - break; + ret = wc_HashUpdate(hash, hashT, buffer, totalLen); - ret = wc_Sha256Final(&sha256, Ai); - if (ret != 0) - break; - } - } - break; -#endif /* NO_SHA256 */ -#ifdef WOLFSSL_SHA512 - case SHA512: - { - Sha512 sha512; - ret = wc_InitSha512(&sha512); - if (ret != 0) - break; + if (ret == 0) + ret = wc_HashFinal(hash, hashT, Ai); - ret = wc_Sha512Update(&sha512, buffer, totalLen); - if (ret != 0) - break; + for (i = 1; i < iterations; i++) { + if (ret == 0) + ret = wc_HashUpdate(hash, hashT, Ai, u); + if (ret == 0) + ret = wc_HashFinal(hash, hashT, Ai); + } - ret = wc_Sha512Final(&sha512, Ai); - if (ret != 0) - break; + wc_HashFree(hash, hashT); - for (i = 1; i < iterations; i++) { - ret = wc_Sha512Update(&sha512, Ai, u); - if (ret != 0) - break; +#ifdef WOLFSSL_SMALL_STACK + XFREE(hash, NULL, DYNAMIC_TYPE_HASHCTX); +#endif - ret = wc_Sha512Final(&sha512, Ai); - if (ret != 0) - break; - } - } - break; -#endif /* WOLFSSL_SHA512 */ + return ret; +} - default: - ret = BAD_FUNC_ARG; - break; - } - return ret; +int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen, + const byte* salt, int saltLen, int iterations, int kLen, int hashType, + int id) +{ + return wc_PKCS12_PBKDF_ex(output, passwd, passLen, salt, saltLen, + iterations, kLen, hashType, id, NULL); } -int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* salt, - int saltLen, int iterations, int kLen, int hashType, int id) + +/* extended API that allows a heap hint to be used */ +int wc_PKCS12_PBKDF_ex(byte* output, const byte* passwd, int passLen, + const byte* salt, int saltLen, int iterations, int kLen, + int hashType, int id, void* heap) { /* all in bytes instead of bits */ word32 u, v, dLen, pLen, iLen, sLen, totalLen; @@ -421,34 +369,48 @@ int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* sa byte* Ai; byte* B; #else - byte Ai[PBKDF_DIGEST_SIZE]; - byte B[PBKDF_DIGEST_SIZE]; + byte Ai[WC_MAX_DIGEST_SIZE]; + byte B[WC_MAX_BLOCK_SIZE]; #endif + enum wc_HashType hashT; + + (void)heap; + + if (output == NULL || passLen < 0 || saltLen < 0 || kLen < 0) { + return BAD_FUNC_ARG; + } - if (!iterations) + if (iterations <= 0) iterations = 1; - ret = GetPKCS12HashSizes(hashType, &v, &u); + hashT = wc_HashTypeConvert(hashType); + ret = wc_HashGetDigestSize(hashT); if (ret < 0) - return BAD_FUNC_ARG; + return ret; + u = ret; + + ret = wc_HashGetBlockSize(hashT); + if (ret < 0) + return ret; + v = ret; #ifdef WOLFSSL_SMALL_STACK - Ai = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + Ai = (byte*)XMALLOC(WC_MAX_DIGEST_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER); if (Ai == NULL) return MEMORY_E; - B = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + B = (byte*)XMALLOC(WC_MAX_BLOCK_SIZE, heap, DYNAMIC_TYPE_TMP_BUFFER); if (B == NULL) { - XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER); return MEMORY_E; } #endif - XMEMSET(Ai, 0, PBKDF_DIGEST_SIZE); - XMEMSET(B, 0, PBKDF_DIGEST_SIZE); + XMEMSET(Ai, 0, WC_MAX_DIGEST_SIZE); + XMEMSET(B, 0, WC_MAX_BLOCK_SIZE); dLen = v; - sLen = v * ((saltLen + v - 1) / v); + sLen = v * ((saltLen + v - 1) / v); if (passLen) pLen = v * ((passLen + v - 1) / v); else @@ -458,11 +420,11 @@ int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* sa totalLen = dLen + sLen + pLen; if (totalLen > sizeof(staticBuffer)) { - buffer = (byte*)XMALLOC(totalLen, 0, DYNAMIC_TYPE_KEY); + buffer = (byte*)XMALLOC(totalLen, heap, DYNAMIC_TYPE_KEY); if (buffer == NULL) { #ifdef WOLFSSL_SMALL_STACK - XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(B, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(B, heap, DYNAMIC_TYPE_TMP_BUFFER); #endif return MEMORY_E; } @@ -522,7 +484,7 @@ int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* sa else { if (outSz > (int)v) { /* take off MSB */ - byte tmp[129]; + byte tmp[WC_MAX_BLOCK_SIZE + 1]; ret = mp_to_unsigned_bin(&res, tmp); XMEMCPY(I + i, tmp + 1, v); } @@ -546,17 +508,288 @@ int wc_PKCS12_PBKDF(byte* output, const byte* passwd, int passLen,const byte* sa mp_clear(&B1); } - if (dynamic) XFREE(buffer, 0, DYNAMIC_TYPE_KEY); + if (dynamic) XFREE(buffer, heap, DYNAMIC_TYPE_KEY); #ifdef WOLFSSL_SMALL_STACK - XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER); - XFREE(B, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(Ai, heap, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(B, heap, DYNAMIC_TYPE_TMP_BUFFER); #endif return ret; } -#undef PBKDF_DIGEST_SIZE +#endif /* HAVE_PKCS12 */ -#endif /* NO_PWDBASED */ +#ifdef HAVE_SCRYPT +/* Rotate the 32-bit value a by b bits to the left. + * + * a 32-bit value. + * b Number of bits to rotate. + * returns rotated value. + */ +#define R(a, b) rotlFixed(a, b) +/* One round of Salsa20/8. + * Code taken from RFC 7914: scrypt PBKDF. + * + * out Output buffer. + * in Input data to hash. + */ +static void scryptSalsa(word32* out, word32* in) +{ + int i; + word32 x[16]; + +#ifdef LITTLE_ENDIAN_ORDER + for (i = 0; i < 16; ++i) + x[i] = in[i]; +#else + for (i = 0; i < 16; i++) + x[i] = ByteReverseWord32(in[i]); +#endif + for (i = 8; i > 0; i -= 2) { + x[ 4] ^= R(x[ 0] + x[12], 7); x[ 8] ^= R(x[ 4] + x[ 0], 9); + x[12] ^= R(x[ 8] + x[ 4], 13); x[ 0] ^= R(x[12] + x[ 8], 18); + x[ 9] ^= R(x[ 5] + x[ 1], 7); x[13] ^= R(x[ 9] + x[ 5], 9); + x[ 1] ^= R(x[13] + x[ 9], 13); x[ 5] ^= R(x[ 1] + x[13], 18); + x[14] ^= R(x[10] + x[ 6], 7); x[ 2] ^= R(x[14] + x[10], 9); + x[ 6] ^= R(x[ 2] + x[14], 13); x[10] ^= R(x[ 6] + x[ 2], 18); + x[ 3] ^= R(x[15] + x[11], 7); x[ 7] ^= R(x[ 3] + x[15], 9); + x[11] ^= R(x[ 7] + x[ 3], 13); x[15] ^= R(x[11] + x[ 7], 18); + x[ 1] ^= R(x[ 0] + x[ 3], 7); x[ 2] ^= R(x[ 1] + x[ 0], 9); + x[ 3] ^= R(x[ 2] + x[ 1], 13); x[ 0] ^= R(x[ 3] + x[ 2], 18); + x[ 6] ^= R(x[ 5] + x[ 4], 7); x[ 7] ^= R(x[ 6] + x[ 5], 9); + x[ 4] ^= R(x[ 7] + x[ 6], 13); x[ 5] ^= R(x[ 4] + x[ 7], 18); + x[11] ^= R(x[10] + x[ 9], 7); x[ 8] ^= R(x[11] + x[10], 9); + x[ 9] ^= R(x[ 8] + x[11], 13); x[10] ^= R(x[ 9] + x[ 8], 18); + x[12] ^= R(x[15] + x[14], 7); x[13] ^= R(x[12] + x[15], 9); + x[14] ^= R(x[13] + x[12], 13); x[15] ^= R(x[14] + x[13], 18); + } +#ifdef LITTLE_ENDIAN_ORDER + for (i = 0; i < 16; ++i) + out[i] = in[i] + x[i]; +#else + for (i = 0; i < 16; i++) + out[i] = ByteReverseWord32(ByteReverseWord32(in[i]) + x[i]); +#endif +} + +/* Mix a block using Salsa20/8. + * Based on RFC 7914: scrypt PBKDF. + * + * b Blocks to mix. + * y Temporary storage. + * r Size of the block. + */ +static void scryptBlockMix(byte* b, byte* y, int r) +{ + byte x[64]; +#ifdef WORD64_AVAILABLE + word64* b64 = (word64*)b; + word64* y64 = (word64*)y; + word64* x64 = (word64*)x; +#else + word32* b32 = (word32*)b; + word32* y32 = (word32*)y; + word32* x32 = (word32*)x; +#endif + int i; + int j; + + /* Step 1. */ + XMEMCPY(x, b + (2 * r - 1) * 64, sizeof(x)); + /* Step 2. */ + for (i = 0; i < 2 * r; i++) + { +#ifdef WORD64_AVAILABLE + for (j = 0; j < 8; j++) + x64[j] ^= b64[i * 8 + j]; +#else + for (j = 0; j < 16; j++) + x32[j] ^= b32[i * 16 + j]; +#endif + scryptSalsa((word32*)x, (word32*)x); + XMEMCPY(y + i * 64, x, sizeof(x)); + } + /* Step 3. */ + for (i = 0; i < r; i++) { +#ifdef WORD64_AVAILABLE + for (j = 0; j < 8; j++) { + b64[i * 8 + j] = y64[2 * i * 8 + j]; + b64[(r + i) * 8 + j] = y64[(2 * i + 1) * 8 + j]; + } +#else + for (j = 0; j < 16; j++) { + b32[i * 16 + j] = y32[2 * i * 16 + j]; + b32[(r + i) * 16 + j] = y32[(2 * i + 1) * 16 + j]; + } +#endif + } +} + +/* Random oracles mix. + * Based on RFC 7914: scrypt PBKDF. + * + * x Data to mix. + * v Temporary buffer. + * y Temporary buffer for the block mix. + * r Block size parameter. + * n CPU/Memory cost parameter. + */ +static void scryptROMix(byte* x, byte* v, byte* y, int r, word32 n) +{ + word32 i; + word32 j; + word32 k; + word32 bSz = 128 * r; +#ifdef WORD64_AVAILABLE + word64* x64 = (word64*)x; + word64* v64 = (word64*)v; +#else + word32* x32 = (word32*)x; + word32* v32 = (word32*)v; +#endif + + /* Step 1. X = B (B not needed therefore not implemented) */ + /* Step 2. */ + for (i = 0; i < n; i++) + { + XMEMCPY(v + i * bSz, x, bSz); + scryptBlockMix(x, y, r); + } + + /* Step 3. */ + for (i = 0; i < n; i++) + { +#ifdef LITTLE_ENDIAN_ORDER +#ifdef WORD64_AVAILABLE + j = *(word64*)(x + (2*r - 1) * 64) & (n-1); +#else + j = *(word32*)(x + (2*r - 1) * 64) & (n-1); +#endif +#else + byte* t = x + (2*r - 1) * 64; + j = (t[0] | (t[1] << 8) | (t[2] << 16) | ((word32)t[3] << 24)) & (n-1); +#endif +#ifdef WORD64_AVAILABLE + for (k = 0; k < bSz / 8; k++) + x64[k] ^= v64[j * bSz / 8 + k]; +#else + for (k = 0; k < bSz / 4; k++) + x32[k] ^= v32[j * bSz / 4 + k]; +#endif + scryptBlockMix(x, y, r); + } + /* Step 4. B' = X (B = X = B' so not needed, therefore not implemented) */ +} + +/* Generates an key derived from a password and salt using a memory hard + * algorithm. + * Implements RFC 7914: scrypt PBKDF. + * + * output The derived key. + * passwd The password to derive key from. + * passLen The length of the password. + * salt The key specific data. + * saltLen The length of the salt data. + * cost The CPU/memory cost parameter. Range: 1..(128*r/8-1) + * (Iterations = 2^cost) + * blockSize The number of 128 byte octets in a working block. + * parallel The number of parallel mix operations to perform. + * (Note: this implementation does not use threads.) + * dkLen The length of the derived key in bytes. + * returns BAD_FUNC_ARG when: blockSize is too large for cost. + */ +int wc_scrypt(byte* output, const byte* passwd, int passLen, + const byte* salt, int saltLen, int cost, int blockSize, + int parallel, int dkLen) +{ + int ret = 0; + int i; + byte* v = NULL; + byte* y = NULL; + byte* blocks = NULL; + word32 blocksSz; + word32 bSz; + + if (blockSize > 8) + return BAD_FUNC_ARG; + + if (cost < 1 || cost >= 128 * blockSize / 8 || parallel < 1 || dkLen < 1) + return BAD_FUNC_ARG; + + bSz = 128 * blockSize; + blocksSz = bSz * parallel; + blocks = (byte*)XMALLOC(blocksSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (blocks == NULL) + goto end; + /* Temporary for scryptROMix. */ + v = (byte*)XMALLOC((1 << cost) * bSz, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (v == NULL) + goto end; + /* Temporary for scryptBlockMix. */ + y = (byte*)XMALLOC(blockSize * 128, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (y == NULL) + goto end; + + /* Step 1. */ + ret = wc_PBKDF2(blocks, passwd, passLen, salt, saltLen, 1, blocksSz, + WC_SHA256); + if (ret != 0) + goto end; + + /* Step 2. */ + for (i = 0; i < parallel; i++) + scryptROMix(blocks + i * bSz, v, y, blockSize, 1 << cost); + + /* Step 3. */ + ret = wc_PBKDF2(output, passwd, passLen, blocks, blocksSz, 1, dkLen, + WC_SHA256); +end: + if (blocks != NULL) + XFREE(blocks, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (v != NULL) + XFREE(v, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (y != NULL) + XFREE(y, NULL, DYNAMIC_TYPE_TMP_BUFFER); + + return ret; +} + +/* Generates an key derived from a password and salt using a memory hard + * algorithm. + * Implements RFC 7914: scrypt PBKDF. + * + * output Derived key. + * passwd Password to derive key from. + * passLen Length of the password. + * salt Key specific data. + * saltLen Length of the salt data. + * iterations Number of iterations to perform. Range: 1 << (1..(128*r/8-1)) + * blockSize Number of 128 byte octets in a working block. + * parallel Number of parallel mix operations to perform. + * (Note: this implementation does not use threads.) + * dkLen Length of the derived key in bytes. + * returns BAD_FUNC_ARG when: iterations is not a power of 2 or blockSize is too + * large for iterations. + */ +int wc_scrypt_ex(byte* output, const byte* passwd, int passLen, + const byte* salt, int saltLen, word32 iterations, + int blockSize, int parallel, int dkLen) +{ + int cost; + + /* Iterations must be a power of 2. */ + if ((iterations & (iterations - 1)) != 0) + return BAD_FUNC_ARG; + + for (cost = -1; iterations != 0; cost++) { + iterations >>= 1; + } + + return wc_scrypt(output, passwd, passLen, salt, saltLen, cost, blockSize, + parallel, dkLen); +} +#endif /* HAVE_SCRYPT */ + +#endif /* NO_PWDBASED */ |