github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/accounts/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/rand" 32 "crypto/sha256" 33 "encoding/hex" 34 "encoding/json" 35 "fmt" 36 "io" 37 "io/ioutil" 38 "os" 39 "path/filepath" 40 41 "github.com/celo-org/bls-zexe/go" 42 "github.com/ethereum/go-ethereum/common" 43 "github.com/ethereum/go-ethereum/common/math" 44 "github.com/ethereum/go-ethereum/crypto" 45 "github.com/ethereum/go-ethereum/crypto/bls" 46 "github.com/pborman/uuid" 47 "golang.org/x/crypto/pbkdf2" 48 "golang.org/x/crypto/scrypt" 49 ) 50 51 const ( 52 keyHeaderKDF = "scrypt" 53 54 // StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB 55 // memory and taking approximately 1s CPU time on a modern processor. 56 StandardScryptN = 1 << 18 57 58 // StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB 59 // memory and taking approximately 1s CPU time on a modern processor. 60 StandardScryptP = 1 61 62 // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB 63 // memory and taking approximately 100ms CPU time on a modern processor. 64 LightScryptN = 1 << 12 65 66 // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB 67 // memory and taking approximately 100ms CPU time on a modern processor. 68 LightScryptP = 6 69 70 scryptR = 8 71 scryptDKLen = 32 72 ) 73 74 type keyStorePassphrase struct { 75 keysDirPath string 76 scryptN int 77 scryptP int 78 // skipKeyFileVerification disables the security-feature which does 79 // reads and decrypts any newly created keyfiles. This should be 'false' in all 80 // cases except tests -- setting this to 'true' is not recommended. 81 skipKeyFileVerification bool 82 } 83 84 func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) { 85 // Load the key from the keystore and decrypt its contents 86 keyjson, err := ioutil.ReadFile(filename) 87 if err != nil { 88 return nil, err 89 } 90 key, err := DecryptKey(keyjson, auth) 91 if err != nil { 92 return nil, err 93 } 94 // Make sure we're really operating on the requested key (no swap attacks) 95 if key.Address != addr { 96 return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr) 97 } 98 return key, nil 99 } 100 101 // StoreKey generates a key, encrypts with 'auth' and stores in the given directory 102 func StoreKey(dir, auth string, scryptN, scryptP int) (common.Address, error) { 103 _, a, err := storeNewKey(&keyStorePassphrase{dir, scryptN, scryptP, false}, rand.Reader, auth) 104 return a.Address, err 105 } 106 107 func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error { 108 keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP) 109 if err != nil { 110 return err 111 } 112 // Write into temporary file 113 tmpName, err := writeTemporaryKeyFile(filename, keyjson) 114 if err != nil { 115 return err 116 } 117 if !ks.skipKeyFileVerification { 118 // Verify that we can decrypt the file with the given password. 119 _, err = ks.GetKey(key.Address, tmpName, auth) 120 if err != nil { 121 msg := "An error was encountered when saving and verifying the keystore file. \n" + 122 "This indicates that the keystore is corrupted. \n" + 123 "The corrupted file is stored at \n%v\n" + 124 "Please file a ticket at:\n\n" + 125 "https://github.com/ethereum/go-ethereum/issues." + 126 "The error was : %s" 127 return fmt.Errorf(msg, tmpName, err) 128 } 129 } 130 return os.Rename(tmpName, filename) 131 } 132 133 func (ks keyStorePassphrase) JoinPath(filename string) string { 134 if filepath.IsAbs(filename) { 135 return filename 136 } 137 return filepath.Join(ks.keysDirPath, filename) 138 } 139 140 // Encryptdata encrypts the data given as 'data' with the password 'auth'. 141 func EncryptDataV3(data, auth []byte, scryptN, scryptP int) (CryptoJSON, error) { 142 143 salt := make([]byte, 32) 144 if _, err := io.ReadFull(rand.Reader, salt); err != nil { 145 panic("reading from crypto/rand failed: " + err.Error()) 146 } 147 derivedKey, err := scrypt.Key(auth, salt, scryptN, scryptR, scryptP, scryptDKLen) 148 if err != nil { 149 return CryptoJSON{}, err 150 } 151 encryptKey := derivedKey[:16] 152 153 iv := make([]byte, aes.BlockSize) // 16 154 if _, err := io.ReadFull(rand.Reader, iv); err != nil { 155 panic("reading from crypto/rand failed: " + err.Error()) 156 } 157 cipherText, err := aesCTRXOR(encryptKey, data, iv) 158 if err != nil { 159 return CryptoJSON{}, err 160 } 161 mac := crypto.Keccak256(derivedKey[16:32], cipherText) 162 163 scryptParamsJSON := make(map[string]interface{}, 5) 164 scryptParamsJSON["n"] = scryptN 165 scryptParamsJSON["r"] = scryptR 166 scryptParamsJSON["p"] = scryptP 167 scryptParamsJSON["dklen"] = scryptDKLen 168 scryptParamsJSON["salt"] = hex.EncodeToString(salt) 169 cipherParamsJSON := cipherparamsJSON{ 170 IV: hex.EncodeToString(iv), 171 } 172 173 cryptoStruct := CryptoJSON{ 174 Cipher: "aes-128-ctr", 175 CipherText: hex.EncodeToString(cipherText), 176 CipherParams: cipherParamsJSON, 177 KDF: keyHeaderKDF, 178 KDFParams: scryptParamsJSON, 179 MAC: hex.EncodeToString(mac), 180 } 181 return cryptoStruct, nil 182 } 183 184 // EncryptKey encrypts a key using the specified scrypt parameters into a json 185 // blob that can be decrypted later on. 186 func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { 187 keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 32) 188 blsPrivateKeyBytes, err := blscrypto.ECDSAToBLS(key.PrivateKey) 189 if err != nil { 190 return nil, err 191 } 192 privateKey, err := bls.DeserializePrivateKey(blsPrivateKeyBytes) 193 if err != nil { 194 return nil, err 195 } 196 defer privateKey.Destroy() 197 publicKey, err := privateKey.ToPublic() 198 if err != nil { 199 return nil, err 200 } 201 defer publicKey.Destroy() 202 publicKeyBytes, err := publicKey.Serialize() 203 if err != nil { 204 return nil, err 205 } 206 207 cryptoStruct, err := EncryptDataV3(keyBytes, []byte(auth), scryptN, scryptP) 208 if err != nil { 209 return nil, err 210 } 211 encryptedKeyJSONV3 := encryptedKeyJSONV3{ 212 hex.EncodeToString(key.Address[:]), 213 hex.EncodeToString(publicKeyBytes), 214 cryptoStruct, 215 key.Id.String(), 216 version, 217 } 218 return json.Marshal(encryptedKeyJSONV3) 219 } 220 221 // DecryptKey decrypts a key from a json blob, returning the private key itself. 222 func DecryptKey(keyjson []byte, auth string) (*Key, error) { 223 // Parse the json into a simple map to fetch the key version 224 m := make(map[string]interface{}) 225 if err := json.Unmarshal(keyjson, &m); err != nil { 226 return nil, err 227 } 228 // Depending on the version try to parse one way or another 229 var ( 230 keyBytes, keyId []byte 231 err error 232 ) 233 if version, ok := m["version"].(string); ok && version == "1" { 234 k := new(encryptedKeyJSONV1) 235 if err := json.Unmarshal(keyjson, k); err != nil { 236 return nil, err 237 } 238 keyBytes, keyId, err = decryptKeyV1(k, auth) 239 } else { 240 k := new(encryptedKeyJSONV3) 241 if err := json.Unmarshal(keyjson, k); err != nil { 242 return nil, err 243 } 244 keyBytes, keyId, err = decryptKeyV3(k, auth) 245 } 246 // Handle any decryption errors and return the key 247 if err != nil { 248 return nil, err 249 } 250 key := crypto.ToECDSAUnsafe(keyBytes) 251 252 return &Key{ 253 Id: uuid.UUID(keyId), 254 Address: crypto.PubkeyToAddress(key.PublicKey), 255 PrivateKey: key, 256 }, nil 257 } 258 259 func DecryptDataV3(cryptoJson CryptoJSON, auth string) ([]byte, error) { 260 if cryptoJson.Cipher != "aes-128-ctr" { 261 return nil, fmt.Errorf("Cipher not supported: %v", cryptoJson.Cipher) 262 } 263 mac, err := hex.DecodeString(cryptoJson.MAC) 264 if err != nil { 265 return nil, err 266 } 267 268 iv, err := hex.DecodeString(cryptoJson.CipherParams.IV) 269 if err != nil { 270 return nil, err 271 } 272 273 cipherText, err := hex.DecodeString(cryptoJson.CipherText) 274 if err != nil { 275 return nil, err 276 } 277 278 derivedKey, err := getKDFKey(cryptoJson, auth) 279 if err != nil { 280 return nil, err 281 } 282 283 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 284 if !bytes.Equal(calculatedMAC, mac) { 285 return nil, ErrDecrypt 286 } 287 288 plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv) 289 if err != nil { 290 return nil, err 291 } 292 return plainText, err 293 } 294 295 func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { 296 if keyProtected.Version != version { 297 return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) 298 } 299 keyId = uuid.Parse(keyProtected.Id) 300 plainText, err := DecryptDataV3(keyProtected.Crypto, auth) 301 if err != nil { 302 return nil, nil, err 303 } 304 return plainText, keyId, err 305 } 306 307 func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) { 308 keyId = uuid.Parse(keyProtected.Id) 309 mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 310 if err != nil { 311 return nil, nil, err 312 } 313 314 iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 315 if err != nil { 316 return nil, nil, err 317 } 318 319 cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 320 if err != nil { 321 return nil, nil, err 322 } 323 324 derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 325 if err != nil { 326 return nil, nil, err 327 } 328 329 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 330 if !bytes.Equal(calculatedMAC, mac) { 331 return nil, nil, ErrDecrypt 332 } 333 334 plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv) 335 if err != nil { 336 return nil, nil, err 337 } 338 return plainText, keyId, err 339 } 340 341 func getKDFKey(cryptoJSON CryptoJSON, auth string) ([]byte, error) { 342 authArray := []byte(auth) 343 salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) 344 if err != nil { 345 return nil, err 346 } 347 dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) 348 349 if cryptoJSON.KDF == keyHeaderKDF { 350 n := ensureInt(cryptoJSON.KDFParams["n"]) 351 r := ensureInt(cryptoJSON.KDFParams["r"]) 352 p := ensureInt(cryptoJSON.KDFParams["p"]) 353 return scrypt.Key(authArray, salt, n, r, p, dkLen) 354 355 } else if cryptoJSON.KDF == "pbkdf2" { 356 c := ensureInt(cryptoJSON.KDFParams["c"]) 357 prf := cryptoJSON.KDFParams["prf"].(string) 358 if prf != "hmac-sha256" { 359 return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) 360 } 361 key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) 362 return key, nil 363 } 364 365 return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) 366 } 367 368 // TODO: can we do without this when unmarshalling dynamic JSON? 369 // why do integers in KDF params end up as float64 and not int after 370 // unmarshal? 371 func ensureInt(x interface{}) int { 372 res, ok := x.(int) 373 if !ok { 374 res = int(x.(float64)) 375 } 376 return res 377 }