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