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