github.com/klaytn/klaytn@v1.10.2/networks/p2p/rlpx.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from p2p/rlpx.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package p2p 22 23 import ( 24 "bufio" 25 "bytes" 26 "crypto/aes" 27 "crypto/cipher" 28 "crypto/ecdsa" 29 "crypto/elliptic" 30 "crypto/hmac" 31 "crypto/rand" 32 "encoding/binary" 33 "errors" 34 "fmt" 35 "hash" 36 "io" 37 "io/ioutil" 38 mrand "math/rand" 39 "net" 40 "sync" 41 "time" 42 43 "github.com/klaytn/klaytn/common" 44 45 "github.com/golang/snappy" 46 "github.com/klaytn/klaytn/crypto" 47 "github.com/klaytn/klaytn/crypto/ecies" 48 "github.com/klaytn/klaytn/crypto/secp256k1" 49 "github.com/klaytn/klaytn/crypto/sha3" 50 "github.com/klaytn/klaytn/networks/p2p/discover" 51 "github.com/klaytn/klaytn/rlp" 52 ) 53 54 const ( 55 maxUint24 = ^uint32(0) >> 8 56 57 sskLen = 16 // ecies.MaxSharedKeyLength(pubKey) / 2 58 sigLen = crypto.SignatureLength // elliptic S256 59 pubLen = 64 // 512 bit pubkey in uncompressed representation without format byte 60 shaLen = 32 // hash length (for nonce etc) 61 62 authMsgLen = sigLen + shaLen + pubLen + shaLen + 1 63 authRespLen = pubLen + shaLen + 1 64 65 eciesOverhead = 65 /* pubkey */ + 16 /* IV */ + 32 /* MAC */ 66 67 encAuthMsgLen = authMsgLen + eciesOverhead // size of encrypted pre-EIP-8 initiator handshake 68 encAuthRespLen = authRespLen + eciesOverhead // size of encrypted pre-EIP-8 handshake reply 69 70 // total timeout for encryption handshake and protocol 71 // handshake in both directions. 72 handshakeTimeout = 5 * time.Second 73 74 // This is the timeout for sending the disconnect reason. 75 // This is shorter than the usual timeout because we don't want 76 // to wait if the connection is known to be bad anyway. 77 discWriteTimeout = 1 * time.Second 78 ) 79 80 // errPlainMessageTooLarge is returned if a decompressed message length exceeds 81 // the allowed 24 bits (i.e. length >= 16MB). 82 var errPlainMessageTooLarge = errors.New("message length >= 16MB") 83 84 // rlpx is the transport protocol used by actual (non-test) connections. 85 // It wraps the frame encoder with locks and read/write deadlines. 86 type rlpx struct { 87 fd net.Conn 88 89 rmu, wmu sync.Mutex 90 rw *rlpxFrameRW 91 } 92 93 func newRLPX(fd net.Conn) transport { 94 fd.SetDeadline(time.Now().Add(handshakeTimeout)) 95 return &rlpx{fd: fd} 96 } 97 98 func (t *rlpx) ReadMsg() (Msg, error) { 99 t.rmu.Lock() 100 defer t.rmu.Unlock() 101 t.fd.SetReadDeadline(time.Now().Add(frameReadTimeout)) 102 return t.rw.ReadMsg() 103 } 104 105 func (t *rlpx) WriteMsg(msg Msg) error { 106 t.wmu.Lock() 107 defer t.wmu.Unlock() 108 t.fd.SetWriteDeadline(time.Now().Add(frameWriteTimeout)) 109 return t.rw.WriteMsg(msg) 110 } 111 112 func (t *rlpx) close(err error) { 113 t.wmu.Lock() 114 defer t.wmu.Unlock() 115 // Tell the remote end why we're disconnecting if possible. 116 if t.rw != nil { 117 if r, ok := err.(DiscReason); ok && r != DiscNetworkError { 118 // rlpx tries to send DiscReason to disconnected peer 119 // if the connection is net.Pipe (in-memory simulation) 120 // it hangs forever, since net.Pipe does not implement 121 // a write deadline. Because of this only try to send 122 // the disconnect reason message if there is no error. 123 if err := t.fd.SetWriteDeadline(time.Now().Add(discWriteTimeout)); err == nil { 124 SendItems(t.rw, discMsg, r) 125 } 126 } 127 } 128 t.fd.Close() 129 } 130 131 func (c *rlpx) writeType(myConnType common.ConnType) error { 132 if !myConnType.Valid() { 133 return errors.New("Connection Type is not valid") 134 } 135 byteW := byte(int(myConnType)) 136 if _, err := c.fd.Write([]byte{byteW}); err != nil { 137 return err 138 } 139 return nil 140 } 141 142 func (c *rlpx) readType() (error, byte) { 143 r := bufio.NewReader(c.fd) 144 byteVal, err := r.ReadByte() 145 if err != nil { 146 return err, 0 147 } 148 return nil, byteVal 149 } 150 151 func (c *rlpx) doConnTypeHandshake(myConnType common.ConnType) (common.ConnType, error) { 152 var e error 153 var b byte 154 werr := make(chan error, 1) 155 go func() { werr <- c.writeType(myConnType) }() 156 if e, b = c.readType(); e != nil { 157 <-werr // make sure the write terminates too 158 return common.ConnTypeUndefined, e 159 } 160 if e = <-werr; e != nil { 161 return common.ConnTypeUndefined, e 162 } 163 conntype := common.ConnType(int(b)) 164 if !conntype.Valid() { 165 return common.ConnTypeUndefined, fmt.Errorf("invalid connection type: %v", conntype) 166 } 167 return conntype, nil 168 } 169 170 func (t *rlpx) doProtoHandshake(our *protoHandshake) (their *protoHandshake, err error) { 171 // Writing our handshake happens concurrently, we prefer 172 // returning the handshake read error. If the remote side 173 // disconnects us early with a valid reason, we should return it 174 // as the error so it can be tracked elsewhere. 175 werr := make(chan error, 1) 176 go func() { werr <- Send(t.rw, handshakeMsg, our) }() 177 if their, err = readProtocolHandshake(t.rw, our); err != nil { 178 <-werr // make sure the write terminates too 179 return nil, err 180 } 181 if err := <-werr; err != nil { 182 return nil, fmt.Errorf("write error: %v", err) 183 } 184 // If the protocol version supports Snappy encoding, upgrade immediately 185 t.rw.snappy = their.Version >= snappyProtocolVersion 186 187 return their, nil 188 } 189 190 func readProtocolHandshake(rw MsgReader, our *protoHandshake) (*protoHandshake, error) { 191 msg, err := rw.ReadMsg() 192 if err != nil { 193 return nil, err 194 } 195 if msg.Size > baseProtocolMaxMsgSize { 196 return nil, fmt.Errorf("message too big") 197 } 198 if msg.Code == discMsg { 199 // Disconnect before protocol handshake is valid according to the 200 // spec and we send it ourself if the posthanshake checks fail. 201 // We can't return the reason directly, though, because it is echoed 202 // back otherwise. Wrap it in a string instead. 203 var reason [1]DiscReason 204 rlp.Decode(msg.Payload, &reason) 205 return nil, reason[0] 206 } 207 if msg.Code != handshakeMsg { 208 return nil, fmt.Errorf("expected handshake, got %x", msg.Code) 209 } 210 var hs protoHandshake 211 if err := msg.Decode(&hs); err != nil { 212 return nil, err 213 } 214 if (hs.ID == discover.NodeID{}) { 215 return nil, DiscInvalidIdentity 216 } 217 return &hs, nil 218 } 219 220 // doEncHandshake runs the protocol handshake using authenticated 221 // messages. the protocol handshake is the first authenticated message 222 // and also verifies whether the encryption handshake 'worked' and the 223 // remote side actually provided the right public key. 224 func (t *rlpx) doEncHandshake(prv *ecdsa.PrivateKey, dial *discover.Node) (discover.NodeID, error) { 225 var ( 226 sec secrets 227 err error 228 ) 229 if dial == nil { 230 sec, err = receiverEncHandshake(t.fd, prv, nil) 231 } else { 232 sec, err = initiatorEncHandshake(t.fd, prv, dial.ID) 233 } 234 if err != nil { 235 return discover.NodeID{}, err 236 } 237 t.wmu.Lock() 238 t.rw = newRLPXFrameRW(t.fd, sec) 239 t.wmu.Unlock() 240 return sec.RemoteID, nil 241 } 242 243 // encHandshake contains the state of the encryption handshake. 244 type encHandshake struct { 245 initiator bool 246 remoteID discover.NodeID 247 248 remotePub *ecies.PublicKey // remote-pubk 249 initNonce, respNonce []byte // nonce 250 randomPrivKey *ecies.PrivateKey // ecdhe-random 251 remoteRandomPub *ecies.PublicKey // ecdhe-random-pubk 252 } 253 254 // secrets represents the connection secrets 255 // which are negotiated during the encryption handshake. 256 type secrets struct { 257 RemoteID discover.NodeID 258 AES, MAC []byte 259 EgressMAC, IngressMAC hash.Hash 260 Token []byte 261 } 262 263 // RLPx v4 handshake auth (defined in EIP-8). 264 type authMsgV4 struct { 265 gotPlain bool // whether read packet had plain format. 266 267 Signature [sigLen]byte 268 InitiatorPubkey [pubLen]byte 269 Nonce [shaLen]byte 270 Version uint 271 272 // Ignore additional fields (forward-compatibility) 273 Rest []rlp.RawValue `rlp:"tail"` 274 } 275 276 // RLPx v4 handshake response (defined in EIP-8). 277 type authRespV4 struct { 278 RandomPubkey [pubLen]byte 279 Nonce [shaLen]byte 280 Version uint 281 282 // Ignore additional fields (forward-compatibility) 283 Rest []rlp.RawValue `rlp:"tail"` 284 } 285 286 // secrets is called after the handshake is completed. 287 // It extracts the connection secrets from the handshake values. 288 func (h *encHandshake) secrets(auth, authResp []byte) (secrets, error) { 289 ecdheSecret, err := h.randomPrivKey.GenerateShared(h.remoteRandomPub, sskLen, sskLen) 290 if err != nil { 291 return secrets{}, err 292 } 293 294 // derive base secrets from ephemeral key agreement 295 sharedSecret := crypto.Keccak256(ecdheSecret, crypto.Keccak256(h.respNonce, h.initNonce)) 296 aesSecret := crypto.Keccak256(ecdheSecret, sharedSecret) 297 s := secrets{ 298 RemoteID: h.remoteID, 299 AES: aesSecret, 300 MAC: crypto.Keccak256(ecdheSecret, aesSecret), 301 } 302 303 // setup sha3 instances for the MACs 304 mac1 := sha3.NewKeccak256() 305 mac1.Write(xor(s.MAC, h.respNonce)) 306 mac1.Write(auth) 307 mac2 := sha3.NewKeccak256() 308 mac2.Write(xor(s.MAC, h.initNonce)) 309 mac2.Write(authResp) 310 if h.initiator { 311 s.EgressMAC, s.IngressMAC = mac1, mac2 312 } else { 313 s.EgressMAC, s.IngressMAC = mac2, mac1 314 } 315 316 return s, nil 317 } 318 319 // staticSharedSecret returns the static shared secret, the result 320 // of key agreement between the local and remote static node key. 321 func (h *encHandshake) staticSharedSecret(prv *ecdsa.PrivateKey) ([]byte, error) { 322 return ecies.ImportECDSA(prv).GenerateShared(h.remotePub, sskLen, sskLen) 323 } 324 325 // initiatorEncHandshake negotiates a session token on conn. 326 // it should be called on the dialing side of the connection. 327 // 328 // prv is the local client's private key. 329 func initiatorEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, remoteID discover.NodeID) (s secrets, err error) { 330 h := &encHandshake{initiator: true, remoteID: remoteID} 331 authMsg, err := h.makeAuthMsg(prv) 332 if err != nil { 333 return s, err 334 } 335 authPacket, err := sealEIP8(authMsg, h) 336 if err != nil { 337 return s, err 338 } 339 if _, err = conn.Write(authPacket); err != nil { 340 return s, err 341 } 342 343 authRespMsg := new(authRespV4) 344 authRespPacket, err := readHandshakeMsg(authRespMsg, encAuthRespLen, prv, conn) 345 if err != nil { 346 return s, err 347 } 348 if err := h.handleAuthResp(authRespMsg); err != nil { 349 return s, err 350 } 351 return h.secrets(authPacket, authRespPacket) 352 } 353 354 // makeAuthMsg creates the initiator handshake message. 355 func (h *encHandshake) makeAuthMsg(prv *ecdsa.PrivateKey) (*authMsgV4, error) { 356 rpub, err := h.remoteID.Pubkey() 357 if err != nil { 358 return nil, fmt.Errorf("bad remoteID: %v", err) 359 } 360 h.remotePub = ecies.ImportECDSAPublic(rpub) 361 // Generate random initiator nonce. 362 h.initNonce = make([]byte, shaLen) 363 if _, err := rand.Read(h.initNonce); err != nil { 364 return nil, err 365 } 366 // Generate random keypair to for ECDH. 367 h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil) 368 if err != nil { 369 return nil, err 370 } 371 372 // Sign known message: static-shared-secret ^ nonce 373 token, err := h.staticSharedSecret(prv) 374 if err != nil { 375 return nil, err 376 } 377 signed := xor(token, h.initNonce) 378 signature, err := crypto.Sign(signed, h.randomPrivKey.ExportECDSA()) 379 if err != nil { 380 return nil, err 381 } 382 383 msg := new(authMsgV4) 384 copy(msg.Signature[:], signature) 385 copy(msg.InitiatorPubkey[:], crypto.FromECDSAPub(&prv.PublicKey)[1:]) 386 copy(msg.Nonce[:], h.initNonce) 387 msg.Version = 4 388 return msg, nil 389 } 390 391 func (h *encHandshake) handleAuthResp(msg *authRespV4) (err error) { 392 h.respNonce = msg.Nonce[:] 393 h.remoteRandomPub, err = importPublicKey(msg.RandomPubkey[:]) 394 return err 395 } 396 397 // receiverEncHandshake negotiates a session token on conn. 398 // it should be called on the listening side of the connection. 399 // 400 // prv is the local client's private key. 401 // token is the token from a previous session with this node. 402 func receiverEncHandshake(conn io.ReadWriter, prv *ecdsa.PrivateKey, token []byte) (s secrets, err error) { 403 authMsg := new(authMsgV4) 404 authPacket, err := readHandshakeMsg(authMsg, encAuthMsgLen, prv, conn) 405 if err != nil { 406 return s, err 407 } 408 h := new(encHandshake) 409 if err := h.handleAuthMsg(authMsg, prv); err != nil { 410 return s, err 411 } 412 413 authRespMsg, err := h.makeAuthResp() 414 if err != nil { 415 return s, err 416 } 417 var authRespPacket []byte 418 if authMsg.gotPlain { 419 authRespPacket, err = authRespMsg.sealPlain(h) 420 } else { 421 authRespPacket, err = sealEIP8(authRespMsg, h) 422 } 423 if err != nil { 424 return s, err 425 } 426 if _, err = conn.Write(authRespPacket); err != nil { 427 return s, err 428 } 429 return h.secrets(authPacket, authRespPacket) 430 } 431 432 func (h *encHandshake) handleAuthMsg(msg *authMsgV4, prv *ecdsa.PrivateKey) error { 433 // Import the remote identity. 434 h.initNonce = msg.Nonce[:] 435 h.remoteID = msg.InitiatorPubkey 436 rpub, err := h.remoteID.Pubkey() 437 if err != nil { 438 return fmt.Errorf("bad remoteID: %#v", err) 439 } 440 h.remotePub = ecies.ImportECDSAPublic(rpub) 441 442 // Generate random keypair for ECDH. 443 // If a private key is already set, use it instead of generating one (for testing). 444 if h.randomPrivKey == nil { 445 h.randomPrivKey, err = ecies.GenerateKey(rand.Reader, crypto.S256(), nil) 446 if err != nil { 447 return err 448 } 449 } 450 451 // Check the signature. 452 token, err := h.staticSharedSecret(prv) 453 if err != nil { 454 return err 455 } 456 signedMsg := xor(token, h.initNonce) 457 remoteRandomPub, err := secp256k1.RecoverPubkey(signedMsg, msg.Signature[:]) 458 if err != nil { 459 return err 460 } 461 h.remoteRandomPub, _ = importPublicKey(remoteRandomPub) 462 return nil 463 } 464 465 func (h *encHandshake) makeAuthResp() (msg *authRespV4, err error) { 466 // Generate random nonce. 467 h.respNonce = make([]byte, shaLen) 468 if _, err = rand.Read(h.respNonce); err != nil { 469 return nil, err 470 } 471 472 msg = new(authRespV4) 473 copy(msg.Nonce[:], h.respNonce) 474 copy(msg.RandomPubkey[:], exportPubkey(&h.randomPrivKey.PublicKey)) 475 msg.Version = 4 476 return msg, nil 477 } 478 479 func (msg *authMsgV4) sealPlain(h *encHandshake) ([]byte, error) { 480 buf := make([]byte, authMsgLen) 481 n := copy(buf, msg.Signature[:]) 482 n += copy(buf[n:], crypto.Keccak256(exportPubkey(&h.randomPrivKey.PublicKey))) 483 n += copy(buf[n:], msg.InitiatorPubkey[:]) 484 n += copy(buf[n:], msg.Nonce[:]) 485 buf[n] = 0 // token-flag 486 return ecies.Encrypt(rand.Reader, h.remotePub, buf, nil, nil) 487 } 488 489 func (msg *authMsgV4) decodePlain(input []byte) { 490 n := copy(msg.Signature[:], input) 491 n += shaLen // skip sha3(initiator-ephemeral-pubk) 492 n += copy(msg.InitiatorPubkey[:], input[n:]) 493 copy(msg.Nonce[:], input[n:]) 494 msg.Version = 4 495 msg.gotPlain = true 496 } 497 498 func (msg *authRespV4) sealPlain(hs *encHandshake) ([]byte, error) { 499 buf := make([]byte, authRespLen) 500 n := copy(buf, msg.RandomPubkey[:]) 501 copy(buf[n:], msg.Nonce[:]) 502 return ecies.Encrypt(rand.Reader, hs.remotePub, buf, nil, nil) 503 } 504 505 func (msg *authRespV4) decodePlain(input []byte) { 506 n := copy(msg.RandomPubkey[:], input) 507 copy(msg.Nonce[:], input[n:]) 508 msg.Version = 4 509 } 510 511 var padSpace = make([]byte, 300) 512 513 func sealEIP8(msg interface{}, h *encHandshake) ([]byte, error) { 514 buf := new(bytes.Buffer) 515 if err := rlp.Encode(buf, msg); err != nil { 516 return nil, err 517 } 518 // pad with random amount of data. the amount needs to be at least 100 bytes to make 519 // the message distinguishable from pre-EIP-8 handshakes. 520 pad := padSpace[:mrand.Intn(len(padSpace)-100)+100] 521 buf.Write(pad) 522 prefix := make([]byte, 2) 523 binary.BigEndian.PutUint16(prefix, uint16(buf.Len()+eciesOverhead)) 524 525 enc, err := ecies.Encrypt(rand.Reader, h.remotePub, buf.Bytes(), nil, prefix) 526 return append(prefix, enc...), err 527 } 528 529 type plainDecoder interface { 530 decodePlain([]byte) 531 } 532 533 func readHandshakeMsg(msg plainDecoder, plainSize int, prv *ecdsa.PrivateKey, r io.Reader) ([]byte, error) { 534 buf := make([]byte, plainSize) 535 if _, err := io.ReadFull(r, buf); err != nil { 536 return buf, err 537 } 538 // Attempt decoding pre-EIP-8 "plain" format. 539 key := ecies.ImportECDSA(prv) 540 if dec, err := key.Decrypt(buf, nil, nil); err == nil { 541 msg.decodePlain(dec) 542 return buf, nil 543 } 544 // Could be EIP-8 format, try that. 545 prefix := buf[:2] 546 size := binary.BigEndian.Uint16(prefix) 547 if size < uint16(plainSize) { 548 return buf, fmt.Errorf("size underflow, need at least %d bytes", plainSize) 549 } 550 buf = append(buf, make([]byte, size-uint16(plainSize)+2)...) 551 if _, err := io.ReadFull(r, buf[plainSize:]); err != nil { 552 return buf, err 553 } 554 dec, err := key.Decrypt(buf[2:], nil, prefix) 555 if err != nil { 556 return buf, err 557 } 558 // Can't use rlp.DecodeBytes here because it rejects 559 // trailing data (forward-compatibility). 560 s := rlp.NewStream(bytes.NewReader(dec), 0) 561 return buf, s.Decode(msg) 562 } 563 564 // importPublicKey unmarshals 512 bit public keys. 565 func importPublicKey(pubKey []byte) (*ecies.PublicKey, error) { 566 var pubKey65 []byte 567 switch len(pubKey) { 568 case 64: 569 // add 'uncompressed key' flag 570 pubKey65 = append([]byte{0x04}, pubKey...) 571 case 65: 572 pubKey65 = pubKey 573 default: 574 return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey)) 575 } 576 // TODO: fewer pointless conversions 577 pub, err := crypto.UnmarshalPubkey(pubKey65) 578 if err != nil { 579 return nil, err 580 } 581 return ecies.ImportECDSAPublic(pub), nil 582 } 583 584 func exportPubkey(pub *ecies.PublicKey) []byte { 585 if pub == nil { 586 panic("nil pubkey") 587 } 588 return elliptic.Marshal(pub.Curve, pub.X, pub.Y)[1:] 589 } 590 591 func xor(one, other []byte) (xor []byte) { 592 xor = make([]byte, len(one)) 593 for i := 0; i < len(one); i++ { 594 xor[i] = one[i] ^ other[i] 595 } 596 return xor 597 } 598 599 var ( 600 // this is used in place of actual frame header data. 601 // TODO: replace this when Msg contains the protocol type code. 602 zeroHeader = []byte{0xC2, 0x80, 0x80} 603 // sixteen zero bytes 604 zero16 = make([]byte, 16) 605 ) 606 607 // rlpxFrameRW implements a simplified version of RLPx framing. 608 // chunked messages are not supported and all headers are equal to 609 // zeroHeader. 610 // 611 // rlpxFrameRW is not safe for concurrent use from multiple goroutines. 612 type rlpxFrameRW struct { 613 conn io.ReadWriter 614 enc cipher.Stream 615 dec cipher.Stream 616 617 macCipher cipher.Block 618 egressMAC hash.Hash 619 ingressMAC hash.Hash 620 621 snappy bool 622 } 623 624 func newRLPXFrameRW(conn io.ReadWriter, s secrets) *rlpxFrameRW { 625 macc, err := aes.NewCipher(s.MAC) 626 if err != nil { 627 panic("invalid MAC secret: " + err.Error()) 628 } 629 encc, err := aes.NewCipher(s.AES) 630 if err != nil { 631 panic("invalid AES secret: " + err.Error()) 632 } 633 // we use an all-zeroes IV for AES because the key used 634 // for encryption is ephemeral. 635 iv := make([]byte, encc.BlockSize()) 636 return &rlpxFrameRW{ 637 conn: conn, 638 enc: cipher.NewCTR(encc, iv), 639 dec: cipher.NewCTR(encc, iv), 640 macCipher: macc, 641 egressMAC: s.EgressMAC, 642 ingressMAC: s.IngressMAC, 643 } 644 } 645 646 func (rw *rlpxFrameRW) WriteMsg(msg Msg) error { 647 ptype, _ := rlp.EncodeToBytes(msg.Code) 648 649 // if snappy is enabled, compress message now 650 if rw.snappy { 651 if msg.Size > maxUint24 { 652 return errPlainMessageTooLarge 653 } 654 payload, _ := ioutil.ReadAll(msg.Payload) 655 payload = snappy.Encode(nil, payload) 656 657 msg.Payload = bytes.NewReader(payload) 658 msg.Size = uint32(len(payload)) 659 } 660 // write header 661 headbuf := make([]byte, 32) 662 fsize := uint32(len(ptype)) + msg.Size 663 if fsize > maxUint24 { 664 return errors.New("message size overflows uint24") 665 } 666 putInt24(fsize, headbuf) // TODO: check overflow 667 copy(headbuf[3:], zeroHeader) 668 rw.enc.XORKeyStream(headbuf[:16], headbuf[:16]) // first half is now encrypted 669 670 // write header MAC 671 copy(headbuf[16:], updateMAC(rw.egressMAC, rw.macCipher, headbuf[:16])) 672 if _, err := rw.conn.Write(headbuf); err != nil { 673 return err 674 } 675 676 // write encrypted frame, updating the egress MAC hash with 677 // the data written to conn. 678 tee := cipher.StreamWriter{S: rw.enc, W: io.MultiWriter(rw.conn, rw.egressMAC)} 679 if _, err := tee.Write(ptype); err != nil { 680 return err 681 } 682 if _, err := io.Copy(tee, msg.Payload); err != nil { 683 return err 684 } 685 if padding := fsize % 16; padding > 0 { 686 if _, err := tee.Write(zero16[:16-padding]); err != nil { 687 return err 688 } 689 } 690 691 // write frame MAC. egress MAC hash is up to date because 692 // frame content was written to it as well. 693 fmacseed := rw.egressMAC.Sum(nil) 694 mac := updateMAC(rw.egressMAC, rw.macCipher, fmacseed) 695 _, err := rw.conn.Write(mac) 696 return err 697 } 698 699 func (rw *rlpxFrameRW) ReadMsg() (msg Msg, err error) { 700 // read the header 701 headbuf := make([]byte, 32) 702 if _, err := io.ReadFull(rw.conn, headbuf); err != nil { 703 return msg, err 704 } 705 // verify header mac 706 shouldMAC := updateMAC(rw.ingressMAC, rw.macCipher, headbuf[:16]) 707 if !hmac.Equal(shouldMAC, headbuf[16:]) { 708 return msg, errors.New("bad header MAC") 709 } 710 rw.dec.XORKeyStream(headbuf[:16], headbuf[:16]) // first half is now decrypted 711 fsize := readInt24(headbuf) 712 // ignore protocol type for now 713 714 // read the frame content 715 rsize := fsize // frame size rounded up to 16 byte boundary 716 if padding := fsize % 16; padding > 0 { 717 rsize += 16 - padding 718 } 719 framebuf := make([]byte, rsize) 720 if _, err := io.ReadFull(rw.conn, framebuf); err != nil { 721 return msg, err 722 } 723 724 // read and validate frame MAC. we can re-use headbuf for that. 725 rw.ingressMAC.Write(framebuf) 726 fmacseed := rw.ingressMAC.Sum(nil) 727 if _, err := io.ReadFull(rw.conn, headbuf[:16]); err != nil { 728 return msg, err 729 } 730 shouldMAC = updateMAC(rw.ingressMAC, rw.macCipher, fmacseed) 731 if !hmac.Equal(shouldMAC, headbuf[:16]) { 732 return msg, errors.New("bad frame MAC") 733 } 734 735 // decrypt frame content 736 rw.dec.XORKeyStream(framebuf, framebuf) 737 738 // decode message code 739 content := bytes.NewReader(framebuf[:fsize]) 740 if err := rlp.Decode(content, &msg.Code); err != nil { 741 return msg, err 742 } 743 msg.Size = uint32(content.Len()) 744 msg.Payload = content 745 746 // if snappy is enabled, verify and decompress message 747 if rw.snappy { 748 payload, err := ioutil.ReadAll(msg.Payload) 749 if err != nil { 750 return msg, err 751 } 752 size, err := snappy.DecodedLen(payload) 753 if err != nil { 754 return msg, err 755 } 756 if size > int(maxUint24) { 757 return msg, errPlainMessageTooLarge 758 } 759 payload, err = snappy.Decode(nil, payload) 760 if err != nil { 761 return msg, err 762 } 763 msg.Size, msg.Payload = uint32(size), bytes.NewReader(payload) 764 } 765 return msg, nil 766 } 767 768 // updateMAC reseeds the given hash with encrypted seed. 769 // it returns the first 16 bytes of the hash sum after seeding. 770 func updateMAC(mac hash.Hash, block cipher.Block, seed []byte) []byte { 771 aesbuf := make([]byte, aes.BlockSize) 772 block.Encrypt(aesbuf, mac.Sum(nil)) 773 for i := range aesbuf { 774 aesbuf[i] ^= seed[i] 775 } 776 mac.Write(aesbuf) 777 return mac.Sum(nil)[:16] 778 } 779 780 func readInt24(b []byte) uint32 { 781 return uint32(b[2]) | uint32(b[1])<<8 | uint32(b[0])<<16 782 } 783 784 func putInt24(v uint32, b []byte) { 785 b[0] = byte(v >> 16) 786 b[1] = byte(v >> 8) 787 b[2] = byte(v) 788 }