github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/swarm/api/act.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:46</date>
    10  //</624342668259889152>
    11  
    12  package api
    13  
    14  import (
    15  	"context"
    16  	"crypto/ecdsa"
    17  	"crypto/rand"
    18  	"encoding/hex"
    19  	"encoding/json"
    20  	"errors"
    21  	"fmt"
    22  	"io"
    23  	"strings"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/crypto"
    28  	"github.com/ethereum/go-ethereum/crypto/ecies"
    29  	"github.com/ethereum/go-ethereum/crypto/sha3"
    30  	"github.com/ethereum/go-ethereum/swarm/log"
    31  	"github.com/ethereum/go-ethereum/swarm/sctx"
    32  	"github.com/ethereum/go-ethereum/swarm/storage"
    33  	"golang.org/x/crypto/scrypt"
    34  	cli "gopkg.in/urfave/cli.v1"
    35  )
    36  
    37  var (
    38  	ErrDecrypt                = errors.New("cant decrypt - forbidden")
    39  	ErrUnknownAccessType      = errors.New("unknown access type (or not implemented)")
    40  	ErrDecryptDomainForbidden = errors.New("decryption request domain forbidden - can only decrypt on localhost")
    41  	AllowedDecryptDomains     = []string{
    42  		"localhost",
    43  		"127.0.0.1",
    44  	}
    45  )
    46  
    47  const EMPTY_CREDENTIALS = ""
    48  
    49  type AccessEntry struct {
    50  	Type      AccessType
    51  	Publisher string
    52  	Salt      []byte
    53  	Act       string
    54  	KdfParams *KdfParams
    55  }
    56  
    57  type DecryptFunc func(*ManifestEntry) error
    58  
    59  func (a *AccessEntry) MarshalJSON() (out []byte, err error) {
    60  
    61  	return json.Marshal(struct {
    62  		Type      AccessType `json:"type,omitempty"`
    63  		Publisher string     `json:"publisher,omitempty"`
    64  		Salt      string     `json:"salt,omitempty"`
    65  		Act       string     `json:"act,omitempty"`
    66  		KdfParams *KdfParams `json:"kdf_params,omitempty"`
    67  	}{
    68  		Type:      a.Type,
    69  		Publisher: a.Publisher,
    70  		Salt:      hex.EncodeToString(a.Salt),
    71  		Act:       a.Act,
    72  		KdfParams: a.KdfParams,
    73  	})
    74  
    75  }
    76  
    77  func (a *AccessEntry) UnmarshalJSON(value []byte) error {
    78  	v := struct {
    79  		Type      AccessType `json:"type,omitempty"`
    80  		Publisher string     `json:"publisher,omitempty"`
    81  		Salt      string     `json:"salt,omitempty"`
    82  		Act       string     `json:"act,omitempty"`
    83  		KdfParams *KdfParams `json:"kdf_params,omitempty"`
    84  	}{}
    85  
    86  	err := json.Unmarshal(value, &v)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	a.Act = v.Act
    91  	a.KdfParams = v.KdfParams
    92  	a.Publisher = v.Publisher
    93  	a.Salt, err = hex.DecodeString(v.Salt)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	if len(a.Salt) != 32 {
    98  		return errors.New("salt should be 32 bytes long")
    99  	}
   100  	a.Type = v.Type
   101  	return nil
   102  }
   103  
   104  type KdfParams struct {
   105  	N int `json:"n"`
   106  	P int `json:"p"`
   107  	R int `json:"r"`
   108  }
   109  
   110  type AccessType string
   111  
   112  const AccessTypePass = AccessType("pass")
   113  const AccessTypePK = AccessType("pk")
   114  const AccessTypeACT = AccessType("act")
   115  
   116  func NewAccessEntryPassword(salt []byte, kdfParams *KdfParams) (*AccessEntry, error) {
   117  	if len(salt) != 32 {
   118  		return nil, fmt.Errorf("salt should be 32 bytes long")
   119  	}
   120  	return &AccessEntry{
   121  		Type:      AccessTypePass,
   122  		Salt:      salt,
   123  		KdfParams: kdfParams,
   124  	}, nil
   125  }
   126  
   127  func NewAccessEntryPK(publisher string, salt []byte) (*AccessEntry, error) {
   128  	if len(publisher) != 66 {
   129  		return nil, fmt.Errorf("publisher should be 66 characters long, got %d", len(publisher))
   130  	}
   131  	if len(salt) != 32 {
   132  		return nil, fmt.Errorf("salt should be 32 bytes long")
   133  	}
   134  	return &AccessEntry{
   135  		Type:      AccessTypePK,
   136  		Publisher: publisher,
   137  		Salt:      salt,
   138  	}, nil
   139  }
   140  
   141  func NewAccessEntryACT(publisher string, salt []byte, act string) (*AccessEntry, error) {
   142  	if len(salt) != 32 {
   143  		return nil, fmt.Errorf("salt should be 32 bytes long")
   144  	}
   145  	if len(publisher) != 66 {
   146  		return nil, fmt.Errorf("publisher should be 66 characters long")
   147  	}
   148  
   149  	return &AccessEntry{
   150  		Type:      AccessTypeACT,
   151  		Publisher: publisher,
   152  		Salt:      salt,
   153  		Act:       act,
   154  	}, nil
   155  }
   156  
   157  func NOOPDecrypt(*ManifestEntry) error {
   158  	return nil
   159  }
   160  
   161  var DefaultKdfParams = NewKdfParams(262144, 1, 8)
   162  
   163  func NewKdfParams(n, p, r int) *KdfParams {
   164  
   165  	return &KdfParams{
   166  		N: n,
   167  		P: p,
   168  		R: r,
   169  	}
   170  }
   171  
   172  //newsessionkeypassword基于共享机密(密码)和给定的salt创建会话密钥
   173  //和访问项中的kdf参数
   174  func NewSessionKeyPassword(password string, accessEntry *AccessEntry) ([]byte, error) {
   175  	if accessEntry.Type != AccessTypePass {
   176  		return nil, errors.New("incorrect access entry type")
   177  	}
   178  	return scrypt.Key(
   179  		[]byte(password),
   180  		accessEntry.Salt,
   181  		accessEntry.KdfParams.N,
   182  		accessEntry.KdfParams.R,
   183  		accessEntry.KdfParams.P,
   184  		32,
   185  	)
   186  }
   187  
   188  //newsessionkeypk为给定的密钥对和给定的salt值使用ECDH共享机密创建新的act会话密钥
   189  func NewSessionKeyPK(private *ecdsa.PrivateKey, public *ecdsa.PublicKey, salt []byte) ([]byte, error) {
   190  	granteePubEcies := ecies.ImportECDSAPublic(public)
   191  	privateKey := ecies.ImportECDSA(private)
   192  
   193  	bytes, err := privateKey.GenerateShared(granteePubEcies, 16, 16)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	bytes = append(salt, bytes...)
   198  	sessionKey := crypto.Keccak256(bytes)
   199  	return sessionKey, nil
   200  }
   201  
   202  func (a *API) NodeSessionKey(privateKey *ecdsa.PrivateKey, publicKey *ecdsa.PublicKey, salt []byte) ([]byte, error) {
   203  	return NewSessionKeyPK(privateKey, publicKey, salt)
   204  }
   205  func (a *API) doDecrypt(ctx context.Context, credentials string, pk *ecdsa.PrivateKey) DecryptFunc {
   206  	return func(m *ManifestEntry) error {
   207  		if m.Access == nil {
   208  			return nil
   209  		}
   210  
   211  		allowed := false
   212  		requestDomain := sctx.GetHost(ctx)
   213  		for _, v := range AllowedDecryptDomains {
   214  			if strings.Contains(requestDomain, v) {
   215  				allowed = true
   216  			}
   217  		}
   218  
   219  		if !allowed {
   220  			return ErrDecryptDomainForbidden
   221  		}
   222  
   223  		switch m.Access.Type {
   224  		case "pass":
   225  			if credentials != "" {
   226  				key, err := NewSessionKeyPassword(credentials, m.Access)
   227  				if err != nil {
   228  					return err
   229  				}
   230  
   231  				ref, err := hex.DecodeString(m.Hash)
   232  				if err != nil {
   233  					return err
   234  				}
   235  
   236  				enc := NewRefEncryption(len(ref) - 8)
   237  				decodedRef, err := enc.Decrypt(ref, key)
   238  				if err != nil {
   239  					return ErrDecrypt
   240  				}
   241  
   242  				m.Hash = hex.EncodeToString(decodedRef)
   243  				m.Access = nil
   244  				return nil
   245  			}
   246  			return ErrDecrypt
   247  		case "pk":
   248  			publisherBytes, err := hex.DecodeString(m.Access.Publisher)
   249  			if err != nil {
   250  				return ErrDecrypt
   251  			}
   252  			publisher, err := crypto.DecompressPubkey(publisherBytes)
   253  			if err != nil {
   254  				return ErrDecrypt
   255  			}
   256  			key, err := a.NodeSessionKey(pk, publisher, m.Access.Salt)
   257  			if err != nil {
   258  				return ErrDecrypt
   259  			}
   260  			ref, err := hex.DecodeString(m.Hash)
   261  			if err != nil {
   262  				return err
   263  			}
   264  
   265  			enc := NewRefEncryption(len(ref) - 8)
   266  			decodedRef, err := enc.Decrypt(ref, key)
   267  			if err != nil {
   268  				return ErrDecrypt
   269  			}
   270  
   271  			m.Hash = hex.EncodeToString(decodedRef)
   272  			m.Access = nil
   273  			return nil
   274  		case "act":
   275  			publisherBytes, err := hex.DecodeString(m.Access.Publisher)
   276  			if err != nil {
   277  				return ErrDecrypt
   278  			}
   279  			publisher, err := crypto.DecompressPubkey(publisherBytes)
   280  			if err != nil {
   281  				return ErrDecrypt
   282  			}
   283  
   284  			sessionKey, err := a.NodeSessionKey(pk, publisher, m.Access.Salt)
   285  			if err != nil {
   286  				return ErrDecrypt
   287  			}
   288  
   289  			hasher := sha3.NewKeccak256()
   290  			hasher.Write(append(sessionKey, 0))
   291  			lookupKey := hasher.Sum(nil)
   292  
   293  			hasher.Reset()
   294  
   295  			hasher.Write(append(sessionKey, 1))
   296  			accessKeyDecryptionKey := hasher.Sum(nil)
   297  
   298  			lk := hex.EncodeToString(lookupKey)
   299  			list, err := a.GetManifestList(ctx, NOOPDecrypt, storage.Address(common.Hex2Bytes(m.Access.Act)), lk)
   300  
   301  			found := ""
   302  			for _, v := range list.Entries {
   303  				if v.Path == lk {
   304  					found = v.Hash
   305  				}
   306  			}
   307  
   308  			if found == "" {
   309  				return ErrDecrypt
   310  			}
   311  
   312  			v, err := hex.DecodeString(found)
   313  			if err != nil {
   314  				return err
   315  			}
   316  			enc := NewRefEncryption(len(v) - 8)
   317  			decodedRef, err := enc.Decrypt(v, accessKeyDecryptionKey)
   318  			if err != nil {
   319  				return ErrDecrypt
   320  			}
   321  
   322  			ref, err := hex.DecodeString(m.Hash)
   323  			if err != nil {
   324  				return err
   325  			}
   326  
   327  			enc = NewRefEncryption(len(ref) - 8)
   328  			decodedMainRef, err := enc.Decrypt(ref, decodedRef)
   329  			if err != nil {
   330  				return ErrDecrypt
   331  			}
   332  			m.Hash = hex.EncodeToString(decodedMainRef)
   333  			m.Access = nil
   334  			return nil
   335  		}
   336  		return ErrUnknownAccessType
   337  	}
   338  }
   339  
   340  func GenerateAccessControlManifest(ctx *cli.Context, ref string, accessKey []byte, ae *AccessEntry) (*Manifest, error) {
   341  	refBytes, err := hex.DecodeString(ref)
   342  	if err != nil {
   343  		return nil, err
   344  	}
   345  //用accesskey加密ref
   346  	enc := NewRefEncryption(len(refBytes))
   347  	encrypted, err := enc.Encrypt(refBytes, accessKey)
   348  	if err != nil {
   349  		return nil, err
   350  	}
   351  
   352  	m := &Manifest{
   353  		Entries: []ManifestEntry{
   354  			{
   355  				Hash:        hex.EncodeToString(encrypted),
   356  				ContentType: ManifestType,
   357  				ModTime:     time.Now(),
   358  				Access:      ae,
   359  			},
   360  		},
   361  	}
   362  
   363  	return m, nil
   364  }
   365  
   366  func DoPKNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, granteePublicKey string, salt []byte) (sessionKey []byte, ae *AccessEntry, err error) {
   367  	if granteePublicKey == "" {
   368  		return nil, nil, errors.New("need a grantee Public Key")
   369  	}
   370  	b, err := hex.DecodeString(granteePublicKey)
   371  	if err != nil {
   372  		log.Error("error decoding grantee public key", "err", err)
   373  		return nil, nil, err
   374  	}
   375  
   376  	granteePub, err := crypto.DecompressPubkey(b)
   377  	if err != nil {
   378  		log.Error("error decompressing grantee public key", "err", err)
   379  		return nil, nil, err
   380  	}
   381  
   382  	sessionKey, err = NewSessionKeyPK(privateKey, granteePub, salt)
   383  	if err != nil {
   384  		log.Error("error getting session key", "err", err)
   385  		return nil, nil, err
   386  	}
   387  
   388  	ae, err = NewAccessEntryPK(hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)), salt)
   389  	if err != nil {
   390  		log.Error("error generating access entry", "err", err)
   391  		return nil, nil, err
   392  	}
   393  
   394  	return sessionKey, ae, nil
   395  }
   396  
   397  func DoACTNew(ctx *cli.Context, privateKey *ecdsa.PrivateKey, salt []byte, grantees []string) (accessKey []byte, ae *AccessEntry, actManifest *Manifest, err error) {
   398  	if len(grantees) == 0 {
   399  		return nil, nil, nil, errors.New("did not get any grantee public keys")
   400  	}
   401  
   402  	publisherPub := hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey))
   403  	grantees = append(grantees, publisherPub)
   404  
   405  	accessKey = make([]byte, 32)
   406  	if _, err := io.ReadFull(rand.Reader, salt); err != nil {
   407  		panic("reading from crypto/rand failed: " + err.Error())
   408  	}
   409  	if _, err := io.ReadFull(rand.Reader, accessKey); err != nil {
   410  		panic("reading from crypto/rand failed: " + err.Error())
   411  	}
   412  
   413  	lookupPathEncryptedAccessKeyMap := make(map[string]string)
   414  	i := 0
   415  	for _, v := range grantees {
   416  		i++
   417  		if v == "" {
   418  			return nil, nil, nil, errors.New("need a grantee Public Key")
   419  		}
   420  		b, err := hex.DecodeString(v)
   421  		if err != nil {
   422  			log.Error("error decoding grantee public key", "err", err)
   423  			return nil, nil, nil, err
   424  		}
   425  
   426  		granteePub, err := crypto.DecompressPubkey(b)
   427  		if err != nil {
   428  			log.Error("error decompressing grantee public key", "err", err)
   429  			return nil, nil, nil, err
   430  		}
   431  		sessionKey, err := NewSessionKeyPK(privateKey, granteePub, salt)
   432  
   433  		hasher := sha3.NewKeccak256()
   434  		hasher.Write(append(sessionKey, 0))
   435  		lookupKey := hasher.Sum(nil)
   436  
   437  		hasher.Reset()
   438  		hasher.Write(append(sessionKey, 1))
   439  
   440  		accessKeyEncryptionKey := hasher.Sum(nil)
   441  
   442  		enc := NewRefEncryption(len(accessKey))
   443  		encryptedAccessKey, err := enc.Encrypt(accessKey, accessKeyEncryptionKey)
   444  
   445  		lookupPathEncryptedAccessKeyMap[hex.EncodeToString(lookupKey)] = hex.EncodeToString(encryptedAccessKey)
   446  	}
   447  
   448  	m := &Manifest{
   449  		Entries: []ManifestEntry{},
   450  	}
   451  
   452  	for k, v := range lookupPathEncryptedAccessKeyMap {
   453  		m.Entries = append(m.Entries, ManifestEntry{
   454  			Path:        k,
   455  			Hash:        v,
   456  			ContentType: "text/plain",
   457  		})
   458  	}
   459  
   460  	ae, err = NewAccessEntryACT(hex.EncodeToString(crypto.CompressPubkey(&privateKey.PublicKey)), salt, "")
   461  	if err != nil {
   462  		return nil, nil, nil, err
   463  	}
   464  
   465  	return accessKey, ae, m, nil
   466  }
   467  
   468  func DoPasswordNew(ctx *cli.Context, password string, salt []byte) (sessionKey []byte, ae *AccessEntry, err error) {
   469  	ae, err = NewAccessEntryPassword(salt, DefaultKdfParams)
   470  	if err != nil {
   471  		return nil, nil, err
   472  	}
   473  
   474  	sessionKey, err = NewSessionKeyPassword(password, ae)
   475  	if err != nil {
   476  		return nil, nil, err
   477  	}
   478  	return sessionKey, ae, nil
   479  }
   480