]> Sergey Matveev's repositories - vors.git/commitdiff
Shorter MAC
authorSergey Matveev <stargrave@stargrave.org>
Wed, 10 Apr 2024 21:54:15 +0000 (00:54 +0300)
committerSergey Matveev <stargrave@stargrave.org>
Wed, 10 Apr 2024 21:54:15 +0000 (00:54 +0300)
cmd/client/main.go
doc/proto.texi

index 6b4fe68911b6d3a8cd92ab588d51b5dca1aa84466a1d9fd47235c6172bbdbd48..87d77fcafa17ea0b33e53be978b3532e204277d4b854e442df06390d27598a5a 100644 (file)
@@ -18,6 +18,7 @@ package main
 import (
        "bufio"
        "bytes"
+       "crypto/subtle"
        "crypto/tls"
        "crypto/x509"
        "encoding/binary"
@@ -39,11 +40,12 @@ import (
        vors "go.stargrave.org/vors/internal"
        "golang.org/x/crypto/blake2s"
        "golang.org/x/crypto/chacha20"
-       "golang.org/x/crypto/chacha20poly1305"
        "golang.org/x/crypto/poly1305"
        "gopkg.in/hraban/opus.v2"
 )
 
+const TagLen = 8
+
 type Stream struct {
        name  string
        ctr   uint32
@@ -188,12 +190,7 @@ func main() {
        Streams[sid] = &Stream{name: *Name, stats: OurStats}
 
        tlsState := ctrl.ConnectionState()
-       key, err := tlsState.ExportKeyingMaterial(
-               cols[1], nil, chacha20poly1305.KeySize)
-       if err != nil {
-               log.Fatal(err)
-       }
-       ciph, err := chacha20poly1305.New(key)
+       keyOur, err := tlsState.ExportKeyingMaterial(cols[1], nil, chacha20.KeySize)
        if err != nil {
                log.Fatal(err)
        }
@@ -277,10 +274,6 @@ func main() {
                                        stats: &Stats{dead: make(chan struct{})},
                                }
                                go func() {
-                                       ciph, err := chacha20poly1305.New(key)
-                                       if err != nil {
-                                               log.Fatal(err)
-                                       }
                                        dec, err := opus.NewDecoder(vors.Rate, 1)
                                        if err != nil {
                                                log.Fatal(err)
@@ -300,24 +293,39 @@ func main() {
                                                }
                                        }
 
-                                       ctr := uint32(sid) << 24
+                                       var ciph *chacha20.Cipher
+                                       var macKey [32]byte
+                                       var mac *poly1305.MAC
+                                       tag := make([]byte, poly1305.TagSize)
+                                       var ctr uint32
                                        pcm := make([]int16, vors.FrameLen)
                                        pcmbuf := make([]byte, 2*vors.FrameLen)
-                                       decbuf := make([]byte, 2*vors.FrameLen)
-                                       nonce := make([]byte, chacha20.NonceSize)
-                                       ctrBuf := nonce[len(nonce)-4:]
+                                       nonce := make([]byte, 12)
                                        var pkt []byte
                                        lost := -1
                                        var lastDur int
                                        for buf := range stream.in {
-                                               ctr = binary.BigEndian.Uint32(buf)
-                                               copy(ctrBuf, buf)
-                                               pkt, err = ciph.Open(
-                                                       decbuf[:0], nonce, buf[4:], []byte{buf[0]})
+                                               copy(nonce[len(nonce)-4:], buf)
+                                               ciph, err = chacha20.NewUnauthenticatedCipher(key, nonce)
                                                if err != nil {
-                                                       log.Println("decrypt:", stream.name, err)
+                                                       log.Fatal(err)
+                                               }
+                                               clear(macKey[:])
+                                               ciph.XORKeyStream(macKey[:], macKey[:])
+                                               ciph.SetCounter(1)
+                                               mac = poly1305.New(&macKey)
+                                               if _, err = mac.Write(buf[4 : len(buf)-TagLen]); err != nil {
+                                                       log.Fatal(err)
+                                               }
+                                               mac.Sum(tag[:0])
+                                               if subtle.ConstantTimeCompare(tag[:TagLen], buf[len(buf)-TagLen:]) != 1 {
+                                                       log.Println("decrypt:", stream.name, "tag differs")
                                                        continue
                                                }
+                                               pkt = buf[4 : len(buf)-TagLen]
+                                               ciph.XORKeyStream(pkt, pkt)
+
+                                               ctr = binary.BigEndian.Uint32(nonce[len(nonce)-4:])
                                                if lost == -1 {
                                                        // ignore the very first packet in the stream
                                                        lost = 0
@@ -460,12 +468,14 @@ func main() {
                        return
                }
                <-LoggerReady
+               var ciph *chacha20.Cipher
+               var macKey [32]byte
+               var mac *poly1305.MAC
+               tag := make([]byte, poly1305.TagSize)
                buf := make([]byte, 2*vors.FrameLen)
                pcm := make([]int16, vors.FrameLen)
-               nonce := make([]byte, ciph.NonceSize())
+               nonce := make([]byte, 12)
                nonce[len(nonce)-4] = sid
-               ctr := nonce[len(nonce)-3:]
-               sidAndCtr := nonce[len(nonce)-4:]
                var pkt []byte
                var n, i int
                for {
@@ -483,13 +493,29 @@ func main() {
                        if vad != 0 && vors.RMS(pcm) < vad {
                                continue
                        }
-                       incr(ctr)
-                       copy(buf, sidAndCtr)
                        n, err = opusEnc.Encode(pcm, buf[4:])
                        if err != nil {
                                log.Fatal(err)
                        }
-                       pkt = ciph.Seal(buf[:4], nonce, buf[4:4+n], []byte{sid})
+
+                       incr(nonce[len(nonce)-3:])
+                       copy(buf, nonce[len(nonce)-4:])
+                       ciph, err = chacha20.NewUnauthenticatedCipher(keyOur, nonce)
+                       if err != nil {
+                               log.Fatal(err)
+                       }
+                       clear(macKey[:])
+                       ciph.XORKeyStream(macKey[:], macKey[:])
+                       ciph.SetCounter(1)
+                       ciph.XORKeyStream(buf[4:4+n], buf[4:4+n])
+                       mac = poly1305.New(&macKey)
+                       if _, err = mac.Write(buf[4 : 4+n]); err != nil {
+                               log.Fatal(err)
+                       }
+                       mac.Sum(tag[:0])
+                       copy(buf[4+n:], tag[:TagLen])
+                       pkt = buf[:4+n+TagLen]
+
                        OurStats.pkts++
                        OurStats.bytes += uint64(len(pkt))
                        OurStats.last = time.Now()
index 10fb381a89f09eb2dd9841a24d2473d148c44edfdecb68fda8486a6c76ca78d2..6ebaca70c9a9119ba408a490d33e844d3329e61fb856fda1e16eac1123652521 100644 (file)
@@ -11,13 +11,13 @@ dropped. 24-bit counter is long enough for very long talk sessions.
 
 Each packet is encrypted with ChaCha20-Poly1305. Key is generated during
 handshake procedure with the server and is shared among other participants.
-Packet counter is used as a nonce. Stream identifier is additional
-authenticated data.
+Stream identifier with packet counter are used as a nonce. Only 64-bits
+of Poly1305 are used.
 
 It is tuned for 32Kbps bandwidth. 24Kbps should be enough, but 40B of
-IPv6 header, +16B of Poly1305 authentication tag, +4B of stream
-identifier with the counter, +8B of UDP header for 50pps means ~28Kbps
-of bandwidth only for overhead transmission.
+IPv6 header, +8B of Poly1305 authentication tag, +4B of stream
+identifier with the counter, +8B of UDP header for 50pps means also
+24Kbps of bandwidth only for overhead transmission.
 
 Each client handshakes with the server over TCP protocol using TLS 1.3
 with curve25519 key-agreement protocol. @command{vors-keygen} generates