The typical brain wallet is constructed by hashing a memorable phrase using SHA-256, and using the result as the private key. It is well-established that the typical brain wallet is not secure. This thread demonstrates that very clearly:
Collection of 18.509 found and used Brainwallets
Here is a good example from that thread showing that even a seemingly good brain wallet phrase can be cracked:
The basic attack against brain wallets involves generating a huge list of potential phrases, and then checking the blockchain for the addresses derived from the hashes of those phrases. The defenses against this attack are to increase the range of potential phrases and to make it slower and more expensive to check them.
The cracked brain wallet above demonstrates to me that the benefit of increasing the potential range is limited. That is basically because a human's ability to create meaningful and memorable phrases is limited. For this reason, we have to accept that although a carefully chosen phrase is important, it is not sufficient, and it is also necessary to make it slower and more expensive to check the hashes of potential phrases.
The issue with SHA-256 is that it is very fast, and it is easy for the attacker to generate the private keys for a large number of potential brain wallets. A typical PC can generate up to a billion SHA-256 hashes every second. SHA-256 is not appropriate for hashing brain wallet phrases (or any kind of passwords).
Now, there are certain hashing algorithms specifically designed to resist attacks on hashed passwords: bcrypt, scrypt, and argon2id, for example. They have these advantages:
My question for the experts: would switching to an appropriate hash algorithm such as the ones listed above be enough to make a brain wallet secure?
Collection of 18.509 found and used Brainwallets
Here is a good example from that thread showing that even a seemingly good brain wallet phrase can be cracked:
... "To the moon!!! ┗(°0°)┛ ..○" -> https://www.blockchain.com/btc/address/18vqVNQi9fobKZcJWCjZNoDzBxronENfZr
The basic attack against brain wallets involves generating a huge list of potential phrases, and then checking the blockchain for the addresses derived from the hashes of those phrases. The defenses against this attack are to increase the range of potential phrases and to make it slower and more expensive to check them.
The cracked brain wallet above demonstrates to me that the benefit of increasing the potential range is limited. That is basically because a human's ability to create meaningful and memorable phrases is limited. For this reason, we have to accept that although a carefully chosen phrase is important, it is not sufficient, and it is also necessary to make it slower and more expensive to check the hashes of potential phrases.
The issue with SHA-256 is that it is very fast, and it is easy for the attacker to generate the private keys for a large number of potential brain wallets. A typical PC can generate up to a billion SHA-256 hashes every second. SHA-256 is not appropriate for hashing brain wallet phrases (or any kind of passwords).
Now, there are certain hashing algorithms specifically designed to resist attacks on hashed passwords: bcrypt, scrypt, and argon2id, for example. They have these advantages:
- They are much slower than SHA-256. For example, Litecoin's configuration of scrypt is about 1000 times slower than SHA-256.
- They require much more memory, which limits the parallelization.
- They also generally include a "salt" parameter that limits the ability to use pre-generated hash tables.
My question for the experts: would switching to an appropriate hash algorithm such as the ones listed above be enough to make a brain wallet secure?
Why limit yourself to one hash function???
You could switch between different hash functions in the same algorithm.
Something like this
Code:
for i in range (10000):
if int(str[-1:], 16) == 0: hash = hashlib.sha256(str.encode())
elif int(str[-1:], 16) == 1: hash = hashlib.sha3_256(str.encode())
elif int(str[-1:], 16) == 2: hash = hashlib.blake2s256(str.encode())
elif int(str[-1:], 16) == 3: hash = hashlib.sha512(str.encode())
# and so on ...
str = hash.hexdigest()
The hashing function for the next hash depends on the result of the previous hash
This prevents the prehashed tables attacks against your brain wallet
The algorithm is now part of the entropy of the passphrase and if you keep it secret you can use easier to remember seeds to feed the algo