github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/p2p/rlpx.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:41</date>
    10  //</624450106275401728>
    11  
    12  
    13  package p2p
    14  
    15  import (
    16  	"bytes"
    17  	"crypto/aes"
    18  	"crypto/cipher"
    19  	"crypto/ecdsa"
    20  	"crypto/elliptic"
    21  	"crypto/hmac"
    22  	"crypto/rand"
    23  	"encoding/binary"
    24  	"errors"
    25  	"fmt"
    26  	"hash"
    27  	"io"
    28  	"io/ioutil"
    29  	mrand "math/rand"
    30  	"net"
    31  	"sync"
    32  	"time"
    33  
    34  	"github.com/ethereum/go-ethereum/common/bitutil"
    35  	"github.com/ethereum/go-ethereum/crypto"
    36  	"github.com/ethereum/go-ethereum/crypto/ecies"
    37  	"github.com/ethereum/go-ethereum/crypto/secp256k1"
    38  	"github.com/ethereum/go-ethereum/rlp"
    39  	"github.com/golang/snappy"
    40  	"golang.org/x/crypto/sha3"
    41  )
    42  
    43  const (
    44  	maxUint24 = ^uint32(0) >> 8
    45  
    46  sskLen = 16 //指定最大共享密钥长度(pubkey)/2
    47  sigLen = 65 //椭圆形S256
    48  pubLen = 64 //512位pubkey,未压缩表示,无格式字节
    49  shaLen = 32 //哈希长度(用于nonce等)
    50  
    51  	authMsgLen  = sigLen + shaLen + pubLen + shaLen + 1
    52  	authRespLen = pubLen + shaLen + 1
    53  
    54   /*eSoverhead=65/*pubkey*/+16/*iv*/+32/*mac*/
    55  
    56   encauthmsglen=authmsglen+eciesoverhead//加密的pre-eip-8发起程序握手大小
    57   encauthresplen=authresplen+eciesoverhead//加密的pre-eip-8握手回复的大小
    58  
    59   //加密握手和协议的总超时时间
    60   //双向握手。
    61   握手超时=5*次。秒
    62  
    63   //这是发送断开连接原因的超时。
    64   //这比通常的超时时间短,因为我们不希望
    65   //等待连接是否损坏。
    66   discWriteTimeout=1*时间。秒
    67  )
    68  
    69  //如果解压缩的消息长度超过
    70  //允许的24位(即长度大于等于16MB)。
    71  var errplanmessagetoolarge=errors.new(“消息长度>=16MB”)
    72  
    73  //rlpx是实际(非测试)连接使用的传输协议。
    74  //它用锁和读/写截止时间包装帧编码器。
    75  RLPX型结构
    76   康德网络
    77  
    78   rmu,wmu同步.mutex
    79   rw*rlpxframerw
    80  }
    81  
    82  func newrlpx(fd net.conn)传输
    83   fd.setDeadline(time.now().add(handshakeTimeout))。
    84   返回&rlpx fd:fd
    85  }
    86  
    87  func(t*rlpx)readmsg()(msg,错误)
    88   锁定()
    89   延迟t.rmu.unlock()
    90   t.fd.setreadDeadline(time.now().add(framereadTimeout))。
    91   返回t.rw.readmsg()。
    92  }
    93  
    94  func(t*rlpx)writemsg(msg msg)错误
    95   T.WMU.
    96   延迟t.wmu.unlock()
    97   t.fd.setWriteDeadline(time.now().add(frameWriteTimeout))。
    98   返回t.rw.writemsg(msg)
    99  }
   100  
   101  func(t*rlpx)关闭(err错误)
   102   T.WMU.
   103   延迟t.wmu.unlock()
   104   //如果可能,告诉远端为什么要断开连接。
   105   如果T.RW!= nIL{
   106    如果R,则OK:=错误(不合理);OK&&R!=DiscNetworkError
   107     //rlpx尝试向断开连接的对等端发送discreason
   108     //如果连接为net.pipe(内存模拟)
   109     //它永远挂起,因为net.pipe不实现
   110     //写入截止时间。因为这只会试图发送
   111     //如果没有错误,则显示断开原因消息。
   112     if err:=t.fd.setWriteDeadline(time.now().add(discWriteTimeout));err==nil
   113      发送项(t.rw、discmsg、r)
   114     }
   115    }
   116   }
   117   T.F.C.()
   118  }
   119  
   120  func(t*rlpx)doprotochandshake(our*protochandshake)(their*protochandshake,err error)
   121   //写我们的握手是同时进行的,我们更喜欢
   122   //返回握手读取错误。如果远端
   123   //有正当理由提前断开我们的连接,我们应该将其返回
   124   //作为错误,以便在其他地方跟踪它。
   125   werr:=make(chan错误,1)
   126   go func()werr<-send(t.rw,handshakemsg,our)()
   127   如果他们的,err=readProtocolHandshake(t.rw,我们的);err!= nIL{
   128    <-werr//确保写入也终止
   129    返回零
   130   }
   131   如果错误:=<-werr;err!= nIL{
   132    返回nil,fmt.errorf(“写入错误:%v”,err)
   133   }
   134   //如果协议版本支持快速编码,则立即升级
   135   t.rw.snappy=their.version>=snappyrotocolversion
   136  
   137   归还他们的,零
   138  }
   139  
   140  func readprotocolhandshake(rw msgreader,our*protochandshake)(*protochandshake,error)
   141   msg,err:=rw.readmsg()。
   142   如果犯错!= nIL{
   143    返回零
   144   }
   145   如果消息大小>baseprotocolmaxmsgsize
   146    返回nil,fmt.errorf(“消息太大”)
   147   }
   148   如果msg.code==discmsg
   149    //根据协议握手有效之前断开连接
   150    //spec,如果post handshake检查失败,我们会自行发送。
   151    //但是我们不能直接返回原因,因为它被回送了
   152    //否则返回。改为用绳子把它包起来。
   153    VaR原因[1]不一致
   154    rlp.decode(消息有效负载和原因)
   155    返回零,原因[0]
   156   }
   157   如果是MSG,代码!=握手
   158    返回nil,fmt.errorf(“预期握手,得到%x”,消息代码)
   159   }
   160   var-hs协议握手
   161   如果错误:=msg.decode(&hs);错误!= nIL{
   162    返回零
   163   }
   164   如果莱恩(H.ID)!= 64乘!bitutil.testBytes(hs.id)_
   165    返回零,DiscInvalidIdentity
   166   }
   167   返回与HS
   168  }
   169  
   170  //doenchandshake使用authenticated运行协议握手
   171  / /消息。协议握手是第一条经过身份验证的消息
   172  //并验证加密握手是否“有效”以及
   173  //远程端实际上提供了正确的公钥。
   174  func(t*rlpx)doenchandshake(prv*ecdsa.privatekey,dial*ecdsa.publickey)(*ecdsa.publickey,error)
   175   var
   176    证券交易秘密
   177    错误率
   178   )
   179   如果刻度盘=零
   180    sec,err=receiverenchandshake(t.fd,prv)
   181   }否则{
   182    sec,err=initiatorenchandshake(t.fd,prv,dial)
   183   }
   184   如果犯错!= nIL{
   185    返回零
   186   }
   187   T.WMU.
   188   t.rw=newrlpxframerw(t.fd,秒)
   189   解锁()
   190   返回sec.remote.exportecdsa(),nil
   191  }
   192  
   193  //enchandshake包含加密握手的状态。
   194  类型enchandshake结构
   195   发起人bool
   196   remote*ecies.publickey//远程pubk
   197   initnoce,respnoce[]字节//nonce
   198   randomprivkey*ecies.privatekey//ecdhe随机
   199   remoterandompub*ecies.publickey//ecdhe random pubk
   200  }
   201  
   202  //机密表示连接机密
   203  //在加密握手期间协商。
   204  类型机密结构
   205   远程*ecies.publickey
   206   aes,mac[]字节
   207   出口MAC,入口MAC哈希.hash
   208   标记[]字节
   209  }
   210  
   211  //rlpx v4握手认证(在eip-8中定义)。
   212  类型authmsgv4结构
   213   gotplan bool//读包是否有纯格式。
   214  
   215   签名[siglen]字节
   216   initiatorSubkey[publen]字节
   217   nonce[shalen]字节
   218   版本uint
   219  
   220   //忽略其他字段(向前兼容)
   221   其余[]rlp.rawvalue`rlp:“tail”`
   222  }
   223  
   224  //rlpx v4握手响应(在eip-8中定义)。
   225  键入authrespv4 struct_
   226   randompubkey[publen]字节
   227   nonce[shalen]字节
   228   版本uint
   229  
   230   //忽略其他字段(向前兼容)
   231   其余[]rlp.rawvalue`rlp:“tail”`
   232  }
   233  
   234  //在握手完成后调用secrets。
   235  //从握手值中提取连接机密。
   236  func(h*enchandshake)机密(auth,authresp[]byte)(机密,错误)
   237   ecdhesecret,err:=h.randomprivkey.generateshared(h.remoterrandompub,ssklen,ssklen)
   238   如果犯错!= nIL{
   239    返回机密,错误
   240   }
   241  
   242   //从临时密钥协议派生基本机密
   243   sharedSecret:=crypto.keccak256(ecdhesecret,crypto.keccak256(h.responce,h.initonce))。
   244   aesecret:=crypto.keccak256(ecdhesecret,sharedsecret)
   245   S: =秘密{
   246    遥控器:H.遥控器,
   247    伊丝:伊丝密,
   248    mac:crypto.keccak256(ecdhesecret,aesecret)
   249   }
   250  
   251   //为macs设置sha3实例
   252   mac1:=sha3.newlegacykeccak256()。
   253   mac1.write(xor(s.mac,h.respnce))。
   254   mac1.写入(auth)
   255   mac2:=sha3.newlegacykeccak256()。
   256   mac2.write(xor(s.mac,h.initonce))。
   257   MAC2.写入(authresp)
   258   如果H.发起人
   259    S.egressmac,S.ingressmac=mac1,mac2
   260   }否则{
   261    S.egressmac,S.ingressmac=mac2,mac1
   262   }
   263  
   264   返回零
   265  }
   266  
   267  //StaticSharedSecret返回静态共享机密,结果
   268  //本地和远程静态节点密钥之间的密钥协议。
   269  func(h*enchandshake)staticsharedsecret(prv*ecdsa.privatekey)([]字节,错误)
   270   返回ecies.importecdsa(prv).generateshared(h.remote、ssklen、ssklen)
   271  }
   272  
   273  //initiatorenchandshake在conn上协商会话令牌。
   274  //应该在连接的拨号端调用它。
   275  / /
   276  //prv是本地客户端的私钥。
   277  func initiatorenchandshake(conn io.readwriter,prv*ecdsa.privatekey,remote*ecdsa.publickey)(s secrets,err error)
   278   h:=&enchandshake发起者:真,远程:指定。导入ecdsapublic(远程)
   279   authmsg,错误:=h.makeauthmsg(prv)
   280   如果犯错!= nIL{
   281    返回S
   282   }
   283   authpacket,错误:=sealeip8(authmsg,h)
   284   如果犯错!= nIL{
   285    返回S
   286   }
   287   如果,err=conn.write(authpacket);err!= nIL{
   288    返回S
   289   }
   290  
   291   AuthRespMsg:=新建(AuthRespv4)
   292   AuthRespPacket,错误:=readHandshakemsg(AuthRespMsg,EnauthRespLen,prv,conn)
   293   如果犯错!= nIL{
   294    返回S
   295   }
   296   如果错误:=H.HandleAuthResp(AuthRespMsg);错误!= nIL{
   297    返回S
   298   }
   299   返回h.secrets(authpacket、authrespacket)
   300  }
   301  
   302  //makeauthmsg创建启动器握手消息。
   303  func(h*enchandshake)makeauthmsg(prv*ecdsa.privatekey)(*authmsgv4,错误)
   304   //生成随机发起程序nonce。
   305   h.initonce=生成([]字节,shalen)
   306   错误:=rand.read(h.initonce)
   307   如果犯错!= nIL{
   308    返回零
   309   }
   310   //为ECDH生成随机密钥对to。
   311   h.randomprivkey,err=ecies.generatekey(rand.reader,crypto.s256(),nil)
   312   如果犯错!= nIL{
   313    返回零
   314   }
   315  
   316   //为已知消息签名:静态共享机密^nonce
   317   令牌,错误:=h.staticsharedsecret(prv)
   318   如果犯错!= nIL{
   319    返回零
   320   }
   321   有符号:=xor(token,h.initonce)
   322   签名,错误:=crypto.sign(signed,h.randomprivkey.exportecdsa())
   323   如果犯错!= nIL{
   324    返回零
   325   }
   326  
   327   消息:=new(authmsgv4)
   328   副本(消息签名[:],签名)
   329   复制(msg.initiatorpubkey[:],crypto.fromecdsapub(&prv.publickey)[1:]
   330   复制(msg.nonce[:],h.initonce)
   331   版本=4
   332   返回MSG,NIL
   333  }
   334  
   335  func(h*enchandshake)handleauthresp(msg*authresp4)(错误)
   336   h.respnce=msg.nonce[:]
   337   h.remoterandompub,err=importpublickey(msg.randompubkey[:])
   338   返回错误
   339  }
   340  
   341  //receiverenchandshake在conn上协商会话令牌。
   342  //应该在连接的侦听端调用它。
   343  / /
   344  //prv是本地客户端的私钥。
   345  func receiverenchandshake(conn io.readwriter,prv*ecdsa.privatekey)(s secrets,err error)
   346   authmsg:=新建(authmsgv4)
   347   authpacket,错误:=readhandshakemsg(authmsg,encauthmsglen,prv,conn)
   348   如果犯错!= nIL{
   349    返回S
   350   }
   351   H:=新(Enchandshake)
   352   如果错误:=h.handleauthmsg(authmsg,prv);错误!= nIL{
   353    返回S
   354   }
   355  
   356   AuthRespMsg,错误:=H.MakeAuthResp()。
   357   如果犯错!= nIL{
   358    返回S
   359   }
   360   var authresppacket[]字节
   361   如果authmsg.gotplan
   362    AuthRespPacket,err=AuthRespMsg.SealPlain(H)
   363   }否则{
   364    AuthRespPacket,err=SealeIP8(AuthRespMsg,H)
   365   }
   366   如果犯错!= nIL{
   367    返回S
   368   }
   369   如果,err=conn.write(authresppacket);err!= nIL{
   370    返回S
   371   }
   372   返回h.secrets(authpacket、authrespacket)
   373  }
   374  
   375  func(h*enchandshake)handleauthmsg(msg*authmsgv4,prv*ecdsa.privatekey)错误
   376   //导入远程标识。
   377   rpub,err:=importpublickey(msg.initiatorpubkey[:])
   378   如果犯错!= nIL{
   379    返回错误
   380   }
   381   h.initonce=msg.nonce[:]
   382   远程遥控器
   383  
   384   //为ECDH生成随机密钥对。
   385   //如果已经设置了私钥,则使用它而不是生成一个(用于测试)。
   386   如果h.randomprivkey==nil
   387    h.randomprivkey,err=ecies.generatekey(rand.reader,crypto.s256(),nil)
   388    如果犯错!= nIL{
   389     返回错误
   390    }
   391   }
   392  
   393   //检查签名。
   394   令牌,错误:=h.staticsharedsecret(prv)
   395   如果犯错!= nIL{
   396    返回错误
   397   }
   398   signedsg:=xor(token,h.initonce)
   399   remoteRandoPub,错误:=secp256k1.recoverpubkey(signedsg,msg.signature[:])
   400   如果犯错!= nIL{
   401    返回错误
   402   }
   403   H.RemoteRandompub,u=导入公共密钥(RemoteRandompub)
   404   返回零
   405  }
   406  
   407  func(h*enchandshake)makeauthresp()(msg*authresp4,err error)
   408   //生成随机nonce。
   409   h.responce=make([]字节,shalen)
   410   如果,err=rand.read(h.respnce);err!= nIL{
   411    返回零
   412   }
   413  
   414   msg=新建(authrespv4)
   415   复制(msg.nonce[:],h.respnce)
   416   复制(msg.randompubkey[:],exportpubkey(&h.randomprivkey.publickey))
   417   版本=4
   418   返回MSG,NIL
   419  }
   420  
   421  func(msg*authmsgv4)sealplain(h*enchandshake)([]字节,错误)
   422   buf:=make([]字节,authmsglen)
   423   n:=副本(buf,msg.签名[:])
   424   n+=复制(buf[n:],crypto.keccak256(exportpubkey(&h.randomprivkey.publickey)))
   425   n+=复制(buf[n:],msg.initiatorSubkey[:])
   426   n+=复制(buf[n:],msg.nonce[:])
   427   buf[n]=0//令牌标志
   428   返回ecies.encrypt(rand.reader、h.remote、buf、nil、nil)
   429  }
   430  
   431  func(msg*authmsgv4)decodeplain(input[]byte)
   432   n:=复制(消息签名[:],输入)
   433   n+=shalen//跳过sha3(发起人短暂发布)
   434   n+=复制(msg.initiatorSubkey[:],输入[n:]
   435   复制(msg.nonce[:],输入[n:])
   436   版本=4
   437   msg.gotplan=真
   438  }
   439  
   440  func(msg*authrespv4)sealplain(hs*enchandshake)([]字节,错误)
   441   buf:=make([]字节,authresplen)
   442   n:=复制(buf,msg.randombkey[:])
   443   复制(buf[n:],msg.nonce[:])
   444   返回ecies.encrypt(rand.reader、hs.remote、buf、nil、nil)
   445  }
   446  
   447  func(msg*authrespv4)decodeplain(input[]byte)
   448   n:=复制(msg.randompubkey[:],输入)
   449   复制(msg.nonce[:],输入[n:])
   450   版本=4
   451  }
   452  
   453  var padspace=make([]字节,300)
   454  
   455  func sealeip8(msg interface,h*enchandshake)([]字节,错误)
   456   buf:=新建(bytes.buffer)
   457   如果错误:=rlp.encode(buf,msg);错误!= nIL{
   458    返回零
   459   }
   460   //用随机数据量填充。数量至少需要100个字节才能
   461   //该消息可与EIP-8之前的握手区分开来。
   462   焊盘:=padspace[:mrand.intn(len(padspace)-100)+100]
   463   BUF.写(PAD)
   464   前缀:=make([]字节,2)
   465   binary.bigendian.putuint16(前缀,uint16(buf.len()+eciesoverhead))
   466  
   467   enc,err:=ecies.encrypt(rand.reader,h.remote,buf.bytes(),nil,prefix)
   468   返回append(prefix,enc…),err
   469  }
   470  
   471  类型普通解码器接口
   472   decodeplain([]字节)
   473  }
   474  
   475  func readhandshakemsg(msg plaindecoder,plainsize int,prv*ecdsa.privatekey,r io.reader)([]字节,错误)
   476   buf:=make([]字节,普通大小)
   477   如果,错误:=io.readfull(r,buf);错误!= nIL{
   478    返回BUF
   479   }
   480   //尝试解码pre-eip-8“plain”格式。
   481   键:=ecies.importecdsa(prv)
   482   如果是dec,则错误:=key.decrypt(buf,nil,nil);err==nil
   483    解码原稿消息(DEC)
   484    返回BUF,NIL
   485   }
   486   //可以是EIP-8格式,试试看。
   487   前缀:=buf[:2]
   488   大小:=binary.bigendian.uint16(前缀)
   489   如果尺寸<uint16(plainsize)
   490    返回buf,fmt.errorf(“大小下溢,至少需要%d字节”,plainsize)
   491   }
   492   buf=append(buf,make([]byte,size-uint16(plainsize)+2)…)
   493   如果uu,错误:=io.readfull(r,buf[plainsize:]);错误!= nIL{
   494    返回BUF
   495   }
   496   dec,err:=key.decrypt(buf[2:],nil,前缀)
   497   如果犯错!= nIL{
   498    返回BUF
   499   }
   500   //此处不能使用rlp.decodebytes,因为它拒绝
   501   //尾随数据(向前兼容)。
   502   S:=rlp.newstream(bytes.newreader(dec),0)
   503   返回buf,s.decode(msg)
   504  }
   505  
   506  //importpublickey取消标记512位公钥。
   507  func importpublickey(pubkey[]byte)(*ecies.publickey,error)
   508   var pubkey65[]字节
   509   交换长度(pubkey)
   510   案例64:
   511    //添加“uncompressed key”标志
   512    pubkey65=append([]字节0x04,pubkey…)
   513   案例65:
   514    pubKey65=发布键
   515   违约:
   516    返回nil,fmt.errorf(“无效的公钥长度%v(预期64/65)”,len(pubkey))
   517   }
   518   //TODO:更少的无意义转换
   519   pub,err:=crypto.unmashalpubkey(pubkey65)
   520   如果犯错!= nIL{
   521    返回零
   522   }
   523   退货特定进口适用性(pub),无
   524  }
   525  
   526  func exportpubkey(pub*ecies.publickey)[]字节
   527   如果Pub=nI{
   528    恐慌(“nil pubkey”)
   529   }
   530   返回Elliptic.Marshal(pub.curve,pub.x,pub.y)[1:]
   531  }
   532  
   533  func xor(一个,另一个[]字节)(xor[]字节)
   534   xor=make([]byte,len(one))。
   535   对于i:=0;i<len(one);i++
   536    xor[i]=一个[i]^另一个[i]
   537   }
   538   返回异或
   539  }
   540  
   541  var
   542   //用于代替实际帧头数据。
   543   //TODO:当msg包含协议类型代码时替换此项。
   544   ZeroHeader=[]字节0xc2、0x80、0x80_
   545   //十六个零字节
   546   zero16=make([]字节,16)
   547  )
   548  
   549  //rlpxframerw实现了rlpx framework的简化版本。
   550  //不支持分块消息,所有头等于
   551  //ZooHead。
   552  / /
   553  //rlpxframerw对于从多个goroutine并发使用不安全。
   554  类型rlpxframerw struct_
   555   连接IO.readwriter
   556   加密流
   557   DEC密码流
   558  
   559   maccipher cipher.block
   560   Egressmac哈希.hash
   561   入口MAC哈希.hash
   562  
   563   快活布尔
   564  }
   565  
   566  func newrlpxframerw(conn io.readwriter,s secrets)*rlpxframerw_
   567   macc,err:=aes.newcipher(s.mac)
   568   如果犯错!= nIL{
   569    panic(“无效的MAC机密:”+err.error())
   570   }
   571   ENCC,错误:=aes.newcipher(s.aes)
   572   如果犯错!= nIL{
   573    panic(“无效的aes秘密:”+err.error())
   574   }
   575   //我们对aes使用全零IV,因为使用的密钥
   576   //因为加密是短暂的。
   577   iv:=make([]字节,encc.blocksize())
   578   返回&rlpxframerw_
   579    连接件:连接件,
   580    Enc:Cipher.Newctr(Encc,IV),第
   581    DEC:cipher.newctr(encc,iv)
   582    麦克西弗:麦克西弗,
   583    白鹭:白鹭,
   584    入口MAC:S.IngressMAC,
   585   }
   586  }
   587  
   588  func(rw*rlpxframerw)writemsg(msg msg)错误
   589   ptype,:=rlp.encodetobytes(消息代码)
   590  
   591   //如果启用了snappy,则立即压缩消息
   592   如果RW.SNAPPY {
   593    如果消息大小>maxuint24
   594     返回errplanmessagetoolarge
   595    }
   596    有效载荷,:=ioutil.readall(msg.payload)
   597    有效载荷=快速编码(零,有效载荷)
   598  
   599    msg.payload=bytes.newreader(有效负载)
   600    msg.size=uint32(len(有效载荷)
   601   }
   602   //写头
   603   headbuf:=make([]字节,32)
   604   fsize:=uint32(len(ptype))+消息大小
   605   如果fsize>maxuint24
   606    返回errors.new(“消息大小溢出uint24”)
   607   }
   608   putint24(fsize,headbuf)//todo:检查溢出
   609   复制(headbuf[3:],zeroheader)
   610   rw.enc.xorkeystream(headbuf[:16],headbuf[:16])//上半部分现在已加密
   611  
   612   //写入头MAC
   613   副本(headbuf[16:],updatemac(rw.egissmac,rw.maccipher,headbuf[:16]))
   614   如果uux,错误:=rw.conn.write(headbuf);错误!= nIL{
   615    返回错误
   616   }
   617  
   618   //写入加密帧,更新出口MAC哈希
   619   //写入conn的数据。
   620   tee:=cipher.streamwriter s:rw.enc,w:io.multiwriter(rw.conn,rw.egissmac)
   621   如果ux,err:=tee.write(ptype);err!= nIL{
   622    返回错误
   623   }
   624   如果uu,错误:=io.copy(tee,msg.payload);错误!= nIL{
   625    返回错误
   626   }
   627   如果填充:=fsize%16;填充>0
   628    如果u,err:=tee.write(zero16[:16 padding]);err!= nIL{
   629     返回错误
   630    }
   631   }
   632  
   633   //写入帧mac。出口MAC哈希是最新的,因为
   634   //框架内容也写入了它。
   635   fmacseed:=rw.egissmac.sum(零)
   636   mac:=更新mac(rw.egissmac、rw.maccipher、fmacseed)
   637   _uuErr:=rw.conn.write(mac)
   638   返回错误
   639  }
   640  
   641  func(rw*rlpxframerw)readmsg()(msg,err error)
   642   //读取头
   643   headbuf:=make([]字节,32)
   644   如果,错误:=io.readfull(rw.conn,headbuf);错误!= nIL{
   645    返回MSG
   646   }
   647   //验证头MAC
   648   shouldmac:=updateMac(rw.ingressmac,rw.maccipher,headbuf[:16])
   649   如果!hmac.相等(shouldmac,headbuf[16:)
   650    返回msg,errors.new(“错误的header mac”)
   651   }
   652   rw.dec.xorkeystream(headbuf[:16],headbuf[:16])//上半部分现在被解密
   653   fsize:=readInt24(headbuf)
   654   //暂时忽略协议类型
   655  
   656   //读取帧内容
   657   var rsize=fsize//帧大小四舍五入到16字节边界
   658   如果填充:=fsize%16;填充>0
   659    rsize+=16-填充
   660   }
   661   framebuf:=make([]字节,rsize)
   662   如果uux,错误:=io.readfull(rw.conn,framebuf);错误!= nIL{
   663    返回MSG
   664   }
   665  
   666   //读取并验证帧MAC。我们可以重复使用headbuf。
   667   rw.ingressmac.write(framebuf)
   668   fmacseed:=rw.ingressmac.sum(零)
   669   如果uu,错误:=io.readfull(rw.conn,headbuf[:16]);错误!= nIL{
   670    返回MSG
   671   }
   672   shouldmac=updateMac(rw.ingressmac,rw.maccipher,fmacseed)
   673   如果!hmac.equal(shouldmac,headbuf[:16]);
   674    返回msg,errors.new(“坏帧MAC”)
   675   }
   676  
   677   //解密帧内容
   678   rw.dec.xorkeystream(framebuf,framebuf)代码
   679  
   680   //解码消息代码
   681   内容:=bytes.newreader(framebuf[:fsize])
   682   如果错误:=rlp.decode(content,&msg.code);错误!= nIL{
   683    返回MSG
   684   }
   685   msg.size=uint32(content.len())
   686   msg.payload=内容
   687  
   688   //如果启用了snappy,则验证并解压缩消息
   689   如果RW.SNAPPY {
   690    有效负载,错误:=ioutil.readall(msg.payload)
   691    如果犯错!= nIL{
   692     返回MSG
   693    }
   694    大小,错误:=snappy.decodedlen(有效负载)
   695    如果犯错!= nIL{
   696     返回MSG
   697    }
   698    如果大小>int(maxuint24)
   699     返回消息,errplanmessagetoolarge
   700    }
   701    有效载荷,err=snappy.decode(nil,有效载荷)
   702    如果犯错!= nIL{
   703     返回MSG
   704    }
   705    msg.size,msg.payload=uint32(大小),bytes.newreader(有效负载)
   706   }
   707   返回MSG,NIL
   708  }
   709  
   710  //updateMac使用加密种子重新设置给定哈希。
   711  //返回种子设定后哈希和的前16个字节。
   712  func updatemac(mac hash.hash,block cipher.block,seed[]byte)[]byte_
   713   aesbuf:=make([]字节,aes.blocksize)
   714   block.encrypt(aesbuf,mac.sum(nil))。
   715   对于i:=范围aesbuf
   716    aesbuf[i]^=种子[i]
   717   }
   718   书写(aesbuf)
   719   返回mac.sum(nil)[:16]
   720  }
   721  
   722  func readint24(b[]字节)uint32
   723   返回uint32(b[2])uint32(b[1])<<8_uint32(b[0])<<16
   724  }
   725  
   726  func putint24(v uint32,b[]字节)
   727   B[0]=字节(V>>16)
   728   B[1]=字节(V>>8)
   729   B〔2〕=字节(V)
   730  }
   731