github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/swarm/api/act.go (about)

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