From 942b8865cff26cc1c734112205dd25951774fc61 Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Sat, 13 Jan 2018 10:01:27 -0800 Subject: [PATCH] Start of proto kexsh tool client/server --- demo/client/client.go | 15 ++++++++++---- demo/dbgclient/client.go | 6 +----- demo/server/server.go | 14 ++++++++++++- hkexchan.go | 31 +++++++++++------------------ hkexnet.go | 43 ++++++++++++++++++++++++++++++---------- 5 files changed, 69 insertions(+), 40 deletions(-) diff --git a/demo/client/client.go b/demo/client/client.go index f8fc796..ffbc7a1 100644 --- a/demo/client/client.go +++ b/demo/client/client.go @@ -11,10 +11,16 @@ import ( // Demo of a simple client that dials up to a simple test server to // send data. -// Note this code is identical to standard tcp client code, save for -// declaring a 'hkex' rather than a 'net' Dialer Conn. The KEx and -// encrypt/decrypt is done within the type. -// Compare to 'clientp.go' in this directory to see the equivalence. +// +// While conforming to the basic net.Conn interface HKex.Conn has extra +// capabilities designed to allow apps to define connection options, +// encryption/hmac settings and operations across the encrypted channel. +// +// Initial setup is the same as using plain net.Dial(), but one may +// specify extra extension tags (strings) to set the cipher and hmac +// setting desired; as well as the intended operation mode for the +// connection (app-specific, passed through to the server to use or +// ignore at its discretion). func main() { var cAlg string var hAlg string @@ -30,6 +36,7 @@ func main() { fmt.Println("Err!") panic(err) } + fmt.Fprintf(conn,"e") // tell server just to echo _, err = io.Copy(conn, os.Stdin) if err != nil && err.Error() != "EOF" { fmt.Println(err) diff --git a/demo/dbgclient/client.go b/demo/dbgclient/client.go index f8fc796..93d85c6 100644 --- a/demo/dbgclient/client.go +++ b/demo/dbgclient/client.go @@ -16,16 +16,12 @@ import ( // encrypt/decrypt is done within the type. // Compare to 'clientp.go' in this directory to see the equivalence. func main() { - var cAlg string - var hAlg string var server string - flag.StringVar(&cAlg, "c", "C_AES_256", "cipher [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\"]") - flag.StringVar(&hAlg, "h", "H_SHA256", "hmac [\"H_SHA256\"]") flag.StringVar(&server, "s", "localhost:2000", "server hostname/address[:port]") flag.Parse() - conn, err := hkex.Dial("tcp", server, cAlg, hAlg) + conn, err := hkex.Dial("tcp", server) if err != nil { fmt.Println("Err!") panic(err) diff --git a/demo/server/server.go b/demo/server/server.go index 295d8cb..7f2687f 100644 --- a/demo/server/server.go +++ b/demo/server/server.go @@ -45,6 +45,7 @@ func main() { ch := make(chan []byte) chN := 0 eCh := make(chan error) + var connOp *byte = nil // Start a goroutine to read from our net connection go func(ch chan []byte, eCh chan error) { @@ -57,12 +58,23 @@ func main() { eCh <- err return } + if connOp == nil { + // Initial xmit - get op byte + // (TODO: determine valid ops + // for now 'e' (echo), 'i' (interactive), 'x' (exec), ... ?) + connOp = new(byte) + *connOp = data[0] + data = data[1:] + chN -= 1 + fmt.Printf("[* connOp '%c']\n", *connOp) + } + // send data if we read some. ch <- data[0:chN] } }(ch, eCh) - ticker := time.Tick(time.Second/100) + ticker := time.Tick(time.Second / 100) Term: // continuously read from the connection for { diff --git a/hkexchan.go b/hkexchan.go index 7faa296..cdc096c 100644 --- a/hkexchan.go +++ b/hkexchan.go @@ -1,25 +1,8 @@ -/* Herradura - a Key exchange scheme in the style of Diffie-Hellman Key Exchange. - Copyright (C) 2017 Omar Alejandro Herrera Reyna - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - - golang implementation by Russ Magee (rmagee_at_gmail.com) */ - package herradurakex /* Support functions to set up encryption once an HKEx Conn has been -established with FA exchange */ +established with FA exchange and support channel operations +(echo, file-copy, remote-cmd, ...) */ import ( "crypto/aes" @@ -46,6 +29,16 @@ const ( HmacNoneDisallowed ) +type ChanOp uint8 + +const ( + ChanOpNop = '.' + ChanOpEcho = 'e' // For testing - echo client data to stderr + //ChanOpFileWrite = "w" + //ChanOpFileRead = "r" + //ChanOpRemoteCmd = "x" +) + /*TODO: HMAC derived from HKEx FA.*/ /* Support functionality to set up encryption after a channel has been negotiated via hkexnet.go diff --git a/hkexnet.go b/hkexnet.go index a37092e..ed32a0e 100644 --- a/hkexnet.go +++ b/hkexnet.go @@ -36,7 +36,8 @@ type Conn struct { c net.Conn // which also implements io.Reader, io.Writer, ... h *HerraduraKEx cipheropts uint32 // post-KEx cipher/hmac options - opts uint32 // post-KEx protocol options + opts uint32 // post-KEx protocol options (caller-defined) + op uint8 // post-KEx 'op' (caller-defined) r cipher.Stream w cipher.Stream } @@ -78,6 +79,26 @@ func (c *Conn) SetOpts(opts uint32) { c.opts = opts } +// Op returns the 'op' value, which is sent to the peer +// but is not itself part of the KEx or connection (cipher/hmac) setup. +// +// Consumers of this lib may use this to indicate connection-specific +// operations not part of the KEx or encryption info used by the connection. +func (c *Conn) Op() uint8 { + return c.op +} + +// SetOp sets the 'op' value, which is sent to the peer +// but is not itself part of the KEx or connection (cipher/hmac) setup. +// +// Consumers of this lib may use this to indicate connection-specific +// operations not part of the KEx or encryption info used by the connection. +// +// op - a uint8, caller-defined +func (c *Conn) SetOp(op uint8) { + c.op = op +} + func (c *Conn) applyConnExtensions(extensions ...string) { for _, s := range extensions { switch s { @@ -120,20 +141,20 @@ func Dial(protocol string, ipport string, extensions ...string) (hc *Conn, err e if err != nil { return nil, err } - hc = &Conn{c: c, h: New(0, 0), cipheropts: 0, opts: 0, r: nil, w: nil} + hc = &Conn{c: c, h: New(0, 0), cipheropts: 0, opts: 0, op:0, r: nil, w: nil} hc.applyConnExtensions(extensions...) - fmt.Fprintf(c, "0x%s\n%08x:%08x\n", hc.h.d.Text(16), - hc.cipheropts, hc.opts) + fmt.Fprintf(c, "0x%s\n%08x:%08x:%02x\n", hc.h.d.Text(16), + hc.cipheropts, hc.opts, hc.op) d := big.NewInt(0) _, err = fmt.Fscanln(c, d) if err != nil { return nil, err } - _, err = fmt.Fscanf(c, "%08x:%08x\n", - &hc.cipheropts, &hc.opts) + _, err = fmt.Fscanf(c, "%08x:%08x:%02x\n", + &hc.cipheropts, &hc.opts, &hc.op) if err != nil { return nil, err } @@ -197,15 +218,15 @@ func (hl *HKExListener) Accept() (hc Conn, err error) { } fmt.Println("[Accepted]") - hc = Conn{c: c, h: New(0, 0), cipheropts: 0, opts: 0, r: nil, w: nil} + hc = Conn{c: c, h: New(0, 0), cipheropts: 0, opts: 0, op:0, r: nil, w: nil} d := big.NewInt(0) _, err = fmt.Fscanln(c, d) if err != nil { return hc, err } - _, err = fmt.Fscanf(c, "%08x:%08x\n", - &hc.cipheropts, &hc.opts) + _, err = fmt.Fscanf(c, "%08x:%08x:%02x\n", + &hc.cipheropts, &hc.opts, &hc.op) if err != nil { return hc, err } @@ -215,8 +236,8 @@ func (hl *HKExListener) Accept() (hc Conn, err error) { hc.h.FA() fmt.Printf("**(s)** FA:%s\n", hc.h.fa) - fmt.Fprintf(c, "0x%s\n%08x:%08x\n", hc.h.d.Text(16), - hc.cipheropts, hc.opts) + fmt.Fprintf(c, "0x%s\n%08x:%08x:%02x\n", hc.h.d.Text(16), + hc.cipheropts, hc.opts, hc.op) hc.r = hc.getStream(hc.h.fa) hc.w = hc.getStream(hc.h.fa)