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