github.com/cranelv/ethereum_mpc@v0.0.0-20191031014521-23aeb1415092/accounts/keystore/mpcKeyStore.go (about)

     1  package keystore
     2  
     3  import (
     4  	"math/big"
     5  	"github.com/pborman/uuid"
     6  	"github.com/ethereum/go-ethereum/common"
     7  	"crypto/ecdsa"
     8  	"github.com/ethereum/go-ethereum/crypto"
     9  	"github.com/ethereum/go-ethereum/accounts"
    10  	"crypto/aes"
    11  	"encoding/hex"
    12  	"encoding/json"
    13  	"github.com/ethereum/go-ethereum/crypto/randentropy"
    14  	"golang.org/x/crypto/scrypt"
    15  	"github.com/ethereum/go-ethereum/common/math"
    16  	"errors"
    17  	"sync"
    18  	"path/filepath"
    19  	"io/ioutil"
    20  	"github.com/ethereum/go-ethereum/log"
    21  	"github.com/ethereum/go-ethereum/crypto/secp256k1"
    22  )
    23  var MpcKeyStoreScheme = "mpcKeystore"
    24  type MpcKey struct {
    25  	Id uuid.UUID // Version 4 "random" for unique id not derived from key data
    26  	// to simplify lookups we also store the address
    27  	Address common.MpcAddress
    28  	// we only store privkey as pubkey/address can be derived from it
    29  	// privkey in this struct is always in plaintext
    30  	PrivateKey *big.Int
    31  	//MPC
    32  	MPCSeed uint64
    33  	Quorum  uint64
    34  	MPCGroup []uint64
    35  
    36  }
    37  type encryptedMpcKeyJSONV3 struct {
    38  	Address string     `json:"address"`
    39  	Crypto  cryptoJSON `json:"crypto"`
    40  	Id      string     `json:"id"`
    41  	MPCSeed uint64	   `json:"mpcseed"`
    42  	Quorum  uint64	   `json:"quorum"`
    43  	MPCGroup []uint64	   `json:"mpcGroup"`
    44  	Version int        `json:"version"`
    45  }
    46  
    47  // EncryptKey encrypts a key using the specified scrypt parameters into a json
    48  // blob that can be decrypted later on.
    49  func (key* MpcKey)EncryptKey(auth string, scryptN, scryptP int) ([]byte, error) {
    50  	authArray := []byte(auth)
    51  	salt := randentropy.GetEntropyCSPRNG(32)
    52  	derivedKey, err := scrypt.Key(authArray, salt, scryptN, scryptR, scryptP, scryptDKLen)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  	encryptKey := derivedKey[:16]
    57  	keyBytes := math.PaddedBigBytes(key.PrivateKey, 32)
    58  
    59  	iv := randentropy.GetEntropyCSPRNG(aes.BlockSize) // 16
    60  	cipherText, err := aesCTRXOR(encryptKey, keyBytes, iv)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  	mac := crypto.Keccak256(derivedKey[16:32], cipherText)
    65  
    66  	scryptParamsJSON := make(map[string]interface{}, 5)
    67  	scryptParamsJSON["n"] = scryptN
    68  	scryptParamsJSON["r"] = scryptR
    69  	scryptParamsJSON["p"] = scryptP
    70  	scryptParamsJSON["dklen"] = scryptDKLen
    71  	scryptParamsJSON["salt"] = hex.EncodeToString(salt)
    72  
    73  	cipherParamsJSON := cipherparamsJSON{
    74  		IV: hex.EncodeToString(iv),
    75  	}
    76  
    77  	cryptoStruct := cryptoJSON{
    78  		Cipher:       "aes-128-ctr",
    79  		CipherText:   hex.EncodeToString(cipherText),
    80  		CipherParams: cipherParamsJSON,
    81  		KDF:          keyHeaderKDF,
    82  		KDFParams:    scryptParamsJSON,
    83  		MAC:          hex.EncodeToString(mac),
    84  	}
    85  	encryptedKeyJSONV3 := encryptedMpcKeyJSONV3{
    86  		hex.EncodeToString(key.Address[:]),
    87  		cryptoStruct,
    88  		key.Id.String(),
    89  		key.MPCSeed,
    90  		key.Quorum,
    91  		key.MPCGroup,
    92  		version,
    93  	}
    94  	return json.Marshal(encryptedKeyJSONV3)
    95  }
    96  func PubkeyToMpcAddress(p ecdsa.PublicKey) common.MpcAddress{
    97  	var addr common.MpcAddress
    98  	copy(addr[:],secp256k1.CompressPubkey(p.X,p.Y))
    99  	return addr
   100  }
   101  func newMpcKey(pKey *ecdsa.PublicKey, pShare *big.Int, seed uint64,quorum uint64,MPCGroup[]uint64) (*MpcKey, error) {
   102  	priv := new(ecdsa.PrivateKey)
   103  	priv.PublicKey.Curve = crypto.S256()
   104  	priv.D = pShare
   105  	priv.PublicKey.X, priv.PublicKey.Y = priv.PublicKey.Curve.ScalarBaseMult(pShare.Bytes())
   106  	id := uuid.NewRandom()
   107  
   108  	key := &MpcKey{
   109  		Id:         id,
   110  //		Address:    common.BytesToHash()secp256k1.CompressPubkey(pKey.X,pKey.Y),
   111  		PrivateKey: pShare,
   112  		MPCSeed:seed,
   113  		Quorum:quorum,
   114  		MPCGroup:MPCGroup,
   115  	}
   116  	copy(key.Address[:],secp256k1.CompressPubkey(pKey.X,pKey.Y))
   117  	//3 bytes for every seed
   118  	return key , nil
   119  }
   120  // DecryptKey decrypts a key from a json blob, returning the private key itself.
   121  func DecryptMpcKey(keyjson []byte, auth string) (*MpcKey, error) {
   122  	// Parse the json into a simple map to fetch the key version
   123  	m := make(map[string]interface{})
   124  	if err := json.Unmarshal(keyjson, &m); err != nil {
   125  		return nil, err
   126  	}
   127  	// Depending on the version try to parse one way or another
   128  	var (
   129  		keyBytes, keyId []byte
   130  		err             error
   131  	)
   132  	if version, ok := m["version"].(string); ok && version != "3" {
   133  		return nil,errors.New("version must equal 3")
   134  	}
   135  	k := new(encryptedMpcKeyJSONV3)
   136  	if err := json.Unmarshal(keyjson, k); err != nil {
   137  		return nil, err
   138  	}
   139  	k1 := encryptedKeyJSONV3{
   140  		k.Address,
   141  		k.Crypto,
   142  		k.Id,
   143  		k.Version,
   144  	}
   145  	keyBytes, keyId, err = decryptKeyV3(&k1, auth)
   146  	// Handle any decryption errors and return the key
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	key := crypto.ToECDSAUnsafe(keyBytes)
   151  
   152  	mpcKey := MpcKey{
   153  		Id:         uuid.UUID(keyId),
   154  //		Address:    common.HexToAddress(k.Address),
   155  		PrivateKey: key.D,
   156  		MPCSeed : k.MPCSeed,
   157  		Quorum: k.Quorum,
   158  		MPCGroup:k.MPCGroup,
   159  	}
   160  	copy(mpcKey.Address[:],common.FromHex(k.Address))
   161  	return &mpcKey,nil
   162  }
   163  //cranelv add storemanKey
   164  func storeMpcKey(ks keyStore, pKey *ecdsa.PublicKey, pShare *big.Int, seed uint64,quorum uint64,MPCGroup []uint64, passphrase string)(*MpcKey,accounts.MpcAccount,  error){
   165  	key, err := newMpcKey(pKey, pShare, seed,quorum,MPCGroup)
   166  	if err!= nil {
   167  		return nil,accounts.MpcAccount{}, err
   168  	}
   169  
   170  	a := accounts.MpcAccount{key.Address,accounts.URL{Scheme: MpcKeyStoreScheme, Path: ks.JoinPath(mpcKeyFileName(key.Address))}}
   171  	if err := ks.StoreMpcKey(a.URL.Path, key, passphrase); err != nil {
   172  		key.PrivateKey = big.NewInt(0)
   173  		return nil,a, err
   174  	}
   175  
   176  	return key,a, err
   177  }
   178  type MpcKeyStore struct {
   179  	mu sync.RWMutex
   180  	keyDir string
   181  	storage  keyStore                     // Storage backend, might be cleartext or encrypted
   182  	keyStoreFiles map[common.MpcAddress] string
   183  	unlocked map[common.MpcAddress]*MpcKey // Currently unlocked account (decrypted private keys)
   184  }
   185  func (mks* MpcKeyStore) UnlockAddress(address common.MpcAddress,password string)error{
   186  	mks.mu.Lock()
   187  	defer mks.mu.Unlock()
   188  	if _,exist := mks.unlocked[address];exist{
   189  		return nil
   190  	}
   191  	if file,exist := mks.keyStoreFiles[address];!exist{
   192  		return ErrNoMatch
   193  	}else{
   194  		key,err := mks.storage.GetMpcKey(address,file,password)
   195  		if err != nil{
   196  			return err
   197  		}
   198  		mks.unlocked[address] = key
   199  		return nil
   200  	}
   201  }
   202  func (mks* MpcKeyStore) init(keydir string){
   203  	mks.keyDir = keydir
   204  	err := mks.scan()
   205  	if err != nil{
   206  		log.Error("MpcKeyStore init Error","error",err)
   207  	}
   208  }
   209  
   210  // scan performs a new scan on the given directory, compares against the already
   211  // cached filenames, and returns file sets: creates, deletes, updates.
   212  func (mks* MpcKeyStore) scan() error {
   213  
   214  	// List all the failes from the keystore folder
   215  	files, err := ioutil.ReadDir(mks.keyDir)
   216  	if err != nil {
   217  		return err
   218  	}
   219  
   220  	for _, fi := range files {
   221  		// Skip any non-key files from the folder
   222  		path := filepath.Join(mks.keyDir, fi.Name())
   223  		if skipKeyFile(fi) {
   224  			log.Trace("Ignoring file on account scan", "path", path)
   225  			continue
   226  		}
   227  		keyjson, err := ioutil.ReadFile(path)
   228  		if err != nil {
   229  			return err
   230  		}
   231  		k := new(encryptedMpcKeyJSONV3)
   232  		if err := json.Unmarshal(keyjson, k); err != nil {
   233  			return err
   234  		}
   235  		mks.keyStoreFiles[common.HexToMpcAddress(k.Address)] = path
   236  	}
   237  	return nil
   238  }
   239  
   240  func (mks* MpcKeyStore) GetMpcKey(address common.MpcAddress)*MpcKey{
   241  	mks.mu.RLock()
   242  	defer mks.mu.RUnlock()
   243  	return mks.unlocked[address]
   244  }
   245  func (mks* MpcKeyStore)StoreMpcKey(pKey *ecdsa.PublicKey, pShare *big.Int, seed uint64,quorum uint64,mpcGroup []uint64, passphrase string)(common.MpcAddress,error){
   246  	_,acc,err := storeMpcKey(mks.storage,pKey,pShare,seed,quorum,mpcGroup,passphrase)
   247  	if err != nil{
   248  		return common.MpcAddress{},err
   249  	}
   250  	mks.mu.Lock()
   251  	defer mks.mu.Unlock()
   252  	mks.keyStoreFiles[acc.Address] = acc.URL.Path
   253  	return acc.Address,nil
   254  }
   255  func NewMpcKeyStore(keydir string) *MpcKeyStore {
   256  	keydir, _ = filepath.Abs(keydir)
   257  	ks := &MpcKeyStore{storage: &keyStorePassphrase{keydir, LightScryptN, LightScryptP},
   258  	keyStoreFiles:make(map[common.MpcAddress] string),
   259  	unlocked:make(map[common.MpcAddress]*MpcKey)}
   260  	ks.init(keydir)
   261  	return ks
   262  }