github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/accounts/keystore/keystore_passphrase.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 /* 18 19 This key store behaves as KeyStorePlain with the difference that 20 the private key is encrypted and on disk uses another JSON encoding. 21 22 The crypto is documented at https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition 23 24 */ 25 26 package keystore 27 28 import ( 29 "bytes" 30 "crypto/aes" 31 "crypto/ecdsa" 32 "crypto/sha256" 33 "encoding/hex" 34 "encoding/json" 35 "errors" 36 "fmt" 37 "io/ioutil" 38 "path/filepath" 39 40 "github.com/pborman/uuid" 41 "github.com/wanchain/go-wanchain/common" 42 "github.com/wanchain/go-wanchain/common/math" 43 "github.com/wanchain/go-wanchain/crypto" 44 "github.com/wanchain/go-wanchain/crypto/randentropy" 45 "golang.org/x/crypto/pbkdf2" 46 "golang.org/x/crypto/scrypt" 47 ) 48 49 const ( 50 keyHeaderKDF = "scrypt" 51 52 // StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB 53 // memory and taking approximately 1s CPU time on a modern processor. 54 StandardScryptN = 1 << 18 55 56 // StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB 57 // memory and taking approximately 1s CPU time on a modern processor. 58 StandardScryptP = 1 59 60 // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB 61 // memory and taking approximately 100ms CPU time on a modern processor. 62 LightScryptN = 1 << 12 63 64 // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB 65 // memory and taking approximately 100ms CPU time on a modern processor. 66 LightScryptP = 6 67 68 scryptR = 8 69 scryptDKLen = 32 70 ) 71 72 type keyStorePassphrase struct { 73 keysDirPath string 74 scryptN int 75 scryptP int 76 } 77 78 var ( 79 ErrWAddressFieldNotExist = errors.New("It seems that this account doesn't include a valid wanchain address field, please update your keyfile version") 80 ErrWAddressInvalid = errors.New("invalid wanchain address") 81 ErrInvalidAccountKey = errors.New("invalid account key") 82 ErrInvalidPrivateKey = errors.New("invalid private key") 83 ) 84 85 func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) { 86 // Load the key from the keystore and decrypt its contents 87 keyjson, err := ioutil.ReadFile(filename) 88 if err != nil { 89 return nil, err 90 } 91 key, err := DecryptKey(keyjson, auth) 92 if err != nil { 93 return nil, err 94 } 95 // Make sure we're really operating on the requested key (no swap attacks) 96 if key.Address != addr { 97 return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr) 98 } 99 return key, nil 100 } 101 102 func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error { 103 keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP) 104 if err != nil { 105 return err 106 } 107 return writeKeyFile(filename, keyjson) 108 } 109 110 // Implements GetEncryptedKey method of keystore interface 111 func (ks keyStorePassphrase) GetEncryptedKey(a common.Address, filename string) (*Key, error) { 112 // load the encrypted json keyfile 113 keyjson, err := ioutil.ReadFile(filename) 114 if err != nil { 115 return nil, err 116 } 117 key, err := GenerateKeyWithWAddress(keyjson) 118 if err != nil { 119 return nil, err 120 } 121 key.Address = a 122 return key, nil 123 } 124 125 // Generate a Key initialized with WAddress field 126 func GenerateKeyWithWAddress(keyjson []byte) (*Key, error) { 127 // parse the json blob into a simple map to fetch the key version 128 m := make(map[string]interface{}) 129 if err := json.Unmarshal(keyjson, &m); err != nil { 130 return nil, err 131 } 132 133 waddress, ok := m["waddress"].(string) 134 135 if !ok || waddress == "" { 136 return nil, ErrWAddressFieldNotExist 137 } 138 139 waddressRaw, err := hex.DecodeString(waddress) 140 if err != nil { 141 return nil, err 142 } 143 144 if len(waddressRaw) != common.WAddressLength { 145 return nil, ErrWAddressInvalid 146 } 147 148 key := new(Key) 149 copy(key.WAddress[:], waddressRaw) 150 return key, nil 151 } 152 153 func (ks keyStorePassphrase) JoinPath(filename string) string { 154 if filepath.IsAbs(filename) { 155 return filename 156 } else { 157 return filepath.Join(ks.keysDirPath, filename) 158 } 159 } 160 161 // EncryptKey encrypts a key using the specified scrypt parameters into a json 162 // blob that can be decrypted later on. 163 func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { 164 if key == nil { 165 return nil, ErrInvalidAccountKey 166 } 167 168 cryptoStruct, err := EncryptOnePrivateKey(key.PrivateKey, auth, scryptN, scryptP) 169 if err != nil { 170 return nil, err 171 } 172 173 cryptoStruct2, err := EncryptOnePrivateKey(key.PrivateKey2, auth, scryptN, scryptP) 174 if err != nil { 175 return nil, err 176 } 177 178 encryptedKeyJSONV3 := encryptedKeyJSONV3{ 179 key.Address.Hex()[2:], 180 *cryptoStruct, 181 *cryptoStruct2, 182 key.Id.String(), 183 version, 184 hex.EncodeToString(key.WAddress[:]), 185 } 186 return json.Marshal(encryptedKeyJSONV3) 187 } 188 189 // EncryptOnePrivateKey encrypts a key using the specified scrypt parameters into one field of a json 190 // blob that can be decrypted later on. 191 func EncryptOnePrivateKey(privateKey *ecdsa.PrivateKey, auth string, scryptN, scryptP int) (*cryptoJSON, error) { 192 if privateKey == nil { 193 return nil, ErrInvalidPrivateKey 194 } 195 196 authArray := []byte(auth) 197 salt := randentropy.GetEntropyCSPRNG(32) 198 derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) 199 if err != nil { 200 return nil, err 201 } 202 203 encryptKey := derivedKey[:16] 204 keyBytes := math.PaddedBigBytes(privateKey.D, 32) 205 206 iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16 207 208 cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) 209 if err != nil { 210 return nil, err 211 } 212 mac := crypto.Keccak256(derivedKey[16:32], cipherText) 213 214 scryptParamsJSON := make(map[string]interface{}, 5) 215 scryptParamsJSON["n"] = scryptN 216 scryptParamsJSON["r"] = scryptR 217 scryptParamsJSON["p"] = scryptP 218 scryptParamsJSON["dklen"] = scryptDKLen 219 scryptParamsJSON["salt"] = hex.EncodeToString(salt) 220 221 cipherParamsJSON := cipherparamsJSON{ 222 IV: hex.EncodeToString(iv), 223 } 224 225 cryptoStruct := &cryptoJSON{ 226 Cipher: "aes-128-ctr", 227 CipherText: hex.EncodeToString(cipherText), 228 CipherParams: cipherParamsJSON, 229 KDF: keyHeaderKDF, 230 KDFParams: scryptParamsJSON, 231 MAC: hex.EncodeToString(mac), 232 } 233 234 return cryptoStruct, nil 235 236 } 237 238 // DecryptKey decrypts a key from a json blob, returning the private key itself. 239 func DecryptKey(keyjson []byte, auth string) (*Key, error) { 240 // Parse the json into a simple map to fetch the key version 241 m := make(map[string]interface{}) 242 if err := json.Unmarshal(keyjson, &m); err != nil { 243 return nil, err 244 } 245 // Depending on the version try to parse one way or another 246 var ( 247 keyBytes, keyBytes2, keyId []byte 248 err error 249 waddressStr *string 250 ) 251 if version, ok := m["version"].(string); ok && version == "1" { 252 k := new(encryptedKeyJSONV1) 253 if err := json.Unmarshal(keyjson, k); err != nil { 254 return nil, err 255 } 256 257 keyBytes, keyId, err = decryptKeyV1(k, auth) 258 key, err := crypto.ToECDSA(keyBytes) 259 if err != nil || key == nil { 260 return nil, err 261 } 262 263 return &Key{ 264 Id: uuid.UUID(keyId), 265 Address: crypto.PubkeyToAddress(key.PublicKey), 266 PrivateKey: key, 267 }, nil 268 } else { 269 k := new(encryptedKeyJSONV3) 270 if err := json.Unmarshal(keyjson, k); err != nil { 271 return nil, err 272 } 273 keyBytes, keyBytes2, keyId, err = decryptKeyV3(k, auth) 274 if err != nil { 275 return nil, err 276 } 277 278 waddressStr = &k.WAddress 279 } 280 281 key, err := crypto.ToECDSA(keyBytes) 282 if err != nil || key == nil { 283 return nil, ErrInvalidPrivateKey 284 } 285 286 key2, err := crypto.ToECDSA(keyBytes2) 287 if err != nil || key2 == nil { 288 return nil, ErrInvalidPrivateKey 289 } 290 291 waddressRaw, err := hex.DecodeString(*waddressStr) 292 if err != nil { 293 return nil, err 294 } 295 296 var waddress common.WAddress 297 copy(waddress[:], waddressRaw) 298 299 return &Key{ 300 Id: uuid.UUID(keyId), 301 Address: crypto.PubkeyToAddress(key.PublicKey), 302 PrivateKey: key, 303 PrivateKey2: key2, 304 WAddress: waddress, 305 }, nil 306 } 307 308 func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyBytes2 []byte, keyId []byte, err error) { 309 if keyProtected.Version != version { 310 return nil, nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) 311 } 312 313 keyId = uuid.Parse(keyProtected.Id) 314 315 plainText, err := decryptKeyV3Item(keyProtected.Crypto, auth) 316 if err != nil { 317 return nil, nil, nil, err 318 } 319 320 plainText2, err2 := decryptKeyV3Item(keyProtected.Crypto2, auth) 321 if err2 != nil { 322 if "" == keyProtected.Crypto2.Cipher { 323 plainText2 = make([]byte, 0) 324 } else { 325 return nil, nil, nil, err2 326 } 327 } 328 329 return plainText, plainText2, keyId, err 330 } 331 332 func decryptKeyV3Item(cryptoItem cryptoJSON, auth string) (keyBytes []byte, err error) { 333 if cryptoItem.Cipher != "aes-128-ctr" { 334 return nil, fmt.Errorf("Cipher not supported: %v", cryptoItem.Cipher) 335 } 336 337 mac, err := hex.DecodeString(cryptoItem.MAC) 338 if err != nil { 339 return nil, err 340 } 341 342 iv, err := hex.DecodeString(cryptoItem.CipherParams.IV) 343 if err != nil { 344 return nil, err 345 } 346 347 cipherText, err := hex.DecodeString(cryptoItem.CipherText) 348 if err != nil { 349 return nil, err 350 } 351 352 derivedKey, err := getKDFKey(cryptoItem, auth) 353 if err != nil { 354 return nil, err 355 } 356 357 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 358 if !bytes.Equal(calculatedMAC, mac) { 359 return nil, ErrDecrypt 360 } 361 362 plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv) 363 if err != nil { 364 return nil, err 365 } 366 367 return plainText, err 368 } 369 370 func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) { 371 keyId = uuid.Parse(keyProtected.Id) 372 mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 373 if err != nil { 374 return nil, nil, err 375 } 376 377 iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 378 if err != nil { 379 return nil, nil, err 380 } 381 382 cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 383 if err != nil { 384 return nil, nil, err 385 } 386 387 derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 388 if err != nil { 389 return nil, nil, err 390 } 391 392 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 393 if !bytes.Equal(calculatedMAC, mac) { 394 return nil, nil, ErrDecrypt 395 } 396 397 plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv) 398 if err != nil { 399 return nil, nil, err 400 } 401 return plainText, keyId, err 402 } 403 404 func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) { 405 authArray := []byte(auth) 406 salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) 407 if err != nil { 408 return nil, err 409 } 410 dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) 411 412 if cryptoJSON.KDF == keyHeaderKDF { 413 n := ensureInt(cryptoJSON.KDFParams["n"]) 414 r := ensureInt(cryptoJSON.KDFParams["r"]) 415 p := ensureInt(cryptoJSON.KDFParams["p"]) 416 return scrypt.Key(authArray, salt, n, r, p, dkLen) 417 418 } else if cryptoJSON.KDF == "pbkdf2" { 419 c := ensureInt(cryptoJSON.KDFParams["c"]) 420 prf := cryptoJSON.KDFParams["prf"].(string) 421 if prf != "hmac-sha256" { 422 return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) 423 } 424 key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) 425 return key, nil 426 } 427 428 return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) 429 } 430 431 // TODO: can we do without this when unmarshalling dynamic JSON? 432 // why do integers in KDF params end up as float64 and not int after 433 // unmarshal? 434 func ensureInt(x interface{}) int { 435 res, ok := x.(int) 436 if !ok { 437 res = int(x.(float64)) 438 } 439 return res 440 }