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