During the security audit, we found a few potential risks of the current wallet format (version 1):
- The current KDF is double sha256, making brute force password searching quite low cost if an attacker managed to get
wallet.json
: only one Ed25519 key gen is needed per password. - Password hash is stored in
wallet.json
, further reduce brute force cost: just two sha256 are needed to test a password.
To eliminate these potential risks, we are proposing the next wallet format version (version 2), with the following changes to wallet.json
:
- Use scrypt as KDF instead of double sha256, and store scrypt parameters (salt, n, r, p) in
Scrypt
field. - Remove the following fields:
PasswordHash
,ProgramHash
,ContractData
. - Upgrade the value of
Version
to 2.
Algorithm change:
- The value of passwordKey is changed from
sha256(sha256(password))
toscrypt(salt, n, r, p, 32)
. Salt is a random byte array, encoded in hex format. The recommended (n, r, p) is (32768, 8, 1), and the recommended salt size is 8 bytes. - When verify whether a password is correct or not, one should decrypt the wallet, compute wallet address, and compare it with the
Address
field of wallet.json. A correct password should give you the correct address, otherwise the password is wrong.
A sample wallet.json
with password 123
:
{
"Version":2,
"IV":"ffa90ac9ea923af95da01500f43875b0",
"MasterKey":"232f695a7bce7b66855adc6191849c1f687b50341ad3d1aef554c721af22eb44",
"SeedEncrypted":"cbc6e1eac1d3e17fb3e19e60db70ff9dfca487d93b169bef0355bc306bc3ebbd",
"Address":"NKNV6H1RDx2Fc1iXMmCJN4hoxDdrfCDTPQPR",
"Scrypt":{
"Salt":"6551484dbb1a982a",
"N":32768,
"R":8,
"P":1
}
}
The SDK should still be able to parse and use v1 wallet format (based on Version
field), but newly generated wallet should use v2 format for better security.