github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/whisper/whisperv5/message.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:51</date>
    10  //</624342689046859776>
    11  
    12  //
    13  //
    14  //
    15  //
    16  //
    17  //
    18  //
    19  //
    20  //
    21  //
    22  //
    23  //
    24  //
    25  //
    26  //
    27  
    28  //
    29  
    30  package whisperv5
    31  
    32  import (
    33  	"crypto/aes"
    34  	"crypto/cipher"
    35  	"crypto/ecdsa"
    36  	crand "crypto/rand"
    37  	"encoding/binary"
    38  	"errors"
    39  	"strconv"
    40  
    41  	"github.com/ethereum/go-ethereum/common"
    42  	"github.com/ethereum/go-ethereum/crypto"
    43  	"github.com/ethereum/go-ethereum/crypto/ecies"
    44  	"github.com/ethereum/go-ethereum/log"
    45  )
    46  
    47  //
    48  type MessageParams struct {
    49  	TTL      uint32
    50  	Src      *ecdsa.PrivateKey
    51  	Dst      *ecdsa.PublicKey
    52  	KeySym   []byte
    53  	Topic    TopicType
    54  	WorkTime uint32
    55  	PoW      float64
    56  	Payload  []byte
    57  	Padding  []byte
    58  }
    59  
    60  //
    61  //
    62  //
    63  type sentMessage struct {
    64  	Raw []byte
    65  }
    66  
    67  //
    68  //
    69  type ReceivedMessage struct {
    70  	Raw []byte
    71  
    72  	Payload   []byte
    73  	Padding   []byte
    74  	Signature []byte
    75  
    76  PoW   float64          //
    77  Sent  uint32           //
    78  TTL   uint32           //
    79  Src   *ecdsa.PublicKey //
    80  Dst   *ecdsa.PublicKey //
    81  	Topic TopicType
    82  
    83  SymKeyHash      common.Hash //
    84  EnvelopeHash    common.Hash //
    85  	EnvelopeVersion uint64
    86  }
    87  
    88  func isMessageSigned(flags byte) bool {
    89  	return (flags & signatureFlag) != 0
    90  }
    91  
    92  func (msg *ReceivedMessage) isSymmetricEncryption() bool {
    93  	return msg.SymKeyHash != common.Hash{}
    94  }
    95  
    96  func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
    97  	return msg.Dst != nil
    98  }
    99  
   100  //
   101  func NewSentMessage(params *MessageParams) (*sentMessage, error) {
   102  	msg := sentMessage{}
   103  	msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit)
   104  msg.Raw[0] = 0 //
   105  	err := msg.appendPadding(params)
   106  	if err != nil {
   107  		return nil, err
   108  	}
   109  	msg.Raw = append(msg.Raw, params.Payload...)
   110  	return &msg, nil
   111  }
   112  
   113  //
   114  func getSizeOfLength(b []byte) (sz int, err error) {
   115  sz = intSize(len(b))      //
   116  sz = intSize(len(b) + sz) //
   117  	if sz > 3 {
   118  		err = errors.New("oversized padding parameter")
   119  	}
   120  	return sz, err
   121  }
   122  
   123  //
   124  func intSize(i int) (s int) {
   125  	for s = 1; i >= 256; s++ {
   126  		i /= 256
   127  	}
   128  	return s
   129  }
   130  
   131  //
   132  //
   133  func (msg *sentMessage) appendPadding(params *MessageParams) error {
   134  	rawSize := len(params.Payload) + 1
   135  	if params.Src != nil {
   136  		rawSize += signatureLength
   137  	}
   138  	odd := rawSize % padSizeLimit
   139  
   140  	if len(params.Padding) != 0 {
   141  		padSize := len(params.Padding)
   142  		padLengthSize, err := getSizeOfLength(params.Padding)
   143  		if err != nil {
   144  			return err
   145  		}
   146  		totalPadSize := padSize + padLengthSize
   147  		buf := make([]byte, 8)
   148  		binary.LittleEndian.PutUint32(buf, uint32(totalPadSize))
   149  		buf = buf[:padLengthSize]
   150  		msg.Raw = append(msg.Raw, buf...)
   151  		msg.Raw = append(msg.Raw, params.Padding...)
   152  msg.Raw[0] |= byte(padLengthSize) //
   153  	} else if odd != 0 {
   154  		totalPadSize := padSizeLimit - odd
   155  		if totalPadSize > 255 {
   156  //
   157  //
   158  //
   159  			panic("please fix the padding algorithm before releasing new version")
   160  		}
   161  		buf := make([]byte, totalPadSize)
   162  		_, err := crand.Read(buf[1:])
   163  		if err != nil {
   164  			return err
   165  		}
   166  		if totalPadSize > 6 && !validateSymmetricKey(buf) {
   167  			return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize))
   168  		}
   169  		buf[0] = byte(totalPadSize)
   170  		msg.Raw = append(msg.Raw, buf...)
   171  msg.Raw[0] |= byte(0x1) //
   172  	}
   173  	return nil
   174  }
   175  
   176  //
   177  //
   178  func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error {
   179  	if isMessageSigned(msg.Raw[0]) {
   180  //
   181  		log.Error("failed to sign the message: already signed")
   182  		return nil
   183  	}
   184  
   185  	msg.Raw[0] |= signatureFlag
   186  	hash := crypto.Keccak256(msg.Raw)
   187  	signature, err := crypto.Sign(hash, key)
   188  	if err != nil {
   189  msg.Raw[0] &= ^signatureFlag //
   190  		return err
   191  	}
   192  	msg.Raw = append(msg.Raw, signature...)
   193  	return nil
   194  }
   195  
   196  //
   197  func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
   198  	if !ValidatePublicKey(key) {
   199  		return errors.New("invalid public key provided for asymmetric encryption")
   200  	}
   201  	encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil)
   202  	if err == nil {
   203  		msg.Raw = encrypted
   204  	}
   205  	return err
   206  }
   207  
   208  //
   209  //
   210  func (msg *sentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) {
   211  	if !validateSymmetricKey(key) {
   212  		return nil, errors.New("invalid key provided for symmetric encryption")
   213  	}
   214  
   215  	block, err := aes.NewCipher(key)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  	aesgcm, err := cipher.NewGCM(block)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  
   224  //
   225  	nonce = make([]byte, aesgcm.NonceSize())
   226  	_, err = crand.Read(nonce)
   227  	if err != nil {
   228  		return nil, err
   229  	} else if !validateSymmetricKey(nonce) {
   230  		return nil, errors.New("crypto/rand failed to generate nonce")
   231  	}
   232  
   233  	msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil)
   234  	return nonce, nil
   235  }
   236  
   237  //
   238  func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) {
   239  	if options.TTL == 0 {
   240  		options.TTL = DefaultTTL
   241  	}
   242  	if options.Src != nil {
   243  		if err = msg.sign(options.Src); err != nil {
   244  			return nil, err
   245  		}
   246  	}
   247  	var nonce []byte
   248  	if options.Dst != nil {
   249  		err = msg.encryptAsymmetric(options.Dst)
   250  	} else if options.KeySym != nil {
   251  		nonce, err = msg.encryptSymmetric(options.KeySym)
   252  	} else {
   253  		err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
   254  	}
   255  	if err != nil {
   256  		return nil, err
   257  	}
   258  
   259  	envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg)
   260  	if err = envelope.Seal(options); err != nil {
   261  		return nil, err
   262  	}
   263  	return envelope, nil
   264  }
   265  
   266  //
   267  //
   268  func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error {
   269  	block, err := aes.NewCipher(key)
   270  	if err != nil {
   271  		return err
   272  	}
   273  	aesgcm, err := cipher.NewGCM(block)
   274  	if err != nil {
   275  		return err
   276  	}
   277  	if len(nonce) != aesgcm.NonceSize() {
   278  		log.Error("decrypting the message", "AES nonce size", len(nonce))
   279  		return errors.New("wrong AES nonce size")
   280  	}
   281  	decrypted, err := aesgcm.Open(nil, nonce, msg.Raw, nil)
   282  	if err != nil {
   283  		return err
   284  	}
   285  	msg.Raw = decrypted
   286  	return nil
   287  }
   288  
   289  //
   290  func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error {
   291  	decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil)
   292  	if err == nil {
   293  		msg.Raw = decrypted
   294  	}
   295  	return err
   296  }
   297  
   298  //
   299  func (msg *ReceivedMessage) Validate() bool {
   300  	end := len(msg.Raw)
   301  	if end < 1 {
   302  		return false
   303  	}
   304  
   305  	if isMessageSigned(msg.Raw[0]) {
   306  		end -= signatureLength
   307  		if end <= 1 {
   308  			return false
   309  		}
   310  		msg.Signature = msg.Raw[end:]
   311  		msg.Src = msg.SigToPubKey()
   312  		if msg.Src == nil {
   313  			return false
   314  		}
   315  	}
   316  
   317  	padSize, ok := msg.extractPadding(end)
   318  	if !ok {
   319  		return false
   320  	}
   321  
   322  	msg.Payload = msg.Raw[1+padSize : end]
   323  	return true
   324  }
   325  
   326  //
   327  //
   328  //
   329  //
   330  func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
   331  	paddingSize := 0
   332  sz := int(msg.Raw[0] & paddingMask) //
   333  //
   334  	if sz != 0 {
   335  		paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
   336  		if paddingSize < sz || paddingSize+1 > end {
   337  			return 0, false
   338  		}
   339  		msg.Padding = msg.Raw[1+sz : 1+paddingSize]
   340  	}
   341  	return paddingSize, true
   342  }
   343  
   344  //
   345  func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey {
   346  defer func() { recover() }() //
   347  
   348  	pub, err := crypto.SigToPub(msg.hash(), msg.Signature)
   349  	if err != nil {
   350  		log.Error("failed to recover public key from signature", "err", err)
   351  		return nil
   352  	}
   353  	return pub
   354  }
   355  
   356  //
   357  func (msg *ReceivedMessage) hash() []byte {
   358  	if isMessageSigned(msg.Raw[0]) {
   359  		sz := len(msg.Raw) - signatureLength
   360  		return crypto.Keccak256(msg.Raw[:sz])
   361  	}
   362  	return crypto.Keccak256(msg.Raw)
   363  }
   364