func Server(key []byte, nc net.Conn) *Conn {
	return &Conn{
		conn:      nc,
		secretKey: secretKeyFromKeyData(key),
		isClient:  false,
	}
}
Server returns a new spipe server connection using nc as the
underlying connection.
package spipe
import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/hmac"
	"crypto/rand"
	"crypto/sha256"
	"crypto/subtle"
	"encoding/binary"
	"errors"
	"hash"
	"io"
	"net"
	"sync"
	"time"
	"golang.org/x/crypto/pbkdf2"
	"github.com/dchest/dhgroup14"
)
const (
	messageSize = 1024                       
	payloadSize = messageSize + 4            
	packetSize  = payloadSize + sha256.Size  
)
type encryptor struct {
	sync.Mutex
	blockCipher cipher.Block
	mac         hash.Hash
	packetNum   uint64  
	buf    [packetSize]byte  
	buflen int               
	out io.Writer  
}
func newEncryptor(w io.Writer, cipherKey, hmacKey []byte) *encryptor {
	blockCipher, err := aes.NewCipher(cipherKey)
	if err != nil {
		panic("spipe: " + err.Error())
	}
	return &encryptor{
		blockCipher: blockCipher,
		mac:         hmac.New(sha256.New, hmacKey),
		out:         w,
	}
}
func (w *encryptor) flushBuffer() error {
	n, err := w.out.Write(w.buf[len(w.buf)-w.buflen:])
	w.buflen -= n
	if err != nil {
		return err
	}
	if w.buflen != 0 {
		return errors.New("spipe: wrote partial packet")
	}
	w.packetNum++
	for i := range w.buf {
		w.buf[i] = 0
	}
	return nil
}
func (w *encryptor) Flush() error {
	w.Lock()
	defer w.Unlock()
	return w.flushBuffer()
}
func (w *encryptor) sealPacket() {
	var iv [16]byte
	binary.BigEndian.PutUint64(iv[:8], w.packetNum)
	c := cipher.NewCTR(w.blockCipher, iv[:])
	c.XORKeyStream(w.buf[:payloadSize], w.buf[:payloadSize])
	w.mac.Reset()
	w.mac.Write(w.buf[:payloadSize])
	w.mac.Write(iv[:8])
	w.mac.Sum(w.buf[payloadSize:payloadSize])
	w.buflen = packetSize
}
func (w *encryptor) Write(p []byte) (nn int, err error) {
	w.Lock()
	defer w.Unlock()
	if w.buflen > 0 {
		if err := w.flushBuffer(); err != nil {
			return 0, err
		}
	}
	for len(p) > 0 {
		msgLen := copy(w.buf[:messageSize], p)
		binary.BigEndian.PutUint32(w.buf[messageSize:], uint32(msgLen))
		w.sealPacket()
		nn += msgLen
		p = p[msgLen:]
		if err := w.flushBuffer(); err != nil {
			return nn, err
		}
	}
	return
}
type decryptor struct {
	sync.Mutex
	blockCipher cipher.Block
	mac         hash.Hash
	packetNum   uint64  
	buf    [packetSize]byte  
	buflen int               
	msg    []byte            
	in io.Reader  
}
func newDecryptor(r io.Reader, cipherKey, hmacKey []byte) *decryptor {
	blockCipher, err := aes.NewCipher(cipherKey)
	if err != nil {
		panic("spipe: " + err.Error())
	}
	return &decryptor{
		blockCipher: blockCipher,
		mac:         hmac.New(sha256.New, hmacKey),
		in:          r,
	}
}
func (r *decryptor) openPacket() error {
	var iv [16]byte
	binary.BigEndian.PutUint64(iv[:8], r.packetNum)
	var sum [32]byte
	r.mac.Reset()
	r.mac.Write(r.buf[:payloadSize])
	r.mac.Write(iv[:8])
	if subtle.ConstantTimeCompare(r.mac.Sum(sum[:0]), r.buf[payloadSize:]) != 1 {
		return errors.New("spipe: failed to authenticate packet")
	}
	r.packetNum++
	c := cipher.NewCTR(r.blockCipher, iv[:])
	c.XORKeyStream(r.buf[:payloadSize], r.buf[:payloadSize])
	msgLen := binary.BigEndian.Uint32(r.buf[messageSize:])
	if msgLen > messageSize {
		return errors.New("spipe: message length is too large")
	}
	r.msg = r.buf[:msgLen]
	return nil
}
func (r *decryptor) Read(p []byte) (nn int, err error) {
	if len(p) == 0 {
		return 0, nil
	}
	r.Lock()
	defer r.Unlock()
	if len(r.msg) > 0 {
		n := copy(p, r.msg)
		p = p[n:]
		r.msg = r.msg[n:]
		nn += n
	}
	if len(p) > 0 {
		n, err := r.in.Read(r.buf[r.buflen:])
		r.buflen += n
		if r.buflen == packetSize {
			r.buflen = 0
			if err := r.openPacket(); err != nil {
				return nn, err
			}
			n := copy(p, r.msg)
			p = p[n:]
			r.msg = r.msg[n:]
			nn += n
		}
		if err != nil {
			return nn, err
		}
	}
	return
}
type Conn struct {
	w *encryptor
	r *decryptor
	isClient  bool
	secretKey []byte
	handshakeMutex     sync.Mutex
	handshakePerformed bool
	conn net.Conn  
}
func (c *Conn) LocalAddr() net.Addr                { return c.conn.LocalAddr() }
func (c *Conn) RemoteAddr() net.Addr               { return c.conn.RemoteAddr() }
func (c *Conn) SetDeadline(t time.Time) error      { return c.conn.SetDeadline(t) }
func (c *Conn) SetReadDeadline(t time.Time) error  { return c.conn.SetReadDeadline(t) }
func (c *Conn) SetWriteDeadline(t time.Time) error { return c.conn.SetWriteDeadline(t) }
func (c *Conn) sendBytes(p []byte) error {
	n, err := c.conn.Write(p)
	if err != nil {
		return err
	}
	if n != len(p) {
		return errors.New("spipe: partial write")
	}
	return nil
}
func (c *Conn) receiveBytes(p []byte) error {
	if _, err := io.ReadFull(c.conn, p); err != nil {
		if err == io.EOF {
			return io.ErrUnexpectedEOF
		}
		return err
	}
	return nil
}
func (c *Conn) Handshake() error {
	c.handshakeMutex.Lock()
	defer c.handshakeMutex.Unlock()
	if c.handshakePerformed {
		return nil
	}
	var nonces [32 + 32 + dhgroup14.SharedKeySize]byte
	if _, err := io.ReadFull(rand.Reader, nonces[:64]); err != nil {
		return err
	}
	nonceC := nonces[0:32]
	nonceS := nonces[32:64]
	if c.isClient {
		if err := c.sendBytes(nonceC); err != nil {
			return err
		}
		if err := c.receiveBytes(nonceS); err != nil {
			return err
		}
	} else {
		if err := c.receiveBytes(nonceC); err != nil {
			return err
		}
		if err := c.sendBytes(nonceS); err != nil {
			return err
		}
	}
	dk1 := pbkdf2.Key(c.secretKey, nonces[:64], 1, 64, sha256.New)
	dhmacC := dk1[0:32]
	dhmacS := dk1[32:64]
	var myDHMac, theirDHMac []byte
	if c.isClient {
		myDHMac = dhmacC
		theirDHMac = dhmacS
	} else {
		myDHMac = dhmacS
		theirDHMac = dhmacC
	}
	myPublicKey, myPrivateKey, err := dhgroup14.GenerateKeyPair(rand.Reader)
	if err != nil {
		return err
	}
	var myAuthPublicKey [256 + 32]byte
	copy(myAuthPublicKey[:], myPublicKey)
	h := hmac.New(sha256.New, myDHMac)
	h.Write(myAuthPublicKey[0:256])
	h.Sum(myAuthPublicKey[256:256])
	var theirAuthPublicKey [256 + 32]byte
	if c.isClient {
		if err := c.sendBytes(myAuthPublicKey[:]); err != nil {
			return err
		}
	}
	if err := c.receiveBytes(theirAuthPublicKey[:]); err != nil {
		return err
	}
	var sum [32]byte
	h = hmac.New(sha256.New, theirDHMac)
	h.Write(theirAuthPublicKey[0:256])
	if subtle.ConstantTimeCompare(h.Sum(sum[:0]), theirAuthPublicKey[256:]) != 1 {
		return errors.New("spipe: authentication failed")
	}
	if !c.isClient {
		if err := c.sendBytes(myAuthPublicKey[:]); err != nil {
			return err
		}
	}
	theirPublicKey := theirAuthPublicKey[:256]
	dhSharedKey, err := dhgroup14.SharedKey(rand.Reader, theirPublicKey, myPrivateKey)
	if err != nil {
		return err
	}
	copy(nonces[64:], dhSharedKey)
	dk2 := pbkdf2.Key(c.secretKey, nonces[:], 1, 128, sha256.New)
	eC, hC, eS, hS := dk2[0:32], dk2[32:64], dk2[64:96], dk2[96:128]
	if c.isClient {
		c.w = newEncryptor(c.conn, eC, hC)
		c.r = newDecryptor(c.conn, eS, hS)
	} else {
		c.w = newEncryptor(c.conn, eS, hS)
		c.r = newDecryptor(c.conn, eC, hC)
	}
	c.handshakePerformed = true
	return nil
}
func (c *Conn) Close() error {
	c.handshakeMutex.Lock()
	defer c.handshakeMutex.Unlock()
	c.handshakePerformed = false
	c.r = nil
	c.w = nil
	return c.conn.Close()
}
func (c *Conn) Read(p []byte) (nn int, err error) {
	if err := c.Handshake(); err != nil {
		return 0, err
	}
	return c.r.Read(p)
}
func (c *Conn) Write(p []byte) (nn int, err error) {
	if err := c.Handshake(); err != nil {
		return 0, err
	}
	return c.w.Write(p)
}
func (c *Conn) Flush() error {
	if err := c.Handshake(); err != nil {
		return err
	}
	return c.w.Flush()
}
func secretKeyFromKeyData(keyData []byte) []byte {
	h := sha256.New()
	h.Write(keyData)
	return h.Sum(nil)
}
func Dial(key []byte, network, raddr string) (*Conn, error) {
	nc, err := net.Dial(network, raddr)
	if err != nil {
		return nil, err
	}
	c := Client(key, nc)
	if err := c.Handshake(); err != nil {
		c.Close()
		return nil, err
	}
	return c, nil
}
type listener struct {
	net.Listener
	secretKey []byte
}
func Listen(key []byte, network, laddr string) (net.Listener, error) {
	nl, err := net.Listen(network, laddr)
	if err != nil {
		return nil, err
	}
	return &listener{
		Listener:  nl,
		secretKey: secretKeyFromKeyData(key),
	}, nil
}
func (l *listener) Accept() (c net.Conn, err error) {
	nc, err := l.Listener.Accept()
	if err != nil {
		return nil, err
	}
	return &Conn{
		conn:      nc,
		secretKey: l.secretKey,
		isClient:  false,
	}, nil
}
func Client(key []byte, nc net.Conn) *Conn {
	return &Conn{
		conn:      nc,
		secretKey: secretKeyFromKeyData(key),
		isClient:  true,
	}
}