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  }