crypto: allow to provide non-default scrypt parameters

This commit is contained in:
Anna Shaleva 2021-06-04 14:27:22 +03:00
parent 61dfca346c
commit 50296975e2
24 changed files with 59 additions and 58 deletions

View file

@ -744,7 +744,7 @@ func getAccFromContext(ctx *cli.Context) (*wallet.Account, *wallet.Wallet, error
return nil, nil, cli.NewExitError(err, 1)
}
pass := strings.TrimRight(string(rawPass), "\n")
err = acc.Decrypt(pass)
err = acc.Decrypt(pass, wall.Scrypt)
if err != nil {
return nil, nil, cli.NewExitError(err, 1)
}

View file

@ -50,9 +50,9 @@ func newWalletV2FromFile(path string) (*walletV2, error) {
const simpleSigLen = 35
func (a *accountV2) convert(pass string) (*wallet.Account, error) {
func (a *accountV2) convert(pass string, scrypt keys.ScryptParams) (*wallet.Account, error) {
address.Prefix = address.NEO2Prefix
priv, err := keys.NEP2Decrypt(a.EncryptedWIF, pass)
priv, err := keys.NEP2Decrypt(a.EncryptedWIF, pass, scrypt)
if err != nil {
return nil, err
}
@ -83,7 +83,7 @@ func (a *accountV2) convert(pass string) (*wallet.Account, error) {
newAcc.Default = a.Default
newAcc.Label = a.Label
newAcc.Locked = a.Locked
return newAcc, newAcc.Encrypt(pass)
return newAcc, newAcc.Encrypt(pass, scrypt)
}
const (

View file

@ -214,7 +214,7 @@ func getDecryptedAccount(ctx *cli.Context, wall *wallet.Wallet, addr util.Uint16
if pass, err := input.ReadPassword("Password > "); err != nil {
fmt.Println("ERROR", pass, err)
return nil, err
} else if err := acc.Decrypt(pass); err != nil {
} else if err := acc.Decrypt(pass, wall.Scrypt); err != nil {
return nil, err
}
return acc, nil

View file

@ -297,13 +297,14 @@ func convertWallet(ctx *cli.Context) error {
return cli.NewExitError(err, 1)
}
defer newWallet.Close()
newWallet.Scrypt = wall.Scrypt
for _, acc := range wall.Accounts {
pass, err := input.ReadPassword(fmt.Sprintf("Enter passphrase for account %s (label '%s') > ", acc.Address, acc.Label))
if err != nil {
return cli.NewExitError(err, 1)
}
newAcc, err := acc.convert(pass)
newAcc, err := acc.convert(pass, wall.Scrypt)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -374,7 +375,7 @@ loop:
return cli.NewExitError(err, 1)
}
pk, err := keys.NEP2Decrypt(wif, pass)
pk, err := keys.NEP2Decrypt(wif, pass, wall.Scrypt)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -411,7 +412,7 @@ func importMultisig(ctx *cli.Context) error {
}
}
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"))
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -443,7 +444,7 @@ func importDeployed(ctx *cli.Context) error {
return cli.NewExitError("contract hash was not provided", 1)
}
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"))
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -492,7 +493,7 @@ func importWallet(ctx *cli.Context) error {
}
defer wall.Close()
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"))
acc, err := newAccountFromWIF(ctx.App.Writer, ctx.String("wif"), wall.Scrypt)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -570,7 +571,7 @@ func dumpWallet(ctx *cli.Context) error {
}
for i := range wall.Accounts {
// Just testing the decryption here.
err := wall.Accounts[i].Decrypt(pass)
err := wall.Accounts[i].Decrypt(pass, wall.Scrypt)
if err != nil {
return cli.NewExitError(err, 1)
}
@ -685,7 +686,7 @@ func openWallet(path string) (*wallet.Wallet, error) {
return wallet.NewWalletFromFile(path)
}
func newAccountFromWIF(w io.Writer, wif string) (*wallet.Account, error) {
func newAccountFromWIF(w io.Writer, wif string, scrypt keys.ScryptParams) (*wallet.Account, error) {
// note: NEP2 strings always have length of 58 even though
// base58 strings can have different lengths even if slice lengths are equal
if len(wif) == 58 {
@ -694,7 +695,7 @@ func newAccountFromWIF(w io.Writer, wif string) (*wallet.Account, error) {
return nil, err
}
return wallet.NewAccountFromEncryptedWIF(wif, pass)
return wallet.NewAccountFromEncryptedWIF(wif, pass, scrypt)
}
acc, err := wallet.NewAccountFromWIF(wif)
@ -709,7 +710,7 @@ func newAccountFromWIF(w io.Writer, wif string) (*wallet.Account, error) {
}
acc.Label = name
if err := acc.Encrypt(pass); err != nil {
if err := acc.Encrypt(pass, scrypt); err != nil {
return nil, err
}

View file

@ -48,7 +48,7 @@ func TestWalletInit(t *testing.T) {
require.NoError(t, err)
require.Len(t, w.Accounts, 1)
require.Equal(t, "букandmore", w.Accounts[0].Label)
require.NoError(t, w.Accounts[0].Decrypt("пароль"))
require.NoError(t, w.Accounts[0].Decrypt("пароль", w.Scrypt))
w.Close()
})
@ -62,7 +62,7 @@ func TestWalletInit(t *testing.T) {
require.NoError(t, err)
require.Len(t, w.Accounts, 1)
require.Equal(t, w.Accounts[0].Label, "testname")
require.NoError(t, w.Accounts[0].Decrypt("testpass"))
require.NoError(t, w.Accounts[0].Decrypt("testpass", w.Scrypt))
w.Close()
t.Run("RemoveAccount", func(t *testing.T) {
@ -94,7 +94,7 @@ func TestWalletInit(t *testing.T) {
acc := w.GetAccount(priv.GetScriptHash())
require.NotNil(t, acc)
require.Equal(t, "test_account", acc.Label)
require.NoError(t, acc.Decrypt("qwerty"))
require.NoError(t, acc.Decrypt("qwerty", w.Scrypt))
t.Run("AlreadyExists", func(t *testing.T) {
e.In.WriteString("test_account_2\r")
@ -107,7 +107,7 @@ func TestWalletInit(t *testing.T) {
t.Run("EncryptedWIF", func(t *testing.T) {
acc, err := wallet.NewAccount()
require.NoError(t, err)
require.NoError(t, acc.Encrypt("somepass"))
require.NoError(t, acc.Encrypt("somepass", keys.NEP2ScryptParams()))
t.Run("InvalidPassword", func(t *testing.T) {
e.In.WriteString("password1\r")
@ -124,7 +124,7 @@ func TestWalletInit(t *testing.T) {
t.Cleanup(w.Close)
actual := w.GetAccount(acc.PrivateKey().GetScriptHash())
require.NotNil(t, actual)
require.NoError(t, actual.Decrypt("somepass"))
require.NoError(t, actual.Decrypt("somepass", w.Scrypt))
})
t.Run("Multisig", func(t *testing.T) {
privs, pubs := generateKeys(t, 4)
@ -160,7 +160,7 @@ func TestWalletInit(t *testing.T) {
t.Cleanup(w.Close)
actual := w.GetAccount(hash.Hash160(script))
require.NotNil(t, actual)
require.NoError(t, actual.Decrypt("multipass"))
require.NoError(t, actual.Decrypt("multipass", w.Scrypt))
require.Equal(t, script, actual.Contract.Script)
})
})
@ -174,7 +174,7 @@ func TestWalletExport(t *testing.T) {
"--wallet", validatorWallet, validatorAddr)
line, err := e.Out.ReadString('\n')
require.NoError(t, err)
enc, err := keys.NEP2Encrypt(validatorPriv, "one")
enc, err := keys.NEP2Encrypt(validatorPriv, "one", keys.NEP2ScryptParams())
require.NoError(t, err)
require.Equal(t, enc, strings.TrimSpace(line))
})

View file

@ -142,7 +142,7 @@ func NewService(cfg Config) (Service, error) {
// Check that wallet password is correct for at least one account.
var ok bool
for _, acc := range srv.wallet.Accounts {
err := acc.Decrypt(srv.Config.Wallet.Password)
err := acc.Decrypt(srv.Config.Wallet.Password, srv.wallet.Scrypt)
if err == nil {
ok = true
break
@ -345,7 +345,7 @@ func (s *service) getKeyPair(pubs []crypto.PublicKey) (int, crypto.PrivateKey, c
key := acc.PrivateKey()
if acc.PrivateKey() == nil {
err := acc.Decrypt(s.Config.Wallet.Password)
err := acc.Decrypt(s.Config.Wallet.Password, s.wallet.Scrypt)
if err != nil {
s.log.Fatal("can't unlock account", zap.String("address", address.Uint160ToString(sh)))
break

View file

@ -449,7 +449,7 @@ func initBasicChain(t *testing.T, bc *Blockchain) {
// Designate new Notary node
ntr, err := wallet.NewWalletFromFile(path.Join(notaryModulePath, "./testdata/notary1.json"))
require.NoError(t, err)
require.NoError(t, ntr.Accounts[0].Decrypt("one"))
require.NoError(t, ntr.Accounts[0].Decrypt("one", ntr.Scrypt))
bc.setNodesByRole(t, true, noderoles.P2PNotary, keys.PublicKeys{ntr.Accounts[0].PrivateKey().PublicKey()})
t.Logf("Designated Notary node: %s", hex.EncodeToString(ntr.Accounts[0].PrivateKey().PublicKey().Bytes()))

View file

@ -52,7 +52,7 @@ func getTestNotary(t *testing.T, bc *Blockchain, walletPath, pass string, onTx f
w, err := wallet.NewWalletFromFile(path.Join(notaryModulePath, walletPath))
require.NoError(t, err)
require.NoError(t, w.Accounts[0].Decrypt(pass))
require.NoError(t, w.Accounts[0].Decrypt(pass, w.Scrypt))
return w.Accounts[0], ntr, mp
}

View file

@ -66,7 +66,7 @@ func getTestOracle(t *testing.T, bc *Blockchain, walletPath, pass string) (
w, err := wallet.NewWalletFromFile(path.Join(oracleModulePath, walletPath))
require.NoError(t, err)
require.NoError(t, w.Accounts[0].Decrypt(pass))
require.NoError(t, w.Accounts[0].Decrypt(pass, w.Scrypt))
return w.Accounts[0], orc, m, ch
}

View file

@ -172,7 +172,7 @@ func TestStateRootInitNonZeroHeight(t *testing.T) {
func createAndWriteWallet(t *testing.T, acc *wallet.Account, path, password string) *wallet.Wallet {
w, err := wallet.NewWallet(path)
require.NoError(t, err)
require.NoError(t, acc.Encrypt(password))
require.NoError(t, acc.Encrypt(password, w.Scrypt))
w.AddAccount(acc)
require.NoError(t, w.Save())
w.Close()

View file

@ -42,13 +42,13 @@ func NEP2ScryptParams() ScryptParams {
// NEP2Encrypt encrypts a the PrivateKey using a given passphrase
// under the NEP-2 standard.
func NEP2Encrypt(priv *PrivateKey, passphrase string) (s string, err error) {
func NEP2Encrypt(priv *PrivateKey, passphrase string, params ScryptParams) (s string, err error) {
address := priv.Address()
addrHash := hash.Checksum([]byte(address))
// Normalize the passphrase according to the NFC standard.
phraseNorm := norm.NFC.Bytes([]byte(passphrase))
derivedKey, err := scrypt.Key(phraseNorm, addrHash, n, r, p, keyLen)
derivedKey, err := scrypt.Key(phraseNorm, addrHash, params.N, params.R, params.P, keyLen)
if err != nil {
return s, err
}
@ -77,7 +77,7 @@ func NEP2Encrypt(priv *PrivateKey, passphrase string) (s string, err error) {
// NEP2Decrypt decrypts an encrypted key using a given passphrase
// under the NEP-2 standard.
func NEP2Decrypt(key, passphrase string) (*PrivateKey, error) {
func NEP2Decrypt(key, passphrase string, params ScryptParams) (*PrivateKey, error) {
b, err := base58.CheckDecode(key)
if err != nil {
return nil, err
@ -89,7 +89,7 @@ func NEP2Decrypt(key, passphrase string) (*PrivateKey, error) {
addrHash := b[3:7]
// Normalize the passphrase according to the NFC standard.
phraseNorm := norm.NFC.Bytes([]byte(passphrase))
derivedKey, err := scrypt.Key(phraseNorm, addrHash, n, r, p, keyLen)
derivedKey, err := scrypt.Key(phraseNorm, addrHash, params.N, params.R, params.P, keyLen)
if err != nil {
return nil, err
}

View file

@ -17,7 +17,7 @@ func TestNEP2Encrypt(t *testing.T) {
assert.Nil(t, err)
encryptedWif, err := NEP2Encrypt(privKey, testCase.Passphrase)
encryptedWif, err := NEP2Encrypt(privKey, testCase.Passphrase, NEP2ScryptParams())
assert.Nil(t, err)
assert.Equal(t, testCase.EncryptedWif, encryptedWif)
@ -26,7 +26,7 @@ func TestNEP2Encrypt(t *testing.T) {
func TestNEP2Decrypt(t *testing.T) {
for _, testCase := range keytestcases.Arr {
privKey, err := NEP2Decrypt(testCase.EncryptedWif, testCase.Passphrase)
privKey, err := NEP2Decrypt(testCase.EncryptedWif, testCase.Passphrase, NEP2ScryptParams())
if testCase.Invalid {
assert.Error(t, err)
continue
@ -48,12 +48,12 @@ func TestNEP2DecryptErrors(t *testing.T) {
// Not a base58-encoded value
s := "qazwsx"
_, err := NEP2Decrypt(s, p)
_, err := NEP2Decrypt(s, p, NEP2ScryptParams())
assert.Error(t, err)
// Valid base58, but not a NEP-2 format.
s = "KxhEDBQyyEFymvfJD96q8stMbJMbZUb6D1PmXqBWZDU2WvbvVs9o"
_, err = NEP2Decrypt(s, p)
_, err = NEP2Decrypt(s, p, NEP2ScryptParams())
assert.Error(t, err)
}

View file

@ -621,7 +621,7 @@ func TestSignAndPushP2PNotaryRequest(t *testing.T) {
w, err := wallet.NewWalletFromFile(notaryPath)
require.NoError(t, err)
ntr := w.Accounts[0]
err = ntr.Decrypt(notaryPass)
err = ntr.Decrypt(notaryPass, w.Scrypt)
require.NoError(t, err)
req.FallbackTransaction.Scripts[0] = transaction.Witness{
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, ntr.PrivateKey().SignHashable(uint32(testchain.Network()), req.FallbackTransaction)...),

View file

@ -28,7 +28,7 @@ func (n *Notary) UpdateNotaryNodes(notaryNodes keys.PublicKeys) {
if acc.PrivateKey() != nil {
break
}
err := acc.Decrypt(n.Config.MainCfg.UnlockWallet.Password)
err := acc.Decrypt(n.Config.MainCfg.UnlockWallet.Password, n.wallet.Scrypt)
if err != nil {
n.Config.Log.Warn("can't unlock notary node account",
zap.String("address", address.Uint160ToString(acc.Contract.ScriptHash())),

View file

@ -33,7 +33,7 @@ func getTestNotary(t *testing.T, bc blockchainer.Blockchainer, walletPath, pass
w, err := wallet.NewWalletFromFile(walletPath)
require.NoError(t, err)
require.NoError(t, w.Accounts[0].Decrypt(pass))
require.NoError(t, w.Accounts[0].Decrypt(pass, w.Scrypt))
return w.Accounts[0], ntr, mp
}
@ -57,14 +57,14 @@ func TestUpdateNotaryNodes(t *testing.T) {
t.Run("good config password", func(t *testing.T) {
w, err := wallet.NewWalletFromFile("./testdata/notary1.json")
require.NoError(t, err)
require.NoError(t, w.Accounts[1].Decrypt("one"))
require.NoError(t, w.Accounts[1].Decrypt("one", w.Scrypt))
ntr.UpdateNotaryNodes(keys.PublicKeys{w.Accounts[1].PrivateKey().PublicKey()})
require.Equal(t, w.Accounts[1], ntr.currAccount)
})
t.Run("bad config password", func(t *testing.T) {
w, err := wallet.NewWalletFromFile("./testdata/notary1.json")
require.NoError(t, err)
require.NoError(t, w.Accounts[2].Decrypt("four"))
require.NoError(t, w.Accounts[2].Decrypt("four", w.Scrypt))
ntr.UpdateNotaryNodes(keys.PublicKeys{w.Accounts[2].PrivateKey().PublicKey()})
require.Nil(t, ntr.currAccount)
})

View file

@ -94,7 +94,7 @@ func NewNotary(cfg Config, net netmode.Magic, mp *mempool.Pool, onTransaction fu
haveAccount := false
for _, acc := range wallet.Accounts {
if err := acc.Decrypt(w.Password); err == nil {
if err := acc.Decrypt(w.Password, wallet.Scrypt); err == nil {
haveAccount = true
break
}

View file

@ -33,7 +33,7 @@ func (o *Oracle) UpdateOracleNodes(oracleNodes keys.PublicKeys) {
if acc.PrivateKey() != nil {
break
}
err := acc.Decrypt(o.MainCfg.UnlockWallet.Password)
err := acc.Decrypt(o.MainCfg.UnlockWallet.Password, o.wallet.Scrypt)
if err != nil {
o.Log.Error("can't unlock account",
zap.String("address", address.Uint160ToString(acc.Contract.ScriptHash())),

View file

@ -130,7 +130,7 @@ func NewOracle(cfg Config) (*Oracle, error) {
haveAccount := false
for _, acc := range o.wallet.Accounts {
if err := acc.Decrypt(w.Password); err == nil {
if err := acc.Decrypt(w.Password, o.wallet.Scrypt); err == nil {
haveAccount = true
break
}

View file

@ -85,7 +85,7 @@ func New(cfg config.StateRoot, log *zap.Logger, bc blockchainer.Blockchainer, cb
haveAccount := false
for _, acc := range s.wallet.Accounts {
if err := acc.Decrypt(w.Password); err == nil {
if err := acc.Decrypt(w.Password, s.wallet.Scrypt); err == nil {
haveAccount = true
break
}
@ -141,7 +141,7 @@ func (s *service) updateValidators(height uint32, pubs keys.PublicKeys) {
s.acc = nil
for i := range pubs {
if acc := s.wallet.GetAccount(pubs[i].GetScriptHash()); acc != nil {
err := acc.Decrypt(s.MainCfg.UnlockWallet.Password)
err := acc.Decrypt(s.MainCfg.UnlockWallet.Password, s.wallet.Scrypt)
if err == nil {
s.acc = acc
s.accHeight = height

View file

@ -119,13 +119,13 @@ func (a *Account) GetVerificationScript() []byte {
// Decrypt decrypts the EncryptedWIF with the given passphrase returning error
// if anything goes wrong.
func (a *Account) Decrypt(passphrase string) error {
func (a *Account) Decrypt(passphrase string, scrypt keys.ScryptParams) error {
var err error
if a.EncryptedWIF == "" {
return errors.New("no encrypted wif in the account")
}
a.privateKey, err = keys.NEP2Decrypt(a.EncryptedWIF, passphrase)
a.privateKey, err = keys.NEP2Decrypt(a.EncryptedWIF, passphrase, scrypt)
if err != nil {
return err
}
@ -138,8 +138,8 @@ func (a *Account) Decrypt(passphrase string) error {
// Encrypt encrypts the wallet's PrivateKey with the given passphrase
// under the NEP-2 standard.
func (a *Account) Encrypt(passphrase string) error {
wif, err := keys.NEP2Encrypt(a.privateKey, passphrase)
func (a *Account) Encrypt(passphrase string, scrypt keys.ScryptParams) error {
wif, err := keys.NEP2Encrypt(a.privateKey, passphrase, scrypt)
if err != nil {
return err
}
@ -162,8 +162,8 @@ func NewAccountFromWIF(wif string) (*Account, error) {
}
// NewAccountFromEncryptedWIF creates a new Account from the given encrypted WIF.
func NewAccountFromEncryptedWIF(wif string, pass string) (*Account, error) {
priv, err := keys.NEP2Decrypt(wif, pass)
func NewAccountFromEncryptedWIF(wif string, pass string, scrypt keys.ScryptParams) (*Account, error) {
priv, err := keys.NEP2Decrypt(wif, pass, scrypt)
if err != nil {
return nil, err
}

View file

@ -22,7 +22,7 @@ func TestDecryptAccount(t *testing.T) {
for _, testCase := range keytestcases.Arr {
acc := &Account{EncryptedWIF: testCase.EncryptedWif}
assert.Nil(t, acc.PrivateKey())
err := acc.Decrypt(testCase.Passphrase)
err := acc.Decrypt(testCase.Passphrase, keys.NEP2ScryptParams())
if testCase.Invalid {
assert.Error(t, err)
continue
@ -34,7 +34,7 @@ func TestDecryptAccount(t *testing.T) {
}
// No encrypted key.
acc := &Account{}
require.Error(t, acc.Decrypt("qwerty"))
require.Error(t, acc.Decrypt("qwerty", keys.NEP2ScryptParams()))
}
func TestNewFromWif(t *testing.T) {
@ -52,7 +52,7 @@ func TestNewFromWif(t *testing.T) {
func TestNewAccountFromEncryptedWIF(t *testing.T) {
for _, tc := range keytestcases.Arr {
acc, err := NewAccountFromEncryptedWIF(tc.EncryptedWif, tc.Passphrase)
acc, err := NewAccountFromEncryptedWIF(tc.EncryptedWif, tc.Passphrase, keys.NEP2ScryptParams())
if tc.Invalid {
assert.Error(t, err)
continue

View file

@ -39,7 +39,7 @@ func getKeys(t *testing.T) []*keys.PublicKey {
func getAccount(t *testing.T, wif, pass string) *Account {
acc, err := NewAccountFromWIF(wif)
require.NoError(t, err)
require.NoError(t, acc.Encrypt(pass))
require.NoError(t, acc.Encrypt(pass, keys.NEP2ScryptParams()))
return acc
}

View file

@ -92,7 +92,7 @@ func (w *Wallet) CreateAccount(name, passphrase string) error {
return err
}
acc.Label = name
if err := acc.Encrypt(passphrase); err != nil {
if err := acc.Encrypt(passphrase, w.Scrypt); err != nil {
return err
}
w.AddAccount(acc)

View file

@ -108,7 +108,7 @@ func TestSave(t *testing.T) {
w2, err := NewWalletFromFile(openedWallet.path)
require.NoError(t, err)
require.Equal(t, 2, len(w2.Accounts))
require.NoError(t, w2.Accounts[1].Decrypt("pass"))
require.NoError(t, w2.Accounts[1].Decrypt("pass", w2.Scrypt))
require.Equal(t, openedWallet.Accounts, w2.Accounts)
})
}
@ -207,7 +207,7 @@ func TestWalletForExamples(t *testing.T) {
require.NoError(t, err)
require.Equal(t, 1, len(w.Accounts))
require.Equal(t, accountLabel, w.Accounts[0].Label)
require.NoError(t, w.Accounts[0].Decrypt(walletPass))
require.NoError(t, w.Accounts[0].Decrypt(walletPass, w.Scrypt))
// we need to keep the owner of the example contracts the same as the wallet account
require.Equal(t, "NbrUYaZgyhSkNoRo9ugRyEMdUZxrhkNaWB", w.Accounts[0].Address, "need to change `owner` in the example contracts")