diff --git a/brontide/noise.go b/brontide/noise.go index 723b7bfb..2bc30969 100644 --- a/brontide/noise.go +++ b/brontide/noise.go @@ -345,6 +345,20 @@ type Machine struct { ephemeralGen func() (*btcec.PrivateKey, error) handshakeState + + // nextCipherHeader is a static buffer that we'll use to read in the + // next ciphertext header from the wire. The header is a 2 byte length + // (of the next ciphertext), followed by a 16 byte MAC. + nextCipherHeader [lengthHeaderSize + macSize]byte + + // nextCipherText is a static buffer that we'll use to read in the + // bytes of the next cipher text message. As all messages in the + // protocol MUST be below 65KB plus our macSize, this will be + // sufficient to buffer all messages from the socket when we need to + // read the next one. Having a fixed buffer that's re-used also means + // that we save on allocations as we don't need to create a new one + // each time. + nextCipherText [math.MaxUint16 + macSize]byte } // NewBrontideMachine creates a new instance of the brontide state-machine. If @@ -698,25 +712,25 @@ func (b *Machine) WriteMessage(w io.Writer, p []byte) error { // ReadMessage attempts to read the next message from the passed io.Reader. In // the case of an authentication error, a non-nil error is returned. func (b *Machine) ReadMessage(r io.Reader) ([]byte, error) { - var cipherLen [lengthHeaderSize + macSize]byte - if _, err := io.ReadFull(r, cipherLen[:]); err != nil { + if _, err := io.ReadFull(r, b.nextCipherHeader[:]); err != nil { return nil, err } // Attempt to decrypt+auth the packet length present in the stream. - pktLenBytes, err := b.recvCipher.Decrypt(nil, nil, cipherLen[:]) + pktLenBytes, err := b.recvCipher.Decrypt( + nil, nil, b.nextCipherHeader[:], + ) if err != nil { return nil, err } // Next, using the length read from the packet header, read the // encrypted packet itself. - var cipherText [math.MaxUint16 + macSize]byte pktLen := uint32(binary.BigEndian.Uint16(pktLenBytes)) + macSize - if _, err := io.ReadFull(r, cipherText[:pktLen]); err != nil { + if _, err := io.ReadFull(r, b.nextCipherText[:pktLen]); err != nil { return nil, err } // TODO(roasbeef): modify to let pass in slice - return b.recvCipher.Decrypt(nil, nil, cipherText[:pktLen]) + return b.recvCipher.Decrypt(nil, nil, b.nextCipherText[:pktLen]) }