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