Author

Topic: get sha-512 of wallet.dat (Read 208 times)

legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
June 24, 2021, 02:55:12 PM
#10
It must be my eyes or something.
I just can't see any PBKDF2 anywhere.
Surely i can see openssl's EVP BytesToKey and SHA512 functions but no PBKDF2.
I guess i'm getting old.

The PBKDF2 function in Bitcoin Core is not called "PBKDF2" or "KDF" or anything else obvious, it's literally "SetKeyFromPassphrase", and it has all the parameters that an ordinary PBKDF2 function would take:

Number of rounds i.e. iterations? Check: nRounds parameter (this is the number of times SHA512 is ran)
Salt? Check: chSalt parameter (note that the salt is always randomly generated)
Salt length? Check: chSalt.size() (this is always 16)
Hash function number? Check: nDerivationMethod parameter (always equals 0, which stands for "use SHA512 for the hash function")

Encrypted key (not obvious but is also a requirement to have a proper PBKDF2)? Check: The vchKey and vchIV members of the CCrypter class, which are directly calculated from the password.

The rest, length of encryption key, length of derivation method, additional arguments, these are all constants for Bitcoin wallet hashes and so they aren't even seen in this code snippet (ccrypter.h, ccrypter.cpp).

Edit: small typo
member
Activity: 180
Merit: 38
June 24, 2021, 12:49:43 PM
#9
PBKDF2 ? Really ?
Are you sure about that ?

Yes. You said:

That is incorrect.
The keys are stored encrypted with AES-256-CBC and not SHA512.
So you can not extract a sha-512 from a wallet.

But OP is getting wallet.dat password mixed up with private key (ckey) encryption. They are using two different algorithms/concepts.

The AES-256-CBC is a cipher that is used inside the PBKDF2 derivation, along with the SHA512 hash function. You can't just do a KDF without a hash function and a cipher to go with it. It is even referencing number of rounds and nDerivation method inside SetKeyFromPassphrase:

Quote
// This hashes the password (strKeyData, SecureString is the class used to represent a password)
// a number of times to a SHA512 hash *which is then* split in half to get an AES-256-CBC key and IV.
int CCrypter::BytesToKeySHA512AES(const std::vector& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const
~
// This is the actual KDF function. It checks for the parameters mentioned in the linked thread.
bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
    if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
        return false;

    int i = 0;
    if (nDerivationMethod == 0)
        i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
~snip

Notice how there's only an nDerivationMethod of 0. According to achow's comment in the thread I linked this stands for SHA-512 derivation function.

Quote
/*
 * The rest of this stuff is just using the AES-256-CBC key *generated* from the PBKDF2 function
 * above to encrypt uint256 stuff i.e. private keys
 */
bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector& chNewIV)
bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector &vchCiphertext) const
bool CCrypter::Decrypt(const std::vector& vchCiphertext, CKeyingMaterial& vchPlaintext) const
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext)
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)

As you can see, the password has never been encrypted anywhere, that's why it makes no sense to talk about extracting the encrypted password, because there is no encrypted password, only AES keys generated from the password.

Even these are not stored in the file, only a bunch of constant values along with the salt separated by dollar sign $ to make up the bitcoin wallet hash (which I sometimes [wrongly] call PBKDF2 hash)

The password generates the encryption keys, that's also the reason why wallet.dat files have one of the slowest keys/second cracking time, versus regular AES256CBC (in the KDF this function + the hashing is repeated several hundred times!)

It must be my eyes or something.
I just can't see any PBKDF2 anywhere.
Surely i can see openssl's EVP BytesToKey and SHA512 functions but no PBKDF2.
I guess i'm getting old.
newbie
Activity: 10
Merit: 0
June 21, 2021, 04:52:52 PM
#8
I guess you are using hashcat? Then indeed the john bitcoin2john.py is needed.
If you want to use btcrecover, you can use this script: https://github.com/UwSoftWare/trustless_btc_recovery

(btcrecover has its own extract script, but this will also extract the public keys, easier to check the balance before helping your friend)
legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
June 18, 2021, 01:40:22 PM
#7
PBKDF2 ? Really ?
Are you sure about that ?

Yes. You said:

That is incorrect.
The keys are stored encrypted with AES-256-CBC and not SHA512.
So you can not extract a sha-512 from a wallet.

But OP is getting wallet.dat password mixed up with private key (ckey) encryption. They are using two different algorithms/concepts.

The AES-256-CBC is a cipher that is used inside the PBKDF2 derivation, along with the SHA512 hash function. You can't just do a KDF without a hash function and a cipher to go with it. It is even referencing number of rounds and nDerivation method inside SetKeyFromPassphrase:

Quote
// This hashes the password (strKeyData, SecureString is the class used to represent a password)
// a number of times to a SHA512 hash *which is then* split in half to get an AES-256-CBC key and IV.
int CCrypter::BytesToKeySHA512AES(const std::vector& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const
~
// This is the actual KDF function. It checks for the parameters mentioned in the linked thread.
bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
    if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
        return false;

    int i = 0;
    if (nDerivationMethod == 0)
        i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());
~snip

Notice how there's only an nDerivationMethod of 0. According to achow's comment in the thread I linked this stands for SHA-512 derivation function.

Quote
/*
 * The rest of this stuff is just using the AES-256-CBC key *generated* from the PBKDF2 function
 * above to encrypt uint256 stuff i.e. private keys
 */
bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector& chNewIV)
bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector &vchCiphertext) const
bool CCrypter::Decrypt(const std::vector& vchCiphertext, CKeyingMaterial& vchPlaintext) const
bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext)
bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)

As you can see, the password has never been encrypted anywhere, that's why it makes no sense to talk about extracting the encrypted password, because there is no encrypted password, only AES keys generated from the password.

Even these are not stored in the file, only a bunch of constant values along with the salt separated by dollar sign $ to make up the bitcoin wallet hash (which I sometimes [wrongly] call PBKDF2 hash)

The password generates the encryption keys, that's also the reason why wallet.dat files have one of the slowest keys/second cracking time, versus regular AES256CBC (in the KDF this function + the hashing is repeated several hundred times!)
member
Activity: 180
Merit: 38
June 18, 2021, 10:05:15 AM
#6
You must be referring to the wallet.dat hash of the password (and not the wallet's encrypted private keys, which do use AES-256-CBC), which looks similar to this:

Code:
BTC2014 $ bitcoin $ 64 $ 6a750G4ef1867cff00d941df3d1165c39164b4273aca3c7e57af5adf60183945 $ 16 $ 83c69fe19b89ab31 $ 81501 $ 2 $ 00 $ 2 $ 00

Hashing a password in a wallet.dat is done using PBKDF2, and the SHA512 is merely a hash function used on a chunk of data within the many HMAC functions invoked in the PBKDF2 hash. So, you are not looking for a SHA512 hash, you want the PBKDF2 hash, which looks like the one I quoted above.

This hash can be obtained using the script bitcoin2john.py which is available on Github at https://raw.githubusercontent.com/magnumripper/JohnTheRipper/bleeding-jumbo/run/bitcoin2john.py .


PBKDF2 ? Really ?
Are you sure about that ?

I'm not even gonna argue anymore on this forum.
I will just drop the code that say's it all.

Quote
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include

#include
#include
#include

#include

int CCrypter::BytesToKeySHA512AES(const std::vector& chSalt, const SecureString& strKeyData, int count, unsigned char *key,unsigned char *iv) const
{
    // This mimics the behavior of openssl's EVP_BytesToKey with an aes256cbc
    // cipher and sha512 message digest. Because sha512's output size (64b) is
    // greater than the aes256 block size (16b) + aes256 key size (32b),
    // there's no need to process more than once (D_0).

    if(!count || !key || !iv)
        return 0;

    unsigned char buf[CSHA512::OUTPUT_SIZE];
    CSHA512 di;

    di.Write((const unsigned char*)strKeyData.data(), strKeyData.size());
    di.Write(chSalt.data(), chSalt.size());
    di.Finalize(buf);

    for(int i = 0; i != count - 1; i++)
        di.Reset().Write(buf, sizeof(buf)).Finalize(buf);

    memcpy(key, buf, WALLET_CRYPTO_KEY_SIZE);
    memcpy(iv, buf + WALLET_CRYPTO_KEY_SIZE, WALLET_CRYPTO_IV_SIZE);
    memory_cleanse(buf, sizeof(buf));
    return WALLET_CRYPTO_KEY_SIZE;
}

bool CCrypter::SetKeyFromPassphrase(const SecureString& strKeyData, const std::vector& chSalt, const unsigned int nRounds, const unsigned int nDerivationMethod)
{
    if (nRounds < 1 || chSalt.size() != WALLET_CRYPTO_SALT_SIZE)
        return false;

    int i = 0;
    if (nDerivationMethod == 0)
        i = BytesToKeySHA512AES(chSalt, strKeyData, nRounds, vchKey.data(), vchIV.data());

    if (i != (int)WALLET_CRYPTO_KEY_SIZE)
    {
        memory_cleanse(vchKey.data(), vchKey.size());
        memory_cleanse(vchIV.data(), vchIV.size());
        return false;
    }

    fKeySet = true;
    return true;
}

bool CCrypter::SetKey(const CKeyingMaterial& chNewKey, const std::vector& chNewIV)
{
    if (chNewKey.size() != WALLET_CRYPTO_KEY_SIZE || chNewIV.size() != WALLET_CRYPTO_IV_SIZE)
        return false;

    memcpy(vchKey.data(), chNewKey.data(), chNewKey.size());
    memcpy(vchIV.data(), chNewIV.data(), chNewIV.size());

    fKeySet = true;
    return true;
}

bool CCrypter::Encrypt(const CKeyingMaterial& vchPlaintext, std::vector &vchCiphertext) const
{
    if (!fKeySet)
        return false;

    // max ciphertext len for a n bytes of plaintext is
    // n + AES_BLOCKSIZE bytes
    vchCiphertext.resize(vchPlaintext.size() + AES_BLOCKSIZE);

    AES256CBCEncrypt enc(vchKey.data(), vchIV.data(), true);
    size_t nLen = enc.Encrypt(vchPlaintext.data(), vchPlaintext.size(), vchCiphertext.data());
    if(nLen < vchPlaintext.size())
        return false;
    vchCiphertext.resize(nLen);

    return true;
}

bool CCrypter::Decrypt(const std::vector& vchCiphertext, CKeyingMaterial& vchPlaintext) const
{
    if (!fKeySet)
        return false;

    // plaintext will always be equal to or lesser than length of ciphertext
    int nLen = vchCiphertext.size();

    vchPlaintext.resize(nLen);

    AES256CBCDecrypt dec(vchKey.data(), vchIV.data(), true);
    nLen = dec.Decrypt(vchCiphertext.data(), vchCiphertext.size(), vchPlaintext.data());
    if(nLen == 0)
        return false;
    vchPlaintext.resize(nLen);
    return true;
}

bool EncryptSecret(const CKeyingMaterial& vMasterKey, const CKeyingMaterial &vchPlaintext, const uint256& nIV, std::vector &vchCiphertext)
{
    CCrypter cKeyCrypter;
    std::vector chIV(WALLET_CRYPTO_IV_SIZE);
    memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
    if(!cKeyCrypter.SetKey(vMasterKey, chIV))
        return false;
    return cKeyCrypter.Encrypt(*((const CKeyingMaterial*)&vchPlaintext), vchCiphertext);
}

bool DecryptSecret(const CKeyingMaterial& vMasterKey, const std::vector& vchCiphertext, const uint256& nIV, CKeyingMaterial& vchPlaintext)
{
    CCrypter cKeyCrypter;
    std::vector chIV(WALLET_CRYPTO_IV_SIZE);
    memcpy(chIV.data(), &nIV, WALLET_CRYPTO_IV_SIZE);
    if(!cKeyCrypter.SetKey(vMasterKey, chIV))
        return false;
    return cKeyCrypter.Decrypt(vchCiphertext, vchPlaintext);
}

bool DecryptKey(const CKeyingMaterial& vMasterKey, const std::vector& vchCryptedSecret, const CPubKey& vchPubKey, CKey& key)
{
    CKeyingMaterial vchSecret;
    if(!DecryptSecret(vMasterKey, vchCryptedSecret, vchPubKey.GetHash(), vchSecret))
        return false;

    if (vchSecret.size() != 32)
        return false;

    key.Set(vchSecret.begin(), vchSecret.end(), vchPubKey.IsCompressed());
    return key.VerifyPubKey(vchPubKey);
}
legendary
Activity: 1568
Merit: 6660
bitcoincleanup.com / bitmixlist.org
June 14, 2021, 03:38:57 PM
#5
You must be referring to the wallet.dat hash of the password (and not the wallet's encrypted private keys, which do use AES-256-CBC), which looks similar to this:

Code:
BTC2014 $ bitcoin $ 64 $ 6a750G4ef1867cff00d941df3d1165c39164b4273aca3c7e57af5adf60183945 $ 16 $ 83c69fe19b89ab31 $ 81501 $ 2 $ 00 $ 2 $ 00

Hashing a password in a wallet.dat is done using PBKDF2, and the SHA512 is merely a hash function used on a chunk of data within the many HMAC functions invoked in the PBKDF2 hash. So, you are not looking for a SHA512 hash, you want the PBKDF2 hash, which looks like the one I quoted above.

This hash can be obtained using the script bitcoin2john.py which is available on Github at https://raw.githubusercontent.com/magnumripper/JohnTheRipper/bleeding-jumbo/run/bitcoin2john.py .
HCP
legendary
Activity: 2086
Merit: 4361
June 13, 2021, 04:03:17 PM
#4
You might want to have a read of this thread, starting from this post: https://bitcointalksearch.org/topic/recover-keys-from-walletdat-without-using-pywallet-5333765.msg56938441#msg56938441

I did some investigation into whether it was possible to "manually" extract and decrypt the master key (assuming you know the wallet passphrase) and then use that mkey to decrypt individual private keys from a wallet.dat. Posts further down that thread have links to scripts/code that will assist with extracting the mkey from a wallet.dat and then decrypting it... and then you can use the decrypted mkey to decrypt individual private keys.
newbie
Activity: 2
Merit: 0
June 13, 2021, 02:27:29 PM
#3
master key is then encrypted with AES-256-CBC with a key derived from the passphrase using SHA-512 and OpenSSL's EVP_BytesToKey and a dynamic number of rounds determined by the speed of the machine which does the initial encryption
member
Activity: 180
Merit: 38
June 13, 2021, 01:24:38 PM
#2
That is incorrect.
The keys are stored encrypted with AES-256-CBC and not SHA512.
So you can not extract a sha-512 from a wallet.
newbie
Activity: 2
Merit: 0
June 13, 2021, 01:21:22 PM
#1
Hi my friends .
I want to crack the bitcoin backup wallet.dat file  and access its private key. I went through good steps and I can say that if I can extract the sha-512  from the wallet.dat, you can easily crack all the wallets using the key and the IV that is in the sha-512.
Is it possible to extract sha-512 from a wallet.dat?
As you know, sha-512 is created in each wallet as follows.
sha-512 (nDerivations + salt + passphrase)
Can anyone help me how to extract this  encrypted code sha-512 of bitcoin wallet.dat file
Thank you all
Jump to: