github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/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  	"crypto/ecdsa"
    32  	"crypto/sha256"
    33  	"encoding/hex"
    34  	"encoding/json"
    35  	"errors"
    36  	"fmt"
    37  	"io/ioutil"
    38  	"path/filepath"
    39  
    40  	"github.com/pborman/uuid"
    41  	"github.com/wanchain/go-wanchain/common"
    42  	"github.com/wanchain/go-wanchain/common/math"
    43  	"github.com/wanchain/go-wanchain/crypto"
    44  	"github.com/wanchain/go-wanchain/crypto/randentropy"
    45  	"golang.org/x/crypto/pbkdf2"
    46  	"golang.org/x/crypto/scrypt"
    47  )
    48  
    49  const (
    50  	keyHeaderKDF = "scrypt"
    51  
    52  	// StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB
    53  	// memory and taking approximately 1s CPU time on a modern processor.
    54  	StandardScryptN = 1 << 18
    55  
    56  	// StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB
    57  	// memory and taking approximately 1s CPU time on a modern processor.
    58  	StandardScryptP = 1
    59  
    60  	// LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB
    61  	// memory and taking approximately 100ms CPU time on a modern processor.
    62  	LightScryptN = 1 << 12
    63  
    64  	// LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB
    65  	// memory and taking approximately 100ms CPU time on a modern processor.
    66  	LightScryptP = 6
    67  
    68  	scryptR     = 8
    69  	scryptDKLen = 32
    70  )
    71  
    72  type keyStorePassphrase struct {
    73  	keysDirPath string
    74  	scryptN     int
    75  	scryptP     int
    76  }
    77  
    78  var (
    79  	ErrWAddressFieldNotExist = errors.New("It seems that this account doesn't include a valid wanchain address field, please update your keyfile version")
    80  	ErrWAddressInvalid       = errors.New("invalid wanchain address")
    81  	ErrInvalidAccountKey     = errors.New("invalid account key")
    82  	ErrInvalidPrivateKey     = errors.New("invalid private key")
    83  )
    84  
    85  func (ks keyStorePassphrase) GetKey(addr common.Address, filename, auth string) (*Key, error) {
    86  	// Load the key from the keystore and decrypt its contents
    87  	keyjson, err := ioutil.ReadFile(filename)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	key, err := DecryptKey(keyjson, auth)
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	// Make sure we're really operating on the requested key (no swap attacks)
    96  	if key.Address != addr {
    97  		return nil, fmt.Errorf("key content mismatch: have account %x, want %x", key.Address, addr)
    98  	}
    99  	return key, nil
   100  }
   101  
   102  func (ks keyStorePassphrase) StoreKey(filename string, key *Key, auth string) error {
   103  	keyjson, err := EncryptKey(key, auth, ks.scryptN, ks.scryptP)
   104  	if err != nil {
   105  		return err
   106  	}
   107  	return writeKeyFile(filename, keyjson)
   108  }
   109  
   110  // Implements GetEncryptedKey method of keystore interface
   111  func (ks keyStorePassphrase) GetEncryptedKey(a common.Address, filename string) (*Key, error) {
   112  	// load the encrypted json keyfile
   113  	keyjson, err := ioutil.ReadFile(filename)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	key, err := GenerateKeyWithWAddress(keyjson)
   118  	if err != nil {
   119  		return nil, err
   120  	}
   121  	key.Address = a
   122  	return key, nil
   123  }
   124  
   125  // Generate a Key initialized with WAddress field
   126  func GenerateKeyWithWAddress(keyjson []byte) (*Key, error) {
   127  	// parse the json blob into a simple map to fetch the key version
   128  	m := make(map[string]interface{})
   129  	if err := json.Unmarshal(keyjson, &m); err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	waddress, ok := m["waddress"].(string)
   134  
   135  	if !ok || waddress == "" {
   136  		return nil, ErrWAddressFieldNotExist
   137  	}
   138  
   139  	waddressRaw, err := hex.DecodeString(waddress)
   140  	if err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	if len(waddressRaw) != common.WAddressLength {
   145  		return nil, ErrWAddressInvalid
   146  	}
   147  
   148  	key := new(Key)
   149  	copy(key.WAddress[:], waddressRaw)
   150  	return key, nil
   151  }
   152  
   153  func (ks keyStorePassphrase) JoinPath(filename string) string {
   154  	if filepath.IsAbs(filename) {
   155  		return filename
   156  	} else {
   157  		return filepath.Join(ks.keysDirPath, filename)
   158  	}
   159  }
   160  
   161  // EncryptKey encrypts a key using the specified scrypt parameters into a json
   162  // blob that can be decrypted later on.
   163  func EncryptKey(key *Key, auth string, scryptN, scryptP int) ([]byte, error) {
   164  	if key == nil {
   165  		return nil, ErrInvalidAccountKey
   166  	}
   167  
   168  	cryptoStruct, err := EncryptOnePrivateKey(key.PrivateKey, auth, scryptN, scryptP)
   169  	if err != nil {
   170  		return nil, err
   171  	}
   172  
   173  	cryptoStruct2, err := EncryptOnePrivateKey(key.PrivateKey2, auth, scryptN, scryptP)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  
   178  	encryptedKeyJSONV3 := encryptedKeyJSONV3{
   179  		key.Address.Hex()[2:],
   180  		*cryptoStruct,
   181  		*cryptoStruct2,
   182  		key.Id.String(),
   183  		version,
   184  		hex.EncodeToString(key.WAddress[:]),
   185  	}
   186  	return json.Marshal(encryptedKeyJSONV3)
   187  }
   188  
   189  // EncryptOnePrivateKey encrypts a key using the specified scrypt parameters into one field of a json
   190  // blob that can be decrypted later on.
   191  func EncryptOnePrivateKey(privateKey *ecdsa.PrivateKey, auth string, scryptN, scryptP int) (*cryptoJSON, error) {
   192  	if privateKey == nil {
   193  		return nil, ErrInvalidPrivateKey
   194  	}
   195  
   196  	authArray := []byte(auth)
   197  	salt := randentropy.GetEntropyCSPRNG(32)
   198  	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen)
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  
   203  	encryptKey := derivedKey[:16]
   204  	keyBytes := math.PaddedBigBytes(privateKey.D, 32)
   205  
   206  	iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
   207  
   208  	cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  	mac := crypto.Keccak256(derivedKey[16:32], cipherText)
   213  
   214  	scryptParamsJSON := make(map[string]interface{}, 5)
   215  	scryptParamsJSON["n"] = scryptN
   216  	scryptParamsJSON["r"] = scryptR
   217  	scryptParamsJSON["p"] = scryptP
   218  	scryptParamsJSON["dklen"] = scryptDKLen
   219  	scryptParamsJSON["salt"] = hex.EncodeToString(salt)
   220  
   221  	cipherParamsJSON := cipherparamsJSON{
   222  		IV: hex.EncodeToString(iv),
   223  	}
   224  
   225  	cryptoStruct := &cryptoJSON{
   226  		Cipher:       "aes-128-ctr",
   227  		CipherText:   hex.EncodeToString(cipherText),
   228  		CipherParams: cipherParamsJSON,
   229  		KDF:          keyHeaderKDF,
   230  		KDFParams:    scryptParamsJSON,
   231  		MAC:          hex.EncodeToString(mac),
   232  	}
   233  
   234  	return cryptoStruct, nil
   235  
   236  }
   237  
   238  // DecryptKey decrypts a key from a json blob, returning the private key itself.
   239  func DecryptKey(keyjson []byte, auth string) (*Key, error) {
   240  	// Parse the json into a simple map to fetch the key version
   241  	m := make(map[string]interface{})
   242  	if err := json.Unmarshal(keyjson, &m); err != nil {
   243  		return nil, err
   244  	}
   245  	// Depending on the version try to parse one way or another
   246  	var (
   247  		keyBytes, keyBytes2, keyId []byte
   248  		err                        error
   249  		waddressStr                *string
   250  	)
   251  	if version, ok := m["version"].(string); ok && version == "1" {
   252  		k := new(encryptedKeyJSONV1)
   253  		if err := json.Unmarshal(keyjson, k); err != nil {
   254  			return nil, err
   255  		}
   256  
   257  		keyBytes, keyId, err = decryptKeyV1(k, auth)
   258  		key, err := crypto.ToECDSA(keyBytes)
   259  		if err != nil || key == nil {
   260  			return nil, err
   261  		}
   262  
   263  		return &Key{
   264  			Id:         uuid.UUID(keyId),
   265  			Address:    crypto.PubkeyToAddress(key.PublicKey),
   266  			PrivateKey: key,
   267  		}, nil
   268  	} else {
   269  		k := new(encryptedKeyJSONV3)
   270  		if err := json.Unmarshal(keyjson, k); err != nil {
   271  			return nil, err
   272  		}
   273  		keyBytes, keyBytes2, keyId, err = decryptKeyV3(k, auth)
   274  		if err != nil {
   275  			return nil, err
   276  		}
   277  
   278  		waddressStr = &k.WAddress
   279  	}
   280  
   281  	key, err := crypto.ToECDSA(keyBytes)
   282  	if err != nil || key == nil {
   283  		return nil, ErrInvalidPrivateKey
   284  	}
   285  
   286  	key2, err := crypto.ToECDSA(keyBytes2)
   287  	if err != nil || key2 == nil {
   288  		return nil, ErrInvalidPrivateKey
   289  	}
   290  
   291  	waddressRaw, err := hex.DecodeString(*waddressStr)
   292  	if err != nil {
   293  		return nil, err
   294  	}
   295  
   296  	var waddress common.WAddress
   297  	copy(waddress[:], waddressRaw)
   298  
   299  	return &Key{
   300  		Id:          uuid.UUID(keyId),
   301  		Address:     crypto.PubkeyToAddress(key.PublicKey),
   302  		PrivateKey:  key,
   303  		PrivateKey2: key2,
   304  		WAddress:    waddress,
   305  	}, nil
   306  }
   307  
   308  func decryptKeyV3(keyProtected *encryptedKeyJSONV3, auth string) (keyBytes []byte, keyBytes2 []byte, keyId []byte, err error) {
   309  	if keyProtected.Version != version {
   310  		return nil, nil, nil, fmt.Errorf("Version not supported: %v", keyProtected.Version)
   311  	}
   312  
   313  	keyId = uuid.Parse(keyProtected.Id)
   314  
   315  	plainText, err := decryptKeyV3Item(keyProtected.Crypto, auth)
   316  	if err != nil {
   317  		return nil, nil, nil, err
   318  	}
   319  
   320  	plainText2, err2 := decryptKeyV3Item(keyProtected.Crypto2, auth)
   321  	if err2 != nil {
   322  		if "" == keyProtected.Crypto2.Cipher {
   323  			plainText2 = make([]byte, 0)
   324  		} else {
   325  			return nil, nil, nil, err2
   326  		}
   327  	}
   328  
   329  	return plainText, plainText2, keyId, err
   330  }
   331  
   332  func decryptKeyV3Item(cryptoItem cryptoJSON, auth string) (keyBytes []byte, err error) {
   333  	if cryptoItem.Cipher != "aes-128-ctr" {
   334  		return nil, fmt.Errorf("Cipher not supported: %v", cryptoItem.Cipher)
   335  	}
   336  
   337  	mac, err := hex.DecodeString(cryptoItem.MAC)
   338  	if err != nil {
   339  		return nil, err
   340  	}
   341  
   342  	iv, err := hex.DecodeString(cryptoItem.CipherParams.IV)
   343  	if err != nil {
   344  		return nil, err
   345  	}
   346  
   347  	cipherText, err := hex.DecodeString(cryptoItem.CipherText)
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  
   352  	derivedKey, err := getKDFKey(cryptoItem, auth)
   353  	if err != nil {
   354  		return nil, err
   355  	}
   356  
   357  	calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
   358  	if !bytes.Equal(calculatedMAC, mac) {
   359  		return nil, ErrDecrypt
   360  	}
   361  
   362  	plainText, err := aesCTRXOR(derivedKey[:16], cipherText, iv)
   363  	if err != nil {
   364  		return nil, err
   365  	}
   366  
   367  	return plainText, err
   368  }
   369  
   370  func decryptKeyV1(keyProtected *encryptedKeyJSONV1, auth string) (keyBytes []byte, keyId []byte, err error) {
   371  	keyId = uuid.Parse(keyProtected.Id)
   372  	mac, err := hex.DecodeString(keyProtected.Crypto.MAC)
   373  	if err != nil {
   374  		return nil, nil, err
   375  	}
   376  
   377  	iv, err := hex.DecodeString(keyProtected.Crypto.CipherParams.IV)
   378  	if err != nil {
   379  		return nil, nil, err
   380  	}
   381  
   382  	cipherText, err := hex.DecodeString(keyProtected.Crypto.CipherText)
   383  	if err != nil {
   384  		return nil, nil, err
   385  	}
   386  
   387  	derivedKey, err := getKDFKey(keyProtected.Crypto, auth)
   388  	if err != nil {
   389  		return nil, nil, err
   390  	}
   391  
   392  	calculatedMAC := crypto.Keccak256(derivedKey[16:32], cipherText)
   393  	if !bytes.Equal(calculatedMAC, mac) {
   394  		return nil, nil, ErrDecrypt
   395  	}
   396  
   397  	plainText, err := aesCBCDecrypt(crypto.Keccak256(derivedKey[:16])[:16], cipherText, iv)
   398  	if err != nil {
   399  		return nil, nil, err
   400  	}
   401  	return plainText, keyId, err
   402  }
   403  
   404  func getKDFKey(cryptoJSON cryptoJSON, auth string) ([]byte, error) {
   405  	authArray := []byte(auth)
   406  	salt, err := hex.DecodeString(cryptoJSON.KDFParams["salt"].(string))
   407  	if err != nil {
   408  		return nil, err
   409  	}
   410  	dkLen := ensureInt(cryptoJSON.KDFParams["dklen"])
   411  
   412  	if cryptoJSON.KDF == keyHeaderKDF {
   413  		n := ensureInt(cryptoJSON.KDFParams["n"])
   414  		r := ensureInt(cryptoJSON.KDFParams["r"])
   415  		p := ensureInt(cryptoJSON.KDFParams["p"])
   416  		return scrypt.Key(authArray, salt, n, r, p, dkLen)
   417  
   418  	} else if cryptoJSON.KDF == "pbkdf2" {
   419  		c := ensureInt(cryptoJSON.KDFParams["c"])
   420  		prf := cryptoJSON.KDFParams["prf"].(string)
   421  		if prf != "hmac-sha256" {
   422  			return nil, fmt.Errorf("Unsupported PBKDF2 PRF: %s", prf)
   423  		}
   424  		key := pbkdf2.Key(authArray, salt, c, dkLen, sha256.New)
   425  		return key, nil
   426  	}
   427  
   428  	return nil, fmt.Errorf("Unsupported KDF: %s", cryptoJSON.KDF)
   429  }
   430  
   431  // TODO: can we do without this when unmarshalling dynamic JSON?
   432  // why do integers in KDF params end up as float64 and not int after
   433  // unmarshal?
   434  func ensureInt(x interface{}) int {
   435  	res, ok := x.(int)
   436  	if !ok {
   437  		res = int(x.(float64))
   438  	}
   439  	return res
   440  }