Scrypt
Documentation |
#include <cryptopp/scrypt.h>
|
Scrypt is a key derivation function and password hashing algorithm created by Colin Percival. Scrypt was the first of the modern "memory hard" algorithms. The algorithm is standardized in RFC 7914, The scrypt Password-Based Key Derivation Function. Also see Stronger Key Derivation via Sequential Memory-Hard Functions and The scrypt key derivation function.
The Scrypt
class derives from the KeyDerivationFuction
class, which is the base class of all derivation functions. KeyDerivationFuction
provides several member functions but the one of interest is DeriveKey
. Each derived class will override DeriveKey
and provide a specialized implementation for a consistent interface.
The Scrypt algorithm provides three tunable security parameters called cost
, blockSize
and parallelization
. There are some restrictions on how the parameters are combined, and you should examine ValidateParameters
for some of the details. The overarching concern is allocation success, so byte* buffer = new byte[cost*blockSize*128];
must not overflow when calculating the size
of the buffer.
The algorithm was added at Crypto++ 6.2. The Crypto++ implementation provides OpenMP support for parallel hashing. OpenMP must be enabled when building the Crypto++ library for threading to be available. Also see Issue 613, Add scrypt key derivation function.
The Scrypt implementation took one bug report after it was cut-in. The class over-committed resources when the parallelization
parameter was less than the number of OMP threads. The over-commit was fixed at Commit edc7689a7fa4. Also see GitHub Issue 641.
Constructors
Scrypt
uses trivial constructors generated by the compiler.
DeriveKey
DeriveKey
is the member function of interest for KeyDerivationFuction
derived classes. The base class DeriveKey
signature is shown below.
size_t DeriveKey(byte *derived, size_t derivedLen, const byte *secret, size_t secretLen, const NameValuePairs& params)
derived
is a pointer to the derived key, and derivedLen
is the size of the buffer.
secret
is a pointer to the key or seed material, and keyLen
is the size of the buffer.
params
are NameValuePairs used to provide additional configuration information.
Using NameValuePairs to configure an object is an acquired taste, so each KeyDerivationFuction
derived object provides a DeriveKey
which unrolls the parameters as shown below. The default parameter arguments were taken from RFC 7914.
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)
derived
is a pointer to the derived key, and derivedLen
is the size of the buffer.
secret
is a pointer to the key or seed material, and keyLen
is the size of the buffer.
salt
is a pointer to additional seed material, and saltLen
is the size of the buffer.
cost
is the CPU/memory tradeoff.
blockSize
is the number of 256-byte blocks.
parallelization
is the number of discrete processing parts.
Sample Programs
The following are some sample programs for Scrypt.
Test Vectors
RFC 7914 provides 4 test vectors. Three of them are enabled when running cryptest.exe v
. The fourth is disabled because it takes so long to run it appears the test program hangs. The program below id the second test vector from the RFC. The parameters are secret="password", salt="NaCl", cost=1024, blockSize=8, paralellization=16
.
$ cat test.cxx #include "cryptlib.h" #include "secblock.h" #include "scrypt.h" #include "osrng.h" #include "files.h" #include "hex.h" #include <iostream> int main() { using namespace CryptoPP; SecByteBlock derived(64); const byte pass[] = "password"; const byte salt[] = "NaCl"; Scrypt scrypt; scrypt.DeriveKey(derived, derived.size(), pass, 8, salt, 4, 1024, 8, 16); std::cout << "Derived: "; StringSource(derived, 16, true, new HexEncoder(new FileSink(std::cout))); std::cout << "..." << std::endl; return 0; }
Running the program results in the following output. The known answer from the test vector is
fdbabe1c9d347200 7856e7190d01e9fe 7c6ad7cbc8237830 e77376634b373162 2eaf30d92e22a388 6ff109279d9830da c727afb94a83ee6d 8360cbdfa2cc0640
.
$ time ./test.exe Derived: FDBABE1C9D3472007856E7190D01E9FE... real 0m0.017s user 0m0.040s sys 0m0.009s
If you want to call the base class DeriveKey
using NameValuePairs then you can use the following code.
std::string pass("password"), salt("NaCl"); word64 cost=1024, blockSize=8, parallelization=16; AlgorithmParameters params = MakeParameters("Cost", cost) ("BlockSize", blockSize)("Parallelization", parallelization) ("Salt", ConstByteArrayParameter((const byte*)&salt[0], salt.size())); SecByteBlock derived(64); pbkdf.DeriveKey(derived, derived.size(), (const byte*)&pass[0], pass.size(), params);
OpenMP
The following program uses OpenMP to speed up hashing on a Core i5 with four cores. You have to build the library with OpenMP support and the steps are detailed on the OpenMP wiki page. Though the RFC recommends cost=2
and parallelization=1
, the program below uses cost=(1<<20)
and parallelization=4
. 1<<20
is approximately 1 million and it highlights the benefit of OpenMP for this algorithm.
$ cat test.cxx #include "cryptlib.h" #include "secblock.h" #include "scrypt.h" #include "osrng.h" #include "files.h" #include "hex.h" #include <iostream> #include <omp.h> int main() { using namespace CryptoPP; int threads = 1; #pragma omp parallel { threads = omp_get_num_threads(); } std::cout << "Threads: " << threads << std::endl; AutoSeededRandomPool prng; SecByteBlock key(64), salt(16*1024); prng.GenerateBlock(key, key.size()); prng.GenerateBlock(salt, salt.size()); Scrypt scrypt; scrypt.DeriveKey(key, key.size(), key, key.size(), salt, salt.size(), 1<<20, 12, 4); std::cout << "Key: "; StringSource(key, 16, true, new HexEncoder(new FileSink(std::cout))); std::cout << "..." << std::endl; return 0; }
The multithreaded OpenMP version of the program is about 3x faster than the single threaded version. The different results are due to using random parameters. Using the same parameters would produce the same result.
$ time OMP_NUM_THREADS=1 ./test.exe Threads: 1 Key: 4A433D4B73F5EA27400D6EC001CA3C9E... real 0m13.516s user 0m13.061s sys 0m0.438s $ time OMP_NUM_THREADS=2 ./test.exe Threads: 2 Key: 9EF3B82A54E57ADA188E0CD83B80C24A... real 0m7.889s user 0m14.684s sys 0m0.966s $ time OMP_NUM_THREADS=4 ./test.exe Threads: 4 Key: 512B6C8C44CCCA1A1E67C990178EB2CC... real 0m4.869s user 0m16.618s sys 0m2.136s $ time OMP_NUM_THREADS=6 ./test.exe Threads: 6 Key: 0A23D30D90C4E2212A7DF2FCA8A67412... real 0m4.831s user 0m16.634s sys 0m2.022s $ time OMP_NUM_THREADS=8 ./test.exe Threads: 8 Key: 033BE7CE45D127234261905E36761BB9... real 0m4.894s user 0m16.705s sys 0m2.206s $ time OMP_NUM_THREADS=12 ./test.exe Threads: 12 Key: A8BC687006F55B67D2F283FBA242736A... real 0m4.848s user 0m16.652s sys 0m2.059s
Downloads
No downloads.