forked from umbracle/ethgo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathv3.go
129 lines (110 loc) · 2.79 KB
/
v3.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package keystore
import (
"bytes"
"crypto/aes"
"encoding/json"
"fmt"
"github.com/umbracle/ethgo"
)
// EncryptV3 encrypts data in v3 format
func EncryptV3(content []byte, password string, customScrypt ...int) ([]byte, error) {
// default scrypt values
scryptN, scryptP := 1<<18, 1
if len(customScrypt) >= 1 {
scryptN = customScrypt[0]
}
if len(customScrypt) >= 2 {
scryptP = customScrypt[1]
}
iv := getRand(aes.BlockSize)
scrypt := scryptParams{
N: scryptN,
R: 8,
P: scryptP,
Dklen: 32,
Salt: hexString(getRand(32)),
}
kdf, err := scrypt.Key([]byte(password))
if err != nil {
return nil, err
}
cipherText, err := aesCTR(kdf[:16], content, iv)
if err != nil {
return nil, err
}
// generate mac
mac := ethgo.Keccak256(kdf[16:32], cipherText)
v3 := &v3Encoding{
Version: 3,
Crypto: &cryptoEncoding{
Cipher: "aes-128-ctr",
CipherText: hexString(cipherText),
CipherParams: struct{ IV hexString }{
IV: hexString(iv),
},
KDF: "scrypt",
KDFParams: scrypt,
Mac: hexString(mac),
},
}
encrypted, err := v3.Marshal()
if err != nil {
return nil, err
}
return encrypted, nil
}
// DecryptV3 decodes bytes in the v3 keystore format
func DecryptV3(content []byte, password string) ([]byte, error) {
encoding := v3Encoding{}
if err := encoding.Unmarshal(content); err != nil {
return nil, err
}
if encoding.Version != 3 {
return nil, fmt.Errorf("only version 3 supported")
}
if encoding.Crypto.Cipher != "aes-128-ctr" {
return nil, fmt.Errorf("cipher %s not supported", encoding.Crypto.Cipher)
}
// decode the kdf
kdf, err := applyKdf(encoding.Crypto.KDF, []byte(password), encoding.Crypto.KDFParamsRaw)
if err != nil {
return nil, err
}
// validate mac
mac := ethgo.Keccak256(kdf[16:32], encoding.Crypto.CipherText)
if !bytes.Equal(mac, encoding.Crypto.Mac) {
return nil, fmt.Errorf("incorrect mac")
}
dst, err := aesCTR(kdf[:16], encoding.Crypto.CipherText, encoding.Crypto.CipherParams.IV)
if err != nil {
return nil, err
}
return dst, nil
}
type v3Encoding struct {
ID string `json:"id"`
Version int64 `json:"version"`
Crypto *cryptoEncoding `json:"crypto"`
}
func (j *v3Encoding) Marshal() ([]byte, error) {
params, err := json.Marshal(j.Crypto.KDFParams)
if err != nil {
return nil, err
}
j.Crypto.KDFParamsRaw = json.RawMessage(params)
return json.Marshal(j)
}
func (j *v3Encoding) Unmarshal(data []byte) error {
return json.Unmarshal(data, j)
}
type cryptoEncoding struct {
Cipher string `json:"cipher"`
CipherParams struct {
IV hexString
} `json:"cipherparams"`
CipherText hexString `json:"ciphertext"`
KDF string `json:"kdf"`
KDFParams interface{}
KDFParamsRaw json.RawMessage `json:"kdfparams"`
Mac hexString `json:"mac"`
}