55 lines
1.5 KiB
Go
55 lines
1.5 KiB
Go
package multicast
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"net/netip"
|
|
|
|
"golang.org/x/crypto/nacl/sign"
|
|
)
|
|
|
|
const (
|
|
BufferSize = packetSize + SignedPacketSize
|
|
SignedPacketSize = packetSize + signSize
|
|
packetSize = 43
|
|
signSize = 64
|
|
)
|
|
|
|
// Layout:
|
|
//
|
|
// [0] final octet of the sender's VPN IP
|
|
// [1:33] WG public key
|
|
// [33:35] WG listen port (big-endian uint16)
|
|
// [35:43] send time, Unix seconds (big-endian int64) — freshness/replay gate
|
|
type Packet struct {
|
|
PeerIP byte // Final octet of the sender's VPN IP.
|
|
WGPubKey [32]byte // WG public key.
|
|
WGPort uint16 // WG listen port.
|
|
Timestamp int64 // Unix timestamp.
|
|
Src netip.Addr // Source of packet.
|
|
Signed []byte // Raw signed message for verification (incoming packet).
|
|
}
|
|
|
|
// Marshal the packet into a buffer with prefixed signature.
|
|
func (p Packet) Marshal(buf []byte, signKey *[64]byte) []byte {
|
|
buf[0] = p.PeerIP
|
|
copy(buf[1:33], p.WGPubKey[:])
|
|
binary.BigEndian.PutUint16(buf[33:35], p.WGPort)
|
|
binary.BigEndian.PutUint64(buf[35:43], uint64(p.Timestamp))
|
|
return sign.Sign(buf[packetSize:packetSize], buf[:packetSize], signKey)
|
|
}
|
|
|
|
func (p Packet) Verify(buf []byte, pubKey *[32]byte) bool {
|
|
_, ok := sign.Open(buf, p.Signed, pubKey)
|
|
return ok
|
|
}
|
|
|
|
func Unmarshal(signed []byte) (p Packet) {
|
|
buf := signed[signSize:]
|
|
p.PeerIP = buf[0]
|
|
copy(p.WGPubKey[:], buf[1:33])
|
|
p.WGPort = binary.BigEndian.Uint16(buf[33:35])
|
|
p.Timestamp = int64(binary.BigEndian.Uint64(buf[35:43]))
|
|
p.Signed = signed
|
|
return
|
|
}
|