summaryrefslogtreecommitdiff
path: root/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pwdbased.c
diff options
context:
space:
mode:
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pwdbased.c')
-rw-r--r--FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/pwdbased.c785
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 */