commit f17df4ce8833765640c62a3062157a512bb27e49 Author: Justin Hawkins Date: Sun Jan 9 13:05:36 2022 +1030 Initial commit, based mostly on https://github.com/austburn/gocrypt diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..befe466 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "netgiv" + ] +} \ No newline at end of file diff --git a/client.go b/client.go new file mode 100644 index 0000000..715fd0c --- /dev/null +++ b/client.go @@ -0,0 +1,55 @@ +package main + +import ( + "bufio" + "errors" + "fmt" + "net" + "os" + + "github.com/tardisx/netgiv/secure" +) + +type Client struct { + port int +} + +func (c *Client) Connect() error { + address := fmt.Sprintf("127.0.0.1:%d", c.port) + serverAddress, _ := net.ResolveTCPAddr("tcp", address) + + conn, err := net.DialTCP("tcp", nil, serverAddress) + if err != nil { + return errors.New("Problem connecting to server, is it running?\n") + } + defer conn.Close() + + fmt.Printf("Connection on %s\n", address) + + sharedKey := secure.Handshake(conn) + secureConnection := secure.SecureConnection{Conn: conn, SharedKey: sharedKey} + + reader := bufio.NewReader(os.Stdin) + + for { + fmt.Print("> ") + // Read up to the newline character + msg, _ := reader.ReadBytes(0xA) + // Kill the newline char + msg = msg[:len(msg)-1] + + _, err := secureConnection.Write(msg) + + response := make([]byte, 1024) + + _, err = secureConnection.Read(response) + if err != nil { + fmt.Print("Connection to the server was closed.\n") + break + } + + fmt.Printf("%s\n", response) + } + + return nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..5d51094 --- /dev/null +++ b/go.mod @@ -0,0 +1,8 @@ +module github.com/tardisx/netgiv + +go 1.17 + +require ( + golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect + golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e11fe49 --- /dev/null +++ b/go.sum @@ -0,0 +1,4 @@ +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/main.go b/main.go new file mode 100644 index 0000000..54867f0 --- /dev/null +++ b/main.go @@ -0,0 +1,25 @@ +package main + +import ( + "flag" + "fmt" +) + +func main() { + port := flag.Int("p", 9000, "Port to run server/client on.") + isServer := flag.Bool("s", false, "Set if running the server.") + flag.Parse() + + if *isServer { + fmt.Printf("Server running on %d\n", *port) + s := Server{port: *port} + s.Run() + } else { + fmt.Printf("Client running on %d\n", *port) + c := Client{port: *port} + err := c.Connect() + if err != nil { + fmt.Print(err) + } + } +} diff --git a/secure/secure.go b/secure/secure.go new file mode 100644 index 0000000..0cb05b7 --- /dev/null +++ b/secure/secure.go @@ -0,0 +1,82 @@ +package secure + +import ( + "bytes" + "crypto/rand" + "errors" + "net" + + "golang.org/x/crypto/nacl/box" +) + +type SecureMessage struct { + Msg []byte + Nonce [24]byte +} + +func (s *SecureMessage) toByteArray() []byte { + return append(s.Nonce[:], s.Msg[:]...) +} + +func ConstructSecureMessage(sm []byte) SecureMessage { + var nonce [24]byte + nonceArray := sm[:24] + copy(nonce[:], nonceArray) + + // Trim out all unnecessary bytes + msg := bytes.Trim(sm[24:], "\x00") + + return SecureMessage{Msg: msg, Nonce: nonce} +} + +type SecureConnection struct { + Conn *net.TCPConn + SharedKey *[32]byte +} + +func (s *SecureConnection) Read(p []byte) (int, error) { + message := make([]byte, 2048) + // Read the message from the buffer + n, err := s.Conn.Read(message) + + secureMessage := ConstructSecureMessage(message) + decryptedMessage, ok := box.OpenAfterPrecomputation(nil, secureMessage.Msg, &secureMessage.Nonce, s.SharedKey) + + if !ok { + return 0, errors.New("Problem decrypting the message.\n") + } + + // Actually copy it to the destination byte array + n = copy(p, decryptedMessage) + + return n, err +} + +func (s *SecureConnection) Write(p []byte) (int, error) { + var nonce [24]byte + + // Create a new nonce for each message sent + rand.Read(nonce[:]) + + encryptedMessage := box.SealAfterPrecomputation(nil, p, &nonce, s.SharedKey) + sm := SecureMessage{Msg: encryptedMessage, Nonce: nonce} + + // Write it to the connection + return s.Conn.Write(sm.toByteArray()) +} + +func Handshake(conn *net.TCPConn) *[32]byte { + var peerKey, sharedKey [32]byte + + publicKey, privateKey, _ := box.GenerateKey(rand.Reader) + + conn.Write(publicKey[:]) + + peerKeyArray := make([]byte, 32) + conn.Read(peerKeyArray) + copy(peerKey[:], peerKeyArray) + + box.Precompute(&sharedKey, &peerKey, privateKey) + + return &sharedKey +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..5a8ebaf --- /dev/null +++ b/server.go @@ -0,0 +1,51 @@ +package main + +import ( + "fmt" + "net" + "os" + + "github.com/tardisx/netgiv/secure" +) + +type Server struct { + port int +} + +func (s *Server) Run() { + address := fmt.Sprintf("127.0.0.1:%d", s.port) + networkAddress, _ := net.ResolveTCPAddr("tcp", address) + + listener, err := net.ListenTCP("tcp", networkAddress) + if err != nil { + fmt.Print(err) + os.Exit(2) + } + + for { + conn, err := listener.AcceptTCP() + + if err != nil { + fmt.Print(err) + } + + go handleConnection(conn) + } +} + +func handleConnection(conn *net.TCPConn) { + defer conn.Close() + sharedKey := secure.Handshake(conn) + secureConnection := secure.SecureConnection{Conn: conn, SharedKey: sharedKey} + + for { + msg := make([]byte, 1024) + _, err := secureConnection.Read(msg) + + if err != nil { + break + } + + secureConnection.Write(msg) + } +}