github.com/mit-dci/lit@v0.0.0-20221102210550-8c3d3b49f2ce/lndc/noise.go (about)

     1  package lndc
     2  
     3  import (
     4  	"crypto/cipher"
     5  	"crypto/sha256"
     6  	"encoding/binary"
     7  	"errors"
     8  	"fmt"
     9  	"io"
    10  	"math"
    11  	"time"
    12  
    13  	"golang.org/x/crypto/chacha20poly1305"
    14  	"golang.org/x/crypto/hkdf"
    15  
    16  	"github.com/mit-dci/lit/crypto/koblitz"
    17  )
    18  
    19  const (
    20  	// protocolName is the precise instantiation of the Noise protocol
    21  	// This value will be used as part of the prologue. If the initiator
    22  	// and responder aren't using the exact same string for this value,
    23  	// along with prologue of the Bitcoin network, then the initial
    24  	// handshake will fail.
    25  	protocolName = "Noise_XX_secp256k1_ChaChaPoly_SHA256"
    26  
    27  	// macSize is the length in bytes of the tags generated by poly1305.
    28  	macSize = 16
    29  
    30  	// lengthHeaderSize is the number of bytes used to prefix encode the
    31  	// length of a message payload.
    32  	lengthHeaderSize = 2
    33  
    34  	// keyRotationInterval is the number of messages sent on a single
    35  	// cipher stream before the keys are rotated forwards.
    36  	keyRotationInterval = 1000
    37  
    38  	// handshakeReadTimeout is a read timeout that will be enforced when
    39  	// waiting for data payloads during the various acts of lndc. If
    40  	// the remote party fails to deliver the proper payload within this
    41  	// time frame, then we'll fail the connection.
    42  	handshakeReadTimeout = time.Second * 5 // not 10 because of litrpc
    43  )
    44  
    45  // ecdh performs an ECDH operation between pub and priv. The returned value is
    46  // the sha256 of the compressed shared point.
    47  func ecdh(pub *koblitz.PublicKey, priv *koblitz.PrivateKey) []byte {
    48  	s := &koblitz.PublicKey{}
    49  	x, y := koblitz.S256().ScalarMult(pub.X, pub.Y, priv.D.Bytes())
    50  	s.X = x
    51  	s.Y = y
    52  
    53  	h := sha256.Sum256(s.SerializeCompressed())
    54  	return h[:]
    55  }
    56  
    57  // cipherState encapsulates the state for the AEAD which will be used to
    58  // encrypt+authenticate any payloads sent during the handshake, and messages
    59  // sent once the handshake has completed.
    60  type cipherState struct {
    61  	// nonce is the nonce passed into the chacha20-poly1305 instance for
    62  	// encryption+decryption. The nonce is incremented after each successful
    63  	// encryption/decryption.
    64  	nonce uint64
    65  
    66  	// secretKey is the shared symmetric key which will be used to
    67  	// instantiate the cipher.
    68  	secretKey [32]byte
    69  
    70  	// salt is an additional secret which is used during key rotation to
    71  	// generate new keys.
    72  	salt [32]byte
    73  
    74  	// cipher is an instance of the ChaCha20-Poly1305 AEAD construction
    75  	// created using the secretKey above.
    76  	cipher cipher.AEAD
    77  }
    78  
    79  // Encrypt returns a ciphertext which is the encryption of the plainText
    80  // observing the passed associatedData within the AEAD construction.
    81  func (c *cipherState) Encrypt(associatedData, cipherText, plainText []byte) []byte {
    82  	defer func() {
    83  		c.nonce++
    84  
    85  		if c.nonce == keyRotationInterval {
    86  			c.rotateKey()
    87  		}
    88  	}()
    89  
    90  	var nonce [12]byte
    91  	binary.LittleEndian.PutUint64(nonce[4:], c.nonce)
    92  
    93  	return c.cipher.Seal(cipherText, nonce[:], plainText, associatedData)
    94  }
    95  
    96  // Decrypt attempts to decrypt the passed ciphertext observing the specified
    97  // associatedData within the AEAD construction. In the case that the final MAC
    98  // check fails, then a non-nil error will be returned.
    99  func (c *cipherState) Decrypt(associatedData, plainText, cipherText []byte) ([]byte, error) {
   100  	defer func() {
   101  		c.nonce++
   102  
   103  		if c.nonce == keyRotationInterval {
   104  			c.rotateKey()
   105  		}
   106  	}()
   107  
   108  	var nonce [12]byte
   109  	binary.LittleEndian.PutUint64(nonce[4:], c.nonce)
   110  
   111  	return c.cipher.Open(plainText, nonce[:], cipherText, associatedData)
   112  }
   113  
   114  // InitializeKey initializes the secret key and AEAD cipher scheme based off of
   115  // the passed key.
   116  func (c *cipherState) InitializeKey(key [32]byte) {
   117  	c.secretKey = key
   118  	c.nonce = 0
   119  
   120  	// Safe to ignore the error here as our key is properly sized
   121  	// (32-bytes).
   122  	c.cipher, _ = chacha20poly1305.New(c.secretKey[:])
   123  }
   124  
   125  // InitializeKeyWithSalt is identical to InitializeKey however it also sets the
   126  // cipherState's salt field which is used for key rotation.
   127  func (c *cipherState) InitializeKeyWithSalt(salt, key [32]byte) {
   128  	c.salt = salt
   129  	c.InitializeKey(key)
   130  }
   131  
   132  // rotateKey rotates the current encryption/decryption key for this cipherState
   133  // instance. Key rotation is performed by ratcheting the current key forward
   134  // using an HKDF invocation with the cipherState's salt as the salt, and the
   135  // current key as the input.
   136  func (c *cipherState) rotateKey() {
   137  	var (
   138  		info    []byte
   139  		nextKey [32]byte
   140  	)
   141  
   142  	oldKey := c.secretKey
   143  	h := hkdf.New(sha256.New, oldKey[:], c.salt[:], info)
   144  
   145  	// hkdf(ck, k, zero)
   146  	// |
   147  	// | \
   148  	// |  \
   149  	// ck  k'
   150  	h.Read(c.salt[:])
   151  	h.Read(nextKey[:])
   152  
   153  	c.InitializeKey(nextKey)
   154  }
   155  
   156  // symmetricState encapsulates a cipherState object and houses the ephemeral
   157  // handshake digest state. This struct is used during the handshake to derive
   158  // new shared secrets based off of the result of ECDH operations. Ultimately,
   159  // the final key yielded by this struct is the result of an incremental
   160  // Triple-DH operation.
   161  type symmetricState struct {
   162  	cipherState
   163  
   164  	// chainingKey is used as the salt to the HKDF function to derive a new
   165  	// chaining key as well as a new tempKey which is used for
   166  	// encryption/decryption.
   167  	chainingKey [32]byte
   168  
   169  	// tempKey is the latter 32 bytes resulted from the latest HKDF
   170  	// iteration. This key is used to encrypt/decrypt any handshake
   171  	// messages or payloads sent until the next DH operation is executed.
   172  	tempKey [32]byte
   173  
   174  	// handshakeDigest is the cumulative hash digest of all handshake
   175  	// messages sent from start to finish. This value is never transmitted
   176  	// to the other side, but will be used as the AD when
   177  	// encrypting/decrypting messages using our AEAD construction.
   178  	handshakeDigest [32]byte
   179  }
   180  
   181  // mixKey is implements a basic HKDF-based key ratchet. This method is called
   182  // with the result of each DH output generated during the handshake process.
   183  // The first 32 bytes extract from the HKDF reader is the next chaining key,
   184  // then latter 32 bytes become the temp secret key using within any future AEAD
   185  // operations until another DH operation is performed.
   186  func (s *symmetricState) mixKey(input []byte) {
   187  	var info []byte
   188  
   189  	secret := input
   190  	salt := s.chainingKey
   191  	h := hkdf.New(sha256.New, secret, salt[:], info)
   192  
   193  	// hkdf(ck, input, zero)
   194  	// |
   195  	// | \
   196  	// |  \
   197  	// ck  k
   198  	h.Read(s.chainingKey[:])
   199  	h.Read(s.tempKey[:])
   200  
   201  	// cipher.k = temp_key
   202  	s.InitializeKey(s.tempKey)
   203  }
   204  
   205  // mixHash hashes the passed input data into the cumulative handshake digest.
   206  // The running result of this value (h) is used as the associated data in all
   207  // decryption/encryption operations.
   208  func (s *symmetricState) mixHash(data []byte) {
   209  	h := sha256.New()
   210  	h.Write(s.handshakeDigest[:])
   211  	h.Write(data)
   212  
   213  	copy(s.handshakeDigest[:], h.Sum(nil))
   214  }
   215  
   216  // EncryptAndHash returns the authenticated encryption of the passed plaintext.
   217  // When encrypting the handshake digest (h) is used as the associated data to
   218  // the AEAD cipher.
   219  func (s *symmetricState) EncryptAndHash(plaintext []byte) []byte {
   220  	ciphertext := s.Encrypt(s.handshakeDigest[:], nil, plaintext)
   221  	s.mixHash(ciphertext)
   222  
   223  	return ciphertext
   224  }
   225  
   226  // DecryptAndHash returns the authenticated decryption of the passed
   227  // ciphertext.  When encrypting the handshake digest (h) is used as the
   228  // associated data to the AEAD cipher.
   229  func (s *symmetricState) DecryptAndHash(ciphertext []byte) ([]byte, error) {
   230  	plaintext, err := s.Decrypt(s.handshakeDigest[:], nil, ciphertext)
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  	s.mixHash(ciphertext)
   235  
   236  	return plaintext, nil
   237  }
   238  
   239  // InitializeSymmetric initializes the symmetric state by setting the handshake
   240  // digest (h) and the chaining key (ck) to protocol name.
   241  func (s *symmetricState) InitializeSymmetric(protocolName []byte) {
   242  	var empty [32]byte
   243  	s.handshakeDigest = sha256.Sum256(protocolName)
   244  	s.chainingKey = s.handshakeDigest
   245  	s.InitializeKey(empty) // init with empty key
   246  }
   247  
   248  // handshakeState encapsulates the symmetricState and keeps track of all the
   249  // public keys (static and ephemeral) for both sides during the handshake
   250  // transcript. If the handshake completes successfully, then two instances of a
   251  // cipherState are emitted: one to encrypt messages from initiator to
   252  // responder, and the other for the opposite direction.
   253  type handshakeState struct {
   254  	symmetricState
   255  
   256  	initiator bool
   257  
   258  	localStatic    *koblitz.PrivateKey
   259  	localEphemeral *koblitz.PrivateKey
   260  
   261  	remoteStatic    *koblitz.PublicKey
   262  	remoteEphemeral *koblitz.PublicKey
   263  }
   264  
   265  // newHandshakeState returns a new instance of the handshake state initialized
   266  // with the prologue and protocol name. If this is the responder's handshake
   267  // state, then the remotePub can be nil.
   268  func newHandshakeState(initiator bool, prologue []byte,
   269  	localStatic *koblitz.PrivateKey) handshakeState {
   270  
   271  	h := handshakeState{
   272  		initiator:   initiator,
   273  		localStatic: localStatic,
   274  	}
   275  
   276  	// Set the current chaining key and handshake digest to the hash of the
   277  	// protocol name, and additionally mix in the prologue. If either sides
   278  	// disagree about the prologue or protocol name, then the handshake
   279  	// will fail.
   280  	h.InitializeSymmetric([]byte(protocolName))
   281  	h.mixHash(prologue)
   282  	return h
   283  }
   284  
   285  // EphemeralGenerator is a functional option that allows callers to substitute
   286  // a custom function for use when generating ephemeral keys for ActOne or
   287  // ActTwo.  The function closure return by this function can be passed into
   288  // NewNoiseMachine as a function option parameter.
   289  func EphemeralGenerator(gen func() (*koblitz.PrivateKey, error)) func(*Machine) {
   290  	return func(m *Machine) {
   291  		m.ephemeralGen = gen
   292  	}
   293  }
   294  
   295  // Machine is a state-machine which implements lndc: an
   296  // Authenticated-key Exchange in Three Acts. lndc is derived from the Noise
   297  // framework, specifically implementing the Noise_XX handshake. Once the
   298  // initial 3-act handshake has completed all messages are encrypted with a
   299  // chacha20 AEAD cipher. On the wire, all messages are prefixed with an
   300  // authenticated+encrypted length field. Additionally, the encrypted+auth'd
   301  // length prefix is used as the AD when encrypting+decryption messages. This
   302  // construction provides confidentiality of packet length, avoids introducing
   303  // a padding-oracle, and binds the encrypted packet length to the packet
   304  // itself. Noise protocol reference: http://noiseprotocol.org/noise.html
   305  //
   306  // The acts proceeds the following order (initiator on the left):
   307  //  GenActOne()   ->
   308  //                    RecvActOne()
   309  //                <-  GenActTwo()
   310  //  RecvActTwo()
   311  //  GenActThree() ->
   312  //                    RecvActThree()
   313  //
   314  // The protocol has the following steps involved:
   315  // XX(s, rs):
   316  //  INITIATOR -> e            RESPONDER
   317  //  INITIATOR <- e, ee, s, es RESPONDER
   318  //  INITIATOR -> s, se        RESPONDER
   319  // s refers to the static key (or public key) belonging to an entity
   320  // e refers to the ephemeral key
   321  // e, ee, es refer to a DH exchange between the initiator's key pair and the
   322  // responder's key pair. The letters e and s hold the same meaning as before.
   323  
   324  type Machine struct {
   325  	sendCipher cipherState
   326  	recvCipher cipherState
   327  
   328  	ephemeralGen func() (*koblitz.PrivateKey, error)
   329  
   330  	handshakeState
   331  
   332  	// nextCipherHeader is a static buffer that we'll use to read in the
   333  	// next ciphertext header from the wire. The header is a 2 byte length
   334  	// (of the next ciphertext), followed by a 16 byte MAC.
   335  	nextCipherHeader [lengthHeaderSize + macSize]byte
   336  
   337  	// nextCipherText is a static buffer that we'll use to read in the
   338  	// bytes of the next cipher text message. As all messages in the
   339  	// protocol MUST be below 65KB plus our macSize, this will be
   340  	// sufficient to buffer all messages from the socket when we need to
   341  	// read the next one. Having a fixed buffer that's re-used also means
   342  	// that we save on allocations as we don't need to create a new one
   343  	// each time.
   344  	nextCipherText [math.MaxUint16 + macSize]byte
   345  }
   346  
   347  // NewNoiseMachine creates a new instance of the lndc state-machine. If
   348  // the responder (listener) is creating the object, then the remotePub should
   349  // be nil. The handshake state within lndc is initialized using the ascii
   350  // string "lightning" as the prologue. The last parameter is a set of variadic
   351  // arguments for adding additional options to the lndc Machine
   352  // initialization.
   353  func NewNoiseMachine(initiator bool, localStatic *koblitz.PrivateKey,
   354  	options ...func(*Machine)) *Machine {
   355  
   356  	handshake := newHandshakeState(initiator, []byte("lit"), localStatic)
   357  	// TODO: if we're sending messages of type XK, set it back to
   358  	// "lightning" which is what BOLT uses
   359  
   360  	m := &Machine{handshakeState: handshake}
   361  
   362  	// With the initial base machine created, we'll assign our default
   363  	// version of the ephemeral key generator.
   364  	m.ephemeralGen = func() (*koblitz.PrivateKey, error) {
   365  		return koblitz.NewPrivateKey(koblitz.S256())
   366  	}
   367  	// With the default options established, we'll now process all the
   368  	// options passed in as parameters.
   369  	for _, option := range options {
   370  		option(m)
   371  	}
   372  
   373  	return m
   374  }
   375  
   376  const (
   377  	// HandshakeVersion is the expected version of the lndc handshake.
   378  	// Any messages that carry a different version will cause the handshake
   379  	// to abort immediately.
   380  	HandshakeVersion = byte(1) // TODO: add support for noise_XK (brontide) as well
   381  
   382  	// ActOneSize is the size of the packet sent from initiator to
   383  	// responder in ActOne. The packet consists of a handshake version, an
   384  	// ephemeral key in compressed format, and a 16-byte poly1305 tag.
   385  	// -> e
   386  	// 1 + 33 + 16
   387  	ActOneSize = 50
   388  
   389  	// ActTwoSize is the size the packet sent from responder to initiator
   390  	// in ActTwo. The packet consists of a handshake version, an ephemeral
   391  	// key in compressed format, a public key in compressed format
   392  	// and a 16-byte poly1305 tag.
   393  	// <- e, ee, s, es
   394  	// 1 + 33 + 33 + 16
   395  	ActTwoSize = 83
   396  
   397  	// ActThreeSize is the size of the packet sent from initiator to
   398  	// responder in ActThree. The packet consists of a handshake version,
   399  	// the initiators static key encrypted with strong forward secrecy and
   400  	// a 16-byte poly1035 tag.
   401  	// -> s, se
   402  	// 1 + 33 + 16 + 16
   403  	ActThreeSize = 66
   404  )
   405  
   406  // GenActOne generates the initial packet (act one) to be sent from initiator
   407  // to responder. During act one the initiator generates an ephemeral key and
   408  // hashes it into the handshake digest. Future payloads are encrypted with a key
   409  // derived from this result.
   410  // -> e
   411  
   412  func (b *Machine) GenActOne() ([ActOneSize]byte, error) {
   413  	var (
   414  		err    error
   415  		actOne [ActOneSize]byte
   416  	)
   417  
   418  	// Generate e
   419  	b.localEphemeral, err = b.ephemeralGen()
   420  	if err != nil {
   421  		return actOne, err
   422  	}
   423  
   424  	// Compress e
   425  	e := b.localEphemeral.PubKey().SerializeCompressed()
   426  	// Hash it into the handshake digest
   427  	b.mixHash(e)
   428  
   429  	authPayload := b.EncryptAndHash([]byte{})
   430  	actOne[0] = HandshakeVersion
   431  	copy(actOne[1:34], e)
   432  	copy(actOne[34:], authPayload)
   433  	return actOne, nil
   434  }
   435  
   436  // RecvActOne processes the act one packet sent by the initiator. The responder
   437  // executes the mirrored actions to that of the initiator extending the
   438  // handshake digest and deriving a new shared secret based on an ECDH with the
   439  // initiator's ephemeral key and responder's static key.
   440  func (b *Machine) RecvActOne(actOne [ActOneSize]byte) error {
   441  	var (
   442  		err error
   443  		e   [33]byte
   444  		p   [16]byte
   445  	)
   446  
   447  	// If the handshake version is unknown, then the handshake fails
   448  	// immediately.
   449  	if actOne[0] != HandshakeVersion {
   450  		return fmt.Errorf("Act One: invalid handshake version: %v, "+
   451  			"only %v is valid, msg=%x", actOne[0], HandshakeVersion,
   452  			actOne[:])
   453  	}
   454  
   455  	copy(e[:], actOne[1:34])
   456  	copy(p[:], actOne[34:])
   457  
   458  	// e
   459  	b.remoteEphemeral, err = koblitz.ParsePubKey(e[:], koblitz.S256())
   460  	if err != nil {
   461  		return err
   462  	}
   463  	b.mixHash(b.remoteEphemeral.SerializeCompressed())
   464  
   465  	_, err = b.DecryptAndHash(p[:])
   466  	return err // nil means Act one completed successfully
   467  }
   468  
   469  // GenActTwo generates the second packet (act two) to be sent from the
   470  // responder to the initiator
   471  // <- e, ee, s, es
   472  func (b *Machine) GenActTwo() ([ActTwoSize]byte, error) {
   473  	var (
   474  		err    error
   475  		actTwo [ActTwoSize]byte
   476  	)
   477  
   478  	// e
   479  	b.localEphemeral, err = b.ephemeralGen()
   480  	if err != nil {
   481  		return actTwo, err
   482  	}
   483  
   484  	e := b.localEphemeral.PubKey().SerializeCompressed()
   485  	b.mixHash(b.localEphemeral.PubKey().SerializeCompressed())
   486  
   487  	// ee
   488  	ee := ecdh(b.remoteEphemeral, b.localEphemeral)
   489  	b.mixKey(ee)
   490  
   491  	// s
   492  	s := b.localStatic.PubKey().SerializeCompressed()
   493  	b.mixHash(s)
   494  
   495  	// es
   496  	es := ecdh(b.remoteEphemeral, b.localStatic)
   497  	b.mixKey(es)
   498  
   499  	authPayload := b.EncryptAndHash([]byte{})
   500  	actTwo[0] = HandshakeVersion
   501  	copy(actTwo[1:34], e)
   502  	copy(actTwo[34:67], s)
   503  	copy(actTwo[67:], authPayload)
   504  	// add additional stuff based on what we need
   505  	return actTwo, nil
   506  }
   507  
   508  // RecvActTwo processes the second packet (act two) sent from the responder to
   509  // the initiator. A successful processing of this packet authenticates the
   510  // initiator to the responder.
   511  func (b *Machine) RecvActTwo(actTwo [ActTwoSize]byte) ([33]byte, error) {
   512  	var (
   513  		err error
   514  		e   [33]byte
   515  		s   [33]byte
   516  		p   [16]byte
   517  	)
   518  	var empty [33]byte
   519  	// If the handshake version is unknown, then the handshake fails
   520  	// immediately.
   521  	if actTwo[0] != HandshakeVersion {
   522  		return empty, fmt.Errorf("Act Two: invalid handshake version: %v, "+
   523  			"only %v is valid, msg=%x", actTwo[0], HandshakeVersion,
   524  			actTwo[:])
   525  	}
   526  
   527  	copy(e[:], actTwo[1:34])
   528  	copy(s[:], actTwo[34:67])
   529  	copy(p[:], actTwo[67:])
   530  
   531  	// e
   532  	b.remoteEphemeral, err = koblitz.ParsePubKey(e[:], koblitz.S256())
   533  	if err != nil {
   534  		return empty, err
   535  	}
   536  	b.mixHash(b.remoteEphemeral.SerializeCompressed())
   537  
   538  	// ee
   539  	ee := ecdh(b.remoteEphemeral, b.localEphemeral)
   540  	b.mixKey(ee)
   541  
   542  	// s
   543  	b.remoteStatic, err = koblitz.ParsePubKey(s[:], koblitz.S256())
   544  	if err != nil {
   545  		return empty, err
   546  	}
   547  	b.mixHash(b.remoteStatic.SerializeCompressed())
   548  
   549  	// es
   550  	es := ecdh(b.remoteStatic, b.localEphemeral)
   551  	b.mixKey(es)
   552  
   553  	_, err = b.DecryptAndHash(p[:])
   554  	return s, err
   555  }
   556  
   557  // GenActThree creates the final (act three) packet of the handshake. Act three
   558  // is to be sent from the initiator to the responder. The purpose of act three
   559  // is to transmit the initiator's public key under strong forward secrecy to
   560  // the responder. This act also includes the final ECDH operation which yields
   561  // the final session.
   562  // -> s, se
   563  func (b *Machine) GenActThree() ([ActThreeSize]byte, error) {
   564  	var actThree [ActThreeSize]byte
   565  
   566  	// s
   567  	s := b.localStatic.PubKey().SerializeCompressed()
   568  	encryptedS := b.EncryptAndHash(s)
   569  
   570  	//se
   571  	se := ecdh(b.remoteEphemeral, b.localStatic)
   572  	b.mixKey(se)
   573  
   574  	authPayload := b.EncryptAndHash([]byte{})
   575  
   576  	actThree[0] = HandshakeVersion
   577  	copy(actThree[1:50], encryptedS)
   578  	copy(actThree[50:], authPayload)
   579  
   580  	// With the final ECDH operation complete, derive the session sending
   581  	// and receiving keys.
   582  	b.split()
   583  	return actThree, nil
   584  }
   585  
   586  // RecvActThree processes the final act (act three) sent from the initiator to
   587  // the responder. After processing this act, the responder learns of the
   588  // initiator's static public key. Decryption of the static key serves to
   589  // authenticate the initiator to the responder.
   590  func (b *Machine) RecvActThree(actThree [ActThreeSize]byte) error {
   591  	var (
   592  		err error
   593  		s   [49]byte
   594  		p   [16]byte
   595  	)
   596  
   597  	// If the handshake version is unknown, then the handshake fails
   598  	// immediately.
   599  	if actThree[0] != HandshakeVersion {
   600  		return fmt.Errorf("Act Three: invalid handshake version: %v, "+
   601  			"only %v is valid, msg=%x", actThree[0], HandshakeVersion,
   602  			actThree[:])
   603  	}
   604  
   605  	copy(s[:], actThree[1:50])
   606  	copy(p[:], actThree[50:])
   607  
   608  	// s
   609  	remotePub, err := b.DecryptAndHash(s[:])
   610  	if err != nil {
   611  		return err
   612  	}
   613  
   614  	b.remoteStatic, err = koblitz.ParsePubKey(remotePub, koblitz.S256())
   615  	if err != nil {
   616  		return err
   617  	}
   618  
   619  	// se
   620  	se := ecdh(b.remoteStatic, b.localEphemeral)
   621  	b.mixKey(se)
   622  
   623  	if _, err := b.DecryptAndHash(p[:]); err != nil {
   624  		return err
   625  	}
   626  
   627  	// With the final ECDH operation complete, derive the session sending
   628  	// and receiving keys.
   629  	b.split()
   630  	return nil
   631  }
   632  
   633  // split is the final wrap-up act to be executed at the end of a successful
   634  // three act handshake. This function creates two internal cipherState
   635  // instances: one which is used to encrypt messages from the initiator to the
   636  // responder, and another which is used to encrypt message for the opposite
   637  // direction.
   638  func (b *Machine) split() {
   639  	var (
   640  		empty   []byte
   641  		sendKey [32]byte
   642  		recvKey [32]byte
   643  	)
   644  
   645  	h := hkdf.New(sha256.New, empty, b.chainingKey[:], empty)
   646  
   647  	// If we're the initiator the first 32 bytes are used to encrypt our
   648  	// messages and the second 32-bytes to decrypt their messages. For the
   649  	// responder the opposite is true.
   650  	if b.initiator {
   651  		h.Read(sendKey[:])
   652  		b.sendCipher = cipherState{}
   653  		b.sendCipher.InitializeKeyWithSalt(b.chainingKey, sendKey)
   654  
   655  		h.Read(recvKey[:])
   656  		b.recvCipher = cipherState{}
   657  		b.recvCipher.InitializeKeyWithSalt(b.chainingKey, recvKey)
   658  	} else {
   659  		h.Read(recvKey[:])
   660  		b.recvCipher = cipherState{}
   661  		b.recvCipher.InitializeKeyWithSalt(b.chainingKey, recvKey)
   662  
   663  		h.Read(sendKey[:])
   664  		b.sendCipher = cipherState{}
   665  		b.sendCipher.InitializeKeyWithSalt(b.chainingKey, sendKey)
   666  	}
   667  }
   668  
   669  // WriteMessage writes the next message p to the passed io.Writer. The
   670  // ciphertext of the message is prepended with an encrypt+auth'd length which
   671  // must be used as the AD to the AEAD construction when being decrypted by the
   672  // other side.
   673  func (b *Machine) WriteMessage(w io.Writer, p []byte) error {
   674  	// The total length of each message payload including the MAC size
   675  	// payload exceed the largest number encodable within a 16-bit unsigned
   676  	// integer.
   677  	if len(p) > math.MaxUint16 {
   678  		return errors.New("the generated payload exceeds " +
   679  			"the max allowed message length of (2^16)-1")
   680  	}
   681  
   682  	// The full length of the packet is only the packet length, and does
   683  	// NOT include the MAC.
   684  	fullLength := uint16(len(p))
   685  
   686  	var pktLen [2]byte
   687  	binary.BigEndian.PutUint16(pktLen[:], fullLength)
   688  
   689  	// First, write out the encrypted+MAC'd length prefix for the packet.
   690  	cipherLen := b.sendCipher.Encrypt(nil, nil, pktLen[:])
   691  	if _, err := w.Write(cipherLen); err != nil {
   692  		return err
   693  	}
   694  
   695  	// Finally, write out the encrypted packet itself. We only write out a
   696  	// single packet, as any fragmentation should have taken place at a
   697  	// higher level.
   698  	cipherText := b.sendCipher.Encrypt(nil, nil, p)
   699  	_, err := w.Write(cipherText)
   700  	return err
   701  }
   702  
   703  // ReadMessage attempts to read the next message from the passed io.Reader. In
   704  // the case of an authentication error, a non-nil error is returned.
   705  func (b *Machine) ReadMessage(r io.Reader) ([]byte, error) {
   706  	if _, err := io.ReadFull(r, b.nextCipherHeader[:]); err != nil {
   707  		return nil, err
   708  	}
   709  
   710  	// Attempt to decrypt+auth the packet length present in the stream.
   711  	pktLenBytes, err := b.recvCipher.Decrypt(
   712  		nil, nil, b.nextCipherHeader[:],
   713  	)
   714  	if err != nil {
   715  		return nil, err
   716  	}
   717  
   718  	// Next, using the length read from the packet header, read the
   719  	// encrypted packet itself.
   720  	pktLen := uint32(binary.BigEndian.Uint16(pktLenBytes)) + macSize
   721  	if _, err := io.ReadFull(r, b.nextCipherText[:pktLen]); err != nil {
   722  		return nil, err
   723  	}
   724  
   725  	return b.recvCipher.Decrypt(nil, nil, b.nextCipherText[:pktLen])
   726  }