From 4c286ae6c16b48f18813d5ed998cfad80a369fcc Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Mon, 8 Oct 2018 21:31:11 -0700 Subject: [PATCH 1/2] Set up to handle Kyber768 KEM --- hkexnet/consts.go | 4 +- hkexnet/hkexnet.go | 230 ++++++++++++++++++++++++++++----------------- hkexsh/hkexsh.go | 2 +- 3 files changed, 147 insertions(+), 89 deletions(-) diff --git a/hkexnet/consts.go b/hkexnet/consts.go index d92499d..cd4e273 100644 --- a/hkexnet/consts.go +++ b/hkexnet/consts.go @@ -9,10 +9,11 @@ package hkexnet const ( KEX_HERRADURA = iota // this MUST be first for default if omitted in ctor - KEX_FOO + KEX_KYBER768 //KEX_DH //KEX_ETC ) + // Sent from client to server in order to specify which // algo shall be used (eg., HerraduraKEx, [TODO: others...]) type KEXAlg uint8 @@ -39,6 +40,7 @@ const ( // Channel status type type CSOType uint32 +//TODO: this should be small (max unfragmented packet size?) const MAX_PAYLOAD_LEN = 4*1024*1024*1024 - 1 const ( diff --git a/hkexnet/hkexnet.go b/hkexnet/hkexnet.go index d72c0fc..545e2b7 100644 --- a/hkexnet/hkexnet.go +++ b/hkexnet/hkexnet.go @@ -69,14 +69,15 @@ type ( szMax uint // max size in bytes } - // Conn is a HKex connection - a superset of net.Conn + //h *hkex.HerraduraKEx // TODO: make an interface? + + // Conn is a connection wrapping net.Conn with KEX & session state Conn struct { - kex KEXAlg - m *sync.Mutex - c net.Conn // which also implements io.Reader, io.Writer, ... - h *hkex.HerraduraKEx // TODO: make an interface? - cipheropts uint32 // post-KEx cipher/hmac options - opts uint32 // post-KEx protocol options (caller-defined) + kex KEXAlg // KEX/KEM propsal (client -> server) + m *sync.Mutex // (internal) + c *net.Conn // which also implements io.Reader, io.Writer, ... + cipheropts uint32 // post-KEx cipher/hmac options + opts uint32 // post-KEx protocol options (caller-defined) WinCh chan WinSize Rows uint16 Cols uint16 @@ -138,6 +139,48 @@ func (hc *Conn) SetOpts(opts uint32) { hc.opts = opts } +func getkexalgnum(extensions ...string) (k KEXAlg) { + for _, s := range extensions { + switch s { + case "KEX_HERRADURA": + default: + log.Println("[extension arg = KEX_HERRADURA]") + k = KEX_HERRADURA + case "KEX_KYBER768": + log.Println("[extension arg = KEX_KYBER768]") + k = KEX_KYBER768 + } + } + return +} + +// Return a new hkexnet.Conn +// +// Note this is internal: use Dial() or Accept() +func _new(kexAlg KEXAlg, conn *net.Conn) (hc *Conn, e error) { + // Set up stuff common to all KEx/KEM types + hc = &Conn{kex: kexAlg, + m: &sync.Mutex{}, + c: conn, + closeStat: new(CSOType), + WinCh: make(chan WinSize, 1), + dBuf: new(bytes.Buffer)} + + *hc.closeStat = CSEStillOpen // open or prematurely-closed status + + // Set up KEx/KEM-specifics + switch hc.kex { + case KEX_HERRADURA: + default: + return hc, HKExAcceptSetup(hc.c, hc) + log.Printf("[KEx alg %d accepted]\n", kexAlg) + case KEX_KYBER768: + fmt.Println("KYBER768: TODO") + return nil, errors.New("KEx Setup failed") + } + return +} + func (hc *Conn) applyConnExtensions(extensions ...string) { //fmt.Printf("CSENone:%d CSEBadAuth:%d CSETruncCSO:%d CSEStillOpen:%d CSEExecFail:%d CSEPtyExecFail:%d\n", // CSENone, CSEBadAuth, CSETruncCSO, CSEStillOpen, CSEExecFail, CSEPtyExecFail) @@ -147,14 +190,6 @@ func (hc *Conn) applyConnExtensions(extensions ...string) { for _, s := range extensions { switch s { - case "KEX_HERRADURA": - log.Println("[extension arg = KEX_HERRADURA]") - hc.kex = KEX_HERRADURA - break - case "KEX_FOO": - log.Println("[extension arg = KEX_FOO]") - hc.kex = KEX_FOO - break case "C_AES_256": log.Println("[extension arg = C_AES_256]") hc.cipheropts &= (0xFFFFFF00) @@ -187,10 +222,15 @@ func (hc *Conn) applyConnExtensions(extensions ...string) { } } +func Kyber768DialSetup(c net.Conn, hc *Conn) (err error) { + return errors.New("NOT IMPLEMENTED") +} + func HKExDialSetup(c net.Conn, hc *Conn) (err error) { + h := hkex.New(0, 0) // Send hkexnet.Conn parameters to remote side // d is value for Herradura key exchange - fmt.Fprintf(c, "0x%s\n%08x:%08x\n", hc.h.D().Text(16), + fmt.Fprintf(c, "0x%s\n%08x:%08x\n", h.D().Text(16), hc.cipheropts, hc.opts) d := big.NewInt(0) @@ -205,44 +245,49 @@ func HKExDialSetup(c net.Conn, hc *Conn) (err error) { return err } - hc.h.SetPeerD(d) - log.Printf("** local D:%s\n", hc.h.D().Text(16)) - log.Printf("**(c)** peer D:%s\n", hc.h.PeerD().Text(16)) - hc.h.ComputeFA() - log.Printf("**(c)** FA:%s\n", hc.h.FA()) + h.SetPeerD(d) + log.Printf("** local D:%s\n", h.D().Text(16)) + log.Printf("**(c)** peer D:%s\n", h.PeerD().Text(16)) + h.ComputeFA() + log.Printf("**(c)** FA:%s\n", h.FA()) - hc.r, hc.rm, err = hc.getStream(hc.h.FA()) - hc.w, hc.wm, err = hc.getStream(hc.h.FA()) + hc.r, hc.rm, err = hc.getStream(h.FA()) + hc.w, hc.wm, err = hc.getStream(h.FA()) return } -func HKExAcceptSetup(c net.Conn, hc *Conn) (err error) { +func Kyber768AcceptSetup(c *net.Conn, hc *Conn) (err error) { + return errors.New("NOT IMPLEMENTED") +} + +func HKExAcceptSetup(c *net.Conn, hc *Conn) (err error) { + h := hkex.New(0, 0) // Read in hkexnet.Conn parameters over raw Conn c // d is value for Herradura key exchange d := big.NewInt(0) - _, err = fmt.Fscanln(c, d) + _, err = fmt.Fscanln(*c, d) log.Printf("[Got d:%v]", d) if err != nil { return err } - _, err = fmt.Fscanf(c, "%08x:%08x\n", + _, err = fmt.Fscanf(*c, "%08x:%08x\n", &hc.cipheropts, &hc.opts) log.Printf("[Got cipheropts, opts:%v, %v]", hc.cipheropts, hc.opts) if err != nil { return err } - hc.h.SetPeerD(d) - log.Printf("** D:%s\n", hc.h.D().Text(16)) - log.Printf("**(s)** peerD:%s\n", hc.h.PeerD().Text(16)) - hc.h.ComputeFA() - log.Printf("**(s)** FA:%s\n", hc.h.FA()) + h.SetPeerD(d) + log.Printf("** D:%s\n", h.D().Text(16)) + log.Printf("**(s)** peerD:%s\n", h.PeerD().Text(16)) + h.ComputeFA() + log.Printf("**(s)** FA:%s\n", h.FA()) // Send D and cipheropts/conn_opts to peer - fmt.Fprintf(c, "0x%s\n%08x:%08x\n", hc.h.D().Text(16), + fmt.Fprintf(*c, "0x%s\n%08x:%08x\n", h.D().Text(16), hc.cipheropts, hc.opts) - hc.r, hc.rm, err = hc.getStream(hc.h.FA()) - hc.w, hc.wm, err = hc.getStream(hc.h.FA()) + hc.r, hc.rm, err = hc.getStream(h.FA()) + hc.w, hc.wm, err = hc.getStream(h.FA()) return } @@ -259,38 +304,38 @@ func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err er // Open raw Conn c c, err := net.Dial(protocol, ipport) if err != nil { - return hc, err + return Conn{}, err } + // Init hkexnet.Conn hc over net.Conn c - // NOTE: kex default of KEX_HERRADURA may be overridden by - // future extension args to applyConnExtensions(), which is - // called prior to Dial() - hc = Conn{m: &sync.Mutex{}, c: c, closeStat: new(CSOType), h: hkex.New(0, 0), dBuf: new(bytes.Buffer)} + ret, err := _new(getkexalgnum(extensions...), &c) + if err != nil { + return Conn{}, err + } + hc = *ret + + // Client has full control over Conn extensions. It's the server's + // responsibility to accept or reject the proposed parameters. hc.applyConnExtensions(extensions...) - // TODO: Factor out ALL params following this to helpers for - // specific KEx algs - fmt.Fprintf(c, "%02x\n", hc.kex) - // -- - - *hc.closeStat = CSEStillOpen // open or prematurely-closed status - // Perform Key Exchange according to client-request algorithm + fmt.Fprintf(c, "%02x\n", hc.kex) switch hc.kex { case KEX_HERRADURA: + fmt.Println("[HKExDialSetup()]") if HKExDialSetup(c, &hc) != nil { - return hc, nil + return Conn{}, nil } - case KEX_FOO: - // For testing: set up as HKEx anyway, but server via Accept() should - // reject as invalid. - //if FooKExDialSetup(c, hc) != nil { - if HKExDialSetup(c, &hc) != nil { - return hc, nil + case KEX_KYBER768: + fmt.Println("[Kyber768DialSetup()]") + if Kyber768DialSetup(c, &hc) != nil { + return Conn{}, nil } default: - log.Printf("Invalid kex alg (%d), rejecting\n", hc.kex) - return hc, errors.New("Invalid kex alg") + fmt.Println("[Default HKExDialSetup()]") + if HKExDialSetup(c, &hc) != nil { + return Conn{}, nil + } } return } @@ -302,19 +347,19 @@ func (hc *Conn) Close() (err error) { binary.BigEndian.PutUint32(s, uint32(*hc.closeStat)) log.Printf("** Writing closeStat %d at Close()\n", *hc.closeStat) hc.WritePacket(s, CSOExitStatus) - err = hc.c.Close() + err = (*hc.c).Close() log.Println("[Conn Closing]") return } // LocalAddr returns the local network address. func (hc *Conn) LocalAddr() net.Addr { - return hc.c.LocalAddr() + return (*hc.c).LocalAddr() } // RemoteAddr returns the remote network address. func (hc *Conn) RemoteAddr() net.Addr { - return hc.c.RemoteAddr() + return (*hc.c).RemoteAddr() } // SetDeadline sets the read and write deadlines associated @@ -333,7 +378,7 @@ func (hc *Conn) RemoteAddr() net.Addr { // // A zero value for t means I/O operations will not time out. func (hc *Conn) SetDeadline(t time.Time) error { - return hc.c.SetDeadline(t) + return (*hc.c).SetDeadline(t) } // SetWriteDeadline sets the deadline for future Write calls @@ -342,14 +387,14 @@ func (hc *Conn) SetDeadline(t time.Time) error { // some of the data was successfully written. // A zero value for t means Write will not time out. func (hc *Conn) SetWriteDeadline(t time.Time) error { - return hc.c.SetWriteDeadline(t) + return (*hc.c).SetWriteDeadline(t) } // SetReadDeadline sets the deadline for future Read calls // and any currently-blocked Read call. // A zero value for t means Read will not time out. func (hc *Conn) SetReadDeadline(t time.Time) error { - return hc.c.SetReadDeadline(t) + return (*hc.c).SetReadDeadline(t) } /*---------------------------------------------------------------------*/ @@ -397,35 +442,46 @@ func (hl *HKExListener) Accept() (hc Conn, err error) { // Open raw Conn c c, err := hl.l.Accept() if err != nil { - hc := Conn{m: &sync.Mutex{}, c: nil, h: nil, closeStat: new(CSOType), cipheropts: 0, opts: 0, - r: nil, w: nil} - return hc, err + return Conn{}, err } - log.Println("[Accepted]") + log.Println("[net.Listener Accepted]") - hc = Conn{ /*kex: from client,*/ m: &sync.Mutex{}, c: c, h: hkex.New(0, 0), closeStat: new(CSOType), WinCh: make(chan WinSize, 1), - dBuf: new(bytes.Buffer)} - - // TODO: Factor out ALL params following this to helpers for - // specific KEx algs - var kexAlg uint8 + // Read KEx alg proposed by client + var kexAlg KEXAlg _, err = fmt.Fscanln(c, &kexAlg) if err != nil { - return hc, err + return Conn{}, err } log.Printf("[Client proposed KEx alg: %v]\n", kexAlg) // -- - switch kexAlg { + ret, err := _new(kexAlg, &c) + if err != nil { + return Conn{}, err + } + hc = *ret + + switch hc.kex { case KEX_HERRADURA: - log.Printf("[KEx alg %d accepted]\n", kexAlg) - if HKExAcceptSetup(c, &hc) != nil { - return hc, nil + log.Println("[Setting up for KEX_HERRADURA]") + if HKExAcceptSetup(&c, &hc) != nil { + log.Println("[ERROR - KEX_HERRADURA]") + return Conn{}, nil + } + case KEX_KYBER768: + log.Println("[Setting up for KEX_KYBER768]") + if Kyber768AcceptSetup(&c, &hc) != nil { + log.Println("[ERROR - KEX_KYBER768]") + return Conn{}, nil } default: - log.Printf("[KEx alg %d rejected]\n", kexAlg) - return hc, errors.New("KEx rejected") + log.Println("[unknown alg, Setting up for KEX_HERRADURA]") + if HKExAcceptSetup(&c, &hc) != nil { + log.Println("[ERROR - default KEX_HERRADURA]") + return Conn{}, nil + } } + log.Println("[hc.Accept successful]") return } @@ -447,7 +503,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { var payloadLen uint32 // Read ctrl/status opcode (CSOHmacInvalid on hmac mismatch) - err = binary.Read(hc.c, binary.BigEndian, &ctrlStatOp) + err = binary.Read(*hc.c, binary.BigEndian, &ctrlStatOp) log.Printf("[ctrlStatOp: %v]\n", ctrlStatOp) if ctrlStatOp == CSOHmacInvalid { // Other side indicated channel tampering, close channel @@ -456,7 +512,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { } // Read the hmac and payload len first - err = binary.Read(hc.c, binary.BigEndian, &hmacIn) + err = binary.Read(*hc.c, binary.BigEndian, &hmacIn) // Normal client 'exit' from interactive session will cause // (on server side) err.Error() == ": use of closed network connection" if err != nil { @@ -468,7 +524,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { return 0, err } - err = binary.Read(hc.c, binary.BigEndian, &payloadLen) + err = binary.Read(*hc.c, binary.BigEndian, &payloadLen) if err != nil { if err.Error() != "EOF" { log.Println("[2]unexpected Read() err:", err) @@ -482,7 +538,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { } var payloadBytes = make([]byte, payloadLen) - n, err = io.ReadFull(hc.c, payloadBytes) + n, err = io.ReadFull(*hc.c, payloadBytes) // Normal client 'exit' from interactive session will cause // (on server side) err.Error() == ": use of closed network connection" @@ -553,7 +609,7 @@ func (hc Conn) Read(b []byte) (n int, err error) { // Log alert if hmac didn't match, corrupted channel if !bytes.Equal(hTmp, []byte(hmacIn[0:])) /*|| hmacIn[0] > 0xf8*/ { fmt.Println("** ALERT - detected HMAC mismatch, possible channel tampering **") - _, _ = hc.c.Write([]byte{CSOHmacInvalid}) + _, _ = (*hc.c).Write([]byte{CSOHmacInvalid}) } } } @@ -642,14 +698,14 @@ func (hc *Conn) WritePacket(b []byte, op byte) (n int, err error) { log.Printf(" ->ctext:\r\n%s\r\n", hex.Dump(wb.Bytes())) ctrlStatOp := op - err = binary.Write(hc.c, binary.BigEndian, &ctrlStatOp) + err = binary.Write(*hc.c, binary.BigEndian, &ctrlStatOp) if err == nil { // Write hmac LSB, payloadLen followed by payload - err = binary.Write(hc.c, binary.BigEndian, hmacOut) + err = binary.Write(*hc.c, binary.BigEndian, hmacOut) if err == nil { - err = binary.Write(hc.c, binary.BigEndian, payloadLen) + err = binary.Write(*hc.c, binary.BigEndian, payloadLen) if err == nil { - n, err = hc.c.Write(wb.Bytes()) + n, err = (*hc.c).Write(wb.Bytes()) } else { //fmt.Println("[c]WriteError!") } diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index 81af203..af1e1c3 100755 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -543,7 +543,7 @@ func main() { } } - conn, err := hkexnet.Dial("tcp", server /*[kexAlg eg. "KEX_HERRADURA"], */, cAlg, hAlg) + conn, err := hkexnet.Dial("tcp", server, "KEX_HERRADURA", cAlg, hAlg) if err != nil { fmt.Println(err) panic(err) From 231ede17347a6994f74b1586ce3a2b063abc24fd Mon Sep 17 00:00:00 2001 From: Russ Magee Date: Wed, 10 Oct 2018 21:12:38 -0700 Subject: [PATCH 2/2] KYBER768 KEM works. :O --- hkexnet/hkexchan.go | 15 +++---- hkexnet/hkexnet.go | 104 +++++++++++++++++++++++++++++++++++++++----- hkexsh/hkexsh.go | 8 ++-- 3 files changed, 105 insertions(+), 22 deletions(-) diff --git a/hkexnet/hkexchan.go b/hkexnet/hkexchan.go index b475562..543e86e 100644 --- a/hkexnet/hkexchan.go +++ b/hkexnet/hkexchan.go @@ -19,7 +19,6 @@ import ( "fmt" "hash" "log" - "math/big" "golang.org/x/crypto/blowfish" "golang.org/x/crypto/twofish" @@ -33,7 +32,7 @@ import ( /* Support functionality to set up encryption after a channel has been negotiated via hkexnet.go */ -func (hc Conn) getStream(keymat *big.Int) (rc cipher.Stream, mc hash.Hash, err error) { +func (hc Conn) getStream(keymat []byte) (rc cipher.Stream, mc hash.Hash, err error) { var key []byte var block cipher.Block var iv []byte @@ -44,23 +43,23 @@ func (hc Conn) getStream(keymat *big.Int) (rc cipher.Stream, mc hash.Hash, err e // is >= 2*cipher.BlockSize (enough for both key and iv) switch copts { case CAlgAES256: - key = keymat.Bytes()[0:aes.BlockSize] + key = keymat[0:aes.BlockSize] block, err = aes.NewCipher(key) ivlen = aes.BlockSize - iv = keymat.Bytes()[aes.BlockSize : aes.BlockSize+ivlen] + iv = keymat[aes.BlockSize : aes.BlockSize+ivlen] rc = cipher.NewOFB(block, iv) log.Printf("[cipher AES_256 (%d)]\n", copts) break case CAlgTwofish128: - key = keymat.Bytes()[0:twofish.BlockSize] + key = keymat[0:twofish.BlockSize] block, err = twofish.NewCipher(key) ivlen = twofish.BlockSize - iv = keymat.Bytes()[twofish.BlockSize : twofish.BlockSize+ivlen] + iv = keymat[twofish.BlockSize : twofish.BlockSize+ivlen] rc = cipher.NewOFB(block, iv) log.Printf("[cipher TWOFISH_128 (%d)]\n", copts) break case CAlgBlowfish64: - key = keymat.Bytes()[0:blowfish.BlockSize] + key = keymat[0:blowfish.BlockSize] block, err = blowfish.NewCipher(key) ivlen = blowfish.BlockSize // N.b. Bounds enforcement of differing cipher algorithms @@ -72,7 +71,7 @@ func (hc Conn) getStream(keymat *big.Int) (rc cipher.Stream, mc hash.Hash, err e // // I assume the other two check bounds and only // copy what's needed whereas blowfish does no such check. - iv = keymat.Bytes()[blowfish.BlockSize : blowfish.BlockSize+ivlen] + iv = keymat[blowfish.BlockSize : blowfish.BlockSize+ivlen] rc = cipher.NewOFB(block, iv) log.Printf("[cipher BLOWFISH_64 (%d)]\n", copts) break diff --git a/hkexnet/hkexnet.go b/hkexnet/hkexnet.go index 545e2b7..12742b2 100644 --- a/hkexnet/hkexnet.go +++ b/hkexnet/hkexnet.go @@ -46,6 +46,7 @@ import ( "time" "blitter.com/go/hkexsh/herradurakex" + kyber "git.schwanenlied.me/yawning/kyber.git" ) /*---------------------------------------------------------------------*/ @@ -171,12 +172,14 @@ func _new(kexAlg KEXAlg, conn *net.Conn) (hc *Conn, e error) { // Set up KEx/KEM-specifics switch hc.kex { case KEX_HERRADURA: - default: - return hc, HKExAcceptSetup(hc.c, hc) + return hc, nil //HKExAcceptSetup(hc.c, hc) log.Printf("[KEx alg %d accepted]\n", kexAlg) case KEX_KYBER768: - fmt.Println("KYBER768: TODO") - return nil, errors.New("KEx Setup failed") + return hc, nil //Kyber768AcceptSetup(hc.c, hc) + log.Printf("[KEx alg %d accepted]\n", kexAlg) + default: + return hc, nil //HKExAcceptSetup(hc.c, hc) + log.Printf("[KEx alg %d accepted]\n", kexAlg) } return } @@ -222,8 +225,53 @@ func (hc *Conn) applyConnExtensions(extensions ...string) { } } +// randReader wraps rand.Read() in a struct that implements io.Reader +// for use by the Kyber KEM methods. +type randReader struct { +} + +func (r randReader) Read(b []byte) (n int, e error) { + n, e = rand.Read(b) + return +} + func Kyber768DialSetup(c net.Conn, hc *Conn) (err error) { - return errors.New("NOT IMPLEMENTED") + //h := hkex.New(0, 0) + // Send hkexnet.Conn parameters to remote side + + // Alice, step 1: Generate a key pair. + r := new(randReader) + alicePublicKey, alicePrivateKey, err := kyber.Kyber768.GenerateKeyPair(r) + if err != nil { + panic(err) + } + + // Alice, step 2: Send the public key to Bob + fmt.Fprintf(c, "0x%x\n%08x:%08x\n", alicePublicKey.Bytes(), + hc.cipheropts, hc.opts) + + // [Bob, step 1-3], from which we read cipher text + b := big.NewInt(0) + _, err = fmt.Fscanln(c, b) + if err != nil { + return err + } + log.Printf("[Got server ciphertext:0x%x]\n", b.Bytes()) + + // Read cipheropts, session opts + _, err = fmt.Fscanf(c, "%08x:%08x\n", + &hc.cipheropts, &hc.opts) + if err != nil { + return err + } + + // Alice, step 3: Decrypt the KEM cipher text. + aliceSharedSecret := alicePrivateKey.KEMDecrypt(b.Bytes()) + + log.Printf("[Derived sharedSecret:0x%x]\n", aliceSharedSecret) + hc.r, hc.rm, err = hc.getStream(aliceSharedSecret) + hc.w, hc.wm, err = hc.getStream(aliceSharedSecret) + return } func HKExDialSetup(c net.Conn, hc *Conn) (err error) { @@ -251,13 +299,47 @@ func HKExDialSetup(c net.Conn, hc *Conn) (err error) { h.ComputeFA() log.Printf("**(c)** FA:%s\n", h.FA()) - hc.r, hc.rm, err = hc.getStream(h.FA()) - hc.w, hc.wm, err = hc.getStream(h.FA()) + hc.r, hc.rm, err = hc.getStream(h.FA().Bytes()) + hc.w, hc.wm, err = hc.getStream(h.FA().Bytes()) return } func Kyber768AcceptSetup(c *net.Conn, hc *Conn) (err error) { - return errors.New("NOT IMPLEMENTED") + //h := hkex.New(0, 0) + // Bob, step 1: Deserialize Alice's public key from the binary encoding. + alicePublicKey := big.NewInt(0) + _, err = fmt.Fscanln(*c, alicePublicKey) + log.Printf("[Got client pubKey:0x%x\n]", alicePublicKey) + if err != nil { + return err + } + _, err = fmt.Fscanf(*c, "%08x:%08x\n", + &hc.cipheropts, &hc.opts) + log.Printf("[Got cipheropts, opts:%v, %v]", hc.cipheropts, hc.opts) + if err != nil { + return err + } + + peerPublicKey, err := kyber.Kyber768.PublicKeyFromBytes(alicePublicKey.Bytes()) + if err != nil { + panic(err) + } + + // Bob, step 2: Generate the KEM cipher text and shared secret. + r := new(randReader) + cipherText, bobSharedSecret, err := peerPublicKey.KEMEncrypt(r) + if err != nil { + panic(err) + } + + // Bob, step 3: Send the cipher text to Alice (Not shown). + fmt.Fprintf(*c, "0x%x\n%08x:%08x\n", cipherText, + hc.cipheropts, hc.opts) + + log.Printf("[Derived sharedSecret:0x%x]\n", bobSharedSecret) + hc.r, hc.rm, err = hc.getStream(bobSharedSecret) + hc.w, hc.wm, err = hc.getStream(bobSharedSecret) + return } func HKExAcceptSetup(c *net.Conn, hc *Conn) (err error) { @@ -286,8 +368,8 @@ func HKExAcceptSetup(c *net.Conn, hc *Conn) (err error) { fmt.Fprintf(*c, "0x%s\n%08x:%08x\n", h.D().Text(16), hc.cipheropts, hc.opts) - hc.r, hc.rm, err = hc.getStream(h.FA()) - hc.w, hc.wm, err = hc.getStream(h.FA()) + hc.r, hc.rm, err = hc.getStream(h.FA().Bytes()) + hc.w, hc.wm, err = hc.getStream(h.FA().Bytes()) return } @@ -306,7 +388,7 @@ func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err er if err != nil { return Conn{}, err } - + // Init hkexnet.Conn hc over net.Conn c ret, err := _new(getkexalgnum(extensions...), &c) if err != nil { diff --git a/hkexsh/hkexsh.go b/hkexsh/hkexsh.go index af1e1c3..173a097 100755 --- a/hkexsh/hkexsh.go +++ b/hkexsh/hkexsh.go @@ -351,8 +351,9 @@ func main() { var gopt bool //login via password, asking server to generate authToken var dbg bool var shellMode bool // if true act as shell, else file copier - var cAlg string - var hAlg string + var cAlg string //cipher alg + var hAlg string //hmac alg + var kAlg string //KEX/KEM alg var server string var port uint var cmdStr string @@ -373,6 +374,7 @@ func main() { flag.BoolVar(&dbg, "d", false, "debug logging") flag.StringVar(&cAlg, "c", "C_AES_256", "`cipher` [\"C_AES_256\" | \"C_TWOFISH_128\" | \"C_BLOWFISH_64\"]") flag.StringVar(&hAlg, "m", "H_SHA256", "`hmac` [\"H_SHA256\"]") + flag.StringVar(&kAlg, "k", "KEX_HERRADURA", "`kex` [\"KEX_HERRADURA\" | \"KEX_KYBER768\"]") flag.UintVar(&port, "p", 2000, "`port`") //flag.StringVar(&authCookie, "a", "", "auth cookie") flag.BoolVar(&chaffEnabled, "e", true, "enabled chaff pkts (default true)") @@ -543,7 +545,7 @@ func main() { } } - conn, err := hkexnet.Dial("tcp", server, "KEX_HERRADURA", cAlg, hAlg) + conn, err := hkexnet.Dial("tcp", server, cAlg, hAlg, kAlg) if err != nil { fmt.Println(err) panic(err)