Add scrypt+sha512 key derivation method.
authoralex <alex@alex-VirtualBox.(none)>
Fri, 23 Aug 2013 21:56:49 +0000 (01:56 +0400)
committeralex <alex@alex-VirtualBox.(none)>
Fri, 23 Aug 2013 21:56:49 +0000 (01:56 +0400)
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
src/crypter.h
src/init.cpp
src/main.h
src/scrypt.cpp
src/scrypt.h
src/wallet.cpp

index 181b8fa..6deab04 100644 (file)
@@ -11,6 +11,7 @@
 #endif
 
 #include "crypter.h"
+#include "scrypt.h"
 
 bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector<unsigned char>& 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)
     {
index 04538a3..dd5d506 100644 (file)
@@ -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<unsigned char>(0);
     }
+
+    CMasterKey(unsigned int nDerivationMethodIndex)
+    {
+        switch (nDerivationMethodIndex)
+        {
+            case 0: // sha512
+            default:
+                nDeriveIterations = 25000;
+                nDerivationMethod = 0;
+                vchOtherDerivationParameters = std::vector<unsigned char>(0);
+            break;
+
+            case 1: // scrypt+sha512
+                nDeriveIterations = 10000;
+                nDerivationMethod = 1;
+                vchOtherDerivationParameters = std::vector<unsigned char>(0);
+            break;
+        }
+    }
+
 };
 
 typedef std::vector<unsigned char, secure_allocator<unsigned char> > CKeyingMaterial;
index 621dcfa..5b05ea8 100644 (file)
@@ -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=<n>          " + _("Threshold for disconnecting misbehaving peers (default: 100)") + "\n" +
         "  -bantime=<n>           " + _("Number of seconds to keep misbehaving peers from reconnecting (default: 86400)") + "\n" +
         "  -maxreceivebuffer=<n>  " + _("Maximum per-connection receive buffer, <n>*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);
index 8b92292..3dfdef3 100644 (file)
@@ -89,6 +89,7 @@ extern std::map<uint256, CBlock*> mapOrphanBlocks;
 // Settings
 extern int64 nTransactionFee;
 extern bool fStakeUsePooledKeys;
+extern unsigned int nDerivationMethodIndex;
 
 // Minimum disk space required - used in CheckDiskSpace()
 static const uint64 nMinDiskSpace = 52428800;
index 7cc1b30..c54202e 100644 (file)
@@ -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);
 }
+
index 2d2112d..17afd85 100644 (file)
@@ -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);
 
index 063a1ed..aecb227 100644 (file)
@@ -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);