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