github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/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 19:16:46</date>
    10  //</624450124650647552>
    11  
    12  
    13  //包含耳语协议消息元素。
    14  
    15  package whisperv5
    16  
    17  import (
    18  	"crypto/aes"
    19  	"crypto/cipher"
    20  	"crypto/ecdsa"
    21  	crand "crypto/rand"
    22  	"encoding/binary"
    23  	"errors"
    24  	"strconv"
    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/log"
    30  )
    31  
    32  //messageparams指定将消息包装到信封中的确切方式。
    33  type MessageParams struct {
    34  	TTL      uint32
    35  	Src      *ecdsa.PrivateKey
    36  	Dst      *ecdsa.PublicKey
    37  	KeySym   []byte
    38  	Topic    TopicType
    39  	WorkTime uint32
    40  	PoW      float64
    41  	Payload  []byte
    42  	Padding  []byte
    43  }
    44  
    45  //sentmessage表示要通过
    46  //耳语协议。它们被包装成信封,不需要
    47  //中间节点理解,刚刚转发。
    48  type sentMessage struct {
    49  	Raw []byte
    50  }
    51  
    52  //ReceivedMessage表示要通过
    53  //耳语协议。
    54  type ReceivedMessage struct {
    55  	Raw []byte
    56  
    57  	Payload   []byte
    58  	Padding   []byte
    59  	Signature []byte
    60  
    61  PoW   float64          //耳语规范中所述的工作证明
    62  Sent  uint32           //消息发布到网络的时间
    63  TTL   uint32           //消息允许的最长生存时间
    64  Src   *ecdsa.PublicKey //邮件收件人(用于解码邮件的标识)
    65  Dst   *ecdsa.PublicKey //邮件收件人(用于解码邮件的标识)
    66  	Topic TopicType
    67  
    68  SymKeyHash      common.Hash //与主题关联的密钥的keccak256hash
    69  EnvelopeHash    common.Hash //作为唯一ID的消息信封哈希
    70  	EnvelopeVersion uint64
    71  }
    72  
    73  func isMessageSigned(flags byte) bool {
    74  	return (flags & signatureFlag) != 0
    75  }
    76  
    77  func (msg *ReceivedMessage) isSymmetricEncryption() bool {
    78  	return msg.SymKeyHash != common.Hash{}
    79  }
    80  
    81  func (msg *ReceivedMessage) isAsymmetricEncryption() bool {
    82  	return msg.Dst != nil
    83  }
    84  
    85  //newsentmessage创建并初始化一个未签名、未加密的悄悄消息。
    86  func NewSentMessage(params *MessageParams) (*sentMessage, error) {
    87  	msg := sentMessage{}
    88  	msg.Raw = make([]byte, 1, len(params.Payload)+len(params.Padding)+signatureLength+padSizeLimit)
    89  msg.Raw[0] = 0 //将所有标志设置为零
    90  	err := msg.appendPadding(params)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	msg.Raw = append(msg.Raw, params.Payload...)
    95  	return &msg, nil
    96  }
    97  
    98  //getsizeoflength返回对整个大小填充进行编码所需的字节数(包括这些字节)
    99  func getSizeOfLength(b []byte) (sz int, err error) {
   100  sz = intSize(len(b))      //第一次迭代
   101  sz = intSize(len(b) + sz) //第二次迭代
   102  	if sz > 3 {
   103  		err = errors.New("oversized padding parameter")
   104  	}
   105  	return sz, err
   106  }
   107  
   108  //sizeofinsize返回对整数值进行编码所需的最小字节数
   109  func intSize(i int) (s int) {
   110  	for s = 1; i >= 256; s++ {
   111  		i /= 256
   112  	}
   113  	return s
   114  }
   115  
   116  //AppendPadding附加伪随机填充字节并设置填充标志。
   117  //最后一个字节包含填充大小(因此,其大小不能超过256)。
   118  func (msg *sentMessage) appendPadding(params *MessageParams) error {
   119  	rawSize := len(params.Payload) + 1
   120  	if params.Src != nil {
   121  		rawSize += signatureLength
   122  	}
   123  	odd := rawSize % padSizeLimit
   124  
   125  	if len(params.Padding) != 0 {
   126  		padSize := len(params.Padding)
   127  		padLengthSize, err := getSizeOfLength(params.Padding)
   128  		if err != nil {
   129  			return err
   130  		}
   131  		totalPadSize := padSize + padLengthSize
   132  		buf := make([]byte, 8)
   133  		binary.LittleEndian.PutUint32(buf, uint32(totalPadSize))
   134  		buf = buf[:padLengthSize]
   135  		msg.Raw = append(msg.Raw, buf...)
   136  		msg.Raw = append(msg.Raw, params.Padding...)
   137  msg.Raw[0] |= byte(padLengthSize) //指示填充大小的字节数
   138  	} else if odd != 0 {
   139  		totalPadSize := padSizeLimit - odd
   140  		if totalPadSize > 255 {
   141  //此算法仅在padsizelimit<256时有效。
   142  //如果padsizelimit将更改,请修复算法
   143  //(另请参见receivedmessage.extractpadding()函数)。
   144  			panic("please fix the padding algorithm before releasing new version")
   145  		}
   146  		buf := make([]byte, totalPadSize)
   147  		_, err := crand.Read(buf[1:])
   148  		if err != nil {
   149  			return err
   150  		}
   151  		if totalPadSize > 6 && !validateSymmetricKey(buf) {
   152  			return errors.New("failed to generate random padding of size " + strconv.Itoa(totalPadSize))
   153  		}
   154  		buf[0] = byte(totalPadSize)
   155  		msg.Raw = append(msg.Raw, buf...)
   156  msg.Raw[0] |= byte(0x1) //指示填充大小的字节数
   157  	}
   158  	return nil
   159  }
   160  
   161  //sign计算并设置消息的加密签名,
   162  //同时设置标志标志。
   163  func (msg *sentMessage) sign(key *ecdsa.PrivateKey) error {
   164  	if isMessageSigned(msg.Raw[0]) {
   165  //这不应该发生,但没有理由惊慌
   166  		log.Error("failed to sign the message: already signed")
   167  		return nil
   168  	}
   169  
   170  	msg.Raw[0] |= signatureFlag
   171  	hash := crypto.Keccak256(msg.Raw)
   172  	signature, err := crypto.Sign(hash, key)
   173  	if err != nil {
   174  msg.Raw[0] &= ^signatureFlag //清旗
   175  		return err
   176  	}
   177  	msg.Raw = append(msg.Raw, signature...)
   178  	return nil
   179  }
   180  
   181  //加密非对称使用公钥加密消息。
   182  func (msg *sentMessage) encryptAsymmetric(key *ecdsa.PublicKey) error {
   183  	if !ValidatePublicKey(key) {
   184  		return errors.New("invalid public key provided for asymmetric encryption")
   185  	}
   186  	encrypted, err := ecies.Encrypt(crand.Reader, ecies.ImportECDSAPublic(key), msg.Raw, nil, nil)
   187  	if err == nil {
   188  		msg.Raw = encrypted
   189  	}
   190  	return err
   191  }
   192  
   193  //encryptsymmetric使用aes-gcm-256使用主题密钥对消息进行加密。
   194  //nonce大小应为12个字节(请参阅cipher.gcmstandardnoncosize)。
   195  func (msg *sentMessage) encryptSymmetric(key []byte) (nonce []byte, err error) {
   196  	if !validateSymmetricKey(key) {
   197  		return nil, errors.New("invalid key provided for symmetric encryption")
   198  	}
   199  
   200  	block, err := aes.NewCipher(key)
   201  	if err != nil {
   202  		return nil, err
   203  	}
   204  	aesgcm, err := cipher.NewGCM(block)
   205  	if err != nil {
   206  		return nil, err
   207  	}
   208  
   209  //对于给定的键,不要使用超过2^32个随机nonce
   210  	nonce = make([]byte, aesgcm.NonceSize())
   211  	_, err = crand.Read(nonce)
   212  	if err != nil {
   213  		return nil, err
   214  	} else if !validateSymmetricKey(nonce) {
   215  		return nil, errors.New("crypto/rand failed to generate nonce")
   216  	}
   217  
   218  	msg.Raw = aesgcm.Seal(nil, nonce, msg.Raw, nil)
   219  	return nonce, nil
   220  }
   221  
   222  //将消息打包成一个信封,通过网络传输。
   223  func (msg *sentMessage) Wrap(options *MessageParams) (envelope *Envelope, err error) {
   224  	if options.TTL == 0 {
   225  		options.TTL = DefaultTTL
   226  	}
   227  	if options.Src != nil {
   228  		if err = msg.sign(options.Src); err != nil {
   229  			return nil, err
   230  		}
   231  	}
   232  	var nonce []byte
   233  	if options.Dst != nil {
   234  		err = msg.encryptAsymmetric(options.Dst)
   235  	} else if options.KeySym != nil {
   236  		nonce, err = msg.encryptSymmetric(options.KeySym)
   237  	} else {
   238  		err = errors.New("unable to encrypt the message: neither symmetric nor assymmetric key provided")
   239  	}
   240  	if err != nil {
   241  		return nil, err
   242  	}
   243  
   244  	envelope = NewEnvelope(options.TTL, options.Topic, nonce, msg)
   245  	if err = envelope.Seal(options); err != nil {
   246  		return nil, err
   247  	}
   248  	return envelope, nil
   249  }
   250  
   251  //decryptsymmetric使用aes-gcm-256使用主题密钥解密消息。
   252  //nonce大小应为12个字节(请参阅cipher.gcmstandardnoncosize)。
   253  func (msg *ReceivedMessage) decryptSymmetric(key []byte, nonce []byte) error {
   254  	block, err := aes.NewCipher(key)
   255  	if err != nil {
   256  		return err
   257  	}
   258  	aesgcm, err := cipher.NewGCM(block)
   259  	if err != nil {
   260  		return err
   261  	}
   262  	if len(nonce) != aesgcm.NonceSize() {
   263  		log.Error("decrypting the message", "AES nonce size", len(nonce))
   264  		return errors.New("wrong AES nonce size")
   265  	}
   266  	decrypted, err := aesgcm.Open(nil, nonce, msg.Raw, nil)
   267  	if err != nil {
   268  		return err
   269  	}
   270  	msg.Raw = decrypted
   271  	return nil
   272  }
   273  
   274  //解密非对称使用私钥解密加密的负载。
   275  func (msg *ReceivedMessage) decryptAsymmetric(key *ecdsa.PrivateKey) error {
   276  	decrypted, err := ecies.ImportECDSA(key).Decrypt(msg.Raw, nil, nil)
   277  	if err == nil {
   278  		msg.Raw = decrypted
   279  	}
   280  	return err
   281  }
   282  
   283  //验证检查有效性并在成功时提取字段
   284  func (msg *ReceivedMessage) Validate() bool {
   285  	end := len(msg.Raw)
   286  	if end < 1 {
   287  		return false
   288  	}
   289  
   290  	if isMessageSigned(msg.Raw[0]) {
   291  		end -= signatureLength
   292  		if end <= 1 {
   293  			return false
   294  		}
   295  		msg.Signature = msg.Raw[end:]
   296  		msg.Src = msg.SigToPubKey()
   297  		if msg.Src == nil {
   298  			return false
   299  		}
   300  	}
   301  
   302  	padSize, ok := msg.extractPadding(end)
   303  	if !ok {
   304  		return false
   305  	}
   306  
   307  	msg.Payload = msg.Raw[1+padSize : end]
   308  	return true
   309  }
   310  
   311  //提取填充从原始消息中提取填充。
   312  //尽管我们不支持发送填充大小的邮件
   313  //超过255字节,此类消息完全有效,并且
   314  //可以成功解密。
   315  func (msg *ReceivedMessage) extractPadding(end int) (int, bool) {
   316  	paddingSize := 0
   317  sz := int(msg.Raw[0] & paddingMask) //指示填充整个大小的字节数(包括这些字节)
   318  //可能是零——意味着没有填充
   319  	if sz != 0 {
   320  		paddingSize = int(bytesToUintLittleEndian(msg.Raw[1 : 1+sz]))
   321  		if paddingSize < sz || paddingSize+1 > end {
   322  			return 0, false
   323  		}
   324  		msg.Padding = msg.Raw[1+sz : 1+paddingSize]
   325  	}
   326  	return paddingSize, true
   327  }
   328  
   329  //sigtopubkey检索消息签名者的公钥。
   330  func (msg *ReceivedMessage) SigToPubKey() *ecdsa.PublicKey {
   331  defer func() { recover() }() //如果签名无效
   332  
   333  	pub, err := crypto.SigToPub(msg.hash(), msg.Signature)
   334  	if err != nil {
   335  		log.Error("failed to recover public key from signature", "err", err)
   336  		return nil
   337  	}
   338  	return pub
   339  }
   340  
   341  //hash计算消息标志、有效负载和填充的sha3校验和。
   342  func (msg *ReceivedMessage) hash() []byte {
   343  	if isMessageSigned(msg.Raw[0]) {
   344  		sz := len(msg.Raw) - signatureLength
   345  		return crypto.Keccak256(msg.Raw[:sz])
   346  	}
   347  	return crypto.Keccak256(msg.Raw)
   348  }
   349