-
-
Save rikonor/aea81f6834ec15e5cad8db4bdb4031c3 to your computer and use it in GitHub Desktop.
package main | |
import ( | |
"bytes" | |
"crypto/aes" | |
"crypto/cipher" | |
"encoding/hex" | |
"encoding/json" | |
"flag" | |
"fmt" | |
"log" | |
"os" | |
"golang.org/x/crypto/scrypt" | |
"golang.org/x/crypto/sha3" | |
) | |
type Config struct { | |
Password string | |
Verify bool | |
} | |
func main() { | |
cfg := &Config{} | |
flag.StringVar(&cfg.Password, "password", "", "Keystore Password") | |
flag.BoolVar(&cfg.Verify, "verify", true, "Verify Derivation Key") | |
flag.Parse() | |
k := KeyStore{} | |
if err := json.NewDecoder(os.Stdin).Decode(&k); err != nil { | |
log.Fatal(err) | |
} | |
pk, err := Convert(k, cfg.Password, cfg.Verify) | |
if err != nil { | |
log.Fatal(err) | |
} | |
fmt.Printf("0x%s\n", hex.EncodeToString(pk)) | |
} | |
type CipherParams struct { | |
IV string `json:"iv"` | |
} | |
type KDFParams struct { | |
DKLen int `json:"dklen"` | |
N int `json:"n"` | |
P int `json:"p"` | |
R int `json:"r"` | |
Salt string `json:"salt"` | |
} | |
type Crypto struct { | |
Cipher string `json:"cipher"` | |
CipherText string `json:"ciphertext"` | |
CipherParams CipherParams `json:"cipherparams"` | |
KDF string `json:"kdf"` | |
KDFParams KDFParams `json:"kdfparams"` | |
MAC string `json:"mac"` | |
} | |
type KeyStore struct { | |
Address string `json:"address"` | |
Crypto Crypto `json:"crypto"` | |
ID string `json:"id"` | |
Version int `json:"version"` | |
} | |
func Convert(k KeyStore, pw string, verify bool) ([]byte, error) { | |
getDerivationKey := func(pw string, kdfParams KDFParams) ([]byte, error) { | |
s, err := hex.DecodeString(kdfParams.Salt) | |
if err != nil { | |
return nil, err | |
} | |
dk, err := scrypt.Key( | |
[]byte(pw), // password | |
s, // salt | |
k.Crypto.KDFParams.N, // N | |
k.Crypto.KDFParams.R, // r | |
k.Crypto.KDFParams.P, // p | |
k.Crypto.KDFParams.DKLen, // keyLen | |
) | |
if err != nil { | |
return nil, err | |
} | |
return dk, nil | |
} | |
dk, err := getDerivationKey(pw, k.Crypto.KDFParams) | |
if err != nil { | |
return nil, err | |
} | |
verifyDerivationKey := func(dk []byte, cipherText string, mac string) error { | |
c, err := hex.DecodeString(cipherText) | |
if err != nil { | |
return err | |
} | |
m, err := hex.DecodeString(mac) | |
if err != nil { | |
return err | |
} | |
h := sha3.NewLegacyKeccak256() | |
h.Write(dk[16:]) | |
h.Write(c) | |
out := h.Sum(nil) | |
if !bytes.Equal(out, m) { | |
return fmt.Errorf("derivation key verification failed") | |
} | |
return nil | |
} | |
if verify { | |
sha3.NewLegacyKeccak256() | |
if err := verifyDerivationKey(dk, k.Crypto.CipherText, k.Crypto.MAC); err != nil { | |
return nil, err | |
} | |
} | |
decryptCipherText := func(dk []byte, iv string, cipherText string) ([]byte, error) { | |
ivb, err := hex.DecodeString(iv) | |
if err != nil { | |
return nil, err | |
} | |
c, err := hex.DecodeString(cipherText) | |
if err != nil { | |
return nil, err | |
} | |
b, err := aes.NewCipher(dk[0:16]) | |
if err != nil { | |
return nil, err | |
} | |
s := cipher.NewCTR( | |
b, // block | |
ivb, // iv | |
) | |
out := make([]byte, len(c)) | |
s.XORKeyStream( | |
out, // dst | |
c, // src | |
) | |
return out, nil | |
} | |
pk, err := decryptCipherText(dk, k.Crypto.CipherParams.IV, k.Crypto.CipherText) | |
if err != nil { | |
return nil, err | |
} | |
return pk, nil | |
} |
package main | |
import ( | |
"encoding/hex" | |
"fmt" | |
"testing" | |
) | |
func TestConvert(t *testing.T) { | |
type testCase struct { | |
k KeyStore | |
pw string | |
out string | |
} | |
testCases := []testCase{ | |
testCase{ | |
k: KeyStore{ | |
Address: "8e3fb75a5a2b150df32f0a9e5107fa21969c838c", | |
Crypto: Crypto{ | |
Cipher: "aes-128-ctr", | |
CipherText: "02b7d60b1940943f847e3184623553319a522125e903d16c48622c7e87506011", | |
CipherParams: CipherParams{ | |
IV: "7dc1e9ffbcfb894712713ac8ed3a3a49", | |
}, | |
KDF: "scrypt", | |
KDFParams: KDFParams{ | |
DKLen: 32, | |
N: 262144, | |
P: 1, | |
R: 8, | |
Salt: "ac85ef9c5b07026c482a9cce49d5685d35c9ff876b8507c67edd437d2e7e34a0", | |
}, | |
MAC: "23eb6987b5d5cc26a5cc180f2f67c50bd4caa1fc0556492b4e9af2c6587270e9", | |
}, | |
ID: "1bd782c9-e103-48f0-b483-c484a5be85ea", | |
Version: 3, | |
}, | |
pw: "123456", | |
out: "0xf8668027023d051e86d987938d3cd3d1aff88ea9d3851470ba2d5ba0939c1998", | |
}, | |
} | |
for _, tc := range testCases { | |
pk, err := Convert( | |
tc.k, // k | |
tc.pw, // password | |
true, // verify | |
) | |
if err != nil { | |
t.Fatalf("unexpected error: %s", err) | |
} | |
if out := fmt.Sprintf("0x%s", hex.EncodeToString(pk)); out != tc.out { | |
t.Fatalf("wrong output: %s, expected %s", out, tc.out) | |
} | |
} | |
} |
@Oluwatobilobaoke What kind of problems are you having? Do you have Go installed?
@rikonor i have go installed when i ran the code it says a package is deprecated
@Oluwatobilobaoke What's maintest.go
? You should really just need to copy main.go
from this gist.
Hmm try this - create a new directory and put main.go
in it. Then run:
$ go mod init tmp
$ go mod tidy
$ go run main.go
Ok, you're very close! Do you have a a key-store JSON file? Assuming you do, run the following:
$ go build
$ cat key-store.json | ./tmp --password "<PASSWORD>"
thank you it worked..
but i got a lot of ffff in the key what do you think could be wrong?
0xfffffffffffffffffffffffffffffff.....364141
@Oluwatobilobaoke I honestly have not touched this stuff in ages, so it's hard for me to say. If I could make a suggestion, it would be to join the CryptoDevs Discord - you are very likely to get better help there.
thank you it worked..
but i got a lot of ffff in the key what do you think could be wrong?
0xfffffffffffffffffffffffffffffff.....364141
what is the steps u followed to run it, please share them
@peacecodes12 it's highlighted above
Please how can i run this, i seem to be having problem using it @rikonor