github.com/zhiqiangxu/go-ethereum@v1.9.16-0.20210824055606-be91cfdebc48/p2p/discover/v5_encoding.go (about)

     1  // Copyright 2019 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 discover
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/aes"
    22  	"crypto/cipher"
    23  	"crypto/ecdsa"
    24  	"crypto/elliptic"
    25  	crand "crypto/rand"
    26  	"crypto/sha256"
    27  	"errors"
    28  	"fmt"
    29  	"hash"
    30  	"net"
    31  	"time"
    32  
    33  	"github.com/zhiqiangxu/go-ethereum/common/math"
    34  	"github.com/zhiqiangxu/go-ethereum/common/mclock"
    35  	"github.com/zhiqiangxu/go-ethereum/crypto"
    36  	"github.com/zhiqiangxu/go-ethereum/p2p/enode"
    37  	"github.com/zhiqiangxu/go-ethereum/p2p/enr"
    38  	"github.com/zhiqiangxu/go-ethereum/rlp"
    39  	"golang.org/x/crypto/hkdf"
    40  )
    41  
    42  // TODO concurrent WHOAREYOU tie-breaker
    43  // TODO deal with WHOAREYOU amplification factor (min packet size?)
    44  // TODO add counter to nonce
    45  // TODO rehandshake after X packets
    46  
    47  // Discovery v5 packet types.
    48  const (
    49  	p_pingV5 byte = iota + 1
    50  	p_pongV5
    51  	p_findnodeV5
    52  	p_nodesV5
    53  	p_requestTicketV5
    54  	p_ticketV5
    55  	p_regtopicV5
    56  	p_regconfirmationV5
    57  	p_topicqueryV5
    58  	p_unknownV5   = byte(255) // any non-decryptable packet
    59  	p_whoareyouV5 = byte(254) // the WHOAREYOU packet
    60  )
    61  
    62  // Discovery v5 packet structures.
    63  type (
    64  	// unknownV5 represents any packet that can't be decrypted.
    65  	unknownV5 struct {
    66  		AuthTag []byte
    67  	}
    68  
    69  	// WHOAREYOU contains the handshake challenge.
    70  	whoareyouV5 struct {
    71  		AuthTag   []byte
    72  		IDNonce   [32]byte // To be signed by recipient.
    73  		RecordSeq uint64   // ENR sequence number of recipient
    74  
    75  		node *enode.Node
    76  		sent mclock.AbsTime
    77  	}
    78  
    79  	// PING is sent during liveness checks.
    80  	pingV5 struct {
    81  		ReqID  []byte
    82  		ENRSeq uint64
    83  	}
    84  
    85  	// PONG is the reply to PING.
    86  	pongV5 struct {
    87  		ReqID  []byte
    88  		ENRSeq uint64
    89  		ToIP   net.IP // These fields should mirror the UDP envelope address of the ping
    90  		ToPort uint16 // packet, which provides a way to discover the the external address (after NAT).
    91  	}
    92  
    93  	// FINDNODE is a query for nodes in the given bucket.
    94  	findnodeV5 struct {
    95  		ReqID    []byte
    96  		Distance uint
    97  	}
    98  
    99  	// NODES is the reply to FINDNODE and TOPICQUERY.
   100  	nodesV5 struct {
   101  		ReqID []byte
   102  		Total uint8
   103  		Nodes []*enr.Record
   104  	}
   105  
   106  	// REQUESTTICKET requests a ticket for a topic queue.
   107  	requestTicketV5 struct {
   108  		ReqID []byte
   109  		Topic []byte
   110  	}
   111  
   112  	// TICKET is the response to REQUESTTICKET.
   113  	ticketV5 struct {
   114  		ReqID  []byte
   115  		Ticket []byte
   116  	}
   117  
   118  	// REGTOPIC registers the sender in a topic queue using a ticket.
   119  	regtopicV5 struct {
   120  		ReqID  []byte
   121  		Ticket []byte
   122  		ENR    *enr.Record
   123  	}
   124  
   125  	// REGCONFIRMATION is the reply to REGTOPIC.
   126  	regconfirmationV5 struct {
   127  		ReqID      []byte
   128  		Registered bool
   129  	}
   130  
   131  	// TOPICQUERY asks for nodes with the given topic.
   132  	topicqueryV5 struct {
   133  		ReqID []byte
   134  		Topic []byte
   135  	}
   136  )
   137  
   138  const (
   139  	// Encryption/authentication parameters.
   140  	authSchemeName   = "gcm"
   141  	aesKeySize       = 16
   142  	gcmNonceSize     = 12
   143  	idNoncePrefix    = "discovery-id-nonce"
   144  	handshakeTimeout = time.Second
   145  )
   146  
   147  var (
   148  	errTooShort               = errors.New("packet too short")
   149  	errUnexpectedHandshake    = errors.New("unexpected auth response, not in handshake")
   150  	errHandshakeNonceMismatch = errors.New("wrong nonce in auth response")
   151  	errInvalidAuthKey         = errors.New("invalid ephemeral pubkey")
   152  	errUnknownAuthScheme      = errors.New("unknown auth scheme in handshake")
   153  	errNoRecord               = errors.New("expected ENR in handshake but none sent")
   154  	errInvalidNonceSig        = errors.New("invalid ID nonce signature")
   155  	zeroNonce                 = make([]byte, gcmNonceSize)
   156  )
   157  
   158  // wireCodec encodes and decodes discovery v5 packets.
   159  type wireCodec struct {
   160  	sha256           hash.Hash
   161  	localnode        *enode.LocalNode
   162  	privkey          *ecdsa.PrivateKey
   163  	myChtagHash      enode.ID
   164  	myWhoareyouMagic []byte
   165  
   166  	sc *sessionCache
   167  }
   168  
   169  type handshakeSecrets struct {
   170  	writeKey, readKey, authRespKey []byte
   171  }
   172  
   173  type authHeader struct {
   174  	authHeaderList
   175  	isHandshake bool
   176  }
   177  
   178  type authHeaderList struct {
   179  	Auth         []byte   // authentication info of packet
   180  	IDNonce      [32]byte // IDNonce of WHOAREYOU
   181  	Scheme       string   // name of encryption/authentication scheme
   182  	EphemeralKey []byte   // ephemeral public key
   183  	Response     []byte   // encrypted authResponse
   184  }
   185  
   186  type authResponse struct {
   187  	Version   uint
   188  	Signature []byte
   189  	Record    *enr.Record `rlp:"nil"` // sender's record
   190  }
   191  
   192  func (h *authHeader) DecodeRLP(r *rlp.Stream) error {
   193  	k, _, err := r.Kind()
   194  	if err != nil {
   195  		return err
   196  	}
   197  	if k == rlp.Byte || k == rlp.String {
   198  		return r.Decode(&h.Auth)
   199  	}
   200  	h.isHandshake = true
   201  	return r.Decode(&h.authHeaderList)
   202  }
   203  
   204  // ephemeralKey decodes the ephemeral public key in the header.
   205  func (h *authHeaderList) ephemeralKey(curve elliptic.Curve) *ecdsa.PublicKey {
   206  	var key encPubkey
   207  	copy(key[:], h.EphemeralKey)
   208  	pubkey, _ := decodePubkey(curve, key)
   209  	return pubkey
   210  }
   211  
   212  // newWireCodec creates a wire codec.
   213  func newWireCodec(ln *enode.LocalNode, key *ecdsa.PrivateKey, clock mclock.Clock) *wireCodec {
   214  	c := &wireCodec{
   215  		sha256:    sha256.New(),
   216  		localnode: ln,
   217  		privkey:   key,
   218  		sc:        newSessionCache(1024, clock),
   219  	}
   220  	// Create magic strings for packet matching.
   221  	self := ln.ID()
   222  	c.myWhoareyouMagic = c.sha256sum(self[:], []byte("WHOAREYOU"))
   223  	copy(c.myChtagHash[:], c.sha256sum(self[:]))
   224  	return c
   225  }
   226  
   227  // encode encodes a packet to a node. 'id' and 'addr' specify the destination node. The
   228  // 'challenge' parameter should be the most recently received WHOAREYOU packet from that
   229  // node.
   230  func (c *wireCodec) encode(id enode.ID, addr string, packet packetV5, challenge *whoareyouV5) ([]byte, []byte, error) {
   231  	if packet.kind() == p_whoareyouV5 {
   232  		p := packet.(*whoareyouV5)
   233  		enc, err := c.encodeWhoareyou(id, p)
   234  		if err == nil {
   235  			c.sc.storeSentHandshake(id, addr, p)
   236  		}
   237  		return enc, nil, err
   238  	}
   239  	// Ensure calling code sets node if needed.
   240  	if challenge != nil && challenge.node == nil {
   241  		panic("BUG: missing challenge.node in encode")
   242  	}
   243  	writeKey := c.sc.writeKey(id, addr)
   244  	if writeKey != nil || challenge != nil {
   245  		return c.encodeEncrypted(id, addr, packet, writeKey, challenge)
   246  	}
   247  	return c.encodeRandom(id)
   248  }
   249  
   250  // encodeRandom encodes a random packet.
   251  func (c *wireCodec) encodeRandom(toID enode.ID) ([]byte, []byte, error) {
   252  	tag := xorTag(c.sha256sum(toID[:]), c.localnode.ID())
   253  	r := make([]byte, 44) // TODO randomize size
   254  	if _, err := crand.Read(r); err != nil {
   255  		return nil, nil, err
   256  	}
   257  	nonce := make([]byte, gcmNonceSize)
   258  	if _, err := crand.Read(nonce); err != nil {
   259  		return nil, nil, fmt.Errorf("can't get random data: %v", err)
   260  	}
   261  	b := new(bytes.Buffer)
   262  	b.Write(tag[:])
   263  	rlp.Encode(b, nonce)
   264  	b.Write(r)
   265  	return b.Bytes(), nonce, nil
   266  }
   267  
   268  // encodeWhoareyou encodes WHOAREYOU.
   269  func (c *wireCodec) encodeWhoareyou(toID enode.ID, packet *whoareyouV5) ([]byte, error) {
   270  	// Sanity check node field to catch misbehaving callers.
   271  	if packet.RecordSeq > 0 && packet.node == nil {
   272  		panic("BUG: missing node in whoareyouV5 with non-zero seq")
   273  	}
   274  	b := new(bytes.Buffer)
   275  	b.Write(c.sha256sum(toID[:], []byte("WHOAREYOU")))
   276  	err := rlp.Encode(b, packet)
   277  	return b.Bytes(), err
   278  }
   279  
   280  // encodeEncrypted encodes an encrypted packet.
   281  func (c *wireCodec) encodeEncrypted(toID enode.ID, toAddr string, packet packetV5, writeKey []byte, challenge *whoareyouV5) (enc []byte, authTag []byte, err error) {
   282  	nonce := make([]byte, gcmNonceSize)
   283  	if _, err := crand.Read(nonce); err != nil {
   284  		return nil, nil, fmt.Errorf("can't get random data: %v", err)
   285  	}
   286  
   287  	var headEnc []byte
   288  	if challenge == nil {
   289  		// Regular packet, use existing key and simply encode nonce.
   290  		headEnc, _ = rlp.EncodeToBytes(nonce)
   291  	} else {
   292  		// We're answering WHOAREYOU, generate new keys and encrypt with those.
   293  		header, sec, err := c.makeAuthHeader(nonce, challenge)
   294  		if err != nil {
   295  			return nil, nil, err
   296  		}
   297  		if headEnc, err = rlp.EncodeToBytes(header); err != nil {
   298  			return nil, nil, err
   299  		}
   300  		c.sc.storeNewSession(toID, toAddr, sec.readKey, sec.writeKey)
   301  		writeKey = sec.writeKey
   302  	}
   303  
   304  	// Encode the packet.
   305  	body := new(bytes.Buffer)
   306  	body.WriteByte(packet.kind())
   307  	if err := rlp.Encode(body, packet); err != nil {
   308  		return nil, nil, err
   309  	}
   310  	tag := xorTag(c.sha256sum(toID[:]), c.localnode.ID())
   311  	headsize := len(tag) + len(headEnc)
   312  	headbuf := make([]byte, headsize)
   313  	copy(headbuf[:], tag[:])
   314  	copy(headbuf[len(tag):], headEnc)
   315  
   316  	// Encrypt the body.
   317  	enc, err = encryptGCM(headbuf, writeKey, nonce, body.Bytes(), tag[:])
   318  	return enc, nonce, err
   319  }
   320  
   321  // encodeAuthHeader creates the auth header on a call packet following WHOAREYOU.
   322  func (c *wireCodec) makeAuthHeader(nonce []byte, challenge *whoareyouV5) (*authHeaderList, *handshakeSecrets, error) {
   323  	resp := &authResponse{Version: 5}
   324  
   325  	// Add our record to response if it's newer than what remote
   326  	// side has.
   327  	ln := c.localnode.Node()
   328  	if challenge.RecordSeq < ln.Seq() {
   329  		resp.Record = ln.Record()
   330  	}
   331  
   332  	// Create the ephemeral key. This needs to be first because the
   333  	// key is part of the ID nonce signature.
   334  	var remotePubkey = new(ecdsa.PublicKey)
   335  	if err := challenge.node.Load((*enode.Secp256k1)(remotePubkey)); err != nil {
   336  		return nil, nil, fmt.Errorf("can't find secp256k1 key for recipient")
   337  	}
   338  	ephkey, err := crypto.GenerateKey()
   339  	if err != nil {
   340  		return nil, nil, fmt.Errorf("can't generate ephemeral key")
   341  	}
   342  	ephpubkey := encodePubkey(&ephkey.PublicKey)
   343  
   344  	// Add ID nonce signature to response.
   345  	idsig, err := c.signIDNonce(challenge.IDNonce[:], ephpubkey[:])
   346  	if err != nil {
   347  		return nil, nil, fmt.Errorf("can't sign: %v", err)
   348  	}
   349  	resp.Signature = idsig
   350  
   351  	// Create session keys.
   352  	sec := c.deriveKeys(c.localnode.ID(), challenge.node.ID(), ephkey, remotePubkey, challenge)
   353  	if sec == nil {
   354  		return nil, nil, fmt.Errorf("key derivation failed")
   355  	}
   356  
   357  	// Encrypt the authentication response and assemble the auth header.
   358  	respRLP, err := rlp.EncodeToBytes(resp)
   359  	if err != nil {
   360  		return nil, nil, fmt.Errorf("can't encode auth response: %v", err)
   361  	}
   362  	respEnc, err := encryptGCM(nil, sec.authRespKey, zeroNonce, respRLP, nil)
   363  	if err != nil {
   364  		return nil, nil, fmt.Errorf("can't encrypt auth response: %v", err)
   365  	}
   366  	head := &authHeaderList{
   367  		Auth:         nonce,
   368  		Scheme:       authSchemeName,
   369  		IDNonce:      challenge.IDNonce,
   370  		EphemeralKey: ephpubkey[:],
   371  		Response:     respEnc,
   372  	}
   373  	return head, sec, err
   374  }
   375  
   376  // deriveKeys generates session keys using elliptic-curve Diffie-Hellman key agreement.
   377  func (c *wireCodec) deriveKeys(n1, n2 enode.ID, priv *ecdsa.PrivateKey, pub *ecdsa.PublicKey, challenge *whoareyouV5) *handshakeSecrets {
   378  	eph := ecdh(priv, pub)
   379  	if eph == nil {
   380  		return nil
   381  	}
   382  
   383  	info := []byte("discovery v5 key agreement")
   384  	info = append(info, n1[:]...)
   385  	info = append(info, n2[:]...)
   386  	kdf := hkdf.New(c.sha256reset, eph, challenge.IDNonce[:], info)
   387  	sec := handshakeSecrets{
   388  		writeKey:    make([]byte, aesKeySize),
   389  		readKey:     make([]byte, aesKeySize),
   390  		authRespKey: make([]byte, aesKeySize),
   391  	}
   392  	kdf.Read(sec.writeKey)
   393  	kdf.Read(sec.readKey)
   394  	kdf.Read(sec.authRespKey)
   395  	for i := range eph {
   396  		eph[i] = 0
   397  	}
   398  	return &sec
   399  }
   400  
   401  // signIDNonce creates the ID nonce signature.
   402  func (c *wireCodec) signIDNonce(nonce, ephkey []byte) ([]byte, error) {
   403  	idsig, err := crypto.Sign(c.idNonceHash(nonce, ephkey), c.privkey)
   404  	if err != nil {
   405  		return nil, fmt.Errorf("can't sign: %v", err)
   406  	}
   407  	return idsig[:len(idsig)-1], nil // remove recovery ID
   408  }
   409  
   410  // idNonceHash computes the hash of id nonce with prefix.
   411  func (c *wireCodec) idNonceHash(nonce, ephkey []byte) []byte {
   412  	h := c.sha256reset()
   413  	h.Write([]byte(idNoncePrefix))
   414  	h.Write(nonce)
   415  	h.Write(ephkey)
   416  	return h.Sum(nil)
   417  }
   418  
   419  // decode decodes a discovery packet.
   420  func (c *wireCodec) decode(input []byte, addr string) (enode.ID, *enode.Node, packetV5, error) {
   421  	// Delete timed-out handshakes. This must happen before decoding to avoid
   422  	// processing the same handshake twice.
   423  	c.sc.handshakeGC()
   424  
   425  	if len(input) < 32 {
   426  		return enode.ID{}, nil, nil, errTooShort
   427  	}
   428  	if bytes.HasPrefix(input, c.myWhoareyouMagic) {
   429  		p, err := c.decodeWhoareyou(input)
   430  		return enode.ID{}, nil, p, err
   431  	}
   432  	sender := xorTag(input[:32], c.myChtagHash)
   433  	p, n, err := c.decodeEncrypted(sender, addr, input)
   434  	return sender, n, p, err
   435  }
   436  
   437  // decodeWhoareyou decode a WHOAREYOU packet.
   438  func (c *wireCodec) decodeWhoareyou(input []byte) (packetV5, error) {
   439  	packet := new(whoareyouV5)
   440  	err := rlp.DecodeBytes(input[32:], packet)
   441  	return packet, err
   442  }
   443  
   444  // decodeEncrypted decodes an encrypted discovery packet.
   445  func (c *wireCodec) decodeEncrypted(fromID enode.ID, fromAddr string, input []byte) (packetV5, *enode.Node, error) {
   446  	// Decode packet header.
   447  	var head authHeader
   448  	r := bytes.NewReader(input[32:])
   449  	err := rlp.Decode(r, &head)
   450  	if err != nil {
   451  		return nil, nil, err
   452  	}
   453  
   454  	// Decrypt and process auth response.
   455  	readKey, node, err := c.decodeAuth(fromID, fromAddr, &head)
   456  	if err != nil {
   457  		return nil, nil, err
   458  	}
   459  
   460  	// Decrypt and decode the packet body.
   461  	headsize := len(input) - r.Len()
   462  	bodyEnc := input[headsize:]
   463  	body, err := decryptGCM(readKey, head.Auth, bodyEnc, input[:32])
   464  	if err != nil {
   465  		if !head.isHandshake {
   466  			// Can't decrypt, start handshake.
   467  			return &unknownV5{AuthTag: head.Auth}, nil, nil
   468  		}
   469  		return nil, nil, fmt.Errorf("handshake failed: %v", err)
   470  	}
   471  	if len(body) == 0 {
   472  		return nil, nil, errTooShort
   473  	}
   474  	p, err := decodePacketBodyV5(body[0], body[1:])
   475  	return p, node, err
   476  }
   477  
   478  // decodeAuth processes an auth header.
   479  func (c *wireCodec) decodeAuth(fromID enode.ID, fromAddr string, head *authHeader) ([]byte, *enode.Node, error) {
   480  	if !head.isHandshake {
   481  		return c.sc.readKey(fromID, fromAddr), nil, nil
   482  	}
   483  
   484  	// Remote is attempting handshake. Verify against our last WHOAREYOU.
   485  	challenge := c.sc.getHandshake(fromID, fromAddr)
   486  	if challenge == nil {
   487  		return nil, nil, errUnexpectedHandshake
   488  	}
   489  	if head.IDNonce != challenge.IDNonce {
   490  		return nil, nil, errHandshakeNonceMismatch
   491  	}
   492  	sec, n, err := c.decodeAuthResp(fromID, fromAddr, &head.authHeaderList, challenge)
   493  	if err != nil {
   494  		return nil, n, err
   495  	}
   496  	// Swap keys to match remote.
   497  	sec.readKey, sec.writeKey = sec.writeKey, sec.readKey
   498  	c.sc.storeNewSession(fromID, fromAddr, sec.readKey, sec.writeKey)
   499  	c.sc.deleteHandshake(fromID, fromAddr)
   500  	return sec.readKey, n, err
   501  }
   502  
   503  // decodeAuthResp decodes and verifies an authentication response.
   504  func (c *wireCodec) decodeAuthResp(fromID enode.ID, fromAddr string, head *authHeaderList, challenge *whoareyouV5) (*handshakeSecrets, *enode.Node, error) {
   505  	// Decrypt / decode the response.
   506  	if head.Scheme != authSchemeName {
   507  		return nil, nil, errUnknownAuthScheme
   508  	}
   509  	ephkey := head.ephemeralKey(c.privkey.Curve)
   510  	if ephkey == nil {
   511  		return nil, nil, errInvalidAuthKey
   512  	}
   513  	sec := c.deriveKeys(fromID, c.localnode.ID(), c.privkey, ephkey, challenge)
   514  	respPT, err := decryptGCM(sec.authRespKey, zeroNonce, head.Response, nil)
   515  	if err != nil {
   516  		return nil, nil, fmt.Errorf("can't decrypt auth response header: %v", err)
   517  	}
   518  	var resp authResponse
   519  	if err := rlp.DecodeBytes(respPT, &resp); err != nil {
   520  		return nil, nil, fmt.Errorf("invalid auth response: %v", err)
   521  	}
   522  
   523  	// Verify response node record. The remote node should include the record
   524  	// if we don't have one or if ours is older than the latest version.
   525  	node := challenge.node
   526  	if resp.Record != nil {
   527  		if node == nil || node.Seq() < resp.Record.Seq() {
   528  			n, err := enode.New(enode.ValidSchemes, resp.Record)
   529  			if err != nil {
   530  				return nil, nil, fmt.Errorf("invalid node record: %v", err)
   531  			}
   532  			if n.ID() != fromID {
   533  				return nil, nil, fmt.Errorf("record in auth respose has wrong ID: %v", n.ID())
   534  			}
   535  			node = n
   536  		}
   537  	}
   538  	if node == nil {
   539  		return nil, nil, errNoRecord
   540  	}
   541  
   542  	// Verify ID nonce signature.
   543  	err = c.verifyIDSignature(challenge.IDNonce[:], head.EphemeralKey, resp.Signature, node)
   544  	if err != nil {
   545  		return nil, nil, err
   546  	}
   547  	return sec, node, nil
   548  }
   549  
   550  // verifyIDSignature checks that signature over idnonce was made by the node with given record.
   551  func (c *wireCodec) verifyIDSignature(nonce, ephkey, sig []byte, n *enode.Node) error {
   552  	switch idscheme := n.Record().IdentityScheme(); idscheme {
   553  	case "v4":
   554  		var pk ecdsa.PublicKey
   555  		n.Load((*enode.Secp256k1)(&pk)) // cannot fail because record is valid
   556  		if !crypto.VerifySignature(crypto.FromECDSAPub(&pk), c.idNonceHash(nonce, ephkey), sig) {
   557  			return errInvalidNonceSig
   558  		}
   559  		return nil
   560  	default:
   561  		return fmt.Errorf("can't verify ID nonce signature against scheme %q", idscheme)
   562  	}
   563  }
   564  
   565  // decodePacketBody decodes the body of an encrypted discovery packet.
   566  func decodePacketBodyV5(ptype byte, body []byte) (packetV5, error) {
   567  	var dec packetV5
   568  	switch ptype {
   569  	case p_pingV5:
   570  		dec = new(pingV5)
   571  	case p_pongV5:
   572  		dec = new(pongV5)
   573  	case p_findnodeV5:
   574  		dec = new(findnodeV5)
   575  	case p_nodesV5:
   576  		dec = new(nodesV5)
   577  	case p_requestTicketV5:
   578  		dec = new(requestTicketV5)
   579  	case p_ticketV5:
   580  		dec = new(ticketV5)
   581  	case p_regtopicV5:
   582  		dec = new(regtopicV5)
   583  	case p_regconfirmationV5:
   584  		dec = new(regconfirmationV5)
   585  	case p_topicqueryV5:
   586  		dec = new(topicqueryV5)
   587  	default:
   588  		return nil, fmt.Errorf("unknown packet type %d", ptype)
   589  	}
   590  	if err := rlp.DecodeBytes(body, dec); err != nil {
   591  		return nil, err
   592  	}
   593  	return dec, nil
   594  }
   595  
   596  // sha256reset returns the shared hash instance.
   597  func (c *wireCodec) sha256reset() hash.Hash {
   598  	c.sha256.Reset()
   599  	return c.sha256
   600  }
   601  
   602  // sha256sum computes sha256 on the concatenation of inputs.
   603  func (c *wireCodec) sha256sum(inputs ...[]byte) []byte {
   604  	c.sha256.Reset()
   605  	for _, b := range inputs {
   606  		c.sha256.Write(b)
   607  	}
   608  	return c.sha256.Sum(nil)
   609  }
   610  
   611  func xorTag(a []byte, b enode.ID) enode.ID {
   612  	var r enode.ID
   613  	for i := range r {
   614  		r[i] = a[i] ^ b[i]
   615  	}
   616  	return r
   617  }
   618  
   619  // ecdh creates a shared secret.
   620  func ecdh(privkey *ecdsa.PrivateKey, pubkey *ecdsa.PublicKey) []byte {
   621  	secX, secY := pubkey.ScalarMult(pubkey.X, pubkey.Y, privkey.D.Bytes())
   622  	if secX == nil {
   623  		return nil
   624  	}
   625  	sec := make([]byte, 33)
   626  	sec[0] = 0x02 | byte(secY.Bit(0))
   627  	math.ReadBits(secX, sec[1:])
   628  	return sec
   629  }
   630  
   631  // encryptGCM encrypts pt using AES-GCM with the given key and nonce.
   632  func encryptGCM(dest, key, nonce, pt, authData []byte) ([]byte, error) {
   633  	block, err := aes.NewCipher(key)
   634  	if err != nil {
   635  		panic(fmt.Errorf("can't create block cipher: %v", err))
   636  	}
   637  	aesgcm, err := cipher.NewGCMWithNonceSize(block, gcmNonceSize)
   638  	if err != nil {
   639  		panic(fmt.Errorf("can't create GCM: %v", err))
   640  	}
   641  	return aesgcm.Seal(dest, nonce, pt, authData), nil
   642  }
   643  
   644  // decryptGCM decrypts ct using AES-GCM with the given key and nonce.
   645  func decryptGCM(key, nonce, ct, authData []byte) ([]byte, error) {
   646  	block, err := aes.NewCipher(key)
   647  	if err != nil {
   648  		return nil, fmt.Errorf("can't create block cipher: %v", err)
   649  	}
   650  	if len(nonce) != gcmNonceSize {
   651  		return nil, fmt.Errorf("invalid GCM nonce size: %d", len(nonce))
   652  	}
   653  	aesgcm, err := cipher.NewGCMWithNonceSize(block, gcmNonceSize)
   654  	if err != nil {
   655  		return nil, fmt.Errorf("can't create GCM: %v", err)
   656  	}
   657  	pt := make([]byte, 0, len(ct))
   658  	return aesgcm.Open(pt, nonce, ct, authData)
   659  }