mirror of https://gogs.blitter.com/RLabs/xs
Merge branch 'add-kex-kyber768'
This commit is contained in:
commit
fad35aa4fa
|
@ -9,10 +9,11 @@ package hkexnet
|
||||||
|
|
||||||
const (
|
const (
|
||||||
KEX_HERRADURA = iota // this MUST be first for default if omitted in ctor
|
KEX_HERRADURA = iota // this MUST be first for default if omitted in ctor
|
||||||
KEX_FOO
|
KEX_KYBER768
|
||||||
//KEX_DH
|
//KEX_DH
|
||||||
//KEX_ETC
|
//KEX_ETC
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sent from client to server in order to specify which
|
// Sent from client to server in order to specify which
|
||||||
// algo shall be used (eg., HerraduraKEx, [TODO: others...])
|
// algo shall be used (eg., HerraduraKEx, [TODO: others...])
|
||||||
type KEXAlg uint8
|
type KEXAlg uint8
|
||||||
|
@ -39,6 +40,7 @@ const (
|
||||||
// Channel status type
|
// Channel status type
|
||||||
type CSOType uint32
|
type CSOType uint32
|
||||||
|
|
||||||
|
//TODO: this should be small (max unfragmented packet size?)
|
||||||
const MAX_PAYLOAD_LEN = 4*1024*1024*1024 - 1
|
const MAX_PAYLOAD_LEN = 4*1024*1024*1024 - 1
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -19,7 +19,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash"
|
"hash"
|
||||||
"log"
|
"log"
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"golang.org/x/crypto/blowfish"
|
"golang.org/x/crypto/blowfish"
|
||||||
"golang.org/x/crypto/twofish"
|
"golang.org/x/crypto/twofish"
|
||||||
|
@ -33,7 +32,7 @@ import (
|
||||||
/* Support functionality to set up encryption after a channel has
|
/* Support functionality to set up encryption after a channel has
|
||||||
been negotiated via hkexnet.go
|
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 key []byte
|
||||||
var block cipher.Block
|
var block cipher.Block
|
||||||
var iv []byte
|
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)
|
// is >= 2*cipher.BlockSize (enough for both key and iv)
|
||||||
switch copts {
|
switch copts {
|
||||||
case CAlgAES256:
|
case CAlgAES256:
|
||||||
key = keymat.Bytes()[0:aes.BlockSize]
|
key = keymat[0:aes.BlockSize]
|
||||||
block, err = aes.NewCipher(key)
|
block, err = aes.NewCipher(key)
|
||||||
ivlen = aes.BlockSize
|
ivlen = aes.BlockSize
|
||||||
iv = keymat.Bytes()[aes.BlockSize : aes.BlockSize+ivlen]
|
iv = keymat[aes.BlockSize : aes.BlockSize+ivlen]
|
||||||
rc = cipher.NewOFB(block, iv)
|
rc = cipher.NewOFB(block, iv)
|
||||||
log.Printf("[cipher AES_256 (%d)]\n", copts)
|
log.Printf("[cipher AES_256 (%d)]\n", copts)
|
||||||
break
|
break
|
||||||
case CAlgTwofish128:
|
case CAlgTwofish128:
|
||||||
key = keymat.Bytes()[0:twofish.BlockSize]
|
key = keymat[0:twofish.BlockSize]
|
||||||
block, err = twofish.NewCipher(key)
|
block, err = twofish.NewCipher(key)
|
||||||
ivlen = twofish.BlockSize
|
ivlen = twofish.BlockSize
|
||||||
iv = keymat.Bytes()[twofish.BlockSize : twofish.BlockSize+ivlen]
|
iv = keymat[twofish.BlockSize : twofish.BlockSize+ivlen]
|
||||||
rc = cipher.NewOFB(block, iv)
|
rc = cipher.NewOFB(block, iv)
|
||||||
log.Printf("[cipher TWOFISH_128 (%d)]\n", copts)
|
log.Printf("[cipher TWOFISH_128 (%d)]\n", copts)
|
||||||
break
|
break
|
||||||
case CAlgBlowfish64:
|
case CAlgBlowfish64:
|
||||||
key = keymat.Bytes()[0:blowfish.BlockSize]
|
key = keymat[0:blowfish.BlockSize]
|
||||||
block, err = blowfish.NewCipher(key)
|
block, err = blowfish.NewCipher(key)
|
||||||
ivlen = blowfish.BlockSize
|
ivlen = blowfish.BlockSize
|
||||||
// N.b. Bounds enforcement of differing cipher algorithms
|
// 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
|
// I assume the other two check bounds and only
|
||||||
// copy what's needed whereas blowfish does no such check.
|
// 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)
|
rc = cipher.NewOFB(block, iv)
|
||||||
log.Printf("[cipher BLOWFISH_64 (%d)]\n", copts)
|
log.Printf("[cipher BLOWFISH_64 (%d)]\n", copts)
|
||||||
break
|
break
|
||||||
|
|
|
@ -46,6 +46,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"blitter.com/go/hkexsh/herradurakex"
|
"blitter.com/go/hkexsh/herradurakex"
|
||||||
|
kyber "git.schwanenlied.me/yawning/kyber.git"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
|
@ -69,14 +70,15 @@ type (
|
||||||
szMax uint // max size in bytes
|
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 {
|
Conn struct {
|
||||||
kex KEXAlg
|
kex KEXAlg // KEX/KEM propsal (client -> server)
|
||||||
m *sync.Mutex
|
m *sync.Mutex // (internal)
|
||||||
c net.Conn // which also implements io.Reader, io.Writer, ...
|
c *net.Conn // which also implements io.Reader, io.Writer, ...
|
||||||
h *hkex.HerraduraKEx // TODO: make an interface?
|
cipheropts uint32 // post-KEx cipher/hmac options
|
||||||
cipheropts uint32 // post-KEx cipher/hmac options
|
opts uint32 // post-KEx protocol options (caller-defined)
|
||||||
opts uint32 // post-KEx protocol options (caller-defined)
|
|
||||||
WinCh chan WinSize
|
WinCh chan WinSize
|
||||||
Rows uint16
|
Rows uint16
|
||||||
Cols uint16
|
Cols uint16
|
||||||
|
@ -138,6 +140,50 @@ func (hc *Conn) SetOpts(opts uint32) {
|
||||||
hc.opts = opts
|
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:
|
||||||
|
return hc, nil //HKExAcceptSetup(hc.c, hc)
|
||||||
|
log.Printf("[KEx alg %d accepted]\n", kexAlg)
|
||||||
|
case KEX_KYBER768:
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
func (hc *Conn) applyConnExtensions(extensions ...string) {
|
func (hc *Conn) applyConnExtensions(extensions ...string) {
|
||||||
//fmt.Printf("CSENone:%d CSEBadAuth:%d CSETruncCSO:%d CSEStillOpen:%d CSEExecFail:%d CSEPtyExecFail:%d\n",
|
//fmt.Printf("CSENone:%d CSEBadAuth:%d CSETruncCSO:%d CSEStillOpen:%d CSEExecFail:%d CSEPtyExecFail:%d\n",
|
||||||
// CSENone, CSEBadAuth, CSETruncCSO, CSEStillOpen, CSEExecFail, CSEPtyExecFail)
|
// CSENone, CSEBadAuth, CSETruncCSO, CSEStillOpen, CSEExecFail, CSEPtyExecFail)
|
||||||
|
@ -147,14 +193,6 @@ func (hc *Conn) applyConnExtensions(extensions ...string) {
|
||||||
|
|
||||||
for _, s := range extensions {
|
for _, s := range extensions {
|
||||||
switch s {
|
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":
|
case "C_AES_256":
|
||||||
log.Println("[extension arg = C_AES_256]")
|
log.Println("[extension arg = C_AES_256]")
|
||||||
hc.cipheropts &= (0xFFFFFF00)
|
hc.cipheropts &= (0xFFFFFF00)
|
||||||
|
@ -187,10 +225,60 @@ 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) {
|
||||||
|
//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) {
|
func HKExDialSetup(c net.Conn, hc *Conn) (err error) {
|
||||||
|
h := hkex.New(0, 0)
|
||||||
// Send hkexnet.Conn parameters to remote side
|
// Send hkexnet.Conn parameters to remote side
|
||||||
// d is value for Herradura key exchange
|
// 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)
|
hc.cipheropts, hc.opts)
|
||||||
|
|
||||||
d := big.NewInt(0)
|
d := big.NewInt(0)
|
||||||
|
@ -205,44 +293,83 @@ func HKExDialSetup(c net.Conn, hc *Conn) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
hc.h.SetPeerD(d)
|
h.SetPeerD(d)
|
||||||
log.Printf("** local D:%s\n", hc.h.D().Text(16))
|
log.Printf("** local D:%s\n", h.D().Text(16))
|
||||||
log.Printf("**(c)** peer D:%s\n", hc.h.PeerD().Text(16))
|
log.Printf("**(c)** peer D:%s\n", h.PeerD().Text(16))
|
||||||
hc.h.ComputeFA()
|
h.ComputeFA()
|
||||||
log.Printf("**(c)** FA:%s\n", hc.h.FA())
|
log.Printf("**(c)** FA:%s\n", h.FA())
|
||||||
|
|
||||||
hc.r, hc.rm, err = hc.getStream(hc.h.FA())
|
hc.r, hc.rm, err = hc.getStream(h.FA().Bytes())
|
||||||
hc.w, hc.wm, err = hc.getStream(hc.h.FA())
|
hc.w, hc.wm, err = hc.getStream(h.FA().Bytes())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func HKExAcceptSetup(c net.Conn, hc *Conn) (err error) {
|
func Kyber768AcceptSetup(c *net.Conn, hc *Conn) (err error) {
|
||||||
// Read in hkexnet.Conn parameters over raw Conn c
|
//h := hkex.New(0, 0)
|
||||||
// d is value for Herradura key exchange
|
// Bob, step 1: Deserialize Alice's public key from the binary encoding.
|
||||||
d := big.NewInt(0)
|
alicePublicKey := big.NewInt(0)
|
||||||
_, err = fmt.Fscanln(c, d)
|
_, err = fmt.Fscanln(*c, alicePublicKey)
|
||||||
log.Printf("[Got d:%v]", d)
|
log.Printf("[Got client pubKey:0x%x\n]", alicePublicKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = fmt.Fscanf(c, "%08x:%08x\n",
|
_, err = fmt.Fscanf(*c, "%08x:%08x\n",
|
||||||
&hc.cipheropts, &hc.opts)
|
&hc.cipheropts, &hc.opts)
|
||||||
log.Printf("[Got cipheropts, opts:%v, %v]", hc.cipheropts, hc.opts)
|
log.Printf("[Got cipheropts, opts:%v, %v]", hc.cipheropts, hc.opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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())
|
|
||||||
|
|
||||||
// Send D and cipheropts/conn_opts to peer
|
peerPublicKey, err := kyber.Kyber768.PublicKeyFromBytes(alicePublicKey.Bytes())
|
||||||
fmt.Fprintf(c, "0x%s\n%08x:%08x\n", hc.h.D().Text(16),
|
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)
|
hc.cipheropts, hc.opts)
|
||||||
|
|
||||||
hc.r, hc.rm, err = hc.getStream(hc.h.FA())
|
log.Printf("[Derived sharedSecret:0x%x]\n", bobSharedSecret)
|
||||||
hc.w, hc.wm, err = hc.getStream(hc.h.FA())
|
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) {
|
||||||
|
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)
|
||||||
|
log.Printf("[Got d:%v]", d)
|
||||||
|
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
|
||||||
|
}
|
||||||
|
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", h.D().Text(16),
|
||||||
|
hc.cipheropts, hc.opts)
|
||||||
|
|
||||||
|
hc.r, hc.rm, err = hc.getStream(h.FA().Bytes())
|
||||||
|
hc.w, hc.wm, err = hc.getStream(h.FA().Bytes())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,38 +386,38 @@ func Dial(protocol string, ipport string, extensions ...string) (hc Conn, err er
|
||||||
// Open raw Conn c
|
// Open raw Conn c
|
||||||
c, err := net.Dial(protocol, ipport)
|
c, err := net.Dial(protocol, ipport)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hc, err
|
return Conn{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init hkexnet.Conn hc over net.Conn c
|
// Init hkexnet.Conn hc over net.Conn c
|
||||||
// NOTE: kex default of KEX_HERRADURA may be overridden by
|
ret, err := _new(getkexalgnum(extensions...), &c)
|
||||||
// future extension args to applyConnExtensions(), which is
|
if err != nil {
|
||||||
// called prior to Dial()
|
return Conn{}, err
|
||||||
hc = Conn{m: &sync.Mutex{}, c: c, closeStat: new(CSOType), h: hkex.New(0, 0), dBuf: new(bytes.Buffer)}
|
}
|
||||||
|
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...)
|
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
|
// Perform Key Exchange according to client-request algorithm
|
||||||
|
fmt.Fprintf(c, "%02x\n", hc.kex)
|
||||||
switch hc.kex {
|
switch hc.kex {
|
||||||
case KEX_HERRADURA:
|
case KEX_HERRADURA:
|
||||||
|
fmt.Println("[HKExDialSetup()]")
|
||||||
if HKExDialSetup(c, &hc) != nil {
|
if HKExDialSetup(c, &hc) != nil {
|
||||||
return hc, nil
|
return Conn{}, nil
|
||||||
}
|
}
|
||||||
case KEX_FOO:
|
case KEX_KYBER768:
|
||||||
// For testing: set up as HKEx anyway, but server via Accept() should
|
fmt.Println("[Kyber768DialSetup()]")
|
||||||
// reject as invalid.
|
if Kyber768DialSetup(c, &hc) != nil {
|
||||||
//if FooKExDialSetup(c, hc) != nil {
|
return Conn{}, nil
|
||||||
if HKExDialSetup(c, &hc) != nil {
|
|
||||||
return hc, nil
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
log.Printf("Invalid kex alg (%d), rejecting\n", hc.kex)
|
fmt.Println("[Default HKExDialSetup()]")
|
||||||
return hc, errors.New("Invalid kex alg")
|
if HKExDialSetup(c, &hc) != nil {
|
||||||
|
return Conn{}, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -302,19 +429,19 @@ func (hc *Conn) Close() (err error) {
|
||||||
binary.BigEndian.PutUint32(s, uint32(*hc.closeStat))
|
binary.BigEndian.PutUint32(s, uint32(*hc.closeStat))
|
||||||
log.Printf("** Writing closeStat %d at Close()\n", *hc.closeStat)
|
log.Printf("** Writing closeStat %d at Close()\n", *hc.closeStat)
|
||||||
hc.WritePacket(s, CSOExitStatus)
|
hc.WritePacket(s, CSOExitStatus)
|
||||||
err = hc.c.Close()
|
err = (*hc.c).Close()
|
||||||
log.Println("[Conn Closing]")
|
log.Println("[Conn Closing]")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// LocalAddr returns the local network address.
|
// LocalAddr returns the local network address.
|
||||||
func (hc *Conn) LocalAddr() net.Addr {
|
func (hc *Conn) LocalAddr() net.Addr {
|
||||||
return hc.c.LocalAddr()
|
return (*hc.c).LocalAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoteAddr returns the remote network address.
|
// RemoteAddr returns the remote network address.
|
||||||
func (hc *Conn) RemoteAddr() net.Addr {
|
func (hc *Conn) RemoteAddr() net.Addr {
|
||||||
return hc.c.RemoteAddr()
|
return (*hc.c).RemoteAddr()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetDeadline sets the read and write deadlines associated
|
// SetDeadline sets the read and write deadlines associated
|
||||||
|
@ -333,7 +460,7 @@ func (hc *Conn) RemoteAddr() net.Addr {
|
||||||
//
|
//
|
||||||
// A zero value for t means I/O operations will not time out.
|
// A zero value for t means I/O operations will not time out.
|
||||||
func (hc *Conn) SetDeadline(t time.Time) error {
|
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
|
// SetWriteDeadline sets the deadline for future Write calls
|
||||||
|
@ -342,14 +469,14 @@ func (hc *Conn) SetDeadline(t time.Time) error {
|
||||||
// some of the data was successfully written.
|
// some of the data was successfully written.
|
||||||
// A zero value for t means Write will not time out.
|
// A zero value for t means Write will not time out.
|
||||||
func (hc *Conn) SetWriteDeadline(t time.Time) error {
|
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
|
// SetReadDeadline sets the deadline for future Read calls
|
||||||
// and any currently-blocked Read call.
|
// and any currently-blocked Read call.
|
||||||
// A zero value for t means Read will not time out.
|
// A zero value for t means Read will not time out.
|
||||||
func (hc *Conn) SetReadDeadline(t time.Time) error {
|
func (hc *Conn) SetReadDeadline(t time.Time) error {
|
||||||
return hc.c.SetReadDeadline(t)
|
return (*hc.c).SetReadDeadline(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*---------------------------------------------------------------------*/
|
/*---------------------------------------------------------------------*/
|
||||||
|
@ -397,35 +524,46 @@ func (hl *HKExListener) Accept() (hc Conn, err error) {
|
||||||
// Open raw Conn c
|
// Open raw Conn c
|
||||||
c, err := hl.l.Accept()
|
c, err := hl.l.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
hc := Conn{m: &sync.Mutex{}, c: nil, h: nil, closeStat: new(CSOType), cipheropts: 0, opts: 0,
|
return Conn{}, err
|
||||||
r: nil, w: nil}
|
|
||||||
return hc, 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),
|
// Read KEx alg proposed by client
|
||||||
dBuf: new(bytes.Buffer)}
|
var kexAlg KEXAlg
|
||||||
|
|
||||||
// TODO: Factor out ALL params following this to helpers for
|
|
||||||
// specific KEx algs
|
|
||||||
var kexAlg uint8
|
|
||||||
_, err = fmt.Fscanln(c, &kexAlg)
|
_, err = fmt.Fscanln(c, &kexAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return hc, err
|
return Conn{}, err
|
||||||
}
|
}
|
||||||
log.Printf("[Client proposed KEx alg: %v]\n", kexAlg)
|
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:
|
case KEX_HERRADURA:
|
||||||
log.Printf("[KEx alg %d accepted]\n", kexAlg)
|
log.Println("[Setting up for KEX_HERRADURA]")
|
||||||
if HKExAcceptSetup(c, &hc) != nil {
|
if HKExAcceptSetup(&c, &hc) != nil {
|
||||||
return 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:
|
default:
|
||||||
log.Printf("[KEx alg %d rejected]\n", kexAlg)
|
log.Println("[unknown alg, Setting up for KEX_HERRADURA]")
|
||||||
return hc, errors.New("KEx rejected")
|
if HKExAcceptSetup(&c, &hc) != nil {
|
||||||
|
log.Println("[ERROR - default KEX_HERRADURA]")
|
||||||
|
return Conn{}, nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
log.Println("[hc.Accept successful]")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +585,7 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
var payloadLen uint32
|
var payloadLen uint32
|
||||||
|
|
||||||
// Read ctrl/status opcode (CSOHmacInvalid on hmac mismatch)
|
// 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)
|
log.Printf("[ctrlStatOp: %v]\n", ctrlStatOp)
|
||||||
if ctrlStatOp == CSOHmacInvalid {
|
if ctrlStatOp == CSOHmacInvalid {
|
||||||
// Other side indicated channel tampering, close channel
|
// Other side indicated channel tampering, close channel
|
||||||
|
@ -456,7 +594,7 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the hmac and payload len first
|
// 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
|
// Normal client 'exit' from interactive session will cause
|
||||||
// (on server side) err.Error() == "<iface/addr info ...>: use of closed network connection"
|
// (on server side) err.Error() == "<iface/addr info ...>: use of closed network connection"
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -468,7 +606,7 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = binary.Read(hc.c, binary.BigEndian, &payloadLen)
|
err = binary.Read(*hc.c, binary.BigEndian, &payloadLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() != "EOF" {
|
if err.Error() != "EOF" {
|
||||||
log.Println("[2]unexpected Read() err:", err)
|
log.Println("[2]unexpected Read() err:", err)
|
||||||
|
@ -482,7 +620,7 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var payloadBytes = make([]byte, payloadLen)
|
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
|
// Normal client 'exit' from interactive session will cause
|
||||||
// (on server side) err.Error() == "<iface/addr info ...>: use of closed network connection"
|
// (on server side) err.Error() == "<iface/addr info ...>: use of closed network connection"
|
||||||
|
@ -553,7 +691,7 @@ func (hc Conn) Read(b []byte) (n int, err error) {
|
||||||
// Log alert if hmac didn't match, corrupted channel
|
// Log alert if hmac didn't match, corrupted channel
|
||||||
if !bytes.Equal(hTmp, []byte(hmacIn[0:])) /*|| hmacIn[0] > 0xf8*/ {
|
if !bytes.Equal(hTmp, []byte(hmacIn[0:])) /*|| hmacIn[0] > 0xf8*/ {
|
||||||
fmt.Println("** ALERT - detected HMAC mismatch, possible channel tampering **")
|
fmt.Println("** ALERT - detected HMAC mismatch, possible channel tampering **")
|
||||||
_, _ = hc.c.Write([]byte{CSOHmacInvalid})
|
_, _ = (*hc.c).Write([]byte{CSOHmacInvalid})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -642,14 +780,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()))
|
log.Printf(" ->ctext:\r\n%s\r\n", hex.Dump(wb.Bytes()))
|
||||||
|
|
||||||
ctrlStatOp := op
|
ctrlStatOp := op
|
||||||
err = binary.Write(hc.c, binary.BigEndian, &ctrlStatOp)
|
err = binary.Write(*hc.c, binary.BigEndian, &ctrlStatOp)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// Write hmac LSB, payloadLen followed by payload
|
// 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 {
|
if err == nil {
|
||||||
err = binary.Write(hc.c, binary.BigEndian, payloadLen)
|
err = binary.Write(*hc.c, binary.BigEndian, payloadLen)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
n, err = hc.c.Write(wb.Bytes())
|
n, err = (*hc.c).Write(wb.Bytes())
|
||||||
} else {
|
} else {
|
||||||
//fmt.Println("[c]WriteError!")
|
//fmt.Println("[c]WriteError!")
|
||||||
}
|
}
|
||||||
|
|
|
@ -351,8 +351,9 @@ func main() {
|
||||||
var gopt bool //login via password, asking server to generate authToken
|
var gopt bool //login via password, asking server to generate authToken
|
||||||
var dbg bool
|
var dbg bool
|
||||||
var shellMode bool // if true act as shell, else file copier
|
var shellMode bool // if true act as shell, else file copier
|
||||||
var cAlg string
|
var cAlg string //cipher alg
|
||||||
var hAlg string
|
var hAlg string //hmac alg
|
||||||
|
var kAlg string //KEX/KEM alg
|
||||||
var server string
|
var server string
|
||||||
var port uint
|
var port uint
|
||||||
var cmdStr string
|
var cmdStr string
|
||||||
|
@ -373,6 +374,7 @@ func main() {
|
||||||
flag.BoolVar(&dbg, "d", false, "debug logging")
|
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(&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(&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.UintVar(&port, "p", 2000, "`port`")
|
||||||
//flag.StringVar(&authCookie, "a", "", "auth cookie")
|
//flag.StringVar(&authCookie, "a", "", "auth cookie")
|
||||||
flag.BoolVar(&chaffEnabled, "e", true, "enabled chaff pkts (default true)")
|
flag.BoolVar(&chaffEnabled, "e", true, "enabled chaff pkts (default true)")
|
||||||
|
@ -543,7 +545,7 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := hkexnet.Dial("tcp", server /*[kexAlg eg. "KEX_HERRADURA"], */, cAlg, hAlg)
|
conn, err := hkexnet.Dial("tcp", server, cAlg, hAlg, kAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|
Loading…
Reference in New Issue