keys: make NEP2Decrypt return a PrivateKey rather than WIF

There is no point in encoding the output of this function in a WIF format,
most of the users actually want the real key and those who need a WIF can
easily get if from the key (and it's simpler than getting the key from the
WIF).

It also fixes a severe bug in NEP2Decrypt, base58 decoding errors were not
processed correctly.
This commit is contained in:
Roman Khimov 2020-01-09 17:27:12 +03:00
parent 9a8f5c2a5d
commit b5b05a969c
4 changed files with 13 additions and 23 deletions

View file

@ -14,7 +14,6 @@ import (
"github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm/opcode" "github.com/CityOfZion/neo-go/pkg/vm/opcode"
"github.com/CityOfZion/neo-go/pkg/wallet"
"github.com/nspcc-dev/dbft" "github.com/nspcc-dev/dbft"
"github.com/nspcc-dev/dbft/block" "github.com/nspcc-dev/dbft/block"
"github.com/nspcc-dev/dbft/crypto" "github.com/nspcc-dev/dbft/crypto"
@ -178,16 +177,12 @@ func (s *service) validatePayload(p *Payload) bool {
} }
func getKeyPair(cfg *config.WalletConfig) (crypto.PrivateKey, crypto.PublicKey) { func getKeyPair(cfg *config.WalletConfig) (crypto.PrivateKey, crypto.PublicKey) {
acc, err := wallet.DecryptAccount(cfg.Path, cfg.Password) // TODO: replace with wallet opening from the given path (#588)
key, err := keys.NEP2Decrypt(cfg.Path, cfg.Password)
if err != nil { if err != nil {
return nil, nil return nil, nil
} }
key := acc.PrivateKey()
if key == nil {
return nil, nil
}
return &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()} return &privateKey{PrivateKey: key}, &publicKey{PublicKey: key.PublicKey()}
} }

View file

@ -77,13 +77,13 @@ func NEP2Encrypt(priv *PrivateKey, passphrase string) (s string, err error) {
// NEP2Decrypt decrypts an encrypted key using a given passphrase // NEP2Decrypt decrypts an encrypted key using a given passphrase
// under the NEP-2 standard. // under the NEP-2 standard.
func NEP2Decrypt(key, passphrase string) (s string, err error) { func NEP2Decrypt(key, passphrase string) (*PrivateKey, error) {
b, err := base58.CheckDecode(key) b, err := base58.CheckDecode(key)
if err != nil { if err != nil {
return s, nil return nil, err
} }
if err := validateNEP2Format(b); err != nil { if err := validateNEP2Format(b); err != nil {
return s, err return nil, err
} }
addrHash := b[3:7] addrHash := b[3:7]
@ -91,7 +91,7 @@ func NEP2Decrypt(key, passphrase string) (s string, err error) {
phraseNorm := norm.NFC.Bytes([]byte(passphrase)) phraseNorm := norm.NFC.Bytes([]byte(passphrase))
derivedKey, err := scrypt.Key(phraseNorm, addrHash, n, r, p, keyLen) derivedKey, err := scrypt.Key(phraseNorm, addrHash, n, r, p, keyLen)
if err != nil { if err != nil {
return s, err return nil, err
} }
derivedKey1 := derivedKey[:32] derivedKey1 := derivedKey[:32]
@ -100,7 +100,7 @@ func NEP2Decrypt(key, passphrase string) (s string, err error) {
decrypted, err := aesDecrypt(encryptedBytes, derivedKey2) decrypted, err := aesDecrypt(encryptedBytes, derivedKey2)
if err != nil { if err != nil {
return s, err return nil, err
} }
privBytes := xor(decrypted, derivedKey1) privBytes := xor(decrypted, derivedKey1)
@ -108,14 +108,14 @@ func NEP2Decrypt(key, passphrase string) (s string, err error) {
// Rebuild the private key. // Rebuild the private key.
privKey, err := NewPrivateKeyFromBytes(privBytes) privKey, err := NewPrivateKeyFromBytes(privBytes)
if err != nil { if err != nil {
return s, err return nil, err
} }
if !compareAddressHash(privKey, addrHash) { if !compareAddressHash(privKey, addrHash) {
return s, errors.New("password mismatch") return nil, errors.New("password mismatch")
} }
return privKey.WIF(), nil return privKey, nil
} }
func compareAddressHash(priv *PrivateKey, inhash []byte) bool { func compareAddressHash(priv *PrivateKey, inhash []byte) bool {

View file

@ -27,18 +27,13 @@ func TestNEP2Encrypt(t *testing.T) {
func TestNEP2Decrypt(t *testing.T) { func TestNEP2Decrypt(t *testing.T) {
for _, testCase := range keytestcases.Arr { for _, testCase := range keytestcases.Arr {
privKey, err := NEP2Decrypt(testCase.EncryptedWif, testCase.Passphrase)
privKeyString, err := NEP2Decrypt(testCase.EncryptedWif, testCase.Passphrase)
if testCase.Invalid { if testCase.Invalid {
assert.Error(t, err) assert.Error(t, err)
continue continue
} }
assert.Nil(t, err) assert.Nil(t, err)
privKey, err := NewPrivateKeyFromWIF(privKeyString)
assert.Nil(t, err)
assert.Equal(t, testCase.PrivateKey, privKey.String()) assert.Equal(t, testCase.PrivateKey, privKey.String())
wif := privKey.WIF() wif := privKey.WIF()

View file

@ -63,11 +63,11 @@ func NewAccount() (*Account, error) {
// DecryptAccount decrypts the encryptedWIF with the given passphrase and // DecryptAccount decrypts the encryptedWIF with the given passphrase and
// return the decrypted Account. // return the decrypted Account.
func DecryptAccount(encryptedWIF, passphrase string) (*Account, error) { func DecryptAccount(encryptedWIF, passphrase string) (*Account, error) {
wif, err := keys.NEP2Decrypt(encryptedWIF, passphrase) key, err := keys.NEP2Decrypt(encryptedWIF, passphrase)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return NewAccountFromWIF(wif) return newAccountFromPrivateKey(key), nil
} }
// Encrypt encrypts the wallet's PrivateKey with the given passphrase // Encrypt encrypts the wallet's PrivateKey with the given passphrase