session.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright 2020 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. package v5wire
  17. import (
  18. "crypto/ecdsa"
  19. crand "crypto/rand"
  20. "encoding/binary"
  21. "time"
  22. "blockchain-go/common/mclock"
  23. "blockchain-go/p2p/enode"
  24. "blockchain-go/simplelru"
  25. "github.com/ethereum/go-ethereum/crypto"
  26. )
  27. const handshakeTimeout = time.Second
  28. // The SessionCache keeps negotiated encryption keys and
  29. // state for in-progress handshakes in the Discovery v5 wire protocol.
  30. type SessionCache struct {
  31. sessions *simplelru.LRU
  32. handshakes map[sessionID]*Whoareyou
  33. clock mclock.Clock
  34. // hooks for overriding randomness.
  35. nonceGen func(uint32) (Nonce, error)
  36. maskingIVGen func([]byte) error
  37. ephemeralKeyGen func() (*ecdsa.PrivateKey, error)
  38. }
  39. // sessionID identifies a session or handshake.
  40. type sessionID struct {
  41. id enode.ID
  42. addr string
  43. }
  44. // session contains session information
  45. type session struct {
  46. writeKey []byte
  47. readKey []byte
  48. nonceCounter uint32
  49. }
  50. // keysFlipped returns a copy of s with the read and write keys flipped.
  51. func (s *session) keysFlipped() *session {
  52. return &session{s.readKey, s.writeKey, s.nonceCounter}
  53. }
  54. func NewSessionCache(maxItems int, clock mclock.Clock) *SessionCache {
  55. cache, err := simplelru.NewLRU(maxItems, nil)
  56. if err != nil {
  57. panic("can't create session cache")
  58. }
  59. return &SessionCache{
  60. sessions: cache,
  61. handshakes: make(map[sessionID]*Whoareyou),
  62. clock: clock,
  63. nonceGen: generateNonce,
  64. maskingIVGen: generateMaskingIV,
  65. ephemeralKeyGen: crypto.GenerateKey,
  66. }
  67. }
  68. func generateNonce(counter uint32) (n Nonce, err error) {
  69. binary.BigEndian.PutUint32(n[:4], counter)
  70. _, err = crand.Read(n[4:])
  71. return n, err
  72. }
  73. func generateMaskingIV(buf []byte) error {
  74. _, err := crand.Read(buf)
  75. return err
  76. }
  77. // nextNonce creates a nonce for encrypting a message to the given session.
  78. func (sc *SessionCache) nextNonce(s *session) (Nonce, error) {
  79. s.nonceCounter++
  80. return sc.nonceGen(s.nonceCounter)
  81. }
  82. // session returns the current session for the given node, if any.
  83. func (sc *SessionCache) session(id enode.ID, addr string) *session {
  84. item, ok := sc.sessions.Get(sessionID{id, addr})
  85. if !ok {
  86. return nil
  87. }
  88. return item.(*session)
  89. }
  90. // readKey returns the current read key for the given node.
  91. func (sc *SessionCache) readKey(id enode.ID, addr string) []byte {
  92. if s := sc.session(id, addr); s != nil {
  93. return s.readKey
  94. }
  95. return nil
  96. }
  97. // storeNewSession stores new encryption keys in the cache.
  98. func (sc *SessionCache) storeNewSession(id enode.ID, addr string, s *session) {
  99. sc.sessions.Add(sessionID{id, addr}, s)
  100. }
  101. // getHandshake gets the handshake challenge we previously sent to the given remote node.
  102. func (sc *SessionCache) getHandshake(id enode.ID, addr string) *Whoareyou {
  103. return sc.handshakes[sessionID{id, addr}]
  104. }
  105. // storeSentHandshake stores the handshake challenge sent to the given remote node.
  106. func (sc *SessionCache) storeSentHandshake(id enode.ID, addr string, challenge *Whoareyou) {
  107. challenge.sent = sc.clock.Now()
  108. sc.handshakes[sessionID{id, addr}] = challenge
  109. }
  110. // deleteHandshake deletes handshake data for the given node.
  111. func (sc *SessionCache) deleteHandshake(id enode.ID, addr string) {
  112. delete(sc.handshakes, sessionID{id, addr})
  113. }
  114. // handshakeGC deletes timed-out handshakes.
  115. func (sc *SessionCache) handshakeGC() {
  116. deadline := sc.clock.Now().Add(-handshakeTimeout)
  117. for key, challenge := range sc.handshakes {
  118. if challenge.sent < deadline {
  119. delete(sc.handshakes, key)
  120. }
  121. }
  122. }