diff --git a/tests/api.c b/tests/api.c index eafb6dd27..c9dfb0e99 100644 --- a/tests/api.c +++ b/tests/api.c @@ -42625,6 +42625,92 @@ static void test_wolfSSL_EVP_PKEY_derive(void) #endif /* OPENSSL_ALL || WOLFSSL_QT || WOLFSSL_OPENSSH */ } +static void test_wolfSSL_EVP_PBE_scrypt(void) +{ +#if defined(OPENSSL_EXTRA) && defined(HAVE_SCRYPT) && defined(HAVE_PBKDF2) +#if !defined(NO_PWDBASED) && !defined(NO_SHA256) + + int ret; + + const char pwd[] = {'p','a','s','s','w','o','r','d'}; + int pwdlen = sizeof(pwd); + const byte salt[] = {'N','a','C','l'}; + int saltlen = sizeof(salt); + byte key[80]; + word64 numOvr32 = (word64)INT32_MAX + 1; + + /* expected derived key for N:16, r:1, p:1 */ + const byte expectedKey[] = { + 0xAE, 0xC6, 0xB7, 0x48, 0x3E, 0xD2, 0x6E, 0x08, 0x80, 0x2B, + 0x41, 0xF4, 0x03, 0x20, 0x86, 0xA0, 0xE8, 0x86, 0xBE, 0x7A, + 0xC4, 0x8F, 0xCF, 0xD9, 0x2F, 0xF0, 0xCE, 0xF8, 0x10, 0x97, + 0x52, 0xF4, 0xAC, 0x74, 0xB0, 0x77, 0x26, 0x32, 0x56, 0xA6, + 0x5A, 0x99, 0x70, 0x1B, 0x7A, 0x30, 0x4D, 0x46, 0x61, 0x1C, + 0x8A, 0xA3, 0x91, 0xE7, 0x99, 0xCE, 0x10, 0xA2, 0x77, 0x53, + 0xE7, 0xE9, 0xC0, 0x9A}; + + printf(testingFmt, "wolfSSL_EVP_PBE_scrypt()"); + + /* N r p mx key keylen */ + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 0, 1, 1, 0, key, 64); + AssertIntEQ(ret, 0); /* N must be greater than 1 */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 3, 1, 1, 0, key, 64); + AssertIntEQ(ret, 0); /* N must be power of 2 */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 2, 0, 1, 0, key, 64); + AssertIntEQ(ret, 0); /* r must be greater than 0 */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 2, 1, 0, 0, key, 64); + AssertIntEQ(ret, 0); /* p must be greater than 0 */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 2, 1, 1, 0, key, 0); + AssertIntEQ(ret, 0); /* keylen must be greater than 0 */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 2, 9, 1, 0, key, 64); + AssertIntEQ(ret, 0); /* r must be smaller than 9 */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 2, 1, 1, 0, NULL, 64); + AssertIntEQ(ret, 1); /* should succeed if key is NULL */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 2, 1, 1, 0, key, 64); + AssertIntEQ(ret, 1); /* should succeed */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 2, numOvr32, 1, 0, + key, 64); + AssertIntEQ(ret, 0); /* should fail since r is greater than INT32_MAC */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 2, 1, numOvr32, 0, + key, 64); + AssertIntEQ(ret, 0); /* should fail since p is greater than INT32_MAC */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, NULL, 0, 2, 1, 1, 0, key, 64); + AssertIntEQ(ret, 1); /* should succeed even if salt is NULL */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, NULL, 4, 2, 1, 1, 0, key, 64); + AssertIntEQ(ret, 0); /* if salt is NULL, saltlen must be 0, otherwise fail*/ + + ret = EVP_PBE_scrypt(NULL, 0, salt, saltlen, 2, 1, 1, 0, key, 64); + AssertIntEQ(ret, 1); /* should succeed if pwd is NULL and pwdlen is 0*/ + + ret = EVP_PBE_scrypt(NULL, 4, salt, saltlen, 2, 1, 1, 0, key, 64); + AssertIntEQ(ret, 0); /* if pwd is NULL, pwdlen must be 0 */ + + ret = EVP_PBE_scrypt(NULL, 0, NULL, 0, 2, 1, 1, 0, key, 64); + AssertIntEQ(ret, 1); /* should succeed even both pwd and salt are NULL */ + + ret = EVP_PBE_scrypt(pwd, pwdlen, salt, saltlen, 16, 1, 1, 0, key, 64); + AssertIntEQ(ret, 1); + + ret = XMEMCMP(expectedKey, key, sizeof(expectedKey)); + AssertIntEQ(ret, 0); /* derived key must be the same as expected-key */ + + printf(resultFmt, "passed"); + +#endif /* !NO_PWDBASED && !NO_SHA256 */ +#endif /* OPENSSL_EXTRA && HAVE_SCRYPT && HAVE_PBKDF2 */ +} + #ifndef NO_RSA static void test_wolfSSL_RSA_padding_add_PKCS1_PSS(void) { @@ -48742,6 +48828,7 @@ void ApiTest(void) test_wolfSSL_OCSP_resp_count(); test_wolfSSL_OCSP_resp_get0(); test_wolfSSL_EVP_PKEY_derive(); + test_wolfSSL_EVP_PBE_scrypt(); #ifndef NO_RSA test_wolfSSL_RSA_padding_add_PKCS1_PSS(); #endif diff --git a/wolfcrypt/src/evp.c b/wolfcrypt/src/evp.c index 8c95b4f3b..06fbaa02c 100644 --- a/wolfcrypt/src/evp.c +++ b/wolfcrypt/src/evp.c @@ -3218,6 +3218,71 @@ int wolfSSL_PKCS5_PBKDF2_HMAC(const char *pass, int passlen, } #endif /* !NO_PWDBASED */ + +#if defined(HAVE_SCRYPT) && defined(HAVE_PBKDF2) && !defined(NO_PWDBASED) && \ + !defined(NO_SHA256) +/** + * Derives a key from the specified password and the salt using SCRYPT + * algorithm. + * + * Parameters: + * - pass :password data. no need to be null-terminated. NULL is accepted. + * - passlen :length of the password. Must be 0 when pass is NULL. + * - salt :salt. NULL is accepted. + * - saltlen :length of the salt. Must be 0 when salt is NULL. + * - N :cost parameter. Must be grater or equal to 2 and be a power of 2. + * - r :block size. Must 1 or greater. + * - p :parallelism + * - maxmem :maximum size of buffer used for calculation in definition, + * Not referred in this implementation. + * - key :derived key. + * - keylen :length of the derived key + * + * Returns: + * 1 on success, otherwise 0. + */ +int wolfSSL_EVP_PBE_scrypt(const char *pass, size_t passlen, + const unsigned char *salt, size_t saltlen, + word64 N, word64 r, word64 p, + word64 maxmem, unsigned char *key, size_t keylen) +{ + (void)maxmem; + int ret; + int exp = 0; + + WOLFSSL_ENTER("wolfSSL_EVP_PBE_scrypt"); + + if (r > INT32_MAX || p > INT32_MAX) { + WOLFSSL_MSG("Doesn't support greater than 32 bit values of r and p"); + return WOLFSSL_FAILURE; + } + /* N must be a power of 2 and > 2. + if (N & (N-1)) is zero, it means N is a power of 2. + */ + if (N < 2 || (N & (N-1)) || r <= 0 || p <= 0) + return WOLFSSL_FAILURE; + + if (key == NULL) + return WOLFSSL_SUCCESS; + + /* get exponent of power of 2. Confirmed N is power of 2. */ + while (N != 1) { + N >>= 1; + exp++; + } + + ret = wc_scrypt(key, (const byte*)pass, (int)passlen, salt, (int)saltlen, + exp, (int)r, (int)p, (int)keylen); + + WOLFSSL_LEAVE("wolfSSL_EVP_PBE_scrypt", ret); + + if (ret == 0) + return WOLFSSL_SUCCESS; + else + return WOLFSSL_FAILURE; +} +#endif /* HAVE_SCRYPT && HAVE_PBKDF2 && !NO_PWDBASED && !NO_SHA */ + static const struct cipher{ unsigned char type; const char *name; diff --git a/wolfssl/openssl/evp.h b/wolfssl/openssl/evp.h index 3e71e4283..f6f688bc0 100644 --- a/wolfssl/openssl/evp.h +++ b/wolfssl/openssl/evp.h @@ -723,6 +723,14 @@ WOLFSSL_API int wolfSSL_PKCS5_PBKDF2_HMAC(const char *pass, int passlen, const WOLFSSL_EVP_MD *digest, int keylen, unsigned char *out); +#if defined(HAVE_SCRYPT) && defined(HAVE_PBKDF2) && !defined(NO_PWDBASED) && \ + !defined(NO_SHA) +WOLFSSL_API int wolfSSL_EVP_PBE_scrypt(const char *pass, size_t passlen, + const unsigned char *salt, size_t saltlen, + word64 N, word64 r, word64 p, + word64 maxmem, unsigned char *key, size_t keylen); +#endif /* HAVE_SCRYPT && HAVE_PBKDF2 && !NO_PWDBASED && !NO_SHA */ + WOLFSSL_LOCAL int wolfSSL_EVP_get_hashinfo(const WOLFSSL_EVP_MD* evp, int* pHash, int* pHashSz); @@ -992,6 +1000,7 @@ typedef WOLFSSL_ASN1_PCTX ASN1_PCTX; #define PKCS5_PBKDF2_HMAC_SHA1 wolfSSL_PKCS5_PBKDF2_HMAC_SHA1 #define PKCS5_PBKDF2_HMAC wolfSSL_PKCS5_PBKDF2_HMAC +#define EVP_PBE_scrypt wolfSSL_EVP_PBE_scrypt /* OpenSSL compat. ctrl values */ #define EVP_CTRL_INIT 0x0