github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/whisper/whisperv6/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 19:16:46</date>
    10  //</624450125548228608>
    11  
    12  
    13  //包含耳语协议消息元素。
    14  
    15  package whisperv6
    16  
    17  import (
    18  	"crypto/aes"
    19  	"crypto/cipher"
    20  	"crypto/ecdsa"
    21  	crand "crypto/rand"
    22  	"encoding/binary"
    23  	"errors"
    24  	mrand "math/rand"
    25  	"strconv"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/crypto"
    29  	"github.com/ethereum/go-ethereum/crypto/ecies"
    30  	"github.com/ethereum/go-ethereum/log"
    31  )
    32  
    33  //messageparams指定邮件的包装方式
    34  //装进信封里。
    35  type MessageParams struct {
    36  	TTL      uint32
    37  	Src      *ecdsa.PrivateKey
    38  	Dst      *ecdsa.PublicKey
    39  	KeySym   []byte
    40  	Topic    TopicType
    41  	WorkTime uint32
    42  	PoW      float64
    43  	Payload  []byte
    44  	Padding  []byte
    45  }
    46  
    47  //sentmessage表示要通过
    48  //耳语协议。它们被包装成信封,不需要
    49  //中间节点理解,刚刚转发。
    50  type sentMessage struct {
    51  	Raw []byte
    52  }
    53  
    54  //ReceivedMessage表示要通过
    55  //并成功解密。
    56  type ReceivedMessage struct {
    57  	Raw []byte
    58  
    59  	Payload   []byte
    60  	Padding   []byte
    61  	Signature []byte
    62  	Salt      []byte
    63  
    64  PoW   float64          //耳语规范中所述的工作证明
    65  Sent  uint32           //消息发布到网络的时间
    66  TTL   uint32           //消息允许的最长生存时间
    67  Src   *ecdsa.PublicKey //邮件收件人(用于解码邮件的标识)
    68  Dst   *ecdsa.PublicKey //邮件收件人(用于解码邮件的标识)
    69  	Topic TopicType
    70  
    71  SymKeyHash   common.Hash //密钥的keccak256哈希
    72  EnvelopeHash common.Hash //作为唯一ID的消息信封哈希
    73  }
    74  
    75  func isMessageSigned(flags byte) bool {
    76  	return (flags & signatureFlag) != 0
    77  }
    78  
    79  func (msg *ReceivedMessage) isSymmetricEncryption() bool {
    80  	return msg.SymKeyHash != common.Hash{}
    81  }
    82  
    83  func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
    84  	return msg.Dst != nil
    85  }
    86  
    87  //newsentmessage创建并初始化一个未签名、未加密的悄悄消息。
    88  func NewSentMessage(params *MessageParams) (*sentMessage, error) {
    89  	const payloadSizeFieldMaxSize = 4
    90  	msg := sentMessage{}
    91  	msg.Raw = make([]byte, 1,
    92  		flagsLength+payloadSizeFieldMaxSize+len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit)
    93  msg.Raw[0] = 0 //将所有标志设置为零
    94  	msg.addPayloadSizeField(params.Payload)
    95  	msg.Raw = append(msg.Raw, params.Payload...)
    96  	err := msg.appendPadding(params)
    97  	return &msg, err
    98  }
    99  
   100  //AddPayLoadSizeField附加包含有效负载大小的辅助字段
   101  func (msg *sentMessage) addPayloadSizeField(payload []byte) {
   102  	fieldSize := getSizeOfPayloadSizeField(payload)
   103  	field := make([]byte, 4)
   104  	binary.LittleEndian.PutUint32(field, uint32(len(payload)))
   105  	field = field[:fieldSize]
   106  	msg.Raw = append(msg.Raw, field...)
   107  	msg.Raw[0] |= byte(fieldSize)
   108  }
   109  
   110  //GetSizeOfPayLoadSizeField返回对有效负载大小进行编码所需的字节数。
   111  func getSizeOfPayloadSizeField(payload []byte) int {
   112  	s := 1
   113  	for i := len(payload); i >= 256; i /= 256 {
   114  		s++
   115  	}
   116  	return s
   117  }
   118  
   119  //AppendPadding追加参数中指定的填充。
   120  //如果参数中没有提供填充,则生成随机填充。
   121  func (msg *sentMessage) appendPadding(params *MessageParams) error {
   122  	if len(params.Padding) != 0 {
   123  //填充数据由DAPP提供,按原样使用
   124  		msg.Raw = append(msg.Raw, params.Padding...)
   125  		return nil
   126  	}
   127  
   128  	rawSize := flagsLength + getSizeOfPayloadSizeField(params.Payload) + len(params.Payload)
   129  	if params.Src != nil {
   130  		rawSize += signatureLength
   131  	}
   132  	odd := rawSize % padSizeLimit
   133  	paddingSize := padSizeLimit - odd
   134  	pad := make([]byte, paddingSize)
   135  	_, err := crand.Read(pad)
   136  	if err != nil {
   137  		return err
   138  	}
   139  	if !validateDataIntegrity(pad, paddingSize) {
   140  		return errors.New("failed to generate random padding of size " + strconv.Itoa(paddingSize))
   141  	}
   142  	msg.Raw = append(msg.Raw, pad...)
   143  	return nil
   144  }
   145  
   146  //sign计算并设置消息的加密签名,
   147  //同时设置标志标志。
   148  func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error {
   149  	if isMessageSigned(msg.Raw[0]) {
   150  //这不应该发生,但没有理由惊慌
   151  		log.Error("failed to sign the message: already signed")
   152  		return nil
   153  	}
   154  
   155  msg.Raw[0] |= signatureFlag //在签名前设置此标志很重要
   156  	hash := crypto.Keccak256(msg.Raw)
   157  	signature, err := crypto.Sign(hash, key)
   158  	if err != nil {
   159  msg.Raw[0] &= (0xFF ^ signatureFlag) //清旗
   160  		return err
   161  	}
   162  	msg.Raw = append(msg.Raw, signature...)
   163  	return nil
   164  }
   165  
   166  //加密非对称使用公钥加密消息。
   167  func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
   168  	if !ValidatePublicKey(key) {
   169  		return errors.New("invalid public key provided for asymmetric encryption")
   170  	}
   171  	encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil)
   172  	if err == nil {
   173  		msg.Raw = encrypted
   174  	}
   175  	return err
   176  }
   177  
   178  //encryptsymmetric使用aes-gcm-256使用主题密钥对消息进行加密。
   179  //nonce大小应为12个字节(请参阅cipher.gcmstandardnoncosize)。
   180  func (msg *sentMessage) encryptSymmetric(key []byte) (err error) {
   181  	if !validateDataIntegrity(key, aesKeyLength) {
   182  		return errors.New("invalid key provided for symmetric encryption, size: " + strconv.Itoa(len(key)))
   183  	}
   184  	block, err := aes.NewCipher(key)
   185  	if err != nil {
   186  		return err
   187  	}
   188  	aesgcm, err := cipher.NewGCM(block)
   189  	if err != nil {
   190  		return err
   191  	}
   192  salt, err := generateSecureRandomData(aesNonceLength) //对于给定的键,不要使用超过2^32个随机nonce
   193  	if err != nil {
   194  		return err
   195  	}
   196  	encrypted := aesgcm.Seal(nil, salt, msg.Raw, nil)
   197  	msg.Raw = append(encrypted, salt...)
   198  	return nil
   199  }
   200  
   201  //generatesecurerandomdata在需要额外安全性的地方生成随机数据。
   202  //此功能的目的是防止软件或硬件中的某些错误
   203  //提供不太随机的数据。这对aes nonce特别有用,
   204  //真正的随机性并不重要,但是
   205  //每封邮件都是独一无二的。
   206  func generateSecureRandomData(length int) ([]byte, error) {
   207  	x := make([]byte, length)
   208  	y := make([]byte, length)
   209  	res := make([]byte, length)
   210  
   211  	_, err := crand.Read(x)
   212  	if err != nil {
   213  		return nil, err
   214  	} else if !validateDataIntegrity(x, length) {
   215  		return nil, errors.New("crypto/rand failed to generate secure random data")
   216  	}
   217  	_, err = mrand.Read(y)
   218  	if err != nil {
   219  		return nil, err
   220  	} else if !validateDataIntegrity(y, length) {
   221  		return nil, errors.New("math/rand failed to generate secure random data")
   222  	}
   223  	for i := 0; i < length; i++ {
   224  		res[i] = x[i] ^ y[i]
   225  	}
   226  	if !validateDataIntegrity(res, length) {
   227  		return nil, errors.New("failed to generate secure random data")
   228  	}
   229  	return res, nil
   230  }
   231  
   232  //将消息打包成一个信封,通过网络传输。
   233  func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) {
   234  	if options.TTL == 0 {
   235  		options.TTL = DefaultTTL
   236  	}
   237  	if options.Src != nil {
   238  		if err = msg.sign(options.Src); err != nil {
   239  			return nil, err
   240  		}
   241  	}
   242  	if options.Dst != nil {
   243  		err = msg.encryptAsymmetric(options.Dst)
   244  	} else if options.KeySym != nil {
   245  		err = msg.encryptSymmetric(options.KeySym)
   246  	} else {
   247  		err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
   248  	}
   249  	if err != nil {
   250  		return nil, err
   251  	}
   252  
   253  	envelope = NewEnvelope(options.TTL, options.Topic, msg)
   254  	if err = envelope.Seal(options); err != nil {
   255  		return nil, err
   256  	}
   257  	return envelope, nil
   258  }
   259  
   260  //decryptsymmetric使用aes-gcm-256使用主题密钥解密消息。
   261  //nonce大小应为12个字节(请参阅cipher.gcmstandardnoncosize)。
   262  func (msg *ReceivedMessage) decryptSymmetric(key []byte) error {
   263  //对称消息应在有效负载末尾包含12字节的nonce
   264  	if len(msg.Raw) < aesNonceLength {
   265  		return errors.New("missing salt or invalid payload in symmetric message")
   266  	}
   267  	salt := msg.Raw[len(msg.Raw)-aesNonceLength:]
   268  
   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  	decrypted, err := aesgcm.Open(nil, salt, msg.Raw[:len(msg.Raw)-aesNonceLength], nil)
   278  	if err != nil {
   279  		return err
   280  	}
   281  	msg.Raw = decrypted
   282  	msg.Salt = salt
   283  	return nil
   284  }
   285  
   286  //解密非对称使用私钥解密加密的负载。
   287  func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error {
   288  	decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil)
   289  	if err == nil {
   290  		msg.Raw = decrypted
   291  	}
   292  	return err
   293  }
   294  
   295  //validateAndParse检查消息的有效性,并在成功时提取字段。
   296  func (msg *ReceivedMessage) ValidateAndParse() bool {
   297  	end := len(msg.Raw)
   298  	if end < 1 {
   299  		return false
   300  	}
   301  
   302  	if isMessageSigned(msg.Raw[0]) {
   303  		end -= signatureLength
   304  		if end <= 1 {
   305  			return false
   306  		}
   307  		msg.Signature = msg.Raw[end : end+signatureLength]
   308  		msg.Src = msg.SigToPubKey()
   309  		if msg.Src == nil {
   310  			return false
   311  		}
   312  	}
   313  
   314  	beg := 1
   315  	payloadSize := 0
   316  sizeOfPayloadSizeField := int(msg.Raw[0] & SizeMask) //指示有效负载大小的字节数
   317  	if sizeOfPayloadSizeField != 0 {
   318  		payloadSize = int(bytesToUintLittleEndian(msg.Raw[beg : beg+sizeOfPayloadSizeField]))
   319  		if payloadSize+1 > end {
   320  			return false
   321  		}
   322  		beg += sizeOfPayloadSizeField
   323  		msg.Payload = msg.Raw[beg : beg+payloadSize]
   324  	}
   325  
   326  	beg += payloadSize
   327  	msg.Padding = msg.Raw[beg:end]
   328  	return true
   329  }
   330  
   331  //sigtopubkey返回与消息的
   332  //签名。
   333  func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey {
   334  defer func() { recover() }() //如果签名无效
   335  
   336  	pub, err := crypto.SigToPub(msg.hash(), msg.Signature)
   337  	if err != nil {
   338  		log.Error("failed to recover public key from signature", "err", err)
   339  		return nil
   340  	}
   341  	return pub
   342  }
   343  
   344  //hash计算消息标志、有效负载大小字段、有效负载和填充的sha3校验和。
   345  func (msg *ReceivedMessage) hash() []byte {
   346  	if isMessageSigned(msg.Raw[0]) {
   347  		sz := len(msg.Raw) - signatureLength
   348  		return crypto.Keccak256(msg.Raw[:sz])
   349  	}
   350  	return crypto.Keccak256(msg.Raw)
   351  }
   352