This is preparation for changing of TCP protocol: in TCP we can easily
predict needed nonce and udnerstand the bounds of the packet,
eliminating the need of size prefix at all.
Signed-off-by: Sergey Matveev <stargrave@stargrave.org>
@section Transport protocol
@verbatim
@section Transport protocol
@verbatim
-[PktLen] + ENCn(SERIAL) + ENC(KEY, ENCn(SERIAL), DATA_SIZE+DATA+NOISE) +
- AUTH(ENCn(SERIAL) + ENC(KEY, ENCn(SERIAL), DATA_SIZE+DATA+NOISE))
+[PktLen] + ENC(KEY, ENCn(SERIAL), DATA_SIZE+DATA+NOISE) + ENCn(SERIAL) +
+ AUTH(ENC(KEY, ENCn(SERIAL), DATA_SIZE+DATA+NOISE) + ENCn(SERIAL))
@end verbatim
All transport and handshake messages are indistinguishable from
@end verbatim
All transport and handshake messages are indistinguishable from
nonceRecv uint64
frame []byte
nonce []byte
nonceRecv uint64
frame []byte
nonce []byte
- Emptiness = make([]byte, 1<<14)
- taps = make(map[string]*TAP)
+ taps = make(map[string]*TAP)
)
// Create TAP listening goroutine.
)
// Create TAP listening goroutine.
NonceRecv: 0,
Key: key,
NonceCipher: newNonceCipher(key),
NonceRecv: 0,
Key: key,
NonceCipher: newNonceCipher(key),
- buf: make([]byte, MTU+S20BS),
+ buf: make([]byte, MTU+S20BS+NonceSize+poly1305.TagSize),
tag: new([poly1305.TagSize]byte),
keyAuth: new([SSize]byte),
nonce: make([]byte, NonceSize),
tag: new([poly1305.TagSize]byte),
keyAuth: new([SSize]byte),
nonce: make([]byte, NonceSize),
// will be written to the interface immediately (except heartbeat ones).
func (p *Peer) PktProcess(data []byte, tap io.Writer, ready chan struct{}) bool {
p.size = len(data)
// will be written to the interface immediately (except heartbeat ones).
func (p *Peer) PktProcess(data []byte, tap io.Writer, ready chan struct{}) bool {
p.size = len(data)
- copy(p.buf, Emptiness)
- copy(p.tag[:], data[p.size-poly1305.TagSize:])
- copy(p.buf[S20BS:], data[NonceSize:p.size-poly1305.TagSize])
+ p.frame = make([]byte, p.size)
+ copy(p.frame, data)
+ ready <- struct{}{}
+
+ copy(p.buf[S20BS:], p.frame[:p.size-NonceSize-poly1305.TagSize])
+ for i := 0; i < S20BS; i++ {
+ p.buf[i] = byte(0)
+ }
- p.buf[:S20BS+p.size-poly1305.TagSize],
- p.buf[:S20BS+p.size-poly1305.TagSize],
- data[:NonceSize],
+ p.buf[:S20BS+p.size-NonceSize-poly1305.TagSize],
+ p.buf[:S20BS+p.size-NonceSize-poly1305.TagSize],
+ p.frame[p.size-NonceSize-poly1305.TagSize:p.size-poly1305.TagSize],
+ copy(p.tag[:], p.frame[p.size-poly1305.TagSize:])
copy(p.keyAuth[:], p.buf[:SSize])
copy(p.keyAuth[:], p.buf[:SSize])
- if !poly1305.Verify(p.tag, data[:p.size-poly1305.TagSize], p.keyAuth) {
- ready <- struct{}{}
+ if !poly1305.Verify(p.tag, p.frame[:p.size-poly1305.TagSize], p.keyAuth) {
p.FramesUnauth++
return false
}
p.FramesUnauth++
return false
}
// Check from the oldest bucket, as in most cases this will result
// in constant time check.
// If Bucket0 is filled, then it becomes Bucket1.
// Check from the oldest bucket, as in most cases this will result
// in constant time check.
// If Bucket0 is filled, then it becomes Bucket1.
- p.NonceCipher.Decrypt(p.buf, data[:NonceSize])
- ready <- struct{}{}
+ p.NonceCipher.Decrypt(
+ p.nonce,
+ p.frame[p.size-NonceSize-poly1305.TagSize:p.size-poly1305.TagSize],
+ )
- p.nonceRecv, _ = binary.Uvarint(p.buf[:NonceSize])
+ p.nonceRecv = binary.BigEndian.Uint64(p.nonce)
if p.Conn.Reorderable() {
if _, p.nonceFound = p.nonceBucket1[p.NonceRecv]; p.nonceFound {
p.FramesDup++
if p.Conn.Reorderable() {
if _, p.nonceFound = p.nonceBucket1[p.NonceRecv]; p.nonceFound {
p.FramesDup++
p.BytesIn += int64(p.size)
p.LastPing = time.Now()
p.NonceRecv = p.nonceRecv
p.BytesIn += int64(p.size)
p.LastPing = time.Now()
p.NonceRecv = p.nonceRecv
- p.pktSize, _ = binary.Uvarint(p.buf[S20BS : S20BS+PktSizeSize])
+ p.pktSize = binary.BigEndian.Uint16(p.buf[S20BS : S20BS+PktSizeSize])
if p.pktSize == 0 {
p.HeartbeatRecv++
return true
}
if p.pktSize == 0 {
p.HeartbeatRecv++
return true
}
- p.frame = p.buf[S20BS+PktSizeSize : S20BS+PktSizeSize+p.pktSize]
p.BytesPayloadIn += int64(p.pktSize)
p.BytesPayloadIn += int64(p.pktSize)
+ tap.Write(p.buf[S20BS+PktSizeSize : S20BS+PktSizeSize+p.pktSize])
if p.size == 0 && !p.LastSent.Add(p.Timeout).Before(p.now) {
return
}
if p.size == 0 && !p.LastSent.Add(p.Timeout).Before(p.now) {
return
}
if p.size > 0 {
copy(p.buf[S20BS+PktSizeSize:], data)
ready <- struct{}{}
if p.size > 0 {
copy(p.buf[S20BS+PktSizeSize:], data)
ready <- struct{}{}
- binary.PutUvarint(p.buf[S20BS:S20BS+PktSizeSize], uint64(p.size))
+ binary.BigEndian.PutUint16(p.buf[S20BS:S20BS+PktSizeSize], uint16(p.size))
p.BytesPayloadOut += int64(p.size)
} else {
p.BytesPayloadOut += int64(p.size)
} else {
+ p.buf[S20BS+0] = byte(0)
+ p.buf[S20BS+1] = byte(0)
p.HeartbeatSent++
}
p.NonceOur += 2
p.HeartbeatSent++
}
p.NonceOur += 2
- copy(p.nonce, Emptiness)
- binary.PutUvarint(p.nonce, p.NonceOur)
+ binary.BigEndian.PutUint64(p.nonce, p.NonceOur)
p.NonceCipher.Encrypt(p.nonce, p.nonce)
p.NonceCipher.Encrypt(p.nonce, p.nonce)
+ for i := 0; i < S20BS; i++ {
+ p.buf[i] = byte(0)
+ }
salsa20.XORKeyStream(p.buf, p.buf, p.nonce, p.Key)
salsa20.XORKeyStream(p.buf, p.buf, p.nonce, p.Key)
- copy(p.buf[S20BS-NonceSize:S20BS], p.nonce)
- copy(p.keyAuth[:], p.buf[:SSize])
- p.frame = p.buf[S20BS-NonceSize : S20BS+MTU-NonceSize-poly1305.TagSize]
+ p.frame = append(p.buf[S20BS:S20BS+MTU-NonceSize-poly1305.TagSize], p.nonce...)
- p.frame = p.buf[S20BS-NonceSize : S20BS+PktSizeSize+p.size]
+ p.frame = append(p.buf[S20BS:S20BS+PktSizeSize+p.size], p.nonce...)
+ copy(p.keyAuth[:], p.buf[:SSize])
poly1305.Sum(p.tag, p.frame, p.keyAuth)
p.BytesOut += int64(len(p.frame) + poly1305.TagSize)
poly1305.Sum(p.tag, p.frame, p.keyAuth)
p.BytesOut += int64(len(p.frame) + poly1305.TagSize)