No sabemos qué pasará en el futuro, es decir no sabemos si nos robaran la cartera o la perderemos en algún USB y alguien la encontrara. Tampoco sabemos la cantidad de poder de computo que existira.
Pero además de tener cifrada nuestra cartera con un buen passphrase de más de 40 caracteres, se puede lograr una mejor seguridad, para en el caso de que sea robada sea inviable que por medio de fuerza bruta directo contra el passphrase.
Nuestra Cartera está protegida con el resultado de un hash sha512 derivado N veces a partir de nuestro Passphrase y un salt.
Es decir:
Código:
(key,IV) = PBKDF2_algo("sha512",passphrase+salt,N);
Normalmente el cliente bitcoin-core calcula ese N de tal forma que la Operación en total no lleve más de 1 Segundo
¿Por que? ¿Por que ponérsela fácil a los crackers de wallets?
Se puede editar el código fuente del bitcoin-core de tal forma que cuando nosotros cambiemos el passphrase este utilice un número N tal que N el proceso completo de PBKDF2_algo lleve al menos uno o dos minutos por passphare, es un pequeño precio de espera. Y el resultado será sumamente desalentador para quien se robe o encuentre la cartera.
¿Como hacer esta modificacion?
Si revisamos la versión estable y actual al dia de hoy, el bitcoin core 0.20 el archivo wallet.cpp tiene la solución:
https://github.com/bitcoin/bitcoin/blob/0.20/src/wallet/wallet.cpp En la linea 322 tenemos lo siguiente:
Código
bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase) { bool fWasLocked = IsLocked(); { LOCK(cs_wallet); Lock(); CCrypter crypter; CKeyingMaterial _vMasterKey; for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys) { if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) return false; if (Unlock(_vMasterKey)) { int64_t nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); pMasterKey.second.nDeriveIterations = static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * (100 / ((double)(GetTimeMillis() - nStartTime)))); nStartTime = GetTimeMillis(); crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod); pMasterKey.second.nDeriveIterations = (pMasterKey.second.nDeriveIterations + static_cast<unsigned int>(pMasterKey.second.nDeriveIterations * 100 / ((double)(GetTimeMillis() - nStartTime)))) / 2; if (pMasterKey.second.nDeriveIterations < 25000) pMasterKey.second.nDeriveIterations = 25000; WalletLogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations); if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey)) return false; WalletBatch(*database).WriteMasterKey(pMasterKey.first, pMasterKey.second); if (fWasLocked) Lock(); return true; } } } return false; }
Y solo tendria que quedar de la siguiente manera:
Código
bool CWallet::ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase) { bool fWasLocked = IsLocked(); { LOCK(cs_wallet); Lock(); CCrypter crypter; CKeyingMaterial _vMasterKey; for (MasterKeyMap::value_type& pMasterKey : mapMasterKeys) { if(!crypter.SetKeyFromPassphrase(strOldWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Decrypt(pMasterKey.second.vchCryptedKey, _vMasterKey)) return false; if (Unlock(_vMasterKey)) { pMasterKey.second.nDeriveIterations = 133707331; WalletLogPrintf("Wallet passphrase changed to an nDeriveIterations of %i\n", pMasterKey.second.nDeriveIterations); if (!crypter.SetKeyFromPassphrase(strNewWalletPassphrase, pMasterKey.second.vchSalt, pMasterKey.second.nDeriveIterations, pMasterKey.second.nDerivationMethod)) return false; if (!crypter.Encrypt(_vMasterKey, pMasterKey.second.vchCryptedKey)) return false; WalletBatch(*database).WriteMasterKey(pMasterKey.first, pMasterKey.second); if (fWasLocked) Lock(); return true; } } } return false; }
Si quitamos todo lo relacionado con el calculo del tiempo y agregamos la linea:
Código
pMasterKey.second.nDeriveIterations = 133707331;
En mi caso con el bitcoin-core oficial recompilado y con un procesador Intel Xeon CPU E3-1271 v3 @ 3.60GHz cambiar el passphrase toma alrededor de un minuto
Saludos!