github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/keystore/key.go (about) 1 2 //此源码被清华学神尹成大魔王专业翻译分析并修改 3 //尹成QQ77025077 4 //尹成微信18510341407 5 //尹成所在QQ群721929980 6 //尹成邮箱 yinc13@mails.tsinghua.edu.cn 7 //尹成毕业于清华大学,微软区块链领域全球最有价值专家 8 //https://mvp.microsoft.com/zh-cn/PublicProfile/4033620 9 //版权所有2014 Go Ethereum作者 10 //此文件是Go以太坊库的一部分。 11 // 12 //Go-Ethereum库是免费软件:您可以重新分发它和/或修改 13 //根据GNU发布的较低通用公共许可证的条款 14 //自由软件基金会,或者许可证的第3版,或者 15 //(由您选择)任何更高版本。 16 // 17 //Go以太坊图书馆的发行目的是希望它会有用, 18 //但没有任何保证;甚至没有 19 //适销性或特定用途的适用性。见 20 //GNU较低的通用公共许可证,了解更多详细信息。 21 // 22 //你应该收到一份GNU较低级别的公共许可证副本 23 //以及Go以太坊图书馆。如果没有,请参见<http://www.gnu.org/licenses/>。 24 25 package keystore 26 27 import ( 28 "bytes" 29 "crypto/ecdsa" 30 "encoding/hex" 31 "encoding/json" 32 "fmt" 33 "io" 34 "io/ioutil" 35 "os" 36 "path/filepath" 37 "strings" 38 "time" 39 40 "github.com/ethereum/go-ethereum/accounts" 41 "github.com/ethereum/go-ethereum/common" 42 "github.com/ethereum/go-ethereum/crypto" 43 "github.com/pborman/uuid" 44 ) 45 46 const ( 47 version = 3 48 ) 49 50 type Key struct { 51 Id uuid.UUID //唯一ID的版本4“随机”不是从密钥数据派生的 52 //为了简化查找,我们还存储了地址 53 Address common.Address 54 //我们只存储privkey,因为pubkey/地址可以从中派生 55 //此结构中的privkey始终为纯文本 56 PrivateKey *ecdsa.PrivateKey 57 } 58 59 type keyStore interface { 60 //从磁盘加载和解密密钥。 61 GetKey(addr common.Address, filename string, auth string) (*Key, error) 62 //写入并加密密钥。 63 StoreKey(filename string, k *Key, auth string) error 64 // 65 JoinPath(filename string) string 66 } 67 68 type plainKeyJSON struct { 69 Address string `json:"address"` 70 PrivateKey string `json:"privatekey"` 71 Id string `json:"id"` 72 Version int `json:"version"` 73 } 74 75 type encryptedKeyJSONV3 struct { 76 Address string `json:"address"` 77 Crypto cryptoJSON `json:"crypto"` 78 Id string `json:"id"` 79 Version int `json:"version"` 80 } 81 82 type encryptedKeyJSONV1 struct { 83 Address string `json:"address"` 84 Crypto cryptoJSON `json:"crypto"` 85 Id string `json:"id"` 86 Version string `json:"version"` 87 } 88 89 type cryptoJSON struct { 90 Cipher string `json:"cipher"` 91 CipherText string `json:"ciphertext"` 92 CipherParams cipherparamsJSON `json:"cipherparams"` 93 KDF string `json:"kdf"` 94 KDFParams map[string]interface{} `json:"kdfparams"` 95 MAC string `json:"mac"` 96 } 97 98 type cipherparamsJSON struct { 99 IV string `json:"iv"` 100 } 101 102 func (k *Key) MarshalJSON() (j []byte, err error) { 103 jStruct := plainKeyJSON{ 104 hex.EncodeToString(k.Address[:]), 105 hex.EncodeToString(crypto.FromECDSA(k.PrivateKey)), 106 k.Id.String(), 107 version, 108 } 109 j, err = json.Marshal(jStruct) 110 return j, err 111 } 112 113 func (k *Key) UnmarshalJSON(j []byte) (err error) { 114 keyJSON := new(plainKeyJSON) 115 err = json.Unmarshal(j, &keyJSON) 116 if err != nil { 117 return err 118 } 119 120 u := new(uuid.UUID) 121 *u = uuid.Parse(keyJSON.Id) 122 k.Id = *u 123 addr, err := hex.DecodeString(keyJSON.Address) 124 if err != nil { 125 return err 126 } 127 privkey, err := crypto.HexToECDSA(keyJSON.PrivateKey) 128 if err != nil { 129 return err 130 } 131 132 k.Address = common.BytesToAddress(addr) 133 k.PrivateKey = privkey 134 135 return nil 136 } 137 138 func newKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key { 139 id := uuid.NewRandom() 140 key := &Key{ 141 Id: id, 142 Address: crypto.PubkeyToAddress(privateKeyECDSA.PublicKey), 143 PrivateKey: privateKeyECDSA, 144 } 145 return key 146 } 147 148 //newkeywordirecticap生成一个地址小于155位的密钥,以便它可以 149 //为了简化和更容易与其他libs兼容,我们在直接的icap规范中 150 //重试,直到第一个字节为0。 151 func NewKeyForDirectICAP(rand io.Reader) *Key { 152 randBytes := make([]byte, 64) 153 _, err := rand.Read(randBytes) 154 if err != nil { 155 panic("key generation: could not read from random source: " + err.Error()) 156 } 157 reader := bytes.NewReader(randBytes) 158 privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), reader) 159 if err != nil { 160 panic("key generation: ecdsa.GenerateKey failed: " + err.Error()) 161 } 162 key := newKeyFromECDSA(privateKeyECDSA) 163 if !strings.HasPrefix(key.Address.Hex(), "0x00") { 164 return NewKeyForDirectICAP(rand) 165 } 166 return key 167 } 168 169 func newKey(rand io.Reader) (*Key, error) { 170 privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand) 171 if err != nil { 172 return nil, err 173 } 174 return newKeyFromECDSA(privateKeyECDSA), nil 175 } 176 177 func storeNewKey(ks keyStore, rand io.Reader, auth string) (*Key, accounts.Account, error) { 178 key, err := newKey(rand) 179 if err != nil { 180 return nil, accounts.Account{}, err 181 } 182 a := accounts.Account{Address: key.Address, URL: accounts.URL{Scheme: KeyStoreScheme, Path: ks.JoinPath(keyFileName(key.Address))}} 183 if err := ks.StoreKey(a.URL.Path, key, auth); err != nil { 184 zeroKey(key.PrivateKey) 185 return nil, a, err 186 } 187 return key, a, err 188 } 189 190 func writeKeyFile(file string, content []byte) error { 191 //使用适当的权限创建keystore目录 192 //以防它还没有出现。 193 const dirPerm = 0700 194 if err := os.MkdirAll(filepath.Dir(file), dirPerm); err != nil { 195 return err 196 } 197 //原子写入:首先创建临时隐藏文件 198 //然后移动到位。tempfile指定模式0600。 199 f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp") 200 if err != nil { 201 return err 202 } 203 if _, err := f.Write(content); err != nil { 204 f.Close() 205 os.Remove(f.Name()) 206 return err 207 } 208 f.Close() 209 return os.Rename(f.Name(), file) 210 } 211 212 //keyfilename实现了keyfiles的命名约定: 213 //UTC——<created_at UTC iso8601>-<address hex> 214 func keyFileName(keyAddr common.Address) string { 215 ts := time.Now().UTC() 216 return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:])) 217 } 218 219 func toISO8601(t time.Time) string { 220 var tz string 221 name, offset := t.Zone() 222 if name == "UTC" { 223 tz = "Z" 224 } else { 225 tz = fmt.Sprintf("%03d00", offset/3600) 226 } 227 return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz) 228 }