forked from blocktree/openwallet
/
hdkeystore.go
169 lines (140 loc) · 4.69 KB
/
hdkeystore.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
* Copyright 2018 The openwallet Authors
* This file is part of the openwallet library.
*
* The openwallet library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The openwallet library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
package hdkeystore
import (
"crypto/hmac"
"errors"
"fmt"
"io/ioutil"
"path/filepath"
"github.com/blocktree/openwallet/v2/crypto/sha3"
)
const (
keyHeaderKDF = "scrypt"
// StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB
// memory and taking approximately 1s CPU time on a modern processor.
StandardScryptN = 1 << 18
// StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB
// memory and taking approximately 1s CPU time on a modern processor.
StandardScryptP = 1
// LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB
// memory and taking approximately 100ms CPU time on a modern processor.
LightScryptN = 1 << 12
// LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB
// memory and taking approximately 100ms CPU time on a modern processor.
LightScryptP = 6
scryptR = 8
scryptDKLen = 32
//种子长度
SeedLen = 32
)
var (
//ErrLocked = accounts.NewAuthNeededError("password or unlock")
ErrNoMatch = errors.New("no key for given address or file")
//ErrDecrypt 机密出错
ErrDecrypt = errors.New("could not decrypt key with given passphrase")
)
//HDKeystore HDKey的存粗工具类
type HDKeystore struct {
keysDirPath string
//MasterKey string
scryptN int
scryptP int
}
// NewHDKeystore 实例化HDKeystore
func NewHDKeystore(keydir string, scryptN, scryptP int) *HDKeystore {
keydir, _ = filepath.Abs(keydir)
ks := &HDKeystore{keydir, scryptN, scryptP}
return ks
}
// StoreHDKey 创建HDKey
func StoreHDKey(dir, alias, auth string, scryptN, scryptP int) (*HDKey, string, error) {
seed, err := GenerateSeed(SeedLen)
if err != nil {
return nil, "", err
}
//extSeed, err := GetExtendSeed(seed, masterKey)
//if err != nil {
// return "", err
//}
return StoreHDKeyWithSeed(dir, alias, auth, seed, scryptN, scryptP)
}
// StoreHDKey 创建HDKey
func StoreHDKeyWithSeed(dir, alias, auth string, seed []byte, scryptN, scryptP int) (*HDKey, string, error) {
key, filePath, err := storeNewKey(&HDKeystore{dir, scryptN, scryptP}, alias, auth, seed)
return key, filePath, err
}
//storeNewKey 用随机种子生成HDKey
func storeNewKey(ks *HDKeystore, alias, auth string, seed []byte) (*HDKey, string, error) {
key, err := NewHDKey(seed, alias, OpenwCoinTypePath)
if err != nil {
return nil, "", err
}
filePath := ks.JoinPath(KeyFileName(key.Alias, key.KeyID) + ".key")
ks.StoreKey(filePath, key, auth)
return key, filePath, err
}
//GetKey 通过accountId读取钥匙
func (ks HDKeystore) GetKey(rootId, filename, auth string) (*HDKey, error) {
// Load the key from the keystore and decrypt its contents
keyPath := ks.JoinPath(filename)
keyjson, err := ioutil.ReadFile(keyPath)
if err != nil {
return nil, err
}
key, err := DecryptHDKey(keyjson, auth)
if err != nil {
return nil, err
}
if len(rootId) > 0 {
// Make sure we're really operating on the requested key (no swap attacks)
if key.KeyID != rootId {
return nil, fmt.Errorf("key content mismatch: have account %s, want %s", key.KeyID, rootId)
}
}
return key, nil
}
//StoreKey 把HDKey重写加密写入到文件中
func (ks *HDKeystore) StoreKey(filename string, key *HDKey, auth string) error {
keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
if err != nil {
return err
}
return writeKeyFile(filename, keyjson)
}
//JoinPath 文件路径组合
func (ks *HDKeystore) JoinPath(filename string) string {
if filepath.IsAbs(filename) {
return filename
} else {
return filepath.Join(ks.keysDirPath, filename)
}
}
//getDecryptedKey 获取解密后的钥匙
func (ks *HDKeystore) getDecryptedKey(alias, rootId, auth string) (*HDKey, error) {
path := ks.JoinPath(KeyFileName(alias, rootId) + ".key")
key, err := ks.GetKey(rootId, path, auth)
return key, err
}
//GetExtendSeed 获得某个币种的扩展种子
func GetExtendSeed(seed []byte, masterKey string) ([]byte, error) {
if len(seed) < MinSeedBytes || len(seed) > MaxSeedBytes {
return nil, ErrInvalidSeedLen
}
hmac256 := hmac.New(sha3.New256, []byte(masterKey))
hmac256.Write(seed)
ext := hmac256.Sum(nil)
return ext, nil
}