github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/keystore/keystore_passphrase.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 /* 26 27 此密钥存储区的行为与密钥存储区的区别在于 28 私钥是加密的,在磁盘上使用另一个JSON编码。 29 30 密码记录在https://github.com/ethereum/wiki/wiki/web3-secret-storage-definition上。 31 32 **/ 33 34 35 package keystore 36 37 import ( 38 "bytes" 39 "crypto/aes" 40 "crypto/rand" 41 "crypto/sha256" 42 "encoding/hex" 43 "encoding/json" 44 "fmt" 45 "io" 46 "io/ioutil" 47 "path/filepath" 48 49 "github.com/ethereum/go-ethereum/common" 50 "github.com/ethereum/go-ethereum/common/math" 51 "github.com/ethereum/go-ethereum/crypto" 52 "github.com/pborman/uuid" 53 "golang.org/x/crypto/pbkdf2" 54 "golang.org/x/crypto/scrypt" 55 ) 56 57 const ( 58 keyHeaderKDF = "scrypt" 59 60 //标准加密是加密算法的n个参数,使用256MB 61 //在现代处理器上占用大约1秒的CPU时间。 62 StandardScryptN = 1 << 18 63 64 //StandardScryptP是加密算法的P参数,使用256MB 65 //在现代处理器上占用大约1秒的CPU时间。 66 StandardScryptP = 1 67 68 //lightscryptn是加密算法的n个参数,使用4MB 69 //在现代处理器上占用大约100毫秒的CPU时间。 70 LightScryptN = 1 << 12 71 72 //lightscryptp是加密算法的p参数,使用4MB 73 //在现代处理器上占用大约100毫秒的CPU时间。 74 LightScryptP = 6 75 76 scryptR = 8 77 scryptDKLen = 32 78 ) 79 80 type keyStorePassphrase struct { 81 keysDirPath string 82 scryptN int 83 scryptP int 84 } 85 86 func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) { 87 //从密钥库加载密钥并解密其内容 88 keyjson, err := ioutil.ReadFile(filename) 89 if err != nil { 90 return nil, err 91 } 92 key, err := DecryptKey(keyjson, auth) 93 if err != nil { 94 return nil, err 95 } 96 //确保我们确实在使用请求的密钥(没有交换攻击) 97 if key.Address != addr { 98 return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr) 99 } 100 return key, nil 101 } 102 103 //storekey生成一个密钥,用auth加密并存储在给定的目录中 104 func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) { 105 _, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP}, rand.Reader, auth) 106 return a.Address, err 107 } 108 109 func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error { 110 keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP) 111 if err != nil { 112 return err 113 } 114 return writeKeyFile(filename, keyjson) 115 } 116 117 func (ks keyStorePassphrase) JoinPath(filename string) string { 118 if filepath.IsAbs(filename) { 119 return filename 120 } 121 return filepath.Join(ks.keysDirPath, filename) 122 } 123 124 //encryptkey使用指定的scrypt参数将密钥加密到JSON中 125 //稍后可以解密的blob。 126 func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { 127 authArray := []byte(auth) 128 129 salt := make([]byte, 32) 130 if _, err := io.ReadFull(rand.Reader, salt); err != nil { 131 panic("reading from crypto/rand failed: " + err.Error()) 132 } 133 derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) 134 if err != nil { 135 return nil, err 136 } 137 encryptKey := derivedKey[:16] 138 keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32) 139 140 iv := make([]byte, aes.BlockSize) //十六 141 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 142 panic("reading from crypto/rand failed: " + err.Error()) 143 } 144 cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) 145 if err != nil { 146 return nil, err 147 } 148 mac := crypto.Keccak256(derivedKey[16:32], cipherText) 149 150 scryptParamsJSON := make(map[string]interface{}, 5) 151 scryptParamsJSON["n"] = scryptN 152 scryptParamsJSON["r"] = scryptR 153 scryptParamsJSON["p"] = scryptP 154 scryptParamsJSON["dklen"] = scryptDKLen 155 scryptParamsJSON["salt"] = hex.EncodeToString(salt) 156 157 cipherParamsJSON := cipherparamsJSON{ 158 IV: hex.EncodeToString(iv), 159 } 160 161 cryptoStruct := cryptoJSON{ 162 Cipher: "aes-128-ctr", 163 CipherText: hex.EncodeToString(cipherText), 164 CipherParams: cipherParamsJSON, 165 KDF: keyHeaderKDF, 166 KDFParams: scryptParamsJSON, 167 MAC: hex.EncodeToString(mac), 168 } 169 encryptedKeyJSONV3 := encryptedKeyJSONV3{ 170 hex.EncodeToString(key.Address[:]), 171 cryptoStruct, 172 key.Id.String(), 173 version, 174 } 175 return json.Marshal(encryptedKeyJSONV3) 176 } 177 178 //decryptkey从JSON blob中解密密钥,返回私钥本身。 179 func DecryptKey(keyjson []byte, auth string) (*Key, error) { 180 //将JSON解析为一个简单的映射以获取密钥版本 181 m := make(map[string]interface{}) 182 if err := json.Unmarshal(keyjson, &m); err != nil { 183 return nil, err 184 } 185 //根据版本,尝试以某种方式分析 186 var ( 187 keyBytes, keyId []byte 188 err error 189 ) 190 if version, ok := m["version"].(string); ok && version == "1" { 191 k := new(encryptedKeyJSONV1) 192 if err := json.Unmarshal(keyjson, k); err != nil { 193 return nil, err 194 } 195 keyBytes, keyId, err = decryptKeyV1(k, auth) 196 } else { 197 k := new(encryptedKeyJSONV3) 198 if err := json.Unmarshal(keyjson, k); err != nil { 199 return nil, err 200 } 201 keyBytes, keyId, err = decryptKeyV3(k, auth) 202 } 203 //处理任何解密错误并返回密钥 204 if err != nil { 205 return nil, err 206 } 207 key := crypto.ToECDSAUnsafe(keyBytes) 208 209 return &Key{ 210 Id: uuid.UUID(keyId), 211 Address: crypto.PubkeyToAddress(key.PublicKey), 212 PrivateKey: key, 213 }, nil 214 } 215 216 func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { 217 if keyProtected.Version != version { 218 return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) 219 } 220 221 if keyProtected.Crypto.Cipher != "aes-128-ctr" { 222 return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher) 223 } 224 225 keyId = uuid.Parse(keyProtected.Id) 226 mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 227 if err != nil { 228 return nil, nil, err 229 } 230 231 iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 232 if err != nil { 233 return nil, nil, err 234 } 235 236 cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 237 if err != nil { 238 return nil, nil, err 239 } 240 241 derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 242 if err != nil { 243 return nil, nil, err 244 } 245 246 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 247 if !bytes.Equal(calculatedMAC, mac) { 248 return nil, nil, ErrDecrypt 249 } 250 251 plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv) 252 if err != nil { 253 return nil, nil, err 254 } 255 return plainText, keyId, err 256 } 257 258 func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) { 259 keyId = uuid.Parse(keyProtected.Id) 260 mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 261 if err != nil { 262 return nil, nil, err 263 } 264 265 iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 266 if err != nil { 267 return nil, nil, err 268 } 269 270 cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 271 if err != nil { 272 return nil, nil, err 273 } 274 275 derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 276 if err != nil { 277 return nil, nil, err 278 } 279 280 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 281 if !bytes.Equal(calculatedMAC, mac) { 282 return nil, nil, ErrDecrypt 283 } 284 285 plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv) 286 if err != nil { 287 return nil, nil, err 288 } 289 return plainText, keyId, err 290 } 291 292 func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) { 293 authArray := []byte(auth) 294 salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) 295 if err != nil { 296 return nil, err 297 } 298 dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) 299 300 if cryptoJSON.KDF == keyHeaderKDF { 301 n := ensureInt(cryptoJSON.KDFParams["n"]) 302 r := ensureInt(cryptoJSON.KDFParams["r"]) 303 p := ensureInt(cryptoJSON.KDFParams["p"]) 304 return scrypt.Key(authArray, salt, n, r, p, dkLen) 305 306 } else if cryptoJSON.KDF == "pbkdf2" { 307 c := ensureInt(cryptoJSON.KDFParams["c"]) 308 prf := cryptoJSON.KDFParams["prf"].(string) 309 if prf != "hmac-sha256" { 310 return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) 311 } 312 key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) 313 return key, nil 314 } 315 316 return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) 317 } 318 319 //TODO:在解组动态JSON时,我们可以不这样做吗? 320 //为什么kdf参数中的整数以float64结尾,而不是后面的int 321 //元帅? 322 func ensureInt(x interface{}) int { 323 res, ok := x.(int) 324 if !ok { 325 res = int(x.(float64)) 326 } 327 return res 328 }