From 1205af0ac0ea196adbbbd324d979d393d2b49c39 Mon Sep 17 00:00:00 2001 From: andrei Date: Wed, 17 Apr 2019 12:37:13 +0900 Subject: [PATCH 1/2] NEP2 directly to wallet to avoid double decryption This will allow going directly from NEP2 to wallet object. If only return Wif have to recall NeoutilsGenerateFrom Wif, which redoes the private key derivation which is costly operation. This should cut time of all wallet switching operations in half --- neoutils/nep2/nep2.go | 48 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/neoutils/nep2/nep2.go b/neoutils/nep2/nep2.go index 1f3940a..b2a3601 100644 --- a/neoutils/nep2/nep2.go +++ b/neoutils/nep2/nep2.go @@ -126,6 +126,54 @@ func NEP2Decrypt(key, passphrase string) (s string, err error) { return privKey.ToWIFC(), nil } +func NEP2DecryptToWallet(key, passphrase string) (*Wallet, err error) { + encrypted, err := crypto.Base58CheckDecode(key) + if err != nil { + return s, nil + } + if err := validateNEP2Format(encrypted); err != nil { + return s, err + } + + addrHash := encrypted[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) + if err != nil { + return s, err + } + + derivedKey1 := derivedKey[:32] + derivedKey2 := derivedKey[32:] + encryptedBytes := encrypted[7:] + + decrypted, err := crypto.AESDecrypt(encryptedBytes, derivedKey2) + if err != nil { + return s, err + } + privBytes := xor(decrypted, derivedKey1) + // Rebuild the private key. + var privKey btckey.PrivateKey + err = privKey.FromBytes(privBytes) + if err != nil { + return s, err + } + + if !compareAddressHash(&privKey, addrHash) { + return s, errors.New("password mismatch") + } + + wallet := &Wallet{ + PublicKey: privKey.PublicKey.ToBytes(), + PrivateKey: privKey.ToBytes(), + Address: privKey.ToNeoAddress(), + WIF: privKey.ToWIFC(), + HashedSignature: privKey.ToNeoSignature(), + } + return wallet, nil +} + func compareAddressHash(priv *btckey.PrivateKey, hash []byte) bool { address := priv.ToNeoAddress() addrHash := hashAddress(address)[0:4] From a60fd09f7b425e8e28569f05b404172b7c1dabae Mon Sep 17 00:00:00 2001 From: Apisit Toompakdee Date: Wed, 17 Apr 2019 13:14:51 +0900 Subject: [PATCH 2/2] nep2 to wallet --- neoutils/nep2.go | 15 +++++++++++++++ neoutils/nep2/nep2.go | 23 ++++++++--------------- neoutils/nep2/nep2_test.go | 17 ++++++++++++++--- neoutils/nep2_test.go | 20 ++++++++++++++++++++ neoutils/serializer_test.go | 23 ----------------------- 5 files changed, 57 insertions(+), 41 deletions(-) create mode 100644 neoutils/nep2_test.go diff --git a/neoutils/nep2.go b/neoutils/nep2.go index 6e2a69b..413135b 100644 --- a/neoutils/nep2.go +++ b/neoutils/nep2.go @@ -18,3 +18,18 @@ func NEP2Encrypt(wif string, passphrase string) (*NEP2, error) { func NEP2Decrypt(key, passphrase string) (s string, err error) { return nep2.NEP2Decrypt(key, passphrase) } + +func NEP2DecryptToWallet(key, passphrase string) (*Wallet, error) { + priv, err := nep2.NEP2DecryptToPrivateKey(key, passphrase) + if err != nil { + return nil, err + } + wallet := &Wallet{ + PublicKey: priv.PublicKey.ToBytes(), + PrivateKey: priv.ToBytes(), + Address: priv.ToNeoAddress(), + WIF: priv.ToWIFC(), + HashedSignature: priv.ToNeoSignature(), + } + return wallet, nil +} diff --git a/neoutils/nep2/nep2.go b/neoutils/nep2/nep2.go index b2a3601..c641913 100644 --- a/neoutils/nep2/nep2.go +++ b/neoutils/nep2/nep2.go @@ -126,13 +126,13 @@ func NEP2Decrypt(key, passphrase string) (s string, err error) { return privKey.ToWIFC(), nil } -func NEP2DecryptToWallet(key, passphrase string) (*Wallet, err error) { +func NEP2DecryptToPrivateKey(key, passphrase string) (pk btckey.PrivateKey, err error) { encrypted, err := crypto.Base58CheckDecode(key) if err != nil { - return s, nil + return pk, err } if err := validateNEP2Format(encrypted); err != nil { - return s, err + return pk, err } addrHash := encrypted[3:7] @@ -141,7 +141,7 @@ func NEP2DecryptToWallet(key, passphrase string) (*Wallet, err error) { phraseNorm := norm.NFC.Bytes([]byte(passphrase)) derivedKey, err := scrypt.Key(phraseNorm, addrHash, n, r, p, keyLen) if err != nil { - return s, err + return pk, err } derivedKey1 := derivedKey[:32] @@ -150,28 +150,21 @@ func NEP2DecryptToWallet(key, passphrase string) (*Wallet, err error) { decrypted, err := crypto.AESDecrypt(encryptedBytes, derivedKey2) if err != nil { - return s, err + return pk, err } privBytes := xor(decrypted, derivedKey1) // Rebuild the private key. var privKey btckey.PrivateKey err = privKey.FromBytes(privBytes) if err != nil { - return s, err + return pk, err } if !compareAddressHash(&privKey, addrHash) { - return s, errors.New("password mismatch") + return pk, errors.New("password mismatch") } - wallet := &Wallet{ - PublicKey: privKey.PublicKey.ToBytes(), - PrivateKey: privKey.ToBytes(), - Address: privKey.ToNeoAddress(), - WIF: privKey.ToWIFC(), - HashedSignature: privKey.ToNeoSignature(), - } - return wallet, nil + return privKey, nil } func compareAddressHash(priv *btckey.PrivateKey, hash []byte) bool { diff --git a/neoutils/nep2/nep2_test.go b/neoutils/nep2/nep2_test.go index 0a5725a..390a12c 100644 --- a/neoutils/nep2/nep2_test.go +++ b/neoutils/nep2/nep2_test.go @@ -7,14 +7,25 @@ import ( "github.com/o3labs/neo-utils/neoutils/nep2" ) +func TestNEP2DecryptToWallet(t *testing.T) { + encrypted := "6PYVPVe1fQznphjbUxXP9KZJqPMVnVwCx5s5pr5axRJ8uHkMtZg97eT5kL" + passphrase := "TestingOneTwoThree" + p, err := nep2.NEP2DecryptToPrivateKey(encrypted, passphrase) + if err != nil { + log.Printf("%v", err) + return + } + log.Printf("%+v", p) +} + func TestNEP2(t *testing.T) { - passphase := "TestingOneTwoThree" + passphrase := "TestingOneTwoThree" WIF := "L44B5gGEpqEDRS9vVPz7QT35jcBG2r3CZwSwQ4fCewXAhAhqGVpP" //AStZHy8E6StCqYQbzMqi4poH7YNDHQKxvt expectedEncrypted := "6PYVPVe1fQznphjbUxXP9KZJqPMVnVwCx5s5pr5axRJ8uHkMtZg97eT5kL" // expctedUnencryptedHex := "CBF4B9F70470856BB4F40F80B87EDB90865997FFEE6DF315AB166D713AF433A5" - encrypted, address, err := nep2.NEP2Encrypt(WIF, passphase) + encrypted, address, err := nep2.NEP2Encrypt(WIF, passphrase) if err != nil { log.Printf("err %v", err) return @@ -27,7 +38,7 @@ func TestNEP2(t *testing.T) { return } - decrypted, err := nep2.NEP2Decrypt(encrypted, passphase) + decrypted, err := nep2.NEP2Decrypt(encrypted, passphrase) if err != nil { log.Printf("err %v", err) return diff --git a/neoutils/nep2_test.go b/neoutils/nep2_test.go new file mode 100644 index 0000000..b7dbea7 --- /dev/null +++ b/neoutils/nep2_test.go @@ -0,0 +1,20 @@ +package neoutils_test + +import ( + "log" + "testing" + + "github.com/o3labs/neo-utils/neoutils" +) + +func TestNEP2ToWallet(t *testing.T) { + encrypted := "6PYVPVe1fQznphjbUxXP9KZJqPMVnVwCx5s5pr5axRJ8uHkMtZg97eT5kL" + passphrase := "TestingOneTwoThree" + + w, err := neoutils.NEP2DecryptToWallet(encrypted, passphrase) + if err != nil { + log.Printf("%v", err) + return + } + log.Printf("%v", w) +} diff --git a/neoutils/serializer_test.go b/neoutils/serializer_test.go index 50d9e4e..4f41e85 100644 --- a/neoutils/serializer_test.go +++ b/neoutils/serializer_test.go @@ -1,24 +1 @@ package neoutils_test - -import ( - "encoding/json" - "log" - "testing" - - "github.com/o3labs/neo-utils/neoutils" -) - -func TestSerialize(t *testing.T) { - - data := ` -{"sha256":"accb0534cb4c4d9b8594189d31e759ab96ae7488dc90e52a443b44bb2e2b2493","hash":"ef249c579898e3adaee6f4c5df8117cc08b8a2832bdd5978beeb859cef6620c9","inputs":[{"prevIndex":0,"prevHash":"3a963116b572a466819c05bee74782902a51fd9b83be99f25d9edc5b7891049a"},{"prevIndex":18,"prevHash":"b7e77a70481edc1d5156a182d358aac53da51b9f1653683ae7bcb811b779c759"}],"outputs":[{"assetId":"602c79718b16e442de58778e148d0b1084e3b2dffd5de6b7b16cee7969282de7","scriptHash":"e707714512577b42f9a011f8b870625429f93573","value":1e-08}],"script":"0800ca9a3b000000001432e125258b7db0a0dffde5bd03b2b859253538ab144d2c053c1a5911be6253b3cc1a68397feb3f647053c1076465706f73697467823b63e7c70a795a7615a38d1ba67d9e54c195a1","version":1,"type":209,"attributes":[{"usage":32,"data":"4d2c053c1a5911be6253b3cc1a68397feb3f6470"}],"scripts":[],"gas":0} -` - tx := neoutils.NeonJSTransaction{} - json.Unmarshal([]byte(data), &tx) - - final := neoutils.NeonJSTXSerializer(tx) - log.Printf("%x", final) - - w := WalletForSwitcheoTestNet() - log.Printf("%v", w.Address) -}