github.com/prysmaticlabs/prysm@v1.4.4/shared/keystore/key.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // Modified by Prysmatic Labs 2018 5 // 6 // The go-ethereum library is free software: you can redistribute it and/or modify 7 // it under the terms of the GNU Lesser General Public License as published by 8 // the Free Software Foundation, either version 3 of the License, or 9 // (at your option) any later version. 10 // 11 // The go-ethereum library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU Lesser General Public License for more details. 15 // 16 // You should have received a copy of the GNU Lesser General Public License 17 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 18 19 package keystore 20 21 import ( 22 "encoding/hex" 23 "encoding/json" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 28 "github.com/pborman/uuid" 29 "github.com/prysmaticlabs/prysm/shared/bls" 30 "github.com/prysmaticlabs/prysm/shared/fileutil" 31 ) 32 33 const ( 34 keyHeaderKDF = "scrypt" 35 36 // LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB 37 // memory and taking approximately 100ms CPU time on a modern processor. 38 LightScryptN = 1 << 12 39 40 // LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB 41 // memory and taking approximately 100ms CPU time on a modern processor. 42 LightScryptP = 6 43 44 scryptR = 8 45 scryptDKLen = 32 46 ) 47 48 // Key is the object that stores all the user data related to their public/secret keys. 49 type Key struct { 50 ID uuid.UUID // Version 4 "random" for unique id not derived from key data 51 52 PublicKey bls.PublicKey // Represents the public key of the user. 53 54 SecretKey bls.SecretKey // Represents the private key of the user. 55 } 56 57 type keyStore interface { 58 // GetKey loads and decrypts the key from disk. 59 GetKey(filename string, password string) (*Key, error) 60 // StoreKey writes and encrypts the key. 61 StoreKey(filename string, k *Key, auth string) error 62 // JoinPath joins filename with the key directory unless it is already absolute. 63 JoinPath(filename string) string 64 } 65 66 type plainKeyJSON struct { 67 PublicKey string `json:"address"` 68 SecretKey string `json:"privatekey"` 69 ID string `json:"id"` 70 } 71 72 type encryptedKeyJSON struct { 73 PublicKey string `json:"publickey"` 74 Crypto cryptoJSON `json:"crypto"` 75 ID string `json:"id"` 76 } 77 78 type cryptoJSON struct { 79 Cipher string `json:"cipher"` 80 CipherText string `json:"ciphertext"` 81 CipherParams cipherparamsJSON `json:"cipherparams"` 82 KDF string `json:"kdf"` 83 KDFParams map[string]interface{} `json:"kdfparams"` 84 MAC string `json:"mac"` 85 } 86 87 type cipherparamsJSON struct { 88 IV string `json:"iv"` 89 } 90 91 // MarshalJSON marshals a key struct into a JSON blob. 92 func (k *Key) MarshalJSON() (j []byte, err error) { 93 jStruct := plainKeyJSON{ 94 hex.EncodeToString(k.PublicKey.Marshal()), 95 hex.EncodeToString(k.SecretKey.Marshal()), 96 k.ID.String(), 97 } 98 j, err = json.Marshal(jStruct) 99 return j, err 100 } 101 102 // UnmarshalJSON unmarshals a blob into a key struct. 103 func (k *Key) UnmarshalJSON(j []byte) (err error) { 104 keyJSON := new(plainKeyJSON) 105 err = json.Unmarshal(j, &keyJSON) 106 if err != nil { 107 return err 108 } 109 110 u := new(uuid.UUID) 111 *u = uuid.Parse(keyJSON.ID) 112 k.ID = *u 113 pubkey, err := hex.DecodeString(keyJSON.PublicKey) 114 if err != nil { 115 return err 116 } 117 seckey, err := hex.DecodeString(keyJSON.SecretKey) 118 if err != nil { 119 return err 120 } 121 122 k.PublicKey, err = bls.PublicKeyFromBytes(pubkey) 123 if err != nil { 124 return err 125 } 126 k.SecretKey, err = bls.SecretKeyFromBytes(seckey) 127 if err != nil { 128 return err 129 } 130 return nil 131 } 132 133 // NewKeyFromBLS creates a new keystore Key type using a BLS private key. 134 func NewKeyFromBLS(blsKey bls.SecretKey) (*Key, error) { 135 id := uuid.NewRandom() 136 pubkey := blsKey.PublicKey() 137 key := &Key{ 138 ID: id, 139 PublicKey: pubkey, 140 SecretKey: blsKey, 141 } 142 return key, nil 143 } 144 145 // NewKey generates a new random key. 146 func NewKey() (*Key, error) { 147 secretKey, err := bls.RandKey() 148 if err != nil { 149 return nil, err 150 } 151 return NewKeyFromBLS(secretKey) 152 } 153 154 func storeNewRandomKey(ks keyStore, password string) error { 155 key, err := NewKey() 156 if err != nil { 157 return err 158 } 159 return ks.StoreKey(ks.JoinPath(keyFileName(key.PublicKey)), key, password) 160 } 161 162 func writeKeyFile(file string, content []byte) error { 163 // Create the keystore directory with appropriate permissions 164 // in case it is not present yet. 165 if err := fileutil.MkdirAll(filepath.Dir(file)); err != nil { 166 return err 167 } 168 // Atomic write: create a temporary hidden file first 169 // then move it into place. TempFile assigns mode 0600. 170 f, err := ioutil.TempFile(filepath.Dir(file), "."+filepath.Base(file)+".tmp") 171 if err != nil { 172 return err 173 } 174 if _, err := f.Write(content); err != nil { 175 newErr := f.Close() 176 if newErr != nil { 177 err = newErr 178 } 179 newErr = os.Remove(f.Name()) 180 if newErr != nil { 181 err = newErr 182 } 183 return err 184 } 185 if err := f.Close(); err != nil { 186 return err 187 } 188 return os.Rename(f.Name(), file) 189 }