github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/p2p/connection/secret_connection.go (about)

     1  package connection
     2  
     3  import (
     4  	"bytes"
     5  	crand "crypto/rand"
     6  	"crypto/sha256"
     7  	"encoding/binary"
     8  	"errors"
     9  	"io"
    10  	"net"
    11  	"time"
    12  
    13  	log "github.com/sirupsen/logrus"
    14  	"golang.org/x/crypto/nacl/box"
    15  	"golang.org/x/crypto/nacl/secretbox"
    16  	"golang.org/x/crypto/ripemd160"
    17  
    18  	"github.com/tendermint/go-crypto"
    19  	wire "github.com/tendermint/go-wire"
    20  	cmn "github.com/tendermint/tmlibs/common"
    21  )
    22  
    23  const (
    24  	dataLenSize     = 2 // uint16 to describe the length, is <= dataMaxSize
    25  	dataMaxSize     = 1024
    26  	totalFrameSize  = dataMaxSize + dataLenSize
    27  	sealedFrameSize = totalFrameSize + secretbox.Overhead
    28  	authSigMsgSize  = (32 + 1) + (64 + 1) // fixed size (length prefixed) byte arrays
    29  )
    30  
    31  type authSigMessage struct {
    32  	Key crypto.PubKey
    33  	Sig crypto.Signature
    34  }
    35  
    36  // SecretConnection implements net.Conn
    37  type SecretConnection struct {
    38  	conn       io.ReadWriteCloser
    39  	recvBuffer []byte
    40  	recvNonce  *[24]byte
    41  	sendNonce  *[24]byte
    42  	remPubKey  crypto.PubKeyEd25519
    43  	shrSecret  *[32]byte // shared secret
    44  }
    45  
    46  // MakeSecretConnection performs handshake and returns a new authenticated SecretConnection.
    47  func MakeSecretConnection(conn io.ReadWriteCloser, locPrivKey crypto.PrivKeyEd25519) (*SecretConnection, error) {
    48  	locPubKey := locPrivKey.PubKey().Unwrap().(crypto.PubKeyEd25519)
    49  
    50  	// Generate ephemeral keys for perfect forward secrecy.
    51  	locEphPub, locEphPriv := genEphKeys()
    52  
    53  	// Write local ephemeral pubkey and receive one too.
    54  	// NOTE: every 32-byte string is accepted as a Curve25519 public key
    55  	// (see DJB's Curve25519 paper: http://cr.yp.to/ecdh/curve25519-20060209.pdf)
    56  	remEphPub, err := shareEphPubKey(conn, locEphPub)
    57  	if err != nil {
    58  		return nil, err
    59  	}
    60  
    61  	// Compute common shared secret.
    62  	shrSecret := computeSharedSecret(remEphPub, locEphPriv)
    63  
    64  	// Sort by lexical order.
    65  	loEphPub, hiEphPub := sort32(locEphPub, remEphPub)
    66  
    67  	// Generate nonces to use for secretbox.
    68  	recvNonce, sendNonce := genNonces(loEphPub, hiEphPub, locEphPub == loEphPub)
    69  
    70  	// Generate common challenge to sign.
    71  	challenge := genChallenge(loEphPub, hiEphPub)
    72  
    73  	// Construct SecretConnection.
    74  	sc := &SecretConnection{
    75  		conn:       conn,
    76  		recvBuffer: nil,
    77  		recvNonce:  recvNonce,
    78  		sendNonce:  sendNonce,
    79  		shrSecret:  shrSecret,
    80  	}
    81  
    82  	// Sign the challenge bytes for authentication.
    83  	locSignature := signChallenge(challenge, locPrivKey)
    84  
    85  	// Share (in secret) each other's pubkey & challenge signature
    86  	authSigMsg, err := shareAuthSignature(sc, locPubKey, locSignature)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  
    91  	remPubKey, remSignature := authSigMsg.Key, authSigMsg.Sig
    92  	if _, ok := remPubKey.PubKeyInner.(crypto.PubKeyEd25519); !ok {
    93  		return nil, errors.New("peer sent a nil public key")
    94  	}
    95  
    96  	if !remPubKey.VerifyBytes(challenge[:], remSignature) {
    97  		return nil, errors.New("Challenge verification failed")
    98  	}
    99  
   100  	sc.remPubKey = remPubKey.Unwrap().(crypto.PubKeyEd25519)
   101  	return sc, nil
   102  }
   103  
   104  // CONTRACT: data smaller than dataMaxSize is read atomically.
   105  func (sc *SecretConnection) Read(data []byte) (n int, err error) {
   106  	if 0 < len(sc.recvBuffer) {
   107  		n_ := copy(data, sc.recvBuffer)
   108  		sc.recvBuffer = sc.recvBuffer[n_:]
   109  		return
   110  	}
   111  
   112  	sealedFrame := make([]byte, sealedFrameSize)
   113  	if _, err = io.ReadFull(sc.conn, sealedFrame); err != nil {
   114  		return
   115  	}
   116  
   117  	// decrypt the frame
   118  	frame := make([]byte, totalFrameSize)
   119  	if _, ok := secretbox.Open(frame[:0], sealedFrame, sc.recvNonce, sc.shrSecret); !ok {
   120  		return n, errors.New("Failed to decrypt SecretConnection")
   121  	}
   122  
   123  	incr2Nonce(sc.recvNonce)
   124  	chunkLength := binary.BigEndian.Uint16(frame) // read the first two bytes
   125  	if chunkLength > dataMaxSize {
   126  		return 0, errors.New("chunkLength is greater than dataMaxSize")
   127  	}
   128  
   129  	chunk := frame[dataLenSize : dataLenSize+chunkLength]
   130  	n = copy(data, chunk)
   131  	sc.recvBuffer = chunk[n:]
   132  	return
   133  }
   134  
   135  // RemotePubKey returns authenticated remote pubkey
   136  func (sc *SecretConnection) RemotePubKey() crypto.PubKeyEd25519 {
   137  	return sc.remPubKey
   138  }
   139  
   140  // Writes encrypted frames of `sealedFrameSize`
   141  // CONTRACT: data smaller than dataMaxSize is read atomically.
   142  func (sc *SecretConnection) Write(data []byte) (n int, err error) {
   143  	for 0 < len(data) {
   144  		var chunk []byte
   145  		frame := make([]byte, totalFrameSize)
   146  		if dataMaxSize < len(data) {
   147  			chunk = data[:dataMaxSize]
   148  			data = data[dataMaxSize:]
   149  		} else {
   150  			chunk = data
   151  			data = nil
   152  		}
   153  		binary.BigEndian.PutUint16(frame, uint16(len(chunk)))
   154  		copy(frame[dataLenSize:], chunk)
   155  
   156  		// encrypt the frame
   157  		sealedFrame := make([]byte, sealedFrameSize)
   158  		secretbox.Seal(sealedFrame[:0], frame, sc.sendNonce, sc.shrSecret)
   159  		incr2Nonce(sc.sendNonce)
   160  
   161  		if _, err := sc.conn.Write(sealedFrame); err != nil {
   162  			return n, err
   163  		}
   164  
   165  		n += len(chunk)
   166  	}
   167  	return
   168  }
   169  
   170  // Close implements net.Conn
   171  func (sc *SecretConnection) Close() error { return sc.conn.Close() }
   172  
   173  // LocalAddr implements net.Conn
   174  func (sc *SecretConnection) LocalAddr() net.Addr { return sc.conn.(net.Conn).LocalAddr() }
   175  
   176  // RemoteAddr implements net.Conn
   177  func (sc *SecretConnection) RemoteAddr() net.Addr { return sc.conn.(net.Conn).RemoteAddr() }
   178  
   179  // SetDeadline implements net.Conn
   180  func (sc *SecretConnection) SetDeadline(t time.Time) error { return sc.conn.(net.Conn).SetDeadline(t) }
   181  
   182  // SetReadDeadline implements net.Conn
   183  func (sc *SecretConnection) SetReadDeadline(t time.Time) error {
   184  	return sc.conn.(net.Conn).SetReadDeadline(t)
   185  }
   186  
   187  // SetWriteDeadline implements net.Conn
   188  func (sc *SecretConnection) SetWriteDeadline(t time.Time) error {
   189  	return sc.conn.(net.Conn).SetWriteDeadline(t)
   190  }
   191  
   192  func computeSharedSecret(remPubKey, locPrivKey *[32]byte) (shrSecret *[32]byte) {
   193  	shrSecret = new([32]byte)
   194  	box.Precompute(shrSecret, remPubKey, locPrivKey)
   195  	return
   196  }
   197  
   198  func genChallenge(loPubKey, hiPubKey *[32]byte) (challenge *[32]byte) {
   199  	return hash32(append(loPubKey[:], hiPubKey[:]...))
   200  }
   201  
   202  // increment nonce big-endian by 2 with wraparound.
   203  func incr2Nonce(nonce *[24]byte) {
   204  	incrNonce(nonce)
   205  	incrNonce(nonce)
   206  }
   207  
   208  // increment nonce big-endian by 1 with wraparound.
   209  func incrNonce(nonce *[24]byte) {
   210  	for i := 23; 0 <= i; i-- {
   211  		nonce[i]++
   212  		if nonce[i] != 0 {
   213  			return
   214  		}
   215  	}
   216  }
   217  
   218  func genEphKeys() (ephPub, ephPriv *[32]byte) {
   219  	var err error
   220  	ephPub, ephPriv, err = box.GenerateKey(crand.Reader)
   221  	if err != nil {
   222  		log.Panic("Could not generate ephemeral keypairs")
   223  	}
   224  	return
   225  }
   226  
   227  func genNonces(loPubKey, hiPubKey *[32]byte, locIsLo bool) (*[24]byte, *[24]byte) {
   228  	nonce1 := hash24(append(loPubKey[:], hiPubKey[:]...))
   229  	nonce2 := new([24]byte)
   230  	copy(nonce2[:], nonce1[:])
   231  	nonce2[len(nonce2)-1] ^= 0x01
   232  	if locIsLo {
   233  		return nonce1, nonce2
   234  	}
   235  	return nonce2, nonce1
   236  }
   237  
   238  func signChallenge(challenge *[32]byte, locPrivKey crypto.PrivKeyEd25519) (signature crypto.SignatureEd25519) {
   239  	signature = locPrivKey.Sign(challenge[:]).Unwrap().(crypto.SignatureEd25519)
   240  	return
   241  }
   242  
   243  func shareAuthSignature(sc *SecretConnection, pubKey crypto.PubKeyEd25519, signature crypto.SignatureEd25519) (*authSigMessage, error) {
   244  	var recvMsg authSigMessage
   245  	var err1, err2 error
   246  
   247  	cmn.Parallel(
   248  		func() {
   249  			msgBytes := wire.BinaryBytes(authSigMessage{pubKey.Wrap(), signature.Wrap()})
   250  			_, err1 = sc.Write(msgBytes)
   251  		},
   252  		func() {
   253  			readBuffer := make([]byte, authSigMsgSize)
   254  			_, err2 = io.ReadFull(sc, readBuffer)
   255  			if err2 != nil {
   256  				return
   257  			}
   258  			n := int(0) // not used.
   259  			recvMsg = wire.ReadBinary(authSigMessage{}, bytes.NewBuffer(readBuffer), authSigMsgSize, &n, &err2).(authSigMessage)
   260  		},
   261  	)
   262  
   263  	if err1 != nil {
   264  		return nil, err1
   265  	}
   266  	if err2 != nil {
   267  		return nil, err2
   268  	}
   269  	return &recvMsg, nil
   270  }
   271  
   272  func shareEphPubKey(conn io.ReadWriteCloser, locEphPub *[32]byte) (remEphPub *[32]byte, err error) {
   273  	var err1, err2 error
   274  
   275  	cmn.Parallel(
   276  		func() {
   277  			_, err1 = conn.Write(locEphPub[:])
   278  		},
   279  		func() {
   280  			remEphPub = new([32]byte)
   281  			_, err2 = io.ReadFull(conn, remEphPub[:])
   282  		},
   283  	)
   284  
   285  	if err1 != nil {
   286  		return nil, err1
   287  	}
   288  	if err2 != nil {
   289  		return nil, err2
   290  	}
   291  	return remEphPub, nil
   292  }
   293  
   294  func sort32(foo, bar *[32]byte) (*[32]byte, *[32]byte) {
   295  	if bytes.Compare(foo[:], bar[:]) < 0 {
   296  		return foo, bar
   297  	}
   298  	return bar, foo
   299  }
   300  
   301  // sha256
   302  func hash32(input []byte) (res *[32]byte) {
   303  	hasher := sha256.New()
   304  	hasher.Write(input) // does not error
   305  	resSlice := hasher.Sum(nil)
   306  	res = new([32]byte)
   307  	copy(res[:], resSlice)
   308  	return
   309  }
   310  
   311  // We only fill in the first 20 bytes with ripemd160
   312  func hash24(input []byte) (res *[24]byte) {
   313  	hasher := ripemd160.New()
   314  	hasher.Write(input) // does not error
   315  	resSlice := hasher.Sum(nil)
   316  	res = new([24]byte)
   317  	copy(res[:], resSlice)
   318  	return
   319  }