diff --git a/Filelist.txt b/Filelist.txt
index b679a6cf..50882710 100644
--- a/Filelist.txt
+++ b/Filelist.txt
@@ -253,6 +253,8 @@ safer.cpp
safer.h
salsa.cpp
salsa.h
+scrypt.cpp
+scrypt.h
seal.cpp
seal.h
secblock.h
diff --git a/cryptlib.vcxproj b/cryptlib.vcxproj
index 0d4ab1cd..f57d8fe1 100644
--- a/cryptlib.vcxproj
+++ b/cryptlib.vcxproj
@@ -278,6 +278,7 @@
+
@@ -468,6 +469,7 @@
+
@@ -515,4 +517,4 @@
-
+
\ No newline at end of file
diff --git a/cryptlib.vcxproj.filters b/cryptlib.vcxproj.filters
index 04dec87d..e3060ef0 100644
--- a/cryptlib.vcxproj.filters
+++ b/cryptlib.vcxproj.filters
@@ -329,6 +329,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -801,6 +804,9 @@
Header Files
+
+ Header Files
+
Header Files
@@ -939,4 +945,4 @@
Miscellaneous
-
+
\ No newline at end of file
diff --git a/pwdbased.h b/pwdbased.h
index 499d932a..06a4b025 100644
--- a/pwdbased.h
+++ b/pwdbased.h
@@ -11,6 +11,7 @@
#include "cryptlib.h"
#include "hrtimer.h"
#include "integer.h"
+#include "argnames.h"
#include "hmac.h"
NAMESPACE_BEGIN(CryptoPP)
diff --git a/scrypt.cpp b/scrypt.cpp
new file mode 100644
index 00000000..17a1e7be
--- /dev/null
+++ b/scrypt.cpp
@@ -0,0 +1,312 @@
+// scrypt.cpp - written and placed in public domain by Jeffrey Walton.
+// Based on reference source code by Colin Percival and Simon Josefsson.
+
+#include "pch.h"
+
+#include "scrypt.h"
+#include "argnames.h"
+#include "pwdbased.h"
+#include "stdcpp.h"
+#include "salsa.h"
+#include "misc.h"
+#include "sha.h"
+
+#ifdef _OPENMP
+# include
+#endif
+
+#include
+#include
+#include
+
+ANONYMOUS_NAMESPACE_BEGIN
+
+using CryptoPP::rotlConstant;
+using CryptoPP::AlignedSecByteBlock;
+using CryptoPP::LITTLE_ENDIAN_ORDER;
+using CryptoPP::ConditionalByteReverse;
+
+static inline void LE32ENC(uint8_t* out, uint32_t in)
+{
+ uint32_t* ptr = reinterpret_cast(out);
+ ConditionalByteReverse(LITTLE_ENDIAN_ORDER, ptr, &in, 4);
+}
+
+static inline uint32_t LE32DEC(const uint8_t* in)
+{
+ uint32_t res;
+ const uint32_t* ptr = reinterpret_cast(in);
+ ConditionalByteReverse(LITTLE_ENDIAN_ORDER, &res, ptr, 4);
+ return res;
+}
+
+static inline uint64_t LE64DEC(const uint8_t* in)
+{
+ uint64_t res;
+ const uint64_t* ptr = reinterpret_cast(in);
+ ConditionalByteReverse(LITTLE_ENDIAN_ORDER, &res, ptr, 8);
+ return res;
+}
+
+static inline void BlockCopy(uint8_t * dest, uint8_t * src, size_t len)
+{
+ for (size_t i = 0; i < len; i++)
+ dest[i] = src[i];
+}
+
+static inline void BlockXOR(uint8_t * dest, uint8_t * src, size_t len)
+{
+ for (size_t i = 0; i < len; i++)
+ dest[i] ^= src[i];
+}
+
+static inline void PBKDF2_SHA256(uint8_t * buf, size_t dkLen,
+ const uint8_t * passwd, size_t passwdlen,
+ const uint8_t * salt, size_t saltlen, uint8_t count)
+{
+ using CryptoPP::SHA256;
+ using CryptoPP::PKCS5_PBKDF2_HMAC;
+
+ PKCS5_PBKDF2_HMAC pbkdf;
+ pbkdf.DeriveKey(buf, dkLen, 0, passwd, passwdlen, salt, saltlen, count, 0.0f);
+}
+
+static inline void Salsa20_8(uint8_t B[64])
+{
+ uint32_t B32[16], x[16];
+ size_t i = 0;
+
+ for (i = 0; i < 16; i++)
+ B32[i] = LE32DEC(&B[i * 4]);
+
+ for (i = 0; i < 16; i++)
+ x[i] = B32[i];
+
+ for (i = 0; i < 8; i += 2)
+ {
+ x[ 4] ^= rotlConstant< 7>(x[ 0]+x[12]);
+ x[ 8] ^= rotlConstant< 9>(x[ 4]+x[ 0]);
+ x[12] ^= rotlConstant<13>(x[ 8]+x[ 4]);
+ x[ 0] ^= rotlConstant<18>(x[12]+x[ 8]);
+
+ x[ 9] ^= rotlConstant< 7>(x[ 5]+x[ 1]);
+ x[13] ^= rotlConstant< 9>(x[ 9]+x[ 5]);
+ x[ 1] ^= rotlConstant<13>(x[13]+x[ 9]);
+ x[ 5] ^= rotlConstant<18>(x[ 1]+x[13]);
+
+ x[14] ^= rotlConstant< 7>(x[10]+x[ 6]);
+ x[ 2] ^= rotlConstant< 9>(x[14]+x[10]);
+ x[ 6] ^= rotlConstant<13>(x[ 2]+x[14]);
+ x[10] ^= rotlConstant<18>(x[ 6]+x[ 2]);
+
+ x[ 3] ^= rotlConstant< 7>(x[15]+x[11]);
+ x[ 7] ^= rotlConstant< 9>(x[ 3]+x[15]);
+ x[11] ^= rotlConstant<13>(x[ 7]+x[ 3]);
+ x[15] ^= rotlConstant<18>(x[11]+x[ 7]);
+
+ x[ 1] ^= rotlConstant< 7>(x[ 0]+x[ 3]);
+ x[ 2] ^= rotlConstant< 9>(x[ 1]+x[ 0]);
+ x[ 3] ^= rotlConstant<13>(x[ 2]+x[ 1]);
+ x[ 0] ^= rotlConstant<18>(x[ 3]+x[ 2]);
+
+ x[ 6] ^= rotlConstant< 7>(x[ 5]+x[ 4]);
+ x[ 7] ^= rotlConstant< 9>(x[ 6]+x[ 5]);
+ x[ 4] ^= rotlConstant<13>(x[ 7]+x[ 6]);
+ x[ 5] ^= rotlConstant<18>(x[ 4]+x[ 7]);
+
+ x[11] ^= rotlConstant< 7>(x[10]+x[ 9]);
+ x[ 8] ^= rotlConstant< 9>(x[11]+x[10]);
+ x[ 9] ^= rotlConstant<13>(x[ 8]+x[11]);
+ x[10] ^= rotlConstant<18>(x[ 9]+x[ 8]);
+
+ x[12] ^= rotlConstant< 7>(x[15]+x[14]);
+ x[13] ^= rotlConstant< 9>(x[12]+x[15]);
+ x[14] ^= rotlConstant<13>(x[13]+x[12]);
+ x[15] ^= rotlConstant<18>(x[14]+x[13]);
+ }
+
+ for (i = 0; i < 16; i++)
+ B32[i] += x[i];
+
+ for (i = 0; i < 16; i++)
+ LE32ENC(&B[4 * i], B32[i]);
+}
+
+static inline void BlockMix(uint8_t * B, uint8_t * Y, size_t r)
+{
+ uint8_t X[64];
+ size_t i;
+
+ // 1: X <-- B_{2r - 1}
+ BlockCopy(X, &B[(2 * r - 1) * 64], 64);
+
+ // 2: for i = 0 to 2r - 1 do
+ for (i = 0; i < 2 * r; i++)
+ {
+ // 3: X <-- H(X \xor B_i)
+ BlockXOR(X, &B[i * 64], 64);
+ Salsa20_8(X);
+
+ // 4: Y_i <-- X
+ BlockCopy(&Y[i * 64], X, 64);
+ }
+
+ // 6: B' <-- (Y_0, Y_2 ... Y_{2r-2}, Y_1, Y_3 ... Y_{2r-1})
+ for (i = 0; i < r; i++)
+ BlockCopy(&B[i * 64], &Y[(i * 2) * 64], 64);
+ for (i = 0; i < r; i++)
+ BlockCopy(&B[(i + r) * 64], &Y[(i * 2 + 1) * 64], 64);
+}
+
+static inline uint64_t Integerify(uint8_t * B, size_t r)
+{
+ uint8_t * X = &B[(2 * r - 1) * 64];
+ return LE64DEC(X);
+}
+
+static inline void Smix(uint8_t * B, size_t r, uint64_t N, uint8_t * V, uint8_t * XY)
+{
+ uint8_t * X = XY;
+ uint8_t * Y = XY+128*r;
+ uint64_t i, j;
+
+ // 1: X <-- B
+ BlockCopy(X, B, 128 * r);
+
+ // 2: for i = 0 to N - 1 do
+ for (i = 0; i < N; i++)
+ {
+ // 3: V_i <-- X
+ BlockCopy(&V[i * (128 * r)], X, 128 * r);
+
+ // 4: X <-- H(X)
+ BlockMix(X, Y, r);
+ }
+
+ // 6: for i = 0 to N - 1 do
+ for (i = 0; i < N; i++) {
+ // 7: j <-- Integerify(X) mod N
+ j = Integerify(X, r) & (N - 1);
+
+ // 8: X <-- H(X \xor V_j)
+ BlockXOR(X, &V[j * (128 * r)], 128 * r);
+ BlockMix(X, Y, r);
+ }
+
+ // 10: B' <-- X
+ BlockCopy(B, X, 128 * r);
+}
+ANONYMOUS_NAMESPACE_END
+
+NAMESPACE_BEGIN(CryptoPP)
+
+size_t Scrypt::GetValidDerivedLength(size_t keylength) const
+{
+ if (keylength > MaxDerivedLength())
+ return MaxDerivedLength();
+ return keylength;
+}
+
+void Scrypt::ValidateParameters(size_t derivedLen, word64 cost, word64 blockSize, word64 parallelization) const
+{
+ // Optimizer should remove this on 64-bit platforms
+ if (std::numeric_limits::max() > std::numeric_limits::max())
+ {
+ const uint64_t maxLen = ((static_cast(1) << 32) - 1) * 32;
+ if (derivedLen > maxLen) {
+ std::ostringstream oss;
+ oss << "derivedLen " << derivedLen << " is larger than " << maxLen;
+ throw InvalidArgument("Scrypt: " + oss.str());
+ }
+ }
+
+ if (IsPowerOf2(cost) == false)
+ throw InvalidArgument("Scrypt: cost must be a power of 2");
+
+ const uint64_t prod = static_cast(blockSize) * parallelization;
+ if (prod >= (1U << 30)) {
+ std::ostringstream oss;
+ oss << "r*p " << prod << " is larger than " << (1U << 30);
+ throw InvalidArgument("Scrypt: " + oss.str());
+ }
+
+ // Scrypt has several tests that effectively verify allocations like
+ // '128 * r * N' and '128 * r * p' do not overflow. They are the tests
+ // that set errno to ENOMEM. We can make the logic a little more clear
+ // using word128. At first blush the word128 may seem like overkill.
+ // However, this alogirthm is dominated by slow moving parts, so a
+ // one-time check is insignificant in the bigger picture.
+#if defined(CRYPTOPP_WORD128_AVAILABLE)
+ const word128 maxElems = static_cast(SIZE_MAX);
+ bool bLimit = (maxElems >= static_cast(cost) * blockSize * 128U);
+ bool xyLimit = (maxElems >= static_cast(parallelization) * blockSize * 128U);
+ bool vLimit = (maxElems >= static_cast(blockSize) * 256U + 64U);
+ if (!bLimit || !xyLimit || !vLimit)
+ throw std::bad_alloc();
+#else
+ const word64 maxElems = static_cast(SIZE_MAX);
+ bool bLimit = (blockSize < maxElems / 128U / cost);
+ bool xyLimit = (blockSize < maxElems / 128U / parallelization);
+ bool vLimit = (blockSize < (maxElems - 64U) / 256U);
+
+ if (!bLimit || !xyLimit || !vLimit)
+ throw std::bad_alloc();
+#endif
+}
+
+size_t Scrypt::DeriveKey(byte *derived, size_t derivedLen,
+ const byte *secret, size_t secretLen, const NameValuePairs& params) const
+{
+ CRYPTOPP_ASSERT(secret /*&& secretLen*/);
+ CRYPTOPP_ASSERT(derived && derivedLen);
+ CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
+
+ word64 cost=0, blockSize=0, parallelization=0;
+
+ if(params.GetValue("Cost", cost) == false)
+ cost = defaultCost;
+
+ if(params.GetValue("BlockSize", blockSize) == false)
+ blockSize = defaultBlockSize;
+
+ if(params.GetValue("Parallelization", parallelization) == false)
+ parallelization = defaultParallelization;
+
+ ConstByteArrayParameter salt;
+ (void)params.GetValue("Salt", salt);
+
+ return DeriveKey(derived, derivedLen, secret, secretLen, salt.begin(), salt.size(), cost, blockSize, parallelization);
+}
+
+size_t Scrypt::DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
+ const byte *salt, size_t saltLen, word64 cost, word64 blockSize, word64 parallel) const
+{
+ CRYPTOPP_ASSERT(secret /*&& secretLen*/);
+ CRYPTOPP_ASSERT(derived && derivedLen);
+ CRYPTOPP_ASSERT(derivedLen <= MaxDerivedLength());
+ CRYPTOPP_ASSERT(IsPowerOf2(cost));
+
+ ThrowIfInvalidDerivedLength(derivedLen);
+ ValidateParameters(derivedLen, cost, blockSize, parallel);
+
+ AlignedSecByteBlock B(static_cast(blockSize * parallel * 128U));
+ AlignedSecByteBlock XY(static_cast(blockSize * 256U));
+ AlignedSecByteBlock V(static_cast(blockSize * cost * 128U));
+
+ // 1: (B_0 ... B_{p-1}) <-- PBKDF2(P, S, 1, p * MFLen)
+ PBKDF2_SHA256(B, B.size(), secret, secretLen, salt, saltLen, 1);
+
+ // 2: for i = 0 to p - 1 do
+ for (unsigned int i = 0; i < parallel; i++)
+ {
+ // 3: B_i <-- MF(B_i, N)
+ Smix(B+static_cast(blockSize*i*128), static_cast(blockSize), cost, V, XY);
+ }
+
+ // 5: DK <-- PBKDF2(P, B, 1, dkLen)
+ PBKDF2_SHA256(derived, derivedLen, secret, secretLen, B, static_cast(blockSize*parallel*128), 1);
+
+ return 1;
+}
+
+NAMESPACE_END
diff --git a/scrypt.h b/scrypt.h
new file mode 100644
index 00000000..ef63fb1a
--- /dev/null
+++ b/scrypt.h
@@ -0,0 +1,96 @@
+// scrypt.h - written and placed in public domain by Jeffrey Walton.
+// Based on reference source code by Colin Percival and Simon Josefsson.
+
+/// \file scrypt.h
+/// \brief Classes for Scrypt from RFC 7914
+/// \sa Stronger Key Derivation via
+/// Sequential Memory-Hard Functions,
+/// The scrypt key derivation function
+/// and RFC 7914, The scrypt Password-Based
+/// Key Derivation Function
+/// \since Crypto++ 6.2
+
+#ifndef CRYPTOPP_SCRYPT_H
+#define CRYPTOPP_SCRYPT_H
+
+#include "cryptlib.h"
+#include "secblock.h"
+#include "algparam.h"
+
+NAMESPACE_BEGIN(CryptoPP)
+
+/// \brief Scrypt key derivation function
+/// \sa The scrypt key derivation function
+/// and RFC 7914, The scrypt Password-Based
+/// Key Derivation Function
+/// \since Crypto++ 6.2
+class Scrypt : public KeyDerivationFunction
+{
+public:
+ virtual ~Scrypt() {}
+
+ static std::string StaticAlgorithmName () {
+ return "scrypt";
+ }
+
+ // KeyDerivationFunction interface
+ std::string AlgorithmName() const {
+ return StaticAlgorithmName();
+ }
+
+ // KeyDerivationFunction interface
+ size_t MaxDerivedLength() const {
+ return static_cast(-1);
+ }
+
+ // KeyDerivationFunction interface
+ size_t GetValidDerivedLength(size_t keylength) const;
+
+ // KeyDerivationFunction interface
+ size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
+ const NameValuePairs& params) const;
+
+ /// \brief Derive a key from a seed
+ /// \param derived the derived output buffer
+ /// \param derivedLen the size of the derived buffer, in bytes
+ /// \param secret the seed input buffer
+ /// \param secretLen the size of the secret buffer, in bytes
+ /// \param salt the salt input buffer
+ /// \param saltLen the size of the salt buffer, in bytes
+ /// \param cost the CPU/memory cost factor
+ /// \param blockSize the block size
+ /// \param parallelization the parallelization factor
+ /// \param infoLen the size of the info buffer, in bytes
+ /// \returns the number of iterations performed
+ /// \throws InvalidDerivedLength if derivedLen is invalid for the scheme
+ /// \details DeriveKey() provides a standard interface to derive a key from
+ /// a seed and other parameters. Each class that derives from KeyDerivationFunction
+ /// provides an overload that accepts most parameters used by the derivation function.
+ /// \details The CPU/Memory cost parameter ("N" in the documents) must be
+ /// larger than 1, a power of 2, and less than 2^(128 * r / 8).
+ /// \details The parameter blockSize ("r" in the documents) specifies the block
+ /// size.
+ /// \details The parallelization parameter ("p" in the documents) is a positive
+ /// integer less than or equal to ((2^32-1) * 32) / (128 * r).
+ /// \details Crypto++ uses size_t for its size datatype, and limits are
+ /// based on the 32-bit version of size_t. For example, cost is
+ /// limited to 0xffffffff instead of 2^(128 * r / 8).
+ /// \details Scrypt always returns 1 because it only performs 1 iteration. Other
+ /// derivation functions, like PBKDF's, will return more interesting values.
+ size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen,
+ const byte *salt, size_t saltLen, word64 cost=2, word64 blockSize=8, word64 parallelization=1) const;
+
+protected:
+ enum {defaultCost=2, defaultBlockSize=8, defaultParallelization=1};
+
+ // KeyDerivationFunction interface
+ const Algorithm & GetAlgorithm() const {
+ return *this;
+ }
+
+ inline void ValidateParameters(size_t derivedlen, word64 cost, word64 blockSize, word64 parallelization) const;
+};
+
+NAMESPACE_END
+
+#endif // CRYPTOPP_SCRYPT_H
diff --git a/test.cpp b/test.cpp
index 3568048d..109ca6c6 100644
--- a/test.cpp
+++ b/test.cpp
@@ -925,29 +925,30 @@ bool Validate(int alg, bool thorough, const char *seedInput)
case 56: result = ValidateAdler32(); break;
case 57: result = ValidateMD4(); break;
case 58: result = ValidatePBKDF(); break;
- case 59: result = ValidateESIGN(); break;
- case 60: result = ValidateDLIES(); break;
- case 61: result = ValidateBaseCode(); break;
- case 62: result = ValidateSHACAL2(); break;
- case 63: result = ValidateARIA(); break;
- case 64: result = ValidateCamellia(); break;
- case 65: result = ValidateWhirlpool(); break;
- case 66: result = ValidateTTMAC(); break;
- case 67: result = ValidateSalsa(); break;
- case 68: result = ValidateSosemanuk(); break;
- case 69: result = ValidateVMAC(); break;
- case 70: result = ValidateCCM(); break;
- case 71: result = ValidateGCM(); break;
- case 72: result = ValidateCMAC(); break;
- case 73: result = ValidateHKDF(); break;
- case 74: result = ValidateSM3(); break;
- case 75: result = ValidateBLAKE2s(); break;
- case 76: result = ValidateBLAKE2b(); break;
- case 77: result = ValidatePoly1305(); break;
- case 78: result = ValidateSipHash(); break;
- case 79: result = ValidateHashDRBG(); break;
- case 80: result = ValidateHmacDRBG(); break;
- case 90: result = ValidateNaCl(); break;
+ case 59: result = ValidateHKDF(); break;
+ case 60: result = ValidateScrypt(); break;
+ case 61: result = ValidateESIGN(); break;
+ case 62: result = ValidateDLIES(); break;
+ case 63: result = ValidateBaseCode(); break;
+ case 64: result = ValidateSHACAL2(); break;
+ case 65: result = ValidateARIA(); break;
+ case 66: result = ValidateCamellia(); break;
+ case 67: result = ValidateWhirlpool(); break;
+ case 68: result = ValidateTTMAC(); break;
+ case 69: result = ValidateSalsa(); break;
+ case 70: result = ValidateSosemanuk(); break;
+ case 71: result = ValidateVMAC(); break;
+ case 72: result = ValidateCCM(); break;
+ case 73: result = ValidateGCM(); break;
+ case 74: result = ValidateCMAC(); break;
+ case 75: result = ValidateSM3(); break;
+ case 76: result = ValidateBLAKE2s(); break;
+ case 77: result = ValidateBLAKE2b(); break;
+ case 78: result = ValidatePoly1305(); break;
+ case 79: result = ValidateSipHash(); break;
+ case 80: result = ValidateHashDRBG(); break;
+ case 81: result = ValidateHmacDRBG(); break;
+ case 82: result = ValidateNaCl(); break;
#if defined(CRYPTOPP_EXTENDED_VALIDATION)
// http://github.com/weidai11/cryptopp/issues/92
diff --git a/validat1.cpp b/validat1.cpp
index f4f30de8..e87b24c2 100644
--- a/validat1.cpp
+++ b/validat1.cpp
@@ -146,6 +146,7 @@ bool ValidateAll(bool thorough)
pass=ValidatePBKDF() && pass;
pass=ValidateHKDF() && pass;
+ pass=ValidateScrypt() && pass;
pass=ValidateDES() && pass;
pass=ValidateCipherModes() && pass;
diff --git a/validat3.cpp b/validat3.cpp
index add46a89..f7a377ee 100644
--- a/validat3.cpp
+++ b/validat3.cpp
@@ -28,6 +28,7 @@
#include "ttmac.h"
#include "integer.h"
#include "pwdbased.h"
+#include "scrypt.h"
#include "filters.h"
#include "files.h"
#include "hex.h"
@@ -671,9 +672,9 @@ bool TestHKDF(KeyDerivationFunction &kdf, const HKDF_TestTuple *testSet, unsigne
AlgorithmParameters params;
if (tuple.hexSalt)
- params.operator()(Name::Salt(), ConstByteArrayParameter((const byte*)&salt[0], salt.size()));
+ params(Name::Salt(), ConstByteArrayParameter((const byte*)&salt[0], salt.size()));
if (tuple.hexSalt)
- params.operator()("Info", ConstByteArrayParameter((const byte*)&info[0], info.size()));
+ params("Info", ConstByteArrayParameter((const byte*)&info[0], info.size()));
kdf.DeriveKey((byte*)&derived[0], derived.size(), (const byte*)&secret[0], secret.size(), params);
@@ -700,7 +701,7 @@ bool ValidateHKDF()
{
// SHA-1 from RFC 5869, Appendix A, https://tools.ietf.org/html/rfc5869
- static const HKDF_TestTuple testSet[] =
+ const HKDF_TestTuple testSet[] =
{
// Test Case #4
{"0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "085a01ea1b10f36933068b56efa5ad81 a4f14b822f5b091568a9cdd4f155fda2 c22e422478d305f3f896", 42},
@@ -720,7 +721,7 @@ bool ValidateHKDF()
{
// SHA-256 from RFC 5869, Appendix A, https://tools.ietf.org/html/rfc5869
- static const HKDF_TestTuple testSet[] =
+ const HKDF_TestTuple testSet[] =
{
// Test Case #1
{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "3cb25f25faacd57a90434f64d0362f2a 2d2d0a90cf1a5a4c5db02d56ecc4c5bf 34007208d5b887185865", 42},
@@ -738,7 +739,7 @@ bool ValidateHKDF()
{
// SHA-512, Crypto++ generated, based on RFC 5869, https://tools.ietf.org/html/rfc5869
- static const HKDF_TestTuple testSet[] =
+ const HKDF_TestTuple testSet[] =
{
// Test Case #0
{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "832390086CDA71FB47625BB5CEB168E4 C8E26A1A16ED34D9FC7FE92C14815793 38DA362CB8D9F925D7CB", 42},
@@ -758,7 +759,7 @@ bool ValidateHKDF()
{
// Whirlpool, Crypto++ generated, based on RFC 5869, https://tools.ietf.org/html/rfc5869
- static const HKDF_TestTuple testSet[] =
+ const HKDF_TestTuple testSet[] =
{
// Test Case #0
{"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", "000102030405060708090a0b0c", "f0f1f2f3f4f5f6f7f8f9", "0D29F74CCD8640F44B0DD9638111C1B5 766EFED752AF358109E2E7C9CD4A28EF 2F90B2AD461FBA0744D4", 42},
@@ -779,6 +780,75 @@ bool ValidateHKDF()
return pass;
}
+struct Scrypt_TestTuple
+{
+ const char * passwd;
+ const char * salt;
+ uint64_t n;
+ uint32_t r;
+ uint32_t p;
+ const char * expect;
+};
+
+bool TestScrypt(KeyDerivationFunction &pbkdf, const Scrypt_TestTuple *testSet, unsigned int testSetSize)
+{
+ bool pass = true;
+
+ for (unsigned int i=0; i