diff --git a/node/conn.go b/node/conn.go index fbc16f8..8c23d1d 100644 --- a/node/conn.go +++ b/node/conn.go @@ -4,9 +4,16 @@ import ( "log" "net" "net/netip" + "sync/atomic" "vppn/fasttime" ) +// TODO: +type connRouter interface { + Lookup(byte) *peer + Mediator() *peer +} + type connWriter struct { *net.UDPConn localIP byte @@ -37,10 +44,8 @@ func (w *connWriter) WriteTo(remoteIP, packetType byte, data []byte) error { return nil } - w.counters[remoteIP]++ - h := header{ - Counter: w.counters[remoteIP], + Counter: atomic.AddUint64(&w.counters[remoteIP], 1), SourceIP: w.localIP, ViaIP: 0, DestIP: remoteIP, diff --git a/node/crypto.go b/node/crypto.go new file mode 100644 index 0000000..7240bb7 --- /dev/null +++ b/node/crypto.go @@ -0,0 +1,26 @@ +package node + +import "golang.org/x/crypto/nacl/box" + +// Encrypting the packet will also set the header's DataSize field. +func encryptPacket(h *header, sharedKey, data, out []byte) []byte { + h.DataSize = uint16(len(data) + box.Overhead) + out = out[:h.DataSize+headerSize] + h.Marshal(out) + box.SealAfterPrecomputation(out[headerSize:headerSize], data, (*[24]byte)(out[:headerSize]), (*[32]byte)(sharedKey)) + return out +} + +func decryptPacket(sharedKey, packetAndHeader, out []byte) (decrypted []byte, ok bool) { + return box.OpenAfterPrecomputation( + out[:0], + packetAndHeader[headerSize:], + (*[24]byte)(packetAndHeader[:headerSize]), + (*[32]byte)(sharedKey)) +} + +func computeSharedKey(peerPubKey, privKey []byte) []byte { + shared := [32]byte{} + box.Precompute(&shared, (*[32]byte)(peerPubKey), (*[32]byte)(privKey)) + return shared[:] +} diff --git a/node/crypto_test.go b/node/crypto_test.go new file mode 100644 index 0000000..502dca5 --- /dev/null +++ b/node/crypto_test.go @@ -0,0 +1,121 @@ +package node + +import ( + "bytes" + "crypto/rand" + "reflect" + "testing" + + "golang.org/x/crypto/nacl/box" +) + +func TestEncryptDecryptPacket(t *testing.T) { + pubKey1, privKey1, err := box.GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + + pubKey2, privKey2, err := box.GenerateKey(rand.Reader) + if err != nil { + t.Fatal(err) + } + + sharedEncKey := [32]byte{} + box.Precompute(&sharedEncKey, pubKey2, privKey1) + + sharedDecKey := [32]byte{} + box.Precompute(&sharedDecKey, pubKey1, privKey2) + + original := make([]byte, if_mtu-64) + rand.Read(original) + + h := header{ + Counter: 2893749238, + SourceIP: 5, + ViaIP: 8, + DestIP: 12, + PacketType: 32, + } + + encrypted := make([]byte, bufferSize) + encrypted = encryptPacket(&h, sharedEncKey[:], original, encrypted) + + decrypted := make([]byte, bufferSize) + var ok bool + decrypted, ok = decryptPacket(sharedDecKey[:], encrypted, decrypted) + if !ok { + t.Fatal(ok) + } + + var h2 header + h2.Parse(encrypted) + + if !reflect.DeepEqual(h, h2) { + t.Fatal(h, h2) + } + + if !bytes.Equal(original, decrypted) { + t.Fatal("mismatch") + } +} + +/* +func BenchmarkEncryptPacket(b *testing.B) { + _, privKey1, err := box.GenerateKey(rand.Reader) + if err != nil { + b.Fatal(err) + } + + pubKey2, _, err := box.GenerateKey(rand.Reader) + if err != nil { + b.Fatal(err) + } + + sharedEncKey := [32]byte{} + box.Precompute(&sharedEncKey, pubKey2, privKey1) + + original := make([]byte, MTU) + rand.Read(original) + + nonce := make([]byte, NONCE_SIZE) + rand.Read(nonce) + + encrypted := make([]byte, BUFFER_SIZE) + + for i := 0; i < b.N; i++ { + encrypted = encryptPacket(sharedEncKey[:], nonce, original, encrypted) + } +} + +func BenchmarkDecryptPacket(b *testing.B) { + pubKey1, privKey1, err := box.GenerateKey(rand.Reader) + if err != nil { + b.Fatal(err) + } + + pubKey2, privKey2, err := box.GenerateKey(rand.Reader) + if err != nil { + b.Fatal(err) + } + + sharedEncKey := [32]byte{} + box.Precompute(&sharedEncKey, pubKey2, privKey1) + + sharedDecKey := [32]byte{} + box.Precompute(&sharedDecKey, pubKey1, privKey2) + + original := make([]byte, MTU) + rand.Read(original) + + nonce := make([]byte, NONCE_SIZE) + rand.Read(nonce) + + encrypted := make([]byte, BUFFER_SIZE) + encrypted = encryptPacket(sharedEncKey[:], nonce, original, encrypted) + + decrypted := make([]byte, MTU) + for i := 0; i < b.N; i++ { + decrypted, _ = decryptPacket(sharedDecKey[:], encrypted, decrypted) + } +} +*/ diff --git a/node/peer.go b/node/peer.go index 53479d2..d93f2df 100644 --- a/node/peer.go +++ b/node/peer.go @@ -6,12 +6,9 @@ import ( ) type peer struct { - IP byte - // TODO: Version - Addr *netip.AddrPort - // TODO: ViaIP - // TODO: EncPubKey - // TODO: SignPrivKey + IP byte + Addr *netip.AddrPort // If we have direct connection, otherwise use mediator. + // TODO: SharedKey []byte } type peerRepo [256]*atomic.Pointer[peer]