Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: wolfcrypt/src/pwdbased.c
- Revision:
- 0:d92f9d21154c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wolfcrypt/src/pwdbased.c Fri Jun 26 00:39:20 2015 +0000 @@ -0,0 +1,563 @@ +/* pwdbased.c + * + * Copyright (C) 2006-2015 wolfSSL Inc. + * + * This file is part of wolfSSL. (formerly known as CyaSSL) + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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 + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <wolfssl/wolfcrypt/settings.h> + +#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/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 + #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 */ + + +#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) +{ + Sha sha; +#ifndef NO_MD5 + Md5 md5; +#endif + int hLen = (int)SHA_DIGEST_SIZE; + int i, ret = 0; + byte buffer[SHA_DIGEST_SIZE]; /* max size */ + + if (hashType != MD5 && hashType != SHA) + return BAD_FUNC_ARG; + +#ifndef NO_MD5 + if (hashType == MD5) + hLen = (int)MD5_DIGEST_SIZE; +#endif + + if (kLen > hLen) + return BAD_FUNC_ARG; + + if (iterations < 1) + return BAD_FUNC_ARG; + + 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; + } + + for (i = 1; i < iterations; i++) { + if (hashType == SHA) { + wc_ShaUpdate(&sha, buffer, hLen); + wc_ShaFinal(&sha, buffer); + } +#ifndef NO_MD5 + else { + wc_Md5Update(&md5, buffer, hLen); + wc_Md5Final(&md5, buffer); + } +#endif + } + XMEMCPY(output, buffer, kLen); + + return 0; +} +#endif /* NO_SHA */ + + +int GetDigestSize(int hashType) +{ + int hLen; + + 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; + } + + return hLen; +} + + +int wc_PBKDF2(byte* output, const byte* passwd, int pLen, const byte* salt, + int sLen, int iterations, int kLen, int hashType) +{ + word32 i = 1; + int hLen; + int j, ret; + Hmac hmac; +#ifdef WOLFSSL_SMALL_STACK + byte* buffer; +#else + byte buffer[MAX_DIGEST_SIZE]; +#endif + + hLen = GetDigestSize(hashType); + if (hLen < 0) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_SMALL_STACK + buffer = (byte*)XMALLOC(MAX_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (buffer == NULL) + return MEMORY_E; +#endif + + ret = wc_HmacSetKey(&hmac, hashType, passwd, pLen); + + if (ret == 0) { + while (kLen) { + int currentLen; + + ret = wc_HmacUpdate(&hmac, salt, sLen); + if (ret != 0) + break; + + /* encode i */ + for (j = 0; j < 4; j++) { + byte b = (byte)(i >> ((3-j) * 8)); + + ret = wc_HmacUpdate(&hmac, &b, 1); + if (ret != 0) + break; + } + + /* check ret from inside for loop */ + if (ret != 0) + break; + + ret = wc_HmacFinal(&hmac, buffer); + if (ret != 0) + break; + + currentLen = min(kLen, hLen); + XMEMCPY(output, buffer, currentLen); + + for (j = 1; j < iterations; j++) { + ret = wc_HmacUpdate(&hmac, buffer, hLen); + if (ret != 0) + break; + ret = wc_HmacFinal(&hmac, buffer); + if (ret != 0) + break; + xorbuf(output, buffer, currentLen); + } + + /* check ret from inside for loop */ + if (ret != 0) + break; + + output += currentLen; + kLen -= currentLen; + i++; + } + } + +#ifdef WOLFSSL_SMALL_STACK + XFREE(buffer, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#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) +{ + if (!v || !u) + return BAD_FUNC_ARG; + + 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; + } + + return 0; +} + +/* helper for PKCS12_PBKDF(), does hash operation */ +int DoPKCS12Hash(int hashType, byte* buffer, word32 totalLen, + byte* Ai, word32 u, int iterations) +{ + int i; + int ret = 0; + + 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; + + ret = wc_Sha256Update(&sha256, buffer, totalLen); + if (ret != 0) + break; + + ret = wc_Sha256Final(&sha256, Ai); + if (ret != 0) + break; + + for (i = 1; i < iterations; i++) { + ret = wc_Sha256Update(&sha256, Ai, u); + if (ret != 0) + break; + + 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; + + ret = wc_Sha512Update(&sha512, buffer, totalLen); + if (ret != 0) + break; + + ret = wc_Sha512Final(&sha512, Ai); + if (ret != 0) + break; + + for (i = 1; i < iterations; i++) { + ret = wc_Sha512Update(&sha512, Ai, u); + if (ret != 0) + break; + + ret = wc_Sha512Final(&sha512, Ai); + if (ret != 0) + break; + } + } + break; +#endif /* WOLFSSL_SHA512 */ + + 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) +{ + /* all in bytes instead of bits */ + word32 u, v, dLen, pLen, iLen, sLen, totalLen; + int dynamic = 0; + int ret = 0; + int i; + byte *D, *S, *P, *I; +#ifdef WOLFSSL_SMALL_STACK + byte staticBuffer[1]; /* force dynamic usage */ +#else + byte staticBuffer[1024]; +#endif + byte* buffer = staticBuffer; + +#ifdef WOLFSSL_SMALL_STACK + byte* Ai; + byte* B; +#else + byte Ai[PBKDF_DIGEST_SIZE]; + byte B[PBKDF_DIGEST_SIZE]; +#endif + + if (!iterations) + iterations = 1; + + ret = GetPKCS12HashSizes(hashType, &v, &u); + if (ret < 0) + return BAD_FUNC_ARG; + +#ifdef WOLFSSL_SMALL_STACK + Ai = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (Ai == NULL) + return MEMORY_E; + + B = (byte*)XMALLOC(PBKDF_DIGEST_SIZE, NULL, DYNAMIC_TYPE_TMP_BUFFER); + if (B == NULL) { + XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER); + return MEMORY_E; + } +#endif + + XMEMSET(Ai, 0, PBKDF_DIGEST_SIZE); + XMEMSET(B, 0, PBKDF_DIGEST_SIZE); + + dLen = v; + sLen = v * ((saltLen + v - 1) / v); + if (passLen) + pLen = v * ((passLen + v - 1) / v); + else + pLen = 0; + iLen = sLen + pLen; + + totalLen = dLen + sLen + pLen; + + if (totalLen > sizeof(staticBuffer)) { + buffer = (byte*)XMALLOC(totalLen, 0, DYNAMIC_TYPE_KEY); + if (buffer == NULL) { +#ifdef WOLFSSL_SMALL_STACK + XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(B, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + return MEMORY_E; + } + dynamic = 1; + } + + D = buffer; + S = D + dLen; + P = S + sLen; + I = S; + + XMEMSET(D, id, dLen); + + for (i = 0; i < (int)sLen; i++) + S[i] = salt[i % saltLen]; + for (i = 0; i < (int)pLen; i++) + P[i] = passwd[i % passLen]; + + while (kLen > 0) { + word32 currentLen; + mp_int B1; + + ret = DoPKCS12Hash(hashType, buffer, totalLen, Ai, u, iterations); + if (ret < 0) + break; + + for (i = 0; i < (int)v; i++) + B[i] = Ai[i % u]; + + if (mp_init(&B1) != MP_OKAY) + ret = MP_INIT_E; + else if (mp_read_unsigned_bin(&B1, B, v) != MP_OKAY) + ret = MP_READ_E; + else if (mp_add_d(&B1, (mp_digit)1, &B1) != MP_OKAY) + ret = MP_ADD_E; + + if (ret != 0) { + mp_clear(&B1); + break; + } + + for (i = 0; i < (int)iLen; i += v) { + int outSz; + mp_int i1; + mp_int res; + + if (mp_init_multi(&i1, &res, NULL, NULL, NULL, NULL) != MP_OKAY) { + ret = MP_INIT_E; + break; + } + if (mp_read_unsigned_bin(&i1, I + i, v) != MP_OKAY) + ret = MP_READ_E; + else if (mp_add(&i1, &B1, &res) != MP_OKAY) + ret = MP_ADD_E; + else if ( (outSz = mp_unsigned_bin_size(&res)) < 0) + ret = MP_TO_E; + else { + if (outSz > (int)v) { + /* take off MSB */ + byte tmp[129]; + ret = mp_to_unsigned_bin(&res, tmp); + XMEMCPY(I + i, tmp + 1, v); + } + else if (outSz < (int)v) { + XMEMSET(I + i, 0, v - outSz); + ret = mp_to_unsigned_bin(&res, I + i + v - outSz); + } + else + ret = mp_to_unsigned_bin(&res, I + i); + } + + mp_clear(&i1); + mp_clear(&res); + if (ret < 0) break; + } + + currentLen = min(kLen, (int)u); + XMEMCPY(output, Ai, currentLen); + output += currentLen; + kLen -= currentLen; + mp_clear(&B1); + } + + if (dynamic) XFREE(buffer, 0, DYNAMIC_TYPE_KEY); + +#ifdef WOLFSSL_SMALL_STACK + XFREE(Ai, NULL, DYNAMIC_TYPE_TMP_BUFFER); + XFREE(B, NULL, DYNAMIC_TYPE_TMP_BUFFER); +#endif + + return ret; +} + +#undef PBKDF_DIGEST_SIZE + +#endif /* NO_PWDBASED */ + +