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