From a1f4e0342adc0466a6770f512671c1e42ef8a5df Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Sun, 6 May 2018 17:41:09 -0700 Subject: [PATCH] Added chaff cmdline options to client & server --- hkexnet.go | 43 +++++++++++++++++++++++++------------------ hkexsh/hkexsh.go | 10 +++++++++- hkexshd/hkexshd.go | 16 +++++++++++----- 3 files changed, 45 insertions(+), 24 deletions(-) diff --git a/hkexnet.go b/hkexnet.go index e22aec1..e62ae7c 100644 --- a/hkexnet.go +++ b/hkexnet.go @@ -44,6 +44,13 @@ type WinSize struct { Cols uint16 } +type ChaffConfig struct { + enabled bool + msecsMin uint //msecs min interval + msecsMax uint //msecs max interval + szMax uint // max size in bytes +} + // Conn is a HKex connection - a drop-in replacement for net.Conn type Conn struct { m *sync.Mutex @@ -55,9 +62,7 @@ type Conn struct { Rows uint16 Cols uint16 - chaff bool - chaffMsecsMin int //msecs min interval - chaffMsecsMax int //msecs max interval + chaff ChaffConfig r cipher.Stream //read cipherStream rm hash.Hash @@ -498,30 +503,32 @@ func (c Conn) WritePacket(b []byte, op byte) (n int, err error) { return } -func (c *Conn) Chaff(enable bool, msecsMin int, msecsMax int, szMax int) { - c.chaff = enable - c.chaffMsecsMin = msecsMin //move these to params of chaffHelper() ? - c.chaffMsecsMax = msecsMax +func (c *Conn) EnableChaff() { + c.chaff.enabled = true + log.Println("Chaffing ENABLED") + c.chaffHelper() +} - if enable { - log.Println("Chaffing ENABLED") - c.chaffHelper(szMax) - } +func (c *Conn) Chaff(msecsMin uint, msecsMax uint, szMax uint) { + c.chaff.msecsMin = msecsMin //move these to params of chaffHelper() ? + c.chaff.msecsMax = msecsMax + c.chaff.szMax = szMax } // Helper routine to spawn a chaffing goroutine for each Conn -func (c *Conn) chaffHelper(szMax int) { +func (c *Conn) chaffHelper() { go func() { for { var nextDuration int - if c.chaff { - chaff := make([]byte, rand.Intn(szMax)) - min := c.chaffMsecsMin - nextDuration = rand.Intn(c.chaffMsecsMax-min) + min - _, _ = rand.Read(chaff) - _, err := c.WritePacket(chaff, CSOChaff) + if c.chaff.enabled { + bufTmp := make([]byte, rand.Intn(int(c.chaff.szMax))) + min := int(c.chaff.msecsMin) + nextDuration = rand.Intn(int(c.chaff.msecsMax)-min) + min + _, _ = rand.Read(bufTmp) + _, err := c.WritePacket(bufTmp, CSOChaff) if err != nil { log.Println("[ *** error - chaffHelper quitting *** ]") + c.chaff.enabled = false break } } diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index b0644ac..bf917f4 100644 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -73,6 +73,10 @@ func main() { var cmdStr string var altUser string var authCookie string + var chaffFreqMin uint + var chaffFreqMax uint + var chaffBytesMax uint + isInteractive := false flag.StringVar(&cAlg, "c", "C_AES_256", "cipher [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\"]") @@ -81,6 +85,9 @@ func main() { flag.StringVar(&cmdStr, "x", "", "command to run (default empty - interactive shell)") flag.StringVar(&altUser, "u", "", "specify alternate user") flag.StringVar(&authCookie, "a", "", "auth cookie") + flag.UintVar(&chaffFreqMin, "cfm", 100, "chaff pkt freq min (msecs)") + flag.UintVar(&chaffFreqMax, "cfM", 5000, "chaff pkt freq max (msecs)") + flag.UintVar(&chaffBytesMax, "cbM", 64, "chaff pkt size max (bytes)") flag.BoolVar(&dbg, "d", false, "debug logging") flag.Parse() @@ -228,7 +235,8 @@ func main() { // Copy() expects EOF so this will // exit with outerr == nil //!_, outerr := io.Copy(conn, os.Stdin) - conn.Chaff(true, 100, 500, 32) // enable client->server chaffing + conn.Chaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // enable client->server chaffing + conn.EnableChaff() _, outerr := func(conn *hkexsh.Conn, r io.Reader) (w int64, e error) { return io.Copy(conn, r) }(conn, os.Stdin) diff --git a/hkexshd/hkexshd.go b/hkexshd/hkexshd.go index 8882510..369a121 100644 --- a/hkexshd/hkexshd.go +++ b/hkexshd/hkexshd.go @@ -134,12 +134,9 @@ func runShellAs(who string, cmd string, interactive bool, conn hkexsh.Conn) (err _, _ = io.Copy(ptmx, conn) }() + conn.EnableChaff() + // ..and the pty to stdout. - // --(FIXME: server->client chaffing can't work here as-is, since we - // --pty.Start()ed the command above, and that command has no - // --knowledge of another thread which would do chaffing. - // --Modify pty somehow to slave the command through hkexsh.Copy() ? - conn.Chaff(true, 100, 500, 32) _, _ = io.Copy(conn, ptmx) //err = c.Run() // returns when c finishes. @@ -161,10 +158,16 @@ func rejectUserMsg() string { // Listener and Conns. The KEx and encrypt/decrypt is done within the type. // Compare to 'serverp.go' in this directory to see the equivalence. func main() { + var chaffFreqMin uint + var chaffFreqMax uint + var chaffBytesMax uint var dbg bool var laddr string flag.StringVar(&laddr, "l", ":2000", "interface[:port] to listen") + flag.UintVar(&chaffFreqMin, "cfm", 100, "chaff pkt freq min (msecs)") + flag.UintVar(&chaffFreqMax, "cfM", 5000, "chaff pkt freq max (msecs)") + flag.UintVar(&chaffBytesMax, "cbM", 64, "chaff pkt size max (bytes)") flag.BoolVar(&dbg, "d", false, "debug logging") flag.Parse() @@ -193,6 +196,9 @@ func main() { } else { log.Println("Accepted client") + // Set up chaffing to client + conn.Chaff(chaffFreqMin, chaffFreqMax, chaffBytesMax) // enable client->server chaffing + // Handle the connection in a new goroutine. // The loop then returns to accepting, so that // multiple connections may be served concurrently.