I'm trying out a way to decrypt a MetaMask wallet. MetaMask has its own online tool that provides a way to do this: https://metamask.github.io/vault-decryptor/
I found a Python library that performs this hashdecrypt task: https://pastebin.com/ncREzJSA
I'm trying to implement this code in Golang, but I get an empty result. I hope someone can help and explain what I did wrong.
JSON Wallet:
{"data":"rERJJccSBNfPzRHk32JxDQkpwV7bnMk3PULFnQz8DjKkGiFfmW81ED4dJAG0HHGfIy294AnJYxr7MG9IsVgS0bPD6yVBsfqw40mcsNuBIQLmNXcsw+zCxCnjbqGy2zf5pzvdt76mb4CHtTc7A2UhjApjWaiptR/rxosjkjHUrms0g5kGjr1gWzyZKwI/7u846WUQRRa1PNFX+qnQXWcCAXtjqIJrf762d5+a4rB8bCW3awHHkQm8kroH6PgiX3mYiRZUbDGUSD0DKIZCfHRj6BsndimeNYB0VfX82x0yzoS9D0fagOg1/ETn9cYNplIWT8L39Z9PBxueOOzfcRnQV/SEMozqiHk2SUC0Y1HhoXk4/L1WKF9pJdrCklP6zKaf7RTlXTFqOYkueEf/LGlPQ8MWeq4Nm1zADgJwWiSVWx5Jl6UrOvxNLTd0C4ZPFdunVVPkzYjzBVLgOYrE3udhWF+wqfJQZ6BXu8N5Y1bdoZEtKJ+SPuc+aVBd5Esz0q+mY/WIJswO5laY","iv":"xPb05MBtb23xPtfWxgCLzQ==","salt":"ggTRTywqaFJGxYAj73woAkA6mkjkY6q779u63DKLr3g="}
Password: tester123
You can try to decipher it here: https://metamask.github.io/vault-decryptor/
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"golang.org/x/crypto/pbkdf2"
)
type Payload struct {
Data string `json:"data"`
Salt string `json:"salt"`
Iv string `json:"iv"`
}
var wallet = []byte(`{"data":"rERJJccSBNfPzRHk32JxDQkpwV7bnMk3PULFnQz8DjKkGiFfmW81ED4dJAG0HHGfIy294AnJYxr7MG9IsVgS0bPD6yVBsfqw40mcsNuBIQLmNXcsw+zCxCnjbqGy2zf5pzvdt76mb4CHtTc7A2UhjApjWaiptR/rxosjkjHUrms0g5kGjr1gWzyZKwI/7u846WUQRRa1PNFX+qnQXWcCAXtjqIJrf762d5+a4rB8bCW3awHHkQm8kroH6PgiX3mYiRZUbDGUSD0DKIZCfHRj6BsndimeNYB0VfX82x0yzoS9D0fagOg1/ETn9cYNplIWT8L39Z9PBxueOOzfcRnQV/SEMozqiHk2SUC0Y1HhoXk4/L1WKF9pJdrCklP6zKaf7RTlXTFqOYkueEf/LGlPQ8MWeq4Nm1zADgJwWiSVWx5Jl6UrOvxNLTd0C4ZPFdunVVPkzYjzBVLgOYrE3udhWF+wqfJQZ6BXu8N5Y1bdoZEtKJ+SPuc+aVBd5Esz0q+mY/WIJswO5laY","iv":"xPb05MBtb23xPtfWxgCLzQ==","salt":"ggTRTywqaFJGxYAj73woAkA6mkjkY6q779u63DKLr3g="}`)
func main() {
var payload Payload
json.Unmarshal(wallet, &payload)
iv, _ := base64.StdEncoding.DecodeString(payload.Iv)
salt, _ := base64.StdEncoding.DecodeString(payload.Salt)
data, _ := base64.StdEncoding.DecodeString(payload.Data)
// Remove last 16 symbols, this was done in the hashdecrypt python library
data = data[:len(data)-len(iv)]
password := "tester123"
key := pbkdf2.Key([]byte(password), salt, 1000, 32, sha256.New)
block, _ := aes.NewCipher(key)
// In MetaMask's vault-decryptor, the nonce (initialization vector) size is fixed at 16 bytes.
gcm, _ := cipher.NewGCMWithNonceSize(block, len(iv))
plaintext, err := gcm.Open(nil, iv, data, nil)
fmt.Println(err)
fmt.Println(plaintext)
}
cipher: message authentication failed
[]
Tried different variations, but no way to resolve it. I hope someone can help.
Whoops! My inattention...
The mistake was here:
key := pbkdf2.Key([]byte(password), salt, 1000, 32, sha256.New)
Missed a single zero. It has to be:
key := pbkdf2.Key([]byte(password), salt, 10000, 32, sha256.New)
Also, this line must be deleted:
data = data[:len(data)-len(iv)]
package main
import (
"crypto/aes"
"crypto/cipher"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"golang.org/x/crypto/pbkdf2"
)
type Payload struct {
Data string `json:"data"`
Salt string `json:"salt"`
Iv string `json:"iv"`
}
type Vault struct {
Type string `json:"type"`
Data struct {
Mnemonic []byte `json:"mnemonic"`
NumberOfAccounts int `json:"numberOfAccounts"`
HDPath string `json:"hdPath"`
} `json:"data"`
}
var wallet = []byte(`{"data":"rERJJccSBNfPzRHk32JxDQkpwV7bnMk3PULFnQz8DjKkGiFfmW81ED4dJAG0HHGfIy294AnJYxr7MG9IsVgS0bPD6yVBsfqw40mcsNuBIQLmNXcsw+zCxCnjbqGy2zf5pzvdt76mb4CHtTc7A2UhjApjWaiptR/rxosjkjHUrms0g5kGjr1gWzyZKwI/7u846WUQRRa1PNFX+qnQXWcCAXtjqIJrf762d5+a4rB8bCW3awHHkQm8kroH6PgiX3mYiRZUbDGUSD0DKIZCfHRj6BsndimeNYB0VfX82x0yzoS9D0fagOg1/ETn9cYNplIWT8L39Z9PBxueOOzfcRnQV/SEMozqiHk2SUC0Y1HhoXk4/L1WKF9pJdrCklP6zKaf7RTlXTFqOYkueEf/LGlPQ8MWeq4Nm1zADgJwWiSVWx5Jl6UrOvxNLTd0C4ZPFdunVVPkzYjzBVLgOYrE3udhWF+wqfJQZ6BXu8N5Y1bdoZEtKJ+SPuc+aVBd5Esz0q+mY/WIJswO5laY","iv":"xPb05MBtb23xPtfWxgCLzQ==","salt":"ggTRTywqaFJGxYAj73woAkA6mkjkY6q779u63DKLr3g="}`)
func main() {
var payload Payload
json.Unmarshal(wallet, &payload)
iv, _ := base64.StdEncoding.DecodeString(payload.Iv)
salt, _ := base64.StdEncoding.DecodeString(payload.Salt)
data, _ := base64.StdEncoding.DecodeString(payload.Data)
password := "tester123"
key := pbkdf2.Key([]byte(password), salt, 10000, 32, sha256.New)
block, _ := aes.NewCipher(key)
// In MetaMask's vault-decryptor, the nonce (initialization vector) size is fixed at 16 bytes.
gcm, _ := cipher.NewGCMWithNonceSize(block, len(iv))
plaintext, err := gcm.Open(nil, iv, data, nil)
if err != nil {
panic(err)
}
var vault []Vault
json.Unmarshal(plaintext, &vault)
fmt.Println(string(vault[0].Data.Mnemonic))
}
The code is written as an example, so error checks have been ignored.