From 9acf270b14e561fe959ff25001f083a00e5e1caa Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 24 Aug 2013 01:56:49 +0400 Subject: [PATCH] Add scrypt+sha512 key derivation method. Disabled by default. You can use -derivationmethod option to choose which method will be used for wallet encryption keys generation. Possible values: * sha512 - default, compatible with bitcoin; * scrypt+sha512 - selects scrypt derivation function. Please note that this option only allows you to select default method. If you are already using encrypted wallet then suitable derivation method will be selected automatically. --- src/crypter.cpp | 14 ++++++++++++++ src/crypter.h | 22 +++++++++++++++++++++- src/init.cpp | 6 ++++++ src/main.h | 1 + src/scrypt.cpp | 41 ++++++++++++++++++++++++++++++++++++++--- src/scrypt.h | 2 ++ src/wallet.cpp | 2 +- 7 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/crypter.cpp b/src/crypter.cpp index 181b8fa..6deab04 100644 --- a/src/crypter.cpp +++ b/src/crypter.cpp @@ -11,6 +11,7 @@ #endif #include "crypter.h" +#include "scrypt.h" bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod) { @@ -19,8 +20,21 @@ bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::v int i = 0; if (nDerivationMethod == 0) + { i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0], (unsigned char *)&strKeyData[0], strKeyData.size(), nRounds, chKey, chIV); + } + + if (nDerivationMethod == 1) + { + // Passphrase conversion + uint256 scryptHash = scrypt_salted_multiround_hash((const void*)strKeyData.c_str(), strKeyData.size(), &chSalt[0], 8, nRounds); + + i = EVP_BytesToKey(EVP_aes_256_cbc(), EVP_sha512(), &chSalt[0], + (unsigned char *)&scryptHash, sizeof scryptHash, nRounds, chKey, chIV); + memset(&scryptHash, 0, sizeof scryptHash); + } + if (i != (int)WALLET_CRYPTO_KEY_SIZE) { diff --git a/src/crypter.h b/src/crypter.h index 04538a3..dd5d506 100644 --- a/src/crypter.h +++ b/src/crypter.h @@ -53,9 +53,29 @@ public: // 25000 rounds is just under 0.1 seconds on a 1.86 GHz Pentium M // ie slightly lower than the lowest hardware we need bother supporting nDeriveIterations = 25000; - nDerivationMethod = 0; + nDerivationMethod = 1; vchOtherDerivationParameters = std::vector(0); } + + CMasterKey(unsigned int nDerivationMethodIndex) + { + switch (nDerivationMethodIndex) + { + case 0: // sha512 + default: + nDeriveIterations = 25000; + nDerivationMethod = 0; + vchOtherDerivationParameters = std::vector(0); + break; + + case 1: // scrypt+sha512 + nDeriveIterations = 10000; + nDerivationMethod = 1; + vchOtherDerivationParameters = std::vector(0); + break; + } + } + }; typedef std::vector > CKeyingMaterial; diff --git a/src/init.cpp b/src/init.cpp index 621dcfa..5b05ea8 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -28,6 +28,7 @@ CWallet* pwalletMain; CClientUIInterface uiInterface; std::string strWalletFileName; unsigned int nNodeLifespan; +unsigned int nDerivationMethodIndex; ////////////////////////////////////////////////////////////////////////////// // @@ -246,6 +247,7 @@ std::string HelpMessage() " -dnsseed " + _("Find peers using DNS lookup (default: 1)") + "\n" + " -nosynccheckpoints " + _("Disable sync checkpoints (default: 0)") + "\n" + " -stakepooledkeys " + _("Use pooled pubkeys for the last coinstake output (default: 0)") + "\n" + + " -derivationmethod " + _("Which key derivation method to use by default (default: sha512)") + "\n" + " -banscore= " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" + " -bantime= " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" + " -maxreceivebuffer= " + _("Maximum per-connection receive buffer, *1000 bytes (default: 5000)") + "\n" + @@ -354,6 +356,10 @@ bool AppInit2() nNodeLifespan = GetArg("-addrlifespan", 7); fStakeUsePooledKeys = GetBoolArg("-stakepooledkeys", false); + + if(GetArg("-derivationmethod", "sha512") == "scrypt+sha512") + nDerivationMethodIndex = 1; + fTestNet = GetBoolArg("-testnet"); if (fTestNet) { SoftSetBoolArg("-irc", true); diff --git a/src/main.h b/src/main.h index 8b92292..3dfdef3 100644 --- a/src/main.h +++ b/src/main.h @@ -89,6 +89,7 @@ extern std::map mapOrphanBlocks; // Settings extern int64 nTransactionFee; extern bool fStakeUsePooledKeys; +extern unsigned int nDerivationMethodIndex; // Minimum disk space required - used in CheckDiskSpace() static const uint64 nMinDiskSpace = 52428800; diff --git a/src/scrypt.cpp b/src/scrypt.cpp index 7cc1b30..c54202e 100644 --- a/src/scrypt.cpp +++ b/src/scrypt.cpp @@ -49,7 +49,7 @@ extern "C" void scrypt_core(uint32_t *X, uint32_t *V); r = 1, p = 1, N = 1024 */ -uint256 scrypt(const void* input, size_t inputlen, void *scratchpad) +uint256 scrypt_nosalt(const void* input, size_t inputlen, void *scratchpad) { uint32_t *V; uint32_t X[32]; @@ -63,14 +63,49 @@ uint256 scrypt(const void* input, size_t inputlen, void *scratchpad) return result; } +uint256 scrypt(const void* data, size_t datalen, const void* salt, size_t saltlen, void *scratchpad) +{ + uint32_t *V; + uint32_t X[32]; + uint256 result = 0; + V = (uint32_t *)(((uintptr_t)(scratchpad) + 63) & ~ (uintptr_t)(63)); + + PBKDF2_SHA256((const uint8_t*)data, datalen, (const uint8_t*)salt, saltlen, 1, (uint8_t *)X, 128); + scrypt_core(X, V); + PBKDF2_SHA256((const uint8_t*)data, datalen, (uint8_t *)X, 128, 1, (uint8_t*)&result, 32); + + return result; +} + uint256 scrypt_hash(const void* input, size_t inputlen) { unsigned char scratchpad[SCRYPT_BUFFER_SIZE]; - return scrypt(input, inputlen, scratchpad); + return scrypt_nosalt(input, inputlen, scratchpad); +} + +uint256 scrypt_salted_hash(const void* input, size_t inputlen, const void* salt, size_t saltlen) +{ + unsigned char scratchpad[SCRYPT_BUFFER_SIZE]; + return scrypt(input, inputlen, salt, saltlen, scratchpad); +} + +uint256 scrypt_salted_multiround_hash(const void* input, size_t inputlen, const void* salt, size_t saltlen, const unsigned int nRounds) +{ + uint256 resultHash = scrypt_salted_hash(input, inputlen, salt, saltlen); + uint256 transitionalHash = resultHash; + + for(unsigned int i = 1; i < nRounds; i++) + { + resultHash = scrypt_salted_hash(input, inputlen, (const void*)&transitionalHash, 32); + transitionalHash = resultHash; + } + + return resultHash; } uint256 scrypt_blockhash(const void* input) { unsigned char scratchpad[SCRYPT_BUFFER_SIZE]; - return scrypt(input, 80, scratchpad); + return scrypt_nosalt(input, 80, scratchpad); } + diff --git a/src/scrypt.h b/src/scrypt.h index 2d2112d..17afd85 100644 --- a/src/scrypt.h +++ b/src/scrypt.h @@ -7,6 +7,8 @@ #include "util.h" #include "net.h" +uint256 scrypt_salted_multiround_hash(const void* input, size_t inputlen, const void* salt, size_t saltlen, const unsigned int nRounds); +uint256 scrypt_salted_hash(const void* input, size_t inputlen, const void* salt, size_t saltlen); uint256 scrypt_hash(const void* input, size_t inputlen); uint256 scrypt_blockhash(const void* input); diff --git a/src/wallet.cpp b/src/wallet.cpp index 063a1ed..aecb227 100644 --- a/src/wallet.cpp +++ b/src/wallet.cpp @@ -247,7 +247,7 @@ bool CWallet::EncryptWallet(const SecureString& strWalletPassphrase) vMasterKey.resize(WALLET_CRYPTO_KEY_SIZE); RAND_bytes(&vMasterKey[0], WALLET_CRYPTO_KEY_SIZE); - CMasterKey kMasterKey; + CMasterKey kMasterKey(nDerivationMethodIndex); RandAddSeedPerfmon(); kMasterKey.vchSalt.resize(WALLET_CRYPTO_SALT_SIZE); -- 1.7.1