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