actually authenticate messages with challenges and HMACs
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
Justfile
|
Justfile
|
||||||
|
/test
|
||||||
|
|||||||
@@ -5,5 +5,9 @@ A hub-and-spoke VPN for IPv6
|
|||||||
## Features
|
## Features
|
||||||
* **Post-quantum security:** Uses [XWingMLKEM768X25519](https://datatracker.ietf.org/doc/html/draft-connolly-cfrg-xwing-kem/) + [XChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305#XChaCha20-Poly1305_%E2%80%93_extended_nonce_variant) + [HKDF-SHA-256](https://en.wikipedia.org/wiki/HKDF) for end-to-end encryption
|
* **Post-quantum security:** Uses [XWingMLKEM768X25519](https://datatracker.ietf.org/doc/html/draft-connolly-cfrg-xwing-kem/) + [XChaCha20-Poly1305](https://en.wikipedia.org/wiki/ChaCha20-Poly1305#XChaCha20-Poly1305_%E2%80%93_extended_nonce_variant) + [HKDF-SHA-256](https://en.wikipedia.org/wiki/HKDF) for end-to-end encryption
|
||||||
|
|
||||||
|
## Protocol
|
||||||
|
|
||||||
|
See [proto.go](https://git.ton1.dev/toni/baalvpn/src/branch/main/shared/proto.go)
|
||||||
|
|
||||||
## Third-party dependencies
|
## Third-party dependencies
|
||||||
* [`github.com/songgao/water`](https://github.com/songgao/water) - cross-platform wrapper around TUN interfaces
|
* [`github.com/songgao/water`](https://github.com/songgao/water) - cross-platform wrapper around TUN interfaces
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
"crypto/hpke"
|
"crypto/hpke"
|
||||||
|
"crypto/sha256"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"log"
|
"log"
|
||||||
@@ -26,9 +28,11 @@ var (
|
|||||||
iface *water.Interface
|
iface *water.Interface
|
||||||
conn *net.UDPConn
|
conn *net.UDPConn
|
||||||
serverAddr *net.UDPAddr
|
serverAddr *net.UDPAddr
|
||||||
internalIP net.IP = nil
|
internalIP net.IP
|
||||||
privKey hpke.PrivateKey
|
privKey hpke.PrivateKey
|
||||||
multicastKey []byte
|
multicastKey []byte
|
||||||
|
challengeCh = make(chan []byte, 1)
|
||||||
|
authSecret []byte
|
||||||
|
|
||||||
establishMutex sync.Mutex
|
establishMutex sync.Mutex
|
||||||
peerPubKeys = shared.NewTMap[string, hpke.PublicKey]()
|
peerPubKeys = shared.NewTMap[string, hpke.PublicKey]()
|
||||||
@@ -70,8 +74,23 @@ func register() {
|
|||||||
}
|
}
|
||||||
pubKey := privKey.PublicKey()
|
pubKey := privKey.PublicKey()
|
||||||
|
|
||||||
// TODO: this probably should be repeated until we get RESP_REGISTER
|
// TODO: all this probably should be retried until we get RESP_REGISTER
|
||||||
send(shared.BuildPkt(shared.REQ_REGISTER, pubKey.Bytes()))
|
|
||||||
|
log.Println("requesting register challenge")
|
||||||
|
send(shared.BuildPkt(shared.REQ_GET_CHALLENGE, pubKey.Bytes()))
|
||||||
|
|
||||||
|
challenge := <-challengeCh
|
||||||
|
log.Println("got register challenge")
|
||||||
|
|
||||||
|
authSecret, err = hpke.Open(privKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn-challenge"), challenge)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Println("registering")
|
||||||
|
mac := hmac.New(sha256.New, authSecret)
|
||||||
|
mac.Write(pubKey.Bytes())
|
||||||
|
send(shared.BuildPkt(shared.REQ_REGISTER, mac.Sum(nil), pubKey.Bytes()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func receivePackets() {
|
func receivePackets() {
|
||||||
@@ -116,11 +135,13 @@ func handleIncomingPkt(pkt []byte) {
|
|||||||
pktType := binary.LittleEndian.Uint16(pkt[2:])
|
pktType := binary.LittleEndian.Uint16(pkt[2:])
|
||||||
|
|
||||||
switch pktType {
|
switch pktType {
|
||||||
|
case shared.RESP_GET_CHALLENGE:
|
||||||
|
challengeCh <- pkt[4:]
|
||||||
case shared.RESP_REGISTER:
|
case shared.RESP_REGISTER:
|
||||||
internalIP = net.IP(pkt[4:20])
|
internalIP = net.IP(pkt[4:20])
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
multicastKey, err = hpke.Open(privKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn"), pkt[20:])
|
multicastKey, err = hpke.Open(privKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn-register"), pkt[20:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -129,11 +150,11 @@ func handleIncomingPkt(pkt []byte) {
|
|||||||
setupInterface()
|
setupInterface()
|
||||||
go relayPackets()
|
go relayPackets()
|
||||||
case shared.ENC_PKT:
|
case shared.ENC_PKT:
|
||||||
srcIP := net.IP(pkt[20:36]).String()
|
srcIP := net.IP(pkt[52:68]).String()
|
||||||
|
|
||||||
sessionKey := getOrEstablishSessionKey(srcIP)
|
sessionKey := getOrEstablishSessionKey(srcIP)
|
||||||
|
|
||||||
decryptedPkt, err := DecryptSym(sessionKey, pkt[36:])
|
decryptedPkt, err := DecryptSym(sessionKey, pkt[68:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -143,7 +164,7 @@ func handleIncomingPkt(pkt []byte) {
|
|||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
case shared.BROADCAST_PKT:
|
case shared.BROADCAST_PKT:
|
||||||
decryptedPkt, err := DecryptSym(multicastKey, pkt[4:])
|
decryptedPkt, err := DecryptSym(multicastKey, pkt[36:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -159,14 +180,14 @@ func handleIncomingPkt(pkt []byte) {
|
|||||||
}
|
}
|
||||||
peerPubKeys.Set(respIP, pubKey)
|
peerPubKeys.Set(respIP, pubKey)
|
||||||
case shared.REQ_ESTABLISH:
|
case shared.REQ_ESTABLISH:
|
||||||
srcIP := net.IP(pkt[20:36]).String()
|
srcIP := net.IP(pkt[52:68]).String()
|
||||||
ciphertext := pkt[36:]
|
ciphertext := pkt[68:]
|
||||||
|
|
||||||
r, err := hpke.NewRecipient(ciphertext, privKey, hpke.HKDFSHA256(), hpke.ExportOnly(), nil)
|
r, err := hpke.NewRecipient(ciphertext, privKey, hpke.HKDFSHA256(), hpke.ExportOnly(), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
sessionKey, err := r.Export("baalvpn", 32)
|
sessionKey, err := r.Export("baalvpn-establish", 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -174,10 +195,9 @@ func handleIncomingPkt(pkt []byte) {
|
|||||||
log.Println("received session key from", srcIP)
|
log.Println("received session key from", srcIP)
|
||||||
peerSessionKeys.Set(srcIP, sessionKey)
|
peerSessionKeys.Set(srcIP, sessionKey)
|
||||||
|
|
||||||
reqData := append(net.ParseIP(srcIP), internalIP...)
|
send(buildAuthPkt(shared.RESP_ESTABLISH, net.ParseIP(srcIP), internalIP))
|
||||||
send(shared.BuildPkt(shared.RESP_ESTABLISH, reqData))
|
|
||||||
case shared.RESP_ESTABLISH:
|
case shared.RESP_ESTABLISH:
|
||||||
srcIP := net.IP(pkt[20:36]).String()
|
srcIP := net.IP(pkt[52:68]).String()
|
||||||
log.Println("established session key with", srcIP)
|
log.Println("established session key with", srcIP)
|
||||||
peerEstablishAcks.Set(srcIP, true)
|
peerEstablishAcks.Set(srcIP, true)
|
||||||
default:
|
default:
|
||||||
@@ -215,13 +235,12 @@ func getOrEstablishSessionKey(ip string) []byte {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
sessionKey, err := sender.Export("baalvpn", 32)
|
sessionKey, err := sender.Export("baalvpn-establish", 32)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
reqData := append(net.ParseIP(ip), append(internalIP, ciphertext...)...)
|
send(buildAuthPkt(shared.REQ_ESTABLISH, net.ParseIP(ip), internalIP, ciphertext))
|
||||||
send(shared.BuildPkt(shared.REQ_ESTABLISH, reqData))
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// TODO: eww
|
// TODO: eww
|
||||||
@@ -279,7 +298,7 @@ func relayPackets() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
send(shared.BuildPkt(shared.BROADCAST_PKT, encryptedPkt))
|
send(buildAuthPkt(shared.BROADCAST_PKT, encryptedPkt))
|
||||||
} else {
|
} else {
|
||||||
destSessionKey := getOrEstablishSessionKey(destIP)
|
destSessionKey := getOrEstablishSessionKey(destIP)
|
||||||
|
|
||||||
@@ -288,12 +307,18 @@ func relayPackets() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
reqBody := append(net.ParseIP(destIP), append(internalIP, encryptedPkt...)...)
|
send(buildAuthPkt(shared.ENC_PKT, net.ParseIP(destIP), internalIP, encryptedPkt))
|
||||||
send(shared.BuildPkt(shared.ENC_PKT, reqBody))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func buildAuthPkt(pktType uint16, parts ...[]byte) []byte {
|
||||||
|
pkt := shared.BuildPkt(pktType, parts...)
|
||||||
|
mac := hmac.New(sha256.New, authSecret)
|
||||||
|
mac.Write(pkt[4:])
|
||||||
|
return append(pkt[:4], append(mac.Sum(nil), pkt[4:]...)...)
|
||||||
|
}
|
||||||
|
|
||||||
func send(req []byte) {
|
func send(req []byte) {
|
||||||
if _, err := conn.WriteToUDP(req, serverAddr); err != nil {
|
if _, err := conn.WriteToUDP(req, serverAddr); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
@@ -3,11 +3,14 @@
|
|||||||
// TODO: somehow persist IPs
|
// TODO: somehow persist IPs
|
||||||
// TODO: key rotation
|
// TODO: key rotation
|
||||||
// TODO: dont trust claimed IP at all
|
// TODO: dont trust claimed IP at all
|
||||||
|
// TODO: replay attacks are still a thing
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/hmac"
|
||||||
"crypto/hpke"
|
"crypto/hpke"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
|
"crypto/sha256"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"log"
|
"log"
|
||||||
@@ -21,6 +24,7 @@ type Peer struct {
|
|||||||
RealAddr *net.UDPAddr
|
RealAddr *net.UDPAddr
|
||||||
InternalIP string
|
InternalIP string
|
||||||
HexPublicKey string
|
HexPublicKey string
|
||||||
|
AuthSecret []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -29,6 +33,7 @@ var (
|
|||||||
peersByPubKey = shared.NewTMap[string, *Peer]()
|
peersByPubKey = shared.NewTMap[string, *Peer]()
|
||||||
conn *net.UDPConn
|
conn *net.UDPConn
|
||||||
multicastKey = make([]byte, 32)
|
multicastKey = make([]byte, 32)
|
||||||
|
authSecretsByPubKey = shared.NewTMap[string, []byte]()
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -93,7 +98,7 @@ func handleReq(req []byte, addr *net.UDPAddr) {
|
|||||||
pktType := binary.LittleEndian.Uint16(req[2:])
|
pktType := binary.LittleEndian.Uint16(req[2:])
|
||||||
|
|
||||||
switch pktType {
|
switch pktType {
|
||||||
case shared.REQ_REGISTER:
|
case shared.REQ_GET_CHALLENGE:
|
||||||
pubKey, err := hpke.MLKEM768X25519().NewPublicKey(req[4:])
|
pubKey, err := hpke.MLKEM768X25519().NewPublicKey(req[4:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("invalid pubkey")
|
log.Println("invalid pubkey")
|
||||||
@@ -102,10 +107,48 @@ func handleReq(req []byte, addr *net.UDPAddr) {
|
|||||||
|
|
||||||
hexPubKey := hex.EncodeToString(pubKey.Bytes())
|
hexPubKey := hex.EncodeToString(pubKey.Bytes())
|
||||||
|
|
||||||
|
authSecret := make([]byte, 32)
|
||||||
|
if _, err = rand.Read(authSecret); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
authSecretsByPubKey.Set(hexPubKey, authSecret)
|
||||||
|
|
||||||
|
ciphertext, err := hpke.Seal(pubKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn-challenge"), authSecret)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendTo(addr, shared.BuildPkt(shared.RESP_GET_CHALLENGE, ciphertext))
|
||||||
|
case shared.REQ_REGISTER:
|
||||||
|
auth := req[4:36]
|
||||||
|
|
||||||
|
pubKey, err := hpke.MLKEM768X25519().NewPublicKey(req[36:])
|
||||||
|
if err != nil {
|
||||||
|
log.Println("invalid pubkey")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
hexPubKey := hex.EncodeToString(pubKey.Bytes())
|
||||||
|
|
||||||
|
authSecret, ok := authSecretsByPubKey.GetOK(hexPubKey)
|
||||||
|
if !ok {
|
||||||
|
log.Println("unknown pubkey tried to REGISTER")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer authSecretsByPubKey.Delete(hexPubKey)
|
||||||
|
|
||||||
|
mac := hmac.New(sha256.New, authSecret)
|
||||||
|
mac.Write(pubKey.Bytes())
|
||||||
|
if !hmac.Equal(mac.Sum(nil), auth) {
|
||||||
|
log.Println("failed to authenticate REGISTER")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var internalIP string
|
var internalIP string
|
||||||
// TODO: authenticating only by PUBLIC key is obviously a bad idea
|
|
||||||
if peer, ok := peersByPubKey.GetOK(hexPubKey); ok {
|
if peer, ok := peersByPubKey.GetOK(hexPubKey); ok {
|
||||||
internalIP = peer.InternalIP
|
internalIP = peer.InternalIP
|
||||||
|
peer.AuthSecret = authSecret
|
||||||
peers.Delete(peer.RealAddr.String())
|
peers.Delete(peer.RealAddr.String())
|
||||||
peer.RealAddr = addr
|
peer.RealAddr = addr
|
||||||
peers.Set(addr.String(), peer)
|
peers.Set(addr.String(), peer)
|
||||||
@@ -115,28 +158,35 @@ func handleReq(req []byte, addr *net.UDPAddr) {
|
|||||||
RealAddr: addr,
|
RealAddr: addr,
|
||||||
InternalIP: internalIP,
|
InternalIP: internalIP,
|
||||||
HexPublicKey: hexPubKey,
|
HexPublicKey: hexPubKey,
|
||||||
|
AuthSecret: authSecret,
|
||||||
}
|
}
|
||||||
peers.Set(addr.String(), peer)
|
peers.Set(addr.String(), peer)
|
||||||
peersByInternal.Set(internalIP, peer)
|
peersByInternal.Set(internalIP, peer)
|
||||||
peersByPubKey.Set(hexPubKey, peer)
|
peersByPubKey.Set(hexPubKey, peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
ciphertext, err := hpke.Seal(pubKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn"), multicastKey)
|
ciphertext, err := hpke.Seal(pubKey, hpke.HKDFSHA256(), hpke.ChaCha20Poly1305(), []byte("baalvpn-register"), multicastKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp := shared.BuildPkt(shared.RESP_REGISTER, append(net.ParseIP(internalIP), ciphertext...))
|
sendTo(addr, shared.BuildPkt(shared.RESP_REGISTER, net.ParseIP(internalIP), ciphertext))
|
||||||
sendTo(addr, resp)
|
|
||||||
case shared.ENC_PKT:
|
case shared.ENC_PKT:
|
||||||
peer := peers.Get(addr.String())
|
peer := peers.Get(addr.String())
|
||||||
if peer == nil {
|
if peer == nil {
|
||||||
log.Println("data from unregistered peer:", addr.String())
|
log.Println("ENC_PKT from unregistered peer:", addr.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
destIP := net.IP(req[4:20]).String()
|
mac := hmac.New(sha256.New, peer.AuthSecret)
|
||||||
srcIP := net.IP(req[20:36]).String()
|
mac.Write(req[36:])
|
||||||
|
if !hmac.Equal(mac.Sum(nil), req[4:36]) {
|
||||||
|
log.Println("failed to authenticate ENC_PKT")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
destIP := net.IP(req[36:52]).String()
|
||||||
|
srcIP := net.IP(req[52:68]).String()
|
||||||
if srcIP != peer.InternalIP {
|
if srcIP != peer.InternalIP {
|
||||||
log.Println("rejected spoofed srcIP in ENC_PKT")
|
log.Println("rejected spoofed srcIP in ENC_PKT")
|
||||||
return
|
return
|
||||||
@@ -151,7 +201,14 @@ func handleReq(req []byte, addr *net.UDPAddr) {
|
|||||||
case shared.BROADCAST_PKT:
|
case shared.BROADCAST_PKT:
|
||||||
peer := peers.Get(addr.String())
|
peer := peers.Get(addr.String())
|
||||||
if peer == nil {
|
if peer == nil {
|
||||||
log.Println("data from unregistered peer:", addr.String())
|
log.Println("BROADCAST_PKT from unregistered peer:", addr.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mac := hmac.New(sha256.New, peer.AuthSecret)
|
||||||
|
mac.Write(req[36:])
|
||||||
|
if !hmac.Equal(mac.Sum(nil), req[4:36]) {
|
||||||
|
log.Println("failed to authenticate BROADCAST_PKT")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,23 +222,29 @@ func handleReq(req []byte, addr *net.UDPAddr) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
resp := shared.BuildPkt(shared.RESP_GET_PUBKEY, append(net.ParseIP(peerIP), pubKey...))
|
sendTo(addr, shared.BuildPkt(shared.RESP_GET_PUBKEY, net.ParseIP(peerIP), pubKey))
|
||||||
sendTo(addr, resp)
|
|
||||||
}
|
}
|
||||||
case shared.REQ_ESTABLISH, shared.RESP_ESTABLISH:
|
case shared.REQ_ESTABLISH, shared.RESP_ESTABLISH:
|
||||||
peer := peers.Get(addr.String())
|
peer := peers.Get(addr.String())
|
||||||
if peer == nil {
|
if peer == nil {
|
||||||
log.Println("unregistered peer tried to ESTABLISH")
|
log.Println("ESTABLISH from unregistered peer:", addr.String())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
srcIP := net.IP(req[20:36]).String()
|
mac := hmac.New(sha256.New, peer.AuthSecret)
|
||||||
|
mac.Write(req[36:])
|
||||||
|
if !hmac.Equal(mac.Sum(nil), req[4:36]) {
|
||||||
|
log.Println("failed to authenticate ESTABLISH")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
srcIP := net.IP(req[52:68]).String()
|
||||||
if srcIP != peer.InternalIP {
|
if srcIP != peer.InternalIP {
|
||||||
log.Println("rejected spoofed srcIP in ESTABLISH")
|
log.Println("rejected spoofed srcIP in ESTABLISH")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
dstIP := net.IP(req[4:20]).String()
|
dstIP := net.IP(req[36:52]).String()
|
||||||
dstPeer := peersByInternal.Get(dstIP)
|
dstPeer := peersByInternal.Get(dstIP)
|
||||||
if dstPeer == nil {
|
if dstPeer == nil {
|
||||||
log.Println("tried to ESTABLISH with an unknown peer")
|
log.Println("tried to ESTABLISH with an unknown peer")
|
||||||
|
|||||||
@@ -4,38 +4,58 @@ import "encoding/binary"
|
|||||||
|
|
||||||
const PROTO_VERSION uint16 = 1
|
const PROTO_VERSION uint16 = 1
|
||||||
|
|
||||||
|
// pubKey - public key generated by the client
|
||||||
|
// privKey - private key generated by the client
|
||||||
|
// sessionKey - key established between two peers
|
||||||
|
// multicastKey - key shared between everyone for encrypting multicast pkts
|
||||||
|
// authSecret - secret given during registration for authenticating subsequent requests
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_ uint16 = iota
|
_ uint16 = iota
|
||||||
|
// (client -> server) requests a challenge to prove the ownership of the privKey
|
||||||
|
// [ pubKey - 1216 bytes ]
|
||||||
|
REQ_GET_CHALLENGE
|
||||||
|
// (server -> client) provides a pubKey-encrypted authSecret
|
||||||
|
// [ ciphertext - 1168 bytes ]
|
||||||
|
RESP_GET_CHALLENGE
|
||||||
// (client -> server) requests an IP
|
// (client -> server) requests an IP
|
||||||
// [ pubkey - 1216 bytes ]
|
// [ HMAC(authSecret, pubKey) - 32 bytes ] [ pubKey - 1216 bytes ]
|
||||||
REQ_REGISTER
|
REQ_REGISTER
|
||||||
// (server -> client) returns the assigned IP and encapsulated multicast key
|
// (server -> client) returns the assigned IP and pubKey-encrypted multicastKey
|
||||||
// [ ip - 16 bytes ] [ ciphertext - 1168 bytes ]
|
// [ ip - 16 bytes ] [ ciphertext - 1168 bytes ]
|
||||||
RESP_REGISTER
|
RESP_REGISTER
|
||||||
// (client -> server -> client2) relays an encrypted packet to a specified peer
|
// (client -> server -> client2) relays an encrypted packet to a specified peer
|
||||||
// [ destIP - 16 bytes ] [ srcIP - 16 bytes ] [ encrypted pkt ]
|
// [ HMAC(authSecret, rest) - 32 bytes ] [ destIP - 16 bytes ] [ srcIP - 16 bytes ] [ encryptedPkt ]
|
||||||
ENC_PKT
|
ENC_PKT
|
||||||
// (client -> server -> *) broadcasts an encrypted packet
|
// (client -> server -> *) broadcasts an encrypted packet
|
||||||
// [ encrypted pkt ]
|
// [ HMAC(authSecret, rest) - 32 bytes ] [ encryptedPkt ]
|
||||||
BROADCAST_PKT
|
BROADCAST_PKT
|
||||||
// (client -> server) requests peer's pubkey from the server for encapsulation
|
// (client -> server) requests peer's pubKey from the server for encapsulation
|
||||||
// [ ip - 16 bytes ]
|
// [ ip - 16 bytes ]
|
||||||
REQ_GET_PUBKEY
|
REQ_GET_PUBKEY
|
||||||
// (server -> client) provides requested pubkey
|
// (server -> client) provides requested pubKey
|
||||||
// [ ip - 16 bytes ] [ pubkey - 1216 bytes ]
|
// [ ip - 16 bytes ] [ pubKey - 1216 bytes ]
|
||||||
RESP_GET_PUBKEY
|
RESP_GET_PUBKEY
|
||||||
// (client -> server -> client2) establishes a session key with another peer
|
// (client -> server -> client2) establishes a sessionKey with another peer
|
||||||
// [ destIP - 16 bytes ] [ srcIP - 16 bytes ] [ ciphertext - 1120 bytes ]
|
// [ HMAC(authSecret, rest) - 32 bytes ] [ destIP - 16 bytes ] [ srcIP - 16 bytes ] [ ciphertext - 1120 bytes ]
|
||||||
REQ_ESTABLISH
|
REQ_ESTABLISH
|
||||||
// (client2 -> server -> client) acknowledges the session key was established
|
// (client2 -> server -> client) acknowledges the sessionKey was established
|
||||||
// [ destIP - 16 bytes ] [ srcIP - 16 bytes ]
|
// [ HMAC(authSecret, rest) - 32 bytes ] [ destIP - 16 bytes ] [ srcIP - 16 bytes ]
|
||||||
RESP_ESTABLISH
|
RESP_ESTABLISH
|
||||||
)
|
)
|
||||||
|
|
||||||
func BuildPkt(pktType uint16, data []byte) []byte {
|
func BuildPkt(pktType uint16, parts ...[]byte) []byte {
|
||||||
out := make([]byte, 4+len(data))
|
var total int
|
||||||
|
for _, p := range parts {
|
||||||
|
total += len(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]byte, 4, 4+total)
|
||||||
binary.LittleEndian.PutUint16(out[0:], PROTO_VERSION)
|
binary.LittleEndian.PutUint16(out[0:], PROTO_VERSION)
|
||||||
binary.LittleEndian.PutUint16(out[2:], pktType)
|
binary.LittleEndian.PutUint16(out[2:], pktType)
|
||||||
copy(out[4:], data)
|
|
||||||
|
for _, p := range parts {
|
||||||
|
out = append(out, p...)
|
||||||
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user