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