80 lines
3.5 KiB
C++
80 lines
3.5 KiB
C++
// Most of this file has been ported from EncryptionUtils.cpp from BitcoinArmory:
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// Copyright(C) 2011-2013, Armory Technologies, Inc. //
|
|
// Distributed under the GNU Affero General Public License (AGPL v3) //
|
|
// See LICENSE or http://www.gnu.org/licenses/agpl.html //
|
|
// //
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// For the KDF:
|
|
//
|
|
// This technique is described in Colin Percival's paper on memory-hard
|
|
// key-derivation functions, used to create "scrypt":
|
|
//
|
|
// http://www.tarsnap.com/scrypt/scrypt.pdf
|
|
//
|
|
// The goal is to create a key-derivation function that can force a memory
|
|
// requirement on the thread applying the KDF. By picking a sequence-length
|
|
// of 1,000,000, each thread will require 32 MB of memory to compute the keys,
|
|
// which completely disarms GPUs of their massive parallelization capabilities
|
|
// (for maximum parallelization, the kernel must use less than 1-2 MB/thread)
|
|
//
|
|
// Even with less than 1,000,000 hashes, as long as it requires more than 64
|
|
// kB of memory, a GPU will have to store the computed lookup tables in global
|
|
// memory, which is extremely slow for random lookup. As a result, GPUs are
|
|
// no better (and possibly much worse) than a CPU for brute-forcing the passwd
|
|
//
|
|
// This KDF is actually the ROMIX algorithm described on page 6 of Colin's
|
|
// paper. This was chosen because it is the simplest technique that provably
|
|
// achieves the goal of being secure, and memory-hard.
|
|
//
|
|
// The computeKdfParams method well test the speed of the system it is running
|
|
// on, and try to pick the largest memory-size the system can compute in less
|
|
// than 0.25s (or specified target).
|
|
//
|
|
//
|
|
// NOTE: If you are getting an error about invalid argument types, from python,
|
|
// it is usually because you passed in a BinaryData/Python-string instead
|
|
// of a SecureBinaryData object
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#pragma once
|
|
#include <string>
|
|
|
|
namespace fc {
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// A memory-bound key-derivation function -- uses a variation of Colin
|
|
// Percival's ROMix algorithm: http://www.tarsnap.com/scrypt/scrypt.pdf
|
|
//
|
|
// The computeKdfParams method takes in a target time, T, for computation
|
|
// on the computer executing the test. The final KDF should take somewhere
|
|
// between T/2 and T seconds.
|
|
class romix
|
|
{
|
|
public:
|
|
romix(u_int32_t memReqts, u_int32_t numIter, std::string salt);
|
|
|
|
std::string deriveKey_OneIter(std::string const & password);
|
|
std::string deriveKey(std::string const & password);
|
|
|
|
private:
|
|
u_int32_t hashOutputBytes_;
|
|
u_int32_t kdfOutputBytes_; // size of final key data
|
|
|
|
u_int32_t memoryReqtBytes_;
|
|
u_int32_t sequenceCount_;
|
|
std::string salt_; // prob not necessary amidst numIter, memReqts
|
|
// but I guess it can't hurt
|
|
|
|
u_int32_t numIterations_; // We set the ROMIX params for a given memory
|
|
// req't. Then run it numIter times to meet
|
|
// the computation-time req't
|
|
};
|
|
|
|
}
|
|
|
|
|