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 1f3940a..c641913 100644 --- a/neoutils/nep2/nep2.go +++ b/neoutils/nep2/nep2.go @@ -126,6 +126,47 @@ func NEP2Decrypt(key, passphrase string) (s string, err error) { return privKey.ToWIFC(), nil } +func NEP2DecryptToPrivateKey(key, passphrase string) (pk btckey.PrivateKey, err error) { + encrypted, err := crypto.Base58CheckDecode(key) + if err != nil { + return pk, err + } + if err := validateNEP2Format(encrypted); err != nil { + return pk, 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 pk, err + } + + derivedKey1 := derivedKey[:32] + derivedKey2 := derivedKey[32:] + encryptedBytes := encrypted[7:] + + decrypted, err := crypto.AESDecrypt(encryptedBytes, derivedKey2) + if err != nil { + return pk, err + } + privBytes := xor(decrypted, derivedKey1) + // Rebuild the private key. + var privKey btckey.PrivateKey + err = privKey.FromBytes(privBytes) + if err != nil { + return pk, err + } + + if !compareAddressHash(&privKey, addrHash) { + return pk, errors.New("password mismatch") + } + + return privKey, nil +} + func compareAddressHash(priv *btckey.PrivateKey, hash []byte) bool { address := priv.ToNeoAddress() addrHash := hashAddress(address)[0:4] 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) -}