Rewrite hap secure connection

This commit is contained in:
Alex X
2023-10-12 17:03:58 +03:00
parent 91c4a3e7b5
commit 8165adcab1
2 changed files with 70 additions and 59 deletions
+1 -1
View File
@@ -217,7 +217,7 @@ func (c *Client) Dial() (err error) {
return return
} }
// new reader for new conn // new reader for new conn
c.reader = bufio.NewReaderSize(c.Conn, 32*1024) // 32K like default request body c.reader = bufio.NewReader(c.Conn)
go c.eventsReader() go c.eventsReader()
+60 -49
View File
@@ -1,6 +1,7 @@
package secure package secure
import ( import (
"bufio"
"encoding/binary" "encoding/binary"
"io" "io"
"net" "net"
@@ -14,6 +15,10 @@ import (
type Conn struct { type Conn struct {
conn net.Conn conn net.Conn
rd *bufio.Reader
wr *bufio.Writer
rb []byte // temporary reading buffer
encryptKey []byte encryptKey []byte
decryptKey []byte decryptKey []byte
encryptCnt uint64 encryptCnt uint64
@@ -33,11 +38,19 @@ func Client(conn net.Conn, sharedKey []byte, isClient bool) (net.Conn, error) {
return nil, err return nil, err
} }
if isClient { c := &Conn{
return &Conn{conn: conn, encryptKey: key2, decryptKey: key1}, nil conn: conn,
} else { rd: bufio.NewReaderSize(conn, BufferSize),
return &Conn{conn: conn, encryptKey: key1, decryptKey: key2}, nil wr: bufio.NewWriterSize(conn, BufferSize),
} }
if isClient {
c.encryptKey, c.decryptKey = key2, key1
} else {
c.encryptKey, c.decryptKey = key1, key2
}
return c, nil
} }
const ( const (
@@ -47,87 +60,85 @@ const (
VerifySize = 2 VerifySize = 2
NonceSize = 8 NonceSize = 8
Overhead = 16 // chacha20poly1305.Overhead Overhead = 16 // chacha20poly1305.Overhead
BufferSize = 2 + 0xFFFF + Overhead
) )
func (c *Conn) Read(b []byte) (n int, err error) { func (c *Conn) Read(b []byte) (n int, err error) {
verify := make([]byte, VerifySize) // = packet length // something in reading buffer
buf := make([]byte, PacketSizeMax+Overhead) if len(c.rb) > 0 {
n = copy(b, c.rb)
c.rb = c.rb[n:]
return
}
verify := make([]byte, 2) // verify = plain message size
if _, err = io.ReadFull(c.rd, verify); err != nil {
return
}
n = int(binary.LittleEndian.Uint16(verify))
ciphertext := make([]byte, n+Overhead)
if _, err = io.ReadFull(c.rd, ciphertext); err != nil {
return
}
nonce := make([]byte, NonceSize) nonce := make([]byte, NonceSize)
for {
if len(b) < PacketSizeMax {
return
}
if _, err = io.ReadFull(c.conn, verify); err != nil {
return
}
size := binary.LittleEndian.Uint16(verify)
ciphertext := buf[:size+Overhead]
if _, err = io.ReadFull(c.conn, ciphertext); err != nil {
return
}
binary.LittleEndian.PutUint64(nonce, c.decryptCnt) binary.LittleEndian.PutUint64(nonce, c.decryptCnt)
c.decryptCnt++ c.decryptCnt++
// put decrypted text to b's end // buffer size enought for direct reading
if n <= cap(b) {
_, err = chacha20poly1305.DecryptAndVerify(c.decryptKey, b[:0], nonce, ciphertext, verify) _, err = chacha20poly1305.DecryptAndVerify(c.decryptKey, b[:0], nonce, ciphertext, verify)
if err != nil {
return return
} }
n += int(size) // plaintext size // reading to temporary buffer
c.rb = make([]byte, 0, n)
// Finish when all bytes fit in b if _, err = chacha20poly1305.DecryptAndVerify(c.decryptKey, c.rb, nonce, ciphertext, verify); err != nil {
if size < PacketSizeMax {
return return
} }
return c.Read(b)
b = b[size:]
}
} }
func (c *Conn) Write(b []byte) (n int, err error) { func (c *Conn) Write(b []byte) (n int, err error) {
c.mx.Lock() var ciphertext []byte
defer c.mx.Unlock() var nonce = make([]byte, NonceSize)
var verify = make([]byte, VerifySize)
nonce := make([]byte, NonceSize) for len(b) > 0 {
buf := make([]byte, NonceSize+PacketSizeMax+Overhead)
verify := buf[:VerifySize] // part of write buffer
for {
size := len(b) size := len(b)
if size > PacketSizeMax { if size > PacketSizeMax {
size = PacketSizeMax size = PacketSizeMax
} }
binary.LittleEndian.PutUint16(verify, uint16(size)) binary.LittleEndian.PutUint16(verify, uint16(size))
if _, err = c.wr.Write(verify); err != nil {
return
}
binary.LittleEndian.PutUint64(nonce, c.encryptCnt) binary.LittleEndian.PutUint64(nonce, c.encryptCnt)
c.encryptCnt++ c.encryptCnt++
// put encrypted text to writing buffer just after size (2 bytes) if cap(ciphertext) < size+Overhead {
_, err = chacha20poly1305.EncryptAndSeal(c.encryptKey, buf[2:2], nonce, b[:size], verify) ciphertext = make([]byte, size+Overhead)
}
_, err = chacha20poly1305.EncryptAndSeal(c.encryptKey, ciphertext[:0], nonce, b[:size], verify)
if err != nil { if err != nil {
return return
} }
if _, err = c.conn.Write(buf[:VerifySize+size+Overhead]); err != nil { if _, err = c.wr.Write(ciphertext); err != nil {
return return
} }
n += size // plaintext size b = b[size:]
n += size
if size < PacketSizeMax {
break
}
b = b[PacketSizeMax:]
} }
err = c.wr.Flush()
return return
} }