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