github.com/klaytn/klaytn@v1.10.2/accounts/keystore/keystore_passphrase.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2014 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from accounts/keystore/keystore_passphrase.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package keystore 22 23 import ( 24 "bytes" 25 "crypto/aes" 26 "crypto/ecdsa" 27 "crypto/rand" 28 "crypto/sha256" 29 "encoding/hex" 30 "encoding/json" 31 "fmt" 32 "io" 33 "io/ioutil" 34 "os" 35 "path/filepath" 36 37 "github.com/klaytn/klaytn/common" 38 "github.com/klaytn/klaytn/common/math" 39 "github.com/klaytn/klaytn/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 // StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB 49 // memory and taking approximately 1s CPU time on a modern processor. 50 StandardScryptN = 1 << 18 51 52 // StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB 53 // memory and taking approximately 1s CPU time on a modern processor. 54 StandardScryptP = 1 55 56 // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB 57 // memory and taking approximately 100ms CPU time on a modern processor. 58 LightScryptN = 1 << 12 59 60 // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB 61 // memory and taking approximately 100ms CPU time on a modern processor. 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 // skipKeyFileVerification disables the security-feature which does 73 // reads and decrypts any newly created keyfiles. This should be 'false' in all 74 // cases except tests -- setting this to 'true' is not recommended. 75 skipKeyFileVerification bool 76 } 77 78 func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (Key, error) { 79 // Load the key from the keystore and decrypt its contents 80 keyjson, err := ioutil.ReadFile(filename) 81 if err != nil { 82 return nil, err 83 } 84 key, err := DecryptKey(keyjson, auth) 85 if err != nil { 86 return nil, err 87 } 88 // Make sure we're really operating on the requested key (no swap attacks) 89 if key.GetAddress() != addr { 90 return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.GetAddress(), addr) 91 } 92 return key, nil 93 } 94 95 // StoreKey generates a key, encrypts with 'auth' and stores in the given directory 96 func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) { 97 _, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP, false}, rand.Reader, auth) 98 return a.Address, err 99 } 100 101 func (ks keyStorePassphrase) StoreKey(filename string, key Key, auth string) error { 102 keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP) 103 if err != nil { 104 return err 105 } 106 // Write into temporary file 107 tmpName, err := writeTemporaryKeyFile(filename, keyjson) 108 if err != nil { 109 return err 110 } 111 if ks.skipKeyFileVerification == false { // do not skip file verification 112 // Verify that we can decrypt the file with the given password. 113 _, err = ks.GetKey(key.GetAddress(), tmpName, auth) 114 if err != nil { 115 msg := "An error was encountered when saving and verifying the keystore file. \n" + 116 "This indicates that the keystore is corrupted. \n" + 117 "The corrupted file is stored at \n%v\n" + 118 "Please file a ticket at:\n\n" + 119 "https://github.com/klaytn/klaytn/issues" + 120 "The error was : %w" 121 return fmt.Errorf(msg, tmpName, err) 122 } 123 } 124 return os.Rename(tmpName, filename) 125 } 126 127 func (ks keyStorePassphrase) JoinPath(filename string) string { 128 if filepath.IsAbs(filename) { 129 return filename 130 } 131 return filepath.Join(ks.keysDirPath, filename) 132 } 133 134 // encryptCrypto encrypts a private key to a cryptoJSON object. 135 func encryptCrypto(keyBytes []byte, auth string, scryptN, scryptP int) (*cryptoJSON, error) { 136 authArray := []byte(auth) 137 138 salt := make([]byte, 32) 139 if _, err := io.ReadFull(rand.Reader, salt); err != nil { 140 panic("reading from crypto/rand failed: " + err.Error()) 141 } 142 derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) 143 if err != nil { 144 return nil, err 145 } 146 encryptKey := derivedKey[:16] 147 148 iv := make([]byte, aes.BlockSize) // 16 149 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 150 panic("reading from crypto/rand failed: " + err.Error()) 151 } 152 cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) 153 if err != nil { 154 return nil, err 155 } 156 mac := crypto.Keccak256(derivedKey[16:32], cipherText) 157 158 scryptParamsJSON := make(map[string]interface{}, 5) 159 scryptParamsJSON["n"] = scryptN 160 scryptParamsJSON["r"] = scryptR 161 scryptParamsJSON["p"] = scryptP 162 scryptParamsJSON["dklen"] = scryptDKLen 163 scryptParamsJSON["salt"] = hex.EncodeToString(salt) 164 165 cipherParamsJSON := cipherparamsJSON{ 166 IV: hex.EncodeToString(iv), 167 } 168 169 return &cryptoJSON{ 170 Cipher: "aes-128-ctr", 171 CipherText: hex.EncodeToString(cipherText), 172 CipherParams: cipherParamsJSON, 173 KDF: keyHeaderKDF, 174 KDFParams: scryptParamsJSON, 175 MAC: hex.EncodeToString(mac), 176 }, nil 177 } 178 179 // EncryptKey encrypts a key using the specified scrypt parameters into a json 180 // blob that can be decrypted later on. It uses the keystore v4 format. 181 func EncryptKey(key Key, auth string, scryptN, scryptP int) ([]byte, error) { 182 pks := key.GetPrivateKeys() 183 crypto := make([][]cryptoJSON, len(pks)) 184 for i, keys := range pks { 185 crypto[i] = make([]cryptoJSON, len(keys)) 186 for j, k := range keys { 187 keyBytes := math.PaddedBigBytes(k.D, 32) 188 c, err := encryptCrypto(keyBytes, auth, scryptN, scryptP) 189 if err != nil { 190 return nil, err 191 } 192 crypto[i][j] = *c 193 } 194 } 195 encryptedKeyJSONV4 := encryptedKeyJSONV4{ 196 hex.EncodeToString(key.GetAddress().Bytes()), 197 crypto, 198 key.GetId().String(), 199 4, 200 } 201 return json.Marshal(encryptedKeyJSONV4) 202 } 203 204 // EncryptKeyV3 encrypts a key using the specified scrypt parameters into a json 205 // blob that can be decrypted later on. It uses the keystore v3 format. 206 func EncryptKeyV3(key Key, auth string, scryptN, scryptP int) ([]byte, error) { 207 authArray := []byte(auth) 208 209 salt := make([]byte, 32) 210 if _, err := io.ReadFull(rand.Reader, salt); err != nil { 211 panic("reading from crypto/rand failed: " + err.Error()) 212 } 213 derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) 214 if err != nil { 215 return nil, err 216 } 217 encryptKey := derivedKey[:16] 218 keyBytes := math.PaddedBigBytes(key.GetPrivateKey().D, 32) 219 220 iv := make([]byte, aes.BlockSize) // 16 221 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 222 panic("reading from crypto/rand failed: " + err.Error()) 223 } 224 cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv) 225 if err != nil { 226 return nil, err 227 } 228 mac := crypto.Keccak256(derivedKey[16:32], cipherText) 229 230 scryptParamsJSON := make(map[string]interface{}, 5) 231 scryptParamsJSON["n"] = scryptN 232 scryptParamsJSON["r"] = scryptR 233 scryptParamsJSON["p"] = scryptP 234 scryptParamsJSON["dklen"] = scryptDKLen 235 scryptParamsJSON["salt"] = hex.EncodeToString(salt) 236 237 cipherParamsJSON := cipherparamsJSON{ 238 IV: hex.EncodeToString(iv), 239 } 240 241 cryptoStruct := cryptoJSON{ 242 Cipher: "aes-128-ctr", 243 CipherText: hex.EncodeToString(cipherText), 244 CipherParams: cipherParamsJSON, 245 KDF: keyHeaderKDF, 246 KDFParams: scryptParamsJSON, 247 MAC: hex.EncodeToString(mac), 248 } 249 encryptedKeyJSONV3 := encryptedKeyJSONV3{ 250 hex.EncodeToString(key.GetAddress().Bytes()), 251 cryptoStruct, 252 key.GetId().String(), 253 3, 254 } 255 return json.Marshal(encryptedKeyJSONV3) 256 } 257 258 // DecryptKey decrypts a key from a json blob, returning the private key itself. 259 // TODO: use encryptedKeyJSON object directly instead of double unmarshalling. 260 func DecryptKey(keyjson []byte, auth string) (Key, error) { 261 // Parse the json into a simple map to fetch the key version 262 m := make(map[string]interface{}) 263 if err := json.Unmarshal(keyjson, &m); err != nil { 264 return nil, err 265 } 266 // Depending on the version try to parse one way or another 267 var ( 268 keyBytes [][][]byte 269 keyId []byte 270 err error 271 address common.Address 272 ) 273 274 switch v := m["version"].(type) { 275 case string: 276 if v == "1" { 277 k := new(encryptedKeyJSONV1) 278 if err := json.Unmarshal(keyjson, k); err != nil { 279 return nil, err 280 } 281 keyBytes = make([][][]byte, 1) 282 keyBytes[0] = make([][]byte, 1) 283 keyBytes[0][0], keyId, err = decryptKeyV1(k, auth) 284 address = common.HexToAddress(k.Address) 285 } 286 287 case float64: 288 switch v { 289 case 3: 290 k := new(encryptedKeyJSONV3) 291 if err := json.Unmarshal(keyjson, k); err != nil { 292 return nil, err 293 } 294 keyBytes = make([][][]byte, 1) 295 keyBytes[0] = make([][]byte, 1) 296 keyBytes[0][0], keyId, err = decryptKeyV3(k, auth) 297 address = common.HexToAddress(k.Address) 298 case 4: 299 // At first, try to decrypt using encryptedKeyJSONV4 300 k := new(encryptedKeyJSONV4) 301 if err := json.Unmarshal(keyjson, k); err != nil { 302 // If it fails, try to decrypt using encryptedKeyJSONV4Single 303 kSingle := new(encryptedKeyJSONV4Single) 304 if err = json.Unmarshal(keyjson, kSingle); err != nil { 305 return nil, err 306 } 307 308 // If succeeded, copy the values of kSingle to k 309 k.Id = kSingle.Id 310 k.Address = kSingle.Address 311 k.Keyring = [][]cryptoJSON{kSingle.Keyring} 312 k.Version = kSingle.Version 313 } 314 315 keyBytes, keyId, err = decryptKeyV4(k, auth) 316 address = common.HexToAddress(k.Address) 317 default: 318 return nil, fmt.Errorf("undefined version: %f", v) 319 } 320 321 default: 322 return nil, fmt.Errorf("undefined type of version: %s", m) 323 } 324 325 // Handle any decryption errors and return the key 326 if err != nil { 327 return nil, err 328 } 329 privateKeys := make([][]*ecdsa.PrivateKey, len(keyBytes)) 330 for i, keys := range keyBytes { 331 privateKeys[i] = make([]*ecdsa.PrivateKey, len(keys)) 332 for j, key := range keys { 333 privateKeys[i][j], err = crypto.ToECDSA(key) 334 if err != nil { 335 return nil, err 336 } 337 } 338 } 339 340 return &KeyV4{ 341 Id: uuid.UUID(keyId), 342 Address: address, 343 PrivateKeys: privateKeys, 344 }, nil 345 } 346 347 func decryptKeyV4(keyProtected *encryptedKeyJSONV4, auth string) (keyBytes [][][]byte, keyId []byte, err error) { 348 if keyProtected.Version != 4 { 349 return nil, nil, fmt.Errorf("version not supported: %v (should be 4)", keyProtected.Version) 350 } 351 352 keyId = uuid.Parse(keyProtected.Id) 353 keyBytes = make([][][]byte, len(keyProtected.Keyring)) 354 355 for i, keys := range keyProtected.Keyring { 356 keyBytes[i] = make([][]byte, len(keys)) 357 for j, key := range keys { 358 keyBytes[i][j], err = decryptKey(key, auth) 359 if err != nil { 360 return nil, nil, err 361 } 362 } 363 } 364 365 return keyBytes, keyId, err 366 } 367 368 func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { 369 if keyProtected.Version != 3 { 370 return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) 371 } 372 keyId = uuid.Parse(keyProtected.Id) 373 374 plainText, err := decryptKey(keyProtected.Crypto, auth) 375 if err != nil { 376 return nil, nil, err 377 } 378 return plainText, keyId, err 379 } 380 381 func decryptKey(cryptoJson cryptoJSON, auth string) (keyBytes []byte, err error) { 382 if cryptoJson.Cipher != "aes-128-ctr" { 383 return nil, fmt.Errorf("Cipher not supported: %v", cryptoJson.Cipher) 384 } 385 386 mac, err := hex.DecodeString(cryptoJson.MAC) 387 if err != nil { 388 return nil, err 389 } 390 391 iv, err := hex.DecodeString(cryptoJson.CipherParams.IV) 392 if err != nil { 393 return nil, err 394 } 395 396 cipherText, err := hex.DecodeString(cryptoJson.CipherText) 397 if err != nil { 398 return nil, err 399 } 400 401 derivedKey, err := getKDFKey(cryptoJson, auth) 402 if err != nil { 403 return nil, err 404 } 405 406 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 407 if !bytes.Equal(calculatedMAC, mac) { 408 return nil, ErrDecrypt 409 } 410 411 plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv) 412 if err != nil { 413 return nil, err 414 } 415 416 return plainText, err 417 } 418 419 func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) { 420 keyId = uuid.Parse(keyProtected.Id) 421 mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 422 if err != nil { 423 return nil, nil, err 424 } 425 426 iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 427 if err != nil { 428 return nil, nil, err 429 } 430 431 cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 432 if err != nil { 433 return nil, nil, err 434 } 435 436 derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 437 if err != nil { 438 return nil, nil, err 439 } 440 441 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 442 if !bytes.Equal(calculatedMAC, mac) { 443 return nil, nil, ErrDecrypt 444 } 445 446 plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv) 447 if err != nil { 448 return nil, nil, err 449 } 450 return plainText, keyId, err 451 } 452 453 func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) { 454 authArray := []byte(auth) 455 salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) 456 if err != nil { 457 return nil, err 458 } 459 dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) 460 461 if cryptoJSON.KDF == keyHeaderKDF { 462 n := ensureInt(cryptoJSON.KDFParams["n"]) 463 r := ensureInt(cryptoJSON.KDFParams["r"]) 464 p := ensureInt(cryptoJSON.KDFParams["p"]) 465 return scrypt.Key(authArray, salt, n, r, p, dkLen) 466 467 } else if cryptoJSON.KDF == "pbkdf2" { 468 c := ensureInt(cryptoJSON.KDFParams["c"]) 469 prf := cryptoJSON.KDFParams["prf"].(string) 470 if prf != "hmac-sha256" { 471 return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) 472 } 473 key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) 474 return key, nil 475 } 476 477 return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) 478 } 479 480 // TODO: can we do without this when unmarshalling dynamic JSON? 481 // why do integers in KDF params end up as float64 and not int after 482 // unmarshal? 483 func ensureInt(x interface{}) int { 484 res, ok := x.(int) 485 if !ok { 486 res = int(x.(float64)) 487 } 488 return res 489 }