github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/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-wtc 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-wtc 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/wtc/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/wtc/go-wtc/common" 39 "github.com/wtc/go-wtc/common/math" 40 "github.com/wtc/go-wtc/crypto" 41 "github.com/wtc/go-wtc/crypto/randentropy" 42 "github.com/pborman/uuid" 43 "golang.org/x/crypto/pbkdf2" 44 "golang.org/x/crypto/scrypt" 45 ) 46 47 const ( 48 keyHeaderKDF = "scrypt" 49 50 // StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB 51 // memory and taking approximately 1s CPU time on a modern processor. 52 StandardScryptN = 1 << 18 53 54 // StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB 55 // memory and taking approximately 1s CPU time on a modern processor. 56 StandardScryptP = 1 57 58 // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB 59 // memory and taking approximately 100ms CPU time on a modern processor. 60 LightScryptN = 1 << 12 61 62 // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB 63 // memory and taking approximately 100ms CPU time on a modern processor. 64 LightScryptP = 6 65 66 scryptR = 8 67 scryptDKLen = 32 68 ) 69 70 type keyStorePassphrase struct { 71 keysDirPath string 72 scryptN int 73 scryptP int 74 } 75 76 func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) { 77 // Load the key from the keystore and decrypt its contents 78 keyjson, err := ioutil.ReadFile(filename) 79 if err != nil { 80 return nil, err 81 } 82 key, err := DecryptKey(keyjson, auth) 83 if err != nil { 84 return nil, err 85 } 86 // Make sure we're really operating on the requested key (no swap attacks) 87 if key.Address != addr { 88 return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr) 89 } 90 return key, nil 91 } 92 93 func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error { 94 keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP) 95 if err != nil { 96 return err 97 } 98 return writeKeyFile(filename, keyjson) 99 } 100 101 func (ks keyStorePassphrase) JoinPath(filename string) string { 102 if filepath.IsAbs(filename) { 103 return filename 104 } else { 105 return filepath.Join(ks.keysDirPath, filename) 106 } 107 } 108 109 // EncryptKey encrypts a key using the specified scrypt parameters into a json 110 // blob that can be decrypted later on. 111 func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) { 112 authArray := []byte(auth) 113 salt := randentropy.GetEntropyCSPRNG(32) 114 derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen) 115 if err != nil { 116 return nil, err 117 } 118 encryptKey := derivedKey[:16] 119 keyBytes := math.PaddedBigBytes(key.PrivateKey.D, 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: keyHeaderKDF, 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.ToECDSAUnsafe(keyBytes) 186 187 return &Key{ 188 Id: uuid.UUID(keyId), 189 Address: crypto.PubkeyToAddress(key.PublicKey), 190 PrivateKey: key, 191 }, nil 192 } 193 194 func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyId []byte, err error) { 195 if keyProtected.Version != version { 196 return nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version) 197 } 198 199 if keyProtected.Crypto.Cipher != "aes-128-ctr" { 200 return nil, nil, fmt.Errorf("Cipher not supported: %v", keyProtected.Crypto.Cipher) 201 } 202 203 keyId = uuid.Parse(keyProtected.Id) 204 mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 205 if err != nil { 206 return nil, nil, err 207 } 208 209 iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 210 if err != nil { 211 return nil, nil, err 212 } 213 214 cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 215 if err != nil { 216 return nil, nil, err 217 } 218 219 derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 220 if err != nil { 221 return nil, nil, err 222 } 223 224 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 225 if !bytes.Equal(calculatedMAC, mac) { 226 return nil, nil, ErrDecrypt 227 } 228 229 plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv) 230 if err != nil { 231 return nil, nil, err 232 } 233 return plainText, keyId, err 234 } 235 236 func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) { 237 keyId = uuid.Parse(keyProtected.Id) 238 mac, err := hex.DecodeString(keyProtected.Crypto.MAC) 239 if err != nil { 240 return nil, nil, err 241 } 242 243 iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV) 244 if err != nil { 245 return nil, nil, err 246 } 247 248 cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText) 249 if err != nil { 250 return nil, nil, err 251 } 252 253 derivedKey, err := getKDFKey(keyProtected.Crypto, auth) 254 if err != nil { 255 return nil, nil, err 256 } 257 258 calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText) 259 if !bytes.Equal(calculatedMAC, mac) { 260 return nil, nil, ErrDecrypt 261 } 262 263 plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv) 264 if err != nil { 265 return nil, nil, err 266 } 267 return plainText, keyId, err 268 } 269 270 func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) { 271 authArray := []byte(auth) 272 salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string)) 273 if err != nil { 274 return nil, err 275 } 276 dkLen := ensureInt(cryptoJSON.KDFParams["dklen"]) 277 278 if cryptoJSON.KDF == keyHeaderKDF { 279 n := ensureInt(cryptoJSON.KDFParams["n"]) 280 r := ensureInt(cryptoJSON.KDFParams["r"]) 281 p := ensureInt(cryptoJSON.KDFParams["p"]) 282 return scrypt.Key(authArray, salt, n, r, p, dkLen) 283 284 } else if cryptoJSON.KDF == "pbkdf2" { 285 c := ensureInt(cryptoJSON.KDFParams["c"]) 286 prf := cryptoJSON.KDFParams["prf"].(string) 287 if prf != "hmac-sha256" { 288 return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf) 289 } 290 key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New) 291 return key, nil 292 } 293 294 return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF) 295 } 296 297 // TODO: can we do without this when unmarshalling dynamic JSON? 298 // why do integers in KDF params end up as float64 and not int after 299 // unmarshal? 300 func ensureInt(x interface{}) int { 301 res, ok := x.(int) 302 if !ok { 303 res = int(x.(float64)) 304 } 305 return res 306 }